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