xref: /csrg-svn/sys/hp300/dev/sd.c (revision 67184)
141480Smckusick /*
263151Sbostic  * Copyright (c) 1990, 1993
363151Sbostic  *	The Regents of the University of California.  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*67184Shibler  *	@(#)sd.c	8.5 (Berkeley) 05/19/94
1141480Smckusick  */
1241480Smckusick 
1341480Smckusick /*
1441480Smckusick  * SCSI CCS (Command Command Set) disk driver.
1541480Smckusick  */
1641480Smckusick #include "sd.h"
1741480Smckusick #if NSD > 0
1841480Smckusick 
1941480Smckusick #ifndef lint
2065662Shibler static char rcsid[] = "$Header: /sys.lite/hp300/dev/RCS/sd.c,v 1.2 1994/01/10 18:29:19 mike Exp mike $";
2141480Smckusick #endif
2241480Smckusick 
2356507Sbostic #include <sys/param.h>
2456507Sbostic #include <sys/systm.h>
2556507Sbostic #include <sys/buf.h>
2657327Shibler #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>
3257327Shibler #include <sys/fcntl.h>
3341480Smckusick 
3456507Sbostic #include <hp/dev/device.h>
3556507Sbostic #include <hp300/dev/scsireg.h>
3657327Shibler #include <hp300/dev/sdvar.h>
3757327Shibler #ifdef USELEDS
3857327Shibler #include <hp300/hp300/led.h>
3957327Shibler #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
7465662Shibler #define SDB_CAPACITY	0x04
7541480Smckusick #endif
7641480Smckusick 
7757327Shibler struct	sd_softc sd_softc[NSD];
7857327Shibler struct	sdstats sdstats[NSD];
7941480Smckusick struct	buf sdtab[NSD];
8041480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
8141480Smckusick struct	scsi_fmt_sense sdsense[NSD];
8241480Smckusick 
8341480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
8441480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
8541480Smckusick 
8641480Smckusick /*
8741480Smckusick  * Table of scsi commands users are allowed to access via "format"
8841480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
8941480Smckusick  * -1 means needs dma and/or wait for intr.
9041480Smckusick  */
9141480Smckusick static char legal_cmds[256] = {
9241480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
9341480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9441480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
9541480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9641480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9741480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9841480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
9941480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10041480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10141480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10241480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10341480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10441480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10541480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10641480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10741480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10841480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
10941480Smckusick };
11041480Smckusick 
11141480Smckusick static struct scsi_inquiry inqbuf;
11241480Smckusick static struct scsi_fmt_cdb inq = {
11341480Smckusick 	6,
11441480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
11541480Smckusick };
11641480Smckusick 
11741480Smckusick static int
11841480Smckusick sdident(sc, hd)
11941480Smckusick 	struct sd_softc *sc;
12041480Smckusick 	struct hp_device *hd;
12141480Smckusick {
12241480Smckusick 	int unit;
12341480Smckusick 	register int ctlr, slave;
12441480Smckusick 	register int i;
12541480Smckusick 	register int tries = 10;
12649304Shibler 	char idstr[32];
12765662Shibler 	int isrm = 0;
12841480Smckusick 
12941480Smckusick 	ctlr = hd->hp_ctlr;
13041480Smckusick 	slave = hd->hp_slave;
13141480Smckusick 	unit = sc->sc_punit;
13249304Shibler 	scsi_delay(-1);
13341480Smckusick 
13441480Smckusick 	/*
13541480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
13641480Smckusick 	 */
13741480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
13845750Smckusick 		if (i == -1 || --tries < 0) {
13965662Shibler 			if (isrm)
14045750Smckusick 				break;
14141480Smckusick 			/* doesn't exist or not a CCS device */
14249304Shibler 			goto failed;
14345750Smckusick 		}
14441480Smckusick 		if (i == STS_CHECKCOND) {
14541480Smckusick 			u_char sensebuf[128];
14641480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
14741480Smckusick 
14841480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
14941480Smckusick 					   sizeof(sensebuf));
15045750Smckusick 			if (sp->class == 7)
15145750Smckusick 				switch (sp->key) {
15265662Shibler 				/*
15365662Shibler 				 * Not ready -- might be removable media
15465662Shibler 				 * device with no media.  Assume as much,
15565662Shibler 				 * if it really isn't, the inquiry commmand
15665662Shibler 				 * below will fail.
15765662Shibler 				 */
15845750Smckusick 				case 2:
15965662Shibler 					isrm = 1;
16045750Smckusick 					break;
16141480Smckusick 				/* drive doing an RTZ -- give it a while */
16245750Smckusick 				case 6:
16345750Smckusick 					DELAY(1000000);
16445750Smckusick 					break;
16545750Smckusick 				default:
16645750Smckusick 					break;
16745750Smckusick 				}
16841480Smckusick 		}
16941480Smckusick 		DELAY(1000);
17041480Smckusick 	}
17145750Smckusick 	/*
17245750Smckusick 	 * Find out about device
17345750Smckusick 	 */
17445750Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq,
17545750Smckusick 			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
17649304Shibler 		goto failed;
17741480Smckusick 	switch (inqbuf.type) {
17841480Smckusick 	case 0:		/* disk */
17941480Smckusick 	case 4:		/* WORM */
18041480Smckusick 	case 5:		/* CD-ROM */
18141480Smckusick 	case 7:		/* Magneto-optical */
18241480Smckusick 		break;
18341480Smckusick 	default:	/* not a disk */
18449304Shibler 		goto failed;
18541480Smckusick 	}
18645750Smckusick 	/*
18749304Shibler 	 * Get a usable id string
18845750Smckusick 	 */
18957327Shibler 	switch (inqbuf.version) {
19057327Shibler 	case 1:
19157327Shibler 	case 2:
19249304Shibler 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
19349304Shibler 		for (i = 27; i > 23; --i)
19449304Shibler 			if (idstr[i] != ' ')
19549304Shibler 				break;
19649304Shibler 		idstr[i+1] = 0;
19749304Shibler 		for (i = 23; i > 7; --i)
19849304Shibler 			if (idstr[i] != ' ')
19949304Shibler 				break;
20049304Shibler 		idstr[i+1] = 0;
20149304Shibler 		for (i = 7; i >= 0; --i)
20249304Shibler 			if (idstr[i] != ' ')
20349304Shibler 				break;
20449304Shibler 		idstr[i+1] = 0;
20557327Shibler 		break;
20657327Shibler 	default:
20757327Shibler 		bcopy("UNKNOWN", &idstr[0], 8);
20857327Shibler 		bcopy("DRIVE TYPE", &idstr[8], 11);
20945750Smckusick 	}
21065662Shibler 	if (inqbuf.qual & 0x80)
21165662Shibler 		sc->sc_flags |= SDF_RMEDIA;
21245750Smckusick 
21365662Shibler 	if (sdgetcapacity(sc, hd, NODEV) < 0)
21465662Shibler 		goto failed;
21565662Shibler 
21657327Shibler 	switch (inqbuf.version) {
21757327Shibler 	case 1:
21857327Shibler 	case 2:
21941480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
22041480Smckusick 			&idstr[24]);
22157327Shibler 		if (inqbuf.version == 2)
22257327Shibler 			printf(" (SCSI-2)");
22357327Shibler 		break;
22457327Shibler 	default:
22557327Shibler 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
22657327Shibler 		       inqbuf.type, inqbuf.qual, inqbuf.version);
22757327Shibler 		break;
22857327Shibler 	}
22965662Shibler 	if (sc->sc_blks)
23065662Shibler 		printf(", %d %d byte blocks",
23165662Shibler 		       sc->sc_blks >> sc->sc_bshift, sc->sc_blksize);
23265662Shibler 	printf("\n");
23341480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
23449304Shibler 	scsi_delay(0);
23541480Smckusick 	return(inqbuf.type);
23649304Shibler failed:
23749304Shibler 	scsi_delay(0);
23849304Shibler 	return(-1);
23941480Smckusick }
24041480Smckusick 
24141480Smckusick int
24241480Smckusick sdinit(hd)
24341480Smckusick 	register struct hp_device *hd;
24441480Smckusick {
24541480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
24641480Smckusick 
24741480Smckusick 	sc->sc_hd = hd;
24853929Shibler 	sc->sc_flags = 0;
24966072Shibler 	/*
25066072Shibler 	 * XXX formerly 0 meant unused but now pid 0 can legitimately
25166072Shibler 	 * use this interface (sdgetcapacity).
25266072Shibler 	 */
25366072Shibler 	sc->sc_format_pid = -1;
25441480Smckusick 	sc->sc_punit = sdpunit(hd->hp_flags);
25541480Smckusick 	sc->sc_type = sdident(sc, hd);
25641480Smckusick 	if (sc->sc_type < 0)
25741480Smckusick 		return(0);
25841480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
25941480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
26041480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
26141480Smckusick 	sc->sc_dq.dq_driver = &sddriver;
26241480Smckusick 
26353929Shibler 	sc->sc_flags |= SDF_ALIVE;
26441480Smckusick 	return(1);
26541480Smckusick }
26641480Smckusick 
26741480Smckusick void
26841480Smckusick sdreset(sc, hd)
26941480Smckusick 	register struct sd_softc *sc;
27041480Smckusick 	register struct hp_device *hd;
27141480Smckusick {
27241480Smckusick 	sdstats[hd->hp_unit].sdresets++;
27341480Smckusick }
27441480Smckusick 
27557327Shibler /*
27665662Shibler  * Determine capacity of a drive.
27765662Shibler  * Returns -1 on a failure, 0 on success, 1 on a failure that is probably
27865662Shibler  * due to missing media.
27965662Shibler  */
28065662Shibler int
28165662Shibler sdgetcapacity(sc, hd, dev)
28265662Shibler 	struct sd_softc *sc;
28365662Shibler 	struct hp_device *hd;
28465662Shibler 	dev_t dev;
28565662Shibler {
28665662Shibler 	static struct scsi_fmt_cdb cap = {
28765662Shibler 		10,
28865662Shibler 		CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
28965662Shibler 	};
29066072Shibler 	u_char *capbuf;
29166072Shibler 	int i, capbufsize;
29265662Shibler 
29366072Shibler 	/*
29466072Shibler 	 * Cannot use stack space for this buffer since stack KVA may not
29566072Shibler 	 * be valid (i.e. in context of this process) when the operation
29666072Shibler 	 * actually starts.
29766072Shibler 	 */
29866072Shibler 	capbufsize = 8;
29966072Shibler 	capbuf = malloc(capbufsize, M_DEVBUF, M_WAITOK);
30066072Shibler 
30165662Shibler 	if (dev == NODEV) {
30265662Shibler 		i = scsi_immed_command(hd->hp_ctlr, hd->hp_slave, sc->sc_punit,
30366072Shibler 				       &cap, capbuf, capbufsize, B_READ);
30465662Shibler 	} else {
30566072Shibler 		struct buf *bp;
30666072Shibler 
30765662Shibler 		/*
30865662Shibler 		 * XXX this is horrible
30965662Shibler 		 */
31066072Shibler 		if (sc->sc_format_pid >= 0)
31165662Shibler 			panic("sdgetcapacity");
31266072Shibler 		bp = malloc(sizeof *bp, M_DEVBUF, M_WAITOK);
31365662Shibler 		sc->sc_format_pid = curproc->p_pid;
31465662Shibler 		bcopy((caddr_t)&cap, (caddr_t)&sdcmd[hd->hp_unit], sizeof cap);
31566072Shibler 		bp->b_dev = dev;
31666072Shibler 		bp->b_flags = B_READ | B_BUSY;
31766072Shibler 		bp->b_un.b_addr = (caddr_t)capbuf;
31866072Shibler 		bp->b_bcount = capbufsize;
31966072Shibler 		sdstrategy(bp);
32066072Shibler 		i = biowait(bp) ? sdsense[hd->hp_unit].status : 0;
32166072Shibler 		free(bp, M_DEVBUF);
32266072Shibler 		sc->sc_format_pid = -1;
32365662Shibler 	}
32465662Shibler 	if (i) {
32565662Shibler 		if (i != STS_CHECKCOND || (sc->sc_flags & SDF_RMEDIA) == 0) {
32665662Shibler #ifdef DEBUG
32765662Shibler 			if (sddebug & SDB_CAPACITY)
32865662Shibler 				printf("sd%d: read_capacity returns %d\n",
32965662Shibler 				       hd->hp_unit, i);
33065662Shibler #endif
33166072Shibler 			free(capbuf, M_DEVBUF);
33265662Shibler 			return (-1);
33365662Shibler 		}
33465662Shibler 		/*
33565662Shibler 		 * XXX assume unformatted or non-existant media
33665662Shibler 		 */
33765662Shibler 		sc->sc_blks = 0;
33865662Shibler 		sc->sc_blksize = DEV_BSIZE;
33965662Shibler 		sc->sc_bshift = 0;
34065662Shibler #ifdef DEBUG
34165662Shibler 		if (sddebug & SDB_CAPACITY)
34265662Shibler 			printf("sd%d: removable media not present\n",
34365662Shibler 			       hd->hp_unit);
34465662Shibler #endif
34566072Shibler 		free(capbuf, M_DEVBUF);
34665662Shibler 		return (1);
34765662Shibler 	}
34865662Shibler 	sc->sc_blks = *(u_int *)&capbuf[0];
34965662Shibler 	sc->sc_blksize = *(int *)&capbuf[4];
35066072Shibler 	free(capbuf, M_DEVBUF);
35165662Shibler 	sc->sc_bshift = 0;
35265662Shibler 
35365662Shibler 	/* return value of read capacity is last valid block number */
35465662Shibler 	sc->sc_blks++;
35565662Shibler 
35665662Shibler 	if (sc->sc_blksize != DEV_BSIZE) {
35765662Shibler 		if (sc->sc_blksize < DEV_BSIZE) {
35866072Shibler 			printf("sd%d: need at least %d byte blocks - %s\n",
35966072Shibler 				hd->hp_unit, DEV_BSIZE, "drive ignored");
36065662Shibler 			return (-1);
36165662Shibler 		}
36265662Shibler 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
36365662Shibler 			++sc->sc_bshift;
36465662Shibler 		sc->sc_blks <<= sc->sc_bshift;
36565662Shibler 	}
36665662Shibler #ifdef DEBUG
36765662Shibler 	if (sddebug & SDB_CAPACITY)
36865662Shibler 		printf("sd%d: blks=%d, blksize=%d, bshift=%d\n", hd->hp_unit,
36965662Shibler 		       sc->sc_blks, sc->sc_blksize, sc->sc_bshift);
37065662Shibler #endif
37165662Shibler 	return (0);
37265662Shibler }
37365662Shibler 
37465662Shibler /*
37557327Shibler  * Read or constuct a disklabel
37657327Shibler  */
37741480Smckusick int
37857327Shibler sdgetinfo(dev)
37957327Shibler 	dev_t dev;
38057327Shibler {
38157327Shibler 	int unit = sdunit(dev);
38257327Shibler 	register struct sd_softc *sc = &sd_softc[unit];
38357327Shibler 	register struct disklabel *lp = &sc->sc_info.si_label;
38457327Shibler 	register struct partition *pi;
38557327Shibler 	char *msg, *readdisklabel();
38665662Shibler #ifdef COMPAT_NOLABEL
38765662Shibler 	int usedefault = 1;
38857327Shibler 
38957327Shibler 	/*
39065662Shibler 	 * For CD-ROM just define a single partition
39157327Shibler 	 */
39265662Shibler 	if (sc->sc_type == 5)
39365662Shibler 		usedefault = 0;
39465662Shibler #endif
39565662Shibler 
39657327Shibler 	bzero((caddr_t)lp, sizeof *lp);
39765662Shibler 	msg = NULL;
39857327Shibler 
39957327Shibler 	/*
40065662Shibler 	 * If removable media or the size unavailable at boot time
40165662Shibler 	 * (i.e. unformatted hard disk), attempt to set the capacity
40265662Shibler 	 * now.
40357327Shibler 	 */
40465662Shibler 	if ((sc->sc_flags & SDF_RMEDIA) || sc->sc_blks == 0) {
40565662Shibler 		switch (sdgetcapacity(sc, sc->sc_hd, dev)) {
40665662Shibler 		case 0:
40765662Shibler 			break;
40865662Shibler 		case -1:
40965662Shibler 			/*
41065662Shibler 			 * Hard error, just return (open will fail).
41165662Shibler 			 */
41265662Shibler 			return (EIO);
41365662Shibler 		case 1:
41465662Shibler 			/*
41565662Shibler 			 * XXX return 0 so open can continue just in case
41665662Shibler 			 * the media is unformatted and we want to format it.
41765662Shibler 			 * We set the error flag so they cannot do much else.
41865662Shibler 			 */
41965662Shibler 			sc->sc_flags |= SDF_ERROR;
42065662Shibler 			msg = "unformatted/missing media";
42165662Shibler #ifdef COMPAT_NOLABEL
42265662Shibler 			usedefault = 0;
42365662Shibler #endif
42465662Shibler 			break;
42565662Shibler 		}
42665662Shibler 	}
42757327Shibler 
42865662Shibler 	/*
42965662Shibler 	 * Set some default values to use while reading the label
43065662Shibler 	 * (or to use if there isn't a label) and try reading it.
43165662Shibler 	 */
43265662Shibler 	if (msg == NULL) {
43365662Shibler 		lp->d_type = DTYPE_SCSI;
43465662Shibler 		lp->d_secsize = DEV_BSIZE;
43565662Shibler 		lp->d_nsectors = 32;
43665662Shibler 		lp->d_ntracks = 20;
43765662Shibler 		lp->d_ncylinders = 1;
43865662Shibler 		lp->d_secpercyl = 32*20;
43965662Shibler 		lp->d_npartitions = 3;
44065662Shibler 		lp->d_partitions[2].p_offset = 0;
44165662Shibler 		/* XXX we can open a device even without SDF_ALIVE */
44265662Shibler 		if (sc->sc_blksize == 0)
44365662Shibler 			sc->sc_blksize = DEV_BSIZE;
44465662Shibler 		/* XXX ensure size is at least one device block */
44565662Shibler 		lp->d_partitions[2].p_size =
44665662Shibler 			roundup(LABELSECTOR+1, btodb(sc->sc_blksize));
44765662Shibler 		msg = readdisklabel(sdlabdev(dev), sdstrategy, lp);
44865662Shibler 		if (msg == NULL)
44965662Shibler 			return (0);
45065662Shibler 	}
45165662Shibler 
45257327Shibler 	pi = lp->d_partitions;
45357327Shibler 	printf("sd%d: WARNING: %s, ", unit, msg);
45457327Shibler #ifdef COMPAT_NOLABEL
45565662Shibler 	if (usedefault) {
45665662Shibler 		printf("using old default partitioning\n");
45765662Shibler 		sdmakedisklabel(unit, lp);
45865662Shibler 		return(0);
45965662Shibler 	}
46065662Shibler #endif
46157327Shibler 	printf("defining `c' partition as entire disk\n");
46257327Shibler 	pi[2].p_size = sc->sc_blks;
463*67184Shibler 	/* XXX reset other info since readdisklabel screws with it */
464*67184Shibler 	lp->d_npartitions = 3;
465*67184Shibler 	pi[0].p_size = 0;
46657327Shibler 	return(0);
46757327Shibler }
46857327Shibler 
46957327Shibler int
47049132Skarels sdopen(dev, flags, mode, p)
47141480Smckusick 	dev_t dev;
47249132Skarels 	int flags, mode;
47349132Skarels 	struct proc *p;
47441480Smckusick {
47541480Smckusick 	register int unit = sdunit(dev);
47641480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
47757327Shibler 	int mask, error;
47841480Smckusick 
47941480Smckusick 	if (unit >= NSD)
48041480Smckusick 		return(ENXIO);
48167054Shibler 	/*
48267054Shibler 	 * If a drive's position was fully qualified (i.e. not wildcarded in
48367054Shibler 	 * any way, we allow root to open the device even though it wasn't
48467054Shibler 	 * found at autoconfig time.  This allows initial formatting of disks.
48567054Shibler 	 * However, if any part of the specification was wildcarded, we won't
48667054Shibler 	 * be able to locate the drive so there is nothing we can do.
48767054Shibler 	 */
48867054Shibler 	if ((sc->sc_flags & SDF_ALIVE) == 0 &&
48967054Shibler 	    (suser(p->p_ucred, &p->p_acflag) ||
49067054Shibler 	     sc->sc_hd->hp_ctlr < 0 || sc->sc_hd->hp_slave < 0))
49141480Smckusick 		return(ENXIO);
49257327Shibler 	if (sc->sc_flags & SDF_ERROR)
49357327Shibler 		return(EIO);
49441480Smckusick 
49557327Shibler 	/*
49657327Shibler 	 * Wait for any pending opens/closes to complete
49757327Shibler 	 */
49857327Shibler 	while (sc->sc_flags & (SDF_OPENING|SDF_CLOSING))
49957327Shibler 		sleep((caddr_t)sc, PRIBIO);
50057327Shibler 	/*
50157327Shibler 	 * On first open, get label and partition info.
50257327Shibler 	 * We may block reading the label, so be careful
50357327Shibler 	 * to stop any other opens.
50457327Shibler 	 */
50557327Shibler 	if (sc->sc_info.si_open == 0) {
50657327Shibler 		sc->sc_flags |= SDF_OPENING;
50757327Shibler 		error = sdgetinfo(dev);
50857327Shibler 		sc->sc_flags &= ~SDF_OPENING;
50957327Shibler 		wakeup((caddr_t)sc);
51057327Shibler 		if (error)
51157327Shibler 			return(error);
51257327Shibler 	}
51341480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
51441480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
51557327Shibler 
51657327Shibler 	mask = 1 << sdpart(dev);
51757327Shibler 	if (mode == S_IFCHR)
51857327Shibler 		sc->sc_info.si_copen |= mask;
51957327Shibler 	else
52057327Shibler 		sc->sc_info.si_bopen |= mask;
52157327Shibler 	sc->sc_info.si_open |= mask;
52241480Smckusick 	return(0);
52341480Smckusick }
52441480Smckusick 
52553929Shibler int
52653929Shibler sdclose(dev, flag, mode, p)
52753929Shibler 	dev_t dev;
52853929Shibler 	int flag, mode;
52953929Shibler 	struct proc *p;
53053929Shibler {
53153929Shibler 	int unit = sdunit(dev);
53253929Shibler 	register struct sd_softc *sc = &sd_softc[unit];
53357327Shibler 	register struct sdinfo *si = &sc->sc_info;
53457327Shibler 	int mask, s;
53553929Shibler 
53657327Shibler 	mask = 1 << sdpart(dev);
53757327Shibler 	if (mode == S_IFCHR)
53857327Shibler 		si->si_copen &= ~mask;
53957327Shibler 	else
54057327Shibler 		si->si_bopen &= ~mask;
54157327Shibler 	si->si_open = si->si_bopen | si->si_copen;
54253929Shibler 	/*
54357327Shibler 	 * On last close, we wait for all activity to cease since
54457327Shibler 	 * the label/parition info will become invalid.  Since we
54557327Shibler 	 * might sleep, we must block any opens while we are here.
54657327Shibler 	 * Note we don't have to about other closes since we know
54757327Shibler 	 * we are the last one.
54853929Shibler 	 */
54957327Shibler 	if (si->si_open == 0) {
55057327Shibler 		sc->sc_flags |= SDF_CLOSING;
55153929Shibler 		s = splbio();
55253929Shibler 		while (sdtab[unit].b_active) {
55353929Shibler 			sc->sc_flags |= SDF_WANTED;
55453929Shibler 			sleep((caddr_t)&sdtab[unit], PRIBIO);
55553929Shibler 		}
55653929Shibler 		splx(s);
55757327Shibler 		sc->sc_flags &= ~(SDF_CLOSING|SDF_WLABEL|SDF_ERROR);
55857327Shibler 		wakeup((caddr_t)sc);
55953929Shibler 	}
56066072Shibler 	sc->sc_format_pid = -1;
56157327Shibler 	return(0);
56253929Shibler }
56353929Shibler 
56441480Smckusick /*
56541480Smckusick  * This routine is called for partial block transfers and non-aligned
56641480Smckusick  * transfers (the latter only being possible on devices with a block size
56741480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
56841480Smckusick  * using a locally allocated buffer:
56941480Smckusick  *	1. transfer any initial partial block
57041480Smckusick  *	2. transfer full blocks
57141480Smckusick  *	3. transfer any final partial block
57241480Smckusick  */
57341480Smckusick static void
57441480Smckusick sdlblkstrat(bp, bsize)
57541480Smckusick 	register struct buf *bp;
57641480Smckusick 	register int bsize;
57741480Smckusick {
57841480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
57941480Smckusick 							M_DEVBUF, M_WAITOK);
58041480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
58141480Smckusick 	register int bn, resid;
58241480Smckusick 	register caddr_t addr;
58341480Smckusick 
58441480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
58549132Skarels 	cbp->b_proc = curproc;		/* XXX */
58641480Smckusick 	cbp->b_dev = bp->b_dev;
58741480Smckusick 	bn = bp->b_blkno;
58841480Smckusick 	resid = bp->b_bcount;
58941480Smckusick 	addr = bp->b_un.b_addr;
59041480Smckusick #ifdef DEBUG
59141480Smckusick 	if (sddebug & SDB_PARTIAL)
59241480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
59341480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
59441480Smckusick #endif
59541480Smckusick 
59641480Smckusick 	while (resid > 0) {
59741480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
59841480Smckusick 		register int count;
59941480Smckusick 
60041480Smckusick 		if (boff || resid < bsize) {
60141480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
60255068Spendry 			count = min(resid, bsize - boff);
60341480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
60441480Smckusick 			cbp->b_blkno = bn - btodb(boff);
60541480Smckusick 			cbp->b_un.b_addr = cbuf;
60641480Smckusick 			cbp->b_bcount = bsize;
60741480Smckusick #ifdef DEBUG
60841480Smckusick 			if (sddebug & SDB_PARTIAL)
60941480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
61041480Smckusick 				       cbp->b_blkno, count, boff, addr);
61141480Smckusick #endif
61241480Smckusick 			sdstrategy(cbp);
61341480Smckusick 			biowait(cbp);
61441480Smckusick 			if (cbp->b_flags & B_ERROR) {
61541480Smckusick 				bp->b_flags |= B_ERROR;
61641480Smckusick 				bp->b_error = cbp->b_error;
61741480Smckusick 				break;
61841480Smckusick 			}
61941480Smckusick 			if (bp->b_flags & B_READ) {
62041480Smckusick 				bcopy(&cbuf[boff], addr, count);
62141480Smckusick 				goto done;
62241480Smckusick 			}
62341480Smckusick 			bcopy(addr, &cbuf[boff], count);
62441480Smckusick #ifdef DEBUG
62541480Smckusick 			if (sddebug & SDB_PARTIAL)
62641480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
62741480Smckusick 				       cbp->b_blkno, count, boff, addr);
62841480Smckusick #endif
62941480Smckusick 		} else {
63041480Smckusick 			count = resid & ~(bsize - 1);
63141480Smckusick 			cbp->b_blkno = bn;
63241480Smckusick 			cbp->b_un.b_addr = addr;
63341480Smckusick 			cbp->b_bcount = count;
63441480Smckusick #ifdef DEBUG
63541480Smckusick 			if (sddebug & SDB_PARTIAL)
63641480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
63741480Smckusick 				       cbp->b_blkno, count, addr);
63841480Smckusick #endif
63941480Smckusick 		}
64041480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
64141480Smckusick 		sdstrategy(cbp);
64241480Smckusick 		biowait(cbp);
64341480Smckusick 		if (cbp->b_flags & B_ERROR) {
64441480Smckusick 			bp->b_flags |= B_ERROR;
64541480Smckusick 			bp->b_error = cbp->b_error;
64641480Smckusick 			break;
64741480Smckusick 		}
64841480Smckusick done:
64941480Smckusick 		bn += btodb(count);
65041480Smckusick 		resid -= count;
65141480Smckusick 		addr += count;
65241480Smckusick #ifdef DEBUG
65341480Smckusick 		if (sddebug & SDB_PARTIAL)
65441480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
65541480Smckusick 			       bn, resid, addr);
65641480Smckusick #endif
65741480Smckusick 	}
65841480Smckusick 	free(cbuf, M_DEVBUF);
65941480Smckusick 	free(cbp, M_DEVBUF);
66041480Smckusick }
66141480Smckusick 
66241480Smckusick void
66341480Smckusick sdstrategy(bp)
66441480Smckusick 	register struct buf *bp;
66541480Smckusick {
66657327Shibler 	int unit = sdunit(bp->b_dev);
66741480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
66841480Smckusick 	register struct buf *dp = &sdtab[unit];
66957327Shibler 	register struct partition *pinfo;
67045750Smckusick 	register daddr_t bn;
67145750Smckusick 	register int sz, s;
67241480Smckusick 
67366072Shibler 	if (sc->sc_format_pid >= 0) {
67449132Skarels 		if (sc->sc_format_pid != curproc->p_pid) {	/* XXX */
67541480Smckusick 			bp->b_error = EPERM;
67657327Shibler 			goto bad;
67741480Smckusick 		}
67841480Smckusick 		bp->b_cylin = 0;
67941480Smckusick 	} else {
68065662Shibler 		if (sc->sc_flags & SDF_ERROR) {
68165662Shibler 			bp->b_error = EIO;
68265662Shibler 			goto bad;
68365662Shibler 		}
68441480Smckusick 		bn = bp->b_blkno;
68545750Smckusick 		sz = howmany(bp->b_bcount, DEV_BSIZE);
68657327Shibler 		pinfo = &sc->sc_info.si_label.d_partitions[sdpart(bp->b_dev)];
68757327Shibler 		if (bn < 0 || bn + sz > pinfo->p_size) {
68857327Shibler 			sz = pinfo->p_size - bn;
68945750Smckusick 			if (sz == 0) {
69041480Smckusick 				bp->b_resid = bp->b_bcount;
69141480Smckusick 				goto done;
69241480Smckusick 			}
69345750Smckusick 			if (sz < 0) {
69445750Smckusick 				bp->b_error = EINVAL;
69557327Shibler 				goto bad;
69645750Smckusick 			}
69745750Smckusick 			bp->b_bcount = dbtob(sz);
69841480Smckusick 		}
69941480Smckusick 		/*
70057327Shibler 		 * Check for write to write protected label
70157327Shibler 		 */
70257327Shibler 		if (bn + pinfo->p_offset <= LABELSECTOR &&
70357327Shibler #if LABELSECTOR != 0
70457327Shibler 		    bn + pinfo->p_offset + sz > LABELSECTOR &&
70557327Shibler #endif
70657327Shibler 		    !(bp->b_flags & B_READ) && !(sc->sc_flags & SDF_WLABEL)) {
70757327Shibler 			bp->b_error = EROFS;
70857327Shibler 			goto bad;
70957327Shibler 		}
71057327Shibler 		/*
71141480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
71241480Smckusick 		 */
71341480Smckusick 		s = sc->sc_blksize - 1;
71441480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
71541480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
71641480Smckusick 			goto done;
71741480Smckusick 		}
71857327Shibler 		bp->b_cylin = (bn + pinfo->p_offset) >> sc->sc_bshift;
71941480Smckusick 	}
72041480Smckusick 	s = splbio();
72141480Smckusick 	disksort(dp, bp);
72241480Smckusick 	if (dp->b_active == 0) {
72341480Smckusick 		dp->b_active = 1;
72441480Smckusick 		sdustart(unit);
72541480Smckusick 	}
72641480Smckusick 	splx(s);
72741480Smckusick 	return;
72857327Shibler bad:
72957327Shibler 	bp->b_flags |= B_ERROR;
73041480Smckusick done:
73145750Smckusick 	biodone(bp);
73241480Smckusick }
73341480Smckusick 
73441480Smckusick void
73541480Smckusick sdustart(unit)
73641480Smckusick 	register int unit;
73741480Smckusick {
73841480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
73941480Smckusick 		sdstart(unit);
74041480Smckusick }
74141480Smckusick 
74250039Skarels /*
74350039Skarels  * Return:
74450039Skarels  *	0	if not really an error
74550039Skarels  *	<0	if we should do a retry
74650039Skarels  *	>0	if a fatal error
74750039Skarels  */
74845750Smckusick static int
74941480Smckusick sderror(unit, sc, hp, stat)
75041480Smckusick 	int unit, stat;
75141480Smckusick 	register struct sd_softc *sc;
75241480Smckusick 	register struct hp_device *hp;
75341480Smckusick {
75450039Skarels 	int cond = 1;
75545750Smckusick 
75641480Smckusick 	sdsense[unit].status = stat;
75741480Smckusick 	if (stat & STS_CHECKCOND) {
75841480Smckusick 		struct scsi_xsense *sp;
75941480Smckusick 
76041480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
76141480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
76241480Smckusick 				   sizeof(sdsense[unit].sense));
76341480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
76441480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
76541480Smckusick 			sp->class, sp->code);
76641480Smckusick 		if (sp->class == 7) {
76741480Smckusick 			printf(", key %d", sp->key);
76841480Smckusick 			if (sp->valid)
76941480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
77050039Skarels 			switch (sp->key) {
77150039Skarels 			/* no sense, try again */
77250039Skarels 			case 0:
77350039Skarels 				cond = -1;
77450039Skarels 				break;
77550039Skarels 			/* recovered error, not a problem */
77650039Skarels 			case 1:
77750039Skarels 				cond = 0;
77850039Skarels 				break;
77957327Shibler 			/* possible media change */
78057327Shibler 			case 6:
78157327Shibler 				/*
78257327Shibler 				 * For removable media, if we are doing the
78357327Shibler 				 * first open (i.e. reading the label) go
78457327Shibler 				 * ahead and retry, otherwise someone has
78557327Shibler 				 * changed the media out from under us and
78657327Shibler 				 * we should abort any further operations
78757327Shibler 				 * until a close is done.
78857327Shibler 				 */
78957327Shibler 				if (sc->sc_flags & SDF_RMEDIA) {
79057327Shibler 					if (sc->sc_flags & SDF_OPENING)
79157327Shibler 						cond = -1;
79257327Shibler 					else
79357327Shibler 						sc->sc_flags |= SDF_ERROR;
79457327Shibler 				}
79557327Shibler 				break;
79650039Skarels 			}
79741480Smckusick 		}
79841480Smckusick 		printf("\n");
79941480Smckusick 	}
80050039Skarels 	return(cond);
80141480Smckusick }
80241480Smckusick 
80341480Smckusick static void
80441480Smckusick sdfinish(unit, sc, bp)
80541480Smckusick 	int unit;
80641480Smckusick 	register struct sd_softc *sc;
80741480Smckusick 	register struct buf *bp;
80841480Smckusick {
80953929Shibler 	register struct buf *dp = &sdtab[unit];
81053929Shibler 
81153929Shibler 	dp->b_errcnt = 0;
81253929Shibler 	dp->b_actf = bp->b_actf;
81341480Smckusick 	bp->b_resid = 0;
81445750Smckusick 	biodone(bp);
81541480Smckusick 	scsifree(&sc->sc_dq);
81653929Shibler 	if (dp->b_actf)
81741480Smckusick 		sdustart(unit);
81853929Shibler 	else {
81953929Shibler 		dp->b_active = 0;
82053929Shibler 		if (sc->sc_flags & SDF_WANTED) {
82153929Shibler 			sc->sc_flags &= ~SDF_WANTED;
82253929Shibler 			wakeup((caddr_t)dp);
82353929Shibler 		}
82453929Shibler 	}
82541480Smckusick }
82641480Smckusick 
82741480Smckusick void
82841480Smckusick sdstart(unit)
82941480Smckusick 	register int unit;
83041480Smckusick {
83141480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
83241480Smckusick 	register struct hp_device *hp = sc->sc_hd;
83341480Smckusick 
83441480Smckusick 	/*
83541480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
83641480Smckusick 	 * so check now.
83741480Smckusick 	 */
83866072Shibler 	if (sc->sc_format_pid >= 0 && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
83941480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
84041480Smckusick 		register int sts;
84141480Smckusick 
84265662Shibler 		sdtab[unit].b_errcnt = 0;
84365662Shibler 		while (1) {
84465662Shibler 			sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
84565662Shibler 						 sc->sc_punit, &sdcmd[unit],
84665662Shibler 						 bp->b_un.b_addr, bp->b_bcount,
84765662Shibler 						 bp->b_flags & B_READ);
84865662Shibler 			sdsense[unit].status = sts;
84965662Shibler 			if ((sts & 0xfe) == 0 ||
85065662Shibler 			    (sts = sderror(unit, sc, hp, sts)) == 0)
85165662Shibler 				break;
85265662Shibler 			if (sts > 0 || sdtab[unit].b_errcnt++ >= SDRETRY) {
85365662Shibler 				bp->b_flags |= B_ERROR;
85465662Shibler 				bp->b_error = EIO;
85565662Shibler 				break;
85665662Shibler 			}
85741480Smckusick 		}
85841480Smckusick 		sdfinish(unit, sc, bp);
85941480Smckusick 
86041480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
86141480Smckusick 		sdgo(unit);
86241480Smckusick }
86341480Smckusick 
86441480Smckusick void
86541480Smckusick sdgo(unit)
86641480Smckusick 	register int unit;
86741480Smckusick {
86841480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
86941480Smckusick 	register struct hp_device *hp = sc->sc_hd;
87041480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
87141480Smckusick 	register int pad;
87241480Smckusick 	register struct scsi_fmt_cdb *cmd;
87341480Smckusick 
87466072Shibler 	if (sc->sc_format_pid >= 0) {
87541480Smckusick 		cmd = &sdcmd[unit];
87641480Smckusick 		pad = 0;
87741480Smckusick 	} else {
87865662Shibler 		/*
87965662Shibler 		 * Drive is in an error state, abort all operations
88065662Shibler 		 */
88165662Shibler 		if (sc->sc_flags & SDF_ERROR) {
88265662Shibler 			bp->b_flags |= B_ERROR;
88365662Shibler 			bp->b_error = EIO;
88465662Shibler 			sdfinish(unit, sc, bp);
88565662Shibler 			return;
88665662Shibler 		}
88741480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
88841480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
88941480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
89041480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
89141480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
89241480Smckusick #ifdef DEBUG
89341480Smckusick 		if (pad)
89441480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
89541480Smckusick 			       unit, bp->b_bcount);
89641480Smckusick #endif
89741480Smckusick 		sdstats[unit].sdtransfers++;
89841480Smckusick 	}
89957327Shibler #ifdef USELEDS
90057327Shibler 	if (inledcontrol == 0)
90157327Shibler 		ledcontrol(0, 0, LED_DISK);
90257327Shibler #endif
90341480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
90441480Smckusick 		if (hp->hp_dk >= 0) {
90541480Smckusick 			dk_busy |= 1 << hp->hp_dk;
90641480Smckusick 			++dk_seek[hp->hp_dk];
90741480Smckusick 			++dk_xfer[hp->hp_dk];
90841480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
90941480Smckusick 		}
91041480Smckusick 		return;
91141480Smckusick 	}
91241480Smckusick #ifdef DEBUG
91341480Smckusick 	if (sddebug & SDB_ERROR)
91441480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
91541480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
91641480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
91741480Smckusick 		       sdtab[unit].b_errcnt);
91841480Smckusick #endif
91941480Smckusick 	bp->b_flags |= B_ERROR;
92041480Smckusick 	bp->b_error = EIO;
92141480Smckusick 	sdfinish(unit, sc, bp);
92241480Smckusick }
92341480Smckusick 
92441480Smckusick void
92541480Smckusick sdintr(unit, stat)
92641480Smckusick 	register int unit;
92741480Smckusick 	int stat;
92841480Smckusick {
92941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
93041480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
93141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
93250039Skarels 	int cond;
93341480Smckusick 
93441480Smckusick 	if (bp == NULL) {
93541480Smckusick 		printf("sd%d: bp == NULL\n", unit);
93641480Smckusick 		return;
93741480Smckusick 	}
93841480Smckusick 	if (hp->hp_dk >= 0)
93941480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
94041480Smckusick 	if (stat) {
94141480Smckusick #ifdef DEBUG
94241480Smckusick 		if (sddebug & SDB_ERROR)
94341480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
94441480Smckusick 				unit, stat);
94541480Smckusick #endif
94650039Skarels 		cond = sderror(unit, sc, hp, stat);
94750039Skarels 		if (cond) {
94850039Skarels 			if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
94950038Skarels #ifdef DEBUG
95050039Skarels 				if (sddebug & SDB_ERROR)
95150039Skarels 					printf("sd%d: retry #%d\n",
95250039Skarels 					       unit, sdtab[unit].b_errcnt);
95350038Skarels #endif
95450039Skarels 				sdstart(unit);
95550039Skarels 				return;
95650039Skarels 			}
95750039Skarels 			bp->b_flags |= B_ERROR;
95850039Skarels 			bp->b_error = EIO;
95945750Smckusick 		}
96041480Smckusick 	}
96141480Smckusick 	sdfinish(unit, sc, bp);
96241480Smckusick }
96341480Smckusick 
96441480Smckusick int
96549132Skarels sdread(dev, uio, flags)
96641480Smckusick 	dev_t dev;
96741480Smckusick 	struct uio *uio;
96849132Skarels 	int flags;
96941480Smckusick {
97041480Smckusick 	register int unit = sdunit(dev);
97141480Smckusick 	register int pid;
97241480Smckusick 
97366072Shibler 	if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
97449132Skarels 	    pid != uio->uio_procp->p_pid)
97541480Smckusick 		return (EPERM);
97641480Smckusick 
97749132Skarels 	return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
97841480Smckusick }
97941480Smckusick 
98041480Smckusick int
98149132Skarels sdwrite(dev, uio, flags)
98241480Smckusick 	dev_t dev;
98341480Smckusick 	struct uio *uio;
98449132Skarels 	int flags;
98541480Smckusick {
98641480Smckusick 	register int unit = sdunit(dev);
98741480Smckusick 	register int pid;
98841480Smckusick 
98966072Shibler 	if ((pid = sd_softc[unit].sc_format_pid) >= 0 &&
99049132Skarels 	    pid != uio->uio_procp->p_pid)
99141480Smckusick 		return (EPERM);
99241480Smckusick 
99349132Skarels 	return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
99441480Smckusick }
99541480Smckusick 
99641480Smckusick int
99749132Skarels sdioctl(dev, cmd, data, flag, p)
99841480Smckusick 	dev_t dev;
99941480Smckusick 	int cmd;
100041480Smckusick 	caddr_t data;
100141480Smckusick 	int flag;
100249132Skarels 	struct proc *p;
100341480Smckusick {
100457327Shibler 	int unit = sdunit(dev);
100541480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
100657327Shibler 	register struct disklabel *lp = &sc->sc_info.si_label;
100757327Shibler 	int error, flags;
100841480Smckusick 
100941480Smckusick 	switch (cmd) {
101041480Smckusick 	default:
101141480Smckusick 		return (EINVAL);
101241480Smckusick 
101357327Shibler 	case DIOCGDINFO:
101457327Shibler 		*(struct disklabel *)data = *lp;
101557327Shibler 		return (0);
101657327Shibler 
101757327Shibler 	case DIOCGPART:
101857327Shibler 		((struct partinfo *)data)->disklab = lp;
101957327Shibler 		((struct partinfo *)data)->part =
102057327Shibler 			&lp->d_partitions[sdpart(dev)];
102157327Shibler 		return (0);
102257327Shibler 
102357327Shibler         case DIOCWLABEL:
102457327Shibler                 if ((flag & FWRITE) == 0)
102557327Shibler                         return (EBADF);
102657327Shibler 		if (*(int *)data)
102757327Shibler 			sc->sc_flags |= SDF_WLABEL;
102857327Shibler 		else
102957327Shibler 			sc->sc_flags &= ~SDF_WLABEL;
103057327Shibler 		return (0);
103157327Shibler 
103257327Shibler         case DIOCSDINFO:
103357327Shibler                 if ((flag & FWRITE) == 0)
103457327Shibler                         return (EBADF);
103557327Shibler 		error = setdisklabel(lp, (struct disklabel *)data,
103657327Shibler 				     (sc->sc_flags & SDF_WLABEL) ? 0
103757327Shibler 				     : sc->sc_info.si_open);
103857327Shibler 		return (error);
103957327Shibler 
104057327Shibler         case DIOCWDINFO:
104157327Shibler 		if ((flag & FWRITE) == 0)
104257327Shibler 			return (EBADF);
104357327Shibler 		error = setdisklabel(lp, (struct disklabel *)data,
104457327Shibler 				     (sc->sc_flags & SDF_WLABEL) ? 0
104557327Shibler 				     : sc->sc_info.si_open);
104657327Shibler 		if (error)
104757327Shibler 			return (error);
104857327Shibler 		flags = sc->sc_flags;
104957327Shibler 		sc->sc_flags = SDF_ALIVE | SDF_WLABEL;
105057327Shibler 		error = writedisklabel(sdlabdev(dev), sdstrategy, lp);
105157327Shibler 		sc->sc_flags = flags;
105257327Shibler 		return (error);
105357327Shibler 
105441480Smckusick 	case SDIOCSFORMAT:
105541480Smckusick 		/* take this device into or out of "format" mode */
105649132Skarels 		if (suser(p->p_ucred, &p->p_acflag))
105741480Smckusick 			return(EPERM);
105841480Smckusick 
105941480Smckusick 		if (*(int *)data) {
106066072Shibler 			if (sc->sc_format_pid >= 0)
106141480Smckusick 				return (EPERM);
106249132Skarels 			sc->sc_format_pid = p->p_pid;
106341480Smckusick 		} else
106466072Shibler 			sc->sc_format_pid = -1;
106541480Smckusick 		return (0);
106641480Smckusick 
106741480Smckusick 	case SDIOCGFORMAT:
106841480Smckusick 		/* find out who has the device in format mode */
106941480Smckusick 		*(int *)data = sc->sc_format_pid;
107041480Smckusick 		return (0);
107141480Smckusick 
107241480Smckusick 	case SDIOCSCSICOMMAND:
107341480Smckusick 		/*
107441480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
107541480Smckusick 		 * read or write to the char device.
107641480Smckusick 		 */
107749132Skarels 		if (sc->sc_format_pid != p->p_pid)
107841480Smckusick 			return (EPERM);
107941480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
108041480Smckusick 			return (EINVAL);
108141480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
108241480Smckusick 		return (0);
108341480Smckusick 
108441480Smckusick 	case SDIOCSENSE:
108541480Smckusick 		/*
108641480Smckusick 		 * return the SCSI sense data saved after the last
108741480Smckusick 		 * operation that completed with "check condition" status.
108841480Smckusick 		 */
108941480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
109041480Smckusick 		return (0);
109141480Smckusick 
109241480Smckusick 	}
109341480Smckusick 	/*NOTREACHED*/
109441480Smckusick }
109541480Smckusick 
109641480Smckusick int
109741480Smckusick sdsize(dev)
109841480Smckusick 	dev_t dev;
109941480Smckusick {
110041480Smckusick 	register int unit = sdunit(dev);
110141480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
110257327Shibler 	int psize, didopen = 0;
110341480Smckusick 
110441480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
110541480Smckusick 		return(-1);
110641480Smckusick 
110757327Shibler 	/*
110857327Shibler 	 * We get called very early on (via swapconf)
110957327Shibler 	 * without the device being open so we may need
111057327Shibler 	 * to handle it here.
111157327Shibler 	 */
111257327Shibler 	if (sc->sc_info.si_open == 0) {
111357327Shibler 		if (sdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
111457327Shibler 			return(-1);
111557327Shibler 		didopen = 1;
111657327Shibler 	}
111757327Shibler 	psize = sc->sc_info.si_label.d_partitions[sdpart(dev)].p_size;
111857327Shibler 	if (didopen)
111957327Shibler 		(void) sdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
112057327Shibler 	return (psize);
112141480Smckusick }
112241480Smckusick 
112341480Smckusick /*
112441480Smckusick  * Non-interrupt driven, non-dma dump routine.
112541480Smckusick  */
112641480Smckusick int
112741480Smckusick sddump(dev)
112841480Smckusick 	dev_t dev;
112941480Smckusick {
113041480Smckusick 	int part = sdpart(dev);
113141480Smckusick 	int unit = sdunit(dev);
113241480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
113341480Smckusick 	register struct hp_device *hp = sc->sc_hd;
113457327Shibler 	register struct partition *pinfo;
113541480Smckusick 	register daddr_t baddr;
113641480Smckusick 	register int maddr;
113741480Smckusick 	register int pages, i;
113841480Smckusick 	int stat;
113966072Shibler 	extern int lowram, dumpsize;
114041480Smckusick 
114141480Smckusick 	/* is drive ok? */
114241480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
114341480Smckusick 		return (ENXIO);
114457327Shibler 	pinfo = &sc->sc_info.si_label.d_partitions[part];
114541480Smckusick 	/* dump parameters in range? */
114657327Shibler 	if (dumplo < 0 || dumplo >= pinfo->p_size ||
114757327Shibler 	    pinfo->p_fstype != FS_SWAP)
114841480Smckusick 		return (EINVAL);
114966072Shibler 	pages = dumpsize;
115057327Shibler 	if (dumplo + ctod(pages) > pinfo->p_size)
115157327Shibler 		pages = dtoc(pinfo->p_size - dumplo);
115241480Smckusick 	maddr = lowram;
115357327Shibler 	baddr = dumplo + pinfo->p_offset;
115441480Smckusick 	/* scsi bus idle? */
115541480Smckusick 	if (!scsireq(&sc->sc_dq)) {
115641480Smckusick 		scsireset(hp->hp_ctlr);
115741480Smckusick 		sdreset(sc, sc->sc_hd);
115841480Smckusick 		printf("[ drive %d reset ] ", unit);
115941480Smckusick 	}
116041480Smckusick 	for (i = 0; i < pages; i++) {
116141480Smckusick #define NPGMB	(1024*1024/NBPG)
116241480Smckusick 		/* print out how many Mbs we have dumped */
116341480Smckusick 		if (i && (i % NPGMB) == 0)
116441480Smckusick 			printf("%d ", i / NPGMB);
116541480Smckusick #undef NPBMG
116652614Smckusick 		pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
116751576Smckusick 		    VM_PROT_READ, TRUE);
116841480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
116941480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
117041480Smckusick 		if (stat) {
117141480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
117241480Smckusick 			return (EIO);
117341480Smckusick 		}
117441480Smckusick 		maddr += NBPG;
117541480Smckusick 		baddr += ctod(1);
117641480Smckusick 	}
117741480Smckusick 	return (0);
117841480Smckusick }
117941480Smckusick #endif
1180