xref: /csrg-svn/sys/hp300/dev/sd.c (revision 49132)
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*49132Skarels  *	@(#)sd.c	7.5 (Berkeley) 05/04/91
1141480Smckusick  */
1241480Smckusick 
1341480Smckusick /*
1441480Smckusick  * SCSI CCS (Command Command Set) disk driver.
1541480Smckusick  */
1641480Smckusick #include "sd.h"
1741480Smckusick #if NSD > 0
1841480Smckusick 
1941480Smckusick #ifndef lint
2045750Smckusick static char rcsid[] = "$Header: sd.c,v 1.3 90/10/10 14:55:10 mike Exp $";
2141480Smckusick #endif
2241480Smckusick 
2345788Sbostic #include "sys/param.h"
2445788Sbostic #include "sys/systm.h"
2545788Sbostic #include "sys/buf.h"
2645788Sbostic #include "sys/dkstat.h"
2745788Sbostic #include "sys/disklabel.h"
2845788Sbostic #include "sys/malloc.h"
2945788Sbostic #include "sys/proc.h"
3041480Smckusick 
31*49132Skarels #include "device.h"
32*49132Skarels #include "scsireg.h"
3345788Sbostic #include "vm/vm_param.h"
34*49132Skarels #include "vm/lock.h"
35*49132Skarels #include "vm/vm_statistics.h"
3645788Sbostic #include "vm/pmap.h"
3745788Sbostic #include "vm/vm_prot.h"
3845750Smckusick 
3941480Smckusick extern int scsi_test_unit_rdy();
4041480Smckusick extern int scsi_request_sense();
4141480Smckusick extern int scsi_inquiry();
4241480Smckusick extern int scsi_read_capacity();
4341480Smckusick extern int scsi_tt_write();
4441480Smckusick extern int scsireq();
4541480Smckusick extern int scsiustart();
4641480Smckusick extern int scsigo();
4741480Smckusick extern void scsifree();
4841480Smckusick extern void scsireset();
4941480Smckusick 
5041480Smckusick extern void disksort();
5141480Smckusick extern void biodone();
5241480Smckusick extern int physio();
5341480Smckusick extern void TBIS();
5441480Smckusick 
5541480Smckusick int	sdinit();
5641480Smckusick void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
5741480Smckusick 
5841480Smckusick struct	driver sddriver = {
5941480Smckusick 	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
6041480Smckusick };
6141480Smckusick 
6241480Smckusick struct	size {
6341480Smckusick 	u_long	strtblk;
6441480Smckusick 	u_long	endblk;
6541480Smckusick 	int	nblocks;
6641480Smckusick };
6741480Smckusick 
6841480Smckusick struct sdinfo {
6941480Smckusick 	struct	size part[8];
7041480Smckusick };
7141480Smckusick 
7241480Smckusick /*
7341480Smckusick  * since the SCSI standard tends to hide the disk structure, we define
7441480Smckusick  * partitions in terms of DEV_BSIZE blocks.  The default partition table
7541480Smckusick  * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
7641480Smckusick  * root and 32 meg of swap.  The rest of the space on the drive goes in
7741480Smckusick  * the G partition.  As usual, the C partition covers the entire disk
7841480Smckusick  * (including the boot area).
7941480Smckusick  */
8041480Smckusick struct sdinfo sddefaultpart = {
8141480Smckusick 	     1024,   17408,   16384   ,	/* A */
8241480Smckusick 	    17408,   82944,   65536   ,	/* B */
8341480Smckusick 	        0,       0,       0   ,	/* C */
8441480Smckusick 	    17408,  115712,   98304   ,	/* D */
8541480Smckusick 	   115712,  218112,  102400   ,	/* E */
8641480Smckusick 	   218112,       0,       0   ,	/* F */
8741480Smckusick 	    82944,       0,       0   ,	/* G */
8841480Smckusick 	   115712,       0,       0   ,	/* H */
8941480Smckusick };
9041480Smckusick 
9141480Smckusick struct	sd_softc {
9241480Smckusick 	struct	hp_device *sc_hd;
9341480Smckusick 	struct	devqueue sc_dq;
9441480Smckusick 	int	sc_format_pid;	/* process using "format" mode */
9541480Smckusick 	short	sc_flags;
9641480Smckusick 	short	sc_type;	/* drive type */
9741480Smckusick 	short	sc_punit;	/* physical unit (scsi lun) */
9841480Smckusick 	u_short	sc_bshift;	/* convert device blocks to DEV_BSIZE blks */
9941480Smckusick 	u_int	sc_blks;	/* number of blocks on device */
10041480Smckusick 	int	sc_blksize;	/* device block size in bytes */
10141480Smckusick 	u_int	sc_wpms;	/* average xfer rate in 16 bit wds/sec. */
10241480Smckusick 	struct	sdinfo sc_info;	/* drive partition table & label info */
10341480Smckusick } sd_softc[NSD];
10441480Smckusick 
10541480Smckusick /* sc_flags values */
10641480Smckusick #define	SDF_ALIVE	0x1
10741480Smckusick 
10841480Smckusick #ifdef DEBUG
10941480Smckusick int sddebug = 1;
11041480Smckusick #define SDB_ERROR	0x01
11141480Smckusick #define SDB_PARTIAL	0x02
11241480Smckusick #endif
11341480Smckusick 
11441480Smckusick struct sdstats {
11541480Smckusick 	long	sdresets;
11641480Smckusick 	long	sdtransfers;
11741480Smckusick 	long	sdpartials;
11841480Smckusick } sdstats[NSD];
11941480Smckusick 
12041480Smckusick struct	buf sdtab[NSD];
12141480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
12241480Smckusick struct	scsi_fmt_sense sdsense[NSD];
12341480Smckusick 
12441480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
12541480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
12641480Smckusick 
127*49132Skarels #define	sdunit(x)	(minor(x) >> 3)
12841480Smckusick #define sdpart(x)	(minor(x) & 0x7)
12941480Smckusick #define	sdpunit(x)	((x) & 7)
13041480Smckusick #define	b_cylin		b_resid
13145750Smckusick 
13241480Smckusick #define	SDRETRY		2
13341480Smckusick 
13441480Smckusick /*
13541480Smckusick  * Table of scsi commands users are allowed to access via "format"
13641480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
13741480Smckusick  * -1 means needs dma and/or wait for intr.
13841480Smckusick  */
13941480Smckusick static char legal_cmds[256] = {
14041480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
14141480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14241480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
14341480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14441480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14541480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14641480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14741480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14841480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14941480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15041480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15141480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15241480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15341480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15441480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15541480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15641480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15741480Smckusick };
15841480Smckusick 
15941480Smckusick static struct scsi_inquiry inqbuf;
16041480Smckusick static struct scsi_fmt_cdb inq = {
16141480Smckusick 	6,
16241480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
16341480Smckusick };
16441480Smckusick 
16541480Smckusick static u_char capbuf[8];
16641480Smckusick struct scsi_fmt_cdb cap = {
16741480Smckusick 	10,
16841480Smckusick 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
16941480Smckusick };
17041480Smckusick 
17141480Smckusick static int
17241480Smckusick sdident(sc, hd)
17341480Smckusick 	struct sd_softc *sc;
17441480Smckusick 	struct hp_device *hd;
17541480Smckusick {
17641480Smckusick 	int unit;
17741480Smckusick 	register int ctlr, slave;
17841480Smckusick 	register int i;
17941480Smckusick 	register int tries = 10;
18045750Smckusick 	int ismo = 0;
18141480Smckusick 
18241480Smckusick 	ctlr = hd->hp_ctlr;
18341480Smckusick 	slave = hd->hp_slave;
18441480Smckusick 	unit = sc->sc_punit;
18541480Smckusick 
18641480Smckusick 	/*
18741480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
18841480Smckusick 	 */
18941480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
19045750Smckusick 		if (i == -1 || --tries < 0) {
19145750Smckusick 			if (ismo)
19245750Smckusick 				break;
19341480Smckusick 			/* doesn't exist or not a CCS device */
19441480Smckusick 			return (-1);
19545750Smckusick 		}
19641480Smckusick 		if (i == STS_CHECKCOND) {
19741480Smckusick 			u_char sensebuf[128];
19841480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
19941480Smckusick 
20041480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
20141480Smckusick 					   sizeof(sensebuf));
20245750Smckusick 			if (sp->class == 7)
20345750Smckusick 				switch (sp->key) {
20445750Smckusick 				/* not ready -- might be MO with no media */
20545750Smckusick 				case 2:
20645750Smckusick 					if (sp->len == 12 &&
20745750Smckusick 					    sensebuf[12] == 10)	/* XXX */
20845750Smckusick 						ismo = 1;
20945750Smckusick 					break;
21041480Smckusick 				/* drive doing an RTZ -- give it a while */
21145750Smckusick 				case 6:
21245750Smckusick 					DELAY(1000000);
21345750Smckusick 					break;
21445750Smckusick 				default:
21545750Smckusick 					break;
21645750Smckusick 				}
21741480Smckusick 		}
21841480Smckusick 		DELAY(1000);
21941480Smckusick 	}
22045750Smckusick 	/*
22145750Smckusick 	 * Find out about device
22245750Smckusick 	 */
22345750Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq,
22445750Smckusick 			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
22545750Smckusick 		return(-1);
22641480Smckusick 	switch (inqbuf.type) {
22741480Smckusick 	case 0:		/* disk */
22841480Smckusick 	case 4:		/* WORM */
22941480Smckusick 	case 5:		/* CD-ROM */
23041480Smckusick 	case 7:		/* Magneto-optical */
23141480Smckusick 		break;
23241480Smckusick 	default:	/* not a disk */
23341480Smckusick 		return (-1);
23441480Smckusick 	}
23545750Smckusick 	/*
23645750Smckusick 	 * XXX determine if this is an HP MO drive.
23745750Smckusick 	 */
23845750Smckusick 	{
23945750Smckusick 		u_long *id = (u_long *)&inqbuf;
24041480Smckusick 
24145750Smckusick 		ismo = (id[2] == 0x48502020 &&	/* "HP  " */
24245750Smckusick 			id[3] == 0x20202020 &&	/* "    " */
24345750Smckusick 			id[4] == 0x53363330 &&	/* "S630" */
24445750Smckusick 			id[5] == 0x302e3635 &&	/* "0.65" */
24545750Smckusick 			id[6] == 0x30412020);	/* "0A  " */
24645750Smckusick 	}
24745750Smckusick 	i = scsi_immed_command(ctlr, slave, unit, &cap,
24845750Smckusick 			       (u_char *)&capbuf, sizeof(capbuf), B_READ);
24945750Smckusick 	if (i) {
25045750Smckusick 		/* XXX unformatted or non-existant MO media; fake it */
25145750Smckusick 		if (i == STS_CHECKCOND && ismo) {
25245750Smckusick 			sc->sc_blks = 318664;
25345750Smckusick 			sc->sc_blksize = 1024;
25445750Smckusick 		} else
25545750Smckusick 			return(-1);
25645750Smckusick 	} else {
25745750Smckusick 		sc->sc_blks = *(u_int *)&capbuf[0];
25845750Smckusick 		sc->sc_blksize = *(int *)&capbuf[4];
25945750Smckusick 	}
26045750Smckusick 	/* return value of read capacity is last valid block number */
26145750Smckusick 	sc->sc_blks++;
26245750Smckusick 
26341480Smckusick 	if (inqbuf.version != 1)
26441480Smckusick 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
26541480Smckusick 			inqbuf.type, inqbuf.qual, inqbuf.version);
26641480Smckusick 	else {
26741480Smckusick 		char idstr[32];
26841480Smckusick 
26941480Smckusick 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
27041480Smckusick 		for (i = 27; i > 23; --i)
27141480Smckusick 			if (idstr[i] != ' ')
27241480Smckusick 				break;
27341480Smckusick 		idstr[i+1] = 0;
27441480Smckusick 		for (i = 23; i > 7; --i)
27541480Smckusick 			if (idstr[i] != ' ')
27641480Smckusick 				break;
27741480Smckusick 		idstr[i+1] = 0;
27841480Smckusick 		for (i = 7; i >= 0; --i)
27941480Smckusick 			if (idstr[i] != ' ')
28041480Smckusick 				break;
28141480Smckusick 		idstr[i+1] = 0;
28241480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
28341480Smckusick 			&idstr[24]);
28441480Smckusick 	}
28541480Smckusick 	printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
28641480Smckusick 	if (sc->sc_blksize != DEV_BSIZE) {
28741480Smckusick 		if (sc->sc_blksize < DEV_BSIZE) {
28841480Smckusick 			printf("sd%d: need %d byte blocks - drive ignored\n",
28941480Smckusick 				unit, DEV_BSIZE);
29041480Smckusick 			return (-1);
29141480Smckusick 		}
29241480Smckusick 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
29341480Smckusick 			++sc->sc_bshift;
29441480Smckusick 		sc->sc_blks <<= sc->sc_bshift;
29541480Smckusick 	}
29641480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
29741480Smckusick 	return(inqbuf.type);
29841480Smckusick }
29941480Smckusick 
30041480Smckusick int
30141480Smckusick sdinit(hd)
30241480Smckusick 	register struct hp_device *hd;
30341480Smckusick {
30441480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
30541480Smckusick 
30641480Smckusick 	sc->sc_hd = hd;
30741480Smckusick 	sc->sc_punit = sdpunit(hd->hp_flags);
30841480Smckusick 	sc->sc_type = sdident(sc, hd);
30941480Smckusick 	if (sc->sc_type < 0)
31041480Smckusick 		return(0);
31141480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
31241480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
31341480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
31441480Smckusick 	sc->sc_dq.dq_driver = &sddriver;
31541480Smckusick 
31641480Smckusick 	/*
31741480Smckusick 	 * If we don't have a disk label, build a default partition
31841480Smckusick 	 * table with 'standard' size root & swap and everything else
31941480Smckusick 	 * in the G partition.
32041480Smckusick 	 */
32141480Smckusick 	sc->sc_info = sddefaultpart;
32241480Smckusick 	/* C gets everything */
32341480Smckusick 	sc->sc_info.part[2].nblocks = sc->sc_blks;
32441480Smckusick 	sc->sc_info.part[2].endblk = sc->sc_blks;
32541480Smckusick 	/* G gets from end of B to end of disk */
32641480Smckusick 	sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk;
32741480Smckusick 	sc->sc_info.part[6].endblk = sc->sc_blks;
32841480Smckusick 	/*
32941480Smckusick 	 * We also define the D, E and F paritions as an alternative to
33041480Smckusick 	 * B and G.  D is 48Mb, starts after A and is intended for swapping.
33141480Smckusick 	 * E is 50Mb, starts after D and is intended for /usr. F starts
33241480Smckusick 	 * after E and is what ever is left.
33341480Smckusick 	 */
33441480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[4].endblk) {
33541480Smckusick 		sc->sc_info.part[5].nblocks =
33641480Smckusick 			sc->sc_blks - sc->sc_info.part[4].endblk;
33741480Smckusick 		sc->sc_info.part[5].endblk = sc->sc_blks;
33841480Smckusick 	} else {
33941480Smckusick 		sc->sc_info.part[5].strtblk = 0;
34041480Smckusick 		sc->sc_info.part[3] = sc->sc_info.part[5];
34141480Smckusick 		sc->sc_info.part[4] = sc->sc_info.part[5];
34241480Smckusick 	}
34341480Smckusick 	/*
34441480Smckusick 	 * H is a single partition alternative to E and F.
34541480Smckusick 	 */
34641480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[3].endblk) {
34741480Smckusick 		sc->sc_info.part[7].nblocks =
34841480Smckusick 			sc->sc_blks - sc->sc_info.part[3].endblk;
34941480Smckusick 		sc->sc_info.part[7].endblk = sc->sc_blks;
35041480Smckusick 	} else {
35141480Smckusick 		sc->sc_info.part[7].strtblk = 0;
35241480Smckusick 	}
35341480Smckusick 
35441480Smckusick 	sc->sc_flags = SDF_ALIVE;
35541480Smckusick 	return(1);
35641480Smckusick }
35741480Smckusick 
35841480Smckusick void
35941480Smckusick sdreset(sc, hd)
36041480Smckusick 	register struct sd_softc *sc;
36141480Smckusick 	register struct hp_device *hd;
36241480Smckusick {
36341480Smckusick 	sdstats[hd->hp_unit].sdresets++;
36441480Smckusick }
36541480Smckusick 
36641480Smckusick int
367*49132Skarels sdopen(dev, flags, mode, p)
36841480Smckusick 	dev_t dev;
369*49132Skarels 	int flags, mode;
370*49132Skarels 	struct proc *p;
37141480Smckusick {
37241480Smckusick 	register int unit = sdunit(dev);
37341480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
37441480Smckusick 
37541480Smckusick 	if (unit >= NSD)
37641480Smckusick 		return(ENXIO);
377*49132Skarels 	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
37841480Smckusick 		return(ENXIO);
37941480Smckusick 
38041480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
38141480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
38241480Smckusick 	return(0);
38341480Smckusick }
38441480Smckusick 
38541480Smckusick /*
38641480Smckusick  * This routine is called for partial block transfers and non-aligned
38741480Smckusick  * transfers (the latter only being possible on devices with a block size
38841480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
38941480Smckusick  * using a locally allocated buffer:
39041480Smckusick  *	1. transfer any initial partial block
39141480Smckusick  *	2. transfer full blocks
39241480Smckusick  *	3. transfer any final partial block
39341480Smckusick  */
39441480Smckusick static void
39541480Smckusick sdlblkstrat(bp, bsize)
39641480Smckusick 	register struct buf *bp;
39741480Smckusick 	register int bsize;
39841480Smckusick {
39941480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
40041480Smckusick 							M_DEVBUF, M_WAITOK);
40141480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
40241480Smckusick 	register int bn, resid;
40341480Smckusick 	register caddr_t addr;
40441480Smckusick 
40541480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
406*49132Skarels 	cbp->b_proc = curproc;		/* XXX */
40741480Smckusick 	cbp->b_dev = bp->b_dev;
40841480Smckusick 	bn = bp->b_blkno;
40941480Smckusick 	resid = bp->b_bcount;
41041480Smckusick 	addr = bp->b_un.b_addr;
41141480Smckusick #ifdef DEBUG
41241480Smckusick 	if (sddebug & SDB_PARTIAL)
41341480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
41441480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
41541480Smckusick #endif
41641480Smckusick 
41741480Smckusick 	while (resid > 0) {
41841480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
41941480Smckusick 		register int count;
42041480Smckusick 
42141480Smckusick 		if (boff || resid < bsize) {
42241480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
42341480Smckusick 			count = MIN(resid, bsize - boff);
42441480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
42541480Smckusick 			cbp->b_blkno = bn - btodb(boff);
42641480Smckusick 			cbp->b_un.b_addr = cbuf;
42741480Smckusick 			cbp->b_bcount = bsize;
42841480Smckusick #ifdef DEBUG
42941480Smckusick 			if (sddebug & SDB_PARTIAL)
43041480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
43141480Smckusick 				       cbp->b_blkno, count, boff, addr);
43241480Smckusick #endif
43341480Smckusick 			sdstrategy(cbp);
43441480Smckusick 			biowait(cbp);
43541480Smckusick 			if (cbp->b_flags & B_ERROR) {
43641480Smckusick 				bp->b_flags |= B_ERROR;
43741480Smckusick 				bp->b_error = cbp->b_error;
43841480Smckusick 				break;
43941480Smckusick 			}
44041480Smckusick 			if (bp->b_flags & B_READ) {
44141480Smckusick 				bcopy(&cbuf[boff], addr, count);
44241480Smckusick 				goto done;
44341480Smckusick 			}
44441480Smckusick 			bcopy(addr, &cbuf[boff], count);
44541480Smckusick #ifdef DEBUG
44641480Smckusick 			if (sddebug & SDB_PARTIAL)
44741480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
44841480Smckusick 				       cbp->b_blkno, count, boff, addr);
44941480Smckusick #endif
45041480Smckusick 		} else {
45141480Smckusick 			count = resid & ~(bsize - 1);
45241480Smckusick 			cbp->b_blkno = bn;
45341480Smckusick 			cbp->b_un.b_addr = addr;
45441480Smckusick 			cbp->b_bcount = count;
45541480Smckusick #ifdef DEBUG
45641480Smckusick 			if (sddebug & SDB_PARTIAL)
45741480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
45841480Smckusick 				       cbp->b_blkno, count, addr);
45941480Smckusick #endif
46041480Smckusick 		}
46141480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
46241480Smckusick 		sdstrategy(cbp);
46341480Smckusick 		biowait(cbp);
46441480Smckusick 		if (cbp->b_flags & B_ERROR) {
46541480Smckusick 			bp->b_flags |= B_ERROR;
46641480Smckusick 			bp->b_error = cbp->b_error;
46741480Smckusick 			break;
46841480Smckusick 		}
46941480Smckusick done:
47041480Smckusick 		bn += btodb(count);
47141480Smckusick 		resid -= count;
47241480Smckusick 		addr += count;
47341480Smckusick #ifdef DEBUG
47441480Smckusick 		if (sddebug & SDB_PARTIAL)
47541480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
47641480Smckusick 			       bn, resid, addr);
47741480Smckusick #endif
47841480Smckusick 	}
47941480Smckusick 	free(cbuf, M_DEVBUF);
48041480Smckusick 	free(cbp, M_DEVBUF);
48141480Smckusick }
48241480Smckusick 
48341480Smckusick void
48441480Smckusick sdstrategy(bp)
48541480Smckusick 	register struct buf *bp;
48641480Smckusick {
48741480Smckusick 	register int unit = sdunit(bp->b_dev);
48841480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
48945750Smckusick 	register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)];
49041480Smckusick 	register struct buf *dp = &sdtab[unit];
49145750Smckusick 	register daddr_t bn;
49245750Smckusick 	register int sz, s;
49341480Smckusick 
49441480Smckusick 	if (sc->sc_format_pid) {
495*49132Skarels 		if (sc->sc_format_pid != curproc->p_pid) {	/* XXX */
49641480Smckusick 			bp->b_error = EPERM;
49745750Smckusick 			bp->b_flags |= B_ERROR;
49845750Smckusick 			goto done;
49941480Smckusick 		}
50041480Smckusick 		bp->b_cylin = 0;
50141480Smckusick 	} else {
50241480Smckusick 		bn = bp->b_blkno;
50345750Smckusick 		sz = howmany(bp->b_bcount, DEV_BSIZE);
50445750Smckusick 		if (bn < 0 || bn + sz > pinfo->nblocks) {
50545750Smckusick 			sz = pinfo->nblocks - bn;
50645750Smckusick 			if (sz == 0) {
50741480Smckusick 				bp->b_resid = bp->b_bcount;
50841480Smckusick 				goto done;
50941480Smckusick 			}
51045750Smckusick 			if (sz < 0) {
51145750Smckusick 				bp->b_error = EINVAL;
51245750Smckusick 				bp->b_flags |= B_ERROR;
51345750Smckusick 				goto done;
51445750Smckusick 			}
51545750Smckusick 			bp->b_bcount = dbtob(sz);
51641480Smckusick 		}
51741480Smckusick 		/*
51841480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
51941480Smckusick 		 */
52041480Smckusick 		s = sc->sc_blksize - 1;
52141480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
52241480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
52341480Smckusick 			goto done;
52441480Smckusick 		}
52545750Smckusick 		bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift;
52641480Smckusick 	}
52741480Smckusick 	s = splbio();
52841480Smckusick 	disksort(dp, bp);
52941480Smckusick 	if (dp->b_active == 0) {
53041480Smckusick 		dp->b_active = 1;
53141480Smckusick 		sdustart(unit);
53241480Smckusick 	}
53341480Smckusick 	splx(s);
53441480Smckusick 	return;
53541480Smckusick done:
53645750Smckusick 	biodone(bp);
53741480Smckusick }
53841480Smckusick 
53941480Smckusick void
54041480Smckusick sdustart(unit)
54141480Smckusick 	register int unit;
54241480Smckusick {
54341480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
54441480Smckusick 		sdstart(unit);
54541480Smckusick }
54641480Smckusick 
54745750Smckusick static int
54841480Smckusick sderror(unit, sc, hp, stat)
54941480Smckusick 	int unit, stat;
55041480Smckusick 	register struct sd_softc *sc;
55141480Smckusick 	register struct hp_device *hp;
55241480Smckusick {
55345750Smckusick 	int retry = 0;
55445750Smckusick 
55541480Smckusick 	sdsense[unit].status = stat;
55641480Smckusick 	if (stat & STS_CHECKCOND) {
55741480Smckusick 		struct scsi_xsense *sp;
55841480Smckusick 
55941480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
56041480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
56141480Smckusick 				   sizeof(sdsense[unit].sense));
56241480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
56341480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
56441480Smckusick 			sp->class, sp->code);
56541480Smckusick 		if (sp->class == 7) {
56641480Smckusick 			printf(", key %d", sp->key);
56741480Smckusick 			if (sp->valid)
56841480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
56945750Smckusick 			/* no sense or recovered error, try again */
57045750Smckusick 			if (sp->key == 0 || sp->key == 1)
57145750Smckusick 				retry = 1;
57241480Smckusick 		}
57341480Smckusick 		printf("\n");
57441480Smckusick 	}
57545750Smckusick 	return(retry);
57641480Smckusick }
57741480Smckusick 
57841480Smckusick static void
57941480Smckusick sdfinish(unit, sc, bp)
58041480Smckusick 	int unit;
58141480Smckusick 	register struct sd_softc *sc;
58241480Smckusick 	register struct buf *bp;
58341480Smckusick {
58441480Smckusick 	sdtab[unit].b_errcnt = 0;
58541480Smckusick 	sdtab[unit].b_actf = bp->b_actf;
58641480Smckusick 	bp->b_resid = 0;
58745750Smckusick 	biodone(bp);
58841480Smckusick 	scsifree(&sc->sc_dq);
58941480Smckusick 	if (sdtab[unit].b_actf)
59041480Smckusick 		sdustart(unit);
59141480Smckusick 	else
59241480Smckusick 		sdtab[unit].b_active = 0;
59341480Smckusick }
59441480Smckusick 
59541480Smckusick void
59641480Smckusick sdstart(unit)
59741480Smckusick 	register int unit;
59841480Smckusick {
59941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
60041480Smckusick 	register struct hp_device *hp = sc->sc_hd;
60141480Smckusick 
60241480Smckusick 	/*
60341480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
60441480Smckusick 	 * so check now.
60541480Smckusick 	 */
60641480Smckusick 	if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
60741480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
60841480Smckusick 		register int sts;
60941480Smckusick 
61041480Smckusick 		sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
61141480Smckusick 					 sc->sc_punit, &sdcmd[unit],
61241480Smckusick 					 bp->b_un.b_addr, bp->b_bcount,
61341480Smckusick 					 bp->b_flags & B_READ);
61441480Smckusick 		sdsense[unit].status = sts;
61541480Smckusick 		if (sts & 0xfe) {
61645750Smckusick 			(void) sderror(unit, sc, hp, sts);
61741480Smckusick 			bp->b_flags |= B_ERROR;
61841480Smckusick 			bp->b_error = EIO;
61941480Smckusick 		}
62041480Smckusick 		sdfinish(unit, sc, bp);
62141480Smckusick 
62241480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
62341480Smckusick 		sdgo(unit);
62441480Smckusick }
62541480Smckusick 
62641480Smckusick void
62741480Smckusick sdgo(unit)
62841480Smckusick 	register int unit;
62941480Smckusick {
63041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
63141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
63241480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
63341480Smckusick 	register int pad;
63441480Smckusick 	register struct scsi_fmt_cdb *cmd;
63541480Smckusick 
63641480Smckusick 	if (sc->sc_format_pid) {
63741480Smckusick 		cmd = &sdcmd[unit];
63841480Smckusick 		pad = 0;
63941480Smckusick 	} else {
64041480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
64141480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
64241480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
64341480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
64441480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
64541480Smckusick #ifdef DEBUG
64641480Smckusick 		if (pad)
64741480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
64841480Smckusick 			       unit, bp->b_bcount);
64941480Smckusick #endif
65041480Smckusick 		sdstats[unit].sdtransfers++;
65141480Smckusick 	}
65241480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
65341480Smckusick 		if (hp->hp_dk >= 0) {
65441480Smckusick 			dk_busy |= 1 << hp->hp_dk;
65541480Smckusick 			++dk_seek[hp->hp_dk];
65641480Smckusick 			++dk_xfer[hp->hp_dk];
65741480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
65841480Smckusick 		}
65941480Smckusick 		return;
66041480Smckusick 	}
66141480Smckusick #ifdef DEBUG
66241480Smckusick 	if (sddebug & SDB_ERROR)
66341480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
66441480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
66541480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
66641480Smckusick 		       sdtab[unit].b_errcnt);
66741480Smckusick #endif
66841480Smckusick 	bp->b_flags |= B_ERROR;
66941480Smckusick 	bp->b_error = EIO;
67041480Smckusick 	sdfinish(unit, sc, bp);
67141480Smckusick }
67241480Smckusick 
67341480Smckusick void
67441480Smckusick sdintr(unit, stat)
67541480Smckusick 	register int unit;
67641480Smckusick 	int stat;
67741480Smckusick {
67841480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
67941480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
68041480Smckusick 	register struct hp_device *hp = sc->sc_hd;
68145750Smckusick 	int retry;
68241480Smckusick 
68341480Smckusick 	if (bp == NULL) {
68441480Smckusick 		printf("sd%d: bp == NULL\n", unit);
68541480Smckusick 		return;
68641480Smckusick 	}
68741480Smckusick 	if (hp->hp_dk >= 0)
68841480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
68941480Smckusick 	if (stat) {
69041480Smckusick #ifdef DEBUG
69141480Smckusick 		if (sddebug & SDB_ERROR)
69241480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
69341480Smckusick 				unit, stat);
69441480Smckusick #endif
69545750Smckusick 		retry = sderror(unit, sc, hp, stat);
69645750Smckusick 		if (retry && sdtab[unit].b_errcnt++ < SDRETRY) {
69745750Smckusick 			printf("sd%d: retry #%d\n",
69845750Smckusick 			       unit, sdtab[unit].b_errcnt);
69945750Smckusick 			sdstart(unit);
70045750Smckusick 			return;
70145750Smckusick 		}
70241480Smckusick 		bp->b_flags |= B_ERROR;
70341480Smckusick 		bp->b_error = EIO;
70441480Smckusick 	}
70541480Smckusick 	sdfinish(unit, sc, bp);
70641480Smckusick }
70741480Smckusick 
70841480Smckusick int
709*49132Skarels sdread(dev, uio, flags)
71041480Smckusick 	dev_t dev;
71141480Smckusick 	struct uio *uio;
712*49132Skarels 	int flags;
71341480Smckusick {
71441480Smckusick 	register int unit = sdunit(dev);
71541480Smckusick 	register int pid;
71641480Smckusick 
717*49132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
718*49132Skarels 	    pid != uio->uio_procp->p_pid)
71941480Smckusick 		return (EPERM);
72041480Smckusick 
721*49132Skarels 	return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
72241480Smckusick }
72341480Smckusick 
72441480Smckusick int
725*49132Skarels sdwrite(dev, uio, flags)
72641480Smckusick 	dev_t dev;
72741480Smckusick 	struct uio *uio;
728*49132Skarels 	int flags;
72941480Smckusick {
73041480Smckusick 	register int unit = sdunit(dev);
73141480Smckusick 	register int pid;
73241480Smckusick 
733*49132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
734*49132Skarels 	    pid != uio->uio_procp->p_pid)
73541480Smckusick 		return (EPERM);
73641480Smckusick 
737*49132Skarels 	return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
73841480Smckusick }
73941480Smckusick 
74041480Smckusick int
741*49132Skarels sdioctl(dev, cmd, data, flag, p)
74241480Smckusick 	dev_t dev;
74341480Smckusick 	int cmd;
74441480Smckusick 	caddr_t data;
74541480Smckusick 	int flag;
746*49132Skarels 	struct proc *p;
74741480Smckusick {
74841480Smckusick 	register int unit = sdunit(dev);
74941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
75041480Smckusick 
75141480Smckusick 	switch (cmd) {
75241480Smckusick 	default:
75341480Smckusick 		return (EINVAL);
75441480Smckusick 
75541480Smckusick 	case SDIOCSFORMAT:
75641480Smckusick 		/* take this device into or out of "format" mode */
757*49132Skarels 		if (suser(p->p_ucred, &p->p_acflag))
75841480Smckusick 			return(EPERM);
75941480Smckusick 
76041480Smckusick 		if (*(int *)data) {
76141480Smckusick 			if (sc->sc_format_pid)
76241480Smckusick 				return (EPERM);
763*49132Skarels 			sc->sc_format_pid = p->p_pid;
76441480Smckusick 		} else
76541480Smckusick 			sc->sc_format_pid = 0;
76641480Smckusick 		return (0);
76741480Smckusick 
76841480Smckusick 	case SDIOCGFORMAT:
76941480Smckusick 		/* find out who has the device in format mode */
77041480Smckusick 		*(int *)data = sc->sc_format_pid;
77141480Smckusick 		return (0);
77241480Smckusick 
77341480Smckusick 	case SDIOCSCSICOMMAND:
77441480Smckusick 		/*
77541480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
77641480Smckusick 		 * read or write to the char device.
77741480Smckusick 		 */
778*49132Skarels 		if (sc->sc_format_pid != p->p_pid)
77941480Smckusick 			return (EPERM);
78041480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
78141480Smckusick 			return (EINVAL);
78241480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
78341480Smckusick 		return (0);
78441480Smckusick 
78541480Smckusick 	case SDIOCSENSE:
78641480Smckusick 		/*
78741480Smckusick 		 * return the SCSI sense data saved after the last
78841480Smckusick 		 * operation that completed with "check condition" status.
78941480Smckusick 		 */
79041480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
79141480Smckusick 		return (0);
79241480Smckusick 
79341480Smckusick 	}
79441480Smckusick 	/*NOTREACHED*/
79541480Smckusick }
79641480Smckusick 
79741480Smckusick int
79841480Smckusick sdsize(dev)
79941480Smckusick 	dev_t dev;
80041480Smckusick {
80141480Smckusick 	register int unit = sdunit(dev);
80241480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
80341480Smckusick 
80441480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
80541480Smckusick 		return(-1);
80641480Smckusick 
80741480Smckusick 	return(sc->sc_info.part[sdpart(dev)].nblocks);
80841480Smckusick }
80941480Smckusick 
81041480Smckusick /*
81141480Smckusick  * Non-interrupt driven, non-dma dump routine.
81241480Smckusick  */
81341480Smckusick int
81441480Smckusick sddump(dev)
81541480Smckusick 	dev_t dev;
81641480Smckusick {
81741480Smckusick 	int part = sdpart(dev);
81841480Smckusick 	int unit = sdunit(dev);
81941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
82041480Smckusick 	register struct hp_device *hp = sc->sc_hd;
82141480Smckusick 	register daddr_t baddr;
82241480Smckusick 	register int maddr;
82341480Smckusick 	register int pages, i;
82441480Smckusick 	int stat;
82541480Smckusick 	extern int lowram;
82641480Smckusick 
82741480Smckusick 	/*
82841480Smckusick 	 * Hmm... all vax drivers dump maxfree pages which is physmem minus
82941480Smckusick 	 * the message buffer.  Is there a reason for not dumping the
83041480Smckusick 	 * message buffer?  Savecore expects to read 'dumpsize' pages of
83141480Smckusick 	 * dump, where dumpsys() sets dumpsize to physmem!
83241480Smckusick 	 */
83341480Smckusick 	pages = physmem;
83441480Smckusick 
83541480Smckusick 	/* is drive ok? */
83641480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
83741480Smckusick 		return (ENXIO);
83841480Smckusick 	/* dump parameters in range? */
83941480Smckusick 	if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
84041480Smckusick 		return (EINVAL);
84141480Smckusick 	if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
84241480Smckusick 		pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
84341480Smckusick 	maddr = lowram;
84441480Smckusick 	baddr = dumplo + sc->sc_info.part[part].strtblk;
84541480Smckusick 	/* scsi bus idle? */
84641480Smckusick 	if (!scsireq(&sc->sc_dq)) {
84741480Smckusick 		scsireset(hp->hp_ctlr);
84841480Smckusick 		sdreset(sc, sc->sc_hd);
84941480Smckusick 		printf("[ drive %d reset ] ", unit);
85041480Smckusick 	}
85141480Smckusick 	for (i = 0; i < pages; i++) {
85241480Smckusick #define NPGMB	(1024*1024/NBPG)
85341480Smckusick 		/* print out how many Mbs we have dumped */
85441480Smckusick 		if (i && (i % NPGMB) == 0)
85541480Smckusick 			printf("%d ", i / NPGMB);
85641480Smckusick #undef NPBMG
85745750Smckusick 		pmap_enter(pmap_kernel(), vmmap, maddr, VM_PROT_READ, TRUE);
85841480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
85941480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
86041480Smckusick 		if (stat) {
86141480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
86241480Smckusick 			return (EIO);
86341480Smckusick 		}
86441480Smckusick 		maddr += NBPG;
86541480Smckusick 		baddr += ctod(1);
86641480Smckusick 	}
86741480Smckusick 	return (0);
86841480Smckusick }
86941480Smckusick #endif
870