Commit | Line | Data |
---|---|---|
60f56dfc KM |
1 | /* |
2 | * Copyright (c) 1990 The 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. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | * | |
029e208f | 10 | * @(#)sd.c 7.2 (Berkeley) %G% |
60f56dfc KM |
11 | */ |
12 | ||
13 | /* | |
14 | * SCSI CCS (Command Command Set) disk driver. | |
15 | */ | |
16 | #include "sd.h" | |
17 | #if NSD > 0 | |
18 | ||
19 | #ifndef lint | |
20 | static char rcsid[] = "$Header: sd.c,v 1.5 90/01/10 16:06:12 mike Locked $"; | |
21 | #endif | |
22 | ||
23 | #include "param.h" | |
24 | #include "systm.h" | |
25 | #include "buf.h" | |
26 | #include "errno.h" | |
27 | #include "dkstat.h" | |
28 | #include "disklabel.h" | |
29 | #include "device.h" | |
30 | #include "malloc.h" | |
31 | #include "scsireg.h" | |
32 | ||
33 | #include "user.h" | |
34 | #include "proc.h" | |
35 | #include "uio.h" | |
36 | ||
37 | extern int scsi_test_unit_rdy(); | |
38 | extern int scsi_request_sense(); | |
39 | extern int scsi_inquiry(); | |
40 | extern int scsi_read_capacity(); | |
41 | extern int scsi_tt_write(); | |
42 | extern int scsireq(); | |
43 | extern int scsiustart(); | |
44 | extern int scsigo(); | |
45 | extern void scsifree(); | |
46 | extern void scsireset(); | |
47 | ||
48 | extern void printf(); | |
49 | extern void bcopy(); | |
50 | extern void disksort(); | |
51 | extern int splbio(); | |
52 | extern void splx(); | |
53 | extern void biodone(); | |
54 | extern int physio(); | |
55 | extern void TBIS(); | |
56 | ||
57 | int sdinit(); | |
58 | void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr(); | |
59 | ||
60 | struct driver sddriver = { | |
61 | sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr, | |
62 | }; | |
63 | ||
64 | struct size { | |
65 | u_long strtblk; | |
66 | u_long endblk; | |
67 | int nblocks; | |
68 | }; | |
69 | ||
70 | struct sdinfo { | |
71 | struct size part[8]; | |
72 | }; | |
73 | ||
74 | /* | |
75 | * since the SCSI standard tends to hide the disk structure, we define | |
76 | * partitions in terms of DEV_BSIZE blocks. The default partition table | |
77 | * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg | |
78 | * root and 32 meg of swap. The rest of the space on the drive goes in | |
79 | * the G partition. As usual, the C partition covers the entire disk | |
80 | * (including the boot area). | |
81 | */ | |
82 | struct sdinfo sddefaultpart = { | |
83 | 1024, 17408, 16384 , /* A */ | |
84 | 17408, 82944, 65536 , /* B */ | |
85 | 0, 0, 0 , /* C */ | |
86 | 17408, 115712, 98304 , /* D */ | |
87 | 115712, 218112, 102400 , /* E */ | |
88 | 218112, 0, 0 , /* F */ | |
89 | 82944, 0, 0 , /* G */ | |
90 | 115712, 0, 0 , /* H */ | |
91 | }; | |
92 | ||
93 | struct sd_softc { | |
94 | struct hp_device *sc_hd; | |
95 | struct devqueue sc_dq; | |
96 | int sc_format_pid; /* process using "format" mode */ | |
97 | short sc_flags; | |
98 | short sc_type; /* drive type */ | |
99 | short sc_punit; /* physical unit (scsi lun) */ | |
100 | u_short sc_bshift; /* convert device blocks to DEV_BSIZE blks */ | |
101 | u_int sc_blks; /* number of blocks on device */ | |
102 | int sc_blksize; /* device block size in bytes */ | |
103 | u_int sc_wpms; /* average xfer rate in 16 bit wds/sec. */ | |
104 | struct sdinfo sc_info; /* drive partition table & label info */ | |
105 | } sd_softc[NSD]; | |
106 | ||
107 | /* sc_flags values */ | |
108 | #define SDF_ALIVE 0x1 | |
109 | ||
110 | #ifdef DEBUG | |
111 | int sddebug = 1; | |
112 | #define SDB_ERROR 0x01 | |
113 | #define SDB_PARTIAL 0x02 | |
114 | #endif | |
115 | ||
116 | struct sdstats { | |
117 | long sdresets; | |
118 | long sdtransfers; | |
119 | long sdpartials; | |
120 | } sdstats[NSD]; | |
121 | ||
122 | struct buf sdtab[NSD]; | |
123 | struct buf sdbuf[NSD]; | |
124 | struct scsi_fmt_cdb sdcmd[NSD]; | |
125 | struct scsi_fmt_sense sdsense[NSD]; | |
126 | ||
127 | static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT }; | |
128 | static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT }; | |
129 | ||
130 | #define sdunit(x) ((minor(x) >> 3) & 0x7) | |
131 | #define sdpart(x) (minor(x) & 0x7) | |
132 | #define sdpunit(x) ((x) & 7) | |
133 | #define b_cylin b_resid | |
134 | #define SDRETRY 2 | |
135 | ||
136 | /* | |
137 | * Table of scsi commands users are allowed to access via "format" | |
138 | * mode. 0 means not legal. 1 means "immediate" (doesn't need dma). | |
139 | * -1 means needs dma and/or wait for intr. | |
140 | */ | |
141 | static char legal_cmds[256] = { | |
142 | /***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */ | |
143 | /*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
144 | /*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, | |
145 | /*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
146 | /*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
147 | /*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
148 | /*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
149 | /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
150 | /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
151 | /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
152 | /*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
153 | /*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
154 | /*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
155 | /*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
156 | /*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
157 | /*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
158 | /*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
159 | }; | |
160 | ||
161 | static struct scsi_inquiry inqbuf; | |
162 | static struct scsi_fmt_cdb inq = { | |
163 | 6, | |
164 | CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 | |
165 | }; | |
166 | ||
167 | static u_char capbuf[8]; | |
168 | struct scsi_fmt_cdb cap = { | |
169 | 10, | |
170 | CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
171 | }; | |
172 | ||
173 | static int | |
174 | sdident(sc, hd) | |
175 | struct sd_softc *sc; | |
176 | struct hp_device *hd; | |
177 | { | |
178 | int unit; | |
179 | register int ctlr, slave; | |
180 | register int i; | |
181 | register int tries = 10; | |
182 | ||
183 | ctlr = hd->hp_ctlr; | |
184 | slave = hd->hp_slave; | |
185 | unit = sc->sc_punit; | |
186 | ||
187 | /* | |
188 | * See if unit exists and is a disk then read block size & nblocks. | |
189 | */ | |
190 | while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) { | |
191 | if (i == -1 || --tries < 0) | |
192 | /* doesn't exist or not a CCS device */ | |
193 | return (-1); | |
194 | if (i == STS_CHECKCOND) { | |
195 | u_char sensebuf[128]; | |
196 | struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; | |
197 | ||
198 | scsi_request_sense(ctlr, slave, unit, sensebuf, | |
199 | sizeof(sensebuf)); | |
200 | if (sp->class == 7 && sp->key == 6) | |
201 | /* drive doing an RTZ -- give it a while */ | |
202 | DELAY(1000000); | |
203 | } | |
204 | DELAY(1000); | |
205 | } | |
206 | if (scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf, | |
207 | sizeof(inqbuf), B_READ) || | |
208 | scsi_immed_command(ctlr, slave, unit, &cap, (u_char *)&capbuf, | |
209 | sizeof(capbuf), B_READ)) | |
210 | /* doesn't exist or not a CCS device */ | |
211 | return (-1); | |
212 | ||
213 | switch (inqbuf.type) { | |
214 | case 0: /* disk */ | |
215 | case 4: /* WORM */ | |
216 | case 5: /* CD-ROM */ | |
217 | case 7: /* Magneto-optical */ | |
218 | break; | |
219 | default: /* not a disk */ | |
220 | return (-1); | |
221 | } | |
222 | sc->sc_blks = *(u_int *)&capbuf[0]; | |
223 | sc->sc_blksize = *(int *)&capbuf[4]; | |
224 | ||
225 | if (inqbuf.version != 1) | |
226 | printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit, | |
227 | inqbuf.type, inqbuf.qual, inqbuf.version); | |
228 | else { | |
229 | char idstr[32]; | |
230 | ||
231 | bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28); | |
232 | for (i = 27; i > 23; --i) | |
233 | if (idstr[i] != ' ') | |
234 | break; | |
235 | idstr[i+1] = 0; | |
236 | for (i = 23; i > 7; --i) | |
237 | if (idstr[i] != ' ') | |
238 | break; | |
239 | idstr[i+1] = 0; | |
240 | for (i = 7; i >= 0; --i) | |
241 | if (idstr[i] != ' ') | |
242 | break; | |
243 | idstr[i+1] = 0; | |
244 | printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8], | |
245 | &idstr[24]); | |
246 | } | |
247 | printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize); | |
248 | if (sc->sc_blksize != DEV_BSIZE) { | |
249 | if (sc->sc_blksize < DEV_BSIZE) { | |
250 | printf("sd%d: need %d byte blocks - drive ignored\n", | |
251 | unit, DEV_BSIZE); | |
252 | return (-1); | |
253 | } | |
254 | for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1) | |
255 | ++sc->sc_bshift; | |
256 | sc->sc_blks <<= sc->sc_bshift; | |
257 | } | |
258 | sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */ | |
259 | return(inqbuf.type); | |
260 | } | |
261 | ||
262 | int | |
263 | sdinit(hd) | |
264 | register struct hp_device *hd; | |
265 | { | |
266 | register struct sd_softc *sc = &sd_softc[hd->hp_unit]; | |
267 | ||
268 | sc->sc_hd = hd; | |
269 | sc->sc_punit = sdpunit(hd->hp_flags); | |
270 | sc->sc_type = sdident(sc, hd); | |
271 | if (sc->sc_type < 0) | |
272 | return(0); | |
273 | sc->sc_dq.dq_ctlr = hd->hp_ctlr; | |
274 | sc->sc_dq.dq_unit = hd->hp_unit; | |
275 | sc->sc_dq.dq_slave = hd->hp_slave; | |
276 | sc->sc_dq.dq_driver = &sddriver; | |
277 | ||
278 | /* | |
279 | * If we don't have a disk label, build a default partition | |
280 | * table with 'standard' size root & swap and everything else | |
281 | * in the G partition. | |
282 | */ | |
283 | sc->sc_info = sddefaultpart; | |
284 | /* C gets everything */ | |
285 | sc->sc_info.part[2].nblocks = sc->sc_blks; | |
286 | sc->sc_info.part[2].endblk = sc->sc_blks; | |
287 | /* G gets from end of B to end of disk */ | |
288 | sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk; | |
289 | sc->sc_info.part[6].endblk = sc->sc_blks; | |
290 | /* | |
291 | * We also define the D, E and F paritions as an alternative to | |
292 | * B and G. D is 48Mb, starts after A and is intended for swapping. | |
293 | * E is 50Mb, starts after D and is intended for /usr. F starts | |
294 | * after E and is what ever is left. | |
295 | */ | |
296 | if (sc->sc_blks >= sc->sc_info.part[4].endblk) { | |
297 | sc->sc_info.part[5].nblocks = | |
298 | sc->sc_blks - sc->sc_info.part[4].endblk; | |
299 | sc->sc_info.part[5].endblk = sc->sc_blks; | |
300 | } else { | |
301 | sc->sc_info.part[5].strtblk = 0; | |
302 | sc->sc_info.part[3] = sc->sc_info.part[5]; | |
303 | sc->sc_info.part[4] = sc->sc_info.part[5]; | |
304 | } | |
305 | /* | |
306 | * H is a single partition alternative to E and F. | |
307 | */ | |
308 | if (sc->sc_blks >= sc->sc_info.part[3].endblk) { | |
309 | sc->sc_info.part[7].nblocks = | |
310 | sc->sc_blks - sc->sc_info.part[3].endblk; | |
311 | sc->sc_info.part[7].endblk = sc->sc_blks; | |
312 | } else { | |
313 | sc->sc_info.part[7].strtblk = 0; | |
314 | } | |
315 | ||
316 | sc->sc_flags = SDF_ALIVE; | |
317 | return(1); | |
318 | } | |
319 | ||
320 | void | |
321 | sdreset(sc, hd) | |
322 | register struct sd_softc *sc; | |
323 | register struct hp_device *hd; | |
324 | { | |
325 | sdstats[hd->hp_unit].sdresets++; | |
326 | } | |
327 | ||
328 | int | |
329 | sdopen(dev, flags) | |
330 | dev_t dev; | |
331 | int flags; | |
332 | { | |
333 | register int unit = sdunit(dev); | |
334 | register struct sd_softc *sc = &sd_softc[unit]; | |
335 | ||
336 | if (unit >= NSD) | |
337 | return(ENXIO); | |
338 | if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(u.u_cred, &u.u_acflag)) | |
339 | return(ENXIO); | |
340 | ||
341 | if (sc->sc_hd->hp_dk >= 0) | |
342 | dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms; | |
343 | return(0); | |
344 | } | |
345 | ||
346 | /* | |
347 | * This routine is called for partial block transfers and non-aligned | |
348 | * transfers (the latter only being possible on devices with a block size | |
349 | * larger than DEV_BSIZE). The operation is performed in three steps | |
350 | * using a locally allocated buffer: | |
351 | * 1. transfer any initial partial block | |
352 | * 2. transfer full blocks | |
353 | * 3. transfer any final partial block | |
354 | */ | |
355 | static void | |
356 | sdlblkstrat(bp, bsize) | |
357 | register struct buf *bp; | |
358 | register int bsize; | |
359 | { | |
360 | register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf), | |
361 | M_DEVBUF, M_WAITOK); | |
362 | caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK); | |
363 | register int bn, resid; | |
364 | register caddr_t addr; | |
365 | ||
366 | bzero((caddr_t)cbp, sizeof(*cbp)); | |
367 | cbp->b_proc = u.u_procp; | |
368 | cbp->b_dev = bp->b_dev; | |
369 | bn = bp->b_blkno; | |
370 | resid = bp->b_bcount; | |
371 | addr = bp->b_un.b_addr; | |
372 | #ifdef DEBUG | |
373 | if (sddebug & SDB_PARTIAL) | |
374 | printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n", | |
375 | bp, bp->b_flags, bn, resid, addr); | |
376 | #endif | |
377 | ||
378 | while (resid > 0) { | |
379 | register int boff = dbtob(bn) & (bsize - 1); | |
380 | register int count; | |
381 | ||
382 | if (boff || resid < bsize) { | |
383 | sdstats[sdunit(bp->b_dev)].sdpartials++; | |
384 | count = MIN(resid, bsize - boff); | |
385 | cbp->b_flags = B_BUSY | B_PHYS | B_READ; | |
386 | cbp->b_blkno = bn - btodb(boff); | |
387 | cbp->b_un.b_addr = cbuf; | |
388 | cbp->b_bcount = bsize; | |
389 | #ifdef DEBUG | |
390 | if (sddebug & SDB_PARTIAL) | |
391 | printf(" readahead: bn %x cnt %x off %x addr %x\n", | |
392 | cbp->b_blkno, count, boff, addr); | |
393 | #endif | |
394 | sdstrategy(cbp); | |
395 | biowait(cbp); | |
396 | if (cbp->b_flags & B_ERROR) { | |
397 | bp->b_flags |= B_ERROR; | |
398 | bp->b_error = cbp->b_error; | |
399 | break; | |
400 | } | |
401 | if (bp->b_flags & B_READ) { | |
402 | bcopy(&cbuf[boff], addr, count); | |
403 | goto done; | |
404 | } | |
405 | bcopy(addr, &cbuf[boff], count); | |
406 | #ifdef DEBUG | |
407 | if (sddebug & SDB_PARTIAL) | |
408 | printf(" writeback: bn %x cnt %x off %x addr %x\n", | |
409 | cbp->b_blkno, count, boff, addr); | |
410 | #endif | |
411 | } else { | |
412 | count = resid & ~(bsize - 1); | |
413 | cbp->b_blkno = bn; | |
414 | cbp->b_un.b_addr = addr; | |
415 | cbp->b_bcount = count; | |
416 | #ifdef DEBUG | |
417 | if (sddebug & SDB_PARTIAL) | |
418 | printf(" fulltrans: bn %x cnt %x addr %x\n", | |
419 | cbp->b_blkno, count, addr); | |
420 | #endif | |
421 | } | |
422 | cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ); | |
423 | sdstrategy(cbp); | |
424 | biowait(cbp); | |
425 | if (cbp->b_flags & B_ERROR) { | |
426 | bp->b_flags |= B_ERROR; | |
427 | bp->b_error = cbp->b_error; | |
428 | break; | |
429 | } | |
430 | done: | |
431 | bn += btodb(count); | |
432 | resid -= count; | |
433 | addr += count; | |
434 | #ifdef DEBUG | |
435 | if (sddebug & SDB_PARTIAL) | |
436 | printf(" done: bn %x resid %x addr %x\n", | |
437 | bn, resid, addr); | |
438 | #endif | |
439 | } | |
440 | free(cbuf, M_DEVBUF); | |
441 | free(cbp, M_DEVBUF); | |
442 | } | |
443 | ||
444 | void | |
445 | sdstrategy(bp) | |
446 | register struct buf *bp; | |
447 | { | |
448 | register int part = sdpart(bp->b_dev); | |
449 | register int unit = sdunit(bp->b_dev); | |
450 | register int bn, sz; | |
451 | register struct sd_softc *sc = &sd_softc[unit]; | |
452 | register struct buf *dp = &sdtab[unit]; | |
453 | register int s; | |
454 | ||
455 | if (sc->sc_format_pid) { | |
456 | if (sc->sc_format_pid != u.u_procp->p_pid) { | |
457 | bp->b_error = EPERM; | |
458 | goto bad; | |
459 | } | |
460 | bp->b_cylin = 0; | |
461 | } else { | |
462 | bn = bp->b_blkno; | |
463 | sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT; | |
464 | if (bn < 0 || bn + sz > sc->sc_info.part[part].nblocks) { | |
465 | if (bn == sc->sc_info.part[part].nblocks) { | |
466 | bp->b_resid = bp->b_bcount; | |
467 | goto done; | |
468 | } | |
469 | bp->b_error = EINVAL; | |
470 | goto bad; | |
471 | } | |
472 | /* | |
473 | * Non-aligned or partial-block transfers handled specially. | |
474 | */ | |
475 | s = sc->sc_blksize - 1; | |
476 | if ((dbtob(bn) & s) || (bp->b_bcount & s)) { | |
477 | sdlblkstrat(bp, sc->sc_blksize); | |
478 | goto done; | |
479 | } | |
480 | bp->b_cylin = (bn + sc->sc_info.part[part].strtblk) >> | |
481 | sc->sc_bshift; | |
482 | } | |
483 | s = splbio(); | |
484 | disksort(dp, bp); | |
485 | if (dp->b_active == 0) { | |
486 | dp->b_active = 1; | |
487 | sdustart(unit); | |
488 | } | |
489 | splx(s); | |
490 | return; | |
491 | bad: | |
492 | bp->b_flags |= B_ERROR; | |
493 | done: | |
494 | iodone(bp); | |
495 | } | |
496 | ||
497 | void | |
498 | sdustart(unit) | |
499 | register int unit; | |
500 | { | |
501 | if (scsireq(&sd_softc[unit].sc_dq)) | |
502 | sdstart(unit); | |
503 | } | |
504 | ||
505 | static void | |
506 | sderror(unit, sc, hp, stat) | |
507 | int unit, stat; | |
508 | register struct sd_softc *sc; | |
509 | register struct hp_device *hp; | |
510 | { | |
511 | sdsense[unit].status = stat; | |
512 | if (stat & STS_CHECKCOND) { | |
513 | struct scsi_xsense *sp; | |
514 | ||
515 | scsi_request_sense(hp->hp_ctlr, hp->hp_slave, | |
516 | sc->sc_punit, sdsense[unit].sense, | |
517 | sizeof(sdsense[unit].sense)); | |
518 | sp = (struct scsi_xsense *)sdsense[unit].sense; | |
519 | printf("sd%d: scsi sense class %d, code %d", unit, | |
520 | sp->class, sp->code); | |
521 | if (sp->class == 7) { | |
522 | printf(", key %d", sp->key); | |
523 | if (sp->valid) | |
524 | printf(", blk %d", *(int *)&sp->info1); | |
525 | } | |
526 | printf("\n"); | |
527 | } | |
528 | } | |
529 | ||
530 | static void | |
531 | sdfinish(unit, sc, bp) | |
532 | int unit; | |
533 | register struct sd_softc *sc; | |
534 | register struct buf *bp; | |
535 | { | |
536 | sdtab[unit].b_errcnt = 0; | |
537 | sdtab[unit].b_actf = bp->b_actf; | |
538 | bp->b_resid = 0; | |
539 | iodone(bp); | |
540 | scsifree(&sc->sc_dq); | |
541 | if (sdtab[unit].b_actf) | |
542 | sdustart(unit); | |
543 | else | |
544 | sdtab[unit].b_active = 0; | |
545 | } | |
546 | ||
547 | void | |
548 | sdstart(unit) | |
549 | register int unit; | |
550 | { | |
551 | register struct sd_softc *sc = &sd_softc[unit]; | |
552 | register struct hp_device *hp = sc->sc_hd; | |
553 | ||
554 | /* | |
555 | * we have the SCSI bus -- in format mode, we may or may not need dma | |
556 | * so check now. | |
557 | */ | |
558 | if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) { | |
559 | register struct buf *bp = sdtab[unit].b_actf; | |
560 | register int sts; | |
561 | ||
562 | sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave, | |
563 | sc->sc_punit, &sdcmd[unit], | |
564 | bp->b_un.b_addr, bp->b_bcount, | |
565 | bp->b_flags & B_READ); | |
566 | sdsense[unit].status = sts; | |
567 | if (sts & 0xfe) { | |
568 | sderror(unit, sc, hp, sts); | |
569 | bp->b_flags |= B_ERROR; | |
570 | bp->b_error = EIO; | |
571 | } | |
572 | sdfinish(unit, sc, bp); | |
573 | ||
574 | } else if (scsiustart(hp->hp_ctlr)) | |
575 | sdgo(unit); | |
576 | } | |
577 | ||
578 | void | |
579 | sdgo(unit) | |
580 | register int unit; | |
581 | { | |
582 | register struct sd_softc *sc = &sd_softc[unit]; | |
583 | register struct hp_device *hp = sc->sc_hd; | |
584 | register struct buf *bp = sdtab[unit].b_actf; | |
585 | register int pad; | |
586 | register struct scsi_fmt_cdb *cmd; | |
587 | ||
588 | if (sc->sc_format_pid) { | |
589 | cmd = &sdcmd[unit]; | |
590 | pad = 0; | |
591 | } else { | |
592 | cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd; | |
593 | *(int *)(&cmd->cdb[2]) = bp->b_cylin; | |
594 | pad = howmany(bp->b_bcount, sc->sc_blksize); | |
595 | *(u_short *)(&cmd->cdb[7]) = pad; | |
596 | pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0; | |
597 | #ifdef DEBUG | |
598 | if (pad) | |
599 | printf("sd%d: partial block xfer -- %x bytes\n", | |
600 | unit, bp->b_bcount); | |
601 | #endif | |
602 | sdstats[unit].sdtransfers++; | |
603 | } | |
604 | if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) { | |
605 | if (hp->hp_dk >= 0) { | |
606 | dk_busy |= 1 << hp->hp_dk; | |
607 | ++dk_seek[hp->hp_dk]; | |
608 | ++dk_xfer[hp->hp_dk]; | |
609 | dk_wds[hp->hp_dk] += bp->b_bcount >> 6; | |
610 | } | |
611 | return; | |
612 | } | |
613 | #ifdef DEBUG | |
614 | if (sddebug & SDB_ERROR) | |
615 | printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n", | |
616 | unit, bp->b_flags & B_READ? "read" : "write", | |
617 | bp->b_un.b_addr, bp->b_cylin, bp->b_bcount, | |
618 | sdtab[unit].b_errcnt); | |
619 | #endif | |
620 | bp->b_flags |= B_ERROR; | |
621 | bp->b_error = EIO; | |
622 | sdfinish(unit, sc, bp); | |
623 | } | |
624 | ||
625 | void | |
626 | sdintr(unit, stat) | |
627 | register int unit; | |
628 | int stat; | |
629 | { | |
630 | register struct sd_softc *sc = &sd_softc[unit]; | |
631 | register struct buf *bp = sdtab[unit].b_actf; | |
632 | register struct hp_device *hp = sc->sc_hd; | |
633 | ||
634 | if (bp == NULL) { | |
635 | printf("sd%d: bp == NULL\n", unit); | |
636 | return; | |
637 | } | |
638 | if (hp->hp_dk >= 0) | |
639 | dk_busy &=~ (1 << hp->hp_dk); | |
640 | if (stat) { | |
641 | #ifdef DEBUG | |
642 | if (sddebug & SDB_ERROR) | |
643 | printf("sd%d: sdintr: bad scsi status 0x%x\n", | |
644 | unit, stat); | |
645 | #endif | |
646 | sderror(unit, sc, hp, stat); | |
647 | bp->b_flags |= B_ERROR; | |
648 | bp->b_error = EIO; | |
649 | } | |
650 | sdfinish(unit, sc, bp); | |
651 | } | |
652 | ||
653 | int | |
654 | sdread(dev, uio) | |
655 | dev_t dev; | |
656 | struct uio *uio; | |
657 | { | |
658 | register int unit = sdunit(dev); | |
659 | register int pid; | |
660 | ||
661 | if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid) | |
662 | return (EPERM); | |
663 | ||
664 | return(physio(sdstrategy, &sdbuf[unit], dev, B_READ, minphys, uio)); | |
665 | } | |
666 | ||
667 | int | |
668 | sdwrite(dev, uio) | |
669 | dev_t dev; | |
670 | struct uio *uio; | |
671 | { | |
672 | register int unit = sdunit(dev); | |
673 | register int pid; | |
674 | ||
675 | if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid) | |
676 | return (EPERM); | |
677 | ||
678 | return(physio(sdstrategy, &sdbuf[unit], dev, B_WRITE, minphys, uio)); | |
679 | } | |
680 | ||
681 | int | |
682 | sdioctl(dev, cmd, data, flag) | |
683 | dev_t dev; | |
684 | int cmd; | |
685 | caddr_t data; | |
686 | int flag; | |
687 | { | |
688 | register int unit = sdunit(dev); | |
689 | register struct sd_softc *sc = &sd_softc[unit]; | |
690 | ||
691 | switch (cmd) { | |
692 | default: | |
693 | return (EINVAL); | |
694 | ||
695 | case SDIOCSFORMAT: | |
696 | /* take this device into or out of "format" mode */ | |
697 | if (suser(u.u_cred, &u.u_acflag)) | |
698 | return(EPERM); | |
699 | ||
700 | if (*(int *)data) { | |
701 | if (sc->sc_format_pid) | |
702 | return (EPERM); | |
703 | sc->sc_format_pid = u.u_procp->p_pid; | |
704 | } else | |
705 | sc->sc_format_pid = 0; | |
706 | return (0); | |
707 | ||
708 | case SDIOCGFORMAT: | |
709 | /* find out who has the device in format mode */ | |
710 | *(int *)data = sc->sc_format_pid; | |
711 | return (0); | |
712 | ||
713 | case SDIOCSCSICOMMAND: | |
714 | /* | |
715 | * Save what user gave us as SCSI cdb to use with next | |
716 | * read or write to the char device. | |
717 | */ | |
718 | if (sc->sc_format_pid != u.u_procp->p_pid) | |
719 | return (EPERM); | |
720 | if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0) | |
721 | return (EINVAL); | |
722 | bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0])); | |
723 | return (0); | |
724 | ||
725 | case SDIOCSENSE: | |
726 | /* | |
727 | * return the SCSI sense data saved after the last | |
728 | * operation that completed with "check condition" status. | |
729 | */ | |
730 | bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0])); | |
731 | return (0); | |
732 | ||
733 | } | |
734 | /*NOTREACHED*/ | |
735 | } | |
736 | ||
737 | int | |
738 | sdsize(dev) | |
739 | dev_t dev; | |
740 | { | |
741 | register int unit = sdunit(dev); | |
742 | register struct sd_softc *sc = &sd_softc[unit]; | |
743 | ||
744 | if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) | |
745 | return(-1); | |
746 | ||
747 | return(sc->sc_info.part[sdpart(dev)].nblocks); | |
748 | } | |
749 | ||
750 | #include "machine/pte.h" | |
751 | #include "machine/vmparam.h" | |
029e208f | 752 | #include "../sys/vmmac.h" |
60f56dfc KM |
753 | |
754 | /* | |
755 | * Non-interrupt driven, non-dma dump routine. | |
756 | */ | |
757 | int | |
758 | sddump(dev) | |
759 | dev_t dev; | |
760 | { | |
761 | int part = sdpart(dev); | |
762 | int unit = sdunit(dev); | |
763 | register struct sd_softc *sc = &sd_softc[unit]; | |
764 | register struct hp_device *hp = sc->sc_hd; | |
765 | register daddr_t baddr; | |
766 | register int maddr; | |
767 | register int pages, i; | |
768 | int stat; | |
769 | extern int lowram; | |
770 | ||
771 | /* | |
772 | * Hmm... all vax drivers dump maxfree pages which is physmem minus | |
773 | * the message buffer. Is there a reason for not dumping the | |
774 | * message buffer? Savecore expects to read 'dumpsize' pages of | |
775 | * dump, where dumpsys() sets dumpsize to physmem! | |
776 | */ | |
777 | pages = physmem; | |
778 | ||
779 | /* is drive ok? */ | |
780 | if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0) | |
781 | return (ENXIO); | |
782 | /* dump parameters in range? */ | |
783 | if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks) | |
784 | return (EINVAL); | |
785 | if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks) | |
786 | pages = dtoc(sc->sc_info.part[part].nblocks - dumplo); | |
787 | maddr = lowram; | |
788 | baddr = dumplo + sc->sc_info.part[part].strtblk; | |
789 | /* scsi bus idle? */ | |
790 | if (!scsireq(&sc->sc_dq)) { | |
791 | scsireset(hp->hp_ctlr); | |
792 | sdreset(sc, sc->sc_hd); | |
793 | printf("[ drive %d reset ] ", unit); | |
794 | } | |
795 | for (i = 0; i < pages; i++) { | |
796 | #define NPGMB (1024*1024/NBPG) | |
797 | /* print out how many Mbs we have dumped */ | |
798 | if (i && (i % NPGMB) == 0) | |
799 | printf("%d ", i / NPGMB); | |
800 | #undef NPBMG | |
801 | mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); | |
802 | stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, | |
803 | vmmap, NBPG, baddr, sc->sc_bshift); | |
804 | if (stat) { | |
805 | printf("sddump: scsi write error 0x%x\n", stat); | |
806 | return (EIO); | |
807 | } | |
808 | maddr += NBPG; | |
809 | baddr += ctod(1); | |
810 | } | |
811 | return (0); | |
812 | } | |
813 | #endif |