BSD 4_4_Lite2 release
[unix-history] / usr / src / sys / hp300 / dev / sd.c
CommitLineData
60f56dfc 1/*
030a8056
KB
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
60f56dfc
KM
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Van Jacobson of Lawrence Berkeley Laboratory.
7 *
ad787160
C
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
60f56dfc 23 *
ad787160
C
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
fd88f5c5 36 * @(#)sd.c 8.9 (Berkeley) 5/14/95
60f56dfc
KM
37 */
38
39/*
40 * SCSI CCS (Command Command Set) disk driver.
41 */
42#include "sd.h"
43#if NSD > 0
44
45#ifndef lint
4bcb05ed 46static char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $";
60f56dfc
KM
47#endif
48
38a01dbe
KB
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/buf.h>
573b5fae 52#include <sys/stat.h>
38a01dbe
KB
53#include <sys/dkstat.h>
54#include <sys/disklabel.h>
55#include <sys/malloc.h>
56#include <sys/proc.h>
57#include <sys/ioctl.h>
573b5fae 58#include <sys/fcntl.h>
60f56dfc 59
38a01dbe
KB
60#include <hp/dev/device.h>
61#include <hp300/dev/scsireg.h>
573b5fae
MH
62#include <hp300/dev/sdvar.h>
63#ifdef USELEDS
64#include <hp300/hp300/led.h>
65#endif
38a01dbe 66
7fee1787 67#include <vm/vm.h>
22d09b27 68
60f56dfc
KM
69extern int scsi_test_unit_rdy();
70extern int scsi_request_sense();
71extern int scsi_inquiry();
72extern int scsi_read_capacity();
73extern int scsi_tt_write();
74extern int scsireq();
75extern int scsiustart();
76extern int scsigo();
77extern void scsifree();
78extern void scsireset();
98d7aa4d 79extern void scsi_delay();
60f56dfc 80
60f56dfc 81extern void disksort();
60f56dfc
KM
82extern void biodone();
83extern int physio();
84extern void TBIS();
85
86int sdinit();
87void sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
88
89struct driver sddriver = {
90 sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
91};
92
60f56dfc
KM
93#ifdef DEBUG
94int sddebug = 1;
95#define SDB_ERROR 0x01
96#define SDB_PARTIAL 0x02
4bcb05ed 97#define SDB_CAPACITY 0x04
60f56dfc
KM
98#endif
99
573b5fae
MH
100struct sd_softc sd_softc[NSD];
101struct sdstats sdstats[NSD];
60f56dfc 102struct buf sdtab[NSD];
60f56dfc
KM
103struct scsi_fmt_cdb sdcmd[NSD];
104struct scsi_fmt_sense sdsense[NSD];
105
106static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
107static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
108
60f56dfc
KM
109/*
110 * Table of scsi commands users are allowed to access via "format"
111 * mode. 0 means not legal. 1 means "immediate" (doesn't need dma).
112 * -1 means needs dma and/or wait for intr.
113 */
114static char legal_cmds[256] = {
115/***** 0 1 2 3 4 5 6 7 8 9 A B C D E F */
116/*00*/ 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117/*10*/ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
118/*20*/ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119/*30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122/*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126/*a0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132};
133
134static struct scsi_inquiry inqbuf;
135static struct scsi_fmt_cdb inq = {
136 6,
137 CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
138};
139
60f56dfc
KM
140static int
141sdident(sc, hd)
142 struct sd_softc *sc;
143 struct hp_device *hd;
144{
145 int unit;
146 register int ctlr, slave;
147 register int i;
148 register int tries = 10;
98d7aa4d 149 char idstr[32];
4bcb05ed 150 int isrm = 0;
60f56dfc
KM
151
152 ctlr = hd->hp_ctlr;
153 slave = hd->hp_slave;
154 unit = sc->sc_punit;
98d7aa4d 155 scsi_delay(-1);
60f56dfc
KM
156
157 /*
158 * See if unit exists and is a disk then read block size & nblocks.
159 */
160 while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
22d09b27 161 if (i == -1 || --tries < 0) {
4bcb05ed 162 if (isrm)
22d09b27 163 break;
60f56dfc 164 /* doesn't exist or not a CCS device */
98d7aa4d 165 goto failed;
22d09b27 166 }
60f56dfc
KM
167 if (i == STS_CHECKCOND) {
168 u_char sensebuf[128];
169 struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
170
171 scsi_request_sense(ctlr, slave, unit, sensebuf,
172 sizeof(sensebuf));
22d09b27
KM
173 if (sp->class == 7)
174 switch (sp->key) {
4bcb05ed
MH
175 /*
176 * Not ready -- might be removable media
177 * device with no media. Assume as much,
178 * if it really isn't, the inquiry commmand
179 * below will fail.
180 */
22d09b27 181 case 2:
4bcb05ed 182 isrm = 1;
22d09b27 183 break;
60f56dfc 184 /* drive doing an RTZ -- give it a while */
22d09b27
KM
185 case 6:
186 DELAY(1000000);
187 break;
188 default:
189 break;
190 }
60f56dfc
KM
191 }
192 DELAY(1000);
193 }
22d09b27
KM
194 /*
195 * Find out about device
196 */
197 if (scsi_immed_command(ctlr, slave, unit, &inq,
198 (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
98d7aa4d 199 goto failed;
60f56dfc
KM
200 switch (inqbuf.type) {
201 case 0: /* disk */
202 case 4: /* WORM */
203 case 5: /* CD-ROM */
204 case 7: /* Magneto-optical */
205 break;
206 default: /* not a disk */
98d7aa4d 207 goto failed;
60f56dfc 208 }
22d09b27 209 /*
98d7aa4d 210 * Get a usable id string
22d09b27 211 */
573b5fae
MH
212 switch (inqbuf.version) {
213 case 1:
214 case 2:
98d7aa4d
MH
215 bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
216 for (i = 27; i > 23; --i)
217 if (idstr[i] != ' ')
218 break;
219 idstr[i+1] = 0;
220 for (i = 23; i > 7; --i)
221 if (idstr[i] != ' ')
222 break;
223 idstr[i+1] = 0;
224 for (i = 7; i >= 0; --i)
225 if (idstr[i] != ' ')
226 break;
227 idstr[i+1] = 0;
573b5fae
MH
228 break;
229 default:
230 bcopy("UNKNOWN", &idstr[0], 8);
231 bcopy("DRIVE TYPE", &idstr[8], 11);
22d09b27 232 }
4bcb05ed
MH
233 if (inqbuf.qual & 0x80)
234 sc->sc_flags |= SDF_RMEDIA;
235
236 if (sdgetcapacity(sc, hd, NODEV) < 0)
237 goto failed;
60f56dfc 238
573b5fae
MH
239 switch (inqbuf.version) {
240 case 1:
241 case 2:
60f56dfc
KM
242 printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
243 &idstr[24]);
573b5fae
MH
244 if (inqbuf.version == 2)
245 printf(" (SCSI-2)");
246 break;
247 default:
248 printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
249 inqbuf.type, inqbuf.qual, inqbuf.version);
250 break;
251 }
4bcb05ed
MH
252 if (sc->sc_blks)
253 printf(", %d %d byte blocks",
254 sc->sc_blks >> sc->sc_bshift, sc->sc_blksize);
255 printf("\n");
60f56dfc 256 sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */
98d7aa4d 257 scsi_delay(0);
60f56dfc 258 return(inqbuf.type);
98d7aa4d
MH
259failed:
260 scsi_delay(0);
261 return(-1);
60f56dfc
KM
262}
263
264int
265sdinit(hd)
266 register struct hp_device *hd;
267{
268 register struct sd_softc *sc = &sd_softc[hd->hp_unit];
269
270 sc->sc_hd = hd;
9acfa6cd 271 sc->sc_flags = 0;
0fb33df5
MH
272 /*
273 * XXX formerly 0 meant unused but now pid 0 can legitimately
274 * use this interface (sdgetcapacity).
275 */
276 sc->sc_format_pid = -1;
60f56dfc
KM
277 sc->sc_punit = sdpunit(hd->hp_flags);
278 sc->sc_type = sdident(sc, hd);
279 if (sc->sc_type < 0)
280 return(0);
281 sc->sc_dq.dq_ctlr = hd->hp_ctlr;
282 sc->sc_dq.dq_unit = hd->hp_unit;
283 sc->sc_dq.dq_slave = hd->hp_slave;
284 sc->sc_dq.dq_driver = &sddriver;
285
9acfa6cd 286 sc->sc_flags |= SDF_ALIVE;
60f56dfc
KM
287 return(1);
288}
289
290void
291sdreset(sc, hd)
292 register struct sd_softc *sc;
293 register struct hp_device *hd;
294{
295 sdstats[hd->hp_unit].sdresets++;
296}
297
4bcb05ed
MH
298/*
299 * Determine capacity of a drive.
300 * Returns -1 on a failure, 0 on success, 1 on a failure that is probably
301 * due to missing media.
302 */
303int
304sdgetcapacity(sc, hd, dev)
305 struct sd_softc *sc;
306 struct hp_device *hd;
307 dev_t dev;
308{
309 static struct scsi_fmt_cdb cap = {
310 10,
311 CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
312 };
0fb33df5
MH
313 u_char *capbuf;
314 int i, capbufsize;
315
316 /*
317 * Cannot use stack space for this buffer since stack KVA may not
318 * be valid (i.e. in context of this process) when the operation
319 * actually starts.
320 */
321 capbufsize = 8;
322 capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK);
4bcb05ed
MH
323
324 if (dev == NODEV) {
325 i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit,
0fb33df5 326 &cap, capbuf, capbufsize, B_READ);
4bcb05ed 327 } else {
0fb33df5
MH
328 struct buf *bp;
329
4bcb05ed
MH
330 /*
331 * XXX this is horrible
332 */
0fb33df5 333 if (sc->sc_format_pid >= 0)
4bcb05ed 334 panic("sdgetcapacity");
0fb33df5 335 bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK);
4bcb05ed
MH
336 sc->sc_format_pid = curproc->p_pid;
337 bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap);
0fb33df5
MH
338 bp->b_dev = dev;
339 bp->b_flags = B_READ | B_BUSY;
340 bp->b_un.b_addr = (caddr_t)capbuf;
341 bp->b_bcount = capbufsize;
342 sdstrategy(bp);
343 i = biowait(bp) ? sdsense[hd->hp_unit].status : 0;
344 free(bp, M_DEVBUF);
345 sc->sc_format_pid = -1;
4bcb05ed
MH
346 }
347 if (i) {
348 if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) {
349#ifdef DEBUG
350 if (sddebug & SDB_CAPACITY)
351 printf("sd%d: read_capacity returns %d\n",
352 hd->hp_unit, i);
353#endif
0fb33df5 354 free(capbuf, M_DEVBUF);
4bcb05ed
MH
355 return (-1);
356 }
357 /*
358 * XXX assume unformatted or non-existant media
359 */
360 sc->sc_blks = 0;
361 sc->sc_blksize = DEV_BSIZE;
362 sc->sc_bshift = 0;
363#ifdef DEBUG
364 if (sddebug & SDB_CAPACITY)
365 printf("sd%d: removable media not present\n",
366 hd->hp_unit);
367#endif
0fb33df5 368 free(capbuf, M_DEVBUF);
4bcb05ed
MH
369 return (1);
370 }
371 sc->sc_blks = *(u_int *)&capbuf[0];
372 sc->sc_blksize = *(int *)&capbuf[4];
0fb33df5 373 free(capbuf, M_DEVBUF);
4bcb05ed
MH
374 sc->sc_bshift = 0;
375
376 /* return value of read capacity is last valid block number */
377 sc->sc_blks++;
378
379 if (sc->sc_blksize != DEV_BSIZE) {
380 if (sc->sc_blksize < DEV_BSIZE) {
0fb33df5
MH
381 printf("sd%d: need at least %d byte blocks - %s\n",
382 hd->hp_unit, DEV_BSIZE, "drive ignored");
4bcb05ed
MH
383 return (-1);
384 }
385 for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
386 ++sc->sc_bshift;
387 sc->sc_blks <<= sc->sc_bshift;
388 }
389#ifdef DEBUG
390 if (sddebug & SDB_CAPACITY)
391 printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit,
392 sc->sc_blks, sc->sc_blksize, sc->sc_bshift);
393#endif
394 return (0);
395}
396
573b5fae
MH
397/*
398 * Read or constuct a disklabel
399 */
400int
401sdgetinfo(dev)
402 dev_t dev;
403{
404 int unit = sdunit(dev);
405 register struct sd_softc *sc = &sd_softc[unit];
406 register struct disklabel *lp = &sc->sc_info.si_label;
407 register struct partition *pi;
408 char *msg, *readdisklabel();
4bcb05ed
MH
409#ifdef COMPAT_NOLABEL
410 int usedefault = 1;
573b5fae
MH
411
412 /*
4bcb05ed 413 * For CD-ROM just define a single partition
573b5fae 414 */
4bcb05ed
MH
415 if (sc->sc_type == 5)
416 usedefault = 0;
417#endif
418
573b5fae 419 bzero((caddr_t)lp, sizeof *lp);
4bcb05ed 420 msg = NULL;
573b5fae
MH
421
422 /*
4bcb05ed
MH
423 * If removable media or the size unavailable at boot time
424 * (i.e. unformatted hard disk), attempt to set the capacity
425 * now.
573b5fae 426 */
4bcb05ed
MH
427 if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) {
428 switch (sdgetcapacity(sc, sc->sc_hd, dev)) {
429 case 0:
430 break;
431 case -1:
432 /*
433 * Hard error, just return (open will fail).
434 */
435 return (EIO);
436 case 1:
437 /*
438 * XXX return 0 so open can continue just in case
439 * the media is unformatted and we want to format it.
440 * We set the error flag so they cannot do much else.
441 */
442 sc->sc_flags |= SDF_ERROR;
443 msg = "unformatted/missing media";
444#ifdef COMPAT_NOLABEL
445 usedefault = 0;
446#endif
447 break;
448 }
449 }
450
451 /*
452 * Set some default values to use while reading the label
453 * (or to use if there isn't a label) and try reading it.
454 */
455 if (msg == NULL) {
456 lp->d_type = DTYPE_SCSI;
457 lp->d_secsize = DEV_BSIZE;
458 lp->d_nsectors = 32;
459 lp->d_ntracks = 20;
460 lp->d_ncylinders = 1;
461 lp->d_secpercyl = 32*20;
462 lp->d_npartitions = 3;
463 lp->d_partitions[2].p_offset = 0;
464 /* XXX we can open a device even without SDF_ALIVE */
465 if (sc->sc_blksize == 0)
466 sc->sc_blksize = DEV_BSIZE;
467 /* XXX ensure size is at least one device block */
468 lp->d_partitions[2].p_size =
469 roundup(LABELSECTOR+1, btodb(sc->sc_blksize));
470 msg = readdisklabel(sdlabdev(dev), sdstrategy, lp);
471 if (msg == NULL)
472 return (0);
473 }
573b5fae
MH
474
475 pi = lp->d_partitions;
476 printf("sd%d: WARNING: %s, ", unit, msg);
477#ifdef COMPAT_NOLABEL
4bcb05ed
MH
478 if (usedefault) {
479 printf("using old default partitioning\n");
480 sdmakedisklabel(unit, lp);
481 return(0);
482 }
483#endif
573b5fae
MH
484 printf("defining `c' partition as entire disk\n");
485 pi[2].p_size = sc->sc_blks;
d2da96c4
MH
486 /* XXX reset other info since readdisklabel screws with it */
487 lp->d_npartitions = 3;
488 pi[0].p_size = 0;
573b5fae
MH
489 return(0);
490}
491
60f56dfc 492int
88f29710 493sdopen(dev, flags, mode, p)
60f56dfc 494 dev_t dev;
88f29710
MK
495 int flags, mode;
496 struct proc *p;
60f56dfc
KM
497{
498 register int unit = sdunit(dev);
499 register struct sd_softc *sc = &sd_softc[unit];
689a3d14 500 int error, mask;
60f56dfc 501
689a3d14 502 if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
60f56dfc 503 return(ENXIO);
60f56dfc 504
573b5fae
MH
505 /*
506 * Wait for any pending opens/closes to complete
507 */
508 while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING))
509 sleep((caddr_t)sc, PRIBIO);
689a3d14 510
573b5fae
MH
511 /*
512 * On first open, get label and partition info.
513 * We may block reading the label, so be careful
514 * to stop any other opens.
515 */
516 if (sc->sc_info.si_open == 0) {
517 sc->sc_flags |= SDF_OPENING;
518 error = sdgetinfo(dev);
519 sc->sc_flags &= ~SDF_OPENING;
520 wakeup((caddr_t)sc);
521 if (error)
522 return(error);
523 }
60f56dfc
KM
524 if (sc->sc_hd->hp_dk >= 0)
525 dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
573b5fae
MH
526
527 mask = 1 << sdpart(dev);
528 if (mode == S_IFCHR)
529 sc->sc_info.si_copen |= mask;
530 else
531 sc->sc_info.si_bopen |= mask;
532 sc->sc_info.si_open |= mask;
60f56dfc
KM
533 return(0);
534}
535
9acfa6cd
MH
536int
537sdclose(dev, flag, mode, p)
538 dev_t dev;
539 int flag, mode;
540 struct proc *p;
541{
542 int unit = sdunit(dev);
543 register struct sd_softc *sc = &sd_softc[unit];
573b5fae
MH
544 register struct sdinfo *si = &sc->sc_info;
545 int mask, s;
9acfa6cd 546
573b5fae
MH
547 mask = 1 << sdpart(dev);
548 if (mode == S_IFCHR)
549 si->si_copen &= ~mask;
550 else
551 si->si_bopen &= ~mask;
552 si->si_open = si->si_bopen | si->si_copen;
9acfa6cd 553 /*
573b5fae
MH
554 * On last close, we wait for all activity to cease since
555 * the label/parition info will become invalid. Since we
556 * might sleep, we must block any opens while we are here.
557 * Note we don't have to about other closes since we know
558 * we are the last one.
9acfa6cd 559 */
573b5fae
MH
560 if (si->si_open == 0) {
561 sc->sc_flags |= SDF_CLOSING;
9acfa6cd
MH
562 s = splbio();
563 while (sdtab[unit].b_active) {
564 sc->sc_flags |= SDF_WANTED;
565 sleep((caddr_t)&sdtab[unit], PRIBIO);
566 }
567 splx(s);
573b5fae
MH
568 sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR);
569 wakeup((caddr_t)sc);
9acfa6cd 570 }
0fb33df5 571 sc->sc_format_pid = -1;
573b5fae 572 return(0);
9acfa6cd
MH
573}
574
60f56dfc
KM
575/*
576 * This routine is called for partial block transfers and non-aligned
577 * transfers (the latter only being possible on devices with a block size
578 * larger than DEV_BSIZE). The operation is performed in three steps
579 * using a locally allocated buffer:
580 * 1. transfer any initial partial block
581 * 2. transfer full blocks
582 * 3. transfer any final partial block
583 */
584static void
585sdlblkstrat(bp, bsize)
586 register struct buf *bp;
587 register int bsize;
588{
589 register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
590 M_DEVBUF, M_WAITOK);
591 caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
592 register int bn, resid;
593 register caddr_t addr;
594
595 bzero((caddr_t)cbp, sizeof(*cbp));
88f29710 596 cbp->b_proc = curproc; /* XXX */
60f56dfc
KM
597 cbp->b_dev = bp->b_dev;
598 bn = bp->b_blkno;
599 resid = bp->b_bcount;
600 addr = bp->b_un.b_addr;
601#ifdef DEBUG
602 if (sddebug & SDB_PARTIAL)
603 printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
604 bp, bp->b_flags, bn, resid, addr);
605#endif
606
607 while (resid > 0) {
608 register int boff = dbtob(bn) & (bsize - 1);
609 register int count;
610
611 if (boff || resid < bsize) {
612 sdstats[sdunit(bp->b_dev)].sdpartials++;
479c0df7 613 count = min(resid, bsize - boff);
60f56dfc
KM
614 cbp->b_flags = B_BUSY | B_PHYS | B_READ;
615 cbp->b_blkno = bn - btodb(boff);
616 cbp->b_un.b_addr = cbuf;
617 cbp->b_bcount = bsize;
618#ifdef DEBUG
619 if (sddebug & SDB_PARTIAL)
620 printf(" readahead: bn %x cnt %x off %x addr %x\n",
621 cbp->b_blkno, count, boff, addr);
622#endif
623 sdstrategy(cbp);
624 biowait(cbp);
625 if (cbp->b_flags & B_ERROR) {
626 bp->b_flags |= B_ERROR;
627 bp->b_error = cbp->b_error;
628 break;
629 }
630 if (bp->b_flags & B_READ) {
631 bcopy(&cbuf[boff], addr, count);
632 goto done;
633 }
634 bcopy(addr, &cbuf[boff], count);
635#ifdef DEBUG
636 if (sddebug & SDB_PARTIAL)
637 printf(" writeback: bn %x cnt %x off %x addr %x\n",
638 cbp->b_blkno, count, boff, addr);
639#endif
640 } else {
641 count = resid & ~(bsize - 1);
642 cbp->b_blkno = bn;
643 cbp->b_un.b_addr = addr;
644 cbp->b_bcount = count;
645#ifdef DEBUG
646 if (sddebug & SDB_PARTIAL)
647 printf(" fulltrans: bn %x cnt %x addr %x\n",
648 cbp->b_blkno, count, addr);
649#endif
650 }
651 cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
652 sdstrategy(cbp);
653 biowait(cbp);
654 if (cbp->b_flags & B_ERROR) {
655 bp->b_flags |= B_ERROR;
656 bp->b_error = cbp->b_error;
657 break;
658 }
659done:
660 bn += btodb(count);
661 resid -= count;
662 addr += count;
663#ifdef DEBUG
664 if (sddebug & SDB_PARTIAL)
665 printf(" done: bn %x resid %x addr %x\n",
666 bn, resid, addr);
667#endif
668 }
669 free(cbuf, M_DEVBUF);
670 free(cbp, M_DEVBUF);
671}
672
673void
674sdstrategy(bp)
675 register struct buf *bp;
676{
573b5fae 677 int unit = sdunit(bp->b_dev);
60f56dfc
KM
678 register struct sd_softc *sc = &sd_softc[unit];
679 register struct buf *dp = &sdtab[unit];
573b5fae 680 register struct partition *pinfo;
22d09b27
KM
681 register daddr_t bn;
682 register int sz, s;
60f56dfc 683
0fb33df5 684 if (sc->sc_format_pid >= 0) {
88f29710 685 if (sc->sc_format_pid != curproc->p_pid) { /* XXX */
60f56dfc 686 bp->b_error = EPERM;
573b5fae 687 goto bad;
60f56dfc
KM
688 }
689 bp->b_cylin = 0;
690 } else {
4bcb05ed
MH
691 if (sc->sc_flags & SDF_ERROR) {
692 bp->b_error = EIO;
693 goto bad;
694 }
60f56dfc 695 bn = bp->b_blkno;
22d09b27 696 sz = howmany(bp->b_bcount, DEV_BSIZE);
573b5fae
MH
697 pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)];
698 if (bn < 0 || bn + sz > pinfo->p_size) {
699 sz = pinfo->p_size - bn;
22d09b27 700 if (sz == 0) {
60f56dfc
KM
701 bp->b_resid = bp->b_bcount;
702 goto done;
703 }
22d09b27
KM
704 if (sz < 0) {
705 bp->b_error = EINVAL;
573b5fae 706 goto bad;
22d09b27
KM
707 }
708 bp->b_bcount = dbtob(sz);
60f56dfc 709 }
573b5fae
MH
710 /*
711 * Check for write to write protected label
712 */
713 if (bn + pinfo->p_offset <= LABELSECTOR &&
714#if LABELSECTOR != 0
715 bn + pinfo->p_offset + sz > LABELSECTOR &&
716#endif
717 !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) {
718 bp->b_error = EROFS;
719 goto bad;
720 }
60f56dfc
KM
721 /*
722 * Non-aligned or partial-block transfers handled specially.
723 */
724 s = sc->sc_blksize - 1;
725 if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
726 sdlblkstrat(bp, sc->sc_blksize);
727 goto done;
728 }
573b5fae 729 bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift;
60f56dfc
KM
730 }
731 s = splbio();
732 disksort(dp, bp);
733 if (dp->b_active == 0) {
734 dp->b_active = 1;
735 sdustart(unit);
736 }
737 splx(s);
738 return;
573b5fae
MH
739bad:
740 bp->b_flags |= B_ERROR;
60f56dfc 741done:
22d09b27 742 biodone(bp);
60f56dfc
KM
743}
744
745void
746sdustart(unit)
747 register int unit;
748{
749 if (scsireq(&sd_softc[unit].sc_dq))
750 sdstart(unit);
751}
752
761052c0
MK
753/*
754 * Return:
755 * 0 if not really an error
756 * <0 if we should do a retry
757 * >0 if a fatal error
758 */
22d09b27 759static int
60f56dfc
KM
760sderror(unit, sc, hp, stat)
761 int unit, stat;
762 register struct sd_softc *sc;
763 register struct hp_device *hp;
764{
761052c0 765 int cond = 1;
22d09b27 766
60f56dfc
KM
767 sdsense[unit].status = stat;
768 if (stat & STS_CHECKCOND) {
769 struct scsi_xsense *sp;
770
771 scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
772 sc->sc_punit, sdsense[unit].sense,
773 sizeof(sdsense[unit].sense));
774 sp = (struct scsi_xsense *)sdsense[unit].sense;
775 printf("sd%d: scsi sense class %d, code %d", unit,
776 sp->class, sp->code);
777 if (sp->class == 7) {
778 printf(", key %d", sp->key);
779 if (sp->valid)
780 printf(", blk %d", *(int *)&sp->info1);
761052c0
MK
781 switch (sp->key) {
782 /* no sense, try again */
783 case 0:
784 cond = -1;
785 break;
786 /* recovered error, not a problem */
787 case 1:
788 cond = 0;
789 break;
573b5fae
MH
790 /* possible media change */
791 case 6:
792 /*
793 * For removable media, if we are doing the
794 * first open (i.e. reading the label) go
795 * ahead and retry, otherwise someone has
796 * changed the media out from under us and
797 * we should abort any further operations
798 * until a close is done.
799 */
800 if (sc->sc_flags & SDF_RMEDIA) {
801 if (sc->sc_flags & SDF_OPENING)
802 cond = -1;
803 else
804 sc->sc_flags |= SDF_ERROR;
805 }
806 break;
761052c0 807 }
60f56dfc
KM
808 }
809 printf("\n");
810 }
761052c0 811 return(cond);
60f56dfc
KM
812}
813
814static void
815sdfinish(unit, sc, bp)
816 int unit;
817 register struct sd_softc *sc;
818 register struct buf *bp;
819{
9acfa6cd
MH
820 register struct buf *dp = &sdtab[unit];
821
822 dp->b_errcnt = 0;
823 dp->b_actf = bp->b_actf;
60f56dfc 824 bp->b_resid = 0;
22d09b27 825 biodone(bp);
60f56dfc 826 scsifree(&sc->sc_dq);
9acfa6cd 827 if (dp->b_actf)
60f56dfc 828 sdustart(unit);
9acfa6cd
MH
829 else {
830 dp->b_active = 0;
831 if (sc->sc_flags & SDF_WANTED) {
832 sc->sc_flags &= ~SDF_WANTED;
833 wakeup((caddr_t)dp);
834 }
835 }
60f56dfc
KM
836}
837
838void
839sdstart(unit)
840 register int unit;
841{
842 register struct sd_softc *sc = &sd_softc[unit];
843 register struct hp_device *hp = sc->sc_hd;
844
845 /*
846 * we have the SCSI bus -- in format mode, we may or may not need dma
847 * so check now.
848 */
0fb33df5 849 if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
60f56dfc
KM
850 register struct buf *bp = sdtab[unit].b_actf;
851 register int sts;
852
4bcb05ed
MH
853 sdtab[unit].b_errcnt = 0;
854 while (1) {
855 sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
856 sc->sc_punit, &sdcmd[unit],
857 bp->b_un.b_addr, bp->b_bcount,
858 bp->b_flags & B_READ);
859 sdsense[unit].status = sts;
860 if ((sts & 0xfe) == 0 ||
861 (sts = sderror(unit, sc, hp, sts)) == 0)
862 break;
863 if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) {
864 bp->b_flags |= B_ERROR;
865 bp->b_error = EIO;
866 break;
867 }
60f56dfc
KM
868 }
869 sdfinish(unit, sc, bp);
870
871 } else if (scsiustart(hp->hp_ctlr))
872 sdgo(unit);
873}
874
875void
876sdgo(unit)
877 register int unit;
878{
879 register struct sd_softc *sc = &sd_softc[unit];
880 register struct hp_device *hp = sc->sc_hd;
881 register struct buf *bp = sdtab[unit].b_actf;
882 register int pad;
883 register struct scsi_fmt_cdb *cmd;
884
0fb33df5 885 if (sc->sc_format_pid >= 0) {
60f56dfc
KM
886 cmd = &sdcmd[unit];
887 pad = 0;
888 } else {
4bcb05ed
MH
889 /*
890 * Drive is in an error state, abort all operations
891 */
892 if (sc->sc_flags & SDF_ERROR) {
893 bp->b_flags |= B_ERROR;
894 bp->b_error = EIO;
895 sdfinish(unit, sc, bp);
896 return;
897 }
60f56dfc
KM
898 cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
899 *(int *)(&cmd->cdb[2]) = bp->b_cylin;
900 pad = howmany(bp->b_bcount, sc->sc_blksize);
901 *(u_short *)(&cmd->cdb[7]) = pad;
902 pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
903#ifdef DEBUG
904 if (pad)
905 printf("sd%d: partial block xfer -- %x bytes\n",
906 unit, bp->b_bcount);
907#endif
908 sdstats[unit].sdtransfers++;
909 }
573b5fae
MH
910#ifdef USELEDS
911 if (inledcontrol == 0)
912 ledcontrol(0, 0, LED_DISK);
913#endif
60f56dfc
KM
914 if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
915 if (hp->hp_dk >= 0) {
916 dk_busy |= 1 << hp->hp_dk;
917 ++dk_seek[hp->hp_dk];
918 ++dk_xfer[hp->hp_dk];
919 dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
920 }
921 return;
922 }
923#ifdef DEBUG
924 if (sddebug & SDB_ERROR)
925 printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
926 unit, bp->b_flags & B_READ? "read" : "write",
927 bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
928 sdtab[unit].b_errcnt);
929#endif
930 bp->b_flags |= B_ERROR;
931 bp->b_error = EIO;
932 sdfinish(unit, sc, bp);
933}
934
935void
936sdintr(unit, stat)
937 register int unit;
938 int stat;
939{
940 register struct sd_softc *sc = &sd_softc[unit];
941 register struct buf *bp = sdtab[unit].b_actf;
942 register struct hp_device *hp = sc->sc_hd;
761052c0 943 int cond;
60f56dfc
KM
944
945 if (bp == NULL) {
946 printf("sd%d: bp == NULL\n", unit);
947 return;
948 }
949 if (hp->hp_dk >= 0)
950 dk_busy &=~ (1 << hp->hp_dk);
951 if (stat) {
952#ifdef DEBUG
953 if (sddebug & SDB_ERROR)
954 printf("sd%d: sdintr: bad scsi status 0x%x\n",
955 unit, stat);
956#endif
761052c0
MK
957 cond = sderror(unit, sc, hp, stat);
958 if (cond) {
959 if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
ebe91f3c 960#ifdef DEBUG
761052c0
MK
961 if (sddebug & SDB_ERROR)
962 printf("sd%d: retry #%d\n",
963 unit, sdtab[unit].b_errcnt);
ebe91f3c 964#endif
761052c0
MK
965 sdstart(unit);
966 return;
967 }
968 bp->b_flags |= B_ERROR;
969 bp->b_error = EIO;
22d09b27 970 }
60f56dfc
KM
971 }
972 sdfinish(unit, sc, bp);
973}
974
975int
88f29710 976sdread(dev, uio, flags)
60f56dfc
KM
977 dev_t dev;
978 struct uio *uio;
88f29710 979 int flags;
60f56dfc
KM
980{
981 register int unit = sdunit(dev);
982 register int pid;
983
0fb33df5 984 if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
88f29710 985 pid != uio->uio_procp->p_pid)
60f56dfc
KM
986 return (EPERM);
987
88f29710 988 return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
60f56dfc
KM
989}
990
991int
88f29710 992sdwrite(dev, uio, flags)
60f56dfc
KM
993 dev_t dev;
994 struct uio *uio;
88f29710 995 int flags;
60f56dfc
KM
996{
997 register int unit = sdunit(dev);
998 register int pid;
999
0fb33df5 1000 if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
88f29710 1001 pid != uio->uio_procp->p_pid)
60f56dfc
KM
1002 return (EPERM);
1003
88f29710 1004 return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
60f56dfc
KM
1005}
1006
1007int
88f29710 1008sdioctl(dev, cmd, data, flag, p)
60f56dfc 1009 dev_t dev;
fea890a2 1010 u_long cmd;
60f56dfc
KM
1011 caddr_t data;
1012 int flag;
88f29710 1013 struct proc *p;
60f56dfc 1014{
573b5fae 1015 int unit = sdunit(dev);
60f56dfc 1016 register struct sd_softc *sc = &sd_softc[unit];
573b5fae
MH
1017 register struct disklabel *lp = &sc->sc_info.si_label;
1018 int error, flags;
60f56dfc
KM
1019
1020 switch (cmd) {
1021 default:
1022 return (EINVAL);
1023
573b5fae
MH
1024 case DIOCGDINFO:
1025 *(struct disklabel *)data = *lp;
1026 return (0);
1027
1028 case DIOCGPART:
1029 ((struct partinfo *)data)->disklab = lp;
1030 ((struct partinfo *)data)->part =
1031 &lp->d_partitions[sdpart(dev)];
1032 return (0);
1033
1034 case DIOCWLABEL:
1035 if ((flag & FWRITE) == 0)
1036 return (EBADF);
1037 if (*(int *)data)
1038 sc->sc_flags |= SDF_WLABEL;
1039 else
1040 sc->sc_flags &= ~SDF_WLABEL;
1041 return (0);
1042
1043 case DIOCSDINFO:
1044 if ((flag & FWRITE) == 0)
1045 return (EBADF);
1046 error = setdisklabel(lp, (struct disklabel *)data,
1047 (sc->sc_flags & SDF_WLABEL) ? 0
1048 : sc->sc_info.si_open);
1049 return (error);
1050
1051 case DIOCWDINFO:
1052 if ((flag & FWRITE) == 0)
1053 return (EBADF);
1054 error = setdisklabel(lp, (struct disklabel *)data,
1055 (sc->sc_flags & SDF_WLABEL) ? 0
1056 : sc->sc_info.si_open);
1057 if (error)
1058 return (error);
1059 flags = sc->sc_flags;
1060 sc->sc_flags = SDF_ALIVE | SDF_WLABEL;
1061 error = writedisklabel(sdlabdev(dev), sdstrategy, lp);
1062 sc->sc_flags = flags;
1063 return (error);
1064
60f56dfc
KM
1065 case SDIOCSFORMAT:
1066 /* take this device into or out of "format" mode */
88f29710 1067 if (suser(p->p_ucred, &p->p_acflag))
60f56dfc
KM
1068 return(EPERM);
1069
1070 if (*(int *)data) {
0fb33df5 1071 if (sc->sc_format_pid >= 0)
60f56dfc 1072 return (EPERM);
88f29710 1073 sc->sc_format_pid = p->p_pid;
60f56dfc 1074 } else
0fb33df5 1075 sc->sc_format_pid = -1;
60f56dfc
KM
1076 return (0);
1077
1078 case SDIOCGFORMAT:
1079 /* find out who has the device in format mode */
1080 *(int *)data = sc->sc_format_pid;
1081 return (0);
1082
1083 case SDIOCSCSICOMMAND:
1084 /*
1085 * Save what user gave us as SCSI cdb to use with next
1086 * read or write to the char device.
1087 */
88f29710 1088 if (sc->sc_format_pid != p->p_pid)
60f56dfc
KM
1089 return (EPERM);
1090 if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
1091 return (EINVAL);
1092 bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
1093 return (0);
1094
1095 case SDIOCSENSE:
1096 /*
1097 * return the SCSI sense data saved after the last
1098 * operation that completed with "check condition" status.
1099 */
1100 bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
1101 return (0);
1102
1103 }
1104 /*NOTREACHED*/
1105}
1106
1107int
1108sdsize(dev)
1109 dev_t dev;
1110{
1111 register int unit = sdunit(dev);
1112 register struct sd_softc *sc = &sd_softc[unit];
573b5fae 1113 int psize, didopen = 0;
60f56dfc
KM
1114
1115 if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
1116 return(-1);
1117
573b5fae
MH
1118 /*
1119 * We get called very early on (via swapconf)
1120 * without the device being open so we may need
1121 * to handle it here.
1122 */
1123 if (sc->sc_info.si_open == 0) {
1124 if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
1125 return(-1);
1126 didopen = 1;
1127 }
1128 psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size;
1129 if (didopen)
1130 (void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
1131 return (psize);
60f56dfc
KM
1132}
1133
60f56dfc
KM
1134/*
1135 * Non-interrupt driven, non-dma dump routine.
1136 */
1137int
1138sddump(dev)
1139 dev_t dev;
1140{
1141 int part = sdpart(dev);
1142 int unit = sdunit(dev);
1143 register struct sd_softc *sc = &sd_softc[unit];
1144 register struct hp_device *hp = sc->sc_hd;
573b5fae 1145 register struct partition *pinfo;
60f56dfc
KM
1146 register daddr_t baddr;
1147 register int maddr;
1148 register int pages, i;
1149 int stat;
0fb33df5 1150 extern int lowram, dumpsize;
60f56dfc 1151
60f56dfc
KM
1152 /* is drive ok? */
1153 if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
1154 return (ENXIO);
573b5fae 1155 pinfo = &sc->sc_info.si_label.d_partitions[part];
60f56dfc 1156 /* dump parameters in range? */
573b5fae
MH
1157 if (dumplo < 0 || dumplo >= pinfo->p_size ||
1158 pinfo->p_fstype != FS_SWAP)
60f56dfc 1159 return (EINVAL);
0fb33df5 1160 pages = dumpsize;
573b5fae
MH
1161 if (dumplo + ctod(pages) > pinfo->p_size)
1162 pages = dtoc(pinfo->p_size - dumplo);
60f56dfc 1163 maddr = lowram;
573b5fae 1164 baddr = dumplo + pinfo->p_offset;
60f56dfc
KM
1165 /* scsi bus idle? */
1166 if (!scsireq(&sc->sc_dq)) {
1167 scsireset(hp->hp_ctlr);
1168 sdreset(sc, sc->sc_hd);
1169 printf("[ drive %d reset ] ", unit);
1170 }
1171 for (i = 0; i < pages; i++) {
1172#define NPGMB (1024*1024/NBPG)
1173 /* print out how many Mbs we have dumped */
1174 if (i && (i % NPGMB) == 0)
1175 printf("%d ", i / NPGMB);
1176#undef NPBMG
7cf88bec 1177 pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
e0f6df7b 1178 VM_PROT_READ, TRUE);
60f56dfc
KM
1179 stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
1180 vmmap, NBPG, baddr, sc->sc_bshift);
1181 if (stat) {
1182 printf("sddump: scsi write error 0x%x\n", stat);
1183 return (EIO);
1184 }
1185 maddr += NBPG;
1186 baddr += ctod(1);
1187 }
1188 return (0);
1189}
1190#endif