Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
c283df85 | 2 | * @(#)uda.c 6.22 (Berkeley) %G% |
da7c5cc6 KM |
3 | */ |
4 | ||
2f961121 MK |
5 | /************************************************************************ |
6 | * * | |
7 | * Copyright (c) 1983 by * | |
8 | * Digital Equipment Corporation, Maynard, MA * | |
9 | * All rights reserved. * | |
10 | * * | |
11 | ************************************************************************/ | |
12 | /* | |
13 | * uda.c - UDA50A Driver | |
2f961121 | 14 | * |
cb6ff96f | 15 | * decvax!rich |
2f961121 | 16 | */ |
db738443 | 17 | |
2f961121 MK |
18 | #define DEBUG |
19 | #define UDADEVNUM (9) /* entry in bdevsw */ | |
db738443 | 20 | #include "ra.h" |
e4b02d7d | 21 | #if NUDA > 0 |
db738443 BJ |
22 | /* |
23 | * UDA50/RAxx disk device driver | |
24 | * | |
25 | * Restrictions: | |
2f961121 | 26 | * Unit numbers must be less than 8. |
db738443 | 27 | */ |
961945a8 | 28 | #include "../machine/pte.h" |
db738443 | 29 | |
2f961121 MK |
30 | #include "param.h" |
31 | #include "systm.h" | |
32 | #include "buf.h" | |
33 | #include "conf.h" | |
34 | #include "dir.h" | |
35 | #include "user.h" | |
36 | #include "map.h" | |
37 | #include "vm.h" | |
38 | #include "dk.h" | |
39 | #include "cmap.h" | |
40 | #include "uio.h" | |
db738443 | 41 | |
896962b1 | 42 | #include "../vax/cpu.h" |
2f961121 MK |
43 | #include "ubareg.h" |
44 | #include "ubavar.h" | |
45 | #include "../vax/mtpr.h" | |
bc3a8383 | 46 | |
2f961121 MK |
47 | #define TENSEC (1000) |
48 | ||
49 | #define NRSPL2 3 /* log2 number of response packets */ | |
50 | #define NCMDL2 3 /* log2 number of command packets */ | |
51 | #define NRSP (1<<NRSPL2) | |
52 | #define NCMD (1<<NCMDL2) | |
bc3a8383 | 53 | |
896962b1 | 54 | #include "../vaxuba/udareg.h" |
896962b1 | 55 | #include "../vax/mscp.h" |
db738443 | 56 | |
2f961121 MK |
57 | |
58 | struct uda_softc { | |
59 | short sc_state; /* state of controller */ | |
60 | short sc_mapped; /* Unibus map allocated for uda struct? */ | |
61 | int sc_ubainfo; /* Unibus mapping info */ | |
62 | struct uda *sc_uda; /* Unibus address of uda struct */ | |
63 | int sc_ivec; /* interrupt vector address */ | |
64 | short sc_credits; /* transfer credits */ | |
65 | short sc_lastcmd; /* pointer into command ring */ | |
66 | short sc_lastrsp; /* pointer into response ring */ | |
67 | } uda_softc[NUDA]; | |
db738443 | 68 | struct uda { |
2f961121 MK |
69 | struct udaca uda_ca; /* communications area */ |
70 | struct mscp uda_rsp[NRSP]; /* response packets */ | |
71 | struct mscp uda_cmd[NCMD]; /* command packets */ | |
db738443 BJ |
72 | } uda[NUDA]; |
73 | ||
dac559fa JB |
74 | #define udunit(dev) (minor(dev) >> 3) |
75 | ||
db738443 BJ |
76 | /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ |
77 | struct size { | |
2f961121 MK |
78 | daddr_t nblocks; |
79 | daddr_t blkoff; | |
80 | } ra25_sizes[8] = { | |
81 | 15884, 0, /* A=blk 0 thru 15883 */ | |
82 | 10032, 15884, /* B=blk 15884 thru 49323 */ | |
83 | -1, 0, /* C=blk 0 thru end */ | |
84 | 0, 0, /* D=blk 340670 thru 356553 */ | |
85 | 0, 0, /* E=blk 356554 thru 412489 */ | |
86 | 0, 0, /* F=blk 412490 thru end */ | |
87 | -1, 25916, /* G=blk 49324 thru 131403 */ | |
88 | 0, 0, /* H=blk 131404 thru end */ | |
d9a8ab76 MK |
89 | }, rd52_sizes[8] = { |
90 | 15884, 0, /* A=blk 0 thru 15883 */ | |
91 | 9766, 15884, /* B=blk 15884 thru 25649 */ | |
92 | -1, 0, /* C=blk 0 thru end */ | |
93 | 0, 0, /* D=unused */ | |
94 | 0, 0, /* E=unused */ | |
95 | 0, 0, /* F=unused */ | |
96 | -1, 25650, /* G=blk 25650 thru end */ | |
97 | 0, 0, /* H=unused */ | |
98 | }, rd53_sizes[8] = { | |
99 | 15884, 0, /* A=blk 0 thru 15883 */ | |
100 | 33440, 15884, /* B=blk 15884 thru 49323 */ | |
101 | -1, 0, /* C=blk 0 thru end */ | |
102 | 0, 0, /* D=unused */ | |
103 | 33440, 0, /* E=blk 0 thru 33439 */ | |
104 | -1, 33440, /* F=blk 33440 thru end */ | |
105 | -1, 49324, /* G=blk 49324 thru end */ | |
106 | -1, 15884, /* H=blk 15884 thru end */ | |
2f961121 | 107 | }, ra60_sizes[8] = { |
4e5b5f0a KM |
108 | 15884, 0, /* A=sectors 0 thru 15883 */ |
109 | 33440, 15884, /* B=sectors 15884 thru 49323 */ | |
110 | 400176, 0, /* C=sectors 0 thru 400175 */ | |
111 | 82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */ | |
112 | 268772, 131404, /* 4.2 H => E=sectors 131404 thru 400175 */ | |
113 | 350852, 49324, /* F=sectors 49324 thru 400175 */ | |
114 | 157570, 242606, /* UCB G => G=sectors 242606 thru 400175 */ | |
115 | 193282, 49324, /* UCB H => H=sectors 49324 thru 242605 */ | |
2f961121 | 116 | }, ra80_sizes[8] = { |
4e5b5f0a KM |
117 | 15884, 0, /* A=sectors 0 thru 15883 */ |
118 | 33440, 15884, /* B=sectors 15884 thru 49323 */ | |
119 | 242606, 0, /* C=sectors 0 thru 242605 */ | |
e4b02d7d | 120 | 0, 0, /* D=unused */ |
4e5b5f0a KM |
121 | 193282, 49324, /* UCB H => E=sectors 49324 thru 242605 */ |
122 | 82080, 49324, /* 4.2 G => F=sectors 49324 thru 131403 */ | |
123 | 192696, 49910, /* G=sectors 49910 thru 242605 */ | |
124 | 111202, 131404, /* 4.2 H => H=sectors 131404 thru 242605 */ | |
2f961121 | 125 | }, ra81_sizes[8] ={ |
4e5b5f0a KM |
126 | /* |
127 | * These are the new standard partition sizes for ra81's. | |
cb6ff96f | 128 | * An RA_COMPAT system is compiled with D, E, and F corresponding |
4e5b5f0a KM |
129 | * to the 4.2 partitions for G, H, and F respectively. |
130 | */ | |
131 | #ifndef UCBRA | |
132 | 15884, 0, /* A=sectors 0 thru 15883 */ | |
133 | 66880, 16422, /* B=sectors 16422 thru 83301 */ | |
134 | 891072, 0, /* C=sectors 0 thru 891071 */ | |
cb6ff96f | 135 | #ifdef RA_COMPAT |
4e5b5f0a KM |
136 | 82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */ |
137 | 759668, 131404, /* 4.2 H => E=sectors 131404 thru 891071 */ | |
138 | 478582, 412490, /* 4.2 F => F=sectors 412490 thru 891071 */ | |
139 | #else | |
140 | 15884, 375564, /* D=sectors 375564 thru 391447 */ | |
141 | 307200, 391986, /* E=sectors 391986 thru 699185 */ | |
142 | 191352, 699720, /* F=sectors 699720 thru 891071 */ | |
cb6ff96f | 143 | #endif RA_COMPAT |
4e5b5f0a KM |
144 | 515508, 375564, /* G=sectors 375564 thru 891071 */ |
145 | 291346, 83538, /* H=sectors 83538 thru 374883 */ | |
146 | ||
147 | /* | |
148 | * These partitions correspond to the sizes used by sites at Berkeley, | |
149 | * and by those sites that have received copies of the Berkeley driver | |
150 | * with deltas 6.2 or greater (11/15/83). | |
151 | */ | |
152 | #else UCBRA | |
153 | ||
154 | 15884, 0, /* A=sectors 0 thru 15883 */ | |
155 | 33440, 15884, /* B=sectors 15884 thru 49323 */ | |
156 | 891072, 0, /* C=sectors 0 thru 891071 */ | |
157 | 15884, 242606, /* D=sectors 242606 thru 258489 */ | |
158 | 307200, 258490, /* E=sectors 258490 thru 565689 */ | |
159 | 325382, 565690, /* F=sectors 565690 thru 891071 */ | |
160 | 648466, 242606, /* G=sectors 242606 thru 891071 */ | |
161 | 193282, 49324, /* H=sectors 49324 thru 242605 */ | |
162 | ||
163 | #endif UCBRA | |
db738443 | 164 | }; |
2f961121 MK |
165 | |
166 | struct ra_info { | |
167 | struct size *ra_sizes; /* Partion tables for drive */ | |
168 | daddr_t radsize; /* Max user size form online pkt */ | |
169 | unsigned ratype; /* Drive type int field */ | |
170 | unsigned rastatus; /* Command status from */ | |
171 | /* last onlin or GTUNT */ | |
172 | } ra_info[NRA]; | |
173 | ||
174 | ||
db738443 | 175 | /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ |
2f961121 MK |
176 | struct uba_ctlr *udminfo[NUDA]; |
177 | struct uba_device *uddinfo[NRA]; | |
178 | struct uba_device *udip[NUDA][8]; /* 8 == max number of drives */ | |
179 | struct buf rudbuf[NRA]; | |
180 | struct buf udutab[NRA]; | |
181 | struct buf udwtab[NUDA]; /* I/O wait queue, per controller */ | |
db738443 | 182 | |
a8e727a7 | 183 | |
2f961121 | 184 | int udamicro[NUDA]; /* to store microcode level */ |
1b58ff00 | 185 | int udaburst[NUDA] = { 0 }; /* DMA burst size, 0 is default */ |
db738443 | 186 | |
db738443 | 187 | |
2f961121 MK |
188 | /* |
189 | * Controller states | |
190 | */ | |
191 | #define S_IDLE 0 /* hasn't been initialized */ | |
192 | #define S_STEP1 1 /* doing step 1 init */ | |
193 | #define S_STEP2 2 /* doing step 2 init */ | |
194 | #define S_STEP3 3 /* doing step 3 init */ | |
195 | #define S_SCHAR 4 /* doing "set controller characteristics" */ | |
196 | #define S_RUN 5 /* running */ | |
197 | ||
198 | ||
199 | int udaerror = 0; /* causes hex dump of packets */ | |
200 | int udadebug = 0; | |
201 | int uda_cp_wait = 0; /* Something to wait on for command */ | |
202 | /* packets and or credits. */ | |
203 | int wakeup(); | |
204 | extern int hz; /* Should find the right include */ | |
205 | #ifdef DEBUG | |
206 | #define printd if (udadebug) printf | |
207 | #define printd10 if(udadebug >= 10) printf | |
208 | #endif | |
209 | #define mprintf printf /* temporary JG hack until Rich fixes*/ | |
210 | ||
211 | int udprobe(), udslave(), udattach(), udintr(); | |
212 | struct mscp *udgetcp(); | |
213 | ||
214 | u_short udstd[] = { 0772150, 0772550, 0777550, 0 }; | |
215 | struct uba_driver udadriver = | |
db738443 | 216 | { udprobe, udslave, udattach, 0, udstd, "ra", uddinfo, "uda", udminfo, 0 }; |
db738443 | 217 | |
2f961121 MK |
218 | #define b_qsize b_resid /* queue size per drive, in udutab */ |
219 | #define b_ubinfo b_resid /* Unibus mapping info, per buffer */ | |
db738443 BJ |
220 | |
221 | udprobe(reg, ctlr) | |
222 | caddr_t reg; | |
223 | int ctlr; | |
224 | { | |
225 | register int br, cvec; | |
226 | register struct uda_softc *sc = &uda_softc[ctlr]; | |
2f961121 MK |
227 | struct udadevice *udaddr; |
228 | ||
229 | int cur_time; | |
db738443 BJ |
230 | |
231 | #ifdef lint | |
2f961121 | 232 | br = 0; cvec = br; br = cvec; |
66923854 | 233 | udreset(0); udintr(0); |
db738443 | 234 | #endif |
2f961121 MK |
235 | udaddr = (struct udadevice *) reg; |
236 | ||
237 | sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4); | |
9d2503c6 BK |
238 | #if VAX630 |
239 | if (cpu == VAX_630) { | |
240 | br = 0x15; | |
241 | cvec = sc->sc_ivec; | |
242 | return(sizeof (struct udadevice)); | |
243 | } | |
244 | #endif | |
2f961121 MK |
245 | udaddr->udaip = 0; /* start initialization */ |
246 | ||
247 | cur_time = mfpr(TODR); /* Time of day */ | |
248 | while(cur_time + TENSEC > mfpr(TODR)){ /* wait for at most 10 secs */ | |
249 | if((udaddr->udasa & UDA_STEP1) != 0) | |
250 | break; | |
251 | } | |
252 | if(cur_time + TENSEC <= mfpr(TODR)) | |
253 | return(0); /* Not a uda or it won't init as it */ | |
254 | /* should within ten seconds. */ | |
255 | udaddr->udasa=UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); | |
256 | while((udaddr->udasa&UDA_STEP2)==0) | |
257 | DELAY(1000); /* intr should have */ | |
258 | /* have happened by now */ | |
259 | ||
9c0adba0 | 260 | return(sizeof (struct udadevice)); |
db738443 BJ |
261 | } |
262 | ||
9418508d | 263 | /* ARGSUSED */ |
db738443 BJ |
264 | udslave(ui, reg) |
265 | struct uba_device *ui; | |
266 | caddr_t reg; | |
267 | { | |
2f961121 MK |
268 | register struct uba_ctlr *um = udminfo[ui->ui_ctlr]; |
269 | register struct uda_softc *sc = &uda_softc[ui->ui_ctlr]; | |
270 | struct udadevice *udaddr; | |
271 | struct mscp *mp; | |
272 | int i; /* Something to write into to start */ | |
273 | /* the uda polling */ | |
274 | ||
275 | ||
2f961121 MK |
276 | udaddr = (struct udadevice *)um->um_addr; |
277 | if(sc->sc_state != S_RUN){ | |
278 | if(!udinit(ui->ui_ctlr)) | |
279 | return(0); | |
280 | } | |
281 | /* Here we will wait for the controller */ | |
282 | /* to come into the run state or go idle. If we go idle we are in */ | |
283 | /* touble and I don't yet know what to do so I will punt */ | |
284 | while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE); /* spin */ | |
285 | if(sc->sc_state == S_IDLE){ /* The Uda failed to initialize */ | |
286 | printf("UDA failed to init\n"); | |
287 | return(0); | |
288 | } | |
289 | /* The controller is up so let see if the drive is there! */ | |
290 | if(0 == (mp = udgetcp(um))){ /* ditto */ | |
291 | printf("UDA can't get command packet\n"); | |
292 | return(0); | |
293 | } | |
294 | mp->mscp_opcode = M_OP_GTUNT; /* This should give us the drive type*/ | |
295 | mp->mscp_unit = ui->ui_slave; | |
296 | mp->mscp_cmdref = (long) ui->ui_slave; | |
297 | #ifdef DEBUG | |
298 | printd("uda%d Get unit status slave %d\n",ui->ui_ctlr,ui->ui_slave); | |
299 | #endif | |
300 | ra_info[ui->ui_unit].rastatus = 0; /* set to zero */ | |
301 | udip[ui->ui_ctlr][ui->ui_slave] = ui; | |
302 | *((long *) mp->mscp_dscptr ) |= UDA_OWN | UDA_INT;/* maybe we should poll*/ | |
303 | i = udaddr->udaip; | |
9418508d MK |
304 | #ifdef lint |
305 | i = i; | |
306 | #endif | |
2f961121 MK |
307 | while(!ra_info[ui->ui_unit].rastatus); /* Wait for some status */ |
308 | udip[ui->ui_ctlr][ui->ui_slave] = 0; | |
309 | if(!ra_info[ui->ui_unit].ratype) /* packet from a GTUNT */ | |
310 | return(0); /* Failed No such drive */ | |
311 | else | |
312 | return(1); /* Got it and it is there */ | |
db738443 BJ |
313 | } |
314 | ||
315 | udattach(ui) | |
316 | register struct uba_device *ui; | |
317 | { | |
2f961121 MK |
318 | register struct uba_ctlr *um = ui->ui_mi ; |
319 | struct udadevice *udaddr = (struct udadevice *) um->um_addr; | |
320 | struct mscp *mp; | |
321 | int i; /* Something to write into to start */ | |
322 | /* the uda polling */ | |
a45a8092 | 323 | if (ui->ui_dk >= 0) |
2f961121 | 324 | dk_mspw[ui->ui_dk] = 1.0 / (60 * 31 * 256); /* approx */ |
db738443 BJ |
325 | ui->ui_flags = 0; |
326 | udip[ui->ui_ctlr][ui->ui_slave] = ui; | |
2f961121 MK |
327 | /* check to see if the drive is a available if it is bring it online */ |
328 | /* if not then just return. open will try an online later */ | |
329 | if(ra_info[ui->ui_unit].rastatus != M_ST_AVLBL) | |
330 | return; /* status was set by a GTUNT */ | |
331 | if(0 == (mp = udgetcp(um))){ /* ditto */ | |
332 | printf("UDA can't get command packet\n"); | |
333 | return; | |
334 | } | |
335 | mp->mscp_opcode = M_OP_ONLIN; | |
336 | mp->mscp_unit = ui->ui_slave; | |
337 | mp->mscp_cmdref = (long) ui->ui_slave; | |
338 | #ifdef DEBUG | |
339 | printd("uda%d ONLIN slave %d\n",ui->ui_ctlr,ui->ui_slave); | |
340 | #endif | |
341 | *((long *) mp->mscp_dscptr ) |= UDA_OWN | UDA_INT; | |
342 | i = udaddr->udaip; | |
9418508d MK |
343 | #ifdef lint |
344 | i = i; | |
345 | #endif | |
2f961121 | 346 | while(ui->ui_flags == 0 && ra_info[ui->ui_unit].ratype != 0); |
db738443 BJ |
347 | } |
348 | ||
349 | /* | |
350 | * Open a UDA. Initialize the device and | |
351 | * set the unit online. | |
352 | */ | |
9418508d | 353 | /* ARGSUSED */ |
db738443 BJ |
354 | udopen(dev, flag) |
355 | dev_t dev; | |
356 | int flag; | |
357 | { | |
358 | register int unit; | |
359 | register struct uba_device *ui; | |
360 | register struct uda_softc *sc; | |
2f961121 MK |
361 | register struct mscp *mp; |
362 | register struct uba_ctlr *um; | |
363 | struct udadevice *udaddr; | |
364 | int s,i; | |
2f961121 | 365 | |
dac559fa | 366 | unit = udunit(dev); |
8011f5df | 367 | if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0) |
7da157da | 368 | return (ENXIO); |
db738443 | 369 | sc = &uda_softc[ui->ui_ctlr]; |
530d0032 | 370 | s = spl5(); |
db738443 BJ |
371 | if (sc->sc_state != S_RUN) { |
372 | if (sc->sc_state == S_IDLE) | |
2f961121 MK |
373 | if(!udinit(ui->ui_ctlr)){ |
374 | printf("uda: Controller failed to init\n"); | |
ca018357 | 375 | (void) splx(s); |
2f961121 MK |
376 | return(ENXIO); |
377 | } | |
155d9ff0 | 378 | /* wait for initialization to complete */ |
2f961121 | 379 | timeout(wakeup,(caddr_t)ui->ui_mi,11*hz); /* to be sure*/ |
155d9ff0 | 380 | sleep((caddr_t)ui->ui_mi, 0); |
7da157da | 381 | if (sc->sc_state != S_RUN) |
2f961121 MK |
382 | { |
383 | (void) splx(s); /* added by Rich */ | |
7da157da | 384 | return (EIO); |
2f961121 MK |
385 | } |
386 | } | |
387 | /* check to see if the device is really there. */ | |
388 | /* this code was taken from Fred Canters 11 driver */ | |
389 | um = ui->ui_mi; | |
390 | udaddr = (struct udadevice *) um->um_addr; | |
391 | (void) splx(s); | |
392 | if(ui->ui_flags == 0){ | |
393 | s = spl5(); | |
394 | while(0 ==(mp = udgetcp(um))){ | |
395 | uda_cp_wait++; | |
8011f5df | 396 | sleep((caddr_t)&uda_cp_wait,PSWP+1); |
2f961121 MK |
397 | uda_cp_wait--; |
398 | } | |
2f961121 MK |
399 | mp->mscp_opcode = M_OP_ONLIN; |
400 | mp->mscp_unit = ui->ui_slave; | |
401 | mp->mscp_cmdref = (long) & ra_info[ui->ui_unit].ratype; | |
402 | /* need to sleep on something */ | |
403 | #ifdef DEBUG | |
404 | printd("uda: bring unit %d online\n",ui->ui_unit); | |
405 | #endif | |
406 | *((long *) mp->mscp_dscptr ) |= UDA_OWN | UDA_INT ; | |
407 | i = udaddr->udaip; | |
9418508d MK |
408 | #ifdef lint |
409 | i = i; | |
410 | #endif | |
2f961121 MK |
411 | timeout(wakeup,(caddr_t) mp->mscp_cmdref,10 * hz); |
412 | /* make sure we wake up */ | |
413 | sleep((caddr_t) mp->mscp_cmdref,PSWP+1); /*wakeup in udrsp() */ | |
b700f087 | 414 | (void) splx(s); |
2f961121 MK |
415 | } |
416 | if(ui->ui_flags == 0){ | |
417 | return(ENXIO); /* Didn't go online */ | |
db738443 | 418 | } |
7da157da | 419 | return (0); |
db738443 BJ |
420 | } |
421 | ||
422 | /* | |
423 | * Initialize a UDA. Set up UBA mapping registers, | |
424 | * initialize data structures, and start hardware | |
425 | * initialization sequence. | |
426 | */ | |
427 | udinit(d) | |
428 | int d; | |
429 | { | |
430 | register struct uda_softc *sc; | |
431 | register struct uda *ud; | |
432 | struct udadevice *udaddr; | |
433 | struct uba_ctlr *um; | |
434 | ||
435 | sc = &uda_softc[d]; | |
436 | um = udminfo[d]; | |
437 | um->um_tab.b_active++; | |
438 | ud = &uda[d]; | |
439 | udaddr = (struct udadevice *)um->um_addr; | |
440 | if (sc->sc_mapped == 0) { | |
441 | /* | |
442 | * Map the communications area and command | |
443 | * and response packets into Unibus address | |
444 | * space. | |
445 | */ | |
446 | sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)ud, | |
447 | sizeof (struct uda), 0); | |
448 | sc->sc_uda = (struct uda *)(sc->sc_ubainfo & 0x3ffff); | |
449 | sc->sc_mapped = 1; | |
450 | } | |
451 | ||
452 | /* | |
453 | * Start the hardware initialization sequence. | |
454 | */ | |
2f961121 MK |
455 | |
456 | udaddr->udaip = 0; /* start initialization */ | |
457 | ||
458 | while((udaddr->udasa & UDA_STEP1) == 0){ | |
459 | if(udaddr->udasa & UDA_ERR) | |
460 | return(0); /* CHECK */ | |
461 | } | |
462 | udaddr->udasa=UDA_ERR|(NCMDL2<<11)|(NRSPL2<<8)|UDA_IE|(sc->sc_ivec/4); | |
db738443 BJ |
463 | /* |
464 | * Initialization continues in interrupt routine. | |
465 | */ | |
466 | sc->sc_state = S_STEP1; | |
467 | sc->sc_credits = 0; | |
2f961121 | 468 | return(1); |
db738443 BJ |
469 | } |
470 | ||
471 | udstrategy(bp) | |
472 | register struct buf *bp; | |
473 | { | |
474 | register struct uba_device *ui; | |
475 | register struct uba_ctlr *um; | |
476 | register struct buf *dp; | |
477 | register int unit; | |
2f961121 | 478 | register struct size *rasizes; |
db738443 BJ |
479 | int xunit = minor(bp->b_dev) & 07; |
480 | daddr_t sz, maxsz; | |
530d0032 | 481 | int s; |
db738443 BJ |
482 | |
483 | sz = (bp->b_bcount+511) >> 9; | |
dac559fa | 484 | unit = udunit(bp->b_dev); |
8011f5df | 485 | if (unit >= NRA) { |
dac559fa | 486 | bp->b_error = ENXIO; |
db738443 | 487 | goto bad; |
dac559fa | 488 | } |
2f961121 | 489 | rasizes = ra_info[unit].ra_sizes; |
db738443 BJ |
490 | ui = uddinfo[unit]; |
491 | um = ui->ui_mi; | |
dac559fa JB |
492 | if (ui == 0 || ui->ui_alive == 0) { |
493 | bp->b_error = ENXIO; | |
db738443 | 494 | goto bad; |
dac559fa | 495 | } |
2f961121 MK |
496 | if ((maxsz = rasizes[xunit].nblocks) < 0) |
497 | maxsz = ra_info[unit].radsize - rasizes[xunit].blkoff; | |
db738443 | 498 | if (bp->b_blkno < 0 || bp->b_blkno+sz > maxsz || |
dac559fa | 499 | rasizes[xunit].blkoff >= ra_info[unit].radsize) { |
9d0e0faa MK |
500 | if (bp->b_blkno == maxsz) { |
501 | bp->b_resid = bp->b_bcount; | |
dac559fa | 502 | goto done; |
9d0e0faa | 503 | } |
dac559fa | 504 | bp->b_error = EINVAL; |
db738443 | 505 | goto bad; |
dac559fa | 506 | } |
530d0032 | 507 | s = spl5(); |
db738443 BJ |
508 | /* |
509 | * Link the buffer onto the drive queue | |
510 | */ | |
511 | dp = &udutab[ui->ui_unit]; | |
512 | if (dp->b_actf == 0) | |
513 | dp->b_actf = bp; | |
514 | else | |
515 | dp->b_actl->av_forw = bp; | |
516 | dp->b_actl = bp; | |
517 | bp->av_forw = 0; | |
518 | /* | |
519 | * Link the drive onto the controller queue | |
520 | */ | |
521 | if (dp->b_active == 0) { | |
522 | dp->b_forw = NULL; | |
523 | if (um->um_tab.b_actf == NULL) | |
524 | um->um_tab.b_actf = dp; | |
525 | else | |
526 | um->um_tab.b_actl->b_forw = dp; | |
527 | um->um_tab.b_actl = dp; | |
528 | dp->b_active = 1; | |
529 | } | |
530 | if (um->um_tab.b_active == 0) { | |
531 | #if defined(VAX750) | |
a8e727a7 SL |
532 | if (cpu == VAX_750 |
533 | && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) { | |
2f961121 MK |
534 | if (um->um_ubinfo != 0) { |
535 | printd("udastrat: ubinfo 0x%x\n",um->um_ubinfo); | |
536 | } else | |
db738443 | 537 | um->um_ubinfo = |
a8e727a7 | 538 | uballoc(um->um_ubanum, (caddr_t)0, 0, |
155d9ff0 | 539 | UBA_NEEDBDP); |
db738443 BJ |
540 | } |
541 | #endif | |
542 | (void) udstart(um); | |
543 | } | |
530d0032 | 544 | splx(s); |
db738443 BJ |
545 | return; |
546 | ||
547 | bad: | |
548 | bp->b_flags |= B_ERROR; | |
dac559fa | 549 | done: |
db738443 BJ |
550 | iodone(bp); |
551 | return; | |
552 | } | |
553 | ||
554 | udstart(um) | |
555 | register struct uba_ctlr *um; | |
556 | { | |
557 | register struct buf *bp, *dp; | |
558 | register struct mscp *mp; | |
559 | register struct uda_softc *sc; | |
560 | register struct uba_device *ui; | |
2f961121 | 561 | struct size *rasizes; |
db738443 | 562 | struct udadevice *udaddr; |
2f961121 | 563 | struct uda *ud = &uda[um->um_ctlr]; |
db738443 BJ |
564 | int i; |
565 | ||
566 | sc = &uda_softc[um->um_ctlr]; | |
567 | ||
568 | loop: | |
569 | if ((dp = um->um_tab.b_actf) == NULL) { | |
570 | /* | |
571 | * Release uneeded UBA resources and return | |
572 | */ | |
573 | um->um_tab.b_active = 0; | |
2f961121 MK |
574 | /* Check for response ring transitions lost in the |
575 | * Race condition | |
576 | */ | |
577 | for (i = sc->sc_lastrsp;; i++) { | |
578 | i %= NRSP; | |
579 | if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) | |
580 | break; | |
581 | udrsp(um, ud, sc, i); | |
582 | ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; | |
583 | } | |
584 | sc->sc_lastrsp = i; | |
155d9ff0 | 585 | return (0); |
db738443 BJ |
586 | } |
587 | if ((bp = dp->b_actf) == NULL) { | |
588 | /* | |
589 | * No more requests for this drive, remove | |
590 | * from controller queue and look at next drive. | |
591 | * We know we're at the head of the controller queue. | |
592 | */ | |
593 | dp->b_active = 0; | |
594 | um->um_tab.b_actf = dp->b_forw; | |
2f961121 | 595 | goto loop; /* Need to check for loop */ |
db738443 BJ |
596 | } |
597 | um->um_tab.b_active++; | |
598 | udaddr = (struct udadevice *)um->um_addr; | |
599 | if ((udaddr->udasa&UDA_ERR) || sc->sc_state != S_RUN) { | |
600 | harderr(bp, "ra"); | |
2f961121 | 601 | mprintf("Uda%d udasa %o, state %d\n",um->um_ctlr , udaddr->udasa&0xffff, sc->sc_state); |
8011f5df | 602 | (void)udinit(um->um_ctlr); |
db738443 | 603 | /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */ |
155d9ff0 | 604 | return (0); |
db738443 | 605 | } |
dac559fa | 606 | ui = uddinfo[udunit(bp->b_dev)]; |
2f961121 MK |
607 | rasizes = ra_info[ui->ui_unit].ra_sizes; |
608 | if (ui->ui_flags == 0) { /* not online */ | |
609 | if ((mp = udgetcp(um)) == NULL){ | |
610 | return (0); | |
611 | } | |
db738443 BJ |
612 | mp->mscp_opcode = M_OP_ONLIN; |
613 | mp->mscp_unit = ui->ui_slave; | |
614 | dp->b_active = 2; | |
2f961121 MK |
615 | um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ |
616 | #ifdef DEBUG | |
db738443 | 617 | printd("uda: bring unit %d online\n", ui->ui_slave); |
2f961121 | 618 | #endif |
db738443 | 619 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; |
2f961121 MK |
620 | if (udaddr->udasa&UDA_ERR) |
621 | printf("Uda (%d) Error (%x)\n",um->um_ctlr , udaddr->udasa&0xffff); | |
db738443 BJ |
622 | i = udaddr->udaip; |
623 | goto loop; | |
624 | } | |
625 | switch (cpu) { | |
a3f1771b | 626 | case VAX_8600: |
db738443 BJ |
627 | case VAX_780: |
628 | i = UBA_NEEDBDP|UBA_CANTWAIT; | |
629 | break; | |
630 | ||
631 | case VAX_750: | |
632 | i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; | |
633 | break; | |
634 | ||
10f66600 | 635 | case VAX_730: |
9d2503c6 | 636 | case VAX_630: |
db738443 BJ |
637 | i = UBA_CANTWAIT; |
638 | break; | |
639 | } | |
feb0c159 MK |
640 | if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) |
641 | return(1); | |
2f961121 | 642 | if ((mp = udgetcp(um)) == NULL) { |
cb6ff96f MK |
643 | #if defined(VAX750) |
644 | if (cpu == VAX_750) | |
645 | i &= 0xfffffff; /* mask off bdp */ | |
646 | #endif | |
2f961121 MK |
647 | ubarelse(um->um_ubanum,&i); |
648 | return(0); | |
db738443 | 649 | } |
2f961121 | 650 | mp->mscp_cmdref = (long)bp; /* pointer to get back */ |
db738443 BJ |
651 | mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; |
652 | mp->mscp_unit = ui->ui_slave; | |
2f961121 | 653 | mp->mscp_lbn = bp->b_blkno + rasizes[minor(bp->b_dev)&7].blkoff; |
db738443 BJ |
654 | mp->mscp_bytecnt = bp->b_bcount; |
655 | mp->mscp_buffer = (i & 0x3ffff) | (((i>>28)&0xf)<<24); | |
656 | #if defined(VAX750) | |
657 | if (cpu == VAX_750) | |
2f961121 | 658 | i &= 0xfffffff; /* mask off bdp */ |
db738443 | 659 | #endif |
2f961121 | 660 | bp->b_ubinfo = i; /* save mapping info */ |
db738443 | 661 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; |
2f961121 MK |
662 | if (udaddr->udasa&UDA_ERR) |
663 | printf("Uda(%d) udasa (%x)\n",um->um_ctlr , udaddr->udasa&0xffff); | |
664 | i = udaddr->udaip; /* initiate polling */ | |
665 | dp->b_qsize++; | |
db738443 BJ |
666 | if (ui->ui_dk >= 0) { |
667 | dk_busy |= 1<<ui->ui_dk; | |
db738443 BJ |
668 | dk_xfer[ui->ui_dk]++; |
669 | dk_wds[ui->ui_dk] += bp->b_bcount>>6; | |
670 | } | |
671 | ||
672 | /* | |
673 | * Move drive to the end of the controller queue | |
674 | */ | |
675 | if (dp->b_forw != NULL) { | |
676 | um->um_tab.b_actf = dp->b_forw; | |
677 | um->um_tab.b_actl->b_forw = dp; | |
678 | um->um_tab.b_actl = dp; | |
679 | dp->b_forw = NULL; | |
680 | } | |
681 | /* | |
682 | * Move buffer to I/O wait queue | |
683 | */ | |
684 | dp->b_actf = bp->av_forw; | |
685 | dp = &udwtab[um->um_ctlr]; | |
686 | bp->av_forw = dp; | |
687 | bp->av_back = dp->av_back; | |
688 | dp->av_back->av_forw = bp; | |
689 | dp->av_back = bp; | |
690 | goto loop; | |
691 | } | |
692 | ||
693 | /* | |
694 | * UDA interrupt routine. | |
695 | */ | |
696 | udintr(d) | |
697 | int d; | |
698 | { | |
699 | register struct uba_ctlr *um = udminfo[d]; | |
700 | register struct udadevice *udaddr = (struct udadevice *)um->um_addr; | |
701 | struct buf *bp; | |
702 | register int i; | |
703 | register struct uda_softc *sc = &uda_softc[d]; | |
704 | register struct uda *ud = &uda[d]; | |
705 | struct uda *uud; | |
706 | struct mscp *mp; | |
707 | ||
2f961121 MK |
708 | #ifdef DEBUG |
709 | printd10("udintr: state %d, udasa %o\n", sc->sc_state, udaddr->udasa); | |
710 | #endif | |
9d2503c6 BK |
711 | #ifdef VAX630 |
712 | (void) spl5(); | |
713 | #endif | |
db738443 BJ |
714 | switch (sc->sc_state) { |
715 | case S_IDLE: | |
716 | printf("uda%d: random interrupt ignored\n", d); | |
717 | return; | |
718 | ||
719 | case S_STEP1: | |
2f961121 MK |
720 | #define STEP1MASK 0174377 |
721 | #define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2) | |
5fd46eab | 722 | if ((udaddr->udasa&STEP1MASK) != STEP1GOOD) { |
db738443 | 723 | sc->sc_state = S_IDLE; |
155d9ff0 | 724 | wakeup((caddr_t)um); |
db738443 BJ |
725 | return; |
726 | } | |
727 | udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)| | |
a3f1771b | 728 | ((cpu == VAX_780) || (cpu == VAX_8600) ? UDA_PI : 0); |
db738443 BJ |
729 | sc->sc_state = S_STEP2; |
730 | return; | |
731 | ||
732 | case S_STEP2: | |
2f961121 MK |
733 | #define STEP2MASK 0174377 |
734 | #define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4)) | |
5fd46eab | 735 | if ((udaddr->udasa&STEP2MASK) != STEP2GOOD) { |
db738443 | 736 | sc->sc_state = S_IDLE; |
155d9ff0 | 737 | wakeup((caddr_t)um); |
db738443 BJ |
738 | return; |
739 | } | |
740 | udaddr->udasa = ((int)&sc->sc_uda->uda_ca.ca_ringbase)>>16; | |
741 | sc->sc_state = S_STEP3; | |
742 | return; | |
743 | ||
744 | case S_STEP3: | |
2f961121 MK |
745 | #define STEP3MASK 0174000 |
746 | #define STEP3GOOD UDA_STEP4 | |
5fd46eab | 747 | if ((udaddr->udasa&STEP3MASK) != STEP3GOOD) { |
db738443 | 748 | sc->sc_state = S_IDLE; |
155d9ff0 | 749 | wakeup((caddr_t)um); |
db738443 BJ |
750 | return; |
751 | } | |
2f961121 MK |
752 | udamicro[d] = udaddr->udasa; |
753 | #ifdef DEBUG | |
754 | printd("Uda%d Version %d model %d\n",d,udamicro[d]&0xF, | |
755 | (udamicro[d]>>4) & 0xF); | |
1b58ff00 | 756 | #endif |
2f961121 MK |
757 | /* |
758 | * Requesting the error status (|= 2) | |
759 | * may hang older controllers. | |
760 | */ | |
83704bde MK |
761 | i = UDA_GO | (udaerror? 2 : 0); |
762 | if (udaburst[d]) | |
763 | i |= (udaburst[d] - 1) << 2; | |
764 | udaddr->udasa = i; | |
db738443 BJ |
765 | udaddr->udasa = UDA_GO; |
766 | sc->sc_state = S_SCHAR; | |
767 | ||
768 | /* | |
769 | * Initialize the data structures. | |
770 | */ | |
771 | uud = sc->sc_uda; | |
772 | for (i = 0; i < NRSP; i++) { | |
773 | ud->uda_ca.ca_rspdsc[i] = UDA_OWN|UDA_INT| | |
774 | (long)&uud->uda_rsp[i].mscp_cmdref; | |
775 | ud->uda_rsp[i].mscp_dscptr = &ud->uda_ca.ca_rspdsc[i]; | |
2f961121 | 776 | ud->uda_rsp[i].mscp_header.uda_msglen = mscp_msglen; |
db738443 BJ |
777 | } |
778 | for (i = 0; i < NCMD; i++) { | |
779 | ud->uda_ca.ca_cmddsc[i] = UDA_INT| | |
780 | (long)&uud->uda_cmd[i].mscp_cmdref; | |
781 | ud->uda_cmd[i].mscp_dscptr = &ud->uda_ca.ca_cmddsc[i]; | |
2f961121 | 782 | ud->uda_cmd[i].mscp_header.uda_msglen = mscp_msglen; |
db738443 BJ |
783 | } |
784 | bp = &udwtab[d]; | |
785 | bp->av_forw = bp->av_back = bp; | |
2f961121 | 786 | sc->sc_lastcmd = 1; |
db738443 | 787 | sc->sc_lastrsp = 0; |
2f961121 MK |
788 | mp = &uda[um->um_ctlr].uda_cmd[0]; |
789 | mp->mscp_unit = mp->mscp_modifier = 0; | |
790 | mp->mscp_flags = 0; | |
791 | mp->mscp_bytecnt = mp->mscp_buffer = 0; | |
792 | mp->mscp_errlgfl = mp->mscp_copyspd = 0; | |
db738443 BJ |
793 | mp->mscp_opcode = M_OP_STCON; |
794 | mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS; | |
795 | *((long *)mp->mscp_dscptr) |= UDA_OWN|UDA_INT; | |
2f961121 | 796 | i = udaddr->udaip; /* initiate polling */ |
db738443 BJ |
797 | return; |
798 | ||
799 | case S_SCHAR: | |
800 | case S_RUN: | |
801 | break; | |
802 | ||
803 | default: | |
804 | printf("uda%d: interrupt in unknown state %d ignored\n", | |
805 | d, sc->sc_state); | |
806 | return; | |
807 | } | |
808 | ||
809 | if (udaddr->udasa&UDA_ERR) { | |
2f961121 | 810 | printf("uda(%d): fatal error (%o)\n", d, udaddr->udasa&0xffff); |
db738443 | 811 | udaddr->udaip = 0; |
155d9ff0 | 812 | wakeup((caddr_t)um); |
db738443 BJ |
813 | } |
814 | ||
815 | /* | |
816 | * Check for a buffer purge request. | |
817 | */ | |
818 | if (ud->uda_ca.ca_bdp) { | |
2f961121 | 819 | #ifdef DEBUG |
db738443 | 820 | printd("uda: purge bdp %d\n", ud->uda_ca.ca_bdp); |
2f961121 | 821 | #endif |
8011f5df | 822 | UBAPURGE(um->um_hd->uh_uba, ud->uda_ca.ca_bdp); |
db738443 | 823 | ud->uda_ca.ca_bdp = 0; |
2f961121 | 824 | udaddr->udasa = 0; /* signal purge complete */ |
db738443 BJ |
825 | } |
826 | ||
827 | /* | |
828 | * Check for response ring transition. | |
829 | */ | |
830 | if (ud->uda_ca.ca_rspint) { | |
831 | ud->uda_ca.ca_rspint = 0; | |
832 | for (i = sc->sc_lastrsp;; i++) { | |
833 | i %= NRSP; | |
834 | if (ud->uda_ca.ca_rspdsc[i]&UDA_OWN) | |
835 | break; | |
836 | udrsp(um, ud, sc, i); | |
837 | ud->uda_ca.ca_rspdsc[i] |= UDA_OWN; | |
838 | } | |
839 | sc->sc_lastrsp = i; | |
840 | } | |
841 | ||
842 | /* | |
843 | * Check for command ring transition. | |
844 | */ | |
845 | if (ud->uda_ca.ca_cmdint) { | |
2f961121 | 846 | #ifdef DEBUG |
db738443 | 847 | printd("uda: command ring transition\n"); |
2f961121 | 848 | #endif |
db738443 BJ |
849 | ud->uda_ca.ca_cmdint = 0; |
850 | } | |
2f961121 | 851 | if(uda_cp_wait) |
8011f5df | 852 | wakeup((caddr_t)&uda_cp_wait); |
155d9ff0 | 853 | (void) udstart(um); |
db738443 BJ |
854 | } |
855 | ||
856 | /* | |
857 | * Process a response packet | |
858 | */ | |
859 | udrsp(um, ud, sc, i) | |
860 | register struct uba_ctlr *um; | |
861 | register struct uda *ud; | |
862 | register struct uda_softc *sc; | |
863 | int i; | |
864 | { | |
865 | register struct mscp *mp; | |
866 | struct uba_device *ui; | |
2f961121 | 867 | struct buf *dp, *bp,nullbp; |
db738443 BJ |
868 | int st; |
869 | ||
870 | mp = &ud->uda_rsp[i]; | |
2f961121 MK |
871 | mp->mscp_header.uda_msglen = mscp_msglen; |
872 | sc->sc_credits += mp->mscp_header.uda_credits & 0xf; /* just 4 bits?*/ | |
873 | if ((mp->mscp_header.uda_credits & 0xf0) > 0x10) /* Check */ | |
db738443 | 874 | return; |
2f961121 MK |
875 | #ifdef DEBUG |
876 | printd10("udarsp, opcode 0x%x status 0x%x\n",mp->mscp_opcode,mp->mscp_status); | |
877 | #endif | |
db738443 BJ |
878 | /* |
879 | * If it's an error log message (datagram), | |
880 | * pass it on for more extensive processing. | |
881 | */ | |
2f961121 | 882 | if ((mp->mscp_header.uda_credits & 0xf0) == 0x10) { /* check */ |
db738443 BJ |
883 | uderror(um, (struct mslg *)mp); |
884 | return; | |
885 | } | |
db738443 | 886 | st = mp->mscp_status&M_ST_MASK; |
2f961121 MK |
887 | /* The controller interrupts as drive 0 */ |
888 | /* this means that you must check for controller interrupts */ | |
889 | /* before you check to see if there is a drive 0 */ | |
890 | if((M_OP_STCON|M_OP_END) == mp->mscp_opcode){ | |
db738443 BJ |
891 | if (st == M_ST_SUCC) |
892 | sc->sc_state = S_RUN; | |
893 | else | |
894 | sc->sc_state = S_IDLE; | |
895 | um->um_tab.b_active = 0; | |
155d9ff0 | 896 | wakeup((caddr_t)um); |
2f961121 MK |
897 | return; |
898 | } | |
899 | if (mp->mscp_unit >= 8) | |
900 | return; | |
901 | if ((ui = udip[um->um_ctlr][mp->mscp_unit]) == 0) | |
902 | return; | |
903 | switch (mp->mscp_opcode) { | |
db738443 BJ |
904 | |
905 | case M_OP_ONLIN|M_OP_END: | |
2f961121 MK |
906 | ra_info[ui->ui_unit].rastatus = st; |
907 | ra_info[ui->ui_unit].ratype = mp->mscp_mediaid; | |
db738443 | 908 | dp = &udutab[ui->ui_unit]; |
db738443 | 909 | if (st == M_ST_SUCC) { |
2f961121 MK |
910 | /* |
911 | * Link the drive onto the controller queue | |
912 | */ | |
913 | dp->b_forw = NULL; | |
914 | if (um->um_tab.b_actf == NULL) | |
915 | um->um_tab.b_actf = dp; | |
916 | else | |
917 | um->um_tab.b_actl->b_forw = dp; | |
918 | um->um_tab.b_actl = dp; | |
919 | ui->ui_flags = 1; /* mark it online */ | |
920 | ra_info[ui->ui_unit].radsize=(daddr_t)mp->mscp_untsize; | |
921 | #ifdef DEBUG | |
db738443 | 922 | printd("uda: unit %d online\n", mp->mscp_unit); |
2f961121 MK |
923 | #endif |
924 | #define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ') | |
925 | /* this mess decodes the Media type identifier */ | |
926 | #ifdef DEBUG | |
927 | printd("uda: unit %d online %x %c%c %c%c%c%d\n" | |
928 | ,mp->mscp_unit, mp->mscp_mediaid | |
929 | ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2) | |
930 | ,F_to_C(mp,1),F_to_C(mp,0) | |
931 | ,mp->mscp_mediaid & 0x7f); | |
932 | #endif | |
9418508d | 933 | switch((int)(mp->mscp_mediaid & 0x7f)){ |
2f961121 MK |
934 | case 25: |
935 | ra_info[ui->ui_unit].ra_sizes = ra25_sizes; | |
936 | break; | |
d9a8ab76 MK |
937 | case 52: |
938 | ra_info[ui->ui_unit].ra_sizes = rd52_sizes; | |
939 | break; | |
9d2503c6 | 940 | case 53: |
d9a8ab76 | 941 | ra_info[ui->ui_unit].ra_sizes = rd53_sizes; |
9d2503c6 | 942 | break; |
2f961121 MK |
943 | case 60: |
944 | ra_info[ui->ui_unit].ra_sizes = ra60_sizes; | |
945 | break; | |
946 | case 80: | |
947 | ra_info[ui->ui_unit].ra_sizes = ra80_sizes; | |
948 | break; | |
949 | case 81: | |
950 | ra_info[ui->ui_unit].ra_sizes = ra81_sizes; | |
951 | break; | |
952 | default: | |
953 | ui->ui_flags = 0; /* mark it offline */ | |
954 | ra_info[ui->ui_unit].ratype = 0; | |
955 | printf("Don't have a parition table for "); | |
956 | printf("a %c%c %c%c%c%d\n" | |
957 | ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2) | |
958 | ,F_to_C(mp,1),F_to_C(mp,0) | |
959 | ,mp->mscp_mediaid & 0x7f); | |
960 | while (bp = dp->b_actf) { | |
961 | dp->b_actf = bp->av_forw; | |
962 | bp->b_flags |= B_ERROR; | |
963 | iodone(bp); | |
964 | } | |
965 | } | |
966 | dp->b_active = 1; | |
db738443 | 967 | } else { |
2f961121 MK |
968 | if(dp->b_actf){ |
969 | harderr(dp->b_actf,"ra"); | |
970 | } else { | |
971 | nullbp.b_blkno = 0; | |
972 | nullbp.b_dev = makedev(UDADEVNUM,ui->ui_unit); | |
973 | harderr(&nullbp, "ra"); | |
974 | } | |
db738443 BJ |
975 | printf("OFFLINE\n"); |
976 | while (bp = dp->b_actf) { | |
977 | dp->b_actf = bp->av_forw; | |
978 | bp->b_flags |= B_ERROR; | |
979 | iodone(bp); | |
980 | } | |
981 | } | |
2f961121 | 982 | if(mp->mscp_cmdref!=NULL){/* Seems to get lost sometimes */ |
8011f5df | 983 | wakeup((caddr_t)mp->mscp_cmdref); |
2f961121 | 984 | } |
db738443 BJ |
985 | break; |
986 | ||
2f961121 MK |
987 | /* |
988 | * The AVAILABLE ATTENTION messages occurs when the | |
989 | * unit becomes available after spinup, | |
990 | * marking the unit offline will force an online command | |
991 | * prior to using the unit. | |
992 | */ | |
db738443 | 993 | case M_OP_AVATN: |
2f961121 | 994 | #ifdef DEBUG |
db738443 | 995 | printd("uda: unit %d attention\n", mp->mscp_unit); |
2f961121 MK |
996 | #endif |
997 | ui->ui_flags = 0; /* it went offline and we didn't notice */ | |
998 | ra_info[ui->ui_unit].ratype = mp->mscp_mediaid; | |
db738443 BJ |
999 | break; |
1000 | ||
2f961121 MK |
1001 | case M_OP_END: |
1002 | /* | |
1003 | * An endcode without an opcode (0200) is an invalid command. | |
1004 | * The mscp specification states that this would be a protocol | |
1005 | * type error, such as illegal opcodes. The mscp spec. also | |
1006 | * states that parameter error type of invalid commands should | |
1007 | * return the normal end message for the command. This does not appear | |
1008 | * to be the case. An invalid logical block number returned an endcode | |
1009 | * of 0200 instead of the 0241 (read) that was expected. | |
1010 | */ | |
1011 | ||
1012 | printf("endcd=%o, stat=%o\n", mp->mscp_opcode, mp->mscp_status); | |
1013 | break; | |
db738443 BJ |
1014 | case M_OP_READ|M_OP_END: |
1015 | case M_OP_WRITE|M_OP_END: | |
1016 | bp = (struct buf *)mp->mscp_cmdref; | |
5fd46eab | 1017 | ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); |
db738443 BJ |
1018 | /* |
1019 | * Unlink buffer from I/O wait queue. | |
1020 | */ | |
1021 | bp->av_back->av_forw = bp->av_forw; | |
1022 | bp->av_forw->av_back = bp->av_back; | |
a8e727a7 | 1023 | #if defined(VAX750) |
cb6ff96f | 1024 | if (cpu == VAX_750 && um->um_tab.b_active == 0 |
a8e727a7 SL |
1025 | && udwtab[um->um_ctlr].av_forw == &udwtab[um->um_ctlr]) { |
1026 | if (um->um_ubinfo == 0) | |
1027 | printf("udintr: um_ubinfo == 0\n"); | |
1028 | else | |
1029 | ubarelse(um->um_ubanum, &um->um_ubinfo); | |
1030 | } | |
1031 | #endif | |
db738443 | 1032 | dp = &udutab[ui->ui_unit]; |
2f961121 | 1033 | dp->b_qsize--; |
db738443 | 1034 | if (ui->ui_dk >= 0) |
2f961121 | 1035 | if (dp->b_qsize == 0) |
db738443 BJ |
1036 | dk_busy &= ~(1<<ui->ui_dk); |
1037 | if (st == M_ST_OFFLN || st == M_ST_AVLBL) { | |
2f961121 | 1038 | ui->ui_flags = 0; /* mark unit offline */ |
db738443 BJ |
1039 | /* |
1040 | * Link the buffer onto the front of the drive queue | |
1041 | */ | |
1042 | if ((bp->av_forw = dp->b_actf) == 0) | |
1043 | dp->b_actl = bp; | |
1044 | dp->b_actf = bp; | |
1045 | /* | |
1046 | * Link the drive onto the controller queue | |
1047 | */ | |
1048 | if (dp->b_active == 0) { | |
1049 | dp->b_forw = NULL; | |
1050 | if (um->um_tab.b_actf == NULL) | |
1051 | um->um_tab.b_actf = dp; | |
1052 | else | |
1053 | um->um_tab.b_actl->b_forw = dp; | |
1054 | um->um_tab.b_actl = dp; | |
1055 | dp->b_active = 1; | |
1056 | } | |
a8e727a7 SL |
1057 | #if defined(VAX750) |
1058 | if (cpu == VAX750 && um->um_ubinfo == 0) | |
1059 | um->um_ubinfo = | |
1060 | uballoc(um->um_ubanum, (caddr_t)0, 0, | |
1061 | UBA_NEEDBDP); | |
1062 | #endif | |
db738443 BJ |
1063 | return; |
1064 | } | |
1065 | if (st != M_ST_SUCC) { | |
1066 | harderr(bp, "ra"); | |
2f961121 MK |
1067 | #ifdef DEBUG |
1068 | printd("status %o\n", mp->mscp_status); | |
1069 | #endif | |
db738443 BJ |
1070 | bp->b_flags |= B_ERROR; |
1071 | } | |
1072 | bp->b_resid = bp->b_bcount - mp->mscp_bytecnt; | |
1073 | iodone(bp); | |
1074 | break; | |
1075 | ||
1076 | case M_OP_GTUNT|M_OP_END: | |
2f961121 MK |
1077 | #ifdef DEBUG |
1078 | printd("GTUNT end packet status = 0x%x media id 0x%x\n" | |
1079 | ,st,mp->mscp_mediaid); | |
1080 | #endif | |
1081 | ra_info[ui->ui_unit].rastatus = st; | |
1082 | ra_info[ui->ui_unit].ratype = mp->mscp_mediaid; | |
db738443 BJ |
1083 | break; |
1084 | ||
1085 | default: | |
1086 | printf("uda: unknown packet\n"); | |
2f961121 | 1087 | uderror(um, (struct mslg *)mp); |
db738443 BJ |
1088 | } |
1089 | } | |
1090 | ||
1091 | ||
1092 | /* | |
1093 | * Process an error log message | |
1094 | * | |
1095 | * For now, just log the error on the console. | |
1096 | * Only minimal decoding is done, only "useful" | |
1097 | * information is printed. Eventually should | |
1098 | * send message to an error logger. | |
1099 | */ | |
1100 | uderror(um, mp) | |
1101 | register struct uba_ctlr *um; | |
1102 | register struct mslg *mp; | |
1103 | { | |
2f961121 MK |
1104 | register i; |
1105 | ||
1106 | ||
1107 | if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT))) | |
1108 | printf("uda%d: hard error\n"); | |
1109 | ||
1110 | mprintf("uda%d: %s error, ", um->um_ctlr, | |
1111 | mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard"); | |
db738443 BJ |
1112 | switch (mp->mslg_format) { |
1113 | case M_FM_CNTERR: | |
2f961121 | 1114 | mprintf("controller error, event 0%o\n", mp->mslg_event); |
db738443 BJ |
1115 | break; |
1116 | ||
1117 | case M_FM_BUSADDR: | |
2f961121 | 1118 | mprintf("host memory access error, event 0%o, addr 0%o\n", |
3b1e560f | 1119 | mp->mslg_event, mp->mslg_busaddr); |
db738443 BJ |
1120 | break; |
1121 | ||
1122 | case M_FM_DISKTRN: | |
2f961121 MK |
1123 | mprintf("disk transfer error, unit %d, grp 0x%x, hdr 0x%x, event 0%o\n", |
1124 | mp->mslg_unit, mp->mslg_group, mp->mslg_hdr, | |
1125 | mp->mslg_event); | |
db738443 BJ |
1126 | break; |
1127 | ||
1128 | case M_FM_SDI: | |
2f961121 | 1129 | mprintf("SDI error, unit %d, event 0%o, hdr 0x%x\n", |
a8e727a7 | 1130 | mp->mslg_unit, mp->mslg_event, mp->mslg_hdr); |
2f961121 MK |
1131 | for(i = 0; i < 12;i++) |
1132 | mprintf("\t0x%x",mp->mslg_sdistat[i] & 0xff); | |
1133 | mprintf("\n"); | |
db738443 BJ |
1134 | break; |
1135 | ||
1136 | case M_FM_SMLDSK: | |
2f961121 | 1137 | mprintf("small disk error, unit %d, event 0%o, cyl %d\n", |
db738443 BJ |
1138 | mp->mslg_unit, mp->mslg_event, mp->mslg_sdecyl); |
1139 | break; | |
1140 | ||
1141 | default: | |
2f961121 | 1142 | mprintf("unknown error, unit %d, format 0%o, event 0%o\n", |
db738443 BJ |
1143 | mp->mslg_unit, mp->mslg_format, mp->mslg_event); |
1144 | } | |
5fd46eab SL |
1145 | |
1146 | if (udaerror) { | |
1147 | register long *p = (long *)mp; | |
5fd46eab SL |
1148 | |
1149 | for (i = 0; i < mp->mslg_header.uda_msglen; i += sizeof(*p)) | |
1150 | printf("%x ", *p++); | |
1151 | printf("\n"); | |
1152 | } | |
db738443 BJ |
1153 | } |
1154 | ||
1155 | ||
1156 | /* | |
1157 | * Find an unused command packet | |
1158 | */ | |
1159 | struct mscp * | |
1160 | udgetcp(um) | |
1161 | struct uba_ctlr *um; | |
1162 | { | |
1163 | register struct mscp *mp; | |
1164 | register struct udaca *cp; | |
1165 | register struct uda_softc *sc; | |
1166 | register int i; | |
2f961121 | 1167 | int s; |
db738443 | 1168 | |
2f961121 | 1169 | s = spl5(); |
db738443 BJ |
1170 | cp = &uda[um->um_ctlr].uda_ca; |
1171 | sc = &uda_softc[um->um_ctlr]; | |
2f961121 MK |
1172 | /* |
1173 | * If no credits, can't issue any commands | |
1174 | * until some outstanding commands complete. | |
1175 | */ | |
db738443 | 1176 | i = sc->sc_lastcmd; |
2f961121 MK |
1177 | if(((cp->ca_cmddsc[i]&(UDA_OWN|UDA_INT))==UDA_INT)&& |
1178 | (sc->sc_credits >= 2)) { | |
1179 | sc->sc_credits--; /* committed to issuing a command */ | |
db738443 BJ |
1180 | cp->ca_cmddsc[i] &= ~UDA_INT; |
1181 | mp = &uda[um->um_ctlr].uda_cmd[i]; | |
1182 | mp->mscp_unit = mp->mscp_modifier = 0; | |
1183 | mp->mscp_opcode = mp->mscp_flags = 0; | |
1184 | mp->mscp_bytecnt = mp->mscp_buffer = 0; | |
1185 | mp->mscp_errlgfl = mp->mscp_copyspd = 0; | |
1186 | sc->sc_lastcmd = (i + 1) % NCMD; | |
2f961121 | 1187 | (void) splx(s); |
db738443 BJ |
1188 | return(mp); |
1189 | } | |
2f961121 | 1190 | (void) splx(s); |
db738443 BJ |
1191 | return(NULL); |
1192 | } | |
1193 | ||
740e4029 | 1194 | udread(dev, uio) |
db738443 | 1195 | dev_t dev; |
740e4029 | 1196 | struct uio *uio; |
db738443 | 1197 | { |
dac559fa | 1198 | register int unit = udunit(dev); |
db738443 | 1199 | |
8011f5df | 1200 | if (unit >= NRA) |
0cd5eac7 BJ |
1201 | return (ENXIO); |
1202 | return (physio(udstrategy, &rudbuf[unit], dev, B_READ, minphys, uio)); | |
db738443 BJ |
1203 | } |
1204 | ||
002227dd | 1205 | udwrite(dev, uio) |
db738443 | 1206 | dev_t dev; |
002227dd | 1207 | struct uio *uio; |
db738443 | 1208 | { |
dac559fa | 1209 | register int unit = udunit(dev); |
db738443 | 1210 | |
8011f5df | 1211 | if (unit >= NRA) |
0cd5eac7 BJ |
1212 | return (ENXIO); |
1213 | return (physio(udstrategy, &rudbuf[unit], dev, B_WRITE, minphys, uio)); | |
db738443 BJ |
1214 | } |
1215 | ||
1216 | udreset(uban) | |
1217 | int uban; | |
1218 | { | |
1219 | register struct uba_ctlr *um; | |
1220 | register struct uba_device *ui; | |
1221 | register struct buf *bp, *dp; | |
1222 | register int unit; | |
1223 | struct buf *nbp; | |
1224 | int d; | |
1225 | ||
1226 | for (d = 0; d < NUDA; d++) { | |
1227 | if ((um = udminfo[d]) == 0 || um->um_ubanum != uban || | |
1228 | um->um_alive == 0) | |
1229 | continue; | |
1230 | printf(" uda%d", d); | |
1231 | um->um_tab.b_active = 0; | |
1232 | um->um_tab.b_actf = um->um_tab.b_actl = 0; | |
1233 | uda_softc[d].sc_state = S_IDLE; | |
2f961121 | 1234 | uda_softc[d].sc_mapped = 0; /* Rich */ |
8011f5df | 1235 | for (unit = 0; unit < NRA; unit++) { |
db738443 BJ |
1236 | if ((ui = uddinfo[unit]) == 0) |
1237 | continue; | |
1238 | if (ui->ui_alive == 0 || ui->ui_mi != um) | |
1239 | continue; | |
1240 | udutab[unit].b_active = 0; | |
1241 | udutab[unit].b_qsize = 0; | |
1242 | } | |
1243 | for (bp = udwtab[d].av_forw; bp != &udwtab[d]; bp = nbp) { | |
1244 | nbp = bp->av_forw; | |
7da157da | 1245 | bp->b_ubinfo = 0; |
db738443 BJ |
1246 | /* |
1247 | * Link the buffer onto the drive queue | |
1248 | */ | |
dac559fa | 1249 | dp = &udutab[udunit(bp->b_dev)]; |
db738443 BJ |
1250 | if (dp->b_actf == 0) |
1251 | dp->b_actf = bp; | |
1252 | else | |
1253 | dp->b_actl->av_forw = bp; | |
1254 | dp->b_actl = bp; | |
1255 | bp->av_forw = 0; | |
1256 | /* | |
1257 | * Link the drive onto the controller queue | |
1258 | */ | |
1259 | if (dp->b_active == 0) { | |
1260 | dp->b_forw = NULL; | |
1261 | if (um->um_tab.b_actf == NULL) | |
1262 | um->um_tab.b_actf = dp; | |
1263 | else | |
1264 | um->um_tab.b_actl->b_forw = dp; | |
1265 | um->um_tab.b_actl = dp; | |
1266 | dp->b_active = 1; | |
1267 | } | |
1268 | } | |
8011f5df | 1269 | (void)udinit(d); |
db738443 BJ |
1270 | } |
1271 | } | |
1272 | ||
2f961121 MK |
1273 | #define DBSIZE 32 |
1274 | ||
1275 | #define ca_Rspdsc ca_rspdsc[0] | |
1276 | #define ca_Cmddsc ca_rspdsc[1] | |
1277 | #define uda_Rsp uda_rsp[0] | |
1278 | #define uda_Cmd uda_cmd[0] | |
1279 | ||
1280 | struct uda udad[NUDA]; | |
1281 | ||
1282 | uddump(dev) | |
1283 | dev_t dev; | |
1284 | { | |
1285 | struct udadevice *udaddr; | |
1286 | struct uda *ud_ubaddr; | |
1287 | char *start; | |
1288 | int num, blk, unit; | |
1289 | int maxsz; | |
1290 | int blkoff; | |
1291 | register struct uba_regs *uba; | |
1292 | register struct uba_device *ui; | |
1293 | register struct uda *udp; | |
1294 | register struct pte *io; | |
1295 | register int i; | |
1296 | struct size *rasizes; | |
dac559fa | 1297 | unit = udunit(dev); |
8011f5df | 1298 | if (unit >= NRA) |
2f961121 MK |
1299 | return (ENXIO); |
1300 | #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) | |
1301 | ui = phys(struct uba_device *, uddinfo[unit]); | |
1302 | if (ui->ui_alive == 0) | |
1303 | return (ENXIO); | |
1304 | uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; | |
1305 | ubainit(uba); | |
1306 | udaddr = (struct udadevice *)ui->ui_physaddr; | |
1307 | DELAY(2000000); | |
1308 | udp = phys(struct uda *, &udad[ui->ui_ctlr]); | |
1309 | ||
1310 | num = btoc(sizeof(struct uda)) + 1; | |
1311 | io = &uba->uba_map[NUBMREG-num]; | |
1312 | for(i = 0; i<num; i++) | |
1313 | *(int *)io++ = UBAMR_MRV|(btop(udp)+i); | |
1314 | ud_ubaddr = (struct uda *)(((int)udp & PGOFSET)|((NUBMREG-num)<<9)); | |
1315 | ||
1316 | udaddr->udaip = 0; | |
1317 | while ((udaddr->udasa & UDA_STEP1) == 0) | |
1318 | if(udaddr->udasa & UDA_ERR) return(EFAULT); | |
1319 | udaddr->udasa = UDA_ERR; | |
1320 | while ((udaddr->udasa & UDA_STEP2) == 0) | |
1321 | if(udaddr->udasa & UDA_ERR) return(EFAULT); | |
1322 | udaddr->udasa = (short)&ud_ubaddr->uda_ca.ca_ringbase; | |
1323 | while ((udaddr->udasa & UDA_STEP3) == 0) | |
1324 | if(udaddr->udasa & UDA_ERR) return(EFAULT); | |
1325 | udaddr->udasa = (short)(((int)&ud_ubaddr->uda_ca.ca_ringbase) >> 16); | |
1326 | while ((udaddr->udasa & UDA_STEP4) == 0) | |
1327 | if(udaddr->udasa & UDA_ERR) return(EFAULT); | |
1328 | udaddr->udasa = UDA_GO; | |
1329 | udp->uda_ca.ca_Rspdsc = (long)&ud_ubaddr->uda_Rsp.mscp_cmdref; | |
1330 | udp->uda_ca.ca_Cmddsc = (long)&ud_ubaddr->uda_Cmd.mscp_cmdref; | |
1331 | udp->uda_Cmd.mscp_cntflgs = 0; | |
1332 | udp->uda_Cmd.mscp_version = 0; | |
1333 | if (udcmd(M_OP_STCON, udp, udaddr) == 0) { | |
1334 | return(EFAULT); | |
1335 | } | |
1336 | udp->uda_Cmd.mscp_unit = ui->ui_slave; | |
1337 | if (udcmd(M_OP_ONLIN, udp, udaddr) == 0) { | |
1338 | return(EFAULT); | |
1339 | } | |
1340 | ||
1341 | num = maxfree; | |
1342 | start = 0; | |
1343 | rasizes = ra_info[ui->ui_unit].ra_sizes; | |
1344 | maxsz = rasizes[minor(dev)&07].nblocks; | |
1345 | blkoff = rasizes[minor(dev)&07].blkoff; | |
1346 | if(maxsz < 0) | |
1347 | maxsz = ra_info[unit].radsize-blkoff; | |
46f6960a | 1348 | if (dumplo < 0) |
2f961121 | 1349 | return (EINVAL); |
46f6960a JB |
1350 | if (dumplo + num >= maxsz) |
1351 | num = maxsz - dumplo; | |
2f961121 MK |
1352 | blkoff += dumplo; |
1353 | while (num > 0) { | |
1354 | blk = num > DBSIZE ? DBSIZE : num; | |
1355 | io = uba->uba_map; | |
1356 | for (i = 0; i < blk; i++) | |
1357 | *(int *)io++ = (btop(start)+i) | UBAMR_MRV; | |
1358 | *(int *)io = 0; | |
1359 | udp->uda_Cmd.mscp_lbn = btop(start) + blkoff; | |
1360 | udp->uda_Cmd.mscp_unit = ui->ui_slave; | |
1361 | udp->uda_Cmd.mscp_bytecnt = blk*NBPG; | |
1362 | udp->uda_Cmd.mscp_buffer = 0; | |
1363 | if (udcmd(M_OP_WRITE, udp, udaddr) == 0) { | |
1364 | return(EIO); | |
1365 | } | |
1366 | start += blk*NBPG; | |
1367 | num -= blk; | |
1368 | } | |
1369 | return (0); | |
1370 | } | |
1371 | ||
1372 | ||
1373 | udcmd(op, udp, udaddr) | |
1374 | int op; | |
1375 | register struct uda *udp; | |
1376 | struct udadevice *udaddr; | |
db738443 | 1377 | { |
2f961121 MK |
1378 | int i; |
1379 | ||
2f961121 MK |
1380 | udp->uda_Cmd.mscp_opcode = op; |
1381 | udp->uda_Rsp.mscp_header.uda_msglen = mscp_msglen; | |
1382 | udp->uda_Cmd.mscp_header.uda_msglen = mscp_msglen; | |
1383 | udp->uda_ca.ca_Rspdsc |= UDA_OWN|UDA_INT; | |
1384 | udp->uda_ca.ca_Cmddsc |= UDA_OWN|UDA_INT; | |
1385 | if (udaddr->udasa&UDA_ERR) | |
1386 | printf("Udaerror udasa (%x)\n", udaddr->udasa&0xffff); | |
1387 | i = udaddr->udaip; | |
9418508d MK |
1388 | #ifdef lint |
1389 | i = i; | |
1390 | #endif | |
2f961121 MK |
1391 | for (;;) { |
1392 | if (udp->uda_ca.ca_cmdint) | |
1393 | udp->uda_ca.ca_cmdint = 0; | |
1394 | if (udp->uda_ca.ca_rspint) | |
1395 | break; | |
1396 | } | |
1397 | udp->uda_ca.ca_rspint = 0; | |
1398 | if (udp->uda_Rsp.mscp_opcode != (op|M_OP_END) || | |
1399 | (udp->uda_Rsp.mscp_status&M_ST_MASK) != M_ST_SUCC) { | |
1400 | printf("error: com %d opc 0x%x stat 0x%x\ndump ", | |
1401 | op, | |
1402 | udp->uda_Rsp.mscp_opcode, | |
1403 | udp->uda_Rsp.mscp_status); | |
1404 | return(0); | |
1405 | } | |
1406 | return(1); | |
db738443 | 1407 | } |
2f961121 | 1408 | |
94e9abff SL |
1409 | udsize(dev) |
1410 | dev_t dev; | |
1411 | { | |
dac559fa | 1412 | int unit = udunit(dev); |
94e9abff | 1413 | struct uba_device *ui; |
2f961121 | 1414 | struct size *rasizes; |
94e9abff | 1415 | |
8011f5df | 1416 | if (unit >= NRA || (ui = uddinfo[unit]) == 0 || ui->ui_alive == 0 |
2f961121 | 1417 | || ui->ui_flags == 0) |
94e9abff | 1418 | return (-1); |
2f961121 MK |
1419 | rasizes = ra_info[ui->ui_unit].ra_sizes; |
1420 | return (rasizes[minor(dev) & 07].nblocks); | |
94e9abff | 1421 | } |
2f961121 | 1422 | |
94e9abff | 1423 | #endif |