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