Commit | Line | Data |
---|---|---|
8898023e | 1 | /* hp.c 4.3 83/01/18 */ |
63c82e3f HS |
2 | |
3 | /* | |
4 | * RP??/RM?? disk driver | |
5 | * with ECC handling and bad block forwarding. | |
6 | * Also supports header io operations and | |
7 | * commands to write check header and data. | |
8 | */ | |
9 | ||
10 | #include "../h/param.h" | |
11 | #include "../h/inode.h" | |
12 | #include "../h/fs.h" | |
13 | #include "../h/dkbad.h" | |
14 | ||
15 | #include "../vax/pte.h" | |
16 | #include "../vaxmba/hpreg.h" | |
17 | #include "../vaxmba/mbareg.h" | |
18 | ||
19 | #include "saio.h" | |
20 | #include "savax.h" | |
21 | ||
22 | #define MASKREG(reg) ((reg)&0xffff) | |
23 | ||
24 | #define MAXBADDESC 126 | |
25 | #define SECTSIZ 512 /* sector size in bytes */ | |
26 | #define HDRSIZ 4 /* number of bytes in sector header */ | |
27 | #define MAXECC 5 /* the maximum number of bad bits accepted in | |
28 | * an ecc error when F_ECCLM is set */ | |
29 | ||
30 | char hp_type[MAXNMBA*8] = { 0 }; | |
31 | ||
32 | /* THIS SHOULD BE READ IN OFF THE PACK, PER DRIVE */ | |
33 | short hp6_off[8] = { 0, 38, 0, -1, -1, -1, 118, -1 }; | |
34 | short rm3_off[8] = { 0, 100, 0, -1, -1, -1, 310, -1 }; | |
35 | short rm5_off[8] = { 0, 27, 0, 562, 589, 681, 562, 82 }; | |
36 | short rm80_off[8] = { 0, 37, 0, -1, -1, -1, 115, 305 }; | |
37 | short hp7_off[8] = { 0, 10, 0, 330, 340, 500, 330, 50 }; | |
38 | short ml_off[8] = { 0, -1, -1, -1, -1, -1, -1, -1 }; | |
39 | short si9775_off[8] = { 0, 13, 0, -1, -1, -1, 40, 441 }; | |
40 | short si9730_off[8] = { 0, 50, 0, -1, -1, -1, -1, 155 }; | |
41 | short hpam_off[8] = { 0, 32, 0, 668, 723, 778, 668, 98 }; | |
42 | /* END SHOULD BE READ IN */ | |
43 | ||
44 | short hptypes[] = | |
45 | { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, MBDT_RP05, MBDT_RP07, | |
46 | MBDT_ML11A, MBDT_ML11B, -1/*9755*/, -1/*9730*/, -1/*Capr*/, MBDT_RM02, 0}; | |
47 | ||
48 | #define RP06 (hptypes[UNITTODRIVE(unit)] <= MBDT_RP06) | |
49 | #define ML11 (hptypes[UNITTODRIVE(unit)] <= MBDT_ML11A) | |
50 | #define RM80 (hptypes[UNITTODRIVE(unit)] <= MBDT_RM80) | |
51 | ||
52 | u_char hp_offset[16] = { | |
53 | HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, | |
54 | HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, | |
55 | HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, | |
56 | 0, 0, 0, 0, | |
57 | }; | |
58 | ||
3857f7f3 | 59 | struct st hpst[] = { |
63c82e3f HS |
60 | 32, 5, 32*5, 823, rm3_off, /* RM03 */ |
61 | 32, 19, 32*19, 823, rm5_off, /* RM05 */ | |
62 | 22, 19, 22*19, 815, hp6_off, /* RP06 */ | |
63 | 31, 14, 31*14, 559, rm80_off, /* RM80 */ | |
64 | 22, 19, 22*19, 411, hp6_off, /* RP06 */ | |
65 | 50, 32, 50*32, 630, hp7_off, /* RP07 */ | |
66 | 1, 1, 1, 1, ml_off, /* ML11A */ | |
67 | 1, 1, 1, 1, ml_off, /* ML11B */ | |
68 | 32, 40, 32*40, 843, si9775_off, /* 9775 */ | |
69 | 32, 10, 32*10, 823, si9730_off, /* 9730 */ | |
70 | 32, 16, 32*16, 1024, hpam_off, /* AMPEX capricorn */ | |
71 | 1, 1, 1, 1, 0, /* rm02 - not used */ | |
72 | }; | |
73 | struct dkbad hpbad[MAXNMBA*8]; | |
74 | int sectsiz; | |
75 | ||
76 | hpopen(io) | |
77 | register struct iob *io; | |
78 | { | |
79 | register unit = io->i_unit; | |
80 | struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); | |
3857f7f3 | 81 | register struct st *st; |
63c82e3f HS |
82 | |
83 | mbainit(UNITTOMBA(unit)); | |
84 | if (hp_type[unit] == 0) { | |
85 | register type = hpaddr->hpdt & MBDT_TYPE; | |
86 | register int i; | |
87 | struct iob tio; | |
88 | ||
89 | for (i = 0; hptypes[i]; i++) | |
90 | if (hptypes[i] == type) | |
91 | goto found; | |
92 | _stop("unknown drive type"); | |
93 | found: | |
94 | switch (i) { | |
95 | case 0: case 1: { /* rm03 or rm05 */ | |
96 | register hpsn = hpaddr->hpsn; | |
97 | ||
98 | if ((hpsn & SIMB_LU) != unit) | |
99 | break; | |
100 | switch ((hpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05)) { | |
101 | case SI9775D: | |
102 | i = 8; /* si9775 */ | |
103 | break; | |
104 | case SI9730D: | |
105 | i = 9; /* si9730 */ | |
106 | break; | |
107 | case SI9766: | |
108 | i = 1; /* rm05 */ | |
109 | hpaddr->hpcs1 = HP_RECAL|HP_GO; | |
110 | DELAY(100000); | |
111 | break; | |
112 | case SI9762: | |
113 | i = 0; /* rm03 */ | |
114 | break; | |
115 | } | |
116 | break; | |
117 | } | |
118 | ||
119 | case 11: /* rm02 */ | |
120 | hpaddr->hpcs1 = HP_NOP; | |
121 | hpaddr->hphr = HPHR_MAXTRAK; | |
122 | if (MASKREG(hpaddr->hphr) == 15) | |
123 | i = 10; /* ampex capricorn */ | |
124 | else | |
125 | i = 0; /* rm03 */ | |
126 | break; | |
127 | ||
128 | case 6: case 7: /* ml11a ml11b */ | |
129 | i = 6; /* ml11a */ | |
130 | break; | |
131 | } | |
132 | hp_type[unit] = i; | |
133 | /* | |
134 | * Read in the bad sector table: | |
135 | * copy the contents of the io structure | |
136 | * to tio for use during the bb pointer | |
137 | * read operation. | |
138 | */ | |
139 | st = &hpst[hp_type[unit]]; | |
140 | tio = *io; | |
141 | tio.i_bn = st->nspc * st->ncyl - st->nsect; | |
142 | tio.i_ma = (char *)&hpbad[tio.i_unit]; | |
143 | tio.i_cc = sizeof (hpbad); | |
144 | tio.i_flgs |= F_RDDATA; | |
145 | for (i = 0; i < 5; i++) { | |
146 | if (hpstrategy(&tio, READ) == sizeof (hpbad)) | |
147 | break; | |
148 | tio.i_bn += 2; | |
149 | } | |
150 | if (i == 5) { | |
151 | printf("Unable to read bad sector table\n"); | |
152 | for (i = 0; i < MAXBADDESC; i++) { | |
153 | hpbad[unit].bt_bad[i].bt_cyl = -1; | |
154 | hpbad[unit].bt_bad[i].bt_trksec = -1; | |
155 | } | |
156 | } | |
157 | } | |
158 | if (io->i_boff < 0 || io->i_boff > 7 || | |
159 | st->off[io->i_boff]== -1) | |
160 | _stop("hp bad minor"); | |
161 | io->i_boff = st->off[io->i_boff] * st->nspc; | |
162 | } | |
163 | ||
164 | hpstrategy(io, func) | |
165 | register struct iob *io; | |
166 | { | |
167 | register unit = io->i_unit; | |
168 | struct mba_regs *mba = mbamba(unit); | |
169 | daddr_t bn; | |
170 | struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); | |
3857f7f3 | 171 | struct st *st = &hpst[hp_type[unit]]; |
63c82e3f HS |
172 | int cn, tn, sn, bytecnt, bytesleft; |
173 | daddr_t startblock; | |
174 | char *membase; | |
175 | int er1, er2, hprecal; | |
176 | ||
177 | sectsiz = SECTSIZ; | |
178 | if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) | |
179 | sectsiz += HDRSIZ; | |
180 | if ((hpaddr->hpds & HPDS_VV) == 0) { | |
181 | hpaddr->hpcs1 = HP_DCLR|HP_GO; | |
182 | hpaddr->hpcs1 = HP_PRESET|HP_GO; | |
183 | if (hp_type[unit] != 6) /* any but ml11 */ | |
184 | hpaddr->hpof = HPOF_FMT22; | |
185 | } | |
186 | io->i_errcnt = 0; | |
187 | bytecnt = io->i_cc; | |
188 | membase = io->i_ma; | |
189 | startblock = io->i_bn; | |
190 | hprecal = 1; | |
191 | readmore: | |
192 | bn = io->i_bn; | |
193 | cn = bn/st->nspc; | |
194 | sn = bn%st->nspc; | |
195 | tn = sn/st->nsect; | |
196 | sn = sn%st->nsect; | |
197 | ||
198 | while ((hpaddr->hpds & HPDS_DRY) == 0) | |
199 | ; | |
200 | if (hp_type[unit] == 6) /* ml11 */ | |
201 | hpaddr->hpda = bn; | |
202 | else { | |
203 | hpaddr->hpdc = cn; | |
204 | hpaddr->hpda = (tn << 8) + sn; | |
205 | } | |
206 | if (mbastart(io, func) != 0) /* start transfer */ | |
207 | return (-1); | |
208 | ||
209 | while ((hpaddr->hpds & HPDS_DRY) == 0) | |
210 | ; | |
211 | if (((hpaddr->hpds&HPDS_ERR) | (mba->mba_sr&MBSR_EBITS)) == 0 ) | |
212 | return(bytecnt); | |
213 | ||
214 | /* ------- error handling ------- */ | |
215 | ||
216 | if (bytesleft = MASKREG(mba->mba_bcr>>16)) | |
217 | bytesleft |= 0xffff0000; /* sign ext */ | |
218 | bn = io->i_bn + (io->i_cc + bytesleft)/sectsiz; | |
219 | cn = bn/st->nspc; | |
220 | sn = bn%st->nspc; | |
221 | tn = sn/st->nsect; | |
222 | sn = sn%st->nsect; | |
223 | er1 = MASKREG(hpaddr->hper1); | |
224 | er2 = MASKREG(hpaddr->hper2); | |
225 | #ifdef HPDEBUG | |
226 | printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", | |
227 | cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); | |
228 | printf("er1=%b er2=%b", | |
229 | er1, HPER1_BITS, | |
230 | er2, HPER2_BITS); | |
231 | printf("\n"); | |
232 | #endif | |
233 | if (er1 & HPER1_HCRC) { | |
234 | er1 &= ~(HPER1_HCE|HPER1_FER); | |
235 | er2 &= ~HPER2_BSE; | |
236 | } | |
237 | if (er1&HPER1_WLE) { | |
238 | printf("hp%d: write locked\n", unit); | |
239 | return(-1); | |
240 | } else if ((er1&0xffff) == HPER1_FER && RP06) { | |
241 | goto badsect; | |
242 | ||
243 | } else if (++io->i_errcnt > 27 || | |
244 | er1 & HPER1_HARD || | |
245 | (!ML11 && (er2 & HPER2_HARD))) { | |
246 | io->i_error = EHER; | |
247 | if ((mba->mba_sr & (MBSR_WCKUP | MBSR_WCKLWR)) != 0) | |
248 | io->i_error = EWCK; | |
249 | hard: | |
250 | io->i_errblk = bn; | |
251 | printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", | |
252 | cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); | |
253 | printf("er1=%b er2=%b", | |
254 | er1, HPER1_BITS, | |
255 | er2, HPER2_BITS); | |
256 | if (hpaddr->hpmr) | |
257 | printf(" mr=%o", hpaddr->hpmr&0xffff); | |
258 | if (hpaddr->hpmr2) | |
259 | printf(" mr2=%o", hpaddr->hpmr2&0xffff); | |
260 | printf("\n"); | |
261 | return(-1); | |
262 | ||
263 | } else if ((er2 & HPER2_BSE) && !ML11) { | |
264 | badsect: | |
265 | if ((io->i_flgs & F_NBSF) != 0) { | |
266 | io->i_error = EBSE; | |
267 | goto hard; | |
268 | } | |
269 | if (hpecc(io, BSE) == 0) | |
270 | goto success; | |
271 | else { | |
272 | io->i_error = EBSE; | |
273 | goto hard; | |
274 | } | |
275 | } else if (RM80 && er2&HPER2_SSE) { | |
276 | /* skip sector error */ | |
277 | (void) hpecc(io, SSE); | |
0cd55454 | 278 | startblock++; /* since one sector was skipped */ |
63c82e3f HS |
279 | goto success; |
280 | } else if ((er1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { | |
281 | if ( hpecc(io, ECC) == 0) | |
282 | goto success; | |
283 | else { | |
284 | io->i_error = EECC; | |
285 | return(1); | |
286 | } | |
287 | } else | |
288 | io->i_active = 0; /* force retry */ | |
289 | ||
290 | hpaddr->hpcs1 = HP_DCLR|HP_GO; | |
291 | while ((hpaddr->hpds & HPDS_DRY) == 0) | |
292 | ; | |
293 | if (ML11) { | |
294 | if (io->i_errcnt >= 16) | |
295 | goto hard; | |
296 | } else if (((io->i_errcnt&07) == 4) && (io->i_active == 0)) { | |
297 | hpaddr->hpcs1 = HP_RECAL|HP_GO; | |
298 | hprecal = 0; | |
299 | goto nextrecal; | |
300 | } | |
301 | switch (hprecal) { | |
302 | ||
303 | case 1: | |
304 | hpaddr->hpdc = cn; | |
305 | hpaddr->hpcs1 = HP_SEEK|HP_GO; | |
306 | goto nextrecal; | |
307 | case 2: | |
308 | if (io->i_errcnt < 16 || (func & READ) == 0) | |
309 | goto donerecal; | |
310 | hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; | |
311 | hpaddr->hpcs1 = HP_OFFSET|HP_GO; | |
312 | nextrecal: | |
313 | hprecal++; | |
314 | io->i_active = 1; | |
315 | goto try_again; | |
316 | donerecal: | |
317 | case 3: | |
318 | hprecal = 0; | |
319 | io->i_active = 0; | |
320 | goto try_again; | |
321 | } | |
322 | if (io->i_active) { | |
323 | if (io->i_errcnt >= 16) { | |
324 | hpaddr->hpcs1 = HP_RTC|HP_GO; | |
325 | while (hpaddr->hpds & HPDS_PIP) | |
326 | ; | |
327 | } | |
328 | } | |
329 | success: /* continue with the next block */ | |
330 | bn++; | |
331 | if ((bn-startblock) * sectsiz < bytecnt) { | |
332 | ||
333 | try_again: /* re-read same block */ | |
334 | io->i_bn = bn; | |
335 | mba->mba_sr = -1; | |
336 | io->i_ma = membase + (io->i_bn - startblock)*sectsiz; | |
337 | io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; | |
338 | #ifdef HPDEBUG | |
339 | printf("restart: bl %d, byte %d, mem 0x%x %d\n", | |
340 | io->i_bn, io->i_cc, io->i_ma, io->i_ma); | |
341 | #endif | |
342 | goto readmore; | |
343 | } | |
344 | return (bytecnt); | |
345 | } | |
346 | hpecc(io, flag) | |
347 | register struct iob *io; | |
348 | int flag; | |
349 | { | |
350 | register unit = io->i_unit; | |
351 | register struct mba_regs *mbp = mbamba(unit); | |
352 | register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); | |
3857f7f3 | 353 | register struct st *st = &hpst[hp_type[unit]]; |
63c82e3f HS |
354 | int npf; |
355 | int bn, cn, tn, sn; | |
356 | int bcr, tad; | |
357 | ||
358 | if (bcr = MASKREG(mbp->mba_bcr>>16)) | |
359 | bcr |= 0xffff0000; /* sxt */ | |
360 | npf = (bcr + io->i_cc)/sectsiz; /* number of sectors read */ | |
0cd55454 | 361 | bn = io->i_bn + npf; |
63c82e3f HS |
362 | switch (flag) { |
363 | case ECC: | |
364 | { | |
365 | register int i; | |
366 | caddr_t addr; | |
367 | int bit, byte, mask, ecccnt = 0; | |
368 | ||
0cd55454 | 369 | printf("hp%d: soft ecc sn%d\n", unit, bn); |
63c82e3f HS |
370 | mask = MASKREG(rp->hpec2); |
371 | i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ | |
372 | bit = i&07; | |
373 | i = (i&~07)>>3; | |
374 | byte = i; | |
375 | rp->hpcs1 = HP_DCLR | HP_GO; | |
376 | while (i <sectsiz && npf*sectsiz + i < io->i_cc && bit > -11) { | |
377 | addr = io->i_ma + (npf*sectsiz) + byte; | |
378 | #ifdef HPECCDEBUG | |
379 | printf("addr %x old:%x ",addr, (*addr&0xff)); | |
380 | #endif | |
381 | if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) | |
382 | *addr ^= (mask << bit); /* don't 'correct' mem- | |
383 | * ory during Wcheck */ | |
384 | #ifdef HPECCDEBUG | |
385 | printf("new:%x\n",(*addr&0xff)); | |
386 | #endif | |
387 | byte++; | |
388 | i++; | |
389 | bit -= 8; | |
390 | if ((ecccnt++>=MAXECC) && ((io->i_flgs&F_ECCLM) != 0)) | |
391 | return(1); | |
392 | } | |
393 | return(0); | |
394 | } | |
395 | ||
0cd55454 HS |
396 | case SSE: /* skip sector error */ |
397 | /* set skip-sector-inhibit and read next sector */ | |
63c82e3f | 398 | rp->hpcs1 = HP_DCLR | HP_GO; |
0cd55454 HS |
399 | while(rp->hpds & HPDS_DRY == 0) |
400 | ; /* avoid RMR error */ | |
63c82e3f | 401 | rp->hpof |= HPOF_SSEI; |
63c82e3f HS |
402 | return(0); |
403 | ||
404 | #ifndef NOBADSECT | |
405 | case BSE: | |
406 | #ifdef HPDEBUG | |
407 | printf("hpecc: BSE @ bn %d\n", bn); | |
408 | #endif | |
409 | rp->hpcs1 = HP_DCLR | HP_GO; | |
0cd55454 | 410 | bcr += sectsiz; |
63c82e3f | 411 | tad = rp->hpda; |
0cd55454 | 412 | if ((bn = isbad(&hpbad[unit], bn/st->nspc,tad>>8,tad&0x7f)) < 0) |
63c82e3f HS |
413 | return(1); |
414 | bn = st->ncyl*st->nspc - st->nsect - 1 - bn; | |
415 | cn = bn/st->nspc; | |
416 | sn = bn%st->nspc; | |
417 | tn = sn/st->nsect; | |
418 | sn %= st->nsect; | |
0cd55454 HS |
419 | io->i_cc = -sectsiz; |
420 | io->i_ma += ((io->i_bn + npf -1)*sectsiz); | |
63c82e3f HS |
421 | #ifdef HPDEBUG |
422 | printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); | |
423 | #endif | |
424 | rp->hpdc = cn; | |
425 | rp->hpda = (tn<<8) + sn; | |
426 | mbp->mba_sr = -1; | |
427 | mbastart(io,io->i_flgs); | |
428 | io->i_errcnt = 0; /* error has been corrected */ | |
63c82e3f HS |
429 | if (rp->hpds&HPDS_ERR) |
430 | return(1); | |
431 | else | |
432 | return(0); | |
433 | } | |
434 | } | |
435 | /*ARGSUSED*/ | |
436 | hpioctl(io, cmd, arg) | |
437 | struct iob *io; | |
438 | int cmd; | |
439 | caddr_t arg; | |
440 | { | |
441 | ||
3857f7f3 | 442 | struct st *st = &hpst[hp_type[io->i_unit]], *tmp; |
63c82e3f | 443 | struct mba_drv *drv = mbadrv(io->i_unit); |
63c82e3f HS |
444 | |
445 | switch(cmd) { | |
446 | ||
447 | case SAIODEVDATA: | |
448 | if ((drv->mbd_dt&MBDT_TAP) == 0) { | |
3857f7f3 HS |
449 | tmp = (struct st *)arg; |
450 | *tmp = *st; | |
63c82e3f HS |
451 | return(0); |
452 | } | |
453 | else | |
454 | return(ECMD); | |
455 | ||
456 | default: | |
457 | return (ECMD); | |
458 | } | |
459 | } | |
460 |