xref: /csrg-svn/sys/hp300/dev/sd.c (revision 41480)
1*41480Smckusick /*
2*41480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
3*41480Smckusick  * All rights reserved.
4*41480Smckusick  *
5*41480Smckusick  * This code is derived from software contributed to Berkeley by
6*41480Smckusick  * Van Jacobson of Lawrence Berkeley Laboratory.
7*41480Smckusick  *
8*41480Smckusick  * %sccs.include.redist.c%
9*41480Smckusick  *
10*41480Smckusick  *	@(#)sd.c	7.1 (Berkeley) 05/08/90
11*41480Smckusick  */
12*41480Smckusick 
13*41480Smckusick /*
14*41480Smckusick  * SCSI CCS (Command Command Set) disk driver.
15*41480Smckusick  */
16*41480Smckusick #include "sd.h"
17*41480Smckusick #if NSD > 0
18*41480Smckusick 
19*41480Smckusick #ifndef lint
20*41480Smckusick static char rcsid[] = "$Header: sd.c,v 1.5 90/01/10 16:06:12 mike Locked $";
21*41480Smckusick #endif
22*41480Smckusick 
23*41480Smckusick #include "param.h"
24*41480Smckusick #include "systm.h"
25*41480Smckusick #include "buf.h"
26*41480Smckusick #include "errno.h"
27*41480Smckusick #include "dkstat.h"
28*41480Smckusick #include "disklabel.h"
29*41480Smckusick #include "device.h"
30*41480Smckusick #include "malloc.h"
31*41480Smckusick #include "scsireg.h"
32*41480Smckusick 
33*41480Smckusick #include "user.h"
34*41480Smckusick #include "proc.h"
35*41480Smckusick #include "uio.h"
36*41480Smckusick 
37*41480Smckusick extern int scsi_test_unit_rdy();
38*41480Smckusick extern int scsi_request_sense();
39*41480Smckusick extern int scsi_inquiry();
40*41480Smckusick extern int scsi_read_capacity();
41*41480Smckusick extern int scsi_tt_write();
42*41480Smckusick extern int scsireq();
43*41480Smckusick extern int scsiustart();
44*41480Smckusick extern int scsigo();
45*41480Smckusick extern void scsifree();
46*41480Smckusick extern void scsireset();
47*41480Smckusick 
48*41480Smckusick extern void printf();
49*41480Smckusick extern void bcopy();
50*41480Smckusick extern void disksort();
51*41480Smckusick extern int splbio();
52*41480Smckusick extern void splx();
53*41480Smckusick extern void biodone();
54*41480Smckusick extern int physio();
55*41480Smckusick extern void TBIS();
56*41480Smckusick 
57*41480Smckusick int	sdinit();
58*41480Smckusick void	sdstrategy(), sdstart(), sdustart(), sdgo(), sdintr();
59*41480Smckusick 
60*41480Smckusick struct	driver sddriver = {
61*41480Smckusick 	sdinit, "sd", (int (*)())sdstart, (int (*)())sdgo, (int (*)())sdintr,
62*41480Smckusick };
63*41480Smckusick 
64*41480Smckusick struct	size {
65*41480Smckusick 	u_long	strtblk;
66*41480Smckusick 	u_long	endblk;
67*41480Smckusick 	int	nblocks;
68*41480Smckusick };
69*41480Smckusick 
70*41480Smckusick struct sdinfo {
71*41480Smckusick 	struct	size part[8];
72*41480Smckusick };
73*41480Smckusick 
74*41480Smckusick /*
75*41480Smckusick  * since the SCSI standard tends to hide the disk structure, we define
76*41480Smckusick  * partitions in terms of DEV_BSIZE blocks.  The default partition table
77*41480Smckusick  * (for an unlabeled disk) reserves 512K for a boot area, has an 8 meg
78*41480Smckusick  * root and 32 meg of swap.  The rest of the space on the drive goes in
79*41480Smckusick  * the G partition.  As usual, the C partition covers the entire disk
80*41480Smckusick  * (including the boot area).
81*41480Smckusick  */
82*41480Smckusick struct sdinfo sddefaultpart = {
83*41480Smckusick 	     1024,   17408,   16384   ,	/* A */
84*41480Smckusick 	    17408,   82944,   65536   ,	/* B */
85*41480Smckusick 	        0,       0,       0   ,	/* C */
86*41480Smckusick 	    17408,  115712,   98304   ,	/* D */
87*41480Smckusick 	   115712,  218112,  102400   ,	/* E */
88*41480Smckusick 	   218112,       0,       0   ,	/* F */
89*41480Smckusick 	    82944,       0,       0   ,	/* G */
90*41480Smckusick 	   115712,       0,       0   ,	/* H */
91*41480Smckusick };
92*41480Smckusick 
93*41480Smckusick struct	sd_softc {
94*41480Smckusick 	struct	hp_device *sc_hd;
95*41480Smckusick 	struct	devqueue sc_dq;
96*41480Smckusick 	int	sc_format_pid;	/* process using "format" mode */
97*41480Smckusick 	short	sc_flags;
98*41480Smckusick 	short	sc_type;	/* drive type */
99*41480Smckusick 	short	sc_punit;	/* physical unit (scsi lun) */
100*41480Smckusick 	u_short	sc_bshift;	/* convert device blocks to DEV_BSIZE blks */
101*41480Smckusick 	u_int	sc_blks;	/* number of blocks on device */
102*41480Smckusick 	int	sc_blksize;	/* device block size in bytes */
103*41480Smckusick 	u_int	sc_wpms;	/* average xfer rate in 16 bit wds/sec. */
104*41480Smckusick 	struct	sdinfo sc_info;	/* drive partition table & label info */
105*41480Smckusick } sd_softc[NSD];
106*41480Smckusick 
107*41480Smckusick /* sc_flags values */
108*41480Smckusick #define	SDF_ALIVE	0x1
109*41480Smckusick 
110*41480Smckusick #ifdef DEBUG
111*41480Smckusick int sddebug = 1;
112*41480Smckusick #define SDB_ERROR	0x01
113*41480Smckusick #define SDB_PARTIAL	0x02
114*41480Smckusick #endif
115*41480Smckusick 
116*41480Smckusick struct sdstats {
117*41480Smckusick 	long	sdresets;
118*41480Smckusick 	long	sdtransfers;
119*41480Smckusick 	long	sdpartials;
120*41480Smckusick } sdstats[NSD];
121*41480Smckusick 
122*41480Smckusick struct	buf sdtab[NSD];
123*41480Smckusick struct	buf sdbuf[NSD];
124*41480Smckusick struct	scsi_fmt_cdb sdcmd[NSD];
125*41480Smckusick struct	scsi_fmt_sense sdsense[NSD];
126*41480Smckusick 
127*41480Smckusick static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
128*41480Smckusick static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
129*41480Smckusick 
130*41480Smckusick #define	sdunit(x)	((minor(x) >> 3) & 0x7)
131*41480Smckusick #define sdpart(x)	(minor(x) & 0x7)
132*41480Smckusick #define	sdpunit(x)	((x) & 7)
133*41480Smckusick #define	b_cylin		b_resid
134*41480Smckusick #define	SDRETRY		2
135*41480Smckusick 
136*41480Smckusick /*
137*41480Smckusick  * Table of scsi commands users are allowed to access via "format"
138*41480Smckusick  * mode.  0 means not legal.  1 means "immediate" (doesn't need dma).
139*41480Smckusick  * -1 means needs dma and/or wait for intr.
140*41480Smckusick  */
141*41480Smckusick static char legal_cmds[256] = {
142*41480Smckusick /*****  0   1   2   3   4   5   6   7     8   9   A   B   C   D   E   F */
143*41480Smckusick /*00*/	0,  0,  0,  0, -1,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
144*41480Smckusick /*10*/	0,  0,  1,  0,  0,  1,  0,  0,    0,  0,  1,  0,  0,  0,  0,  0,
145*41480Smckusick /*20*/	0,  0,  0,  0,  0,  1,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
146*41480Smckusick /*30*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
147*41480Smckusick /*40*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
148*41480Smckusick /*50*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
149*41480Smckusick /*60*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
150*41480Smckusick /*70*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
151*41480Smckusick /*80*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
152*41480Smckusick /*90*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
153*41480Smckusick /*a0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
154*41480Smckusick /*b0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
155*41480Smckusick /*c0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
156*41480Smckusick /*d0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
157*41480Smckusick /*e0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
158*41480Smckusick /*f0*/	0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
159*41480Smckusick };
160*41480Smckusick 
161*41480Smckusick static struct scsi_inquiry inqbuf;
162*41480Smckusick static struct scsi_fmt_cdb inq = {
163*41480Smckusick 	6,
164*41480Smckusick 	CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
165*41480Smckusick };
166*41480Smckusick 
167*41480Smckusick static u_char capbuf[8];
168*41480Smckusick struct scsi_fmt_cdb cap = {
169*41480Smckusick 	10,
170*41480Smckusick 	CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
171*41480Smckusick };
172*41480Smckusick 
173*41480Smckusick static int
174*41480Smckusick sdident(sc, hd)
175*41480Smckusick 	struct sd_softc *sc;
176*41480Smckusick 	struct hp_device *hd;
177*41480Smckusick {
178*41480Smckusick 	int unit;
179*41480Smckusick 	register int ctlr, slave;
180*41480Smckusick 	register int i;
181*41480Smckusick 	register int tries = 10;
182*41480Smckusick 
183*41480Smckusick 	ctlr = hd->hp_ctlr;
184*41480Smckusick 	slave = hd->hp_slave;
185*41480Smckusick 	unit = sc->sc_punit;
186*41480Smckusick 
187*41480Smckusick 	/*
188*41480Smckusick 	 * See if unit exists and is a disk then read block size & nblocks.
189*41480Smckusick 	 */
190*41480Smckusick 	while ((i = scsi_test_unit_rdy(ctlr, slave, unit)) != 0) {
191*41480Smckusick 		if (i == -1 || --tries < 0)
192*41480Smckusick 			/* doesn't exist or not a CCS device */
193*41480Smckusick 			return (-1);
194*41480Smckusick 		if (i == STS_CHECKCOND) {
195*41480Smckusick 			u_char sensebuf[128];
196*41480Smckusick 			struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
197*41480Smckusick 
198*41480Smckusick 			scsi_request_sense(ctlr, slave, unit, sensebuf,
199*41480Smckusick 					   sizeof(sensebuf));
200*41480Smckusick 			if (sp->class == 7 && sp->key == 6)
201*41480Smckusick 				/* drive doing an RTZ -- give it a while */
202*41480Smckusick 				DELAY(1000000);
203*41480Smckusick 		}
204*41480Smckusick 		DELAY(1000);
205*41480Smckusick 	}
206*41480Smckusick 	if (scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf,
207*41480Smckusick 			       sizeof(inqbuf), B_READ) ||
208*41480Smckusick 	    scsi_immed_command(ctlr, slave, unit, &cap, (u_char *)&capbuf,
209*41480Smckusick 			       sizeof(capbuf), B_READ))
210*41480Smckusick 		/* doesn't exist or not a CCS device */
211*41480Smckusick 		return (-1);
212*41480Smckusick 
213*41480Smckusick 	switch (inqbuf.type) {
214*41480Smckusick 	case 0:		/* disk */
215*41480Smckusick 	case 4:		/* WORM */
216*41480Smckusick 	case 5:		/* CD-ROM */
217*41480Smckusick 	case 7:		/* Magneto-optical */
218*41480Smckusick 		break;
219*41480Smckusick 	default:	/* not a disk */
220*41480Smckusick 		return (-1);
221*41480Smckusick 	}
222*41480Smckusick 	sc->sc_blks = *(u_int *)&capbuf[0];
223*41480Smckusick 	sc->sc_blksize = *(int *)&capbuf[4];
224*41480Smckusick 
225*41480Smckusick 	if (inqbuf.version != 1)
226*41480Smckusick 		printf("sd%d: type 0x%x, qual 0x%x, ver %d", hd->hp_unit,
227*41480Smckusick 			inqbuf.type, inqbuf.qual, inqbuf.version);
228*41480Smckusick 	else {
229*41480Smckusick 		char idstr[32];
230*41480Smckusick 
231*41480Smckusick 		bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
232*41480Smckusick 		for (i = 27; i > 23; --i)
233*41480Smckusick 			if (idstr[i] != ' ')
234*41480Smckusick 				break;
235*41480Smckusick 		idstr[i+1] = 0;
236*41480Smckusick 		for (i = 23; i > 7; --i)
237*41480Smckusick 			if (idstr[i] != ' ')
238*41480Smckusick 				break;
239*41480Smckusick 		idstr[i+1] = 0;
240*41480Smckusick 		for (i = 7; i >= 0; --i)
241*41480Smckusick 			if (idstr[i] != ' ')
242*41480Smckusick 				break;
243*41480Smckusick 		idstr[i+1] = 0;
244*41480Smckusick 		printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
245*41480Smckusick 			&idstr[24]);
246*41480Smckusick 	}
247*41480Smckusick 	printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
248*41480Smckusick 	if (sc->sc_blksize != DEV_BSIZE) {
249*41480Smckusick 		if (sc->sc_blksize < DEV_BSIZE) {
250*41480Smckusick 			printf("sd%d: need %d byte blocks - drive ignored\n",
251*41480Smckusick 				unit, DEV_BSIZE);
252*41480Smckusick 			return (-1);
253*41480Smckusick 		}
254*41480Smckusick 		for (i = sc->sc_blksize; i > DEV_BSIZE; i >>= 1)
255*41480Smckusick 			++sc->sc_bshift;
256*41480Smckusick 		sc->sc_blks <<= sc->sc_bshift;
257*41480Smckusick 	}
258*41480Smckusick 	sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
259*41480Smckusick 	return(inqbuf.type);
260*41480Smckusick }
261*41480Smckusick 
262*41480Smckusick int
263*41480Smckusick sdinit(hd)
264*41480Smckusick 	register struct hp_device *hd;
265*41480Smckusick {
266*41480Smckusick 	register struct sd_softc *sc = &sd_softc[hd->hp_unit];
267*41480Smckusick 
268*41480Smckusick 	sc->sc_hd = hd;
269*41480Smckusick 	sc->sc_punit = sdpunit(hd->hp_flags);
270*41480Smckusick 	sc->sc_type = sdident(sc, hd);
271*41480Smckusick 	if (sc->sc_type < 0)
272*41480Smckusick 		return(0);
273*41480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
274*41480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
275*41480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
276*41480Smckusick 	sc->sc_dq.dq_driver = &sddriver;
277*41480Smckusick 
278*41480Smckusick 	/*
279*41480Smckusick 	 * If we don't have a disk label, build a default partition
280*41480Smckusick 	 * table with 'standard' size root & swap and everything else
281*41480Smckusick 	 * in the G partition.
282*41480Smckusick 	 */
283*41480Smckusick 	sc->sc_info = sddefaultpart;
284*41480Smckusick 	/* C gets everything */
285*41480Smckusick 	sc->sc_info.part[2].nblocks = sc->sc_blks;
286*41480Smckusick 	sc->sc_info.part[2].endblk = sc->sc_blks;
287*41480Smckusick 	/* G gets from end of B to end of disk */
288*41480Smckusick 	sc->sc_info.part[6].nblocks = sc->sc_blks - sc->sc_info.part[1].endblk;
289*41480Smckusick 	sc->sc_info.part[6].endblk = sc->sc_blks;
290*41480Smckusick 	/*
291*41480Smckusick 	 * We also define the D, E and F paritions as an alternative to
292*41480Smckusick 	 * B and G.  D is 48Mb, starts after A and is intended for swapping.
293*41480Smckusick 	 * E is 50Mb, starts after D and is intended for /usr. F starts
294*41480Smckusick 	 * after E and is what ever is left.
295*41480Smckusick 	 */
296*41480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[4].endblk) {
297*41480Smckusick 		sc->sc_info.part[5].nblocks =
298*41480Smckusick 			sc->sc_blks - sc->sc_info.part[4].endblk;
299*41480Smckusick 		sc->sc_info.part[5].endblk = sc->sc_blks;
300*41480Smckusick 	} else {
301*41480Smckusick 		sc->sc_info.part[5].strtblk = 0;
302*41480Smckusick 		sc->sc_info.part[3] = sc->sc_info.part[5];
303*41480Smckusick 		sc->sc_info.part[4] = sc->sc_info.part[5];
304*41480Smckusick 	}
305*41480Smckusick 	/*
306*41480Smckusick 	 * H is a single partition alternative to E and F.
307*41480Smckusick 	 */
308*41480Smckusick 	if (sc->sc_blks >= sc->sc_info.part[3].endblk) {
309*41480Smckusick 		sc->sc_info.part[7].nblocks =
310*41480Smckusick 			sc->sc_blks - sc->sc_info.part[3].endblk;
311*41480Smckusick 		sc->sc_info.part[7].endblk = sc->sc_blks;
312*41480Smckusick 	} else {
313*41480Smckusick 		sc->sc_info.part[7].strtblk = 0;
314*41480Smckusick 	}
315*41480Smckusick 
316*41480Smckusick 	sc->sc_flags = SDF_ALIVE;
317*41480Smckusick 	return(1);
318*41480Smckusick }
319*41480Smckusick 
320*41480Smckusick void
321*41480Smckusick sdreset(sc, hd)
322*41480Smckusick 	register struct sd_softc *sc;
323*41480Smckusick 	register struct hp_device *hd;
324*41480Smckusick {
325*41480Smckusick 	sdstats[hd->hp_unit].sdresets++;
326*41480Smckusick }
327*41480Smckusick 
328*41480Smckusick int
329*41480Smckusick sdopen(dev, flags)
330*41480Smckusick 	dev_t dev;
331*41480Smckusick 	int flags;
332*41480Smckusick {
333*41480Smckusick 	register int unit = sdunit(dev);
334*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
335*41480Smckusick 
336*41480Smckusick 	if (unit >= NSD)
337*41480Smckusick 		return(ENXIO);
338*41480Smckusick 	if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(u.u_cred, &u.u_acflag))
339*41480Smckusick 		return(ENXIO);
340*41480Smckusick 
341*41480Smckusick 	if (sc->sc_hd->hp_dk >= 0)
342*41480Smckusick 		dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
343*41480Smckusick 	return(0);
344*41480Smckusick }
345*41480Smckusick 
346*41480Smckusick /*
347*41480Smckusick  * This routine is called for partial block transfers and non-aligned
348*41480Smckusick  * transfers (the latter only being possible on devices with a block size
349*41480Smckusick  * larger than DEV_BSIZE).  The operation is performed in three steps
350*41480Smckusick  * using a locally allocated buffer:
351*41480Smckusick  *	1. transfer any initial partial block
352*41480Smckusick  *	2. transfer full blocks
353*41480Smckusick  *	3. transfer any final partial block
354*41480Smckusick  */
355*41480Smckusick static void
356*41480Smckusick sdlblkstrat(bp, bsize)
357*41480Smckusick 	register struct buf *bp;
358*41480Smckusick 	register int bsize;
359*41480Smckusick {
360*41480Smckusick 	register struct buf *cbp = (struct buf *)malloc(sizeof(struct buf),
361*41480Smckusick 							M_DEVBUF, M_WAITOK);
362*41480Smckusick 	caddr_t cbuf = (caddr_t)malloc(bsize, M_DEVBUF, M_WAITOK);
363*41480Smckusick 	register int bn, resid;
364*41480Smckusick 	register caddr_t addr;
365*41480Smckusick 
366*41480Smckusick 	bzero((caddr_t)cbp, sizeof(*cbp));
367*41480Smckusick 	cbp->b_proc = u.u_procp;
368*41480Smckusick 	cbp->b_dev = bp->b_dev;
369*41480Smckusick 	bn = bp->b_blkno;
370*41480Smckusick 	resid = bp->b_bcount;
371*41480Smckusick 	addr = bp->b_un.b_addr;
372*41480Smckusick #ifdef DEBUG
373*41480Smckusick 	if (sddebug & SDB_PARTIAL)
374*41480Smckusick 		printf("sdlblkstrat: bp %x flags %x bn %x resid %x addr %x\n",
375*41480Smckusick 		       bp, bp->b_flags, bn, resid, addr);
376*41480Smckusick #endif
377*41480Smckusick 
378*41480Smckusick 	while (resid > 0) {
379*41480Smckusick 		register int boff = dbtob(bn) & (bsize - 1);
380*41480Smckusick 		register int count;
381*41480Smckusick 
382*41480Smckusick 		if (boff || resid < bsize) {
383*41480Smckusick 			sdstats[sdunit(bp->b_dev)].sdpartials++;
384*41480Smckusick 			count = MIN(resid, bsize - boff);
385*41480Smckusick 			cbp->b_flags = B_BUSY | B_PHYS | B_READ;
386*41480Smckusick 			cbp->b_blkno = bn - btodb(boff);
387*41480Smckusick 			cbp->b_un.b_addr = cbuf;
388*41480Smckusick 			cbp->b_bcount = bsize;
389*41480Smckusick #ifdef DEBUG
390*41480Smckusick 			if (sddebug & SDB_PARTIAL)
391*41480Smckusick 				printf(" readahead: bn %x cnt %x off %x addr %x\n",
392*41480Smckusick 				       cbp->b_blkno, count, boff, addr);
393*41480Smckusick #endif
394*41480Smckusick 			sdstrategy(cbp);
395*41480Smckusick 			biowait(cbp);
396*41480Smckusick 			if (cbp->b_flags & B_ERROR) {
397*41480Smckusick 				bp->b_flags |= B_ERROR;
398*41480Smckusick 				bp->b_error = cbp->b_error;
399*41480Smckusick 				break;
400*41480Smckusick 			}
401*41480Smckusick 			if (bp->b_flags & B_READ) {
402*41480Smckusick 				bcopy(&cbuf[boff], addr, count);
403*41480Smckusick 				goto done;
404*41480Smckusick 			}
405*41480Smckusick 			bcopy(addr, &cbuf[boff], count);
406*41480Smckusick #ifdef DEBUG
407*41480Smckusick 			if (sddebug & SDB_PARTIAL)
408*41480Smckusick 				printf(" writeback: bn %x cnt %x off %x addr %x\n",
409*41480Smckusick 				       cbp->b_blkno, count, boff, addr);
410*41480Smckusick #endif
411*41480Smckusick 		} else {
412*41480Smckusick 			count = resid & ~(bsize - 1);
413*41480Smckusick 			cbp->b_blkno = bn;
414*41480Smckusick 			cbp->b_un.b_addr = addr;
415*41480Smckusick 			cbp->b_bcount = count;
416*41480Smckusick #ifdef DEBUG
417*41480Smckusick 			if (sddebug & SDB_PARTIAL)
418*41480Smckusick 				printf(" fulltrans: bn %x cnt %x addr %x\n",
419*41480Smckusick 				       cbp->b_blkno, count, addr);
420*41480Smckusick #endif
421*41480Smckusick 		}
422*41480Smckusick 		cbp->b_flags = B_BUSY | B_PHYS | (bp->b_flags & B_READ);
423*41480Smckusick 		sdstrategy(cbp);
424*41480Smckusick 		biowait(cbp);
425*41480Smckusick 		if (cbp->b_flags & B_ERROR) {
426*41480Smckusick 			bp->b_flags |= B_ERROR;
427*41480Smckusick 			bp->b_error = cbp->b_error;
428*41480Smckusick 			break;
429*41480Smckusick 		}
430*41480Smckusick done:
431*41480Smckusick 		bn += btodb(count);
432*41480Smckusick 		resid -= count;
433*41480Smckusick 		addr += count;
434*41480Smckusick #ifdef DEBUG
435*41480Smckusick 		if (sddebug & SDB_PARTIAL)
436*41480Smckusick 			printf(" done: bn %x resid %x addr %x\n",
437*41480Smckusick 			       bn, resid, addr);
438*41480Smckusick #endif
439*41480Smckusick 	}
440*41480Smckusick 	free(cbuf, M_DEVBUF);
441*41480Smckusick 	free(cbp, M_DEVBUF);
442*41480Smckusick }
443*41480Smckusick 
444*41480Smckusick void
445*41480Smckusick sdstrategy(bp)
446*41480Smckusick 	register struct buf *bp;
447*41480Smckusick {
448*41480Smckusick 	register int part = sdpart(bp->b_dev);
449*41480Smckusick 	register int unit = sdunit(bp->b_dev);
450*41480Smckusick 	register int bn, sz;
451*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
452*41480Smckusick 	register struct buf *dp = &sdtab[unit];
453*41480Smckusick 	register int s;
454*41480Smckusick 
455*41480Smckusick 	if (sc->sc_format_pid) {
456*41480Smckusick 		if (sc->sc_format_pid != u.u_procp->p_pid) {
457*41480Smckusick 			bp->b_error = EPERM;
458*41480Smckusick 			goto bad;
459*41480Smckusick 		}
460*41480Smckusick 		bp->b_cylin = 0;
461*41480Smckusick 	} else {
462*41480Smckusick 		bn = bp->b_blkno;
463*41480Smckusick 		sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT;
464*41480Smckusick 		if (bn < 0 || bn + sz > sc->sc_info.part[part].nblocks) {
465*41480Smckusick 			if (bn == sc->sc_info.part[part].nblocks) {
466*41480Smckusick 				bp->b_resid = bp->b_bcount;
467*41480Smckusick 				goto done;
468*41480Smckusick 			}
469*41480Smckusick 			bp->b_error = EINVAL;
470*41480Smckusick 			goto bad;
471*41480Smckusick 		}
472*41480Smckusick 		/*
473*41480Smckusick 		 * Non-aligned or partial-block transfers handled specially.
474*41480Smckusick 		 */
475*41480Smckusick 		s = sc->sc_blksize - 1;
476*41480Smckusick 		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {
477*41480Smckusick 			sdlblkstrat(bp, sc->sc_blksize);
478*41480Smckusick 			goto done;
479*41480Smckusick 		}
480*41480Smckusick 		bp->b_cylin = (bn + sc->sc_info.part[part].strtblk) >>
481*41480Smckusick 				sc->sc_bshift;
482*41480Smckusick 	}
483*41480Smckusick 	s = splbio();
484*41480Smckusick 	disksort(dp, bp);
485*41480Smckusick 	if (dp->b_active == 0) {
486*41480Smckusick 		dp->b_active = 1;
487*41480Smckusick 		sdustart(unit);
488*41480Smckusick 	}
489*41480Smckusick 	splx(s);
490*41480Smckusick 	return;
491*41480Smckusick bad:
492*41480Smckusick 	bp->b_flags |= B_ERROR;
493*41480Smckusick done:
494*41480Smckusick 	iodone(bp);
495*41480Smckusick }
496*41480Smckusick 
497*41480Smckusick void
498*41480Smckusick sdustart(unit)
499*41480Smckusick 	register int unit;
500*41480Smckusick {
501*41480Smckusick 	if (scsireq(&sd_softc[unit].sc_dq))
502*41480Smckusick 		sdstart(unit);
503*41480Smckusick }
504*41480Smckusick 
505*41480Smckusick static void
506*41480Smckusick sderror(unit, sc, hp, stat)
507*41480Smckusick 	int unit, stat;
508*41480Smckusick 	register struct sd_softc *sc;
509*41480Smckusick 	register struct hp_device *hp;
510*41480Smckusick {
511*41480Smckusick 	sdsense[unit].status = stat;
512*41480Smckusick 	if (stat & STS_CHECKCOND) {
513*41480Smckusick 		struct scsi_xsense *sp;
514*41480Smckusick 
515*41480Smckusick 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
516*41480Smckusick 				   sc->sc_punit, sdsense[unit].sense,
517*41480Smckusick 				   sizeof(sdsense[unit].sense));
518*41480Smckusick 		sp = (struct scsi_xsense *)sdsense[unit].sense;
519*41480Smckusick 		printf("sd%d: scsi sense class %d, code %d", unit,
520*41480Smckusick 			sp->class, sp->code);
521*41480Smckusick 		if (sp->class == 7) {
522*41480Smckusick 			printf(", key %d", sp->key);
523*41480Smckusick 			if (sp->valid)
524*41480Smckusick 				printf(", blk %d", *(int *)&sp->info1);
525*41480Smckusick 		}
526*41480Smckusick 		printf("\n");
527*41480Smckusick 	}
528*41480Smckusick }
529*41480Smckusick 
530*41480Smckusick static void
531*41480Smckusick sdfinish(unit, sc, bp)
532*41480Smckusick 	int unit;
533*41480Smckusick 	register struct sd_softc *sc;
534*41480Smckusick 	register struct buf *bp;
535*41480Smckusick {
536*41480Smckusick 	sdtab[unit].b_errcnt = 0;
537*41480Smckusick 	sdtab[unit].b_actf = bp->b_actf;
538*41480Smckusick 	bp->b_resid = 0;
539*41480Smckusick 	iodone(bp);
540*41480Smckusick 	scsifree(&sc->sc_dq);
541*41480Smckusick 	if (sdtab[unit].b_actf)
542*41480Smckusick 		sdustart(unit);
543*41480Smckusick 	else
544*41480Smckusick 		sdtab[unit].b_active = 0;
545*41480Smckusick }
546*41480Smckusick 
547*41480Smckusick void
548*41480Smckusick sdstart(unit)
549*41480Smckusick 	register int unit;
550*41480Smckusick {
551*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
552*41480Smckusick 	register struct hp_device *hp = sc->sc_hd;
553*41480Smckusick 
554*41480Smckusick 	/*
555*41480Smckusick 	 * we have the SCSI bus -- in format mode, we may or may not need dma
556*41480Smckusick 	 * so check now.
557*41480Smckusick 	 */
558*41480Smckusick 	if (sc->sc_format_pid && legal_cmds[sdcmd[unit].cdb[0]] > 0) {
559*41480Smckusick 		register struct buf *bp = sdtab[unit].b_actf;
560*41480Smckusick 		register int sts;
561*41480Smckusick 
562*41480Smckusick 		sts = scsi_immed_command(hp->hp_ctlr, hp->hp_slave,
563*41480Smckusick 					 sc->sc_punit, &sdcmd[unit],
564*41480Smckusick 					 bp->b_un.b_addr, bp->b_bcount,
565*41480Smckusick 					 bp->b_flags & B_READ);
566*41480Smckusick 		sdsense[unit].status = sts;
567*41480Smckusick 		if (sts & 0xfe) {
568*41480Smckusick 			sderror(unit, sc, hp, sts);
569*41480Smckusick 			bp->b_flags |= B_ERROR;
570*41480Smckusick 			bp->b_error = EIO;
571*41480Smckusick 		}
572*41480Smckusick 		sdfinish(unit, sc, bp);
573*41480Smckusick 
574*41480Smckusick 	} else if (scsiustart(hp->hp_ctlr))
575*41480Smckusick 		sdgo(unit);
576*41480Smckusick }
577*41480Smckusick 
578*41480Smckusick void
579*41480Smckusick sdgo(unit)
580*41480Smckusick 	register int unit;
581*41480Smckusick {
582*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
583*41480Smckusick 	register struct hp_device *hp = sc->sc_hd;
584*41480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
585*41480Smckusick 	register int pad;
586*41480Smckusick 	register struct scsi_fmt_cdb *cmd;
587*41480Smckusick 
588*41480Smckusick 	if (sc->sc_format_pid) {
589*41480Smckusick 		cmd = &sdcmd[unit];
590*41480Smckusick 		pad = 0;
591*41480Smckusick 	} else {
592*41480Smckusick 		cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
593*41480Smckusick 		*(int *)(&cmd->cdb[2]) = bp->b_cylin;
594*41480Smckusick 		pad = howmany(bp->b_bcount, sc->sc_blksize);
595*41480Smckusick 		*(u_short *)(&cmd->cdb[7]) = pad;
596*41480Smckusick 		pad = (bp->b_bcount & (sc->sc_blksize - 1)) != 0;
597*41480Smckusick #ifdef DEBUG
598*41480Smckusick 		if (pad)
599*41480Smckusick 			printf("sd%d: partial block xfer -- %x bytes\n",
600*41480Smckusick 			       unit, bp->b_bcount);
601*41480Smckusick #endif
602*41480Smckusick 		sdstats[unit].sdtransfers++;
603*41480Smckusick 	}
604*41480Smckusick 	if (scsigo(hp->hp_ctlr, hp->hp_slave, sc->sc_punit, bp, cmd, pad) == 0) {
605*41480Smckusick 		if (hp->hp_dk >= 0) {
606*41480Smckusick 			dk_busy |= 1 << hp->hp_dk;
607*41480Smckusick 			++dk_seek[hp->hp_dk];
608*41480Smckusick 			++dk_xfer[hp->hp_dk];
609*41480Smckusick 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
610*41480Smckusick 		}
611*41480Smckusick 		return;
612*41480Smckusick 	}
613*41480Smckusick #ifdef DEBUG
614*41480Smckusick 	if (sddebug & SDB_ERROR)
615*41480Smckusick 		printf("sd%d: sdstart: %s adr %d blk %d len %d ecnt %d\n",
616*41480Smckusick 		       unit, bp->b_flags & B_READ? "read" : "write",
617*41480Smckusick 		       bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,
618*41480Smckusick 		       sdtab[unit].b_errcnt);
619*41480Smckusick #endif
620*41480Smckusick 	bp->b_flags |= B_ERROR;
621*41480Smckusick 	bp->b_error = EIO;
622*41480Smckusick 	sdfinish(unit, sc, bp);
623*41480Smckusick }
624*41480Smckusick 
625*41480Smckusick void
626*41480Smckusick sdintr(unit, stat)
627*41480Smckusick 	register int unit;
628*41480Smckusick 	int stat;
629*41480Smckusick {
630*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
631*41480Smckusick 	register struct buf *bp = sdtab[unit].b_actf;
632*41480Smckusick 	register struct hp_device *hp = sc->sc_hd;
633*41480Smckusick 
634*41480Smckusick 	if (bp == NULL) {
635*41480Smckusick 		printf("sd%d: bp == NULL\n", unit);
636*41480Smckusick 		return;
637*41480Smckusick 	}
638*41480Smckusick 	if (hp->hp_dk >= 0)
639*41480Smckusick 		dk_busy &=~ (1 << hp->hp_dk);
640*41480Smckusick 	if (stat) {
641*41480Smckusick #ifdef DEBUG
642*41480Smckusick 		if (sddebug & SDB_ERROR)
643*41480Smckusick 			printf("sd%d: sdintr: bad scsi status 0x%x\n",
644*41480Smckusick 				unit, stat);
645*41480Smckusick #endif
646*41480Smckusick 		sderror(unit, sc, hp, stat);
647*41480Smckusick 		bp->b_flags |= B_ERROR;
648*41480Smckusick 		bp->b_error = EIO;
649*41480Smckusick 	}
650*41480Smckusick 	sdfinish(unit, sc, bp);
651*41480Smckusick }
652*41480Smckusick 
653*41480Smckusick int
654*41480Smckusick sdread(dev, uio)
655*41480Smckusick 	dev_t dev;
656*41480Smckusick 	struct uio *uio;
657*41480Smckusick {
658*41480Smckusick 	register int unit = sdunit(dev);
659*41480Smckusick 	register int pid;
660*41480Smckusick 
661*41480Smckusick 	if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
662*41480Smckusick 		return (EPERM);
663*41480Smckusick 
664*41480Smckusick 	return(physio(sdstrategy, &sdbuf[unit], dev, B_READ, minphys, uio));
665*41480Smckusick }
666*41480Smckusick 
667*41480Smckusick int
668*41480Smckusick sdwrite(dev, uio)
669*41480Smckusick 	dev_t dev;
670*41480Smckusick 	struct uio *uio;
671*41480Smckusick {
672*41480Smckusick 	register int unit = sdunit(dev);
673*41480Smckusick 	register int pid;
674*41480Smckusick 
675*41480Smckusick 	if ((pid = sd_softc[unit].sc_format_pid) && pid != u.u_procp->p_pid)
676*41480Smckusick 		return (EPERM);
677*41480Smckusick 
678*41480Smckusick 	return(physio(sdstrategy, &sdbuf[unit], dev, B_WRITE, minphys, uio));
679*41480Smckusick }
680*41480Smckusick 
681*41480Smckusick int
682*41480Smckusick sdioctl(dev, cmd, data, flag)
683*41480Smckusick 	dev_t dev;
684*41480Smckusick 	int cmd;
685*41480Smckusick 	caddr_t data;
686*41480Smckusick 	int flag;
687*41480Smckusick {
688*41480Smckusick 	register int unit = sdunit(dev);
689*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
690*41480Smckusick 
691*41480Smckusick 	switch (cmd) {
692*41480Smckusick 	default:
693*41480Smckusick 		return (EINVAL);
694*41480Smckusick 
695*41480Smckusick 	case SDIOCSFORMAT:
696*41480Smckusick 		/* take this device into or out of "format" mode */
697*41480Smckusick 		if (suser(u.u_cred, &u.u_acflag))
698*41480Smckusick 			return(EPERM);
699*41480Smckusick 
700*41480Smckusick 		if (*(int *)data) {
701*41480Smckusick 			if (sc->sc_format_pid)
702*41480Smckusick 				return (EPERM);
703*41480Smckusick 			sc->sc_format_pid = u.u_procp->p_pid;
704*41480Smckusick 		} else
705*41480Smckusick 			sc->sc_format_pid = 0;
706*41480Smckusick 		return (0);
707*41480Smckusick 
708*41480Smckusick 	case SDIOCGFORMAT:
709*41480Smckusick 		/* find out who has the device in format mode */
710*41480Smckusick 		*(int *)data = sc->sc_format_pid;
711*41480Smckusick 		return (0);
712*41480Smckusick 
713*41480Smckusick 	case SDIOCSCSICOMMAND:
714*41480Smckusick 		/*
715*41480Smckusick 		 * Save what user gave us as SCSI cdb to use with next
716*41480Smckusick 		 * read or write to the char device.
717*41480Smckusick 		 */
718*41480Smckusick 		if (sc->sc_format_pid != u.u_procp->p_pid)
719*41480Smckusick 			return (EPERM);
720*41480Smckusick 		if (legal_cmds[((struct scsi_fmt_cdb *)data)->cdb[0]] == 0)
721*41480Smckusick 			return (EINVAL);
722*41480Smckusick 		bcopy(data, (caddr_t)&sdcmd[unit], sizeof(sdcmd[0]));
723*41480Smckusick 		return (0);
724*41480Smckusick 
725*41480Smckusick 	case SDIOCSENSE:
726*41480Smckusick 		/*
727*41480Smckusick 		 * return the SCSI sense data saved after the last
728*41480Smckusick 		 * operation that completed with "check condition" status.
729*41480Smckusick 		 */
730*41480Smckusick 		bcopy((caddr_t)&sdsense[unit], data, sizeof(sdsense[0]));
731*41480Smckusick 		return (0);
732*41480Smckusick 
733*41480Smckusick 	}
734*41480Smckusick 	/*NOTREACHED*/
735*41480Smckusick }
736*41480Smckusick 
737*41480Smckusick int
738*41480Smckusick sdsize(dev)
739*41480Smckusick 	dev_t dev;
740*41480Smckusick {
741*41480Smckusick 	register int unit = sdunit(dev);
742*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
743*41480Smckusick 
744*41480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
745*41480Smckusick 		return(-1);
746*41480Smckusick 
747*41480Smckusick 	return(sc->sc_info.part[sdpart(dev)].nblocks);
748*41480Smckusick }
749*41480Smckusick 
750*41480Smckusick #include "machine/pte.h"
751*41480Smckusick #include "machine/vmparam.h"
752*41480Smckusick #include "../h/vmmac.h"
753*41480Smckusick 
754*41480Smckusick /*
755*41480Smckusick  * Non-interrupt driven, non-dma dump routine.
756*41480Smckusick  */
757*41480Smckusick int
758*41480Smckusick sddump(dev)
759*41480Smckusick 	dev_t dev;
760*41480Smckusick {
761*41480Smckusick 	int part = sdpart(dev);
762*41480Smckusick 	int unit = sdunit(dev);
763*41480Smckusick 	register struct sd_softc *sc = &sd_softc[unit];
764*41480Smckusick 	register struct hp_device *hp = sc->sc_hd;
765*41480Smckusick 	register daddr_t baddr;
766*41480Smckusick 	register int maddr;
767*41480Smckusick 	register int pages, i;
768*41480Smckusick 	int stat;
769*41480Smckusick 	extern int lowram;
770*41480Smckusick 
771*41480Smckusick 	/*
772*41480Smckusick 	 * Hmm... all vax drivers dump maxfree pages which is physmem minus
773*41480Smckusick 	 * the message buffer.  Is there a reason for not dumping the
774*41480Smckusick 	 * message buffer?  Savecore expects to read 'dumpsize' pages of
775*41480Smckusick 	 * dump, where dumpsys() sets dumpsize to physmem!
776*41480Smckusick 	 */
777*41480Smckusick 	pages = physmem;
778*41480Smckusick 
779*41480Smckusick 	/* is drive ok? */
780*41480Smckusick 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
781*41480Smckusick 		return (ENXIO);
782*41480Smckusick 	/* dump parameters in range? */
783*41480Smckusick 	if (dumplo < 0 || dumplo >= sc->sc_info.part[part].nblocks)
784*41480Smckusick 		return (EINVAL);
785*41480Smckusick 	if (dumplo + ctod(pages) > sc->sc_info.part[part].nblocks)
786*41480Smckusick 		pages = dtoc(sc->sc_info.part[part].nblocks - dumplo);
787*41480Smckusick 	maddr = lowram;
788*41480Smckusick 	baddr = dumplo + sc->sc_info.part[part].strtblk;
789*41480Smckusick 	/* scsi bus idle? */
790*41480Smckusick 	if (!scsireq(&sc->sc_dq)) {
791*41480Smckusick 		scsireset(hp->hp_ctlr);
792*41480Smckusick 		sdreset(sc, sc->sc_hd);
793*41480Smckusick 		printf("[ drive %d reset ] ", unit);
794*41480Smckusick 	}
795*41480Smckusick 	for (i = 0; i < pages; i++) {
796*41480Smckusick #define NPGMB	(1024*1024/NBPG)
797*41480Smckusick 		/* print out how many Mbs we have dumped */
798*41480Smckusick 		if (i && (i % NPGMB) == 0)
799*41480Smckusick 			printf("%d ", i / NPGMB);
800*41480Smckusick #undef NPBMG
801*41480Smckusick 		mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V);
802*41480Smckusick 		stat = scsi_tt_write(hp->hp_ctlr, hp->hp_slave, sc->sc_punit,
803*41480Smckusick 				     vmmap, NBPG, baddr, sc->sc_bshift);
804*41480Smckusick 		if (stat) {
805*41480Smckusick 			printf("sddump: scsi write error 0x%x\n", stat);
806*41480Smckusick 			return (EIO);
807*41480Smckusick 		}
808*41480Smckusick 		maddr += NBPG;
809*41480Smckusick 		baddr += ctod(1);
810*41480Smckusick 	}
811*41480Smckusick 	return (0);
812*41480Smckusick }
813*41480Smckusick #endif
814