Commit | Line | Data |
---|---|---|
8ae0e4b4 | 1 | /* |
39c71180 | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
8ae0e4b4 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
ae64a1dd | 6 | * @(#)hp.c 7.10 (Berkeley) %G% |
8ae0e4b4 | 7 | */ |
63c82e3f HS |
8 | |
9 | /* | |
4dbcd6a1 KB |
10 | * RP??/RM?? disk driver with ECC handling and bad block forwarding. |
11 | * Also supports header io operations and commands to write check | |
12 | * header and data. | |
63c82e3f | 13 | */ |
39c71180 MK |
14 | #include "param.h" |
15 | #include "inode.h" | |
16 | #include "fs.h" | |
17 | #include "dkbad.h" | |
18 | #include "disklabel.h" | |
63c82e3f HS |
19 | |
20 | #include "../vax/pte.h" | |
39c71180 | 21 | |
63c82e3f HS |
22 | #include "../vaxmba/hpreg.h" |
23 | #include "../vaxmba/mbareg.h" | |
24 | ||
25 | #include "saio.h" | |
26 | #include "savax.h" | |
27 | ||
f834e141 MK |
28 | #define RETRIES 27 |
29 | ||
63c82e3f HS |
30 | #define MASKREG(reg) ((reg)&0xffff) |
31 | ||
356d90a8 SL |
32 | #define MAXBADDESC 126 |
33 | #define SECTSIZ 512 /* sector size in bytes */ | |
34 | #define HDRSIZ 4 /* number of bytes in sector header */ | |
63c82e3f | 35 | |
80c81fbf | 36 | char lbuf[SECTSIZ]; |
63c82e3f | 37 | |
80c81fbf MK |
38 | #define RP06(type) ((type) == MBDT_RP06 || (type) == MBDT_RP05 \ |
39 | || (type) == MBDT_RP04) | |
40 | #define ML11(type) ((type) == MBDT_ML11A) | |
41 | #define RM80(type) ((type) == MBDT_RM80) | |
63c82e3f HS |
42 | |
43 | u_char hp_offset[16] = { | |
4dbcd6a1 KB |
44 | HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, |
45 | HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, | |
46 | HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, | |
47 | 0, 0, 0, 0, | |
63c82e3f HS |
48 | }; |
49 | ||
4dbcd6a1 KB |
50 | #define MAXUNIT 8 |
51 | struct disklabel hplabel[MAXNMBA][MAXUNIT]; | |
80c81fbf | 52 | #ifndef SMALL |
4dbcd6a1 | 53 | struct dkbad hpbad[MAXNMBA][MAXUNIT]; |
80c81fbf MK |
54 | int sectsiz; |
55 | #endif | |
356d90a8 | 56 | |
f834e141 MK |
57 | struct hp_softc { |
58 | char type; | |
59 | char gottype; | |
4dbcd6a1 | 60 | char ssect; /* 1 when on track w/skip sector */ |
f834e141 MK |
61 | char debug; |
62 | # define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */ | |
63 | # define HPF_ECCDEBUG 02 /* debugging ecc correction */ | |
64 | int ecclim; | |
65 | int retries; | |
4dbcd6a1 | 66 | } hp_softc[MAXNMBA][MAXUNIT]; |
356d90a8 | 67 | |
4b5bcdd9 | 68 | /* |
4dbcd6a1 KB |
69 | * When awaiting command completion, don't hang on to the status register |
70 | * since this ties up some controllers. | |
4b5bcdd9 | 71 | */ |
356d90a8 | 72 | #define HPWAIT(addr) \ |
4dbcd6a1 KB |
73 | while ((((addr)->hpds)&HPDS_DRY) == 0) \ |
74 | DELAY(500); | |
4b5bcdd9 | 75 | |
63c82e3f HS |
76 | hpopen(io) |
77 | register struct iob *io; | |
78 | { | |
79 | register unit = io->i_unit; | |
4dbcd6a1 KB |
80 | register struct hp_softc *sc; |
81 | register struct disklabel *lp; | |
82 | struct hpdevice *hpaddr; | |
60bc077a | 83 | struct disklabel *dlp; |
f2f9e58f | 84 | int error = 0; |
63c82e3f | 85 | |
ae64a1dd MK |
86 | /* |
87 | * Accept adaptor number as either controller or adaptor, | |
88 | * but not both. | |
89 | */ | |
90 | if (io->i_ctlr) { | |
91 | if (io->i_adapt == 0) | |
92 | io->i_adapt = io->i_ctlr; | |
93 | else | |
94 | return (ECTLR); | |
95 | } | |
4dbcd6a1 KB |
96 | if ((u_int)io->i_adapt >= MAXNMBA || !mbainit(io->i_adapt)) |
97 | return (EADAPT); | |
4dbcd6a1 KB |
98 | if ((u_int)unit >= MAXUNIT) |
99 | return (EUNIT); | |
100 | hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit); | |
101 | sc = &hp_softc[io->i_adapt][unit]; | |
102 | lp = &hplabel[io->i_adapt][unit]; | |
f834e141 | 103 | if (sc->gottype == 0) { |
4dbcd6a1 | 104 | register int i; |
63c82e3f HS |
105 | struct iob tio; |
106 | ||
80c81fbf | 107 | #ifndef SMALL |
f834e141 MK |
108 | sc->retries = RETRIES; |
109 | sc->ecclim = 11; | |
110 | sc->debug = 0; | |
80c81fbf | 111 | #endif |
7fc00e31 HS |
112 | hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */ |
113 | hpaddr->hpcs1 = HP_PRESET|HP_GO; | |
80c81fbf | 114 | #ifndef SMALL |
9ab9be08 | 115 | if ((hpaddr->hpds & HPDS_DPR) == 0) |
39c71180 | 116 | return (ENXIO); |
80c81fbf MK |
117 | sc->type = hpaddr->hpdt & MBDT_TYPE; |
118 | if (sc->type == MBDT_ML11B) | |
39c71180 | 119 | sc->type = MBDT_ML11A; |
80c81fbf MK |
120 | if (!ML11(sc->type)) |
121 | #endif | |
7fc00e31 | 122 | hpaddr->hpof = HPOF_FMT22; |
63c82e3f | 123 | /* |
80c81fbf | 124 | * Read in the pack label. |
63c82e3f | 125 | */ |
80c81fbf MK |
126 | lp->d_nsectors = 32; |
127 | lp->d_secpercyl = 20*32; | |
63c82e3f | 128 | tio = *io; |
80c81fbf MK |
129 | tio.i_bn = LABELSECTOR; |
130 | tio.i_ma = lbuf; | |
131 | tio.i_cc = SECTSIZ; | |
132 | tio.i_flgs |= F_RDDATA; | |
b04dd895 | 133 | if (hpstrategy(&tio, READ) != SECTSIZ) |
f2f9e58f | 134 | error = ERDLAB; |
60bc077a | 135 | dlp = (struct disklabel *)(lbuf + LABELOFFSET); |
f2f9e58f MK |
136 | if (error == 0 && (dlp->d_magic != DISKMAGIC || |
137 | dlp->d_magic2 != DISKMAGIC)) | |
138 | error = EUNLAB; | |
139 | if (error == 0) | |
140 | *lp = *dlp; | |
141 | else | |
b04dd895 | 142 | #ifdef COMPAT_42 |
f2f9e58f | 143 | if (hpmaptype(hpaddr, hpaddr->hpdt & MBDT_TYPE, unit, lp) == 0) |
80c81fbf | 144 | #endif |
f2f9e58f MK |
145 | return (error); |
146 | ||
60bc077a | 147 | #ifndef SMALL |
80c81fbf MK |
148 | /* |
149 | * Read in the bad sector table. | |
150 | */ | |
151 | tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors; | |
4dbcd6a1 KB |
152 | tio.i_ma = (char *)&hpbad[io->i_adapt][unit]; |
153 | tio.i_cc = sizeof(struct dkbad); | |
63c82e3f | 154 | for (i = 0; i < 5; i++) { |
4dbcd6a1 | 155 | if (hpstrategy(&tio, READ) == sizeof(struct dkbad)) |
63c82e3f HS |
156 | break; |
157 | tio.i_bn += 2; | |
158 | } | |
159 | if (i == 5) { | |
4dbcd6a1 | 160 | printf("hp: can't read bad sector table\n"); |
63c82e3f | 161 | for (i = 0; i < MAXBADDESC; i++) { |
4dbcd6a1 KB |
162 | hpbad[io->i_adapt][unit].bt_bad[i].bt_cyl = -1; |
163 | hpbad[io->i_adapt][unit].bt_bad[i].bt_trksec = -1; | |
63c82e3f | 164 | } |
f834e141 | 165 | } |
80c81fbf | 166 | #endif |
60bc077a | 167 | sc->gottype = 1; |
63c82e3f | 168 | } |
4dbcd6a1 KB |
169 | if (io->i_part >= lp->d_npartitions || |
170 | lp->d_partitions[io->i_part].p_size == 0) | |
171 | return (EPART); | |
172 | io->i_boff = lp->d_partitions[io->i_part].p_offset; | |
80c81fbf | 173 | return (0); |
63c82e3f HS |
174 | } |
175 | ||
176 | hpstrategy(io, func) | |
177 | register struct iob *io; | |
178 | { | |
4dbcd6a1 KB |
179 | register int unit = io->i_unit; |
180 | register struct hp_softc *sc; | |
181 | register struct disklabel *lp; | |
182 | struct mba_regs *mba; | |
183 | struct hpdevice *hpaddr; | |
356d90a8 | 184 | daddr_t bn, startblock; |
39c71180 | 185 | int cn, tn, sn, bytecnt, bytesleft, rv; |
63c82e3f | 186 | int er1, er2, hprecal; |
4dbcd6a1 | 187 | char *membase; |
63c82e3f | 188 | |
4dbcd6a1 KB |
189 | mba = mbamba(io->i_adapt); |
190 | hpaddr = (struct hpdevice *)mbadrv(io->i_adapt, unit); | |
191 | sc = &hp_softc[io->i_adapt][unit]; | |
192 | lp = &hplabel[io->i_adapt][unit]; | |
80c81fbf | 193 | #ifndef SMALL |
63c82e3f HS |
194 | sectsiz = SECTSIZ; |
195 | if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) | |
196 | sectsiz += HDRSIZ; | |
197 | if ((hpaddr->hpds & HPDS_VV) == 0) { | |
198 | hpaddr->hpcs1 = HP_DCLR|HP_GO; | |
199 | hpaddr->hpcs1 = HP_PRESET|HP_GO; | |
80c81fbf | 200 | if (!ML11(sc->type)) |
63c82e3f HS |
201 | hpaddr->hpof = HPOF_FMT22; |
202 | } | |
203 | io->i_errcnt = 0; | |
f834e141 MK |
204 | sc->ssect = 0; |
205 | rv = bytecnt = io->i_cc; | |
63c82e3f HS |
206 | membase = io->i_ma; |
207 | startblock = io->i_bn; | |
308847fc | 208 | hprecal = 0; |
80c81fbf | 209 | #endif |
86bcc486 | 210 | |
ccc991c5 | 211 | restart: |
63c82e3f | 212 | bn = io->i_bn; |
80c81fbf MK |
213 | cn = bn / lp->d_secpercyl; |
214 | sn = bn % lp->d_secpercyl; | |
215 | tn = sn / lp->d_nsectors; | |
216 | sn = sn % lp->d_nsectors + sc->ssect; | |
63c82e3f | 217 | |
4b5bcdd9 | 218 | HPWAIT(hpaddr); |
ccc991c5 | 219 | mba->mba_sr = -1; |
80c81fbf | 220 | if (ML11(sc->type)) |
63c82e3f HS |
221 | hpaddr->hpda = bn; |
222 | else { | |
223 | hpaddr->hpdc = cn; | |
224 | hpaddr->hpda = (tn << 8) + sn; | |
225 | } | |
80c81fbf | 226 | #ifdef SMALL |
4dbcd6a1 | 227 | mbastart(io, io->i_unit, func); /* start transfer */ |
80c81fbf MK |
228 | HPWAIT(hpaddr); |
229 | if (hpaddr->hpds & HPDS_ERR) { | |
230 | printf("hp error: sn [%d-%d) ds=%b er1=%b\n", | |
231 | bn, bn + io->i_cc/SECTSIZ, MASKREG(hpaddr->hpds), HPDS_BITS, | |
232 | MASKREG(hpaddr->hper1), HPER1_BITS); | |
233 | return (-1); | |
234 | } | |
235 | return (io->i_cc); | |
236 | #else | |
4dbcd6a1 | 237 | if (mbastart(io, io->i_unit, func) != 0) { /* start transfer */ |
f834e141 MK |
238 | rv = -1; |
239 | goto done; | |
240 | } | |
4b5bcdd9 | 241 | HPWAIT(hpaddr); |
356d90a8 SL |
242 | /* |
243 | * Successful data transfer, return. | |
244 | */ | |
c5fc2df8 MK |
245 | if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) |
246 | goto done; | |
63c82e3f | 247 | |
356d90a8 SL |
248 | /* |
249 | * Error handling. Calculate location of error. | |
250 | */ | |
251 | bytesleft = MASKREG(mba->mba_bcr); | |
252 | if (bytesleft) | |
253 | bytesleft |= 0xffff0000; /* sxt */ | |
254 | bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz; | |
71da8ead MK |
255 | er1 = MASKREG(hpaddr->hper1); |
256 | er2 = MASKREG(hpaddr->hper2); | |
257 | if (er1 & (HPER1_DCK|HPER1_ECH)) | |
258 | bn--; /* Error is in Prev block */ | |
80c81fbf MK |
259 | cn = bn/lp->d_secpercyl; |
260 | sn = bn%lp->d_secpercyl; | |
261 | tn = sn/lp->d_nsectors; | |
262 | sn = sn%lp->d_nsectors; | |
f834e141 MK |
263 | if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) { |
264 | printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n", | |
265 | bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); | |
356d90a8 SL |
266 | printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS); |
267 | printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft, | |
268 | hpaddr->hpof, hpaddr->hpda); | |
269 | } | |
63c82e3f HS |
270 | if (er1 & HPER1_HCRC) { |
271 | er1 &= ~(HPER1_HCE|HPER1_FER); | |
272 | er2 &= ~HPER2_BSE; | |
f834e141 MK |
273 | if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0) |
274 | goto success; | |
63c82e3f | 275 | } |
86bcc486 SL |
276 | /* |
277 | * Give up early if drive write locked. | |
278 | */ | |
63c82e3f HS |
279 | if (er1&HPER1_WLE) { |
280 | printf("hp%d: write locked\n", unit); | |
f834e141 MK |
281 | rv = -1; |
282 | goto done; | |
9d78a350 | 283 | } |
86bcc486 | 284 | /* |
f834e141 | 285 | * Skip sector handling. |
86bcc486 | 286 | */ |
80c81fbf | 287 | if (RM80(sc->type) && (er2 & HPER2_SSE)) { |
f834e141 MK |
288 | (void) hpecc(io, SSE); |
289 | sc->ssect = 1; | |
290 | goto restart; | |
9d78a350 | 291 | } |
86bcc486 | 292 | /* |
f834e141 MK |
293 | * Attempt to forward bad sectors on anything but an ML11. |
294 | * Interpret format error bit as a bad block on RP06's. | |
86bcc486 | 295 | */ |
80c81fbf MK |
296 | if (((er2 & HPER2_BSE) && !ML11(sc->type)) || |
297 | (MASKREG(er1) == HPER1_FER && RP06(sc->type))) { | |
9d78a350 | 298 | if (io->i_flgs & F_NBSF) { |
4dbcd6a1 | 299 | io->i_error = EBSE; |
63c82e3f HS |
300 | goto hard; |
301 | } | |
302 | if (hpecc(io, BSE) == 0) | |
303 | goto success; | |
9d78a350 SL |
304 | io->i_error = EBSE; |
305 | goto hard; | |
306 | } | |
86bcc486 | 307 | /* |
356d90a8 | 308 | * ECC correction? |
86bcc486 | 309 | */ |
9d78a350 | 310 | if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { |
4b5bcdd9 | 311 | if (hpecc(io, ECC) == 0) |
63c82e3f | 312 | goto success; |
9d78a350 | 313 | io->i_error = EECC; |
71da8ead | 314 | goto hard; |
f834e141 MK |
315 | } |
316 | ||
317 | /* | |
318 | * If a hard error, or maximum retry count | |
319 | * exceeded, clear controller state and | |
320 | * pass back error to caller. | |
321 | */ | |
322 | if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) || | |
80c81fbf MK |
323 | (!ML11(sc->type) && (er2 & HPER2_HARD)) || |
324 | (ML11(sc->type) && (io->i_errcnt >= 16))) { | |
f834e141 MK |
325 | io->i_error = EHER; |
326 | if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) | |
327 | io->i_error = EWCK; | |
328 | hard: | |
329 | io->i_errblk = bn + sc->ssect; | |
330 | if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG)) | |
331 | printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc), | |
332 | MASKREG(hpaddr->hpda)); | |
333 | else { | |
334 | printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", | |
335 | bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); | |
336 | printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); | |
337 | } | |
338 | hpaddr->hpcs1 = HP_DCLR|HP_GO; | |
339 | printf("\n"); | |
340 | rv = -1; | |
341 | goto done; | |
342 | ||
343 | } | |
308847fc | 344 | /* fall thru to retry */ |
63c82e3f | 345 | hpaddr->hpcs1 = HP_DCLR|HP_GO; |
4b5bcdd9 | 346 | HPWAIT(hpaddr); |
86bcc486 SL |
347 | |
348 | /* | |
349 | * Every fourth retry recalibrate. | |
350 | */ | |
356d90a8 | 351 | if (((io->i_errcnt & 07) == 4) ) { |
63c82e3f | 352 | hpaddr->hpcs1 = HP_RECAL|HP_GO; |
71da8ead | 353 | HPWAIT(hpaddr); |
63c82e3f HS |
354 | hpaddr->hpdc = cn; |
355 | hpaddr->hpcs1 = HP_SEEK|HP_GO; | |
71da8ead MK |
356 | HPWAIT(hpaddr); |
357 | } | |
4b5bcdd9 | 358 | |
71da8ead | 359 | if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) { |
63c82e3f HS |
360 | hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; |
361 | hpaddr->hpcs1 = HP_OFFSET|HP_GO; | |
71da8ead | 362 | HPWAIT(hpaddr); |
63c82e3f | 363 | } |
f834e141 | 364 | if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) |
71da8ead MK |
365 | printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", |
366 | io->i_bn, io->i_cc, io->i_ma, hprecal); | |
f834e141 | 367 | goto restart; |
9d78a350 | 368 | |
86bcc486 SL |
369 | success: |
370 | /* | |
371 | * On successful error recovery, bump | |
372 | * block number to advance to next portion | |
373 | * of i/o transfer. | |
374 | */ | |
63c82e3f HS |
375 | bn++; |
376 | if ((bn-startblock) * sectsiz < bytecnt) { | |
63c82e3f | 377 | io->i_bn = bn; |
63c82e3f HS |
378 | io->i_ma = membase + (io->i_bn - startblock)*sectsiz; |
379 | io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; | |
f834e141 | 380 | if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) |
356d90a8 SL |
381 | printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", |
382 | io->i_bn, io->i_cc, io->i_ma, hprecal); | |
ccc991c5 | 383 | goto restart; |
63c82e3f | 384 | } |
c5fc2df8 | 385 | done: |
71da8ead MK |
386 | if (io->i_errcnt >= 16) { |
387 | hpaddr->hpcs1 = HP_RTC|HP_GO; | |
388 | while (hpaddr->hpds & HPDS_PIP) | |
389 | ; | |
390 | } | |
f834e141 | 391 | io->i_bn = startblock; /*reset i_bn to original */ |
2f1563bc | 392 | io->i_cc = bytecnt; /*reset i_cc to total count xfered*/ |
f834e141 MK |
393 | io->i_ma = membase; /*reset i_ma to original */ |
394 | return (rv); | |
80c81fbf | 395 | #endif |
63c82e3f | 396 | } |
4b5bcdd9 | 397 | |
80c81fbf | 398 | #ifndef SMALL |
63c82e3f HS |
399 | hpecc(io, flag) |
400 | register struct iob *io; | |
401 | int flag; | |
402 | { | |
4dbcd6a1 KB |
403 | register int unit = io->i_unit; |
404 | register struct mba_regs *mbp; | |
405 | register struct hpdevice *rp; | |
406 | register struct hp_softc *sc; | |
407 | register struct disklabel *lp; | |
9d78a350 | 408 | int npf, bn, cn, tn, sn, bcr; |
63c82e3f | 409 | |
4dbcd6a1 KB |
410 | mbp = mbamba(io->i_adapt); |
411 | rp = (struct hpdevice *)mbadrv(io->i_adapt, unit); | |
412 | sc = &hp_softc[io->i_adapt][unit]; | |
413 | lp = &hplabel[io->i_adapt][unit]; | |
356d90a8 SL |
414 | bcr = MASKREG(mbp->mba_bcr); |
415 | if (bcr) | |
416 | bcr |= 0xffff0000; /* sxt */ | |
9d78a350 | 417 | npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ |
71da8ead MK |
418 | if (flag == ECC) |
419 | npf--; /* Error is in prev block --ghg */ | |
f834e141 MK |
420 | bn = io->i_bn + npf + sc->ssect; /* physical block #*/ |
421 | if (sc->debug & HPF_ECCDEBUG) | |
356d90a8 | 422 | printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n", |
f834e141 | 423 | bcr, npf, sc->ssect, sectsiz, io->i_cc); |
86bcc486 SL |
424 | /* |
425 | * ECC correction logic. | |
426 | */ | |
427 | if (flag == ECC) { | |
63c82e3f HS |
428 | register int i; |
429 | caddr_t addr; | |
f834e141 | 430 | int bit, o, mask; |
63c82e3f | 431 | |
0cd55454 | 432 | printf("hp%d: soft ecc sn%d\n", unit, bn); |
63c82e3f | 433 | mask = MASKREG(rp->hpec2); |
f834e141 MK |
434 | for (i = mask, bit = 0; i; i >>= 1) |
435 | if (i & 1) | |
436 | bit++; | |
437 | if (bit > sc->ecclim) { | |
438 | printf("%d-bit error\n", bit); | |
439 | return (1); | |
440 | } | |
9d78a350 | 441 | i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ |
63c82e3f | 442 | bit = i&07; |
356d90a8 | 443 | o = (i & ~07) >> 3; |
63c82e3f | 444 | rp->hpcs1 = HP_DCLR | HP_GO; |
10860662 SL |
445 | while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) { |
446 | addr = io->i_ma + (npf*sectsiz) + o; | |
10860662 SL |
447 | /* |
448 | * No data transfer occurs with a write check, | |
449 | * so don't correct the resident copy of data. | |
450 | */ | |
356d90a8 | 451 | if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { |
f834e141 | 452 | if (sc->debug & HPF_ECCDEBUG) |
356d90a8 SL |
453 | printf("addr=%x old=%x ", addr, |
454 | (*addr & 0xff)); | |
86bcc486 | 455 | *addr ^= (mask << bit); |
f834e141 | 456 | if (sc->debug & HPF_ECCDEBUG) |
356d90a8 SL |
457 | printf("new=%x\n",(*addr & 0xff)); |
458 | } | |
10860662 | 459 | o++, bit -= 8; |
63c82e3f | 460 | } |
10860662 | 461 | return (0); |
9d78a350 | 462 | } |
63c82e3f | 463 | |
9d78a350 SL |
464 | /* |
465 | * Skip sector error. | |
466 | * Set skip-sector-inhibit and | |
467 | * read next sector | |
468 | */ | |
86bcc486 | 469 | if (flag == SSE) { |
63c82e3f | 470 | rp->hpcs1 = HP_DCLR | HP_GO; |
4b5bcdd9 | 471 | HPWAIT(rp); |
63c82e3f | 472 | rp->hpof |= HPOF_SSEI; |
4dbcd6a1 | 473 | return (0); |
86bcc486 | 474 | } |
63c82e3f | 475 | |
86bcc486 SL |
476 | /* |
477 | * Bad block forwarding. | |
478 | */ | |
479 | if (flag == BSE) { | |
ccc991c5 | 480 | int bbn; |
9d78a350 | 481 | |
ccc991c5 | 482 | rp->hpcs1 = HP_DCLR | HP_GO; |
f834e141 | 483 | if (sc->debug & HPF_BSEDEBUG) |
356d90a8 | 484 | printf("hpecc: BSE @ bn %d\n", bn); |
80c81fbf MK |
485 | cn = bn / lp->d_secpercyl; |
486 | sn = bn % lp->d_secpercyl; | |
487 | tn = sn / lp->d_nsectors; | |
488 | sn = sn % lp->d_nsectors; | |
ccc991c5 | 489 | bcr += sectsiz; |
4dbcd6a1 | 490 | if ((bbn = isbad(&hpbad[io->i_adapt][unit], cn, tn, sn)) < 0) |
9d78a350 | 491 | return (1); |
80c81fbf MK |
492 | bbn = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors - 1 |
493 | - bbn; | |
494 | cn = bbn / lp->d_secpercyl; | |
495 | sn = bbn % lp->d_secpercyl; | |
496 | tn = sn / lp->d_nsectors; | |
39c71180 | 497 | sn = sn % lp->d_nsectors; |
ccc991c5 | 498 | io->i_cc = sectsiz; |
80c81fbf | 499 | io->i_ma += npf * sectsiz; |
f834e141 | 500 | if (sc->debug & HPF_BSEDEBUG) |
356d90a8 SL |
501 | printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); |
502 | rp->hpof &= ~HPOF_SSEI; | |
ccc991c5 | 503 | mbp->mba_sr = -1; |
63c82e3f HS |
504 | rp->hpdc = cn; |
505 | rp->hpda = (tn<<8) + sn; | |
4dbcd6a1 | 506 | mbastart(io, io->i_unit, io->i_flgs); |
356d90a8 | 507 | io->i_errcnt = 0; |
4b5bcdd9 SL |
508 | HPWAIT(rp); |
509 | return (rp->hpds&HPDS_ERR); | |
63c82e3f | 510 | } |
9d78a350 SL |
511 | printf("hpecc: flag=%d\n", flag); |
512 | return (1); | |
63c82e3f | 513 | } |
86bcc486 | 514 | |
63c82e3f HS |
515 | /*ARGSUSED*/ |
516 | hpioctl(io, cmd, arg) | |
517 | struct iob *io; | |
518 | int cmd; | |
519 | caddr_t arg; | |
520 | { | |
7fc00e31 | 521 | register unit = io->i_unit; |
4dbcd6a1 KB |
522 | register struct hp_softc *sc = &hp_softc[io->i_adapt][unit]; |
523 | register struct disklabel *lp = &hplabel[io->i_adapt][unit]; | |
524 | struct mba_drv *drv = mbadrv(io->i_adapt, unit); | |
63c82e3f HS |
525 | |
526 | switch(cmd) { | |
527 | ||
356d90a8 | 528 | case SAIODEBUG: |
f834e141 MK |
529 | sc->debug = (int)arg; |
530 | break; | |
356d90a8 | 531 | |
63c82e3f | 532 | case SAIODEVDATA: |
f834e141 MK |
533 | if (drv->mbd_dt&MBDT_TAP) |
534 | return (ECMD); | |
80c81fbf | 535 | *(struct disklabel *)arg = *lp; |
f834e141 MK |
536 | break; |
537 | ||
538 | case SAIOGBADINFO: | |
539 | if (drv->mbd_dt&MBDT_TAP) | |
540 | return (ECMD); | |
4dbcd6a1 | 541 | *(struct dkbad *)arg = hpbad[io->i_adapt][unit]; |
f834e141 MK |
542 | break; |
543 | ||
544 | case SAIOECCLIM: | |
545 | sc->ecclim = (int)arg; | |
546 | break; | |
547 | ||
548 | case SAIORETRIES: | |
549 | sc->retries = (int)arg; | |
550 | break; | |
63c82e3f | 551 | |
9d78a350 SL |
552 | case SAIOSSI: /* skip-sector-inhibit */ |
553 | if (drv->mbd_dt&MBDT_TAP) | |
554 | return (ECMD); | |
555 | if ((io->i_flgs&F_SSI) == 0) { | |
556 | /* make sure this is done once only */ | |
557 | io->i_flgs |= F_SSI; | |
80c81fbf MK |
558 | lp->d_nsectors++; |
559 | lp->d_secpercyl += lp->d_ntracks; | |
4b5bcdd9 | 560 | } |
f834e141 | 561 | break; |
ccc991c5 | 562 | |
9d78a350 | 563 | case SAIONOSSI: /* remove skip-sector-inhibit */ |
ccc991c5 HS |
564 | if (io->i_flgs & F_SSI) { |
565 | io->i_flgs &= ~F_SSI; | |
566 | drv->mbd_of &= ~HPOF_SSEI; | |
80c81fbf MK |
567 | lp->d_nsectors--; |
568 | lp->d_secpercyl -= lp->d_ntracks; | |
ccc991c5 | 569 | } |
f834e141 | 570 | break; |
ccc991c5 | 571 | |
4b5bcdd9 | 572 | case SAIOSSDEV: /* drive have skip sector? */ |
80c81fbf | 573 | return (RM80(sc->type) ? 0 : ECMD); |
f834e141 MK |
574 | |
575 | default: | |
576 | return (ECMD); | |
63c82e3f | 577 | } |
f834e141 | 578 | return (0); |
63c82e3f | 579 | } |
4dbcd6a1 | 580 | #endif /* !SMALL */ |