Commit | Line | Data |
---|---|---|
12d43ee5 KM |
1 | /* |
2 | * Copyright (c) 1992 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | * | |
10 | * @(#)rz.c 7.1 (Berkeley) %G% | |
11 | */ | |
12 | ||
13 | /* | |
14 | * SCSI CCS (Command Command Set) disk driver. | |
15 | * NOTE: The name was changed from "sd" to "rz" for DEC compatibility. | |
16 | * I guess I can't avoid confusion someplace. | |
17 | */ | |
18 | #include "rz.h" | |
19 | #if NRZ > 0 | |
20 | ||
21 | #include "param.h" | |
22 | #include "systm.h" | |
23 | #include "buf.h" | |
24 | #include "errno.h" | |
25 | #include "dkstat.h" | |
26 | #include "disklabel.h" | |
27 | #include "malloc.h" | |
28 | ||
29 | #include "device.h" | |
30 | #include "scsi.h" | |
31 | #include "devDiskLabel.h" | |
32 | ||
33 | #include "proc.h" | |
34 | #include "uio.h" | |
35 | ||
36 | extern void printf(); | |
37 | extern void bcopy(); | |
38 | extern void disksort(); | |
39 | extern int splbio(); | |
40 | extern void splx(); | |
41 | extern int physio(); | |
42 | ||
43 | int rzprobe(); | |
44 | void rzstrategy(), rzstart(), rzdone(); | |
45 | ||
46 | struct driver rzdriver = { | |
47 | "rz", rzprobe, rzstart, rzdone, | |
48 | }; | |
49 | ||
50 | struct size { | |
51 | u_long strtblk; | |
52 | u_long endblk; | |
53 | int nblocks; | |
54 | }; | |
55 | ||
56 | struct rzinfo { | |
57 | struct size part[8]; | |
58 | }; | |
59 | ||
60 | /* | |
61 | * Since the SCSI standard tends to hide the disk structure, we define | |
62 | * partitions in terms of DEV_BSIZE blocks. The default partition table | |
63 | * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg | |
64 | * root and 32 meg of swap. The rest of the space on the drive goes in | |
65 | * the G partition. As usual, the C partition covers the entire disk | |
66 | * (including the boot area). | |
67 | */ | |
68 | struct rzinfo rzdefaultpart = { | |
69 | 1024, 17408, 16384 , /* A */ | |
70 | 17408, 82944, 65536 , /* B */ | |
71 | 0, 0, 0 , /* C */ | |
72 | 17408, 115712, 98304 , /* D */ | |
73 | 115712, 218112, 102400 , /* E */ | |
74 | 218112, 0, 0 , /* F */ | |
75 | 82944, 0, 0 , /* G */ | |
76 | 115712, 0, 0 , /* H */ | |
77 | }; | |
78 | ||
79 | struct rzstats { | |
80 | long rzresets; | |
81 | long rztransfers; | |
82 | long rzpartials; | |
83 | }; | |
84 | ||
85 | struct rz_softc { | |
86 | struct scsi_device *sc_sd; /* physical unit info */ | |
87 | int sc_format_pid; /* process using "format" mode */ | |
88 | short sc_flags; /* see below */ | |
89 | short sc_type; /* drive type from INQUIRY cmd */ | |
90 | u_int sc_blks; /* number of blocks on device */ | |
91 | int sc_blksize; /* device block size in bytes */ | |
92 | int sc_bshift; /* convert device blocks to DEV_BSIZE */ | |
93 | u_int sc_wpms; /* average xfer rate in 16bit wds/sec */ | |
94 | struct rzinfo sc_info; /* drive partition table & label info */ | |
95 | struct rzstats sc_stats; /* statisic counts */ | |
96 | struct buf sc_tab; /* queue of pending operations */ | |
97 | struct buf sc_buf; /* buf for doing I/O */ | |
98 | struct buf sc_errbuf; /* buf for doing REQUEST_SENSE */ | |
99 | struct ScsiCmd sc_cmd; /* command for controller */ | |
100 | ScsiGroup1Cmd sc_rwcmd; /* SCSI cmd if not in "format" mode */ | |
101 | struct scsi_fmt_cdb sc_cdb; /* SCSI cmd if in "format" mode */ | |
102 | struct scsi_fmt_sense sc_sense; /* sense data from last cmd */ | |
103 | } rz_softc[NRZ]; | |
104 | ||
105 | /* sc_flags values */ | |
106 | #define RZF_ALIVE 0x1 /* drive found and ready */ | |
107 | #define RZF_SENSEINPROGRESS 0x2 /* REQUEST_SENSE command in progress */ | |
108 | ||
109 | #ifdef DEBUG | |
110 | int rzdebug = 3; | |
111 | #define RZB_ERROR 0x01 | |
112 | #define RZB_PARTIAL 0x02 | |
113 | #define RZB_PRLABEL 0x04 | |
114 | #endif | |
115 | ||
116 | #define rzunit(x) ((minor(x) >> 3) & 0x7) | |
117 | #define rzpart(x) (minor(x) & 0x7) | |
118 | #define b_cylin b_resid | |
119 | ||
120 | /* | |
121 | * Table of scsi commands users are allowed to access via "format" mode. | |
122 | * 0 means not legal. | |
123 | * 1 means legal. | |
124 | */ | |
125 | static char legal_cmds[256] = { | |
126 | /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ | |
127 | /*00*/ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
128 | /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, | |
129 | /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
130 | /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
131 | /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
132 | /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
133 | /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
134 | /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
135 | /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
136 | /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
137 | /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
138 | /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
139 | /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
140 | /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
141 | /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
142 | /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
143 | }; | |
144 | ||
145 | /* | |
146 | * Test to see if device is present. | |
147 | * Return true if found and initialized ok. | |
148 | */ | |
149 | rzprobe(sd) | |
150 | register struct scsi_device *sd; | |
151 | { | |
152 | register struct rz_softc *sc = &rz_softc[sd->sd_unit]; | |
153 | register int tries, i; | |
154 | ScsiInquiryData inqbuf; | |
155 | u_char capbuf[8]; | |
156 | ScsiClass7Sense *sp; | |
157 | ||
158 | /* init some parameters that don't change */ | |
159 | sc->sc_sd = sd; | |
160 | sc->sc_cmd.sd = sd; | |
161 | sc->sc_cmd.unit = sd->sd_unit; | |
162 | sc->sc_rwcmd.unitNumber = sd->sd_slave; | |
163 | ||
164 | /* try to find out what type of device this is */ | |
165 | sc->sc_format_pid = 1; /* force use of sc_cdb */ | |
166 | sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); | |
167 | scsiGroup0Cmd(SCSI_INQUIRY, sd->sd_slave, 0, sizeof(inqbuf), | |
168 | (ScsiGroup0Cmd *)sc->sc_cdb.cdb); | |
169 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
170 | sc->sc_buf.b_bcount = sizeof(inqbuf); | |
171 | sc->sc_buf.b_un.b_addr = (caddr_t)&inqbuf; | |
172 | sc->sc_buf.av_forw = (struct buf *)0; | |
173 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
174 | rzstart(sd->sd_unit); | |
175 | if (biowait(&sc->sc_buf) || | |
176 | (i = sizeof(inqbuf) - sc->sc_buf.b_resid) < 5) | |
177 | goto bad; | |
178 | switch (inqbuf.type) { | |
179 | case SCSI_DISK_TYPE: /* disk */ | |
180 | case SCSI_WORM_TYPE: /* WORM */ | |
181 | case SCSI_ROM_TYPE: /* CD-ROM */ | |
182 | case SCSI_OPTICAL_MEM_TYPE: /* Magneto-optical */ | |
183 | break; | |
184 | ||
185 | default: /* not a disk */ | |
186 | goto bad; | |
187 | } | |
188 | sc->sc_type = inqbuf.type; | |
189 | ||
190 | /* see if device is ready */ | |
191 | for (tries = 10; ; ) { | |
192 | sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); | |
193 | scsiGroup0Cmd(SCSI_TEST_UNIT_READY, sd->sd_slave, 0, 0, | |
194 | (ScsiGroup0Cmd *)sc->sc_cdb.cdb); | |
195 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
196 | sc->sc_buf.b_bcount = 0; | |
197 | sc->sc_buf.b_un.b_addr = (caddr_t)0; | |
198 | sc->sc_buf.av_forw = (struct buf *)0; | |
199 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
200 | ||
201 | sc->sc_cmd.cmd = sc->sc_cdb.cdb; | |
202 | sc->sc_cmd.cmdlen = sc->sc_cdb.len; | |
203 | sc->sc_cmd.buf = (caddr_t)0; | |
204 | sc->sc_cmd.buflen = 0; | |
205 | /* setup synchronous data transfers if the device supports it */ | |
206 | if (tries == 10 && (inqbuf.flags & SCSI_SYNC)) | |
207 | sc->sc_cmd.flags = SCSICMD_USE_SYNC; | |
208 | else | |
209 | sc->sc_cmd.flags = 0; | |
210 | ||
211 | (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); | |
212 | if (!biowait(&sc->sc_buf)) | |
213 | break; | |
214 | if (--tries < 0) | |
215 | goto bad; | |
216 | if (!(sc->sc_sense.status & SCSI_STATUS_CHECKCOND)) | |
217 | goto again; | |
218 | sp = (ScsiClass7Sense *)sc->sc_sense.sense; | |
219 | if (sp->error7 != 0x70) | |
220 | goto again; | |
221 | if (sp->key == SCSI_CLASS7_UNIT_ATTN && tries != 9) { | |
222 | /* drive recalibrating, give it a while */ | |
223 | DELAY(1000000); | |
224 | continue; | |
225 | } | |
226 | if (sp->key == SCSI_CLASS7_NOT_READY) { | |
227 | ScsiStartStopCmd *cp; | |
228 | ||
229 | /* try to spin-up disk with start/stop command */ | |
230 | sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); | |
231 | cp = (ScsiStartStopCmd *)sc->sc_cdb.cdb; | |
232 | cp->command = SCSI_START_STOP; | |
233 | cp->unitNumber = sd->sd_slave; | |
234 | cp->immed = 0; | |
235 | cp->loadEject = 0; | |
236 | cp->start = 1; | |
237 | cp->pad1 = 0; | |
238 | cp->pad2 = 0; | |
239 | cp->pad3 = 0; | |
240 | cp->pad4 = 0; | |
241 | cp->control = 0; | |
242 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
243 | sc->sc_buf.b_bcount = 0; | |
244 | sc->sc_buf.b_un.b_addr = (caddr_t)0; | |
245 | sc->sc_buf.av_forw = (struct buf *)0; | |
246 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
247 | rzstart(sd->sd_unit); | |
248 | if (biowait(&sc->sc_buf)) | |
249 | goto bad; | |
250 | continue; | |
251 | } | |
252 | again: | |
253 | DELAY(1000); | |
254 | } | |
255 | ||
256 | /* find out how big a disk this is */ | |
257 | sc->sc_cdb.len = sizeof(ScsiGroup1Cmd); | |
258 | scsiGroup1Cmd(SCSI_READ_CAPACITY, sd->sd_slave, 0, 0, | |
259 | (ScsiGroup1Cmd *)sc->sc_cdb.cdb); | |
260 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
261 | sc->sc_buf.b_bcount = sizeof(capbuf); | |
262 | sc->sc_buf.b_un.b_addr = (caddr_t)capbuf; | |
263 | sc->sc_buf.av_forw = (struct buf *)0; | |
264 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
265 | rzstart(sd->sd_unit); | |
266 | if (biowait(&sc->sc_buf) || sc->sc_buf.b_resid != 0) | |
267 | goto bad; | |
268 | sc->sc_blks = (capbuf[0] << 24) | (capbuf[1] << 16) | | |
269 | (capbuf[2] << 8) | capbuf[3]; | |
270 | sc->sc_blksize = (capbuf[4] << 24) | (capbuf[5] << 16) | | |
271 | (capbuf[6] << 8) | capbuf[7]; | |
272 | ||
273 | printf("rz%d at %s%d drive %d slave %d", sd->sd_unit, | |
274 | sd->sd_cdriver->d_name, sd->sd_ctlr, sd->sd_drive, | |
275 | sd->sd_slave); | |
276 | if (inqbuf.version > 1 || i < 36) | |
277 | printf(" type 0x%x, qual 0x%x, ver %d", | |
278 | inqbuf.type, inqbuf.qualifier, inqbuf.version); | |
279 | else { | |
280 | char vid[9], pid[17], revl[5]; | |
281 | ||
282 | bcopy((caddr_t)inqbuf.vendorID, (caddr_t)vid, 8); | |
283 | bcopy((caddr_t)inqbuf.productID, (caddr_t)pid, 16); | |
284 | bcopy((caddr_t)inqbuf.revLevel, (caddr_t)revl, 4); | |
285 | for (i = 8; --i > 0; ) | |
286 | if (vid[i] != ' ') | |
287 | break; | |
288 | vid[i+1] = 0; | |
289 | for (i = 16; --i > 0; ) | |
290 | if (pid[i] != ' ') | |
291 | break; | |
292 | pid[i+1] = 0; | |
293 | for (i = 4; --i > 0; ) | |
294 | if (revl[i] != ' ') | |
295 | break; | |
296 | revl[i+1] = 0; | |
297 | printf(" %s %s rev %s", vid, pid, revl); | |
298 | } | |
299 | printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); | |
300 | if (sc->sc_blksize != DEV_BSIZE) { | |
301 | if (sc->sc_blksize < DEV_BSIZE) { | |
302 | printf("rz%d: need %d byte blocks - drive ignored\n", | |
303 | sd->sd_unit, DEV_BSIZE); | |
304 | goto bad; | |
305 | } | |
306 | for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) | |
307 | ++sc->sc_bshift; | |
308 | sc->sc_blks <<= sc->sc_bshift; | |
309 | } | |
310 | sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ | |
311 | sc->sc_format_pid = 0; | |
312 | sc->sc_flags = RZF_ALIVE; | |
313 | ||
314 | /* try to read disk label or partition table information */ | |
315 | if (rzreadlabel(sc, sd) == 0) | |
316 | goto ok; | |
317 | ||
318 | /* | |
319 | * We don't have a disk label, build a default partition | |
320 | * table with 'standard' size root & swap and everything else | |
321 | * in the G partition. | |
322 | */ | |
323 | sc->sc_info = rzdefaultpart; | |
324 | /* C gets everything */ | |
325 | sc->sc_info.part[2].nblocks = sc->sc_blks; | |
326 | sc->sc_info.part[2].endblk = sc->sc_blks; | |
327 | /* G gets from end of B to end of disk */ | |
328 | sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk; | |
329 | sc->sc_info.part[6].endblk = sc->sc_blks; | |
330 | /* | |
331 | * We also define the D, E and F paritions as an alternative to | |
332 | * B and G. D is 48Mb, starts after A and is intended for swapping. | |
333 | * E is 50Mb, starts after D and is intended for /usr. F starts | |
334 | * after E and is what ever is left. | |
335 | */ | |
336 | if (sc->sc_blks >= sc->sc_info.part[4].endblk) { | |
337 | sc->sc_info.part[5].nblocks = | |
338 | sc->sc_blks - sc->sc_info.part[4].endblk; | |
339 | sc->sc_info.part[5].endblk = sc->sc_blks; | |
340 | } else { | |
341 | sc->sc_info.part[5].strtblk = 0; | |
342 | sc->sc_info.part[3] = sc->sc_info.part[5]; | |
343 | sc->sc_info.part[4] = sc->sc_info.part[5]; | |
344 | } | |
345 | /* | |
346 | * H is a single partition alternative to E and F. | |
347 | */ | |
348 | if (sc->sc_blks >= sc->sc_info.part[3].endblk) { | |
349 | sc->sc_info.part[7].nblocks = | |
350 | sc->sc_blks - sc->sc_info.part[3].endblk; | |
351 | sc->sc_info.part[7].endblk = sc->sc_blks; | |
352 | } else | |
353 | sc->sc_info.part[7].strtblk = 0; | |
354 | ||
355 | ok: | |
356 | sc->sc_buf.b_flags = 0; | |
357 | return (1); | |
358 | ||
359 | bad: | |
360 | /* doesn't exist or not a CCS device */ | |
361 | sc->sc_format_pid = 0; | |
362 | sc->sc_buf.b_flags = 0; | |
363 | return (0); | |
364 | } | |
365 | ||
366 | /* | |
367 | * Try to read the disk label and fill in the partition table info. | |
368 | */ | |
369 | static int | |
370 | rzreadlabel(sc, sd) | |
371 | register struct rz_softc *sc; | |
372 | register struct scsi_device *sd; | |
373 | { | |
374 | register struct size *sp; | |
375 | Sun_DiskLabel *sunLabelPtr; | |
376 | Dec_DiskLabel *decLabelPtr; | |
377 | char labelBuffer[DEV_BSIZE]; | |
378 | int part, error; | |
379 | ||
380 | /* | |
381 | * The label of a SCSI disk normally resides in the first sector. | |
382 | * Format and send a SCSI READ command to fetch the sector. | |
383 | */ | |
384 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
385 | sc->sc_buf.b_bcount = sizeof(labelBuffer); | |
386 | sc->sc_buf.b_un.b_addr = labelBuffer; | |
387 | sc->sc_buf.b_cylin = SUN_LABEL_SECTOR; | |
388 | sc->sc_buf.av_forw = (struct buf *)0; | |
389 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
390 | rzstart(sd->sd_unit); | |
391 | if (error = biowait(&sc->sc_buf)) | |
392 | return (error); | |
393 | sunLabelPtr = (Sun_DiskLabel *)labelBuffer; | |
394 | if (sunLabelPtr->magic == SUN_DISK_MAGIC) { | |
395 | /* | |
396 | * XXX - Should really check if label is valid. | |
397 | */ | |
398 | #ifdef DEBUG | |
399 | if (rzdebug & RZB_PRLABEL) { | |
400 | printf("rz%d: SUN label %s\n", sd->sd_unit, | |
401 | sunLabelPtr->asciiLabel); | |
402 | printf(" Partitions"); | |
403 | } | |
404 | #endif | |
405 | sp = sc->sc_info.part; | |
406 | for (part = 0; part < DEV_NUM_DISK_PARTS; part++, sp++) { | |
407 | sp->strtblk = | |
408 | sunLabelPtr->map[part].cylinder * | |
409 | sunLabelPtr->numHeads * | |
410 | sunLabelPtr->numSectors; | |
411 | sp->nblocks = | |
412 | sunLabelPtr->map[part].numBlocks; | |
413 | sp->endblk = sp->strtblk + sp->nblocks; | |
414 | #ifdef DEBUG | |
415 | if (rzdebug & RZB_PRLABEL) | |
416 | printf(" (%d,%d)", sp->strtblk, sp->nblocks); | |
417 | #endif | |
418 | } | |
419 | #ifdef DEBUG | |
420 | if (rzdebug & RZB_PRLABEL) | |
421 | printf("\n"); | |
422 | #endif | |
423 | return (0); | |
424 | } | |
425 | ||
426 | /* | |
427 | * The disk isn't in SUN or UNIX format so try Dec format. | |
428 | * We have to read the right sector first. | |
429 | */ | |
430 | sc->sc_buf.b_flags = B_BUSY | B_PHYS | B_READ; | |
431 | sc->sc_buf.b_bcount = sizeof(labelBuffer); | |
432 | sc->sc_buf.b_un.b_addr = labelBuffer; | |
433 | sc->sc_buf.b_cylin = DEC_LABEL_SECTOR; | |
434 | sc->sc_buf.av_forw = (struct buf *)0; | |
435 | sc->sc_tab.b_actf = sc->sc_tab.b_actl = &sc->sc_buf; | |
436 | rzstart(sd->sd_unit); | |
437 | if (error = biowait(&sc->sc_buf)) | |
438 | return (error); | |
439 | decLabelPtr = (Dec_DiskLabel *)labelBuffer; | |
440 | if (decLabelPtr->magic == DEC_LABEL_MAGIC && | |
441 | decLabelPtr->isPartitioned) { | |
442 | /* | |
443 | * XXX - Should really check if label is valid. | |
444 | */ | |
445 | #ifdef DEBUG | |
446 | if (rzdebug & RZB_PRLABEL) { | |
447 | printf("rz%d: DEC label\n", sd->sd_unit); | |
448 | printf(" Partitions"); | |
449 | } | |
450 | #endif | |
451 | sp = sc->sc_info.part; | |
452 | for (part = 0; part < DEV_NUM_DISK_PARTS; part++, sp++) { | |
453 | sp->strtblk = decLabelPtr->map[part].startBlock; | |
454 | sp->nblocks = decLabelPtr->map[part].numBlocks; | |
455 | sp->endblk = sp->strtblk + sp->nblocks; | |
456 | #ifdef DEBUG | |
457 | if (rzdebug & RZB_PRLABEL) | |
458 | printf(" (%d,%d)", sp->strtblk, sp->nblocks); | |
459 | #endif | |
460 | } | |
461 | #ifdef DEBUG | |
462 | if (rzdebug & RZB_PRLABEL) | |
463 | printf("\n"); | |
464 | #endif | |
465 | return (0); | |
466 | } | |
467 | return (EIO); | |
468 | } | |
469 | ||
470 | /* | |
471 | * This routine is called for partial block transfers and non-aligned | |
472 | * transfers (the latter only being possible on devices with a block size | |
473 | * larger than DEV_BSIZE). The operation is performed in three steps | |
474 | * using a locally allocated buffer: | |
475 | * 1. transfer any initial partial block | |
476 | * 2. transfer full blocks | |
477 | * 3. transfer any final partial block | |
478 | */ | |
479 | static void | |
480 | rzlblkstrat(bp, bsize) | |
481 | register struct buf *bp; | |
482 | register int bsize; | |
483 | { | |
484 | register struct buf *cbp; | |
485 | caddr_t cbuf; | |
486 | register int bn, resid; | |
487 | register caddr_t addr; | |
488 | ||
489 | cbp = (struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK); | |
490 | cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); | |
491 | bzero((caddr_t)cbp, sizeof(*cbp)); | |
492 | cbp->b_proc = curproc; | |
493 | cbp->b_dev = bp->b_dev; | |
494 | bn = bp->b_blkno; | |
495 | resid = bp->b_bcount; | |
496 | addr = bp->b_un.b_addr; | |
497 | #ifdef DEBUG | |
498 | if (rzdebug & RZB_PARTIAL) | |
499 | printf("rzlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", | |
500 | bp, bp->b_flags, bn, resid, addr); | |
501 | #endif | |
502 | ||
503 | while (resid > 0) { | |
504 | register int boff = dbtob(bn) & (bsize - 1); | |
505 | register int count; | |
506 | ||
507 | if (boff || resid < bsize) { | |
508 | rz_softc[rzunit(bp->b_dev)].sc_stats.rzpartials++; | |
509 | count = MIN(resid, bsize - boff); | |
510 | cbp->b_flags = B_BUSY | B_PHYS | B_READ; | |
511 | cbp->b_blkno = bn - btodb(boff); | |
512 | cbp->b_un.b_addr = cbuf; | |
513 | cbp->b_bcount = bsize; | |
514 | #ifdef DEBUG | |
515 | if (rzdebug & RZB_PARTIAL) | |
516 | printf(" readahead: bn %x cnt %x off %x addr %x\n", | |
517 | cbp->b_blkno, count, boff, addr); | |
518 | #endif | |
519 | rzstrategy(cbp); | |
520 | biowait(cbp); | |
521 | if (cbp->b_flags & B_ERROR) { | |
522 | bp->b_flags |= B_ERROR; | |
523 | bp->b_error = cbp->b_error; | |
524 | break; | |
525 | } | |
526 | if (bp->b_flags & B_READ) { | |
527 | bcopy(&cbuf[boff], addr, count); | |
528 | goto done; | |
529 | } | |
530 | bcopy(addr, &cbuf[boff], count); | |
531 | #ifdef DEBUG | |
532 | if (rzdebug & RZB_PARTIAL) | |
533 | printf(" writeback: bn %x cnt %x off %x addr %x\n", | |
534 | cbp->b_blkno, count, boff, addr); | |
535 | #endif | |
536 | } else { | |
537 | count = resid & ~(bsize - 1); | |
538 | cbp->b_blkno = bn; | |
539 | cbp->b_un.b_addr = addr; | |
540 | cbp->b_bcount = count; | |
541 | #ifdef DEBUG | |
542 | if (rzdebug & RZB_PARTIAL) | |
543 | printf(" fulltrans: bn %x cnt %x addr %x\n", | |
544 | cbp->b_blkno, count, addr); | |
545 | #endif | |
546 | } | |
547 | cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); | |
548 | rzstrategy(cbp); | |
549 | biowait(cbp); | |
550 | if (cbp->b_flags & B_ERROR) { | |
551 | bp->b_flags |= B_ERROR; | |
552 | bp->b_error = cbp->b_error; | |
553 | break; | |
554 | } | |
555 | done: | |
556 | bn += btodb(count); | |
557 | resid -= count; | |
558 | addr += count; | |
559 | #ifdef DEBUG | |
560 | if (rzdebug & RZB_PARTIAL) | |
561 | printf(" done: bn %x resid %x addr %x\n", | |
562 | bn, resid, addr); | |
563 | #endif | |
564 | } | |
565 | free(cbuf, M_DEVBUF); | |
566 | free(cbp, M_DEVBUF); | |
567 | } | |
568 | ||
569 | void | |
570 | rzstrategy(bp) | |
571 | register struct buf *bp; | |
572 | { | |
573 | register int unit = rzunit(bp->b_dev); | |
574 | register int part = rzpart(bp->b_dev); | |
575 | register int bn, sz; | |
576 | register struct rz_softc *sc = &rz_softc[unit]; | |
577 | register int s; | |
578 | ||
579 | if (sc->sc_format_pid) { | |
580 | if (sc->sc_format_pid != curproc->p_pid) { | |
581 | bp->b_error = EPERM; | |
582 | goto bad; | |
583 | } | |
584 | bp->b_cylin = 0; | |
585 | } else { | |
586 | bn = bp->b_blkno; | |
587 | sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT; | |
588 | if (bn < 0 || bn + sz > sc->sc_info.part[part].nblocks) { | |
589 | if (bn == sc->sc_info.part[part].nblocks) { | |
590 | bp->b_resid = bp->b_bcount; | |
591 | goto done; | |
592 | } | |
593 | bp->b_error = EINVAL; | |
594 | goto bad; | |
595 | } | |
596 | /* | |
597 | * Non-aligned or partial-block transfers handled specially. | |
598 | */ | |
599 | s = sc->sc_blksize - 1; | |
600 | if ((dbtob(bn) & s) || (bp->b_bcount & s)) { | |
601 | rzlblkstrat(bp, sc->sc_blksize); | |
602 | goto done; | |
603 | } | |
604 | bp->b_cylin = (bn + sc->sc_info.part[part].strtblk) >> | |
605 | sc->sc_bshift; | |
606 | } | |
607 | /* don't let disksort() see sc_errbuf */ | |
608 | while (sc->sc_flags & RZF_SENSEINPROGRESS) | |
609 | printf("SENSE\n"); /* XXX */ | |
610 | s = splbio(); | |
611 | disksort(&sc->sc_tab, bp); | |
612 | if (sc->sc_tab.b_active == 0) { | |
613 | sc->sc_tab.b_active = 1; | |
614 | rzstart(unit); | |
615 | } | |
616 | splx(s); | |
617 | return; | |
618 | bad: | |
619 | bp->b_flags |= B_ERROR; | |
620 | done: | |
621 | biodone(bp); | |
622 | } | |
623 | ||
624 | void | |
625 | rzstart(unit) | |
626 | int unit; | |
627 | { | |
628 | register struct rz_softc *sc = &rz_softc[unit]; | |
629 | register struct buf *bp = sc->sc_tab.b_actf; | |
630 | register int n; | |
631 | ||
632 | sc->sc_cmd.buf = bp->b_un.b_addr; | |
633 | sc->sc_cmd.buflen = bp->b_bcount; | |
634 | ||
635 | if (sc->sc_format_pid || (sc->sc_flags & RZF_SENSEINPROGRESS)) { | |
636 | sc->sc_cmd.flags = !(bp->b_flags & B_READ) ? | |
637 | SCSICMD_DATA_TO_DEVICE : 0; | |
638 | sc->sc_cmd.cmd = sc->sc_cdb.cdb; | |
639 | sc->sc_cmd.cmdlen = sc->sc_cdb.len; | |
640 | } else { | |
641 | if (bp->b_flags & B_READ) { | |
642 | sc->sc_cmd.flags = 0; | |
643 | sc->sc_rwcmd.command = SCSI_READ_EXT; | |
644 | } else { | |
645 | sc->sc_cmd.flags = SCSICMD_DATA_TO_DEVICE; | |
646 | sc->sc_rwcmd.command = SCSI_WRITE_EXT; | |
647 | } | |
648 | sc->sc_cmd.cmd = (u_char *)&sc->sc_rwcmd; | |
649 | sc->sc_cmd.cmdlen = sizeof(sc->sc_rwcmd); | |
650 | n = bp->b_cylin; | |
651 | sc->sc_rwcmd.highAddr = n >> 24; | |
652 | sc->sc_rwcmd.midHighAddr = n >> 16; | |
653 | sc->sc_rwcmd.midLowAddr = n >> 8; | |
654 | sc->sc_rwcmd.lowAddr = n; | |
655 | n = howmany(bp->b_bcount, sc->sc_blksize); | |
656 | sc->sc_rwcmd.highBlockCount = n >> 8; | |
657 | sc->sc_rwcmd.lowBlockCount = n; | |
658 | #ifdef DEBUG | |
659 | if ((bp->b_bcount & (sc->sc_blksize - 1)) != 0) | |
660 | printf("rz%d: partial block xfer -- %x bytes\n", | |
661 | unit, bp->b_bcount); | |
662 | #endif | |
663 | sc->sc_stats.rztransfers++; | |
664 | if ((n = sc->sc_sd->sd_dk) >= 0) { | |
665 | dk_busy |= 1 << n; | |
666 | ++dk_seek[n]; | |
667 | ++dk_xfer[n]; | |
668 | dk_wds[n] += bp->b_bcount >> 6; | |
669 | } | |
670 | } | |
671 | ||
672 | /* tell controller to start this command */ | |
673 | (*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd); | |
674 | } | |
675 | ||
676 | /* | |
677 | * This is called by the controller driver when the command is done. | |
678 | */ | |
679 | void | |
680 | rzdone(unit, error, resid, status) | |
681 | register int unit; | |
682 | int error; /* error number from errno.h */ | |
683 | int resid; /* amount not transfered */ | |
684 | int status; /* SCSI status byte */ | |
685 | { | |
686 | register struct rz_softc *sc = &rz_softc[unit]; | |
687 | register struct buf *bp = sc->sc_tab.b_actf; | |
688 | register struct scsi_device *sd = sc->sc_sd; | |
689 | extern int cold; | |
690 | ||
691 | if (bp == NULL) { | |
692 | printf("rz%d: bp == NULL\n", unit); | |
693 | return; | |
694 | } | |
695 | if (sd->sd_dk >= 0) | |
696 | dk_busy &= ~(1 << sd->sd_dk); | |
697 | if (sc->sc_flags & RZF_SENSEINPROGRESS) { | |
698 | sc->sc_flags &= ~RZF_SENSEINPROGRESS; | |
699 | sc->sc_tab.b_actf = bp = bp->av_forw; /* remove sc_errbuf */ | |
700 | ||
701 | if (error || (status & SCSI_STATUS_CHECKCOND)) { | |
702 | #ifdef DEBUG | |
703 | if (rzdebug & RZB_ERROR) | |
704 | printf("rz%d: error reading sense data: error %d scsi status 0x%x\n", | |
705 | unit, error, status); | |
706 | #endif | |
707 | /* | |
708 | * We got an error during the REQUEST_SENSE, | |
709 | * fill in no sense for data. | |
710 | */ | |
711 | sc->sc_sense.sense[0] = 0x70; | |
712 | sc->sc_sense.sense[2] = SCSI_CLASS7_NO_SENSE; | |
713 | } else if (!cold | |
714 | #ifdef DEBUG | |
715 | || (rzdebug & RZB_ERROR) | |
716 | #endif | |
717 | ) { | |
718 | printf("rz%d: ", unit); | |
719 | scsiPrintSense((ScsiClass7Sense *)sc->sc_sense.sense, | |
720 | sizeof(sc->sc_sense.sense) - resid); | |
721 | } | |
722 | } else if (error || (status & SCSI_STATUS_CHECKCOND)) { | |
723 | #ifdef DEBUG | |
724 | if (rzdebug & RZB_ERROR) | |
725 | printf("rz%d: error %d scsi status 0x%x\n", | |
726 | unit, error, status); | |
727 | #endif | |
728 | /* save error info */ | |
729 | sc->sc_sense.status = status; | |
730 | bp->b_flags |= B_ERROR; | |
731 | bp->b_error = error; | |
732 | bp->b_resid = resid; | |
733 | ||
734 | if (status & SCSI_STATUS_CHECKCOND) { | |
735 | /* | |
736 | * Start a REQUEST_SENSE command. | |
737 | * Since we are called at interrupt time, we can't | |
738 | * wait for the command to finish; that's why we use | |
739 | * the sc_flags field. | |
740 | */ | |
741 | sc->sc_flags |= RZF_SENSEINPROGRESS; | |
742 | sc->sc_cdb.len = sizeof(ScsiGroup0Cmd); | |
743 | scsiGroup0Cmd(SCSI_REQUEST_SENSE, sd->sd_slave, 0, | |
744 | sizeof(sc->sc_sense.sense), | |
745 | (ScsiGroup0Cmd *)sc->sc_cdb.cdb); | |
746 | sc->sc_errbuf.b_flags = B_BUSY | B_PHYS | B_READ; | |
747 | sc->sc_errbuf.b_bcount = sizeof(sc->sc_sense.sense); | |
748 | sc->sc_errbuf.b_un.b_addr = (caddr_t)sc->sc_sense.sense; | |
749 | sc->sc_errbuf.av_forw = bp; | |
750 | sc->sc_tab.b_actf = &sc->sc_errbuf; | |
751 | rzstart(unit); | |
752 | return; | |
753 | } | |
754 | } else { | |
755 | sc->sc_sense.status = status; | |
756 | bp->b_resid = resid; | |
757 | } | |
758 | ||
759 | sc->sc_tab.b_actf = bp->av_forw; | |
760 | biodone(bp); | |
761 | if (sc->sc_tab.b_actf) | |
762 | rzstart(unit); | |
763 | else | |
764 | sc->sc_tab.b_active = 0; | |
765 | } | |
766 | ||
767 | int | |
768 | rzopen(dev, flags, mode, p) | |
769 | dev_t dev; | |
770 | int flags, mode; | |
771 | struct proc *p; | |
772 | { | |
773 | register int unit = rzunit(dev); | |
774 | register struct rz_softc *sc = &rz_softc[unit]; | |
775 | ||
776 | if (unit >= NRZ) | |
777 | return (ENXIO); | |
778 | if (!(sc->sc_flags & RZF_ALIVE) || suser(p->p_ucred, &p->p_acflag)) | |
779 | return (ENXIO); | |
780 | ||
781 | if (sc->sc_sd->sd_dk >= 0) | |
782 | dk_wpms[sc->sc_sd->sd_dk] = sc->sc_wpms; | |
783 | return (0); | |
784 | } | |
785 | ||
786 | rzclose(dev, flags) | |
787 | dev_t dev; | |
788 | int flags; | |
789 | { | |
790 | return (0); | |
791 | } | |
792 | ||
793 | int | |
794 | rzread(dev, uio) | |
795 | dev_t dev; | |
796 | struct uio *uio; | |
797 | { | |
798 | register struct rz_softc *sc = &rz_softc[rzunit(dev)]; | |
799 | ||
800 | if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) | |
801 | return (EPERM); | |
802 | ||
803 | return (physio(rzstrategy, (struct buf *)0, dev, | |
804 | B_READ, minphys, uio)); | |
805 | } | |
806 | ||
807 | int | |
808 | rzwrite(dev, uio) | |
809 | dev_t dev; | |
810 | struct uio *uio; | |
811 | { | |
812 | register struct rz_softc *sc = &rz_softc[rzunit(dev)]; | |
813 | ||
814 | if (sc->sc_format_pid && sc->sc_format_pid != curproc->p_pid) | |
815 | return (EPERM); | |
816 | ||
817 | return (physio(rzstrategy, (struct buf *)0, dev, | |
818 | B_WRITE, minphys, uio)); | |
819 | } | |
820 | ||
821 | int | |
822 | rzioctl(dev, cmd, data, flag, p) | |
823 | dev_t dev; | |
824 | int cmd; | |
825 | caddr_t data; | |
826 | int flag; | |
827 | struct proc *p; | |
828 | { | |
829 | register struct rz_softc *sc = &rz_softc[rzunit(dev)]; | |
830 | ||
831 | switch (cmd) { | |
832 | default: | |
833 | return (EINVAL); | |
834 | ||
835 | case SDIOCSFORMAT: | |
836 | /* take this device into or out of "format" mode */ | |
837 | if (suser(p->p_ucred, &p->p_acflag)) | |
838 | return (EPERM); | |
839 | ||
840 | if (*(int *)data) { | |
841 | if (sc->sc_format_pid) | |
842 | return (EPERM); | |
843 | sc->sc_format_pid = p->p_pid; | |
844 | } else | |
845 | sc->sc_format_pid = 0; | |
846 | return (0); | |
847 | ||
848 | case SDIOCGFORMAT: | |
849 | /* find out who has the device in format mode */ | |
850 | *(int *)data = sc->sc_format_pid; | |
851 | return (0); | |
852 | ||
853 | case SDIOCSCSICOMMAND: | |
854 | /* | |
855 | * Save what user gave us as SCSI cdb to use with next | |
856 | * read or write to the char device. | |
857 | */ | |
858 | if (sc->sc_format_pid != p->p_pid) | |
859 | return (EPERM); | |
860 | if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) | |
861 | return (EINVAL); | |
862 | bcopy(data, (caddr_t)&sc->sc_cdb, sizeof(sc->sc_cdb)); | |
863 | return (0); | |
864 | ||
865 | case SDIOCSENSE: | |
866 | /* | |
867 | * return the SCSI sense data saved after the last | |
868 | * operation that completed with "check condition" status. | |
869 | */ | |
870 | bcopy((caddr_t)&sc->sc_sense, data, sizeof(sc->sc_sense)); | |
871 | return (0); | |
872 | ||
873 | } | |
874 | /*NOTREACHED*/ | |
875 | } | |
876 | ||
877 | int | |
878 | rzsize(dev) | |
879 | dev_t dev; | |
880 | { | |
881 | register int unit = rzunit(dev); | |
882 | register struct rz_softc *sc = &rz_softc[unit]; | |
883 | ||
884 | if (unit >= NRZ || !(sc->sc_flags & RZF_ALIVE)) | |
885 | return (-1); | |
886 | ||
887 | return (sc->sc_info.part[rzpart(dev)].nblocks); | |
888 | } | |
889 | ||
890 | /* | |
891 | * Non-interrupt driven, non-dma dump routine. | |
892 | */ | |
893 | int | |
894 | rzdump(dev) | |
895 | dev_t dev; | |
896 | { | |
897 | #ifdef notdef | |
898 | int part = rzpart(dev); | |
899 | int unit = rzunit(dev); | |
900 | register struct rz_softc *sc = &rz_softc[unit]; | |
901 | register struct scsi_device *sd = sc->sc_hd; | |
902 | register daddr_t baddr; | |
903 | register int maddr; | |
904 | register int pages, i; | |
905 | int stat; | |
906 | extern int lowram; | |
907 | ||
908 | /* | |
909 | * Hmm... all vax drivers dump maxfree pages which is physmem minus | |
910 | * the message buffer. Is there a reason for not dumping the | |
911 | * message buffer? Savecore expects to read 'dumpsize' pages of | |
912 | * dump, where dumpsys() sets dumpsize to physmem! | |
913 | */ | |
914 | pages = physmem; | |
915 | ||
916 | /* is drive ok? */ | |
917 | if (unit >= NRZ || (sc->sc_flags & RZF_ALIVE) == 0) | |
918 | return (ENXIO); | |
919 | /* dump parameters in range? */ | |
920 | if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) | |
921 | return (EINVAL); | |
922 | if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) | |
923 | pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); | |
924 | maddr = lowram; | |
925 | baddr = dumplo + sc->sc_info.part[part].strtblk; | |
926 | /* scsi bus idle? */ | |
927 | if (!scsireq(&sc->sc_dq)) { | |
928 | scsireset(sd->sd_ctlr); | |
929 | sc->sc_stats.rzresets++; | |
930 | printf("[ drive %d reset ] ", unit); | |
931 | } | |
932 | for (i = 0; i < pages; i++) { | |
933 | #define NPGMB (1024*1024/NBPG) | |
934 | /* print out how many Mbs we have dumped */ | |
935 | if (i && (i % NPGMB) == 0) | |
936 | printf("%d ", i / NPGMB); | |
937 | #undef NPBMG | |
938 | mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); | |
939 | stat = scsi_tt_write(sd->sd_ctlr, sd->sd_drive, sd->sd_slave, | |
940 | vmmap, NBPG, baddr, sc->sc_bshift); | |
941 | if (stat) { | |
942 | printf("rzdump: scsi write error 0x%x\n", stat); | |
943 | return (EIO); | |
944 | } | |
945 | maddr += NBPG; | |
946 | baddr += ctod(1); | |
947 | } | |
948 | return (0); | |
949 | #else notdef | |
950 | return (ENXIO); | |
951 | #endif notdef | |
952 | } | |
953 | #endif |