xref: /csrg-svn/sys/hp300/dev/sd.c (revision 57327)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
341480Smckusick  * All rights reserved.
441480Smckusick  *
541480Smckusick  * This code is derived from software contributed to Berkeley by
641480Smckusick  * Van Jacobson of Lawrence Berkeley Laboratory.
741480Smckusick  *
841480Smckusick  * %sccs.include.redist.c%
941480Smckusick  *
10*57327Shibler  *	@(#)sd.c	7.17 (Berkeley) 12/27/92
1141480Smckusick  */
1241480Smckusick 
1341480Smckusick /*
1441480Smckusick  * SCSI CCS (Command Command Set) disk driver.
1541480Smckusick  */
1641480Smckusick #include "sd.h"
1741480Smckusick #if NSD > 0
1841480Smckusick 
1941480Smckusick #ifndef lint
20*57327Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/sd.c,v 1.4 92/12/26 13:26:40 mike Exp $";
2141480Smckusick #endif
2241480Smckusick 
2356507Sbostic #include <sys/param.h>
2456507Sbostic #include <sys/systm.h>
2556507Sbostic #include <sys/buf.h>
26*57327Shibler #include <sys/stat.h>
2756507Sbostic #include <sys/dkstat.h>
2856507Sbostic #include <sys/disklabel.h>
2956507Sbostic #include <sys/malloc.h>
3056507Sbostic #include <sys/proc.h>
3156507Sbostic #include <sys/ioctl.h>
32*57327Shibler #include <sys/fcntl.h>
3341480Smckusick 
3456507Sbostic #include <hp/dev/device.h>
3556507Sbostic #include <hp300/dev/scsireg.h>
36*57327Shibler #include <hp300/dev/sdvar.h>
37*57327Shibler #ifdef USELEDS
38*57327Shibler #include <hp300/hp300/led.h>
39*57327Shibler #endif
4045750Smckusick 
4156507Sbostic #include <vm/vm_param.h>
4256507Sbostic #include <vm/lock.h>
4356507Sbostic #include <vm/vm_prot.h>
4456507Sbostic #include <vm/pmap.h>
4556507Sbostic 
4641480Smckusick extern int scsi_test_unit_rdy();
4741480Smckusick extern int scsi_request_sense();
4841480Smckusick extern int scsi_inquiry();
4941480Smckusick extern int scsi_read_capacity();
5041480Smckusick extern int scsi_tt_write();
5141480Smckusick extern int scsireq();
5241480Smckusick extern int scsiustart();
5341480Smckusick extern int scsigo();
5441480Smckusick extern void scsifree();
5541480Smckusick extern void scsireset();
5649304Shibler extern void scsi_delay();
5741480Smckusick 
5841480Smckusick extern void disksort();
5941480Smckusick extern void biodone();
6041480Smckusick extern int physio();
6141480Smckusick extern void TBIS();
6241480Smckusick 
6341480Smckusick int	sdinit();
6441480Smckusick void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
6541480Smckusick 
6641480Smckusick struct	driver sddriver = {
6741480Smckusick 	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
6841480Smckusick };
6941480Smckusick 
7041480Smckusick #ifdef DEBUG
7141480Smckusick int sddebug = 1;
7241480Smckusick #define SDB_ERROR	0x01
7341480Smckusick #define SDB_PARTIAL	0x02
7441480Smckusick #endif
7541480Smckusick 
76*57327Shibler struct	sd_softc sd_softc[NSD];
77*57327Shibler struct	sdstats sdstats[NSD];
7841480Smckusick struct	buf sdtab[NSD];
7941480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
8041480Smckusick struct	scsi_fmt_sense sdsense[NSD];
8141480Smckusick 
8241480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
8341480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
8441480Smckusick 
8541480Smckusick /*
8641480Smckusick  * Table of scsi commands users are allowed to access via "format"
8741480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
8841480Smckusick  * -1 means needs dma and/or wait for intr.
8941480Smckusick  */
9041480Smckusick static char legal_cmds[256] = {
9141480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
9241480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9341480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
9441480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9541480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9641480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9741480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9841480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9941480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10041480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10141480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10241480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10341480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10441480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10541480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10641480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10741480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10841480Smckusick };
10941480Smckusick 
11041480Smckusick static struct scsi_inquiry inqbuf;
11141480Smckusick static struct scsi_fmt_cdb inq = {
11241480Smckusick 	6,
11341480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
11441480Smckusick };
11541480Smckusick 
11641480Smckusick static u_char capbuf[8];
11741480Smckusick struct scsi_fmt_cdb cap = {
11841480Smckusick 	10,
11941480Smckusick 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
12041480Smckusick };
12141480Smckusick 
12241480Smckusick static int
12341480Smckusick sdident(sc, hd)
12441480Smckusick 	struct sd_softc *sc;
12541480Smckusick 	struct hp_device *hd;
12641480Smckusick {
12741480Smckusick 	int unit;
12841480Smckusick 	register int ctlr, slave;
12941480Smckusick 	register int i;
13041480Smckusick 	register int tries = 10;
13149304Shibler 	char idstr[32];
13245750Smckusick 	int ismo = 0;
13341480Smckusick 
13441480Smckusick 	ctlr = hd->hp_ctlr;
13541480Smckusick 	slave = hd->hp_slave;
13641480Smckusick 	unit = sc->sc_punit;
13749304Shibler 	scsi_delay(-1);
13841480Smckusick 
13941480Smckusick 	/*
14041480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
14141480Smckusick 	 */
14241480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
14345750Smckusick 		if (i == -1 || --tries < 0) {
14445750Smckusick 			if (ismo)
14545750Smckusick 				break;
14641480Smckusick 			/* doesn't exist or not a CCS device */
14749304Shibler 			goto failed;
14845750Smckusick 		}
14941480Smckusick 		if (i == STS_CHECKCOND) {
15041480Smckusick 			u_char sensebuf[128];
15141480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
15241480Smckusick 
15341480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
15441480Smckusick 					   sizeof(sensebuf));
15545750Smckusick 			if (sp->class == 7)
15645750Smckusick 				switch (sp->key) {
15745750Smckusick 				/* not ready -- might be MO with no media */
15845750Smckusick 				case 2:
15945750Smckusick 					if (sp->len == 12 &&
16045750Smckusick 					    sensebuf[12] == 10)	/* XXX */
16145750Smckusick 						ismo = 1;
16245750Smckusick 					break;
16341480Smckusick 				/* drive doing an RTZ -- give it a while */
16445750Smckusick 				case 6:
16545750Smckusick 					DELAY(1000000);
16645750Smckusick 					break;
16745750Smckusick 				default:
16845750Smckusick 					break;
16945750Smckusick 				}
17041480Smckusick 		}
17141480Smckusick 		DELAY(1000);
17241480Smckusick 	}
17345750Smckusick 	/*
17445750Smckusick 	 * Find out about device
17545750Smckusick 	 */
17645750Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq,
17745750Smckusick 			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
17849304Shibler 		goto failed;
17941480Smckusick 	switch (inqbuf.type) {
18041480Smckusick 	case 0:		/* disk */
18141480Smckusick 	case 4:		/* WORM */
18241480Smckusick 	case 5:		/* CD-ROM */
18341480Smckusick 	case 7:		/* Magneto-optical */
18441480Smckusick 		break;
18541480Smckusick 	default:	/* not a disk */
18649304Shibler 		goto failed;
18741480Smckusick 	}
18845750Smckusick 	/*
18949304Shibler 	 * Get a usable id string
19045750Smckusick 	 */
191*57327Shibler 	switch (inqbuf.version) {
192*57327Shibler 	case 1:
193*57327Shibler 	case 2:
19449304Shibler 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
19549304Shibler 		for (i = 27; i > 23; --i)
19649304Shibler 			if (idstr[i] != ' ')
19749304Shibler 				break;
19849304Shibler 		idstr[i+1] = 0;
19949304Shibler 		for (i = 23; i > 7; --i)
20049304Shibler 			if (idstr[i] != ' ')
20149304Shibler 				break;
20249304Shibler 		idstr[i+1] = 0;
20349304Shibler 		for (i = 7; i >= 0; --i)
20449304Shibler 			if (idstr[i] != ' ')
20549304Shibler 				break;
20649304Shibler 		idstr[i+1] = 0;
207*57327Shibler 		break;
208*57327Shibler 	default:
209*57327Shibler 		bcopy("UNKNOWN", &idstr[0], 8);
210*57327Shibler 		bcopy("DRIVE TYPE", &idstr[8], 11);
21145750Smckusick 	}
21245750Smckusick 	i = scsi_immed_command(ctlr, slave, unit, &cap,
21345750Smckusick 			       (u_char *)&capbuf, sizeof(capbuf), B_READ);
21445750Smckusick 	if (i) {
21549304Shibler 		if (i != STS_CHECKCOND ||
21649304Shibler 		    bcmp(&idstr[0], "HP", 3) ||
21749304Shibler 		    bcmp(&idstr[8], "S6300.650A", 11))
21849304Shibler 			goto failed;
21945750Smckusick 		/* XXX unformatted or non-existant MO media; fake it */
22049304Shibler 		sc->sc_blks = 318664;
22149304Shibler 		sc->sc_blksize = 1024;
22245750Smckusick 	} else {
22345750Smckusick 		sc->sc_blks = *(u_int *)&capbuf[0];
22445750Smckusick 		sc->sc_blksize = *(int *)&capbuf[4];
22545750Smckusick 	}
22645750Smckusick 	/* return value of read capacity is last valid block number */
22745750Smckusick 	sc->sc_blks++;
22845750Smckusick 
229*57327Shibler 	switch (inqbuf.version) {
230*57327Shibler 	case 1:
231*57327Shibler 	case 2:
23241480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
23341480Smckusick 			&idstr[24]);
234*57327Shibler 		if (inqbuf.version == 2)
235*57327Shibler 			printf(" (SCSI-2)");
236*57327Shibler 		break;
237*57327Shibler 	default:
238*57327Shibler 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
239*57327Shibler 		       inqbuf.type, inqbuf.qual, inqbuf.version);
240*57327Shibler 		break;
241*57327Shibler 	}
24241480Smckusick 	printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
24353929Shibler 	if (inqbuf.qual & 0x80)
24453929Shibler 		sc->sc_flags |= SDF_RMEDIA;
24541480Smckusick 	if (sc->sc_blksize != DEV_BSIZE) {
24641480Smckusick 		if (sc->sc_blksize < DEV_BSIZE) {
24741480Smckusick 			printf("sd%d: need %d byte blocks - drive ignored\n",
24841480Smckusick 				unit, DEV_BSIZE);
24949304Shibler 			goto failed;
25041480Smckusick 		}
25141480Smckusick 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
25241480Smckusick 			++sc->sc_bshift;
25341480Smckusick 		sc->sc_blks <<= sc->sc_bshift;
25441480Smckusick 	}
25541480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
25649304Shibler 	scsi_delay(0);
25741480Smckusick 	return(inqbuf.type);
25849304Shibler failed:
25949304Shibler 	scsi_delay(0);
26049304Shibler 	return(-1);
26141480Smckusick }
26241480Smckusick 
26341480Smckusick int
26441480Smckusick sdinit(hd)
26541480Smckusick 	register struct hp_device *hd;
26641480Smckusick {
26741480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
26841480Smckusick 
26941480Smckusick 	sc->sc_hd = hd;
27053929Shibler 	sc->sc_flags = 0;
27141480Smckusick 	sc->sc_punit = sdpunit(hd->hp_flags);
27241480Smckusick 	sc->sc_type = sdident(sc, hd);
27341480Smckusick 	if (sc->sc_type < 0)
27441480Smckusick 		return(0);
27541480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
27641480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
27741480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
27841480Smckusick 	sc->sc_dq.dq_driver = &sddriver;
27941480Smckusick 
28053929Shibler 	sc->sc_flags |= SDF_ALIVE;
28141480Smckusick 	return(1);
28241480Smckusick }
28341480Smckusick 
28441480Smckusick void
28541480Smckusick sdreset(sc, hd)
28641480Smckusick 	register struct sd_softc *sc;
28741480Smckusick 	register struct hp_device *hd;
28841480Smckusick {
28941480Smckusick 	sdstats[hd->hp_unit].sdresets++;
29041480Smckusick }
29141480Smckusick 
292*57327Shibler /*
293*57327Shibler  * Read or constuct a disklabel
294*57327Shibler  */
29541480Smckusick int
296*57327Shibler sdgetinfo(dev)
297*57327Shibler 	dev_t dev;
298*57327Shibler {
299*57327Shibler 	int unit = sdunit(dev);
300*57327Shibler 	register struct sd_softc *sc = &sd_softc[unit];
301*57327Shibler 	register struct disklabel *lp = &sc->sc_info.si_label;
302*57327Shibler 	register struct partition *pi;
303*57327Shibler 	char *msg, *readdisklabel();
304*57327Shibler 
305*57327Shibler 	/*
306*57327Shibler 	 * Set some default values to use while reading the label
307*57327Shibler 	 * or to use if there isn't a label.
308*57327Shibler 	 */
309*57327Shibler 	bzero((caddr_t)lp, sizeof *lp);
310*57327Shibler 	lp->d_type = DTYPE_SCSI;
311*57327Shibler 	lp->d_secsize = DEV_BSIZE;
312*57327Shibler 	lp->d_nsectors = 32;
313*57327Shibler 	lp->d_ntracks = 20;
314*57327Shibler 	lp->d_secpercyl = 32*20;
315*57327Shibler 	lp->d_npartitions = 3;
316*57327Shibler 	lp->d_partitions[2].p_offset = 0;
317*57327Shibler 	/* XXX ensure size is at least one device block */
318*57327Shibler 	lp->d_partitions[2].p_size =
319*57327Shibler 		roundup(LABELSECTOR+1, btodb(sc->sc_blksize));
320*57327Shibler 
321*57327Shibler 	/*
322*57327Shibler 	 * Now try to read the disklabel
323*57327Shibler 	 */
324*57327Shibler 	msg = readdisklabel(sdlabdev(dev), sdstrategy, lp);
325*57327Shibler 	if (msg == NULL)
326*57327Shibler 		return(0);
327*57327Shibler 	if (bcmp(msg, "I/O", 3) == 0) /* XXX */
328*57327Shibler 		return(EIO);
329*57327Shibler 
330*57327Shibler 	pi = lp->d_partitions;
331*57327Shibler 	printf("sd%d: WARNING: %s, ", unit, msg);
332*57327Shibler #ifdef COMPAT_NOLABEL
333*57327Shibler 	printf("using old default partitioning\n");
334*57327Shibler 	sdmakedisklabel(unit, lp);
335*57327Shibler #else
336*57327Shibler 	printf("defining `c' partition as entire disk\n");
337*57327Shibler 	pi[2].p_size = sc->sc_blks;
338*57327Shibler #endif
339*57327Shibler 	return(0);
340*57327Shibler }
341*57327Shibler 
342*57327Shibler int
34349132Skarels sdopen(dev, flags, mode, p)
34441480Smckusick 	dev_t dev;
34549132Skarels 	int flags, mode;
34649132Skarels 	struct proc *p;
34741480Smckusick {
34841480Smckusick 	register int unit = sdunit(dev);
34941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
350*57327Shibler 	int mask, error;
35141480Smckusick 
35241480Smckusick 	if (unit >= NSD)
35341480Smckusick 		return(ENXIO);
35449132Skarels 	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
35541480Smckusick 		return(ENXIO);
356*57327Shibler 	if (sc->sc_flags & SDF_ERROR)
357*57327Shibler 		return(EIO);
35841480Smckusick 
359*57327Shibler 	/*
360*57327Shibler 	 * Wait for any pending opens/closes to complete
361*57327Shibler 	 */
362*57327Shibler 	while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING))
363*57327Shibler 		sleep((caddr_t)sc, PRIBIO);
364*57327Shibler 	/*
365*57327Shibler 	 * On first open, get label and partition info.
366*57327Shibler 	 * We may block reading the label, so be careful
367*57327Shibler 	 * to stop any other opens.
368*57327Shibler 	 */
369*57327Shibler 	if (sc->sc_info.si_open == 0) {
370*57327Shibler 		sc->sc_flags |= SDF_OPENING;
371*57327Shibler 		error = sdgetinfo(dev);
372*57327Shibler 		sc->sc_flags &= ~SDF_OPENING;
373*57327Shibler 		wakeup((caddr_t)sc);
374*57327Shibler 		if (error)
375*57327Shibler 			return(error);
376*57327Shibler 	}
37741480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
37841480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
379*57327Shibler 
380*57327Shibler 	mask = 1 << sdpart(dev);
381*57327Shibler 	if (mode == S_IFCHR)
382*57327Shibler 		sc->sc_info.si_copen |= mask;
383*57327Shibler 	else
384*57327Shibler 		sc->sc_info.si_bopen |= mask;
385*57327Shibler 	sc->sc_info.si_open |= mask;
38641480Smckusick 	return(0);
38741480Smckusick }
38841480Smckusick 
38953929Shibler int
39053929Shibler sdclose(dev, flag, mode, p)
39153929Shibler 	dev_t dev;
39253929Shibler 	int flag, mode;
39353929Shibler 	struct proc *p;
39453929Shibler {
39553929Shibler 	int unit = sdunit(dev);
39653929Shibler 	register struct sd_softc *sc = &sd_softc[unit];
397*57327Shibler 	register struct sdinfo *si = &sc->sc_info;
398*57327Shibler 	int mask, s;
39953929Shibler 
400*57327Shibler 	mask = 1 << sdpart(dev);
401*57327Shibler 	if (mode == S_IFCHR)
402*57327Shibler 		si->si_copen &= ~mask;
403*57327Shibler 	else
404*57327Shibler 		si->si_bopen &= ~mask;
405*57327Shibler 	si->si_open = si->si_bopen | si->si_copen;
40653929Shibler 	/*
407*57327Shibler 	 * On last close, we wait for all activity to cease since
408*57327Shibler 	 * the label/parition info will become invalid.  Since we
409*57327Shibler 	 * might sleep, we must block any opens while we are here.
410*57327Shibler 	 * Note we don't have to about other closes since we know
411*57327Shibler 	 * we are the last one.
41253929Shibler 	 */
413*57327Shibler 	if (si->si_open == 0) {
414*57327Shibler 		sc->sc_flags |= SDF_CLOSING;
41553929Shibler 		s = splbio();
41653929Shibler 		while (sdtab[unit].b_active) {
41753929Shibler 			sc->sc_flags |= SDF_WANTED;
41853929Shibler 			sleep((caddr_t)&sdtab[unit], PRIBIO);
41953929Shibler 		}
42053929Shibler 		splx(s);
421*57327Shibler 		sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR);
422*57327Shibler 		wakeup((caddr_t)sc);
42353929Shibler 	}
42453929Shibler 	sc->sc_format_pid = 0;
425*57327Shibler 	return(0);
42653929Shibler }
42753929Shibler 
42841480Smckusick /*
42941480Smckusick  * This routine is called for partial block transfers and non-aligned
43041480Smckusick  * transfers (the latter only being possible on devices with a block size
43141480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
43241480Smckusick  * using a locally allocated buffer:
43341480Smckusick  *	1. transfer any initial partial block
43441480Smckusick  *	2. transfer full blocks
43541480Smckusick  *	3. transfer any final partial block
43641480Smckusick  */
43741480Smckusick static void
43841480Smckusick sdlblkstrat(bp, bsize)
43941480Smckusick 	register struct buf *bp;
44041480Smckusick 	register int bsize;
44141480Smckusick {
44241480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
44341480Smckusick 							M_DEVBUF, M_WAITOK);
44441480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
44541480Smckusick 	register int bn, resid;
44641480Smckusick 	register caddr_t addr;
44741480Smckusick 
44841480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
44949132Skarels 	cbp->b_proc = curproc;		/* XXX */
45041480Smckusick 	cbp->b_dev = bp->b_dev;
45141480Smckusick 	bn = bp->b_blkno;
45241480Smckusick 	resid = bp->b_bcount;
45341480Smckusick 	addr = bp->b_un.b_addr;
45441480Smckusick #ifdef DEBUG
45541480Smckusick 	if (sddebug & SDB_PARTIAL)
45641480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
45741480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
45841480Smckusick #endif
45941480Smckusick 
46041480Smckusick 	while (resid > 0) {
46141480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
46241480Smckusick 		register int count;
46341480Smckusick 
46441480Smckusick 		if (boff || resid < bsize) {
46541480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
46655068Spendry 			count = min(resid, bsize - boff);
46741480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
46841480Smckusick 			cbp->b_blkno = bn - btodb(boff);
46941480Smckusick 			cbp->b_un.b_addr = cbuf;
47041480Smckusick 			cbp->b_bcount = bsize;
47141480Smckusick #ifdef DEBUG
47241480Smckusick 			if (sddebug & SDB_PARTIAL)
47341480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
47441480Smckusick 				       cbp->b_blkno, count, boff, addr);
47541480Smckusick #endif
47641480Smckusick 			sdstrategy(cbp);
47741480Smckusick 			biowait(cbp);
47841480Smckusick 			if (cbp->b_flags & B_ERROR) {
47941480Smckusick 				bp->b_flags |= B_ERROR;
48041480Smckusick 				bp->b_error = cbp->b_error;
48141480Smckusick 				break;
48241480Smckusick 			}
48341480Smckusick 			if (bp->b_flags & B_READ) {
48441480Smckusick 				bcopy(&cbuf[boff], addr, count);
48541480Smckusick 				goto done;
48641480Smckusick 			}
48741480Smckusick 			bcopy(addr, &cbuf[boff], count);
48841480Smckusick #ifdef DEBUG
48941480Smckusick 			if (sddebug & SDB_PARTIAL)
49041480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
49141480Smckusick 				       cbp->b_blkno, count, boff, addr);
49241480Smckusick #endif
49341480Smckusick 		} else {
49441480Smckusick 			count = resid & ~(bsize - 1);
49541480Smckusick 			cbp->b_blkno = bn;
49641480Smckusick 			cbp->b_un.b_addr = addr;
49741480Smckusick 			cbp->b_bcount = count;
49841480Smckusick #ifdef DEBUG
49941480Smckusick 			if (sddebug & SDB_PARTIAL)
50041480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
50141480Smckusick 				       cbp->b_blkno, count, addr);
50241480Smckusick #endif
50341480Smckusick 		}
50441480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
50541480Smckusick 		sdstrategy(cbp);
50641480Smckusick 		biowait(cbp);
50741480Smckusick 		if (cbp->b_flags & B_ERROR) {
50841480Smckusick 			bp->b_flags |= B_ERROR;
50941480Smckusick 			bp->b_error = cbp->b_error;
51041480Smckusick 			break;
51141480Smckusick 		}
51241480Smckusick done:
51341480Smckusick 		bn += btodb(count);
51441480Smckusick 		resid -= count;
51541480Smckusick 		addr += count;
51641480Smckusick #ifdef DEBUG
51741480Smckusick 		if (sddebug & SDB_PARTIAL)
51841480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
51941480Smckusick 			       bn, resid, addr);
52041480Smckusick #endif
52141480Smckusick 	}
52241480Smckusick 	free(cbuf, M_DEVBUF);
52341480Smckusick 	free(cbp, M_DEVBUF);
52441480Smckusick }
52541480Smckusick 
52641480Smckusick void
52741480Smckusick sdstrategy(bp)
52841480Smckusick 	register struct buf *bp;
52941480Smckusick {
530*57327Shibler 	int unit = sdunit(bp->b_dev);
53141480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
53241480Smckusick 	register struct buf *dp = &sdtab[unit];
533*57327Shibler 	register struct partition *pinfo;
53445750Smckusick 	register daddr_t bn;
53545750Smckusick 	register int sz, s;
53641480Smckusick 
537*57327Shibler 	if (sc->sc_flags & SDF_ERROR) {
538*57327Shibler 		bp->b_error = EIO;
539*57327Shibler 		goto bad;
540*57327Shibler 	}
54141480Smckusick 	if (sc->sc_format_pid) {
54249132Skarels 		if (sc->sc_format_pid != curproc->p_pid) {	/* XXX */
54341480Smckusick 			bp->b_error = EPERM;
544*57327Shibler 			goto bad;
54541480Smckusick 		}
54641480Smckusick 		bp->b_cylin = 0;
54741480Smckusick 	} else {
54841480Smckusick 		bn = bp->b_blkno;
54945750Smckusick 		sz = howmany(bp->b_bcount, DEV_BSIZE);
550*57327Shibler 		pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)];
551*57327Shibler 		if (bn < 0 || bn + sz > pinfo->p_size) {
552*57327Shibler 			sz = pinfo->p_size - bn;
55345750Smckusick 			if (sz == 0) {
55441480Smckusick 				bp->b_resid = bp->b_bcount;
55541480Smckusick 				goto done;
55641480Smckusick 			}
55745750Smckusick 			if (sz < 0) {
55845750Smckusick 				bp->b_error = EINVAL;
559*57327Shibler 				goto bad;
56045750Smckusick 			}
56145750Smckusick 			bp->b_bcount = dbtob(sz);
56241480Smckusick 		}
56341480Smckusick 		/*
564*57327Shibler 		 * Check for write to write protected label
565*57327Shibler 		 */
566*57327Shibler 		if (bn + pinfo->p_offset <= LABELSECTOR &&
567*57327Shibler #if LABELSECTOR != 0
568*57327Shibler 		    bn + pinfo->p_offset + sz > LABELSECTOR &&
569*57327Shibler #endif
570*57327Shibler 		    !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) {
571*57327Shibler 			bp->b_error = EROFS;
572*57327Shibler 			goto bad;
573*57327Shibler 		}
574*57327Shibler 		/*
57541480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
57641480Smckusick 		 */
57741480Smckusick 		s = sc->sc_blksize - 1;
57841480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
57941480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
58041480Smckusick 			goto done;
58141480Smckusick 		}
582*57327Shibler 		bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift;
58341480Smckusick 	}
58441480Smckusick 	s = splbio();
58541480Smckusick 	disksort(dp, bp);
58641480Smckusick 	if (dp->b_active == 0) {
58741480Smckusick 		dp->b_active = 1;
58841480Smckusick 		sdustart(unit);
58941480Smckusick 	}
59041480Smckusick 	splx(s);
59141480Smckusick 	return;
592*57327Shibler bad:
593*57327Shibler 	bp->b_flags |= B_ERROR;
59441480Smckusick done:
59545750Smckusick 	biodone(bp);
59641480Smckusick }
59741480Smckusick 
59841480Smckusick void
59941480Smckusick sdustart(unit)
60041480Smckusick 	register int unit;
60141480Smckusick {
60241480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
60341480Smckusick 		sdstart(unit);
60441480Smckusick }
60541480Smckusick 
60650039Skarels /*
60750039Skarels  * Return:
60850039Skarels  *	0	if not really an error
60950039Skarels  *	<0	if we should do a retry
61050039Skarels  *	>0	if a fatal error
61150039Skarels  */
61245750Smckusick static int
61341480Smckusick sderror(unit, sc, hp, stat)
61441480Smckusick 	int unit, stat;
61541480Smckusick 	register struct sd_softc *sc;
61641480Smckusick 	register struct hp_device *hp;
61741480Smckusick {
61850039Skarels 	int cond = 1;
61945750Smckusick 
62041480Smckusick 	sdsense[unit].status = stat;
62141480Smckusick 	if (stat & STS_CHECKCOND) {
62241480Smckusick 		struct scsi_xsense *sp;
62341480Smckusick 
62441480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
62541480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
62641480Smckusick 				   sizeof(sdsense[unit].sense));
62741480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
62841480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
62941480Smckusick 			sp->class, sp->code);
63041480Smckusick 		if (sp->class == 7) {
63141480Smckusick 			printf(", key %d", sp->key);
63241480Smckusick 			if (sp->valid)
63341480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
63450039Skarels 			switch (sp->key) {
63550039Skarels 			/* no sense, try again */
63650039Skarels 			case 0:
63750039Skarels 				cond = -1;
63850039Skarels 				break;
63950039Skarels 			/* recovered error, not a problem */
64050039Skarels 			case 1:
64150039Skarels 				cond = 0;
64250039Skarels 				break;
643*57327Shibler 			/* possible media change */
644*57327Shibler 			case 6:
645*57327Shibler 				/*
646*57327Shibler 				 * For removable media, if we are doing the
647*57327Shibler 				 * first open (i.e. reading the label) go
648*57327Shibler 				 * ahead and retry, otherwise someone has
649*57327Shibler 				 * changed the media out from under us and
650*57327Shibler 				 * we should abort any further operations
651*57327Shibler 				 * until a close is done.
652*57327Shibler 				 */
653*57327Shibler 				if (sc->sc_flags & SDF_RMEDIA) {
654*57327Shibler 					if (sc->sc_flags & SDF_OPENING)
655*57327Shibler 						cond = -1;
656*57327Shibler 					else
657*57327Shibler 						sc->sc_flags |= SDF_ERROR;
658*57327Shibler 				}
659*57327Shibler 				break;
66050039Skarels 			}
66141480Smckusick 		}
66241480Smckusick 		printf("\n");
66341480Smckusick 	}
66450039Skarels 	return(cond);
66541480Smckusick }
66641480Smckusick 
66741480Smckusick static void
66841480Smckusick sdfinish(unit, sc, bp)
66941480Smckusick 	int unit;
67041480Smckusick 	register struct sd_softc *sc;
67141480Smckusick 	register struct buf *bp;
67241480Smckusick {
67353929Shibler 	register struct buf *dp = &sdtab[unit];
67453929Shibler 
67553929Shibler 	dp->b_errcnt = 0;
67653929Shibler 	dp->b_actf = bp->b_actf;
67741480Smckusick 	bp->b_resid = 0;
67845750Smckusick 	biodone(bp);
67941480Smckusick 	scsifree(&sc->sc_dq);
68053929Shibler 	if (dp->b_actf)
68141480Smckusick 		sdustart(unit);
68253929Shibler 	else {
68353929Shibler 		dp->b_active = 0;
68453929Shibler 		if (sc->sc_flags & SDF_WANTED) {
68553929Shibler 			sc->sc_flags &= ~SDF_WANTED;
68653929Shibler 			wakeup((caddr_t)dp);
68753929Shibler 		}
68853929Shibler 	}
68941480Smckusick }
69041480Smckusick 
69141480Smckusick void
69241480Smckusick sdstart(unit)
69341480Smckusick 	register int unit;
69441480Smckusick {
69541480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
69641480Smckusick 	register struct hp_device *hp = sc->sc_hd;
69741480Smckusick 
69841480Smckusick 	/*
69941480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
70041480Smckusick 	 * so check now.
70141480Smckusick 	 */
70241480Smckusick 	if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
70341480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
70441480Smckusick 		register int sts;
70541480Smckusick 
70641480Smckusick 		sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
70741480Smckusick 					 sc->sc_punit, &sdcmd[unit],
70841480Smckusick 					 bp->b_un.b_addr, bp->b_bcount,
70941480Smckusick 					 bp->b_flags & B_READ);
71041480Smckusick 		sdsense[unit].status = sts;
71141480Smckusick 		if (sts & 0xfe) {
71245750Smckusick 			(void) sderror(unit, sc, hp, sts);
71341480Smckusick 			bp->b_flags |= B_ERROR;
71441480Smckusick 			bp->b_error = EIO;
71541480Smckusick 		}
71641480Smckusick 		sdfinish(unit, sc, bp);
71741480Smckusick 
71841480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
71941480Smckusick 		sdgo(unit);
72041480Smckusick }
72141480Smckusick 
72241480Smckusick void
72341480Smckusick sdgo(unit)
72441480Smckusick 	register int unit;
72541480Smckusick {
72641480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
72741480Smckusick 	register struct hp_device *hp = sc->sc_hd;
72841480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
72941480Smckusick 	register int pad;
73041480Smckusick 	register struct scsi_fmt_cdb *cmd;
73141480Smckusick 
732*57327Shibler 	/*
733*57327Shibler 	 * Drive is in an error state, abort all operations
734*57327Shibler 	 */
735*57327Shibler 	if (sc->sc_flags & SDF_ERROR) {
736*57327Shibler 		bp->b_flags |= B_ERROR;
737*57327Shibler 		bp->b_error = EIO;
738*57327Shibler 		sdfinish(unit, sc, bp);
739*57327Shibler 		return;
740*57327Shibler 	}
74141480Smckusick 	if (sc->sc_format_pid) {
74241480Smckusick 		cmd = &sdcmd[unit];
74341480Smckusick 		pad = 0;
74441480Smckusick 	} else {
74541480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
74641480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
74741480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
74841480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
74941480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
75041480Smckusick #ifdef DEBUG
75141480Smckusick 		if (pad)
75241480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
75341480Smckusick 			       unit, bp->b_bcount);
75441480Smckusick #endif
75541480Smckusick 		sdstats[unit].sdtransfers++;
75641480Smckusick 	}
757*57327Shibler #ifdef USELEDS
758*57327Shibler 	if (inledcontrol == 0)
759*57327Shibler 		ledcontrol(0, 0, LED_DISK);
760*57327Shibler #endif
76141480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
76241480Smckusick 		if (hp->hp_dk >= 0) {
76341480Smckusick 			dk_busy |= 1 << hp->hp_dk;
76441480Smckusick 			++dk_seek[hp->hp_dk];
76541480Smckusick 			++dk_xfer[hp->hp_dk];
76641480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
76741480Smckusick 		}
76841480Smckusick 		return;
76941480Smckusick 	}
77041480Smckusick #ifdef DEBUG
77141480Smckusick 	if (sddebug & SDB_ERROR)
77241480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
77341480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
77441480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
77541480Smckusick 		       sdtab[unit].b_errcnt);
77641480Smckusick #endif
77741480Smckusick 	bp->b_flags |= B_ERROR;
77841480Smckusick 	bp->b_error = EIO;
77941480Smckusick 	sdfinish(unit, sc, bp);
78041480Smckusick }
78141480Smckusick 
78241480Smckusick void
78341480Smckusick sdintr(unit, stat)
78441480Smckusick 	register int unit;
78541480Smckusick 	int stat;
78641480Smckusick {
78741480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
78841480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
78941480Smckusick 	register struct hp_device *hp = sc->sc_hd;
79050039Skarels 	int cond;
79141480Smckusick 
79241480Smckusick 	if (bp == NULL) {
79341480Smckusick 		printf("sd%d: bp == NULL\n", unit);
79441480Smckusick 		return;
79541480Smckusick 	}
79641480Smckusick 	if (hp->hp_dk >= 0)
79741480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
79841480Smckusick 	if (stat) {
79941480Smckusick #ifdef DEBUG
80041480Smckusick 		if (sddebug & SDB_ERROR)
80141480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
80241480Smckusick 				unit, stat);
80341480Smckusick #endif
80450039Skarels 		cond = sderror(unit, sc, hp, stat);
80550039Skarels 		if (cond) {
80650039Skarels 			if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
80750038Skarels #ifdef DEBUG
80850039Skarels 				if (sddebug & SDB_ERROR)
80950039Skarels 					printf("sd%d: retry #%d\n",
81050039Skarels 					       unit, sdtab[unit].b_errcnt);
81150038Skarels #endif
81250039Skarels 				sdstart(unit);
81350039Skarels 				return;
81450039Skarels 			}
81550039Skarels 			bp->b_flags |= B_ERROR;
81650039Skarels 			bp->b_error = EIO;
81745750Smckusick 		}
81841480Smckusick 	}
81941480Smckusick 	sdfinish(unit, sc, bp);
82041480Smckusick }
82141480Smckusick 
82241480Smckusick int
82349132Skarels sdread(dev, uio, flags)
82441480Smckusick 	dev_t dev;
82541480Smckusick 	struct uio *uio;
82649132Skarels 	int flags;
82741480Smckusick {
82841480Smckusick 	register int unit = sdunit(dev);
82941480Smckusick 	register int pid;
83041480Smckusick 
83149132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
83249132Skarels 	    pid != uio->uio_procp->p_pid)
83341480Smckusick 		return (EPERM);
83441480Smckusick 
83549132Skarels 	return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
83641480Smckusick }
83741480Smckusick 
83841480Smckusick int
83949132Skarels sdwrite(dev, uio, flags)
84041480Smckusick 	dev_t dev;
84141480Smckusick 	struct uio *uio;
84249132Skarels 	int flags;
84341480Smckusick {
84441480Smckusick 	register int unit = sdunit(dev);
84541480Smckusick 	register int pid;
84641480Smckusick 
84749132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
84849132Skarels 	    pid != uio->uio_procp->p_pid)
84941480Smckusick 		return (EPERM);
85041480Smckusick 
85149132Skarels 	return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
85241480Smckusick }
85341480Smckusick 
85441480Smckusick int
85549132Skarels sdioctl(dev, cmd, data, flag, p)
85641480Smckusick 	dev_t dev;
85741480Smckusick 	int cmd;
85841480Smckusick 	caddr_t data;
85941480Smckusick 	int flag;
86049132Skarels 	struct proc *p;
86141480Smckusick {
862*57327Shibler 	int unit = sdunit(dev);
86341480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
864*57327Shibler 	register struct disklabel *lp = &sc->sc_info.si_label;
865*57327Shibler 	int error, flags;
86641480Smckusick 
86741480Smckusick 	switch (cmd) {
86841480Smckusick 	default:
86941480Smckusick 		return (EINVAL);
87041480Smckusick 
871*57327Shibler 	case DIOCGDINFO:
872*57327Shibler 		*(struct disklabel *)data = *lp;
873*57327Shibler 		return (0);
874*57327Shibler 
875*57327Shibler 	case DIOCGPART:
876*57327Shibler 		((struct partinfo *)data)->disklab = lp;
877*57327Shibler 		((struct partinfo *)data)->part =
878*57327Shibler 			&lp->d_partitions[sdpart(dev)];
879*57327Shibler 		return (0);
880*57327Shibler 
881*57327Shibler         case DIOCWLABEL:
882*57327Shibler                 if ((flag & FWRITE) == 0)
883*57327Shibler                         return (EBADF);
884*57327Shibler 		if (*(int *)data)
885*57327Shibler 			sc->sc_flags |= SDF_WLABEL;
886*57327Shibler 		else
887*57327Shibler 			sc->sc_flags &= ~SDF_WLABEL;
888*57327Shibler 		return (0);
889*57327Shibler 
890*57327Shibler         case DIOCSDINFO:
891*57327Shibler                 if ((flag & FWRITE) == 0)
892*57327Shibler                         return (EBADF);
893*57327Shibler 		error = setdisklabel(lp, (struct disklabel *)data,
894*57327Shibler 				     (sc->sc_flags & SDF_WLABEL) ? 0
895*57327Shibler 				     : sc->sc_info.si_open);
896*57327Shibler 		return (error);
897*57327Shibler 
898*57327Shibler         case DIOCWDINFO:
899*57327Shibler 		if ((flag & FWRITE) == 0)
900*57327Shibler 			return (EBADF);
901*57327Shibler 		error = setdisklabel(lp, (struct disklabel *)data,
902*57327Shibler 				     (sc->sc_flags & SDF_WLABEL) ? 0
903*57327Shibler 				     : sc->sc_info.si_open);
904*57327Shibler 		if (error)
905*57327Shibler 			return (error);
906*57327Shibler 		flags = sc->sc_flags;
907*57327Shibler 		sc->sc_flags = SDF_ALIVE | SDF_WLABEL;
908*57327Shibler 		error = writedisklabel(sdlabdev(dev), sdstrategy, lp);
909*57327Shibler 		sc->sc_flags = flags;
910*57327Shibler 		return (error);
911*57327Shibler 
91241480Smckusick 	case SDIOCSFORMAT:
91341480Smckusick 		/* take this device into or out of "format" mode */
91449132Skarels 		if (suser(p->p_ucred, &p->p_acflag))
91541480Smckusick 			return(EPERM);
91641480Smckusick 
91741480Smckusick 		if (*(int *)data) {
91841480Smckusick 			if (sc->sc_format_pid)
91941480Smckusick 				return (EPERM);
92049132Skarels 			sc->sc_format_pid = p->p_pid;
92141480Smckusick 		} else
92241480Smckusick 			sc->sc_format_pid = 0;
92341480Smckusick 		return (0);
92441480Smckusick 
92541480Smckusick 	case SDIOCGFORMAT:
92641480Smckusick 		/* find out who has the device in format mode */
92741480Smckusick 		*(int *)data = sc->sc_format_pid;
92841480Smckusick 		return (0);
92941480Smckusick 
93041480Smckusick 	case SDIOCSCSICOMMAND:
93141480Smckusick 		/*
93241480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
93341480Smckusick 		 * read or write to the char device.
93441480Smckusick 		 */
93549132Skarels 		if (sc->sc_format_pid != p->p_pid)
93641480Smckusick 			return (EPERM);
93741480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
93841480Smckusick 			return (EINVAL);
93941480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
94041480Smckusick 		return (0);
94141480Smckusick 
94241480Smckusick 	case SDIOCSENSE:
94341480Smckusick 		/*
94441480Smckusick 		 * return the SCSI sense data saved after the last
94541480Smckusick 		 * operation that completed with "check condition" status.
94641480Smckusick 		 */
94741480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
94841480Smckusick 		return (0);
94941480Smckusick 
95041480Smckusick 	}
95141480Smckusick 	/*NOTREACHED*/
95241480Smckusick }
95341480Smckusick 
95441480Smckusick int
95541480Smckusick sdsize(dev)
95641480Smckusick 	dev_t dev;
95741480Smckusick {
95841480Smckusick 	register int unit = sdunit(dev);
95941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
960*57327Shibler 	int psize, didopen = 0;
96141480Smckusick 
96241480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
96341480Smckusick 		return(-1);
96441480Smckusick 
965*57327Shibler 	/*
966*57327Shibler 	 * We get called very early on (via swapconf)
967*57327Shibler 	 * without the device being open so we may need
968*57327Shibler 	 * to handle it here.
969*57327Shibler 	 */
970*57327Shibler 	if (sc->sc_info.si_open == 0) {
971*57327Shibler 		if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
972*57327Shibler 			return(-1);
973*57327Shibler 		didopen = 1;
974*57327Shibler 	}
975*57327Shibler 	psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size;
976*57327Shibler 	if (didopen)
977*57327Shibler 		(void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
978*57327Shibler 	return (psize);
97941480Smckusick }
98041480Smckusick 
98141480Smckusick /*
98241480Smckusick  * Non-interrupt driven, non-dma dump routine.
98341480Smckusick  */
98441480Smckusick int
98541480Smckusick sddump(dev)
98641480Smckusick 	dev_t dev;
98741480Smckusick {
98841480Smckusick 	int part = sdpart(dev);
98941480Smckusick 	int unit = sdunit(dev);
99041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
99141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
992*57327Shibler 	register struct partition *pinfo;
99341480Smckusick 	register daddr_t baddr;
99441480Smckusick 	register int maddr;
99541480Smckusick 	register int pages, i;
99641480Smckusick 	int stat;
99741480Smckusick 	extern int lowram;
99841480Smckusick 
99941480Smckusick 	/* is drive ok? */
100041480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
100141480Smckusick 		return (ENXIO);
1002*57327Shibler 	pinfo = &sc->sc_info.si_label.d_partitions[part];
100341480Smckusick 	/* dump parameters in range? */
1004*57327Shibler 	if (dumplo < 0 || dumplo >= pinfo->p_size ||
1005*57327Shibler 	    pinfo->p_fstype != FS_SWAP)
100641480Smckusick 		return (EINVAL);
1007*57327Shibler 	pages = physmem;
1008*57327Shibler 	if (dumplo + ctod(pages) > pinfo->p_size)
1009*57327Shibler 		pages = dtoc(pinfo->p_size - dumplo);
101041480Smckusick 	maddr = lowram;
1011*57327Shibler 	baddr = dumplo + pinfo->p_offset;
101241480Smckusick 	/* scsi bus idle? */
101341480Smckusick 	if (!scsireq(&sc->sc_dq)) {
101441480Smckusick 		scsireset(hp->hp_ctlr);
101541480Smckusick 		sdreset(sc, sc->sc_hd);
101641480Smckusick 		printf("[ drive %d reset ] ", unit);
101741480Smckusick 	}
101841480Smckusick 	for (i = 0; i < pages; i++) {
101941480Smckusick #define NPGMB	(1024*1024/NBPG)
102041480Smckusick 		/* print out how many Mbs we have dumped */
102141480Smckusick 		if (i && (i % NPGMB) == 0)
102241480Smckusick 			printf("%d ", i / NPGMB);
102341480Smckusick #undef NPBMG
102452614Smckusick 		pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
102551576Smckusick 		    VM_PROT_READ, TRUE);
102641480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
102741480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
102841480Smckusick 		if (stat) {
102941480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
103041480Smckusick 			return (EIO);
103141480Smckusick 		}
103241480Smckusick 		maddr += NBPG;
103341480Smckusick 		baddr += ctod(1);
103441480Smckusick 	}
103541480Smckusick 	return (0);
103641480Smckusick }
103741480Smckusick #endif
1038