xref: /csrg-svn/sys/hp300/dev/sd.c (revision 45750)
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*45750Smckusick  *	@(#)sd.c	7.3 (Berkeley) 12/05/90
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*45750Smckusick static char rcsid[] = "$Header: sd.c,v 1.3 90/10/10 14:55:10 mike Exp $";
2141480Smckusick #endif
2241480Smckusick 
2341480Smckusick #include "param.h"
2441480Smckusick #include "systm.h"
2541480Smckusick #include "buf.h"
2641480Smckusick #include "errno.h"
2741480Smckusick #include "dkstat.h"
2841480Smckusick #include "disklabel.h"
2941480Smckusick #include "device.h"
3041480Smckusick #include "malloc.h"
3141480Smckusick #include "scsireg.h"
3241480Smckusick 
3341480Smckusick #include "user.h"
3441480Smckusick #include "proc.h"
3541480Smckusick #include "uio.h"
3641480Smckusick 
37*45750Smckusick #include "../vm/vm_param.h"
38*45750Smckusick #include "../vm/pmap.h"
39*45750Smckusick #include "../vm/vm_prot.h"
40*45750Smckusick 
4141480Smckusick extern int scsi_test_unit_rdy();
4241480Smckusick extern int scsi_request_sense();
4341480Smckusick extern int scsi_inquiry();
4441480Smckusick extern int scsi_read_capacity();
4541480Smckusick extern int scsi_tt_write();
4641480Smckusick extern int scsireq();
4741480Smckusick extern int scsiustart();
4841480Smckusick extern int scsigo();
4941480Smckusick extern void scsifree();
5041480Smckusick extern void scsireset();
5141480Smckusick 
5241480Smckusick extern void printf();
5341480Smckusick extern void bcopy();
5441480Smckusick extern void disksort();
5541480Smckusick extern int splbio();
5641480Smckusick extern void splx();
5741480Smckusick extern void biodone();
5841480Smckusick extern int physio();
5941480Smckusick extern void TBIS();
6041480Smckusick 
6141480Smckusick int	sdinit();
6241480Smckusick void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
6341480Smckusick 
6441480Smckusick struct	driver sddriver = {
6541480Smckusick 	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
6641480Smckusick };
6741480Smckusick 
6841480Smckusick struct	size {
6941480Smckusick 	u_long	strtblk;
7041480Smckusick 	u_long	endblk;
7141480Smckusick 	int	nblocks;
7241480Smckusick };
7341480Smckusick 
7441480Smckusick struct sdinfo {
7541480Smckusick 	struct	size part[8];
7641480Smckusick };
7741480Smckusick 
7841480Smckusick /*
7941480Smckusick  * since the SCSI standard tends to hide the disk structure, we define
8041480Smckusick  * partitions in terms of DEV_BSIZE blocks.  The default partition table
8141480Smckusick  * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
8241480Smckusick  * root and 32 meg of swap.  The rest of the space on the drive goes in
8341480Smckusick  * the G partition.  As usual, the C partition covers the entire disk
8441480Smckusick  * (including the boot area).
8541480Smckusick  */
8641480Smckusick struct sdinfo sddefaultpart = {
8741480Smckusick 	     1024,   17408,   16384   ,	/* A */
8841480Smckusick 	    17408,   82944,   65536   ,	/* B */
8941480Smckusick 	        0,       0,       0   ,	/* C */
9041480Smckusick 	    17408,  115712,   98304   ,	/* D */
9141480Smckusick 	   115712,  218112,  102400   ,	/* E */
9241480Smckusick 	   218112,       0,       0   ,	/* F */
9341480Smckusick 	    82944,       0,       0   ,	/* G */
9441480Smckusick 	   115712,       0,       0   ,	/* H */
9541480Smckusick };
9641480Smckusick 
9741480Smckusick struct	sd_softc {
9841480Smckusick 	struct	hp_device *sc_hd;
9941480Smckusick 	struct	devqueue sc_dq;
10041480Smckusick 	int	sc_format_pid;	/* process using "format" mode */
10141480Smckusick 	short	sc_flags;
10241480Smckusick 	short	sc_type;	/* drive type */
10341480Smckusick 	short	sc_punit;	/* physical unit (scsi lun) */
10441480Smckusick 	u_short	sc_bshift;	/* convert device blocks to DEV_BSIZE blks */
10541480Smckusick 	u_int	sc_blks;	/* number of blocks on device */
10641480Smckusick 	int	sc_blksize;	/* device block size in bytes */
10741480Smckusick 	u_int	sc_wpms;	/* average xfer rate in 16 bit wds/sec. */
10841480Smckusick 	struct	sdinfo sc_info;	/* drive partition table & label info */
10941480Smckusick } sd_softc[NSD];
11041480Smckusick 
11141480Smckusick /* sc_flags values */
11241480Smckusick #define	SDF_ALIVE	0x1
11341480Smckusick 
11441480Smckusick #ifdef DEBUG
11541480Smckusick int sddebug = 1;
11641480Smckusick #define SDB_ERROR	0x01
11741480Smckusick #define SDB_PARTIAL	0x02
11841480Smckusick #endif
11941480Smckusick 
12041480Smckusick struct sdstats {
12141480Smckusick 	long	sdresets;
12241480Smckusick 	long	sdtransfers;
12341480Smckusick 	long	sdpartials;
12441480Smckusick } sdstats[NSD];
12541480Smckusick 
12641480Smckusick struct	buf sdtab[NSD];
12741480Smckusick struct	buf sdbuf[NSD];
12841480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
12941480Smckusick struct	scsi_fmt_sense sdsense[NSD];
13041480Smckusick 
13141480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
13241480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
13341480Smckusick 
13441480Smckusick #define	sdunit(x)	((minor(x) >> 3) & 0x7)
13541480Smckusick #define sdpart(x)	(minor(x) & 0x7)
13641480Smckusick #define	sdpunit(x)	((x) & 7)
13741480Smckusick #define	b_cylin		b_resid
138*45750Smckusick 
13941480Smckusick #define	SDRETRY		2
14041480Smckusick 
14141480Smckusick /*
14241480Smckusick  * Table of scsi commands users are allowed to access via "format"
14341480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
14441480Smckusick  * -1 means needs dma and/or wait for intr.
14541480Smckusick  */
14641480Smckusick static char legal_cmds[256] = {
14741480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
14841480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14941480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
15041480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15141480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15241480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15341480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15441480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15541480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15641480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15741480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15841480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15941480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16041480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16141480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16241480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16341480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16441480Smckusick };
16541480Smckusick 
16641480Smckusick static struct scsi_inquiry inqbuf;
16741480Smckusick static struct scsi_fmt_cdb inq = {
16841480Smckusick 	6,
16941480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
17041480Smckusick };
17141480Smckusick 
17241480Smckusick static u_char capbuf[8];
17341480Smckusick struct scsi_fmt_cdb cap = {
17441480Smckusick 	10,
17541480Smckusick 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
17641480Smckusick };
17741480Smckusick 
17841480Smckusick static int
17941480Smckusick sdident(sc, hd)
18041480Smckusick 	struct sd_softc *sc;
18141480Smckusick 	struct hp_device *hd;
18241480Smckusick {
18341480Smckusick 	int unit;
18441480Smckusick 	register int ctlr, slave;
18541480Smckusick 	register int i;
18641480Smckusick 	register int tries = 10;
187*45750Smckusick 	int ismo = 0;
18841480Smckusick 
18941480Smckusick 	ctlr = hd->hp_ctlr;
19041480Smckusick 	slave = hd->hp_slave;
19141480Smckusick 	unit = sc->sc_punit;
19241480Smckusick 
19341480Smckusick 	/*
19441480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
19541480Smckusick 	 */
19641480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
197*45750Smckusick 		if (i == -1 || --tries < 0) {
198*45750Smckusick 			if (ismo)
199*45750Smckusick 				break;
20041480Smckusick 			/* doesn't exist or not a CCS device */
20141480Smckusick 			return (-1);
202*45750Smckusick 		}
20341480Smckusick 		if (i == STS_CHECKCOND) {
20441480Smckusick 			u_char sensebuf[128];
20541480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
20641480Smckusick 
20741480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
20841480Smckusick 					   sizeof(sensebuf));
209*45750Smckusick 			if (sp->class == 7)
210*45750Smckusick 				switch (sp->key) {
211*45750Smckusick 				/* not ready -- might be MO with no media */
212*45750Smckusick 				case 2:
213*45750Smckusick 					if (sp->len == 12 &&
214*45750Smckusick 					    sensebuf[12] == 10)	/* XXX */
215*45750Smckusick 						ismo = 1;
216*45750Smckusick 					break;
21741480Smckusick 				/* drive doing an RTZ -- give it a while */
218*45750Smckusick 				case 6:
219*45750Smckusick 					DELAY(1000000);
220*45750Smckusick 					break;
221*45750Smckusick 				default:
222*45750Smckusick 					break;
223*45750Smckusick 				}
22441480Smckusick 		}
22541480Smckusick 		DELAY(1000);
22641480Smckusick 	}
227*45750Smckusick 	/*
228*45750Smckusick 	 * Find out about device
229*45750Smckusick 	 */
230*45750Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq,
231*45750Smckusick 			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
232*45750Smckusick 		return(-1);
23341480Smckusick 	switch (inqbuf.type) {
23441480Smckusick 	case 0:		/* disk */
23541480Smckusick 	case 4:		/* WORM */
23641480Smckusick 	case 5:		/* CD-ROM */
23741480Smckusick 	case 7:		/* Magneto-optical */
23841480Smckusick 		break;
23941480Smckusick 	default:	/* not a disk */
24041480Smckusick 		return (-1);
24141480Smckusick 	}
242*45750Smckusick 	/*
243*45750Smckusick 	 * XXX determine if this is an HP MO drive.
244*45750Smckusick 	 */
245*45750Smckusick 	{
246*45750Smckusick 		u_long *id = (u_long *)&inqbuf;
24741480Smckusick 
248*45750Smckusick 		ismo = (id[2] == 0x48502020 &&	/* "HP  " */
249*45750Smckusick 			id[3] == 0x20202020 &&	/* "    " */
250*45750Smckusick 			id[4] == 0x53363330 &&	/* "S630" */
251*45750Smckusick 			id[5] == 0x302e3635 &&	/* "0.65" */
252*45750Smckusick 			id[6] == 0x30412020);	/* "0A  " */
253*45750Smckusick 	}
254*45750Smckusick 	i = scsi_immed_command(ctlr, slave, unit, &cap,
255*45750Smckusick 			       (u_char *)&capbuf, sizeof(capbuf), B_READ);
256*45750Smckusick 	if (i) {
257*45750Smckusick 		/* XXX unformatted or non-existant MO media; fake it */
258*45750Smckusick 		if (i == STS_CHECKCOND && ismo) {
259*45750Smckusick 			sc->sc_blks = 318664;
260*45750Smckusick 			sc->sc_blksize = 1024;
261*45750Smckusick 		} else
262*45750Smckusick 			return(-1);
263*45750Smckusick 	} else {
264*45750Smckusick 		sc->sc_blks = *(u_int *)&capbuf[0];
265*45750Smckusick 		sc->sc_blksize = *(int *)&capbuf[4];
266*45750Smckusick 	}
267*45750Smckusick 	/* return value of read capacity is last valid block number */
268*45750Smckusick 	sc->sc_blks++;
269*45750Smckusick 
27041480Smckusick 	if (inqbuf.version != 1)
27141480Smckusick 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
27241480Smckusick 			inqbuf.type, inqbuf.qual, inqbuf.version);
27341480Smckusick 	else {
27441480Smckusick 		char idstr[32];
27541480Smckusick 
27641480Smckusick 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
27741480Smckusick 		for (i = 27; i > 23; --i)
27841480Smckusick 			if (idstr[i] != ' ')
27941480Smckusick 				break;
28041480Smckusick 		idstr[i+1] = 0;
28141480Smckusick 		for (i = 23; i > 7; --i)
28241480Smckusick 			if (idstr[i] != ' ')
28341480Smckusick 				break;
28441480Smckusick 		idstr[i+1] = 0;
28541480Smckusick 		for (i = 7; i >= 0; --i)
28641480Smckusick 			if (idstr[i] != ' ')
28741480Smckusick 				break;
28841480Smckusick 		idstr[i+1] = 0;
28941480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
29041480Smckusick 			&idstr[24]);
29141480Smckusick 	}
29241480Smckusick 	printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
29341480Smckusick 	if (sc->sc_blksize != DEV_BSIZE) {
29441480Smckusick 		if (sc->sc_blksize < DEV_BSIZE) {
29541480Smckusick 			printf("sd%d: need %d byte blocks - drive ignored\n",
29641480Smckusick 				unit, DEV_BSIZE);
29741480Smckusick 			return (-1);
29841480Smckusick 		}
29941480Smckusick 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
30041480Smckusick 			++sc->sc_bshift;
30141480Smckusick 		sc->sc_blks <<= sc->sc_bshift;
30241480Smckusick 	}
30341480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
30441480Smckusick 	return(inqbuf.type);
30541480Smckusick }
30641480Smckusick 
30741480Smckusick int
30841480Smckusick sdinit(hd)
30941480Smckusick 	register struct hp_device *hd;
31041480Smckusick {
31141480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
31241480Smckusick 
31341480Smckusick 	sc->sc_hd = hd;
31441480Smckusick 	sc->sc_punit = sdpunit(hd->hp_flags);
31541480Smckusick 	sc->sc_type = sdident(sc, hd);
31641480Smckusick 	if (sc->sc_type < 0)
31741480Smckusick 		return(0);
31841480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
31941480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
32041480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
32141480Smckusick 	sc->sc_dq.dq_driver = &sddriver;
32241480Smckusick 
32341480Smckusick 	/*
32441480Smckusick 	 * If we don't have a disk label, build a default partition
32541480Smckusick 	 * table with 'standard' size root & swap and everything else
32641480Smckusick 	 * in the G partition.
32741480Smckusick 	 */
32841480Smckusick 	sc->sc_info = sddefaultpart;
32941480Smckusick 	/* C gets everything */
33041480Smckusick 	sc->sc_info.part[2].nblocks = sc->sc_blks;
33141480Smckusick 	sc->sc_info.part[2].endblk = sc->sc_blks;
33241480Smckusick 	/* G gets from end of B to end of disk */
33341480Smckusick 	sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk;
33441480Smckusick 	sc->sc_info.part[6].endblk = sc->sc_blks;
33541480Smckusick 	/*
33641480Smckusick 	 * We also define the D, E and F paritions as an alternative to
33741480Smckusick 	 * B and G.  D is 48Mb, starts after A and is intended for swapping.
33841480Smckusick 	 * E is 50Mb, starts after D and is intended for /usr. F starts
33941480Smckusick 	 * after E and is what ever is left.
34041480Smckusick 	 */
34141480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[4].endblk) {
34241480Smckusick 		sc->sc_info.part[5].nblocks =
34341480Smckusick 			sc->sc_blks - sc->sc_info.part[4].endblk;
34441480Smckusick 		sc->sc_info.part[5].endblk = sc->sc_blks;
34541480Smckusick 	} else {
34641480Smckusick 		sc->sc_info.part[5].strtblk = 0;
34741480Smckusick 		sc->sc_info.part[3] = sc->sc_info.part[5];
34841480Smckusick 		sc->sc_info.part[4] = sc->sc_info.part[5];
34941480Smckusick 	}
35041480Smckusick 	/*
35141480Smckusick 	 * H is a single partition alternative to E and F.
35241480Smckusick 	 */
35341480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[3].endblk) {
35441480Smckusick 		sc->sc_info.part[7].nblocks =
35541480Smckusick 			sc->sc_blks - sc->sc_info.part[3].endblk;
35641480Smckusick 		sc->sc_info.part[7].endblk = sc->sc_blks;
35741480Smckusick 	} else {
35841480Smckusick 		sc->sc_info.part[7].strtblk = 0;
35941480Smckusick 	}
36041480Smckusick 
36141480Smckusick 	sc->sc_flags = SDF_ALIVE;
36241480Smckusick 	return(1);
36341480Smckusick }
36441480Smckusick 
36541480Smckusick void
36641480Smckusick sdreset(sc, hd)
36741480Smckusick 	register struct sd_softc *sc;
36841480Smckusick 	register struct hp_device *hd;
36941480Smckusick {
37041480Smckusick 	sdstats[hd->hp_unit].sdresets++;
37141480Smckusick }
37241480Smckusick 
37341480Smckusick int
37441480Smckusick sdopen(dev, flags)
37541480Smckusick 	dev_t dev;
37641480Smckusick 	int flags;
37741480Smckusick {
37841480Smckusick 	register int unit = sdunit(dev);
37941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
38041480Smckusick 
38141480Smckusick 	if (unit >= NSD)
38241480Smckusick 		return(ENXIO);
38341480Smckusick 	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(u.u_cred, &u.u_acflag))
38441480Smckusick 		return(ENXIO);
38541480Smckusick 
38641480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
38741480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
38841480Smckusick 	return(0);
38941480Smckusick }
39041480Smckusick 
39141480Smckusick /*
39241480Smckusick  * This routine is called for partial block transfers and non-aligned
39341480Smckusick  * transfers (the latter only being possible on devices with a block size
39441480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
39541480Smckusick  * using a locally allocated buffer:
39641480Smckusick  *	1. transfer any initial partial block
39741480Smckusick  *	2. transfer full blocks
39841480Smckusick  *	3. transfer any final partial block
39941480Smckusick  */
40041480Smckusick static void
40141480Smckusick sdlblkstrat(bp, bsize)
40241480Smckusick 	register struct buf *bp;
40341480Smckusick 	register int bsize;
40441480Smckusick {
40541480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
40641480Smckusick 							M_DEVBUF, M_WAITOK);
40741480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
40841480Smckusick 	register int bn, resid;
40941480Smckusick 	register caddr_t addr;
41041480Smckusick 
41141480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
41241480Smckusick 	cbp->b_proc = u.u_procp;
41341480Smckusick 	cbp->b_dev = bp->b_dev;
41441480Smckusick 	bn = bp->b_blkno;
41541480Smckusick 	resid = bp->b_bcount;
41641480Smckusick 	addr = bp->b_un.b_addr;
41741480Smckusick #ifdef DEBUG
41841480Smckusick 	if (sddebug & SDB_PARTIAL)
41941480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
42041480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
42141480Smckusick #endif
42241480Smckusick 
42341480Smckusick 	while (resid > 0) {
42441480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
42541480Smckusick 		register int count;
42641480Smckusick 
42741480Smckusick 		if (boff || resid < bsize) {
42841480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
42941480Smckusick 			count = MIN(resid, bsize - boff);
43041480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
43141480Smckusick 			cbp->b_blkno = bn - btodb(boff);
43241480Smckusick 			cbp->b_un.b_addr = cbuf;
43341480Smckusick 			cbp->b_bcount = bsize;
43441480Smckusick #ifdef DEBUG
43541480Smckusick 			if (sddebug & SDB_PARTIAL)
43641480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
43741480Smckusick 				       cbp->b_blkno, count, boff, addr);
43841480Smckusick #endif
43941480Smckusick 			sdstrategy(cbp);
44041480Smckusick 			biowait(cbp);
44141480Smckusick 			if (cbp->b_flags & B_ERROR) {
44241480Smckusick 				bp->b_flags |= B_ERROR;
44341480Smckusick 				bp->b_error = cbp->b_error;
44441480Smckusick 				break;
44541480Smckusick 			}
44641480Smckusick 			if (bp->b_flags & B_READ) {
44741480Smckusick 				bcopy(&cbuf[boff], addr, count);
44841480Smckusick 				goto done;
44941480Smckusick 			}
45041480Smckusick 			bcopy(addr, &cbuf[boff], count);
45141480Smckusick #ifdef DEBUG
45241480Smckusick 			if (sddebug & SDB_PARTIAL)
45341480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
45441480Smckusick 				       cbp->b_blkno, count, boff, addr);
45541480Smckusick #endif
45641480Smckusick 		} else {
45741480Smckusick 			count = resid & ~(bsize - 1);
45841480Smckusick 			cbp->b_blkno = bn;
45941480Smckusick 			cbp->b_un.b_addr = addr;
46041480Smckusick 			cbp->b_bcount = count;
46141480Smckusick #ifdef DEBUG
46241480Smckusick 			if (sddebug & SDB_PARTIAL)
46341480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
46441480Smckusick 				       cbp->b_blkno, count, addr);
46541480Smckusick #endif
46641480Smckusick 		}
46741480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
46841480Smckusick 		sdstrategy(cbp);
46941480Smckusick 		biowait(cbp);
47041480Smckusick 		if (cbp->b_flags & B_ERROR) {
47141480Smckusick 			bp->b_flags |= B_ERROR;
47241480Smckusick 			bp->b_error = cbp->b_error;
47341480Smckusick 			break;
47441480Smckusick 		}
47541480Smckusick done:
47641480Smckusick 		bn += btodb(count);
47741480Smckusick 		resid -= count;
47841480Smckusick 		addr += count;
47941480Smckusick #ifdef DEBUG
48041480Smckusick 		if (sddebug & SDB_PARTIAL)
48141480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
48241480Smckusick 			       bn, resid, addr);
48341480Smckusick #endif
48441480Smckusick 	}
48541480Smckusick 	free(cbuf, M_DEVBUF);
48641480Smckusick 	free(cbp, M_DEVBUF);
48741480Smckusick }
48841480Smckusick 
48941480Smckusick void
49041480Smckusick sdstrategy(bp)
49141480Smckusick 	register struct buf *bp;
49241480Smckusick {
49341480Smckusick 	register int unit = sdunit(bp->b_dev);
49441480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
495*45750Smckusick 	register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)];
49641480Smckusick 	register struct buf *dp = &sdtab[unit];
497*45750Smckusick 	register daddr_t bn;
498*45750Smckusick 	register int sz, s;
49941480Smckusick 
50041480Smckusick 	if (sc->sc_format_pid) {
50141480Smckusick 		if (sc->sc_format_pid != u.u_procp->p_pid) {
50241480Smckusick 			bp->b_error = EPERM;
503*45750Smckusick 			bp->b_flags |= B_ERROR;
504*45750Smckusick 			goto done;
50541480Smckusick 		}
50641480Smckusick 		bp->b_cylin = 0;
50741480Smckusick 	} else {
50841480Smckusick 		bn = bp->b_blkno;
509*45750Smckusick 		sz = howmany(bp->b_bcount, DEV_BSIZE);
510*45750Smckusick 		if (bn < 0 || bn + sz > pinfo->nblocks) {
511*45750Smckusick 			sz = pinfo->nblocks - bn;
512*45750Smckusick 			if (sz == 0) {
51341480Smckusick 				bp->b_resid = bp->b_bcount;
51441480Smckusick 				goto done;
51541480Smckusick 			}
516*45750Smckusick 			if (sz < 0) {
517*45750Smckusick 				bp->b_error = EINVAL;
518*45750Smckusick 				bp->b_flags |= B_ERROR;
519*45750Smckusick 				goto done;
520*45750Smckusick 			}
521*45750Smckusick 			bp->b_bcount = dbtob(sz);
52241480Smckusick 		}
52341480Smckusick 		/*
52441480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
52541480Smckusick 		 */
52641480Smckusick 		s = sc->sc_blksize - 1;
52741480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
52841480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
52941480Smckusick 			goto done;
53041480Smckusick 		}
531*45750Smckusick 		bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift;
53241480Smckusick 	}
53341480Smckusick 	s = splbio();
53441480Smckusick 	disksort(dp, bp);
53541480Smckusick 	if (dp->b_active == 0) {
53641480Smckusick 		dp->b_active = 1;
53741480Smckusick 		sdustart(unit);
53841480Smckusick 	}
53941480Smckusick 	splx(s);
54041480Smckusick 	return;
54141480Smckusick done:
542*45750Smckusick 	biodone(bp);
54341480Smckusick }
54441480Smckusick 
54541480Smckusick void
54641480Smckusick sdustart(unit)
54741480Smckusick 	register int unit;
54841480Smckusick {
54941480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
55041480Smckusick 		sdstart(unit);
55141480Smckusick }
55241480Smckusick 
553*45750Smckusick static int
55441480Smckusick sderror(unit, sc, hp, stat)
55541480Smckusick 	int unit, stat;
55641480Smckusick 	register struct sd_softc *sc;
55741480Smckusick 	register struct hp_device *hp;
55841480Smckusick {
559*45750Smckusick 	int retry = 0;
560*45750Smckusick 
56141480Smckusick 	sdsense[unit].status = stat;
56241480Smckusick 	if (stat & STS_CHECKCOND) {
56341480Smckusick 		struct scsi_xsense *sp;
56441480Smckusick 
56541480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
56641480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
56741480Smckusick 				   sizeof(sdsense[unit].sense));
56841480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
56941480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
57041480Smckusick 			sp->class, sp->code);
57141480Smckusick 		if (sp->class == 7) {
57241480Smckusick 			printf(", key %d", sp->key);
57341480Smckusick 			if (sp->valid)
57441480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
575*45750Smckusick 			/* no sense or recovered error, try again */
576*45750Smckusick 			if (sp->key == 0 || sp->key == 1)
577*45750Smckusick 				retry = 1;
57841480Smckusick 		}
57941480Smckusick 		printf("\n");
58041480Smckusick 	}
581*45750Smckusick 	return(retry);
58241480Smckusick }
58341480Smckusick 
58441480Smckusick static void
58541480Smckusick sdfinish(unit, sc, bp)
58641480Smckusick 	int unit;
58741480Smckusick 	register struct sd_softc *sc;
58841480Smckusick 	register struct buf *bp;
58941480Smckusick {
59041480Smckusick 	sdtab[unit].b_errcnt = 0;
59141480Smckusick 	sdtab[unit].b_actf = bp->b_actf;
59241480Smckusick 	bp->b_resid = 0;
593*45750Smckusick 	biodone(bp);
59441480Smckusick 	scsifree(&sc->sc_dq);
59541480Smckusick 	if (sdtab[unit].b_actf)
59641480Smckusick 		sdustart(unit);
59741480Smckusick 	else
59841480Smckusick 		sdtab[unit].b_active = 0;
59941480Smckusick }
60041480Smckusick 
60141480Smckusick void
60241480Smckusick sdstart(unit)
60341480Smckusick 	register int unit;
60441480Smckusick {
60541480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
60641480Smckusick 	register struct hp_device *hp = sc->sc_hd;
60741480Smckusick 
60841480Smckusick 	/*
60941480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
61041480Smckusick 	 * so check now.
61141480Smckusick 	 */
61241480Smckusick 	if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
61341480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
61441480Smckusick 		register int sts;
61541480Smckusick 
61641480Smckusick 		sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
61741480Smckusick 					 sc->sc_punit, &sdcmd[unit],
61841480Smckusick 					 bp->b_un.b_addr, bp->b_bcount,
61941480Smckusick 					 bp->b_flags & B_READ);
62041480Smckusick 		sdsense[unit].status = sts;
62141480Smckusick 		if (sts & 0xfe) {
622*45750Smckusick 			(void) sderror(unit, sc, hp, sts);
62341480Smckusick 			bp->b_flags |= B_ERROR;
62441480Smckusick 			bp->b_error = EIO;
62541480Smckusick 		}
62641480Smckusick 		sdfinish(unit, sc, bp);
62741480Smckusick 
62841480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
62941480Smckusick 		sdgo(unit);
63041480Smckusick }
63141480Smckusick 
63241480Smckusick void
63341480Smckusick sdgo(unit)
63441480Smckusick 	register int unit;
63541480Smckusick {
63641480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
63741480Smckusick 	register struct hp_device *hp = sc->sc_hd;
63841480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
63941480Smckusick 	register int pad;
64041480Smckusick 	register struct scsi_fmt_cdb *cmd;
64141480Smckusick 
64241480Smckusick 	if (sc->sc_format_pid) {
64341480Smckusick 		cmd = &sdcmd[unit];
64441480Smckusick 		pad = 0;
64541480Smckusick 	} else {
64641480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
64741480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
64841480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
64941480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
65041480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
65141480Smckusick #ifdef DEBUG
65241480Smckusick 		if (pad)
65341480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
65441480Smckusick 			       unit, bp->b_bcount);
65541480Smckusick #endif
65641480Smckusick 		sdstats[unit].sdtransfers++;
65741480Smckusick 	}
65841480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
65941480Smckusick 		if (hp->hp_dk >= 0) {
66041480Smckusick 			dk_busy |= 1 << hp->hp_dk;
66141480Smckusick 			++dk_seek[hp->hp_dk];
66241480Smckusick 			++dk_xfer[hp->hp_dk];
66341480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
66441480Smckusick 		}
66541480Smckusick 		return;
66641480Smckusick 	}
66741480Smckusick #ifdef DEBUG
66841480Smckusick 	if (sddebug & SDB_ERROR)
66941480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
67041480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
67141480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
67241480Smckusick 		       sdtab[unit].b_errcnt);
67341480Smckusick #endif
67441480Smckusick 	bp->b_flags |= B_ERROR;
67541480Smckusick 	bp->b_error = EIO;
67641480Smckusick 	sdfinish(unit, sc, bp);
67741480Smckusick }
67841480Smckusick 
67941480Smckusick void
68041480Smckusick sdintr(unit, stat)
68141480Smckusick 	register int unit;
68241480Smckusick 	int stat;
68341480Smckusick {
68441480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
68541480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
68641480Smckusick 	register struct hp_device *hp = sc->sc_hd;
687*45750Smckusick 	int retry;
68841480Smckusick 
68941480Smckusick 	if (bp == NULL) {
69041480Smckusick 		printf("sd%d: bp == NULL\n", unit);
69141480Smckusick 		return;
69241480Smckusick 	}
69341480Smckusick 	if (hp->hp_dk >= 0)
69441480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
69541480Smckusick 	if (stat) {
69641480Smckusick #ifdef DEBUG
69741480Smckusick 		if (sddebug & SDB_ERROR)
69841480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
69941480Smckusick 				unit, stat);
70041480Smckusick #endif
701*45750Smckusick 		retry = sderror(unit, sc, hp, stat);
702*45750Smckusick 		if (retry && sdtab[unit].b_errcnt++ < SDRETRY) {
703*45750Smckusick 			printf("sd%d: retry #%d\n",
704*45750Smckusick 			       unit, sdtab[unit].b_errcnt);
705*45750Smckusick 			sdstart(unit);
706*45750Smckusick 			return;
707*45750Smckusick 		}
70841480Smckusick 		bp->b_flags |= B_ERROR;
70941480Smckusick 		bp->b_error = EIO;
71041480Smckusick 	}
71141480Smckusick 	sdfinish(unit, sc, bp);
71241480Smckusick }
71341480Smckusick 
71441480Smckusick int
71541480Smckusick sdread(dev, uio)
71641480Smckusick 	dev_t dev;
71741480Smckusick 	struct uio *uio;
71841480Smckusick {
71941480Smckusick 	register int unit = sdunit(dev);
72041480Smckusick 	register int pid;
72141480Smckusick 
72241480Smckusick 	if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
72341480Smckusick 		return (EPERM);
72441480Smckusick 
72541480Smckusick 	return(physio(sdstrategy, &sdbuf[unit], dev, B_READ, minphys, uio));
72641480Smckusick }
72741480Smckusick 
72841480Smckusick int
72941480Smckusick sdwrite(dev, uio)
73041480Smckusick 	dev_t dev;
73141480Smckusick 	struct uio *uio;
73241480Smckusick {
73341480Smckusick 	register int unit = sdunit(dev);
73441480Smckusick 	register int pid;
73541480Smckusick 
73641480Smckusick 	if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
73741480Smckusick 		return (EPERM);
73841480Smckusick 
73941480Smckusick 	return(physio(sdstrategy, &sdbuf[unit], dev, B_WRITE, minphys, uio));
74041480Smckusick }
74141480Smckusick 
74241480Smckusick int
74341480Smckusick sdioctl(dev, cmd, data, flag)
74441480Smckusick 	dev_t dev;
74541480Smckusick 	int cmd;
74641480Smckusick 	caddr_t data;
74741480Smckusick 	int flag;
74841480Smckusick {
74941480Smckusick 	register int unit = sdunit(dev);
75041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
75141480Smckusick 
75241480Smckusick 	switch (cmd) {
75341480Smckusick 	default:
75441480Smckusick 		return (EINVAL);
75541480Smckusick 
75641480Smckusick 	case SDIOCSFORMAT:
75741480Smckusick 		/* take this device into or out of "format" mode */
75841480Smckusick 		if (suser(u.u_cred, &u.u_acflag))
75941480Smckusick 			return(EPERM);
76041480Smckusick 
76141480Smckusick 		if (*(int *)data) {
76241480Smckusick 			if (sc->sc_format_pid)
76341480Smckusick 				return (EPERM);
76441480Smckusick 			sc->sc_format_pid = u.u_procp->p_pid;
76541480Smckusick 		} else
76641480Smckusick 			sc->sc_format_pid = 0;
76741480Smckusick 		return (0);
76841480Smckusick 
76941480Smckusick 	case SDIOCGFORMAT:
77041480Smckusick 		/* find out who has the device in format mode */
77141480Smckusick 		*(int *)data = sc->sc_format_pid;
77241480Smckusick 		return (0);
77341480Smckusick 
77441480Smckusick 	case SDIOCSCSICOMMAND:
77541480Smckusick 		/*
77641480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
77741480Smckusick 		 * read or write to the char device.
77841480Smckusick 		 */
77941480Smckusick 		if (sc->sc_format_pid != u.u_procp->p_pid)
78041480Smckusick 			return (EPERM);
78141480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
78241480Smckusick 			return (EINVAL);
78341480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
78441480Smckusick 		return (0);
78541480Smckusick 
78641480Smckusick 	case SDIOCSENSE:
78741480Smckusick 		/*
78841480Smckusick 		 * return the SCSI sense data saved after the last
78941480Smckusick 		 * operation that completed with "check condition" status.
79041480Smckusick 		 */
79141480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
79241480Smckusick 		return (0);
79341480Smckusick 
79441480Smckusick 	}
79541480Smckusick 	/*NOTREACHED*/
79641480Smckusick }
79741480Smckusick 
79841480Smckusick int
79941480Smckusick sdsize(dev)
80041480Smckusick 	dev_t dev;
80141480Smckusick {
80241480Smckusick 	register int unit = sdunit(dev);
80341480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
80441480Smckusick 
80541480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
80641480Smckusick 		return(-1);
80741480Smckusick 
80841480Smckusick 	return(sc->sc_info.part[sdpart(dev)].nblocks);
80941480Smckusick }
81041480Smckusick 
81141480Smckusick /*
81241480Smckusick  * Non-interrupt driven, non-dma dump routine.
81341480Smckusick  */
81441480Smckusick int
81541480Smckusick sddump(dev)
81641480Smckusick 	dev_t dev;
81741480Smckusick {
81841480Smckusick 	int part = sdpart(dev);
81941480Smckusick 	int unit = sdunit(dev);
82041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
82141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
82241480Smckusick 	register daddr_t baddr;
82341480Smckusick 	register int maddr;
82441480Smckusick 	register int pages, i;
82541480Smckusick 	int stat;
82641480Smckusick 	extern int lowram;
82741480Smckusick 
82841480Smckusick 	/*
82941480Smckusick 	 * Hmm... all vax drivers dump maxfree pages which is physmem minus
83041480Smckusick 	 * the message buffer.  Is there a reason for not dumping the
83141480Smckusick 	 * message buffer?  Savecore expects to read 'dumpsize' pages of
83241480Smckusick 	 * dump, where dumpsys() sets dumpsize to physmem!
83341480Smckusick 	 */
83441480Smckusick 	pages = physmem;
83541480Smckusick 
83641480Smckusick 	/* is drive ok? */
83741480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
83841480Smckusick 		return (ENXIO);
83941480Smckusick 	/* dump parameters in range? */
84041480Smckusick 	if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
84141480Smckusick 		return (EINVAL);
84241480Smckusick 	if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
84341480Smckusick 		pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
84441480Smckusick 	maddr = lowram;
84541480Smckusick 	baddr = dumplo + sc->sc_info.part[part].strtblk;
84641480Smckusick 	/* scsi bus idle? */
84741480Smckusick 	if (!scsireq(&sc->sc_dq)) {
84841480Smckusick 		scsireset(hp->hp_ctlr);
84941480Smckusick 		sdreset(sc, sc->sc_hd);
85041480Smckusick 		printf("[ drive %d reset ] ", unit);
85141480Smckusick 	}
85241480Smckusick 	for (i = 0; i < pages; i++) {
85341480Smckusick #define NPGMB	(1024*1024/NBPG)
85441480Smckusick 		/* print out how many Mbs we have dumped */
85541480Smckusick 		if (i && (i % NPGMB) == 0)
85641480Smckusick 			printf("%d ", i / NPGMB);
85741480Smckusick #undef NPBMG
858*45750Smckusick 		pmap_enter(pmap_kernel(), vmmap, maddr, VM_PROT_READ, TRUE);
85941480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
86041480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
86141480Smckusick 		if (stat) {
86241480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
86341480Smckusick 			return (EIO);
86441480Smckusick 		}
86541480Smckusick 		maddr += NBPG;
86641480Smckusick 		baddr += ctod(1);
86741480Smckusick 	}
86841480Smckusick 	return (0);
86941480Smckusick }
87041480Smckusick #endif
871