Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
f75b5a26 | 2 | * Copyright (c) 1982, 1988 Regents of the University of California. |
da7c5cc6 KM |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
b2291f86 | 6 | * @(#)up.c 7.8 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
258a5c40 | 8 | |
0839bdeb | 9 | /* |
d483c0fd KB |
10 | * UNIBUS peripheral standalone driver with ECC correction and bad |
11 | * block forwarding. Also supports header operation and write check | |
12 | * for data and/or header. | |
0839bdeb | 13 | */ |
233fc5c1 MK |
14 | #include "param.h" |
15 | #include "inode.h" | |
16 | #include "fs.h" | |
17 | #include "dkbad.h" | |
d483c0fd | 18 | #include "disklabel.h" |
258a5c40 | 19 | |
39c71180 MK |
20 | #include "../vax/pte.h" |
21 | ||
22 | #include "../vaxuba/upreg.h" | |
23 | #include "../vaxuba/ubareg.h" | |
258a5c40 | 24 | |
0839bdeb | 25 | #include "saio.h" |
258a5c40 SL |
26 | #include "savax.h" |
27 | ||
31fec9db MK |
28 | #define RETRIES 27 |
29 | ||
b8ca3ab9 HS |
30 | #define MAXBADDESC 126 /* max number of bad sectors recorded */ |
31 | #define SECTSIZ 512 /* sector size in bytes */ | |
32 | #define HDRSIZ 4 /* number of bytes in sector header */ | |
dda2842d | 33 | |
d483c0fd | 34 | #define MAXUNIT 8 |
c48789a9 | 35 | #define MAXCTLR 1 /* all addresses must be specified */ |
b2291f86 KB |
36 | static u_short upstd[MAXCTLR] = { 0776700 }; |
37 | static struct disklabel uplabel[MAXNUBA][MAXCTLR][MAXUNIT]; | |
38 | static char lbuf[SECTSIZ]; | |
0839bdeb | 39 | |
b4736392 | 40 | extern struct st upst[]; |
0839bdeb | 41 | |
233fc5c1 | 42 | #ifndef SMALL |
d483c0fd | 43 | struct dkbad upbad[MAXNUBA][MAXCTLR][MAXUNIT]; /* bad sector table */ |
233fc5c1 | 44 | #endif |
d483c0fd | 45 | int sectsiz; /* real sector size */ |
31fec9db MK |
46 | |
47 | struct up_softc { | |
48 | char gottype; | |
49 | char type; | |
50 | char debug; | |
51 | # define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */ | |
52 | # define UPF_ECCDEBUG 02 /* debugging ecc correction */ | |
53 | int retries; | |
54 | int ecclim; | |
d483c0fd | 55 | } up_softc[MAXNUBA][MAXCTLR][MAXUNIT]; |
dda2842d | 56 | |
258a5c40 SL |
57 | u_char up_offset[16] = { |
58 | UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, | |
59 | UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, | |
60 | UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, | |
61 | 0, 0, 0, 0 | |
62 | }; | |
63 | ||
64 | upopen(io) | |
65 | register struct iob *io; | |
66 | { | |
0839bdeb | 67 | register struct updevice *upaddr; |
c48789a9 | 68 | register struct up_softc *sc; |
31fa9244 | 69 | register struct st *st; |
f75b5a26 MK |
70 | register struct disklabel *lp; |
71 | struct disklabel *dlp; | |
d483c0fd | 72 | register int unit; |
f75b5a26 | 73 | int error = 0, uba, ctlr; |
258a5c40 | 74 | |
f75b5a26 MK |
75 | if ((u_int)(uba = io->i_adapt) >= nuba) |
76 | return (EADAPT); | |
77 | if ((u_int)(ctlr = io->i_ctlr) >= MAXCTLR) | |
c48789a9 | 78 | return (ECTLR); |
d483c0fd | 79 | unit = io->i_unit; |
f75b5a26 MK |
80 | if ((u_int)unit >= MAXUNIT) |
81 | return (EUNIT); | |
b2291f86 | 82 | upaddr = (struct updevice *)ubamem(uba, upstd[ctlr]); |
f75b5a26 | 83 | upaddr->upcs2 = unit; |
c48789a9 | 84 | while ((upaddr->upcs1 & UP_DVA) == 0); |
f75b5a26 MK |
85 | sc = &up_softc[uba][ctlr][unit]; |
86 | lp = &uplabel[uba][ctlr][unit]; | |
31fec9db | 87 | if (sc->gottype == 0) { |
0839bdeb SL |
88 | register int i; |
89 | struct iob tio; | |
90 | ||
d483c0fd | 91 | #ifndef SMALL |
31fec9db MK |
92 | sc->retries = RETRIES; |
93 | sc->ecclim = 11; | |
94 | sc->debug = 0; | |
d483c0fd KB |
95 | #endif |
96 | /* Read in the pack label. */ | |
97 | lp->d_nsectors = 32; | |
98 | lp->d_secpercyl = 19*32; | |
99 | tio = *io; | |
100 | tio.i_bn = LABELSECTOR; | |
101 | tio.i_ma = lbuf; | |
102 | tio.i_cc = SECTSIZ; | |
103 | tio.i_flgs |= F_RDDATA; | |
104 | if (upstrategy(&tio, READ) != SECTSIZ) | |
f2f9e58f | 105 | error = ERDLAB; |
d483c0fd | 106 | dlp = (struct disklabel *)(lbuf + LABELOFFSET); |
f2f9e58f MK |
107 | if (error == 0 && (dlp->d_magic != DISKMAGIC || |
108 | dlp->d_magic2 != DISKMAGIC)) | |
109 | error = EUNLAB; | |
110 | if (error == 0) | |
111 | *lp = *dlp; | |
112 | else | |
d483c0fd | 113 | #ifdef COMPAT_42 |
f2f9e58f | 114 | if (upmaptype(unit, upaddr, lp) == 0) |
d483c0fd | 115 | #endif |
f2f9e58f | 116 | return (error); |
d483c0fd | 117 | |
233fc5c1 | 118 | #ifndef SMALL |
d483c0fd KB |
119 | /* Read in the bad sector table. */ |
120 | tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors; | |
f75b5a26 | 121 | tio.i_ma = (char *)&upbad[uba][ctlr][unit]; |
d483c0fd | 122 | tio.i_cc = sizeof(struct dkbad); |
0839bdeb SL |
123 | tio.i_flgs |= F_RDDATA; |
124 | for (i = 0; i < 5; i++) { | |
d483c0fd | 125 | if (upstrategy(&tio, READ) == sizeof(struct dkbad)) |
0839bdeb | 126 | break; |
258a5c40 SL |
127 | tio.i_bn += 2; |
128 | } | |
129 | if (i == 5) { | |
d483c0fd | 130 | printf("up: can't read bad sector table\n"); |
b8ca3ab9 | 131 | for (i = 0; i < MAXBADDESC; i++) { |
f75b5a26 MK |
132 | upbad[uba][ctlr][unit].bt_bad[i].bt_cyl = -1; |
133 | upbad[uba][ctlr][unit].bt_bad[i].bt_trksec = -1; | |
258a5c40 | 134 | } |
d483c0fd | 135 | } |
233fc5c1 | 136 | #endif |
31fec9db | 137 | sc->gottype = 1; |
258a5c40 | 138 | } |
d483c0fd KB |
139 | if (io->i_part >= lp->d_npartitions || |
140 | lp->d_partitions[io->i_part].p_size == 0) | |
f75b5a26 | 141 | return (EPART); |
d483c0fd | 142 | io->i_boff = lp->d_partitions[io->i_part].p_offset; |
0839bdeb | 143 | io->i_flgs &= ~F_TYPEMASK; |
39c71180 | 144 | return (0); |
258a5c40 SL |
145 | } |
146 | ||
147 | upstrategy(io, func) | |
148 | register struct iob *io; | |
d483c0fd | 149 | int func; |
258a5c40 | 150 | { |
1f4919da | 151 | int cn, tn, sn, o; |
b8ca3ab9 | 152 | register unit = io->i_unit; |
39c71180 | 153 | register daddr_t bn; |
258a5c40 | 154 | int recal, info, waitdry; |
c48789a9 | 155 | register struct updevice *upaddr; |
d483c0fd | 156 | register struct disklabel *lp; |
c48789a9 | 157 | struct up_softc *sc; |
39c71180 MK |
158 | int error, rv = io->i_cc; |
159 | #ifndef SMALL | |
160 | int doprintf = 0; | |
161 | #endif | |
258a5c40 | 162 | |
b2291f86 | 163 | upaddr = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]); |
c48789a9 | 164 | sc = &up_softc[io->i_adapt][io->i_ctlr][unit]; |
d483c0fd | 165 | lp = &uplabel[io->i_adapt][io->i_ctlr][unit]; |
b8ca3ab9 | 166 | sectsiz = SECTSIZ; |
f75b5a26 | 167 | #ifndef SMALL |
3ab40097 | 168 | if (io->i_flgs & (F_HDR|F_HCHECK)) |
b8ca3ab9 | 169 | sectsiz += HDRSIZ; |
f75b5a26 MK |
170 | #endif |
171 | upaddr->upcs2 = unit; | |
258a5c40 SL |
172 | if ((upaddr->upds & UPDS_VV) == 0) { |
173 | upaddr->upcs1 = UP_DCLR|UP_GO; | |
174 | upaddr->upcs1 = UP_PRESET|UP_GO; | |
175 | upaddr->upof = UPOF_FMT22; | |
176 | } | |
31fec9db | 177 | if ((upaddr->upds & UPDS_DREADY) == 0) { |
f75b5a26 | 178 | printf("up%d not ready\n", unit); |
31fec9db MK |
179 | return (-1); |
180 | } | |
258a5c40 SL |
181 | info = ubasetup(io, 1); |
182 | upaddr->upwc = -io->i_cc / sizeof (short); | |
3ab40097 SL |
183 | recal = 0; |
184 | io->i_errcnt = 0; | |
185 | ||
960ade39 | 186 | restart: |
1f4919da SL |
187 | o = io->i_cc + (upaddr->upwc * sizeof (short)); |
188 | upaddr->upba = info + o; | |
189 | bn = io->i_bn + o / sectsiz; | |
39c71180 | 190 | #ifndef SMALL |
f75b5a26 | 191 | error = 0; |
31fec9db | 192 | if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) |
3beb607b | 193 | printf("wc=%d o=%d i_bn=%d bn=%d\n", |
dda2842d | 194 | upaddr->upwc, o, io->i_bn, bn); |
39c71180 | 195 | #endif |
f75b5a26 | 196 | upwaitdry(upaddr); |
d483c0fd | 197 | if (upstart(io, bn, lp) != 0) { |
31fec9db MK |
198 | rv = -1; |
199 | goto done; | |
b8ca3ab9 | 200 | } |
f75b5a26 | 201 | upwaitrdy(upaddr); |
3ab40097 SL |
202 | /* |
203 | * If transfer has completed, free UNIBUS | |
204 | * resources and return transfer size. | |
205 | */ | |
73abfe3c MK |
206 | if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0) |
207 | goto done; | |
31fec9db MK |
208 | bn = io->i_bn + |
209 | (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz; | |
210 | if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH)) | |
211 | bn--; | |
d483c0fd KB |
212 | cn = bn / lp->d_secpercyl; |
213 | sn = bn % lp->d_secpercyl; | |
214 | tn = sn / lp->d_nsectors; | |
215 | sn = sn % lp->d_nsectors; | |
233fc5c1 | 216 | #ifndef SMALL |
31fec9db MK |
217 | if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) { |
218 | printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", | |
219 | bn, cn, tn, sn); | |
3beb607b | 220 | printf("cs2=%b er1=%b er2=%b wc=%d\n", |
dda2842d | 221 | upaddr->upcs2, UPCS2_BITS, upaddr->uper1, |
3beb607b | 222 | UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc); |
dda2842d | 223 | } |
233fc5c1 | 224 | #endif |
258a5c40 | 225 | waitdry = 0; |
3beb607b | 226 | while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz) |
0839bdeb | 227 | DELAY(5); |
233fc5c1 | 228 | #ifndef SMALL |
3ab40097 SL |
229 | if (upaddr->uper1&UPER1_WLE) { |
230 | /* | |
231 | * Give up on write locked devices immediately. | |
232 | */ | |
233 | printf("up%d: write locked\n", unit); | |
31fec9db MK |
234 | rv = -1; |
235 | goto done; | |
3ab40097 | 236 | } |
31fec9db MK |
237 | if (upaddr->uper2 & UPER2_BSE) { |
238 | if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0) | |
239 | goto success; | |
240 | error = EBSE; | |
241 | goto hard; | |
242 | } | |
243 | /* | |
244 | * ECC error. If a soft error, correct it; | |
245 | * if correction is too large, no more retries. | |
246 | */ | |
247 | if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) { | |
248 | if (upecc(io, ECC) == 0) | |
249 | goto success; | |
250 | error = EECC; | |
251 | goto hard; | |
252 | } | |
253 | /* | |
d483c0fd KB |
254 | * If the error is a header CRC, check if a replacement sector |
255 | * exists in the bad sector table. | |
31fec9db MK |
256 | */ |
257 | if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 && | |
258 | upecc(io, BSE) == 0) | |
259 | goto success; | |
233fc5c1 | 260 | #endif |
31fec9db | 261 | if (++io->i_errcnt > sc->retries) { |
258a5c40 SL |
262 | /* |
263 | * After 28 retries (16 without offset, and | |
264 | * 12 with offset positioning) give up. | |
265 | */ | |
b8ca3ab9 | 266 | hard: |
f75b5a26 | 267 | #ifndef SMALL |
31fec9db MK |
268 | if (error == 0) { |
269 | error = EHER; | |
270 | if (upaddr->upcs2 & UPCS2_WCE) | |
271 | error = EWCK; | |
272 | } | |
f75b5a26 MK |
273 | io->i_error = error; |
274 | #endif | |
31fec9db MK |
275 | printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ", |
276 | bn, cn, tn, sn); | |
277 | printf("cs2=%b er1=%b er2=%b\n", | |
3ab40097 SL |
278 | upaddr->upcs2, UPCS2_BITS, upaddr->uper1, |
279 | UPER1_BITS, upaddr->uper2, UPER2_BITS); | |
258a5c40 | 280 | upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
b8ca3ab9 | 281 | io->i_errblk = bn; |
73abfe3c MK |
282 | if (io->i_errcnt >= 16) { |
283 | upaddr->upof = UPOF_FMT22; | |
284 | upaddr->upcs1 = UP_RTC|UP_GO; | |
f75b5a26 | 285 | upwaitdry(upaddr); |
73abfe3c | 286 | } |
31fec9db MK |
287 | rv = -1; |
288 | goto done; | |
258a5c40 | 289 | } |
258a5c40 | 290 | /* |
d483c0fd KB |
291 | * Clear drive error and, every eight attempts, (starting with the |
292 | * fourth) recalibrate to clear the slate. | |
258a5c40 SL |
293 | */ |
294 | upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO; | |
960ade39 | 295 | if ((io->i_errcnt&07) == 4 ) { |
258a5c40 | 296 | upaddr->upcs1 = UP_RECAL|UP_GO; |
f75b5a26 | 297 | upwaitdry(upaddr); |
258a5c40 SL |
298 | upaddr->updc = cn; |
299 | upaddr->upcs1 = UP_SEEK|UP_GO; | |
f75b5a26 | 300 | upwaitdry(upaddr); |
73abfe3c MK |
301 | } |
302 | if (io->i_errcnt >= 16 && (func & READ)) { | |
258a5c40 SL |
303 | upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22; |
304 | upaddr->upcs1 = UP_OFFSET|UP_GO; | |
f75b5a26 | 305 | upwaitdry(upaddr); |
258a5c40 | 306 | } |
960ade39 | 307 | goto restart; |
3ab40097 | 308 | |
258a5c40 | 309 | success: |
3beb607b SL |
310 | #define rounddown(x, y) (((x) / (y)) * (y)) |
311 | upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short)); | |
312 | if (upaddr->upwc) { | |
39c71180 | 313 | #ifndef SMALL |
1f4919da | 314 | doprintf++; |
39c71180 | 315 | #endif |
960ade39 | 316 | goto restart; |
1f4919da | 317 | } |
73abfe3c | 318 | done: |
258a5c40 | 319 | ubafree(io, info); |
73abfe3c MK |
320 | /* |
321 | * If we were offset positioning, | |
322 | * return to centerline. | |
323 | */ | |
324 | if (io->i_errcnt >= 16) { | |
325 | upaddr->upof = UPOF_FMT22; | |
326 | upaddr->upcs1 = UP_RTC|UP_GO; | |
f75b5a26 | 327 | upwaitdry(upaddr); |
73abfe3c | 328 | } |
31fec9db | 329 | return (rv); |
258a5c40 SL |
330 | } |
331 | ||
f75b5a26 MK |
332 | upwaitrdy(upaddr) |
333 | register struct updevice *upaddr; | |
334 | { | |
335 | do { | |
336 | DELAY(25); | |
337 | } while ((upaddr->upcs1 & UP_RDY) == 0); | |
338 | } | |
339 | ||
340 | upwaitdry(upaddr) | |
341 | register struct updevice *upaddr; | |
342 | { | |
343 | while ((upaddr->upds&UPDS_DRY) == 0) | |
344 | DELAY(25); | |
345 | } | |
346 | ||
233fc5c1 | 347 | #ifndef SMALL |
258a5c40 | 348 | /* |
d483c0fd KB |
349 | * Correct an ECC error, and restart the i/o to complete the transfer (if |
350 | * necessary). This is quite complicated because the transfer may be going | |
351 | * to an odd memory address base and/or across a page boundary. | |
258a5c40 | 352 | */ |
0839bdeb | 353 | upecc(io, flag) |
258a5c40 SL |
354 | register struct iob *io; |
355 | int flag; | |
356 | { | |
c48789a9 KB |
357 | register i, unit; |
358 | register struct up_softc *sc; | |
359 | register struct updevice *up; | |
d483c0fd | 360 | register struct disklabel *lp; |
258a5c40 | 361 | caddr_t addr; |
6796f4df | 362 | int bn, twc, npf, mask, cn, tn, sn; |
b8ca3ab9 | 363 | daddr_t bbn; |
258a5c40 SL |
364 | |
365 | /* | |
b4736392 SL |
366 | * Npf is the number of sectors transferred |
367 | * before the sector containing the ECC error; | |
368 | * bn is the current block number. | |
258a5c40 | 369 | */ |
c48789a9 KB |
370 | unit = io->i_unit; |
371 | sc = &up_softc[io->i_adapt][io->i_ctlr][unit]; | |
d483c0fd | 372 | lp = &uplabel[io->i_adapt][io->i_ctlr][unit]; |
b2291f86 | 373 | up = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]); |
b8ca3ab9 | 374 | twc = up->upwc; |
b4736392 | 375 | npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz; |
73abfe3c MK |
376 | if (flag == ECC) |
377 | npf--; | |
31fec9db | 378 | if (sc->debug & UPF_ECCDEBUG) |
3beb607b SL |
379 | printf("npf=%d mask=0x%x ec1=%d wc=%d\n", |
380 | npf, up->upec2, up->upec1, twc); | |
1f4919da | 381 | bn = io->i_bn + npf; |
d483c0fd KB |
382 | cn = bn / lp->d_secpercyl; |
383 | sn = bn % lp->d_secpercyl; | |
384 | tn = sn / lp->d_nsectors; | |
385 | sn = sn % lp->d_nsectors; | |
b4736392 | 386 | |
258a5c40 | 387 | /* |
b4736392 | 388 | * ECC correction. |
258a5c40 SL |
389 | */ |
390 | if (flag == ECC) { | |
31fec9db | 391 | int bit, o; |
3ab40097 | 392 | |
258a5c40 | 393 | mask = up->upec2; |
dda2842d | 394 | printf("up%d: soft ecc sn%d\n", unit, bn); |
31fec9db MK |
395 | for (i = mask, bit = 0; i; i >>= 1) |
396 | if (i & 1) | |
397 | bit++; | |
398 | if (bit > sc->ecclim) { | |
399 | printf("%d-bit error\n", bit); | |
400 | return (1); | |
401 | } | |
258a5c40 | 402 | /* |
1f4919da SL |
403 | * Compute the byte and bit position of |
404 | * the error. o is the byte offset in | |
405 | * the transfer at which the correction | |
406 | * applied. | |
258a5c40 SL |
407 | */ |
408 | i = up->upec1 - 1; /* -1 makes 0 origin */ | |
3beb607b SL |
409 | bit = i & 07; |
410 | o = (i & ~07) >> 3; | |
258a5c40 SL |
411 | up->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
412 | /* | |
b4736392 SL |
413 | * Correct while possible bits remain of mask. |
414 | * Since mask contains 11 bits, we continue while | |
415 | * the bit offset is > -11. Also watch out for | |
416 | * end of this block and the end of the transfer. | |
258a5c40 | 417 | */ |
1f4919da | 418 | while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) { |
258a5c40 | 419 | /* |
b4736392 | 420 | * addr = |
1f4919da | 421 | * (base address of transfer) + |
b4736392 SL |
422 | * (# sectors transferred before the error) * |
423 | * (sector size) + | |
1f4919da | 424 | * (byte offset to incorrect data) |
258a5c40 | 425 | */ |
1f4919da | 426 | addr = io->i_ma + (npf * sectsiz) + o; |
1f4919da SL |
427 | /* |
428 | * No data transfer occurs with a write check, | |
429 | * so don't correct the resident copy of data. | |
430 | */ | |
dda2842d | 431 | if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { |
31fec9db | 432 | if (sc->debug & UPF_ECCDEBUG) |
dda2842d SL |
433 | printf("addr=0x%x old=0x%x ", addr, |
434 | (*addr&0xff)); | |
b8ca3ab9 | 435 | *addr ^= (mask << bit); |
31fec9db | 436 | if (sc->debug & UPF_ECCDEBUG) |
dda2842d SL |
437 | printf("new=0x%x\n", (*addr&0xff)); |
438 | } | |
1f4919da | 439 | o++, bit -= 8; |
73abfe3c | 440 | } |
3ab40097 SL |
441 | return (0); |
442 | } | |
b4736392 SL |
443 | |
444 | /* | |
445 | * Bad sector forwarding. | |
446 | */ | |
3ab40097 | 447 | if (flag == BSE) { |
258a5c40 | 448 | /* |
b4736392 SL |
449 | * If not in bad sector table, |
450 | * indicate a hard error to caller. | |
258a5c40 | 451 | */ |
258a5c40 | 452 | up->upcs1 = UP_TRE|UP_DCLR|UP_GO; |
c48789a9 | 453 | if ((bbn = isbad(&upbad[io->i_adapt][io->i_ctlr][unit], cn, tn, sn)) < 0) |
3ab40097 | 454 | return (1); |
d483c0fd KB |
455 | bbn = (lp->d_ncylinders * lp->d_secpercyl) - |
456 | lp->d_nsectors - 1 - bbn; | |
b8ca3ab9 | 457 | twc = up->upwc + sectsiz; |
3ab40097 | 458 | up->upwc = - (sectsiz / sizeof (short)); |
31fec9db | 459 | if (sc->debug & UPF_BSEDEBUG) |
dda2842d | 460 | printf("revector sn %d to %d\n", sn, bbn); |
258a5c40 | 461 | /* |
b4736392 SL |
462 | * Clear the drive & read the replacement |
463 | * sector. If this is in the middle of a | |
464 | * transfer, then set up the controller | |
465 | * registers in a normal fashion. | |
466 | * The UNIBUS address need not be changed. | |
467 | */ | |
f75b5a26 | 468 | upwaitrdy(up); |
d483c0fd | 469 | if (upstart(io, bbn, lp)) |
b8ca3ab9 HS |
470 | return (1); /* error */ |
471 | io->i_errcnt = 0; /* success */ | |
f75b5a26 | 472 | upwaitrdy(up); |
3beb607b SL |
473 | if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) { |
474 | up->upwc = twc - sectsiz; | |
b8ca3ab9 | 475 | return (1); |
258a5c40 SL |
476 | } |
477 | } | |
960ade39 | 478 | if (twc) |
258a5c40 | 479 | up->upwc = twc; |
b8ca3ab9 | 480 | return (0); |
258a5c40 | 481 | } |
c48789a9 | 482 | #endif /* !SMALL */ |
258a5c40 | 483 | |
d483c0fd | 484 | upstart(io, bn, lp) |
0839bdeb SL |
485 | register struct iob *io; |
486 | daddr_t bn; | |
d483c0fd | 487 | register struct disklabel *lp; |
258a5c40 | 488 | { |
c48789a9 KB |
489 | register struct updevice *upaddr; |
490 | register struct up_softc *sc; | |
258a5c40 SL |
491 | int sn, tn; |
492 | ||
b2291f86 | 493 | upaddr = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]); |
c48789a9 | 494 | sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit]; |
d483c0fd KB |
495 | sn = bn % lp->d_secpercyl; |
496 | tn = sn / lp->d_nsectors; | |
497 | sn = sn % lp->d_nsectors; | |
498 | upaddr->updc = bn / lp->d_secpercyl; | |
258a5c40 | 499 | upaddr->upda = (tn << 8) + sn; |
b8ca3ab9 | 500 | switch (io->i_flgs & F_TYPEMASK) { |
0839bdeb SL |
501 | |
502 | case F_RDDATA: | |
503 | upaddr->upcs1 = UP_RCOM|UP_GO; | |
504 | break; | |
505 | ||
506 | case F_WRDATA: | |
507 | upaddr->upcs1 = UP_WCOM|UP_GO; | |
258a5c40 | 508 | break; |
0839bdeb | 509 | |
233fc5c1 | 510 | #ifndef SMALL |
c48789a9 | 511 | case F_HDR|F_RDDATA: |
0839bdeb SL |
512 | upaddr->upcs1 = UP_RHDR|UP_GO; |
513 | break; | |
514 | ||
515 | case F_HDR|F_WRDATA: | |
516 | upaddr->upcs1 = UP_WHDR|UP_GO; | |
258a5c40 | 517 | break; |
0839bdeb SL |
518 | |
519 | case F_CHECK|F_WRDATA: | |
520 | case F_CHECK|F_RDDATA: | |
258a5c40 SL |
521 | upaddr->upcs1 = UP_WCDATA|UP_GO; |
522 | break; | |
0839bdeb SL |
523 | |
524 | case F_HCHECK|F_WRDATA: | |
525 | case F_HCHECK|F_RDDATA: | |
258a5c40 SL |
526 | upaddr->upcs1 = UP_WCHDR|UP_GO; |
527 | break; | |
233fc5c1 | 528 | #endif |
0839bdeb | 529 | |
258a5c40 | 530 | default: |
0839bdeb SL |
531 | io->i_error = ECMD; |
532 | io->i_flgs &= ~F_TYPEMASK; | |
533 | return (1); | |
258a5c40 | 534 | } |
0839bdeb | 535 | return (0); |
258a5c40 SL |
536 | } |
537 | ||
c48789a9 | 538 | #ifndef SMALL |
0839bdeb SL |
539 | /*ARGSUSED*/ |
540 | upioctl(io, cmd, arg) | |
541 | struct iob *io; | |
542 | int cmd; | |
543 | caddr_t arg; | |
544 | { | |
c48789a9 | 545 | register struct up_softc *sc; |
b8ca3ab9 | 546 | |
d483c0fd | 547 | sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit]; |
b8ca3ab9 | 548 | switch(cmd) { |
dda2842d | 549 | case SAIODEBUG: |
31fec9db MK |
550 | sc->debug = (int)arg; |
551 | break; | |
b8ca3ab9 | 552 | case SAIODEVDATA: |
d483c0fd KB |
553 | *(struct disklabel *)arg = |
554 | uplabel[io->i_adapt][io->i_ctlr][io->i_unit]; | |
31fec9db | 555 | break; |
31fec9db | 556 | case SAIOGBADINFO: |
d483c0fd KB |
557 | *(struct dkbad *)arg = |
558 | upbad[io->i_adapt][io->i_ctlr][io->i_unit]; | |
31fec9db | 559 | break; |
31fec9db MK |
560 | case SAIOECCLIM: |
561 | sc->ecclim = (int)arg; | |
562 | break; | |
31fec9db MK |
563 | case SAIORETRIES: |
564 | sc->retries = (int)arg; | |
565 | break; | |
31fec9db MK |
566 | default: |
567 | return (ECMD); | |
b8ca3ab9 | 568 | } |
31fec9db | 569 | return (0); |
b8ca3ab9 | 570 | } |
c48789a9 | 571 | #endif /* !SMALL */ |