xref: /csrg-svn/sys/hp300/dev/sd.c (revision 56507)
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*56507Sbostic  *	@(#)sd.c	7.16 (Berkeley) 10/11/92
1141480Smckusick  */
1241480Smckusick 
1341480Smckusick /*
1441480Smckusick  * SCSI CCS (Command Command Set) disk driver.
1541480Smckusick  */
1641480Smckusick #include "sd.h"
1741480Smckusick #if NSD > 0
1841480Smckusick 
1941480Smckusick #ifndef lint
2053929Shibler static char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/sd.c,v 1.2 92/04/10 20:48:35 mike Exp $";
2141480Smckusick #endif
2241480Smckusick 
23*56507Sbostic #include <sys/param.h>
24*56507Sbostic #include <sys/systm.h>
25*56507Sbostic #include <sys/buf.h>
26*56507Sbostic #include <sys/dkstat.h>
27*56507Sbostic #include <sys/disklabel.h>
28*56507Sbostic #include <sys/malloc.h>
29*56507Sbostic #include <sys/proc.h>
30*56507Sbostic #include <sys/ioctl.h>
3141480Smckusick 
32*56507Sbostic #include <hp/dev/device.h>
33*56507Sbostic #include <hp300/dev/scsireg.h>
3445750Smckusick 
35*56507Sbostic #include <vm/vm_param.h>
36*56507Sbostic #include <vm/lock.h>
37*56507Sbostic #include <vm/vm_prot.h>
38*56507Sbostic #include <vm/pmap.h>
39*56507Sbostic 
4041480Smckusick extern int scsi_test_unit_rdy();
4141480Smckusick extern int scsi_request_sense();
4241480Smckusick extern int scsi_inquiry();
4341480Smckusick extern int scsi_read_capacity();
4441480Smckusick extern int scsi_tt_write();
4541480Smckusick extern int scsireq();
4641480Smckusick extern int scsiustart();
4741480Smckusick extern int scsigo();
4841480Smckusick extern void scsifree();
4941480Smckusick extern void scsireset();
5049304Shibler extern void scsi_delay();
5141480Smckusick 
5241480Smckusick extern void disksort();
5341480Smckusick extern void biodone();
5441480Smckusick extern int physio();
5541480Smckusick extern void TBIS();
5641480Smckusick 
5741480Smckusick int	sdinit();
5841480Smckusick void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
5941480Smckusick 
6041480Smckusick struct	driver sddriver = {
6141480Smckusick 	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
6241480Smckusick };
6341480Smckusick 
6441480Smckusick struct	size {
6541480Smckusick 	u_long	strtblk;
6641480Smckusick 	u_long	endblk;
6741480Smckusick 	int	nblocks;
6841480Smckusick };
6941480Smckusick 
7041480Smckusick struct sdinfo {
7141480Smckusick 	struct	size part[8];
7241480Smckusick };
7341480Smckusick 
7441480Smckusick /*
7541480Smckusick  * since the SCSI standard tends to hide the disk structure, we define
7641480Smckusick  * partitions in terms of DEV_BSIZE blocks.  The default partition table
7741480Smckusick  * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
7841480Smckusick  * root and 32 meg of swap.  The rest of the space on the drive goes in
7941480Smckusick  * the G partition.  As usual, the C partition covers the entire disk
8041480Smckusick  * (including the boot area).
8141480Smckusick  */
8241480Smckusick struct sdinfo sddefaultpart = {
8341480Smckusick 	     1024,   17408,   16384   ,	/* A */
8441480Smckusick 	    17408,   82944,   65536   ,	/* B */
8541480Smckusick 	        0,       0,       0   ,	/* C */
8641480Smckusick 	    17408,  115712,   98304   ,	/* D */
8741480Smckusick 	   115712,  218112,  102400   ,	/* E */
8841480Smckusick 	   218112,       0,       0   ,	/* F */
8941480Smckusick 	    82944,       0,       0   ,	/* G */
9041480Smckusick 	   115712,       0,       0   ,	/* H */
9141480Smckusick };
9241480Smckusick 
9341480Smckusick struct	sd_softc {
9441480Smckusick 	struct	hp_device *sc_hd;
9541480Smckusick 	struct	devqueue sc_dq;
9641480Smckusick 	int	sc_format_pid;	/* process using "format" mode */
9741480Smckusick 	short	sc_flags;
9841480Smckusick 	short	sc_type;	/* drive type */
9941480Smckusick 	short	sc_punit;	/* physical unit (scsi lun) */
10041480Smckusick 	u_short	sc_bshift;	/* convert device blocks to DEV_BSIZE blks */
10141480Smckusick 	u_int	sc_blks;	/* number of blocks on device */
10241480Smckusick 	int	sc_blksize;	/* device block size in bytes */
10341480Smckusick 	u_int	sc_wpms;	/* average xfer rate in 16 bit wds/sec. */
10441480Smckusick 	struct	sdinfo sc_info;	/* drive partition table & label info */
10541480Smckusick } sd_softc[NSD];
10641480Smckusick 
10741480Smckusick /* sc_flags values */
10841480Smckusick #define	SDF_ALIVE	0x1
10953929Shibler #define SDF_WANTED	0x2
11053929Shibler #define SDF_RMEDIA	0x4
11141480Smckusick 
11241480Smckusick #ifdef DEBUG
11341480Smckusick int sddebug = 1;
11441480Smckusick #define SDB_ERROR	0x01
11541480Smckusick #define SDB_PARTIAL	0x02
11641480Smckusick #endif
11741480Smckusick 
11841480Smckusick struct sdstats {
11941480Smckusick 	long	sdresets;
12041480Smckusick 	long	sdtransfers;
12141480Smckusick 	long	sdpartials;
12241480Smckusick } sdstats[NSD];
12341480Smckusick 
12441480Smckusick struct	buf sdtab[NSD];
12541480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
12641480Smckusick struct	scsi_fmt_sense sdsense[NSD];
12741480Smckusick 
12841480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
12941480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
13041480Smckusick 
13149132Skarels #define	sdunit(x)	(minor(x) >> 3)
13241480Smckusick #define sdpart(x)	(minor(x) & 0x7)
13341480Smckusick #define	sdpunit(x)	((x) & 7)
13441480Smckusick #define	b_cylin		b_resid
13545750Smckusick 
13641480Smckusick #define	SDRETRY		2
13741480Smckusick 
13841480Smckusick /*
13941480Smckusick  * Table of scsi commands users are allowed to access via "format"
14041480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
14141480Smckusick  * -1 means needs dma and/or wait for intr.
14241480Smckusick  */
14341480Smckusick static char legal_cmds[256] = {
14441480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
14541480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14641480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
14741480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14841480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
14941480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15041480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15141480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15241480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15341480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15441480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15541480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15641480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15741480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15841480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
15941480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16041480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
16141480Smckusick };
16241480Smckusick 
16341480Smckusick static struct scsi_inquiry inqbuf;
16441480Smckusick static struct scsi_fmt_cdb inq = {
16541480Smckusick 	6,
16641480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
16741480Smckusick };
16841480Smckusick 
16941480Smckusick static u_char capbuf[8];
17041480Smckusick struct scsi_fmt_cdb cap = {
17141480Smckusick 	10,
17241480Smckusick 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
17341480Smckusick };
17441480Smckusick 
17541480Smckusick static int
17641480Smckusick sdident(sc, hd)
17741480Smckusick 	struct sd_softc *sc;
17841480Smckusick 	struct hp_device *hd;
17941480Smckusick {
18041480Smckusick 	int unit;
18141480Smckusick 	register int ctlr, slave;
18241480Smckusick 	register int i;
18341480Smckusick 	register int tries = 10;
18449304Shibler 	char idstr[32];
18545750Smckusick 	int ismo = 0;
18641480Smckusick 
18741480Smckusick 	ctlr = hd->hp_ctlr;
18841480Smckusick 	slave = hd->hp_slave;
18941480Smckusick 	unit = sc->sc_punit;
19049304Shibler 	scsi_delay(-1);
19141480Smckusick 
19241480Smckusick 	/*
19341480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
19441480Smckusick 	 */
19541480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
19645750Smckusick 		if (i == -1 || --tries < 0) {
19745750Smckusick 			if (ismo)
19845750Smckusick 				break;
19941480Smckusick 			/* doesn't exist or not a CCS device */
20049304Shibler 			goto failed;
20145750Smckusick 		}
20241480Smckusick 		if (i == STS_CHECKCOND) {
20341480Smckusick 			u_char sensebuf[128];
20441480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
20541480Smckusick 
20641480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
20741480Smckusick 					   sizeof(sensebuf));
20845750Smckusick 			if (sp->class == 7)
20945750Smckusick 				switch (sp->key) {
21045750Smckusick 				/* not ready -- might be MO with no media */
21145750Smckusick 				case 2:
21245750Smckusick 					if (sp->len == 12 &&
21345750Smckusick 					    sensebuf[12] == 10)	/* XXX */
21445750Smckusick 						ismo = 1;
21545750Smckusick 					break;
21641480Smckusick 				/* drive doing an RTZ -- give it a while */
21745750Smckusick 				case 6:
21845750Smckusick 					DELAY(1000000);
21945750Smckusick 					break;
22045750Smckusick 				default:
22145750Smckusick 					break;
22245750Smckusick 				}
22341480Smckusick 		}
22441480Smckusick 		DELAY(1000);
22541480Smckusick 	}
22645750Smckusick 	/*
22745750Smckusick 	 * Find out about device
22845750Smckusick 	 */
22945750Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq,
23045750Smckusick 			       (u_char *)&inqbuf, sizeof(inqbuf), B_READ))
23149304Shibler 		goto failed;
23241480Smckusick 	switch (inqbuf.type) {
23341480Smckusick 	case 0:		/* disk */
23441480Smckusick 	case 4:		/* WORM */
23541480Smckusick 	case 5:		/* CD-ROM */
23641480Smckusick 	case 7:		/* Magneto-optical */
23741480Smckusick 		break;
23841480Smckusick 	default:	/* not a disk */
23949304Shibler 		goto failed;
24041480Smckusick 	}
24145750Smckusick 	/*
24249304Shibler 	 * Get a usable id string
24345750Smckusick 	 */
24449304Shibler 	if (inqbuf.version != 1) {
24549304Shibler 		bcopy("UNKNOWN", &idstr[0], 8);
24649304Shibler 		bcopy("DRIVE TYPE", &idstr[8], 11);
24749304Shibler 	} else {
24849304Shibler 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
24949304Shibler 		for (i = 27; i > 23; --i)
25049304Shibler 			if (idstr[i] != ' ')
25149304Shibler 				break;
25249304Shibler 		idstr[i+1] = 0;
25349304Shibler 		for (i = 23; i > 7; --i)
25449304Shibler 			if (idstr[i] != ' ')
25549304Shibler 				break;
25649304Shibler 		idstr[i+1] = 0;
25749304Shibler 		for (i = 7; i >= 0; --i)
25849304Shibler 			if (idstr[i] != ' ')
25949304Shibler 				break;
26049304Shibler 		idstr[i+1] = 0;
26145750Smckusick 	}
26245750Smckusick 	i = scsi_immed_command(ctlr, slave, unit, &cap,
26345750Smckusick 			       (u_char *)&capbuf, sizeof(capbuf), B_READ);
26445750Smckusick 	if (i) {
26549304Shibler 		if (i != STS_CHECKCOND ||
26649304Shibler 		    bcmp(&idstr[0], "HP", 3) ||
26749304Shibler 		    bcmp(&idstr[8], "S6300.650A", 11))
26849304Shibler 			goto failed;
26945750Smckusick 		/* XXX unformatted or non-existant MO media; fake it */
27049304Shibler 		sc->sc_blks = 318664;
27149304Shibler 		sc->sc_blksize = 1024;
27245750Smckusick 	} else {
27345750Smckusick 		sc->sc_blks = *(u_int *)&capbuf[0];
27445750Smckusick 		sc->sc_blksize = *(int *)&capbuf[4];
27545750Smckusick 	}
27645750Smckusick 	/* return value of read capacity is last valid block number */
27745750Smckusick 	sc->sc_blks++;
27845750Smckusick 
27941480Smckusick 	if (inqbuf.version != 1)
28041480Smckusick 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
28141480Smckusick 			inqbuf.type, inqbuf.qual, inqbuf.version);
28249304Shibler 	else
28341480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
28441480Smckusick 			&idstr[24]);
28541480Smckusick 	printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
28653929Shibler 	if (inqbuf.qual & 0x80)
28753929Shibler 		sc->sc_flags |= SDF_RMEDIA;
28841480Smckusick 	if (sc->sc_blksize != DEV_BSIZE) {
28941480Smckusick 		if (sc->sc_blksize < DEV_BSIZE) {
29041480Smckusick 			printf("sd%d: need %d byte blocks - drive ignored\n",
29141480Smckusick 				unit, DEV_BSIZE);
29249304Shibler 			goto failed;
29341480Smckusick 		}
29441480Smckusick 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
29541480Smckusick 			++sc->sc_bshift;
29641480Smckusick 		sc->sc_blks <<= sc->sc_bshift;
29741480Smckusick 	}
29841480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
29949304Shibler 	scsi_delay(0);
30041480Smckusick 	return(inqbuf.type);
30149304Shibler failed:
30249304Shibler 	scsi_delay(0);
30349304Shibler 	return(-1);
30441480Smckusick }
30541480Smckusick 
30641480Smckusick int
30741480Smckusick sdinit(hd)
30841480Smckusick 	register struct hp_device *hd;
30941480Smckusick {
31041480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
31141480Smckusick 
31241480Smckusick 	sc->sc_hd = hd;
31353929Shibler 	sc->sc_flags = 0;
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 
36153929Shibler 	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
37449132Skarels sdopen(dev, flags, mode, p)
37541480Smckusick 	dev_t dev;
37649132Skarels 	int flags, mode;
37749132Skarels 	struct proc *p;
37841480Smckusick {
37941480Smckusick 	register int unit = sdunit(dev);
38041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
38141480Smckusick 
38241480Smckusick 	if (unit >= NSD)
38341480Smckusick 		return(ENXIO);
38449132Skarels 	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
38541480Smckusick 		return(ENXIO);
38641480Smckusick 
38741480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
38841480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
38941480Smckusick 	return(0);
39041480Smckusick }
39141480Smckusick 
39253929Shibler int
39353929Shibler sdclose(dev, flag, mode, p)
39453929Shibler 	dev_t dev;
39553929Shibler 	int flag, mode;
39653929Shibler 	struct proc *p;
39753929Shibler {
39853929Shibler 	int unit = sdunit(dev);
39953929Shibler 	register struct sd_softc *sc = &sd_softc[unit];
40053929Shibler 	int s;
40153929Shibler 
40253929Shibler 	/*
40353929Shibler 	 * XXX we should really do this for all drives.
40453929Shibler 	 */
40553929Shibler 	if (sc->sc_flags & SDF_RMEDIA) {
40653929Shibler 		s = splbio();
40753929Shibler 		while (sdtab[unit].b_active) {
40853929Shibler 			sc->sc_flags |= SDF_WANTED;
40953929Shibler 			sleep((caddr_t)&sdtab[unit], PRIBIO);
41053929Shibler 		}
41153929Shibler 		splx(s);
41253929Shibler 	}
41353929Shibler 	sc->sc_format_pid = 0;
41453929Shibler }
41553929Shibler 
41641480Smckusick /*
41741480Smckusick  * This routine is called for partial block transfers and non-aligned
41841480Smckusick  * transfers (the latter only being possible on devices with a block size
41941480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
42041480Smckusick  * using a locally allocated buffer:
42141480Smckusick  *	1. transfer any initial partial block
42241480Smckusick  *	2. transfer full blocks
42341480Smckusick  *	3. transfer any final partial block
42441480Smckusick  */
42541480Smckusick static void
42641480Smckusick sdlblkstrat(bp, bsize)
42741480Smckusick 	register struct buf *bp;
42841480Smckusick 	register int bsize;
42941480Smckusick {
43041480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
43141480Smckusick 							M_DEVBUF, M_WAITOK);
43241480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
43341480Smckusick 	register int bn, resid;
43441480Smckusick 	register caddr_t addr;
43541480Smckusick 
43641480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
43749132Skarels 	cbp->b_proc = curproc;		/* XXX */
43841480Smckusick 	cbp->b_dev = bp->b_dev;
43941480Smckusick 	bn = bp->b_blkno;
44041480Smckusick 	resid = bp->b_bcount;
44141480Smckusick 	addr = bp->b_un.b_addr;
44241480Smckusick #ifdef DEBUG
44341480Smckusick 	if (sddebug & SDB_PARTIAL)
44441480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
44541480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
44641480Smckusick #endif
44741480Smckusick 
44841480Smckusick 	while (resid > 0) {
44941480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
45041480Smckusick 		register int count;
45141480Smckusick 
45241480Smckusick 		if (boff || resid < bsize) {
45341480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
45455068Spendry 			count = min(resid, bsize - boff);
45541480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
45641480Smckusick 			cbp->b_blkno = bn - btodb(boff);
45741480Smckusick 			cbp->b_un.b_addr = cbuf;
45841480Smckusick 			cbp->b_bcount = bsize;
45941480Smckusick #ifdef DEBUG
46041480Smckusick 			if (sddebug & SDB_PARTIAL)
46141480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
46241480Smckusick 				       cbp->b_blkno, count, boff, addr);
46341480Smckusick #endif
46441480Smckusick 			sdstrategy(cbp);
46541480Smckusick 			biowait(cbp);
46641480Smckusick 			if (cbp->b_flags & B_ERROR) {
46741480Smckusick 				bp->b_flags |= B_ERROR;
46841480Smckusick 				bp->b_error = cbp->b_error;
46941480Smckusick 				break;
47041480Smckusick 			}
47141480Smckusick 			if (bp->b_flags & B_READ) {
47241480Smckusick 				bcopy(&cbuf[boff], addr, count);
47341480Smckusick 				goto done;
47441480Smckusick 			}
47541480Smckusick 			bcopy(addr, &cbuf[boff], count);
47641480Smckusick #ifdef DEBUG
47741480Smckusick 			if (sddebug & SDB_PARTIAL)
47841480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
47941480Smckusick 				       cbp->b_blkno, count, boff, addr);
48041480Smckusick #endif
48141480Smckusick 		} else {
48241480Smckusick 			count = resid & ~(bsize - 1);
48341480Smckusick 			cbp->b_blkno = bn;
48441480Smckusick 			cbp->b_un.b_addr = addr;
48541480Smckusick 			cbp->b_bcount = count;
48641480Smckusick #ifdef DEBUG
48741480Smckusick 			if (sddebug & SDB_PARTIAL)
48841480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
48941480Smckusick 				       cbp->b_blkno, count, addr);
49041480Smckusick #endif
49141480Smckusick 		}
49241480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
49341480Smckusick 		sdstrategy(cbp);
49441480Smckusick 		biowait(cbp);
49541480Smckusick 		if (cbp->b_flags & B_ERROR) {
49641480Smckusick 			bp->b_flags |= B_ERROR;
49741480Smckusick 			bp->b_error = cbp->b_error;
49841480Smckusick 			break;
49941480Smckusick 		}
50041480Smckusick done:
50141480Smckusick 		bn += btodb(count);
50241480Smckusick 		resid -= count;
50341480Smckusick 		addr += count;
50441480Smckusick #ifdef DEBUG
50541480Smckusick 		if (sddebug & SDB_PARTIAL)
50641480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
50741480Smckusick 			       bn, resid, addr);
50841480Smckusick #endif
50941480Smckusick 	}
51041480Smckusick 	free(cbuf, M_DEVBUF);
51141480Smckusick 	free(cbp, M_DEVBUF);
51241480Smckusick }
51341480Smckusick 
51441480Smckusick void
51541480Smckusick sdstrategy(bp)
51641480Smckusick 	register struct buf *bp;
51741480Smckusick {
51841480Smckusick 	register int unit = sdunit(bp->b_dev);
51941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
52045750Smckusick 	register struct size *pinfo = &sc->sc_info.part[sdpart(bp->b_dev)];
52141480Smckusick 	register struct buf *dp = &sdtab[unit];
52245750Smckusick 	register daddr_t bn;
52345750Smckusick 	register int sz, s;
52441480Smckusick 
52541480Smckusick 	if (sc->sc_format_pid) {
52649132Skarels 		if (sc->sc_format_pid != curproc->p_pid) {	/* XXX */
52741480Smckusick 			bp->b_error = EPERM;
52845750Smckusick 			bp->b_flags |= B_ERROR;
52945750Smckusick 			goto done;
53041480Smckusick 		}
53141480Smckusick 		bp->b_cylin = 0;
53241480Smckusick 	} else {
53341480Smckusick 		bn = bp->b_blkno;
53445750Smckusick 		sz = howmany(bp->b_bcount, DEV_BSIZE);
53545750Smckusick 		if (bn < 0 || bn + sz > pinfo->nblocks) {
53645750Smckusick 			sz = pinfo->nblocks - bn;
53745750Smckusick 			if (sz == 0) {
53841480Smckusick 				bp->b_resid = bp->b_bcount;
53941480Smckusick 				goto done;
54041480Smckusick 			}
54145750Smckusick 			if (sz < 0) {
54245750Smckusick 				bp->b_error = EINVAL;
54345750Smckusick 				bp->b_flags |= B_ERROR;
54445750Smckusick 				goto done;
54545750Smckusick 			}
54645750Smckusick 			bp->b_bcount = dbtob(sz);
54741480Smckusick 		}
54841480Smckusick 		/*
54941480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
55041480Smckusick 		 */
55141480Smckusick 		s = sc->sc_blksize - 1;
55241480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
55341480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
55441480Smckusick 			goto done;
55541480Smckusick 		}
55645750Smckusick 		bp->b_cylin = (bn + pinfo->strtblk) >> sc->sc_bshift;
55741480Smckusick 	}
55841480Smckusick 	s = splbio();
55941480Smckusick 	disksort(dp, bp);
56041480Smckusick 	if (dp->b_active == 0) {
56141480Smckusick 		dp->b_active = 1;
56241480Smckusick 		sdustart(unit);
56341480Smckusick 	}
56441480Smckusick 	splx(s);
56541480Smckusick 	return;
56641480Smckusick done:
56745750Smckusick 	biodone(bp);
56841480Smckusick }
56941480Smckusick 
57041480Smckusick void
57141480Smckusick sdustart(unit)
57241480Smckusick 	register int unit;
57341480Smckusick {
57441480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
57541480Smckusick 		sdstart(unit);
57641480Smckusick }
57741480Smckusick 
57850039Skarels /*
57950039Skarels  * Return:
58050039Skarels  *	0	if not really an error
58150039Skarels  *	<0	if we should do a retry
58250039Skarels  *	>0	if a fatal error
58350039Skarels  */
58445750Smckusick static int
58541480Smckusick sderror(unit, sc, hp, stat)
58641480Smckusick 	int unit, stat;
58741480Smckusick 	register struct sd_softc *sc;
58841480Smckusick 	register struct hp_device *hp;
58941480Smckusick {
59050039Skarels 	int cond = 1;
59145750Smckusick 
59241480Smckusick 	sdsense[unit].status = stat;
59341480Smckusick 	if (stat & STS_CHECKCOND) {
59441480Smckusick 		struct scsi_xsense *sp;
59541480Smckusick 
59641480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
59741480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
59841480Smckusick 				   sizeof(sdsense[unit].sense));
59941480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
60041480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
60141480Smckusick 			sp->class, sp->code);
60241480Smckusick 		if (sp->class == 7) {
60341480Smckusick 			printf(", key %d", sp->key);
60441480Smckusick 			if (sp->valid)
60541480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
60650039Skarels 			switch (sp->key) {
60750039Skarels 			/* no sense, try again */
60850039Skarels 			case 0:
60950039Skarels 				cond = -1;
61050039Skarels 				break;
61150039Skarels 			/* recovered error, not a problem */
61250039Skarels 			case 1:
61350039Skarels 				cond = 0;
61450039Skarels 				break;
61550039Skarels 			}
61641480Smckusick 		}
61741480Smckusick 		printf("\n");
61841480Smckusick 	}
61950039Skarels 	return(cond);
62041480Smckusick }
62141480Smckusick 
62241480Smckusick static void
62341480Smckusick sdfinish(unit, sc, bp)
62441480Smckusick 	int unit;
62541480Smckusick 	register struct sd_softc *sc;
62641480Smckusick 	register struct buf *bp;
62741480Smckusick {
62853929Shibler 	register struct buf *dp = &sdtab[unit];
62953929Shibler 
63053929Shibler 	dp->b_errcnt = 0;
63153929Shibler 	dp->b_actf = bp->b_actf;
63241480Smckusick 	bp->b_resid = 0;
63345750Smckusick 	biodone(bp);
63441480Smckusick 	scsifree(&sc->sc_dq);
63553929Shibler 	if (dp->b_actf)
63641480Smckusick 		sdustart(unit);
63753929Shibler 	else {
63853929Shibler 		dp->b_active = 0;
63953929Shibler 		if (sc->sc_flags & SDF_WANTED) {
64053929Shibler 			sc->sc_flags &= ~SDF_WANTED;
64153929Shibler 			wakeup((caddr_t)dp);
64253929Shibler 		}
64353929Shibler 	}
64441480Smckusick }
64541480Smckusick 
64641480Smckusick void
64741480Smckusick sdstart(unit)
64841480Smckusick 	register int unit;
64941480Smckusick {
65041480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
65141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
65241480Smckusick 
65341480Smckusick 	/*
65441480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
65541480Smckusick 	 * so check now.
65641480Smckusick 	 */
65741480Smckusick 	if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
65841480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
65941480Smckusick 		register int sts;
66041480Smckusick 
66141480Smckusick 		sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
66241480Smckusick 					 sc->sc_punit, &sdcmd[unit],
66341480Smckusick 					 bp->b_un.b_addr, bp->b_bcount,
66441480Smckusick 					 bp->b_flags & B_READ);
66541480Smckusick 		sdsense[unit].status = sts;
66641480Smckusick 		if (sts & 0xfe) {
66745750Smckusick 			(void) sderror(unit, sc, hp, sts);
66841480Smckusick 			bp->b_flags |= B_ERROR;
66941480Smckusick 			bp->b_error = EIO;
67041480Smckusick 		}
67141480Smckusick 		sdfinish(unit, sc, bp);
67241480Smckusick 
67341480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
67441480Smckusick 		sdgo(unit);
67541480Smckusick }
67641480Smckusick 
67741480Smckusick void
67841480Smckusick sdgo(unit)
67941480Smckusick 	register int unit;
68041480Smckusick {
68141480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
68241480Smckusick 	register struct hp_device *hp = sc->sc_hd;
68341480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
68441480Smckusick 	register int pad;
68541480Smckusick 	register struct scsi_fmt_cdb *cmd;
68641480Smckusick 
68741480Smckusick 	if (sc->sc_format_pid) {
68841480Smckusick 		cmd = &sdcmd[unit];
68941480Smckusick 		pad = 0;
69041480Smckusick 	} else {
69141480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
69241480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
69341480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
69441480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
69541480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
69641480Smckusick #ifdef DEBUG
69741480Smckusick 		if (pad)
69841480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
69941480Smckusick 			       unit, bp->b_bcount);
70041480Smckusick #endif
70141480Smckusick 		sdstats[unit].sdtransfers++;
70241480Smckusick 	}
70341480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
70441480Smckusick 		if (hp->hp_dk >= 0) {
70541480Smckusick 			dk_busy |= 1 << hp->hp_dk;
70641480Smckusick 			++dk_seek[hp->hp_dk];
70741480Smckusick 			++dk_xfer[hp->hp_dk];
70841480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
70941480Smckusick 		}
71041480Smckusick 		return;
71141480Smckusick 	}
71241480Smckusick #ifdef DEBUG
71341480Smckusick 	if (sddebug & SDB_ERROR)
71441480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
71541480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
71641480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
71741480Smckusick 		       sdtab[unit].b_errcnt);
71841480Smckusick #endif
71941480Smckusick 	bp->b_flags |= B_ERROR;
72041480Smckusick 	bp->b_error = EIO;
72141480Smckusick 	sdfinish(unit, sc, bp);
72241480Smckusick }
72341480Smckusick 
72441480Smckusick void
72541480Smckusick sdintr(unit, stat)
72641480Smckusick 	register int unit;
72741480Smckusick 	int stat;
72841480Smckusick {
72941480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
73041480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
73141480Smckusick 	register struct hp_device *hp = sc->sc_hd;
73250039Skarels 	int cond;
73341480Smckusick 
73441480Smckusick 	if (bp == NULL) {
73541480Smckusick 		printf("sd%d: bp == NULL\n", unit);
73641480Smckusick 		return;
73741480Smckusick 	}
73841480Smckusick 	if (hp->hp_dk >= 0)
73941480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
74041480Smckusick 	if (stat) {
74141480Smckusick #ifdef DEBUG
74241480Smckusick 		if (sddebug & SDB_ERROR)
74341480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
74441480Smckusick 				unit, stat);
74541480Smckusick #endif
74650039Skarels 		cond = sderror(unit, sc, hp, stat);
74750039Skarels 		if (cond) {
74850039Skarels 			if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
74950038Skarels #ifdef DEBUG
75050039Skarels 				if (sddebug & SDB_ERROR)
75150039Skarels 					printf("sd%d: retry #%d\n",
75250039Skarels 					       unit, sdtab[unit].b_errcnt);
75350038Skarels #endif
75450039Skarels 				sdstart(unit);
75550039Skarels 				return;
75650039Skarels 			}
75750039Skarels 			bp->b_flags |= B_ERROR;
75850039Skarels 			bp->b_error = EIO;
75945750Smckusick 		}
76041480Smckusick 	}
76141480Smckusick 	sdfinish(unit, sc, bp);
76241480Smckusick }
76341480Smckusick 
76441480Smckusick int
76549132Skarels sdread(dev, uio, flags)
76641480Smckusick 	dev_t dev;
76741480Smckusick 	struct uio *uio;
76849132Skarels 	int flags;
76941480Smckusick {
77041480Smckusick 	register int unit = sdunit(dev);
77141480Smckusick 	register int pid;
77241480Smckusick 
77349132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
77449132Skarels 	    pid != uio->uio_procp->p_pid)
77541480Smckusick 		return (EPERM);
77641480Smckusick 
77749132Skarels 	return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
77841480Smckusick }
77941480Smckusick 
78041480Smckusick int
78149132Skarels sdwrite(dev, uio, flags)
78241480Smckusick 	dev_t dev;
78341480Smckusick 	struct uio *uio;
78449132Skarels 	int flags;
78541480Smckusick {
78641480Smckusick 	register int unit = sdunit(dev);
78741480Smckusick 	register int pid;
78841480Smckusick 
78949132Skarels 	if ((pid = sd_softc[unit].sc_format_pid) &&
79049132Skarels 	    pid != uio->uio_procp->p_pid)
79141480Smckusick 		return (EPERM);
79241480Smckusick 
79349132Skarels 	return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
79441480Smckusick }
79541480Smckusick 
79641480Smckusick int
79749132Skarels sdioctl(dev, cmd, data, flag, p)
79841480Smckusick 	dev_t dev;
79941480Smckusick 	int cmd;
80041480Smckusick 	caddr_t data;
80141480Smckusick 	int flag;
80249132Skarels 	struct proc *p;
80341480Smckusick {
80441480Smckusick 	register int unit = sdunit(dev);
80541480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
80641480Smckusick 
80741480Smckusick 	switch (cmd) {
80841480Smckusick 	default:
80941480Smckusick 		return (EINVAL);
81041480Smckusick 
81141480Smckusick 	case SDIOCSFORMAT:
81241480Smckusick 		/* take this device into or out of "format" mode */
81349132Skarels 		if (suser(p->p_ucred, &p->p_acflag))
81441480Smckusick 			return(EPERM);
81541480Smckusick 
81641480Smckusick 		if (*(int *)data) {
81741480Smckusick 			if (sc->sc_format_pid)
81841480Smckusick 				return (EPERM);
81949132Skarels 			sc->sc_format_pid = p->p_pid;
82041480Smckusick 		} else
82141480Smckusick 			sc->sc_format_pid = 0;
82241480Smckusick 		return (0);
82341480Smckusick 
82441480Smckusick 	case SDIOCGFORMAT:
82541480Smckusick 		/* find out who has the device in format mode */
82641480Smckusick 		*(int *)data = sc->sc_format_pid;
82741480Smckusick 		return (0);
82841480Smckusick 
82941480Smckusick 	case SDIOCSCSICOMMAND:
83041480Smckusick 		/*
83141480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
83241480Smckusick 		 * read or write to the char device.
83341480Smckusick 		 */
83449132Skarels 		if (sc->sc_format_pid != p->p_pid)
83541480Smckusick 			return (EPERM);
83641480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
83741480Smckusick 			return (EINVAL);
83841480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
83941480Smckusick 		return (0);
84041480Smckusick 
84141480Smckusick 	case SDIOCSENSE:
84241480Smckusick 		/*
84341480Smckusick 		 * return the SCSI sense data saved after the last
84441480Smckusick 		 * operation that completed with "check condition" status.
84541480Smckusick 		 */
84641480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
84741480Smckusick 		return (0);
84841480Smckusick 
84941480Smckusick 	}
85041480Smckusick 	/*NOTREACHED*/
85141480Smckusick }
85241480Smckusick 
85341480Smckusick int
85441480Smckusick sdsize(dev)
85541480Smckusick 	dev_t dev;
85641480Smckusick {
85741480Smckusick 	register int unit = sdunit(dev);
85841480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
85941480Smckusick 
86041480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
86141480Smckusick 		return(-1);
86241480Smckusick 
86341480Smckusick 	return(sc->sc_info.part[sdpart(dev)].nblocks);
86441480Smckusick }
86541480Smckusick 
86641480Smckusick /*
86741480Smckusick  * Non-interrupt driven, non-dma dump routine.
86841480Smckusick  */
86941480Smckusick int
87041480Smckusick sddump(dev)
87141480Smckusick 	dev_t dev;
87241480Smckusick {
87341480Smckusick 	int part = sdpart(dev);
87441480Smckusick 	int unit = sdunit(dev);
87541480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
87641480Smckusick 	register struct hp_device *hp = sc->sc_hd;
87741480Smckusick 	register daddr_t baddr;
87841480Smckusick 	register int maddr;
87941480Smckusick 	register int pages, i;
88041480Smckusick 	int stat;
88141480Smckusick 	extern int lowram;
88241480Smckusick 
88341480Smckusick 	/*
88441480Smckusick 	 * Hmm... all vax drivers dump maxfree pages which is physmem minus
88541480Smckusick 	 * the message buffer.  Is there a reason for not dumping the
88641480Smckusick 	 * message buffer?  Savecore expects to read 'dumpsize' pages of
88741480Smckusick 	 * dump, where dumpsys() sets dumpsize to physmem!
88841480Smckusick 	 */
88941480Smckusick 	pages = physmem;
89041480Smckusick 
89141480Smckusick 	/* is drive ok? */
89241480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
89341480Smckusick 		return (ENXIO);
89441480Smckusick 	/* dump parameters in range? */
89541480Smckusick 	if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
89641480Smckusick 		return (EINVAL);
89741480Smckusick 	if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
89841480Smckusick 		pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
89941480Smckusick 	maddr = lowram;
90041480Smckusick 	baddr = dumplo + sc->sc_info.part[part].strtblk;
90141480Smckusick 	/* scsi bus idle? */
90241480Smckusick 	if (!scsireq(&sc->sc_dq)) {
90341480Smckusick 		scsireset(hp->hp_ctlr);
90441480Smckusick 		sdreset(sc, sc->sc_hd);
90541480Smckusick 		printf("[ drive %d reset ] ", unit);
90641480Smckusick 	}
90741480Smckusick 	for (i = 0; i < pages; i++) {
90841480Smckusick #define NPGMB	(1024*1024/NBPG)
90941480Smckusick 		/* print out how many Mbs we have dumped */
91041480Smckusick 		if (i && (i % NPGMB) == 0)
91141480Smckusick 			printf("%d ", i / NPGMB);
91241480Smckusick #undef NPBMG
91352614Smckusick 		pmap_enter(kernel_pmap, (vm_offset_t)vmmap, maddr,
91451576Smckusick 		    VM_PROT_READ, TRUE);
91541480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
91641480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
91741480Smckusick 		if (stat) {
91841480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
91941480Smckusick 			return (EIO);
92041480Smckusick 		}
92141480Smckusick 		maddr += NBPG;
92241480Smckusick 		baddr += ctod(1);
92341480Smckusick 	}
92441480Smckusick 	return (0);
92541480Smckusick }
92641480Smckusick #endif
927