xref: /csrg-svn/sys/news3400/iodev/sd.c (revision 64628)
153901Smckusick /*
263307Sbostic  * Copyright (c) 1992, 1993
363307Sbostic  *	The Regents of the University of California.  All rights reserved.
453901Smckusick  *
553901Smckusick  * This code is derived from software contributed to Berkeley by
653901Smckusick  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
753901Smckusick  *
853901Smckusick  * %sccs.include.redist.c%
953901Smckusick  *
1053901Smckusick  * from: $Hdr: sd.c,v 4.300 91/06/27 20:42:56 root Rel41 $ SONY
1153901Smckusick  *
12*64628Sbostic  *	@(#)sd.c	8.2 (Berkeley) 09/23/93
1353901Smckusick  */
1453901Smckusick #define	dkblock(bp)	bp->b_blkno
1553901Smckusick 
1653901Smckusick /*
1753901Smckusick  * Copyright (c) 1987-1991 by SONY Corporation.
1853901Smckusick  */
1953901Smckusick 
2053901Smckusick #include "sd.h"
2153901Smckusick #if NSD > 0
2253901Smckusick 
2357182Sutashiro #include <sys/param.h>
2457182Sutashiro #include <sys/buf.h>
2557182Sutashiro #include <sys/proc.h>
2657182Sutashiro #include <sys/user.h>
2757182Sutashiro #include <sys/dkstat.h>
2857182Sutashiro #include <sys/uio.h>
2957182Sutashiro #include <sys/kernel.h>
3057182Sutashiro #include <sys/reboot.h>
3157182Sutashiro #include <sys/ioctl.h>
3257182Sutashiro #include <sys/systm.h>
3357182Sutashiro #include <sys/mtio.h>
3457182Sutashiro #include <sys/stat.h>
3557182Sutashiro #include <sys/disklabel.h>
3657182Sutashiro #include <vm/vm.h>
3757182Sutashiro #include <sys/syslog.h>
3853901Smckusick 
3957182Sutashiro #include <ufs/ffs/fs.h>
4053901Smckusick 
4157182Sutashiro # include <machine/cpu.h>
4253901Smckusick 
4353901Smckusick #ifdef IPC_MRX
4453901Smckusick # include "../iop/iopvar.h"
4553901Smckusick # include "../ipc/newsipc.h"
4653901Smckusick #endif
4753901Smckusick 
4853901Smckusick #ifdef CPU_SINGLE
4957182Sutashiro # include <news3400/hbdev/hbvar.h>
5057182Sutashiro # include <news3400/iodev/ioptohb.h>
5153901Smckusick #endif
5253901Smckusick 
5357182Sutashiro #include <news3400/iodev/scsireg.h>
5457182Sutashiro #include <news3400/iodev/scu.h>
5557182Sutashiro #include <news3400/iodev/dkio.h>
5657182Sutashiro #include <news3400/iodev/sdreg.h>
5753901Smckusick 
5853901Smckusick #define	sce_sdecode	sce_hdecode
5953901Smckusick 
6053901Smckusick #define	dev2unit(x)	((minor(x) & ~0x80) >> 3)
6153901Smckusick #define	dev2part(x)	(minor(x) & 0x7)
6253901Smckusick 
6353901Smckusick /* /sys/sys/file.h */
6453901Smckusick #define	FREAD		00001		/* descriptor read/receive'able */
6553901Smckusick #define	FWRITE		00002		/* descriptor write/send'able */
6653901Smckusick 
6753901Smckusick #define	PART_A		0
6853901Smckusick #define	PART_B		1
6953901Smckusick #define	PART_C		2
7053901Smckusick #define	PART_D		3
7153901Smckusick #define	PART_E		4
7253901Smckusick #define	PART_F		5
7353901Smckusick #define	PART_G		6
7453901Smckusick #define	PART_H		7
7553901Smckusick 
7653901Smckusick #define	MAXPROBERETRY	100
7753901Smckusick #define	NRETRY		10
7853901Smckusick #define	MAXHRDERR	100
7953901Smckusick #define	MAXRETRYCNT	16
8053901Smckusick 
8153901Smckusick #define	SDBSIZE1K	(DEV_BSIZE * 2)
8253901Smckusick #define	MAXSDPHYS	((NSCMAP - 1) * NBPG)
8353901Smckusick 
8453901Smckusick #define	D100MSEC	100000
8553901Smckusick 
8653901Smckusick #if OD_STOPTIME < 1
8753901Smckusick # define	OD_STOPTIME	5
8853901Smckusick #endif /* OD_STOPTIME < 1 */
8953901Smckusick 
9053901Smckusick #define FORMAT_MODE_CORRUPTED	0x31
9153901Smckusick #define	ONLY_ONE	1
9253901Smckusick 
9353901Smckusick /************** PARTITIONS *************************************/
9453901Smckusick 
9553901Smckusick #define	PART_UNUSED	(0)
9653901Smckusick #define	PART_SPEC	(-1)
9753901Smckusick #define	PART_CALCF	(-2)
9853901Smckusick #define	PART_CALCG	(-3)
9953901Smckusick 
10053901Smckusick struct defpart {
10153901Smckusick 	int range_min;
10253901Smckusick 	int range_max;
10353901Smckusick 	int partsize[PNUM];
10453901Smckusick };
10553901Smckusick 
10653901Smckusick struct defpart defpart_std[] = {
10753901Smckusick 	{
10853901Smckusick 		0,		/* range_min */
10953901Smckusick 		20,		/* range_max */
11053901Smckusick 
11153901Smckusick 		  PART_SPEC,		/* A: */
11253901Smckusick 		PART_UNUSED,		/* B: */
11353901Smckusick 		  PART_SPEC,		/* C: */
11453901Smckusick 		PART_UNUSED,		/* D: */
11553901Smckusick 		PART_UNUSED,		/* E: */
11653901Smckusick 		PART_UNUSED,		/* F: */
11753901Smckusick 		PART_UNUSED,		/* G: */
11853901Smckusick 		PART_UNUSED,		/* H: */
11953901Smckusick 	},
12053901Smckusick 	{
12153901Smckusick 		20,		/* range_min */
12253901Smckusick 		61,		/* range_max */
12353901Smckusick 
12453901Smckusick 		      15884,		/* A: */
12553901Smckusick 		      10032,		/* B: */
12653901Smckusick 		  PART_SPEC,		/* C: */
12753901Smckusick 		      15884,		/* D: */
12853901Smckusick 		PART_UNUSED,		/* E: */
12953901Smckusick 		 PART_CALCF,		/* F: */
13053901Smckusick 		 PART_CALCG,		/* G: */
13153901Smckusick 		PART_UNUSED,		/* H: */
13253901Smckusick 	},
13353901Smckusick 	{
13453901Smckusick 		61,		/* range_min */
13553901Smckusick 		206,		/* range_max */
13653901Smckusick 
13753901Smckusick 		      15884,		/* A: */
13853901Smckusick 		      33440,		/* B: */
13953901Smckusick 		  PART_SPEC,		/* C: */
14053901Smckusick 		      15884,		/* D: */
14153901Smckusick 		      55936,		/* E: */
14253901Smckusick 		 PART_CALCF,		/* F: */
14353901Smckusick 		 PART_CALCG,		/* G: */
14453901Smckusick 		PART_UNUSED,		/* H: */
14553901Smckusick 	},
14653901Smckusick 	{
14753901Smckusick 		206,		/* range_min */
14853901Smckusick 		356,		/* range_max */
14953901Smckusick 
15053901Smckusick 		      15884,		/* A: */
15153901Smckusick 		      33440,		/* B: */
15253901Smckusick 		  PART_SPEC,		/* C: */
15353901Smckusick 		      15884,		/* D: */
15453901Smckusick 		      55936,		/* E: */
15553901Smckusick 		 PART_CALCF,		/* F: */
15653901Smckusick 		 PART_CALCG,		/* G: */
15753901Smckusick 		     291346,		/* H: */
15853901Smckusick 	},
15953901Smckusick 	{
16053901Smckusick 		356,		/* range_min */
16153901Smckusick 		99999999,	/* range_max */
16253901Smckusick 
16353901Smckusick 		      15884,		/* A: */
16453901Smckusick 		      66880,		/* B: */
16553901Smckusick 		  PART_SPEC,		/* C: */
16653901Smckusick 		      15884,		/* D: */
16753901Smckusick 		     307200,		/* E: */
16853901Smckusick 		 PART_CALCF,		/* F: */
16953901Smckusick 		 PART_CALCG,		/* G: */
17053901Smckusick 		     291346,		/* H: */
17153901Smckusick 	},
17253901Smckusick 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
17353901Smckusick };
17453901Smckusick 
17553901Smckusick /************* ADDITIONAL SENSE ERROR CODES *************************/
17653901Smckusick 
17753901Smckusick struct msg_list {
17853901Smckusick 	int	ml_code;		/* message code */
17953901Smckusick 	int	ml_msglvl;		/* message level */
18053901Smckusick 	char	*ml_msgstr;		/* message string */
18153901Smckusick };
18253901Smckusick 
18353901Smckusick #define	sdskeylist	skeylist
18453901Smckusick 
18553901Smckusick struct msg_list ecodelist_mo[] = {
18653901Smckusick 	{ 0x80, 0, NULL },
18753901Smckusick 	{ 0x81, 0, NULL },
18853901Smckusick 	{ 0x82, 0, NULL },
18953901Smckusick 	{ 0x83, 0, NULL },
19053901Smckusick 
19153901Smckusick 	{ -1,   0, NULL }
19253901Smckusick };
19353901Smckusick 
19453901Smckusick /************** Ref. sd_var.c ********************************/
19553901Smckusick 
19653901Smckusick extern struct iop/**/_ctlr *sdminfo[];
19753901Smckusick extern struct iop/**/_device *sddinfo[];
19853901Smckusick extern struct iop/**/_device *sdip[][MAXSLAVE];
19953901Smckusick 
20053901Smckusick extern struct buf rsdbuf[];		/* buffer for raw I/O */
20153901Smckusick extern struct buf csdbuf[];		/* buffer for controll */
20253901Smckusick extern struct buf sdutab[];		/* per drive buffers */
20353901Smckusick 
20453901Smckusick extern struct sdc_softc sdc_softc[];
20553901Smckusick extern struct sdd_softc sdd_softc[];
20653901Smckusick extern u_char sd_b_openf[][PNUM];
20753901Smckusick extern u_char sd_c_openf[][PNUM];
20853901Smckusick 
20953901Smckusick extern struct scsi kernscsi[];
21053901Smckusick extern struct sdst sdstdrv[];
21153901Smckusick extern struct disklabel sdlabel[];
21253901Smckusick extern struct size sdsizedrv[][PNUM];
21353901Smckusick 
21453901Smckusick extern u_char sdc_rsense[][RSEN_CNT];
21553901Smckusick 
21653901Smckusick extern struct sync_param sd_sync_param[];
21753901Smckusick 
21853901Smckusick extern int nsd;
21953901Smckusick extern int nsdc;
22053901Smckusick 
22153901Smckusick /************** Ref. sddefs.c *********************************/
22253901Smckusick 
22353901Smckusick extern struct sddevinfo sddevinfo[];
22453901Smckusick 
22553901Smckusick /**************************************************************/
22653901Smckusick 
22753901Smckusick extern struct msg_list skeylist[];
22853901Smckusick extern struct msg_list ecodelist[];
22953901Smckusick 
23053901Smckusick extern int	boothowto;
23153901Smckusick extern int	rsense_msg_disp;	/* RSENSE-message display flag */
23253901Smckusick extern int	mo_disp_format;		/* MO format mode display flag */
23353901Smckusick 
23453901Smckusick int sd_ignore_error;
23553901Smckusick 
23653901Smckusick static int re_init_done;
23753901Smckusick 
23853901Smckusick static u_char sdwork[2340];		/* buffer for error recovery */
23953901Smckusick static u_char sdtmp[DEV_BSIZE];		/* buffer for temporary */
24053901Smckusick #ifdef mips
24153901Smckusick volatile static int sdtmp_stat = 0;	/* status of sdtmp */
24253901Smckusick #else
24353901Smckusick static int sdtmp_stat = 0;		/* status of sdtmp */
24453901Smckusick #endif
24553901Smckusick 
24653901Smckusick char	pname[] = "abcdefgh";
24753901Smckusick 
24853901Smckusick struct scsi *get_scsi();
24953901Smckusick struct sc_map *get_sc_map();
25053901Smckusick struct sc_inq *get_sc_inq();
25153901Smckusick 
25253901Smckusick int	sdprobe(), sdslave(), sdattach(), sddgo(), sdintr();
25353901Smckusick int	sdwstart, sdwatch(), sdstop();	/* Have started guardian */
25453901Smckusick void	sdexec();
25553901Smckusick 
25657173Sutashiro static sd_check(), sd_tstdrv(), sd_other_pages(), sd_err_rcv(), sd_synctr_on();
25757173Sutashiro static disklabel2sdst(), sdst2disklabel(), sd_scu_exec();
25857173Sutashiro 
25953901Smckusick #ifdef CPU_SINGLE
26053901Smckusick struct hb_driver sdcdriver =
26153901Smckusick     {sdprobe, sdslave, sdattach, sddgo, sdintr, "sd", sddinfo, "sdc", sdminfo};
26253901Smckusick #else
26353901Smckusick struct iop_driver sdcdriver =
26453901Smckusick     {sdprobe, sdslave, sdattach, sddgo, "sd", sddinfo, "sdc", sdminfo};
26553901Smckusick #endif
26653901Smckusick 
26753901Smckusick /*ARGSUSED*/
26853901Smckusick sdprobe(im)
26953901Smckusick 	struct iop/**/_ctlr *im;
27053901Smckusick {
27153901Smckusick 	static int sdd_init = 0;
27253901Smckusick 	register struct sc_inq *sci;
27353901Smckusick 	register int ctlr;
27453901Smckusick 	register int fw;
27553901Smckusick 	int i;
27653901Smckusick 
27753901Smckusick 	if (sdd_init == 0) {
27853901Smckusick 		sdd_init++;
27953901Smckusick 		for (i = 0; i < nsd; i++)
28053901Smckusick 			sdd_softc[i].sdd_start = -2;
28153901Smckusick 	}
28253901Smckusick 
28353901Smckusick 	sci = get_sc_inq(im->im_intr);
28453901Smckusick 	ctlr = im->im_ctlr;
28553901Smckusick 	/*
28653901Smckusick 	 * Check device type
28753901Smckusick 	 *	0x00: Direct access device.
28853901Smckusick 	 *	0x01: Sequential access device.
28953901Smckusick 	 *	0x04: Write-once read-multiple device.
29053901Smckusick 	 *	0x05: Read-only Direct-access device.
29153901Smckusick 	 *	0x7f: Specified device is nonexistent.
29253901Smckusick 	 */
29353901Smckusick 	fw = sdc_softc[ctlr].sdc_firmware & ~SDCFW_DEVMASK;
29453901Smckusick 
29553901Smckusick 	switch (sci->sci_devtype) {
29653901Smckusick 
29753901Smckusick 	case 0x00:
29853901Smckusick 		/*
29953901Smckusick 		 * Assumed that the device is HD.
30053901Smckusick 		 *	Later, distinguish MO from HD.
30153901Smckusick 		 */
30253901Smckusick 		sdc_softc[ctlr].sdc_firmware = fw | SDCFW_HD;
30353901Smckusick 		break;
30453901Smckusick 
30553901Smckusick 	default:
30653901Smckusick 		/*
30753901Smckusick 		 * device type mis-match
30853901Smckusick 		 */
30953901Smckusick 		return (0);
31053901Smckusick 	}
31153901Smckusick 
31253901Smckusick 	/*
31353901Smckusick 	 * Set interrupt handler routine
31453901Smckusick 	 */
31553901Smckusick 	if (set_inthandler(im, sdintr) == 0)
31653901Smckusick 		return (0);
31753901Smckusick 
31853901Smckusick 	return (1);
31953901Smckusick }
32053901Smckusick 
32153901Smckusick 
32253901Smckusick /*ARGSUSED*/
sdslave(ii,reg,intr)32353901Smckusick sdslave(ii, reg, intr)
32453901Smckusick 	register struct iop/**/_device *ii;
32553901Smckusick 	caddr_t reg;
32653901Smckusick 	int intr;
32753901Smckusick {
32853901Smckusick 	register struct scsi *sc;
32953901Smckusick 
33053901Smckusick 	sc = get_scsi(intr);
33153901Smckusick 	sdip[ii->ii_ctlr][ii->ii_slave] = ii;
33253901Smckusick 	ii->ii_intr = intr;
33353901Smckusick 
33453901Smckusick 	/*
33553901Smckusick 	 * check what the device is.
33653901Smckusick 	 */
33753901Smckusick 	if ((ii->ii_type = sd_check(ii, sc)) < 0)
33853901Smckusick 		goto bad_slave;
33953901Smckusick 
34053901Smckusick 	/*
34153901Smckusick 	 * set up ERROR RECOVERY PARAMETERS
34253901Smckusick 	 */
34353901Smckusick 	if (sd_err_rcv(ii, sc) < 0)
34453901Smckusick 		goto bad_slave;
34553901Smckusick 
34653901Smckusick 	/*
34753901Smckusick 	 * set up OTHER PARAMETERS
34853901Smckusick 	 */
34953901Smckusick 	if (sd_other_pages(ii, sc) < 0)
35053901Smckusick 		goto bad_slave;
35153901Smckusick 
35253901Smckusick 	/*
35353901Smckusick 	 * set up Synchronous Transfer
35453901Smckusick 	 */
35553901Smckusick 	sd_synctr_on(ii, sc);
35653901Smckusick 
35753901Smckusick 	return (1);
35853901Smckusick 
35953901Smckusick bad_slave:
36053901Smckusick 	/*
36153901Smckusick 	 * no such slave
36253901Smckusick 	 */
36353901Smckusick 	ii->ii_intr = -1;
36453901Smckusick 	return (0);
36553901Smckusick }
36653901Smckusick 
identity_check(sci,capacity,unit)36753901Smckusick identity_check(sci, capacity, unit)
36853901Smckusick 	register struct sc_inq *sci;
36953901Smckusick 	int capacity;
37053901Smckusick 	int unit;
37153901Smckusick {
37253901Smckusick 	register struct sddevinfo *sdi;
37353901Smckusick 	register u_char *id_name;
37453901Smckusick 	register int index;
37553901Smckusick 	register int i;
37653901Smckusick 	int id_pass;
37753901Smckusick 
37853901Smckusick 	id_name = sci->sci_vendid;
37953901Smckusick 	while (*id_name == ' ')
38053901Smckusick 		id_name++;
38153901Smckusick 
38253901Smckusick 	index = UNKNOWN_DISK;
38353901Smckusick 	id_pass = 0;
38453901Smckusick 	for (sdi = sddevinfo; sdi->id_len >= 0; sdi++) {
38553901Smckusick 		/*
38653901Smckusick 		 * check vendor & product ID
38753901Smckusick 		 */
38853901Smckusick 		if (strncmp(id_name, sdi->id_name, sdi->id_len) != 0)
38953901Smckusick 			continue;
39053901Smckusick 		id_pass = sdi - sddevinfo;
39153901Smckusick 
39253901Smckusick 		/*
39353901Smckusick 		 * check revision
39453901Smckusick 		 */
39553901Smckusick 		if (strncmp(sdi->revs, sci->sci_revision, 4) == 0)
39653901Smckusick 			index = id_pass;
39753901Smckusick 		else {
39853901Smckusick 			for (i = 0; i < 4; i++) {
39953901Smckusick 				if (*(sdi->revs + i) == '?')
40053901Smckusick 					continue;
40153901Smckusick 				if (*(sdi->revs + i) != sci->sci_revision[i])
40253901Smckusick 					break;
40353901Smckusick 			}
40453901Smckusick 			if (i < 4)
40553901Smckusick 				continue;
40653901Smckusick 		}
40753901Smckusick 
40853901Smckusick 		/*
40953901Smckusick 		 * check capacity
41053901Smckusick 		 */
41153901Smckusick 		if (capacity == -1)
41253901Smckusick 			break;
41353901Smckusick 		if (sdi->capacity == -1) {
41453901Smckusick 			printf("sd%d: capacity=0x%x(%d)\n",
41553901Smckusick 				unit, capacity, capacity);
41653901Smckusick 			break;
41753901Smckusick 		}
41853901Smckusick 		if (capacity == sdi->capacity)
41953901Smckusick 			break;
42053901Smckusick 	}
42153901Smckusick 	if (index == 0)
42253901Smckusick 		index = id_pass;
42353901Smckusick 
42453901Smckusick 	return (index);
42553901Smckusick }
42653901Smckusick 
search_index(type)42753901Smckusick search_index(type)
42853901Smckusick 	register int type;
42953901Smckusick {
43053901Smckusick 	register struct sddevinfo *sdi;
43153901Smckusick 	register int i;
43253901Smckusick 	int index;
43353901Smckusick 
43453901Smckusick 	index = UNKNOWN_DISK;
43553901Smckusick 	i = 0;
43653901Smckusick 	for (sdi = sddevinfo; sdi->id_len > 0; sdi++) {
43753901Smckusick 		if (sdi->type == type) {
43853901Smckusick 			index = i;
43953901Smckusick 			break;
44053901Smckusick 		}
44153901Smckusick 		i++;
44253901Smckusick 	}
44353901Smckusick 	return (index);
44453901Smckusick }
44553901Smckusick 
44653901Smckusick static
sd_check(ii,sc)44753901Smckusick sd_check(ii, sc)
44853901Smckusick 	register struct iop/**/_device *ii;
44953901Smckusick 	register struct scsi *sc;
45053901Smckusick {
45153901Smckusick 	register struct sc_inq *sci;
45253901Smckusick 	register struct sc_rcap *scr;
45353901Smckusick 	register int intr;
45453901Smckusick 	register int slave;
45553901Smckusick 	register int unit;
45653901Smckusick 	struct sdc_softc *sdc;
45753901Smckusick 	struct sdd_softc *sdd;
45853901Smckusick 	struct sc_extnd *sce;
45953901Smckusick 	int retrycnt;
46053901Smckusick 	int index;
46153901Smckusick 	int media_in;
46253901Smckusick 
46353901Smckusick 	intr = ii->ii_intr;
46453901Smckusick 	slave = ii->ii_slave;
46553901Smckusick 	unit = ii->ii_unit;
46653901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
46753901Smckusick 	sdd = &sdd_softc[unit];
46853901Smckusick 	scr = (struct sc_rcap *)sc->sc_param;
46953901Smckusick 	sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
47053901Smckusick 
47153901Smckusick 	/*
47253901Smckusick 	 * check if the logical unit is ready.
47353901Smckusick 	 *	(by TEST UNIT READY command)
47453901Smckusick 	 */
47553901Smckusick 	media_in = sd_tstdrv(ii, sc);
47653901Smckusick 	if (media_in < 0)
47753901Smckusick 		return (-3);
47853901Smckusick 
47953901Smckusick 	/*
48053901Smckusick 	 * Get controller and drive information.
48153901Smckusick 	 *	(by INQUIRY command)
48253901Smckusick 	 */
48353901Smckusick 	retrycnt = 0;
48453901Smckusick 	sci = get_sc_inq(intr);
48553901Smckusick loop_inq:
48653901Smckusick 	if (retrycnt++ > MAXPROBERETRY)
48753901Smckusick 		return (-1);
48853901Smckusick 
48953901Smckusick 	scop_inquiry(intr, sc, slave, SCSI_INTDIS, sizeof(struct sc_inq), sci);
49053901Smckusick 	sc->sc_tstatus &= TGSTMASK;
49153901Smckusick 
49253901Smckusick 	if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
49353901Smckusick 
49453901Smckusick 		bzero((caddr_t)sce, RSEN_CNT);
49553901Smckusick 		scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
49653901Smckusick 				(caddr_t)sce);
49753901Smckusick 		sc->sc_tstatus &= TGSTMASK;
49853901Smckusick 		if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD)
49953901Smckusick 			return (-1);
50053901Smckusick 		if (sce->sce_extend != 0x70)
50153901Smckusick 			goto loop_inq;
50253901Smckusick 
50353901Smckusick 		switch (sce->sce_sdecode) {
50453901Smckusick 
50553901Smckusick 		case 0x04:	/* Drive Not Ready */
50653901Smckusick 		case 0x28:	/* Medium Changed */
50753901Smckusick 		case 0x29:	/* Power On or Reset or Bus Device Reset */
50853901Smckusick 		case 0x2a:	/* Mode Select Parameter Changed */
50953901Smckusick 			break;
51053901Smckusick 
51153901Smckusick 		default:
51253901Smckusick 			return (-1);
51353901Smckusick 		}
51453901Smckusick 		DELAY(D100MSEC);		/* wait 100 ms. */
51553901Smckusick 		goto loop_inq;
51653901Smckusick 	}
51753901Smckusick 
51853901Smckusick 	index = identity_check(sci, -1, unit);
51953901Smckusick 
52053901Smckusick 	switch (sddevinfo[index].type) {
52153901Smckusick 
52253901Smckusick 	case SMO_S501:
52353901Smckusick 	case SMO_S501_ISO:
52453901Smckusick 	case SMO_S501_ISO2:
52553901Smckusick 		sdc->sdc_firmware =
52653901Smckusick 			SDCFW_MO | (sdc->sdc_firmware & ~SDCFW_DEVMASK);
52753901Smckusick 		break;
52853901Smckusick 
52953901Smckusick 	defaults:
53053901Smckusick 		break;
53153901Smckusick 	}
53253901Smckusick 
53353901Smckusick 	if (sci->sci_qual & 0x80) {
53453901Smckusick 		/*
53553901Smckusick 		 * removable medium device
53653901Smckusick 		 */
53753901Smckusick 		sdc->sdc_firmware |= SDCFW_RMB;
53853901Smckusick 		if ((media_in == 0) || ((sdc->sdc_firmware & SDCFW_MO) == 0))
53953901Smckusick 			return (index);
54053901Smckusick 	}
54153901Smckusick 
54253901Smckusick 	/****************/
54353901Smckusick 	/* HD & MO only */
54453901Smckusick 	/****************/
54553901Smckusick 	/*
54653901Smckusick 	 * Get drive capacity
54753901Smckusick 	 *	(by READ CAPACITY command)
54853901Smckusick 	 */
54953901Smckusick 	retrycnt = 0;
55053901Smckusick loop_rcap:
55153901Smckusick 	if (retrycnt++ > MAXPROBERETRY)
55253901Smckusick 		return (-4);
55353901Smckusick 
55453901Smckusick 	scop_rcap(intr, sc, slave, SCSI_INTDIS, 8, (caddr_t)0);
55553901Smckusick 	sc->sc_tstatus &= TGSTMASK;
55653901Smckusick 	if (sc->sc_istatus != INST_EP)
55753901Smckusick 		return (-5);
55853901Smckusick 	if (sc->sc_tstatus == TGST_CC) {
55953901Smckusick 		bzero((caddr_t)sce, RSEN_CNT);
56053901Smckusick 		scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
56153901Smckusick 				(caddr_t)sce);
56253901Smckusick 		sc->sc_tstatus &= TGSTMASK;
56353901Smckusick 		if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD)
56453901Smckusick 			return (-6);
56553901Smckusick 		if (sderrordisp((caddr_t)sce, ii) == FORMAT_MODE_CORRUPTED) {
56653901Smckusick 			scr->scr_nblock = 0;
56753901Smckusick 			scr->scr_blocklen = DEV_BSIZE;
56853901Smckusick 			sdd->sdd_flags |= SDDF_NONFMT;
56953901Smckusick 		} else {
57053901Smckusick 			DELAY(D100MSEC);		/* wait 100 ms. */
57153901Smckusick 			goto loop_rcap;
57253901Smckusick 		}
57353901Smckusick 	}
57453901Smckusick 	else if (sc->sc_tstatus != TGST_GOOD) {
57553901Smckusick 		DELAY(D100MSEC);		/* wait 100 ms. */
57653901Smckusick 		goto loop_rcap;
57753901Smckusick 	}
57853901Smckusick 
57953901Smckusick 	sdd->sdd_nsect = scr->scr_nblock + 1;
58053901Smckusick 	sdd->sdd_sectsize = scr->scr_blocklen;
58153901Smckusick 
58253901Smckusick 	index = identity_check(sci, scr->scr_nblock +1, unit);
58353901Smckusick 
58453901Smckusick 	return (index);
58553901Smckusick }
58653901Smckusick 
58753901Smckusick static
sd_tstdrv(ii,sc)58853901Smckusick sd_tstdrv(ii, sc)
58953901Smckusick 	register struct iop/**/_device *ii;
59053901Smckusick 	register struct scsi *sc;
59153901Smckusick {
59253901Smckusick 	register struct sc_extnd *sce;
59353901Smckusick 	register int intr;
59453901Smckusick 	register int slave;
59553901Smckusick 	register int retrycnt;
59653901Smckusick 	struct sdc_softc *sdc;
59753901Smckusick 	struct sdd_softc *sdd;
59853901Smckusick 
59953901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
60053901Smckusick 	sdd = &sdd_softc[ii->ii_unit];
60153901Smckusick 
60253901Smckusick 	intr = ii->ii_intr;
60353901Smckusick 	slave = ii->ii_slave;
60453901Smckusick 	sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
60553901Smckusick 	retrycnt = 0;
60653901Smckusick loop_tst:
60753901Smckusick 	if (retrycnt++ > MAXPROBERETRY)
60853901Smckusick 		return (-1);
60953901Smckusick 
61053901Smckusick 	scop_tst(intr, sc, slave, SCSI_INTDIS);
61153901Smckusick 	sc->sc_tstatus &= TGSTMASK;
61253901Smckusick 	if (sc->sc_istatus != INST_EP) {
61353901Smckusick 		DELAY(D100MSEC);		/* wait 100 ms. */
61453901Smckusick 		goto loop_tst;
61553901Smckusick 	}
61653901Smckusick 
61753901Smckusick 	switch (sc->sc_tstatus) {
61853901Smckusick 
61953901Smckusick 	case TGST_CC:
62053901Smckusick 		/* Get error code */
62153901Smckusick 		bzero((caddr_t)sce, RSEN_CNT);
62253901Smckusick 		scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
62353901Smckusick 				(caddr_t)sce);
62453901Smckusick 		sc->sc_tstatus &= TGSTMASK;
62553901Smckusick 		if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
62653901Smckusick 			DELAY(D100MSEC);	/* wait 100 ms. */
62753901Smckusick 			goto loop_tst;
62853901Smckusick 		}
62953901Smckusick 
63053901Smckusick 		if (sce->sce_extend != 0x70)
63153901Smckusick 			goto loop_tst;
63253901Smckusick 
63353901Smckusick 		switch (sce->sce_skey) {
63453901Smckusick 
63553901Smckusick 		case 0x0:		/* No Sense */
63653901Smckusick 		case 0x4:		/* Hardware error */
63753901Smckusick 		case 0x6:		/* Unit attention */
63853901Smckusick 			goto loop_tst;
63953901Smckusick 
64053901Smckusick 		case 0x2:		/* Not ready */
64153901Smckusick 			switch (sce->sce_sdecode) {
64253901Smckusick 
64353901Smckusick 			case 0x04:	/* Not ready */
64453901Smckusick 				/*
64553901Smckusick 				 * Drive not ready... so start..
64653901Smckusick 				 */
64753901Smckusick 				scop_stst(intr, sc, slave, SCSI_INTDIS, SDSS_START);
64853901Smckusick 				DELAY(D100MSEC * 10);	/* wait 1 sec. */
64953901Smckusick 				goto loop_tst;
65053901Smckusick 
65153901Smckusick 			case 0x0a:	/* No Disk *//*MO*/
65253901Smckusick 			default:
65353901Smckusick 				DELAY(D100MSEC);
65453901Smckusick 				goto loop_tst;
65553901Smckusick 			}
65653901Smckusick 			break;
65753901Smckusick 
65853901Smckusick 		case 0x03:
65953901Smckusick 			if (sce->sce_sdecode == FORMAT_MODE_CORRUPTED)
66053901Smckusick 				return (1);	/* ignore error */
66153901Smckusick 			/* fall through */
66253901Smckusick 
66353901Smckusick 		default:
66453901Smckusick 			return (-2);
66553901Smckusick 		}
66653901Smckusick 		break;
66753901Smckusick 
66853901Smckusick 	case TGST_BUSY:
66953901Smckusick 		goto loop_tst;
67053901Smckusick 
67153901Smckusick 	case TGST_GOOD:
67253901Smckusick 		break;
67353901Smckusick 
67453901Smckusick 	default:
67553901Smckusick 		return (-3);
67653901Smckusick 	}
67753901Smckusick 
67853901Smckusick 	return (1);
67953901Smckusick }
68053901Smckusick 
68153901Smckusick static
sd_other_pages(ii,sc)68253901Smckusick sd_other_pages(ii, sc)
68353901Smckusick 	register struct iop/**/_device *ii;
68453901Smckusick 	register struct scsi *sc;
68553901Smckusick {
68653901Smckusick 	register struct sddevinfo *sdi;
68753901Smckusick 	char **p;
68853901Smckusick 	char *page;
68953901Smckusick 	int length;
69053901Smckusick 	int retrycnt;
69153901Smckusick 	int len;
69253901Smckusick 
69353901Smckusick 	sdi = &sddevinfo[ii->ii_type];
69453901Smckusick 	if ((p = sdi->other_pages) == NULL)
69553901Smckusick 		return (0);
69653901Smckusick 
69753901Smckusick 	/*
69853901Smckusick 	 * set other parameters
69953901Smckusick 	 */
70053901Smckusick 	while (page = *p++) {
70153901Smckusick 		retrycnt = 0;
70253901Smckusick loop_other_pages:
70353901Smckusick 		bzero((caddr_t)sdtmp, 4);
70453901Smckusick 		length = *(page + 1) + 2;
70553901Smckusick 		bcopy(page, &sdtmp[4], length);
70653901Smckusick 		if (retrycnt++ > MAXPROBERETRY)
70753901Smckusick 			return (-1);
70853901Smckusick 
70953901Smckusick 		scop_mselect(ii->ii_intr, sc, ii->ii_slave, SCSI_INTDIS,
71053901Smckusick 				(SDM_PF<<24) + length +4, (caddr_t)sdtmp);
71153901Smckusick 		sc->sc_tstatus &= TGSTMASK;
71253901Smckusick 		if ((sc->sc_istatus != INST_EP)
71353901Smckusick 				|| (sc->sc_tstatus != TGST_GOOD)) {
71453901Smckusick 			struct sc_extnd *sce;
71553901Smckusick 
71653901Smckusick 			sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
71753901Smckusick 			scop_rsense(ii->ii_intr, sc, ii->ii_slave, SCSI_INTDIS,
71853901Smckusick 						RSEN_CNT, (caddr_t)sce);
71953901Smckusick 			switch (sce->sce_skey) {
72053901Smckusick 
72153901Smckusick 			case 0x00:
72253901Smckusick 			case 0x02:
72353901Smckusick 			case 0x04:
72453901Smckusick 			case 0x06:
72553901Smckusick 				DELAY(D100MSEC);   /* 100 ms. */
72653901Smckusick 				goto loop_other_pages;
72753901Smckusick 
72853901Smckusick 			default:
72953901Smckusick 				return (-1);
73053901Smckusick 			}
73153901Smckusick 		}
73253901Smckusick 	}
73353901Smckusick 
73453901Smckusick 	if (sdi->firm_flags & FIRM_CACHE_ON)
73553901Smckusick 		sdc_softc[ii->ii_ctlr].sdc_firmware |= SDCFW_CACHE;
73653901Smckusick 	else
73753901Smckusick 		sdc_softc[ii->ii_ctlr].sdc_firmware &= ~SDCFW_CACHE;
73853901Smckusick 
73953901Smckusick 	return (1);
74053901Smckusick }
74153901Smckusick 
74253901Smckusick static
sd_err_rcv(ii,sc)74353901Smckusick sd_err_rcv(ii, sc)
74453901Smckusick 	register struct iop/**/_device *ii;
74553901Smckusick 	register struct scsi *sc;
74653901Smckusick {
74753901Smckusick 	register struct sdc_softc *sdc;
74853901Smckusick 	register int intr;
74953901Smckusick 	register int slave;
75053901Smckusick 	register int len;
75153901Smckusick 	struct sc_extnd *sce;
75253901Smckusick 	struct sdd_softc *sdd;
75353901Smckusick 	struct sddevinfo *sdi;
75453901Smckusick 	int retrycnt;
75553901Smckusick 	char *erp_page;
75653901Smckusick 
75753901Smckusick 	intr = ii->ii_intr;
75853901Smckusick 	slave = ii->ii_slave;
75953901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
76053901Smckusick 	sdd = &sdd_softc[ii->ii_unit];
76153901Smckusick 	sdi = &sddevinfo[ii->ii_type];
76253901Smckusick 	sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
76353901Smckusick 
76453901Smckusick 	/*
76553901Smckusick 	 * set Default DISK sector size
76653901Smckusick 	 */
76753901Smckusick 	if (sdd->sdd_sectsize == 0)
76853901Smckusick 		sdd->sdd_sectsize = DEV_BSIZE;
76953901Smckusick 
77053901Smckusick 
77153901Smckusick 	if (sdi->ERP_page == NULL) {
77253901Smckusick 		/*
77353901Smckusick 		 * use default error recovery parameters
77453901Smckusick 		 */
77553901Smckusick 		sdc->sdc_firmware |= SDCFW_DEFMODE;
77653901Smckusick 		return (0);
77753901Smckusick 	}
77853901Smckusick 
77953901Smckusick 	if (sdi->firm_flags & FIRM_AWRE)
78053901Smckusick 		sdc->sdc_firmware |= SDCFW_AWRE;
78153901Smckusick 	if (sdi->firm_flags & FIRM_ARRE)
78253901Smckusick 		sdc->sdc_firmware |= SDCFW_ARRE;
78353901Smckusick 	/*
78453901Smckusick 	 * set ERROR RECOVERY PARAMETERS
78553901Smckusick 	 */
78653901Smckusick loop_err_rcv:
78753901Smckusick 	bzero((caddr_t)sdtmp, 4);
78853901Smckusick 	erp_page = sdi->ERP_page;
78953901Smckusick 	len = *(erp_page + 1) + 2;
79053901Smckusick 	bcopy(erp_page, &sdtmp[4], len);
79153901Smckusick 
79253901Smckusick 	scop_mselect(intr, sc, slave, SCSI_INTDIS,
79353901Smckusick 			(SDM_PF<<24) + len +4, (caddr_t)sdtmp);
79453901Smckusick 	sc->sc_tstatus &= TGSTMASK;
79553901Smckusick 	if (sc->sc_istatus != INST_EP || sc->sc_tstatus != TGST_GOOD) {
79653901Smckusick 		if (sc->sc_tstatus == TGST_CC) {
79753901Smckusick 			bzero((caddr_t)sce, RSEN_CNT);
79853901Smckusick 			scop_rsense(intr, sc, slave, SCSI_INTDIS, RSEN_CNT,
79953901Smckusick 					(caddr_t)sce);
80053901Smckusick 			if (sce->sce_sdecode == 0x2a) {
80153901Smckusick 				/* mode select parameter changed */
80253901Smckusick 				goto ercv_done;
80353901Smckusick 			} else if (sce->sce_skey == 0x6) {
80453901Smckusick 				/* unit attention */
80553901Smckusick 				goto loop_err_rcv;
80653901Smckusick 			}
80753901Smckusick 		}
80853901Smckusick 		/*
80953901Smckusick 		 * use default ERROR RECOVERY mode
81053901Smckusick 		 */
81153901Smckusick 		sdc->sdc_firmware |= SDCFW_DEFMODE;
81253901Smckusick 		sdc->sdc_firmware &= ~(SDCFW_AWRE|SDCFW_ARRE);
81353901Smckusick 	}
81453901Smckusick 
81553901Smckusick ercv_done:
81653901Smckusick 
81753901Smckusick 	return (1);
81853901Smckusick }
81953901Smckusick 
82053901Smckusick static
sd_synctr_on(ii,sc)82153901Smckusick sd_synctr_on(ii, sc)
82253901Smckusick 	register struct iop/**/_device *ii;
82353901Smckusick 	register struct scsi *sc;
82453901Smckusick {
82553901Smckusick 	register struct sddevinfo *sdi;
82653901Smckusick 	register struct sync_param *syncp;
82753901Smckusick 
82853901Smckusick 	sdi = &sddevinfo[ii->ii_type];
82953901Smckusick 
83053901Smckusick 	if (sdi->firm_flags & FIRM_SYNCTR) {
83153901Smckusick 		scinit(sc, ii->ii_slave, DEV_BSIZE);
83253901Smckusick 		sc->sc_opcode = SCOP_TST;
83353901Smckusick 		sc->sc_message = MSG_EXTND;	/* extended message */
83453901Smckusick 		sc->sc_param[0] = MSG_EXTND;
83553901Smckusick 		sc->sc_param[1] = 0x03;
83653901Smckusick 		sc->sc_param[2] = 0x01;		/* synchronous transfer */
83753901Smckusick 		sc->sc_param[3] = sdi->tr_period;	/* transfer period */
83853901Smckusick 		sc->sc_param[4] = sdi->tr_offset;	/* REQ offset */
83953901Smckusick 
84053901Smckusick 		if (sdc_softc[ii->ii_ctlr].sdc_firmware & SDCFW_CACHE)
84153901Smckusick 			sc->sc_tstatus |= TS_CONTR_ON;	/* contiguous TR ON */
84253901Smckusick 		else
84353901Smckusick 			sc->sc_tstatus |= TS_CONTR_OFF;	/* contiguous TR OFF */
84453901Smckusick 
84553901Smckusick #ifdef news1800
84653901Smckusick 		if (scsi_berr_bug() != 0) {
84753901Smckusick 			sc->sc_tstatus &= ~TS_CONTR_ON;
84853901Smckusick 			sc->sc_tstatus |= TS_CONTR_OFF;
84953901Smckusick 		}
85053901Smckusick #endif
85153901Smckusick 
85253901Smckusick 		if (sc->sc_tstatus & TS_CONTR_OFF)
85353901Smckusick 			sdc_softc[ii->ii_ctlr].sdc_firmware &= ~SDCFW_CONTR;
85453901Smckusick 		else
85553901Smckusick 			sdc_softc[ii->ii_ctlr].sdc_firmware |= SDCFW_CONTR;
85653901Smckusick 
85753901Smckusick 		sc_go(ii->ii_intr, sc, SCSI_INTDIS);
85853901Smckusick 
85953901Smckusick 		syncp = &sd_sync_param[ii->ii_unit];
86053901Smckusick 		syncp->tr_period = sc->sc_param[3];
86153901Smckusick 		syncp->tr_offset = sc->sc_param[4];
86253901Smckusick 		if (sc->sc_param[4])
86353901Smckusick 			sdd_softc[ii->ii_unit].sdd_flags |= SDDF_SYNCTR;
86453901Smckusick 	}
86553901Smckusick }
86653901Smckusick 
86753901Smckusick 
sdattach(ii)86853901Smckusick sdattach(ii)
86953901Smckusick 	register struct iop/**/_device *ii;
87053901Smckusick {
87153901Smckusick 	register int unit;
87253901Smckusick 	register int i;
87353901Smckusick 	struct sdc_softc *sdc;
87453901Smckusick 	struct sdd_softc *sdd;
87553901Smckusick 	int dummy;
87653901Smckusick 
87753901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
87853901Smckusick 	sdc->sdc_timeo = 60;			/* timeout 60 sec */
87953901Smckusick 
88053901Smckusick 	unit = ii->ii_unit;
88153901Smckusick 	sdd = &sdd_softc[unit];
88253901Smckusick 	sdd->sdd_stoptime = OD_STOPTIME;	/* REMOVABLE MEDIA */
88353901Smckusick 	sdd->sdd_start = -2;
88453901Smckusick 
88553901Smckusick 	sdmaptype(ii);
88653901Smckusick 
88753901Smckusick 	if (sdwstart == 0) {
88853901Smckusick 		sdwstart++;
88953901Smckusick 		timeout(sdwatch, (caddr_t)0, hz);
89053901Smckusick 		timeout(sdstop, (caddr_t)0, hz);
89153901Smckusick 	}
89253901Smckusick 
89353901Smckusick 	/*
89453901Smckusick 	 * initialize open flag
89553901Smckusick 	 */
89653901Smckusick 	for (i = 0; i < PNUM; i++) {
89753901Smckusick 		sd_b_openf[unit][i] = 0;
89853901Smckusick 		sd_c_openf[unit][i] = 0;
89953901Smckusick 	}
90053901Smckusick 
90153901Smckusick 	if (re_init_done > 0)
90253901Smckusick 		return;
90353901Smckusick 
90453901Smckusick 	if (sdc->sdc_firmware & SDCFW_HD) {
90553901Smckusick 		/*
90653901Smckusick 		 * If device is Hard Disk,
90753901Smckusick 		 *	then get partition information.
90853901Smckusick 		 */
90953901Smckusick 		sdrpartinfo(ii);
91053901Smckusick 		dummy = DEV_BSIZE * sdstdrv[unit].rps * sdstdrv[unit].nsect;
91153901Smckusick 	} else
91253901Smckusick 		dummy = DEV_BSIZE * 40 * 31;
91353901Smckusick 
91453901Smckusick 	if (ii->ii_dk >= 0 && dummy)
91553901Smckusick 		dk_wpms[ii->ii_dk] = dummy / (2 * 1000000);
91653901Smckusick }
91753901Smckusick 
sdmaptype(ii)91853901Smckusick sdmaptype(ii)
91953901Smckusick 	register struct iop/**/_device *ii;
92053901Smckusick {
92153901Smckusick 	printf("sd%d: %s\n", ii->ii_unit, sddevinfo[ii->ii_type].call_name);
92253901Smckusick }
92353901Smckusick 
92453901Smckusick int sd_b_major = -1;
92553901Smckusick 
sd_b_open(dev,flag)92653901Smckusick sd_b_open(dev, flag)
92753901Smckusick 	dev_t dev;
92853901Smckusick 	int flag;
92953901Smckusick {
93053901Smckusick 	sd_b_major = major(dev);
93153901Smckusick 	return (_sdopen(dev, flag, S_IFBLK));
93253901Smckusick }
93353901Smckusick 
93453901Smckusick int sd_c_major = -1;
93553901Smckusick 
sd_c_open(dev,flag)93653901Smckusick sd_c_open(dev, flag)
93753901Smckusick 	dev_t dev;
93853901Smckusick 	int flag;
93953901Smckusick {
94053901Smckusick 	sd_c_major = major(dev);
94153901Smckusick 	return (_sdopen(dev, flag, S_IFCHR));
94253901Smckusick }
94353901Smckusick 
_sdopen(dev,flag,fmt)94453901Smckusick _sdopen(dev, flag, fmt)
94553901Smckusick 	register dev_t dev;
94653901Smckusick 	int flag;
94753901Smckusick 	int fmt;
94853901Smckusick {
94953901Smckusick 	register struct iop/**/_device *ii;
95053901Smckusick 	register struct sdd_softc *sdd;
95153901Smckusick 	register struct sdc_softc *sdc;
95253901Smckusick 	register struct sddevinfo *sdi;
95353901Smckusick 	register int unit;
95453901Smckusick 	register int i;
95553901Smckusick 	u_char *sdopfp;
95653901Smckusick 	u_char	old_sdopf;
95753901Smckusick 	int media_changed;
95853901Smckusick 	int s;
95953901Smckusick 	int stat;
96053901Smckusick 	struct scsi uscsi;
96153901Smckusick 
96253901Smckusick 	unit = dev2unit(dev);
96353901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
96453901Smckusick 		return (ENXIO);
96553901Smckusick 
96653901Smckusick 	sdd = &sdd_softc[unit];
96753901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
96853901Smckusick 	sdi = &sddevinfo[ii->ii_type];
96953901Smckusick 
97053901Smckusick 	if (sdd->sdd_flags & SDDF_XUSE)
97153901Smckusick 		return (EBUSY);
97253901Smckusick 
97353901Smckusick 	/*
97453901Smckusick 	 * LOCK while sdstop() running.
97553901Smckusick 	 */
97653901Smckusick 	s = splclock();
97753901Smckusick 	while (sdc->sdc_state & SDCS_SCUNLOCK) {
97853901Smckusick 		sdc->sdc_state |= SDCS_OPEN_WAIT;
97953901Smckusick 		sleep((caddr_t)sdc, PRIBIO);
98053901Smckusick 	}
98153901Smckusick 	splx(s);
98253901Smckusick 
98353901Smckusick 	/*
98453901Smckusick 	 * LOCK sdtmp buffer
98553901Smckusick 	 */
98653901Smckusick 	s = splclock();
98753901Smckusick 	while (sdtmp_stat & B_BUSY) {
98853901Smckusick 		sdtmp_stat |= B_WANTED;
98953901Smckusick 		sleep((caddr_t)sdtmp, PRIBIO);
99053901Smckusick 	}
99153901Smckusick 	sdtmp_stat |= B_BUSY;
99253901Smckusick 	splx(s);
99353901Smckusick 	sdd->sdd_flags |= SDDF_GETTMP;
99453901Smckusick 
99553901Smckusick 	if ((fmt & S_IFMT) == S_IFBLK)
99653901Smckusick 		sdopfp = &sd_b_openf[unit][dev2part(dev)];
99753901Smckusick 	else
99853901Smckusick 		sdopfp = &sd_c_openf[unit][dev2part(dev)];
99953901Smckusick 	old_sdopf = *sdopfp;
100053901Smckusick 	if (old_sdopf <= 1)
100153901Smckusick 		*sdopfp += 1;		/* 1: 1st open (ONLY_ONE) */
100253901Smckusick 					/* 2: already opened */
100353901Smckusick 	stat = 0;
100453901Smckusick 	media_changed = 0;
100553901Smckusick 
100653901Smckusick 	/*
100753901Smckusick 	 * From here on until pre_open_done is only for removable devices
100853901Smckusick 	 */
100953901Smckusick 	if ((sdc->sdc_firmware & SDCFW_RMB) == 0)
101053901Smckusick 		goto pre_open_done;
101153901Smckusick 
101253901Smckusick 	if ((minor(dev) & 0x80) || (dev == rootdev))
101353901Smckusick 		sdd->sdd_stoptime = 0x7fffffff;		/*XXX*/
101453901Smckusick 
101553901Smckusick 	/*
101653901Smckusick 	 * Start Unit
101753901Smckusick 	 */
101853901Smckusick 	s = splclock();	/* inhibit clock interrupt */
101953901Smckusick 	i = sdd->sdd_start;
102053901Smckusick 	sdd->sdd_start = sdd->sdd_stoptime;
102153901Smckusick 	splx(s);
102253901Smckusick 	if (i <= 0) {
102353901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
102453901Smckusick 		uscsi.sc_opcode = SCOP_STST;
102553901Smckusick 		uscsi.sc_count = SDSS_START;
102653901Smckusick 
102753901Smckusick 		if (sdcmd(dev, &uscsi)) {
102853901Smckusick 			sdd->sdd_start = i;
102953901Smckusick 			if ((flag & FWRITE) == 0)
103053901Smckusick 				goto sdopen_setup;
103153901Smckusick 			stat = EIO;
103253901Smckusick 			goto pre_open_done;
103353901Smckusick 		}
103453901Smckusick 	}
103553901Smckusick 
103653901Smckusick 	/*
103753901Smckusick 	 * prevent medium removal
103853901Smckusick 	 */
103953901Smckusick 	scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
104053901Smckusick 	uscsi.sc_opcode = SCOP_MEDRMV;
104153901Smckusick 	uscsi.sc_count = SDRMV_PREV;
104253901Smckusick 	if (sdcmd(dev, &uscsi)) {
104353901Smckusick 		stat = EIO;
104453901Smckusick 		goto pre_open_done;
104553901Smckusick 	}
104653901Smckusick 	sdd->sdd_flags |= SDDF_INHRMV;
104753901Smckusick 
104853901Smckusick sdopen_setup:
104953901Smckusick 	if ((sdd->sdd_flags & SDDF_SAMEDSK) == SDDF_DSKCHGD) {
105053901Smckusick 		sdd->sdd_flags |= SDDF_SAMEDSK;
105153901Smckusick 		media_changed = 1;
105253901Smckusick 
105353901Smckusick 		/*
105453901Smckusick 		 * From here on until mo_check_done is only for MO device
105553901Smckusick 		 */
105653901Smckusick 		if ((sdc->sdc_firmware & SDCFW_MO) == 0)
105753901Smckusick 			goto mo_check_done;
105853901Smckusick 
105953901Smckusick 		/*
106053901Smckusick 		 * Mode Sense
106153901Smckusick 		 */
106253901Smckusick 		bzero(sdtmp, 36);
106353901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
106453901Smckusick 		uscsi.sc_cpoint = sdtmp;
106553901Smckusick 		uscsi.sc_ctrnscnt = 36;
106653901Smckusick 		uscsi.sc_opcode = SCOP_MSENSE;
106753901Smckusick 		uscsi.sc_lad = (SDM_PF << 16)|((SDM_PC_CUR|SDM_PCODE_ALL) << 8);
106853901Smckusick 		uscsi.sc_count = 36;
106953901Smckusick 
107053901Smckusick 		if (sdcmd(dev, &uscsi) == 0) {
107153901Smckusick 			/*
107253901Smckusick 			 * check Write Protect mode
107353901Smckusick 			 */
107453901Smckusick 			if (sdtmp[2] & 0x80)
107553901Smckusick 				sdd->sdd_flags |= SDDF_WPROTECT;
107653901Smckusick 			else
107753901Smckusick 				sdd->sdd_flags &= ~SDDF_WPROTECT;
107853901Smckusick 			/*
107953901Smckusick 			 * check Format Mode
108053901Smckusick 			 */
108153901Smckusick 			if (sdtmp[26] == 2) {
108253901Smckusick 				ii->ii_type = search_index(SMO_S501);
108353901Smckusick 				if (mo_disp_format)
108453901Smckusick 					printf("sd%d: format mode 2 (original format)\n", unit);
108553901Smckusick 			} else if (sdtmp[26] == 3) {
108653901Smckusick 				int spare;
108753901Smckusick 
108853901Smckusick 				spare = *(short *)&sdtmp[32];
108953901Smckusick 				if (spare == 2048)
109053901Smckusick 					ii->ii_type =
109153901Smckusick 						search_index(SMO_S501_ISO2);
109253901Smckusick 				else
109353901Smckusick 					ii->ii_type =
109453901Smckusick 						search_index(SMO_S501_ISO);
109553901Smckusick 				if (mo_disp_format)
109653901Smckusick 					printf("sd%d: format mode 3 (ISO format) spare=%d\n", unit, spare);
109753901Smckusick 			} else {
109853901Smckusick 				sdd->sdd_flags |= SDDF_NONFMT;
109953901Smckusick 				if (mo_disp_format)
110053901Smckusick 					printf("sd%d: Non format\n", unit);
110153901Smckusick 			}
110253901Smckusick 			sdi = &sddevinfo[ii->ii_type];
110353901Smckusick 		}
110453901Smckusick 
110553901Smckusick 		/*
110653901Smckusick 		 * Mode Select
110753901Smckusick 		 *	Error Recovery Parameters set
110853901Smckusick 		 */
110953901Smckusick 		i = *(sdi->ERP_page +1) + 2;	/* page length */
111053901Smckusick 		bzero(sdtmp, i + 4);
111153901Smckusick 		bcopy(sdi->ERP_page, (caddr_t)&sdtmp[4], i);
111253901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
111353901Smckusick 		uscsi.sc_cpoint = sdtmp;
111453901Smckusick 		uscsi.sc_ctrnscnt = i + 4;
111553901Smckusick 		uscsi.sc_opcode = SCOP_MSELECT;
111653901Smckusick 		uscsi.sc_lad = (SDM_PF << 16);
111753901Smckusick 		uscsi.sc_count = i + 4;
111853901Smckusick 
111953901Smckusick 		(void) sdcmd(dev, &uscsi);
112053901Smckusick 
112153901Smckusick 		/*
112253901Smckusick 		 * Read Grown Defect list
112353901Smckusick 		 */
112453901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
112553901Smckusick 		uscsi.sc_cpoint = sdtmp;
112653901Smckusick 		uscsi.sc_ctrnscnt = 4;
112753901Smckusick 		uscsi.sc_opcode = SCOP_RDL;
112853901Smckusick 		uscsi.sc_cdb.un_type1.t1_ladhi = (SDDL_GLIST|SDDL_PHYSFMT) << 8;
112953901Smckusick 		uscsi.sc_cdb.un_type1.t1_p3 = 4;
113053901Smckusick 
113153901Smckusick 		(void) sdcmd(dev, &uscsi);
113253901Smckusick 		i = *(short *)&sdtmp[2] / 8;
113353901Smckusick 		if (i > (1024*9/10))
113453901Smckusick 			printf("sd%d: WARNING: DEFECT SPARE LOCATION < 10%\n",
113553901Smckusick 				unit);
113653901Smckusick mo_check_done:
113753901Smckusick 		/*
113853901Smckusick 		 * Read Capacity
113953901Smckusick 		 */
114053901Smckusick 		bzero((caddr_t)sdtmp, 8);
114153901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
114253901Smckusick 		uscsi.sc_cpoint = sdtmp;
114353901Smckusick 		uscsi.sc_ctrnscnt = 8;
114453901Smckusick 		uscsi.sc_opcode = SCOP_RCAP;
114553901Smckusick 
114653901Smckusick 		(void) sdcmd(dev, &uscsi);
114753901Smckusick 		sdd->sdd_nsect = *(int *)&sdtmp[0] + 1;
114853901Smckusick 		sdd->sdd_sectsize = *(int *)&sdtmp[4];
114953901Smckusick 
115053901Smckusick 		if ((sdd->sdd_sectsize != DEV_BSIZE)
115153901Smckusick 				&& (sdd->sdd_sectsize != SDBSIZE1K))
115253901Smckusick 			sdd->sdd_sectsize = DEV_BSIZE;
115353901Smckusick 	}
115453901Smckusick 
115553901Smckusick 	if ((sdd->sdd_flags & SDDF_WPROTECT) && (flag & FWRITE))
115653901Smckusick 		stat = EROFS;
115753901Smckusick 
115853901Smckusick pre_open_done:
115953901Smckusick 
116053901Smckusick 	if (stat == 0) {
116153901Smckusick 		if ((isalone(unit) == ONLY_ONE) || media_changed) {
116253901Smckusick 			/*
116353901Smckusick 			 * read partition information from sector zero.
116453901Smckusick 			 */
116553901Smckusick 			sdrpartinfo(ii);
116653901Smckusick 			if (ii->ii_dk >= 0) {
116753901Smckusick 				dk_wpms[ii->ii_dk] =
116853901Smckusick 					sdd->sdd_sectsize * sdstdrv[unit].rps
116953901Smckusick 					* sdstdrv[unit].nsect / (2 * 1000000);
117053901Smckusick 			}
117153901Smckusick 		}
117253901Smckusick 	} else {
117353901Smckusick 		/*
117453901Smckusick 		 * open error
117553901Smckusick 		 */
117653901Smckusick 		*sdopfp = old_sdopf;
117753901Smckusick 		if ((sdd->sdd_flags & SDDF_INHRMV) && (isalone(unit) == 0)) {
117853901Smckusick 			sdd->sdd_flags &= ~SDDF_INHRMV;
117953901Smckusick 			scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
118053901Smckusick 			uscsi.sc_opcode = SCOP_MEDRMV;
118153901Smckusick 			uscsi.sc_count = SDRMV_ALLOW;
118253901Smckusick 			(void) sdcmd(dev, &uscsi);
118353901Smckusick 		}
118453901Smckusick 	}
118553901Smckusick 
118653901Smckusick 	/*
118753901Smckusick 	 * UNLOCK open
118853901Smckusick 	 */
118953901Smckusick 	s = splclock();
119053901Smckusick 	sdd->sdd_flags &= ~SDDF_GETTMP;
119153901Smckusick 	if (sdtmp_stat & B_WANTED)
119253901Smckusick 		wakeup((caddr_t)sdtmp);
119353901Smckusick 	sdtmp_stat &= ~(B_BUSY|B_WANTED);
119453901Smckusick 	splx(s);
119553901Smckusick 	return (stat);
119653901Smckusick }
119753901Smckusick 
119853901Smckusick int sd_access_check_on;		/* Common flags for sd_access_check() */
119953901Smckusick 
sd_access_check(bp)120053901Smckusick sd_access_check(bp)
120153901Smckusick 	register struct buf *bp;
120253901Smckusick {
120353901Smckusick 	register struct iop/**/_device *ii;
120453901Smckusick 	register struct sdd_softc *sdd;
120553901Smckusick 	int unit;
120653901Smckusick 	int check_part;
120753901Smckusick 	int limit;
120853901Smckusick 	int over;
120953901Smckusick 	register struct size *sizes;
121053901Smckusick 	register int lba;	/* logical block address */
121153901Smckusick 	register int sz;
121253901Smckusick 	register int i;
121353901Smckusick 
121453901Smckusick 	check_part = 0;
121553901Smckusick 	unit = dev2unit(bp->b_dev);
121653901Smckusick 	ii = sddinfo[unit];
121753901Smckusick 	sdd = &sdd_softc[unit];
121853901Smckusick 	sizes = sdstdrv[unit].sizes;
121953901Smckusick 
122053901Smckusick 	lba = sizes[dev2part(bp->b_dev)].sd_blkoff + dkblock(bp);
122153901Smckusick 	sz = howmany(bp->b_bcount, sdd->sdd_sectsize);
122253901Smckusick 
122353901Smckusick 	/*
122453901Smckusick 	 * When block device is used,
122553901Smckusick 	 *	inhibit raw device write operation.
122653901Smckusick 	 */
122753901Smckusick 	if ((major(bp->b_dev) == sd_c_major)			/* RAW I/O */
122853901Smckusick 	    && ((bp->b_flags & B_READ) == 0)			/* WRITE */
122953901Smckusick 	    && ((ii->ii_flags & SD_F_ENW) == 0)			/* INHIBIT */
123053901Smckusick 	    && ((sd_access_check_on & SD_F_ENW) == 0)) {
123153901Smckusick 
123253901Smckusick 		for (i = 0; i < PNUM; i++) {
123353901Smckusick 			if (sd_b_openf[unit][i] == 0)
123453901Smckusick 				continue;
123553901Smckusick 			/*
123653901Smckusick 			 *   |----|========|---|======|-------|
123753901Smckusick 			 * 1 |---+++--------------------------| CUT OFF
123853901Smckusick 			 * 2 |---++++++++++++-----------------| CUT OFF
123953901Smckusick 			 * 3 |---++++++++++++++++-------------| CUT OFF
124053901Smckusick 			 * 4 |---++++++++++++++++++++++++-----| CUT OFF
124153901Smckusick 			 * 5 |-------+++----------------------| ERROR
124253901Smckusick 			 * 6 |------------+++-----------------| ERROR
124353901Smckusick 			 * 7 |------------+++++++-------------| ERROR
124453901Smckusick 			 * 8 |------------+++++++++++++++-----| ERROR
124553901Smckusick 			 */
124653901Smckusick 			if ((lba < (sizes[i].sd_blkoff + sizes[i].sd_nblocks))
124753901Smckusick 			    && ((lba + sz) > sizes[i].sd_blkoff))
124853901Smckusick 				check_part |= (1 << i);
124953901Smckusick 		}
125053901Smckusick 	}
125153901Smckusick 
125253901Smckusick 	if (check_part) {
125353901Smckusick 		limit = 0x7fffffff;	/* XXX */
125453901Smckusick 		for (i = 0; i < PNUM; i++) {
125553901Smckusick 			if ((check_part & (1 << i)) == 0)
125653901Smckusick 				continue;
125753901Smckusick 
125853901Smckusick 			if (lba >= sizes[i].sd_blkoff) {
125953901Smckusick 				bp->b_flags |= B_ERROR;
126053901Smckusick 				bp->b_error = EIO;
126153901Smckusick 				bp->b_resid = bp->b_bcount;
126253901Smckusick 
126353901Smckusick 				printf("sd%d%c: RAW DEVICE WRITE PROTECTED: ",
126453901Smckusick 					unit, pname[dev2part(bp->b_dev)]);
126553901Smckusick 				printf("sn = 0x%x(%d), off = 0x%x(%d)\n",
126653901Smckusick 					dkblock(bp)*DEV_BSIZE/sdd->sdd_sectsize,
126753901Smckusick 					dkblock(bp)*DEV_BSIZE/sdd->sdd_sectsize,
126853901Smckusick 					sizes[dev2part(bp->b_dev)].sd_blkoff,
126953901Smckusick 					sizes[dev2part(bp->b_dev)].sd_blkoff);
127053901Smckusick 
127153901Smckusick 				return (-1);
127253901Smckusick 			}
127353901Smckusick 
127453901Smckusick 			if (sizes[i].sd_blkoff < limit)
127553901Smckusick 				limit = sizes[i].sd_blkoff;
127653901Smckusick 		}
127753901Smckusick 	} else {
127853901Smckusick 		limit = sizes[dev2part(bp->b_dev)].sd_blkoff
127953901Smckusick 			+ sizes[dev2part(bp->b_dev)].sd_nblocks;
128053901Smckusick 	}
128153901Smckusick 
128253901Smckusick 	if ((over = (lba + sz) - limit) > 0) {
128353901Smckusick 		/*
128453901Smckusick 		 * Logical Block Address is outside the valid area.
128553901Smckusick 		 */
128653901Smckusick 		if (((ii->ii_flags & SD_F_EOLBA) != 0)
128753901Smckusick 			|| ((sd_access_check_on & SD_F_EOLBA) != 0)) {
128853901Smckusick 			/*
128953901Smckusick 			 * error if outside LBA
129053901Smckusick 			 */
129153901Smckusick 			return(-1);
129253901Smckusick 		}
129353901Smckusick 		bp->b_resid = bp->b_bcount - (sz - over) * sdd->sdd_sectsize;
129453901Smckusick 		if (bp->b_resid >= bp->b_bcount) {
129553901Smckusick 			bp->b_resid = bp->b_bcount;
129653901Smckusick 			return(-1);
129753901Smckusick 		}
129853901Smckusick 	}
129953901Smckusick 
130053901Smckusick 	return (0);
130153901Smckusick }
130253901Smckusick 
sd_b_close(dev,flag)130353901Smckusick sd_b_close(dev, flag)
130453901Smckusick 	dev_t dev;
130553901Smckusick 	int flag;
130653901Smckusick {
130753901Smckusick 	return (_sdclose(dev, flag, S_IFBLK));
130853901Smckusick }
130953901Smckusick 
sd_c_close(dev,flag)131053901Smckusick sd_c_close(dev, flag)
131153901Smckusick 	dev_t dev;
131253901Smckusick 	int flag;
131353901Smckusick {
131453901Smckusick 	return (_sdclose(dev, flag, S_IFCHR));
131553901Smckusick }
131653901Smckusick 
_sdclose(dev,flag,fmt)131753901Smckusick _sdclose(dev, flag, fmt)
131853901Smckusick 	register dev_t dev;
131953901Smckusick 	int flag;
132053901Smckusick 	int fmt;
132153901Smckusick {
132253901Smckusick 	register struct iop/**/_device *ii;
132353901Smckusick 	register struct sdd_softc *sdd;
132453901Smckusick 	register int unit;
132553901Smckusick 	struct sdc_softc *sdc;
132653901Smckusick 	struct scsi uscsi;
132753901Smckusick 	struct sc_extnd *sce;
132853901Smckusick 
132953901Smckusick 	unit = dev2unit(dev);
133053901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
133153901Smckusick 		return (ENXIO);
133253901Smckusick 
133353901Smckusick 	sdd = &sdd_softc[unit];
133453901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
133553901Smckusick 	sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
133653901Smckusick 
133753901Smckusick 	/*
133853901Smckusick 	 * still remain jobs
133953901Smckusick 	 *	sleep about 10ms -> 1sec
134053901Smckusick 	 */
134153901Smckusick 	while (ii->ii_mi->im_tab.b_actf != NULL)
134253901Smckusick 		sleep((caddr_t)&lbolt, PRIBIO);
134353901Smckusick 
134453901Smckusick 	if ((fmt & S_IFMT) == S_IFBLK)
134553901Smckusick 		sd_b_openf[unit][dev2part(dev)] = 0;
134653901Smckusick 	else
134753901Smckusick 		sd_c_openf[unit][dev2part(dev)] = 0;
134853901Smckusick 	sdd->sdd_flags &= ~SDDF_XUSE;
134953901Smckusick 
135053901Smckusick 	if ((sdc->sdc_firmware & SDCFW_RMB) && (isalone(unit) == 0)) {
135153901Smckusick 		sdd->sdd_flags &= ~SDDF_INHRMV;
135253901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
135353901Smckusick 		uscsi.sc_opcode = SCOP_MEDRMV;
135453901Smckusick 		uscsi.sc_count = SDRMV_ALLOW;
135553901Smckusick 		(void) sdcmd(dev, &uscsi);
135653901Smckusick 	}
135753901Smckusick 	return (0);
135853901Smckusick }
135953901Smckusick 
sdcmd(dev,usc)136053901Smckusick sdcmd(dev, usc)
136153901Smckusick 	dev_t dev;
136253901Smckusick 	struct scsi *usc;
136353901Smckusick {
136453901Smckusick 	register struct buf *bp;
136553901Smckusick 	register struct scsi *ksc;
136653901Smckusick 	register u_char *point;
136753901Smckusick 	register int unit;
136853901Smckusick 	int error;
136953901Smckusick 	int s;
137053901Smckusick 	int cnt;
137153901Smckusick 
137253901Smckusick 	if (usc == 0)
137353901Smckusick 		return (ENXIO);
137453901Smckusick 
137553901Smckusick 	error = 0;
137653901Smckusick 	unit = dev2unit(dev);
137753901Smckusick 	bp = &csdbuf[unit];
137853901Smckusick 
137953901Smckusick 	/*
138053901Smckusick 	 * LOCK csdbuf
138153901Smckusick 	 */
138253901Smckusick 	s = splclock();
138353901Smckusick 	while (bp->b_flags & B_BUSY) {
138453901Smckusick 		bp->b_flags |= B_WANTED;
138553901Smckusick 		sleep((caddr_t)bp, PRIBIO);
138653901Smckusick 	}
138753901Smckusick 	bzero((caddr_t)bp, sizeof(struct buf));
138853901Smckusick 	bp->b_flags = B_BUSY|B_READ;
138953901Smckusick 	splx(s);
139053901Smckusick 
139153901Smckusick 	ksc = &kernscsi[unit];
139253901Smckusick 	bcopy((caddr_t)usc, (caddr_t)ksc, sizeof(struct scsi));
139353901Smckusick 	/*
139453901Smckusick 	 * setup command buffer
139553901Smckusick 	 */
139653901Smckusick 	bp->b_dev = dev;
139753901Smckusick 	bp->b_proc = curproc;
139853901Smckusick 	cnt = ksc->sc_ctrnscnt;
139953901Smckusick 	bp->b_bcount = cnt;
140053901Smckusick 
140153901Smckusick 	point = ksc->sc_cpoint;
140253901Smckusick 	bp->b_un.b_addr = (caddr_t)point;
140353901Smckusick 	if (cnt > 0) {
140453901Smckusick 		if (point == NULL) {
140553901Smckusick 			ksc->sc_cpoint = point = get_scsi(unit)->sc_param;
140653901Smckusick 			if (cnt > 20) {
140753901Smckusick 				error = EFAULT;
140853901Smckusick 				goto done;
140953901Smckusick 			}
141053901Smckusick 		}
141153901Smckusick 		if (point < (u_char *)KERNBASE) {
141253901Smckusick 			if (useracc(point, cnt, B_WRITE) == NULL) {
141353901Smckusick 				error = EFAULT;
141453901Smckusick 				goto done;
141553901Smckusick 			}
1416*64628Sbostic 			curproc->p_flag |= P_PHYSIO;
141753901Smckusick 			vslock(point, cnt);
141853901Smckusick 			bp->b_flags |= B_PHYS;
141953901Smckusick 		}
142053901Smckusick #ifndef mips
142153901Smckusick 		else {
142253901Smckusick 			if (kernacc(point, cnt, B_WRITE) == NULL) {
142353901Smckusick 				error = EFAULT;
142453901Smckusick 				goto done;
142553901Smckusick 			}
142653901Smckusick 		}
142753901Smckusick #endif
142853901Smckusick 		ksc->sc_tstatus = TS_MAPPED_PIO;	/* XXX */
142953901Smckusick 	}
143053901Smckusick 
143153901Smckusick 	/*
143253901Smckusick 	 * call strategy entry, and wait command done.
143353901Smckusick 	 */
143453901Smckusick 	sdstrategy(bp);
143553901Smckusick 	iowait(bp);
143653901Smckusick 
143753901Smckusick 	if ((cnt > 0) && (point < (u_char *)KERNBASE)) {
143853901Smckusick 		vsunlock(point, cnt, B_READ);
1439*64628Sbostic 		curproc->p_flag &= ~P_PHYSIO;
144053901Smckusick 	}
144153901Smckusick 	if ((bp->b_flags & B_ERROR) == 0)
144253901Smckusick 		error = 0;
144353901Smckusick 	else {
144453901Smckusick 		if (bp->b_error)
144553901Smckusick 			error = bp->b_error;
144653901Smckusick 		else
144753901Smckusick 			error = EIO;
144853901Smckusick 	}
144953901Smckusick 	bcopy((caddr_t)ksc, (caddr_t)usc, sizeof(struct scsi));
145053901Smckusick 
145153901Smckusick done:
145253901Smckusick 	/*
145353901Smckusick 	 * UNLOCK csdbuf
145453901Smckusick 	 */
145553901Smckusick 	s = splclock();
145653901Smckusick 	if (bp->b_flags & B_WANTED)
145753901Smckusick 		wakeup((caddr_t)bp);
145853901Smckusick 	bp->b_flags = 0;
145953901Smckusick 	splx(s);
146053901Smckusick 	return (error);
146153901Smckusick }
146253901Smckusick 
146353901Smckusick /*
146453901Smckusick  * read partition information from sector zero.
146553901Smckusick  */
sdrpartinfo(ii)146653901Smckusick sdrpartinfo(ii)
146753901Smckusick 	register struct iop/**/_device *ii;
146853901Smckusick {
146953901Smckusick 	register struct disklabel *dlp;
147053901Smckusick 	register struct sdst *hsp;
147153901Smckusick 	register struct sdst *st;
147253901Smckusick 	register int unit;
147353901Smckusick 	register int i;
147453901Smckusick 	struct firstsector *fsp;
147553901Smckusick 	struct sdc_softc *sdc;
147653901Smckusick 	struct sdd_softc *sdd;
147753901Smckusick 	struct sddevinfo *sdi;
147853901Smckusick 	struct scsi uscsi;
147953901Smckusick 	int s;
148053901Smckusick 
148153901Smckusick 	sdi = &sddevinfo[ii->ii_type];
148253901Smckusick 	unit = ii->ii_unit;
148353901Smckusick 
148453901Smckusick 	sdd = &sdd_softc[unit];
148553901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
148653901Smckusick 
148753901Smckusick 	if ((sdd->sdd_flags & (SDDF_NONFMT|SDDF_FMTDONE)) == 0) {
148853901Smckusick 		register struct sc_rcap *scr = (struct sc_rcap *)sdtmp;
148953901Smckusick 
149053901Smckusick 		sdd->sdd_flags |= SDDF_FMTDONE;
149153901Smckusick 
149253901Smckusick 		bzero((caddr_t)sdtmp, 8);
149353901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
149453901Smckusick 		uscsi.sc_cpoint = (u_char *)scr;
149553901Smckusick 		uscsi.sc_ctrnscnt = 8;
149653901Smckusick 		uscsi.sc_opcode = SCOP_RCAP;
149753901Smckusick 		(void) sdcmd(unit << 3, &uscsi);
149853901Smckusick 
149953901Smckusick 		sdd->sdd_nsect = scr->scr_nblock + 1;
150053901Smckusick 		sdd->sdd_sectsize = scr->scr_blocklen;
150153901Smckusick 		if (sdd->sdd_sectsize == 0)
150253901Smckusick 			sdd->sdd_sectsize = SDBSIZE1K;
150353901Smckusick 	}
150453901Smckusick 
150553901Smckusick 	bzero(sdtmp, DEV_BSIZE);
150653901Smckusick 
150753901Smckusick 	if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
150853901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
150953901Smckusick 		uscsi.sc_cpoint = sdtmp;
151053901Smckusick 		uscsi.sc_ctrnscnt = DEV_BSIZE;
151153901Smckusick 		uscsi.sc_opcode = SCOP_READ;
151253901Smckusick 		uscsi.sc_lad = 0;
151353901Smckusick 		uscsi.sc_count = 1;
151453901Smckusick 
151553901Smckusick 		(void) sdcmd(unit << 3, &uscsi);
151653901Smckusick 		sdd->sdd_flags &= ~SDDF_SKIPCHECK;
151753901Smckusick 	}
151853901Smckusick 
151953901Smckusick 	fsp = (struct firstsector *)sdtmp;
152053901Smckusick 	dlp = (struct disklabel *)(sdtmp + LABELOFFSET);
152153901Smckusick 
152253901Smckusick 	s = splclock();
152353901Smckusick 	hsp = &sdstdrv[unit];
152453901Smckusick 	bzero((caddr_t)hsp, sizeof (struct sdst));
152553901Smckusick 	bzero(&sdlabel[unit], sizeof (struct disklabel));
152653901Smckusick 
152753901Smckusick 	if ((dlp->d_magic == DISKMAGIC)
152853901Smckusick 	    && ((ii->ii_flags & SD_F_IGNLABEL) == 0)) {
152953901Smckusick 		sdlabel[unit] = *dlp;
153053901Smckusick 		disklabel2sdst(unit, dlp, hsp);
153153901Smckusick 	} else {
153253901Smckusick 		if ((ii->ii_type == UNKNOWN_DISK)
153353901Smckusick 				|| (sdi->sdstp->sizes == calc_disk_sizes)) {
153453901Smckusick 			/*
153553901Smckusick 			 * If device is UNKNOWN PARTITION SIZE,
153653901Smckusick 			 *	calculate default partition from capacity.
153753901Smckusick 			 */
153853901Smckusick 			st = sdi->sdstp;
153953901Smckusick 			hsp->nsect = st->nsect;		/* # sectors/track */
154053901Smckusick 			hsp->ntrak = st->ntrak;		/* # tracks/cylinder */
154153901Smckusick 			hsp->nspc = st->nspc;		/* # sectors/cylinder */
154253901Smckusick 			hsp->ncyl = st->ncyl;		/* # cylinders */
154353901Smckusick 			hsp->rps = st->rps;		/* # revolutions/sec */
154453901Smckusick 			hsp->sizes = sdsizedrv[unit];	/* partition table */
154553901Smckusick 
154653901Smckusick 			sd_calcpart(ii, hsp->sizes,
154753901Smckusick 					sdd->sdd_nsect, sdd->sdd_sectsize);
154853901Smckusick 			sdst2disklabel(unit, hsp, &sdlabel[unit]);
154953901Smckusick 		} else {
155053901Smckusick 			/*
155153901Smckusick 			 * If device is support disk,
155253901Smckusick 			 *	copy default partition from size table.
155353901Smckusick 			 */
155453901Smckusick 			st = sdi->sdstp;
155553901Smckusick 
155653901Smckusick 			hsp->nsect = st->nsect;	/* # sectors/track */
155753901Smckusick 			hsp->ntrak = st->ntrak;	/* # tracks/cylinder */
155853901Smckusick 			hsp->nspc = st->nspc;	/* # sectors/cylinder */
155953901Smckusick 			hsp->ncyl = st->ncyl;	/* # cylinders */
156053901Smckusick 			hsp->rps = st->rps;	/* # revolutions / second */
156153901Smckusick 			hsp->sizes = sdsizedrv[unit];	/* partition table */
156253901Smckusick 
156353901Smckusick 			for (i = 0; i < PNUM; i++) {
156453901Smckusick 			    hsp->sizes[i].sd_nblocks = st->sizes[i].sd_nblocks;
156553901Smckusick 			    hsp->sizes[i].sd_blkoff = st->sizes[i].sd_blkoff;
156653901Smckusick 			}
156753901Smckusick 			sdst2disklabel(unit, hsp, &sdlabel[unit]);
156853901Smckusick 		}
156953901Smckusick 	}
157053901Smckusick 
157153901Smckusick 	/* BEGIN XXX*/
157253901Smckusick 	if (hsp->rps == 0) {
157353901Smckusick 		/*
157453901Smckusick 		 * If device is support disk,
157553901Smckusick 		 *	copy default partition from size table.
157653901Smckusick 		 */
157753901Smckusick 		st = sdi->sdstp;
157853901Smckusick 
157953901Smckusick 		hsp->nsect = st->nsect;		/* # sectors/track */
158053901Smckusick 		hsp->ntrak = st->ntrak;		/* # tracks/cylinder */
158153901Smckusick 		hsp->nspc = st->nspc;		/* # sectors/cylinder */
158253901Smckusick 		hsp->ncyl = st->ncyl;		/* # cylinders */
158353901Smckusick 		hsp->rps = st->rps;		/* # revolutions / second */
158453901Smckusick 		sdst2disklabel(unit, hsp, &sdlabel[unit]);
158553901Smckusick 	}
158653901Smckusick 	/* END XXX*/
158753901Smckusick 	(void)splx(s);
158853901Smckusick }
158953901Smckusick 
159053901Smckusick static char Warn_Part[] = "sd%d: PARTITION TABLE CHANGED\n";
159153901Smckusick static char Pr_Part_Fmt[] = "sd%d%c: nblk=%d, off=%d\n";
159253901Smckusick 
159353901Smckusick #define stsz(N) st->sizes[(N)].sd_nblocks
159453901Smckusick #define stof(N) st->sizes[(N)].sd_blkoff
159553901Smckusick #define dlsz(N) dlp->d_partitions[(N)].p_size
159653901Smckusick #define dlof(N) dlp->d_partitions[(N)].p_offset
159753901Smckusick #define disz(N) dip->di_part[(N)].dp_nblocks
159853901Smckusick #define diof(N) dip->di_part[(N)].dp_blkoff
159953901Smckusick 
160053901Smckusick #ifndef BBSIZE
160153901Smckusick #define BBSIZE 8192
160253901Smckusick #endif
160353901Smckusick 
160453901Smckusick static
check_sdst(unit,st)160553901Smckusick check_sdst(unit, st)
160653901Smckusick 	int unit;
160753901Smckusick 	struct sdst *st;
160853901Smckusick {
160953901Smckusick 	if (st->nsect == 0) {
161053901Smckusick 		st->nsect = 1;
161153901Smckusick 		printf("sd%d: nsect SHOULD BE != 0, 1 assumed\n", unit);
161253901Smckusick 	}
161353901Smckusick 
161453901Smckusick 	if (st->rps == 0) {
161553901Smckusick 		st->rps = 60;
161653901Smckusick 		printf("sd%d: rps SHOULD BE != 0, 60 assumed\n", unit);
161753901Smckusick 	}
161853901Smckusick }
161953901Smckusick 
162053901Smckusick static
disklabel2sdst(unit,dlp,st)162153901Smckusick disklabel2sdst(unit, dlp, st)
162253901Smckusick 	int unit;
162353901Smckusick 	register struct disklabel *dlp;
162453901Smckusick 	register struct sdst *st;
162553901Smckusick {
162653901Smckusick 	register int i;
162753901Smckusick 	int msg_header_printed;
162853901Smckusick 
162953901Smckusick 	msg_header_printed = 0;
163053901Smckusick 
163153901Smckusick 	st->nsect = dlp->d_nsectors;	/* # sectors/track */
163253901Smckusick 	st->ntrak = dlp->d_ntracks;	/* # tracks/cylinder */
163353901Smckusick 	st->nspc = dlp->d_secpercyl;	/* # sectors/cylinder */
163453901Smckusick 	st->ncyl = dlp->d_ncylinders;	/* # cylinders */
163553901Smckusick 	st->rps = dlp->d_rpm / 60;	/* # revolutions / second */
163653901Smckusick 	st->sizes = sdsizedrv[unit];	/* partition table */
163753901Smckusick 
163853901Smckusick 	check_sdst(unit, st);
163953901Smckusick 
164053901Smckusick 	for (i = 0; i < PNUM; i++) {
164153901Smckusick 		if (msg_header_printed == 0) {
164253901Smckusick 			if (((stsz(i) != 0) || (stof(i) != 0))
164353901Smckusick 			    && ((stsz(i) != dlsz(i)) || (stof(i) != dlof(i)))) {
164453901Smckusick 				msg_header_printed = 1;
164553901Smckusick 			}
164653901Smckusick 		}
164753901Smckusick 	}
164853901Smckusick 
164953901Smckusick 	for (i = 0; i < PNUM; i++) {
165053901Smckusick 		stsz(i) = dlsz(i);
165153901Smckusick 		stof(i) = dlof(i);
165253901Smckusick 	}
165353901Smckusick 
165453901Smckusick 	if (msg_header_printed) {
165553901Smckusick 		printf(Warn_Part, unit);
165653901Smckusick 		for (i = 0; i < PNUM; i++)
165753901Smckusick 			printf(Pr_Part_Fmt, unit, pname[i], stsz(i), stof(i));
165853901Smckusick 	}
165953901Smckusick }
166053901Smckusick 
166153901Smckusick static
sdst2disklabel(unit,st,dlp)166253901Smckusick sdst2disklabel(unit, st, dlp)
166353901Smckusick 	int unit;	/*XXX*/
166453901Smckusick 	register struct sdst *st;
166553901Smckusick 	register struct disklabel *dlp;
166653901Smckusick {
166753901Smckusick 	register int i;
166853901Smckusick 
166953901Smckusick 	dlp->d_type = DTYPE_SCSI;			/* drive type */
167053901Smckusick 	dlp->d_secsize = sdd_softc[unit].sdd_sectsize;	/* # of bytes per sector */
167153901Smckusick 	dlp->d_nsectors = st->nsect;	/* # sectors/track */
167253901Smckusick 	dlp->d_ntracks = st->ntrak;	/* # tracks/cylinder */
167353901Smckusick 	dlp->d_ncylinders = st->ncyl;	/* # cylinders */
167453901Smckusick 	dlp->d_secpercyl = st->nspc;	/* # sectors/cylinder */
167553901Smckusick 	dlp->d_rpm = st->rps * 60;	/* # revolutions / minute */
167653901Smckusick 	dlp->d_bbsize = BBSIZE;	/*XXX*/	/* size of boot area at sn0, bytes */
167753901Smckusick 	dlp->d_sbsize = SBSIZE;	/*XXX*/	/* max size of fs superblock, bytes */
167853901Smckusick 
167953901Smckusick 	for (i = 0; i < PNUM; i++) {
168053901Smckusick 		dlsz(i) = stsz(i);
168153901Smckusick 		dlof(i) = stof(i);
168253901Smckusick 	}
168353901Smckusick }
168453901Smckusick 
168553901Smckusick #undef stsz
168653901Smckusick #undef stof
168753901Smckusick #undef dlsz
168853901Smckusick #undef dlof
168953901Smckusick #undef disz
169053901Smckusick #undef diof
169153901Smckusick 
sd_calcpart(ii,disk_sizes,nsect,sectsize)169253901Smckusick sd_calcpart(ii, disk_sizes, nsect, sectsize)
169353901Smckusick 	register struct iop/**/_device *ii;
169453901Smckusick 	register struct size disk_sizes[];
169553901Smckusick 	int nsect;
169653901Smckusick 	int sectsize;
169753901Smckusick {
169853901Smckusick 	register struct defpart *dp;
169953901Smckusick 	register int size_mb;
170053901Smckusick 	register int i;
170153901Smckusick 	int psize;
170253901Smckusick 
170353901Smckusick 	size_mb = nsect * sectsize / (1024 * 1024);
170453901Smckusick 
170553901Smckusick 	for (dp = defpart_std; dp->range_max; dp++)
170653901Smckusick 		if ((dp->range_min <= size_mb) && (size_mb < dp->range_max))
170753901Smckusick 			break;
170853901Smckusick 
170953901Smckusick 	/* PASS1 */
171053901Smckusick 	for (i = 0; i < PNUM; i++) {
171153901Smckusick 		psize = dp->partsize[i];
171253901Smckusick 
171353901Smckusick 		switch (psize) {
171453901Smckusick 
171553901Smckusick 		case PART_UNUSED:
171653901Smckusick 			disk_sizes[i].sd_nblocks = 0;
171753901Smckusick 			break;
171853901Smckusick 
171953901Smckusick 		case PART_SPEC:
172053901Smckusick 			disk_sizes[i].sd_nblocks = nsect * sectsize / DEV_BSIZE;
172153901Smckusick 			break;
172253901Smckusick 
172353901Smckusick 		case PART_CALCF:
172453901Smckusick 		case PART_CALCG:
172553901Smckusick 			break;
172653901Smckusick 
172753901Smckusick 		default:
172853901Smckusick 			disk_sizes[i].sd_nblocks = psize;
172953901Smckusick 			break;
173053901Smckusick 		}
173153901Smckusick 	}
173253901Smckusick 
173353901Smckusick 	/* PASS2 */
173453901Smckusick 	for (i = 0; i < PNUM; i++) {
173553901Smckusick 		psize = dp->partsize[i];
173653901Smckusick 
173753901Smckusick 		switch (psize) {
173853901Smckusick 
173953901Smckusick 		case PART_UNUSED:
174053901Smckusick 		case PART_SPEC:
174153901Smckusick 			break;
174253901Smckusick 
174353901Smckusick 		case PART_CALCF:
174453901Smckusick 			disk_sizes[i].sd_nblocks =
174553901Smckusick 				disk_sizes[PART_C].sd_nblocks -
174653901Smckusick 				(disk_sizes[PART_A].sd_nblocks +
174753901Smckusick 				 disk_sizes[PART_B].sd_nblocks +
174853901Smckusick 				 disk_sizes[PART_D].sd_nblocks +
174953901Smckusick 				 disk_sizes[PART_E].sd_nblocks +
175053901Smckusick 				 disk_sizes[PART_H].sd_nblocks);
175153901Smckusick 			break;
175253901Smckusick 
175353901Smckusick 		case PART_CALCG:
175453901Smckusick 			disk_sizes[i].sd_nblocks =
175553901Smckusick 				disk_sizes[PART_C].sd_nblocks -
175653901Smckusick 				(disk_sizes[PART_A].sd_nblocks +
175753901Smckusick 				 disk_sizes[PART_B].sd_nblocks +
175853901Smckusick 				 disk_sizes[PART_H].sd_nblocks);
175953901Smckusick 			break;
176053901Smckusick 
176153901Smckusick 		default:
176253901Smckusick 			break;
176353901Smckusick 		}
176453901Smckusick 	}
176553901Smckusick 
176653901Smckusick 	/* OFFSET */
176753901Smckusick 	disk_sizes[PART_A].sd_blkoff = 0;
176853901Smckusick 	disk_sizes[PART_B].sd_blkoff = disk_sizes[PART_A].sd_nblocks;
176953901Smckusick 	disk_sizes[PART_C].sd_blkoff = 0;
177053901Smckusick 	disk_sizes[PART_D].sd_blkoff = disk_sizes[PART_A].sd_nblocks
177153901Smckusick 					+ disk_sizes[PART_B].sd_nblocks
177253901Smckusick 					+ disk_sizes[PART_H].sd_nblocks;
177353901Smckusick 	disk_sizes[PART_E].sd_blkoff = disk_sizes[PART_D].sd_blkoff
177453901Smckusick 					+ disk_sizes[PART_D].sd_nblocks;
177553901Smckusick 	disk_sizes[PART_F].sd_blkoff = disk_sizes[PART_E].sd_blkoff
177653901Smckusick 					+ disk_sizes[PART_E].sd_nblocks;
177753901Smckusick 	disk_sizes[PART_G].sd_blkoff = disk_sizes[PART_D].sd_blkoff;
177853901Smckusick 
177953901Smckusick 	if (disk_sizes[PART_H].sd_nblocks == 0)
178053901Smckusick 		disk_sizes[PART_H].sd_blkoff = 0;
178153901Smckusick 	else {
178253901Smckusick 		disk_sizes[PART_H].sd_blkoff =
178353901Smckusick 			disk_sizes[PART_A].sd_nblocks +
178453901Smckusick 			disk_sizes[PART_B].sd_nblocks;
178553901Smckusick 	}
178653901Smckusick 
178753901Smckusick 	for (i = 0; i < PNUM; i++)
178853901Smckusick 		if (disk_sizes[i].sd_nblocks == 0)
178953901Smckusick 			disk_sizes[i].sd_blkoff = 0;
179053901Smckusick }
179153901Smckusick 
179253901Smckusick int sd_str_pr = 0;
179353901Smckusick 
sdstrategy(bp)179453901Smckusick sdstrategy(bp)
179553901Smckusick 	register struct buf *bp;
179653901Smckusick {
179753901Smckusick 	register struct iop/**/_device *ii;
179853901Smckusick 	register struct sdst *st;
179953901Smckusick 	register struct buf *dp;
180053901Smckusick 	register int unit;
180153901Smckusick 	register int ssize;
180253901Smckusick 	struct sdd_softc *sdd;
180353901Smckusick 	struct sdc_softc *sdc;
180453901Smckusick 	long bn;
180553901Smckusick 	int xunit;
180653901Smckusick 	int s;
180753901Smckusick 
180853901Smckusick 	xunit = dev2part(bp->b_dev);
180953901Smckusick 	unit = dev2unit(bp->b_dev);
181053901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
181153901Smckusick 		goto bad;
181253901Smckusick 
181353901Smckusick 	if (bp != &csdbuf[unit]) {
181453901Smckusick 		/*
181553901Smckusick 		 * READ / WRITE command
181653901Smckusick 		 */
181753901Smckusick 		sdd = &sdd_softc[unit];
181853901Smckusick 		if (sdd->sdd_flags & SDDF_NONFMT)
181953901Smckusick 			goto bad;
182053901Smckusick 		sdc = &sdc_softc[ii->ii_ctlr];
182153901Smckusick 		ssize = sdd->sdd_sectsize;
182253901Smckusick 		if ((ssize != DEV_BSIZE)
182353901Smckusick 			&& ((((dkblock(bp) * DEV_BSIZE) % ssize) != 0)
182453901Smckusick 				|| (((bp->b_flags & B_READ) == 0) &&
182553901Smckusick 				    ((bp->b_bcount % ssize) != 0)))) {
182653901Smckusick 			goto bad;
182753901Smckusick 		}
182853901Smckusick 
182953901Smckusick 		st = &sdstdrv[unit];
183053901Smckusick 		bn = dkblock(bp);
183153901Smckusick 		bp->b_resid = 0;
183253901Smckusick 		if ((bn < 0) || (bn >= st->sizes[xunit].sd_nblocks))
183353901Smckusick 			goto bad2;
183453901Smckusick 		if (sd_access_check(bp) < 0)
183553901Smckusick 			goto bad2;
183653901Smckusick 
183753901Smckusick #ifdef notdef /* KU: XXX */
183853901Smckusick 		bp->b_cylin = (bn + st->sizes[xunit].sd_blkoff) / st->nspc;
183953901Smckusick 	} else {
184053901Smckusick 		bp->b_cylin = 0;
184153901Smckusick #endif
184253901Smckusick 	}
184353901Smckusick 
184453901Smckusick 	s = splsc();
184553901Smckusick 	dp = &sdutab[ii->ii_unit];
184653901Smckusick 	disksort(dp, bp);
184753901Smckusick 	if (dp->b_active == 0) {
184853901Smckusick 		sdustart(ii);
184953901Smckusick 		bp = &ii->ii_mi->im_tab;
185053901Smckusick 		if (bp->b_actf && bp->b_active == 0)
185153901Smckusick 			sdstart(ii->ii_mi);
185253901Smckusick 	}
185353901Smckusick 	splx(s);
185453901Smckusick 	return;
185553901Smckusick 
185653901Smckusick bad:
185753901Smckusick 	bp->b_flags |= B_ERROR;
185853901Smckusick 	goto done;
185953901Smckusick bad2:
186053901Smckusick 	bp->b_resid = bp->b_bcount;
186153901Smckusick done:
186253901Smckusick 	iodone(bp);
186353901Smckusick }
186453901Smckusick 
186553901Smckusick /*
186653901Smckusick  * Unit start routine.
186753901Smckusick  */
sdustart(ii)186853901Smckusick sdustart(ii)
186953901Smckusick 	register struct iop/**/_device *ii;
187053901Smckusick {
187153901Smckusick 	register struct iop/**/_ctlr *im;
187253901Smckusick 	register struct buf *dp;
187353901Smckusick 
187453901Smckusick 	if (ii == NULL)
187553901Smckusick 		return;
187653901Smckusick 	im = ii->ii_mi;
187753901Smckusick 	dk_busy &= ~(1 << ii->ii_dk);
187853901Smckusick 	dp = &sdutab[ii->ii_unit];
187953901Smckusick 	if (dp->b_actf == NULL)
188053901Smckusick 		return;
188153901Smckusick 	/*
188253901Smckusick 	 * If the controller is active, just remember
188353901Smckusick 	 * that this device would like to be positioned ...
188453901Smckusick 	 * if we tried to position now we would confuse the SD.
188553901Smckusick 	 */
188653901Smckusick 	if (im->im_tab.b_active) {
188753901Smckusick 		sdc_softc[im->im_ctlr].sdc_softas |= (1 << ii->ii_slave);
188853901Smckusick 		return;
188953901Smckusick 	}
189053901Smckusick 	/*
189153901Smckusick 	 * If we have already positioned this drive,
189253901Smckusick 	 * then just put it on the ready queue.
189353901Smckusick 	 */
189453901Smckusick 	if (dp->b_active == 0)
189553901Smckusick 		dp->b_active = 1;
189653901Smckusick 	/*
189753901Smckusick 	 * Device is ready to go
189853901Smckusick 	 * put it on the ready queue for the controller
189953901Smckusick 	 * (unless its already there.)
190053901Smckusick 	 */
190153901Smckusick 	if (dp->b_active != 2) {
190257612Sutashiro 		im->im_tab.b_actf = dp;
190353901Smckusick 		dp->b_active = 2;
190453901Smckusick 	}
190553901Smckusick }
190653901Smckusick 
190753901Smckusick /*
190853901Smckusick  * Start up a transfer on a drive.
190953901Smckusick  */
sdstart(im)191053901Smckusick sdstart(im)
191153901Smckusick 	register struct iop/**/_ctlr *im;
191253901Smckusick {
191353901Smckusick 	register struct buf *bp;
191453901Smckusick 	register struct buf *dp;
191553901Smckusick 	register struct sdc_softc *sdc;
191653901Smckusick 
191753901Smckusick loop:
191853901Smckusick 	/*
191953901Smckusick 	 * Pull a request off the controller queue.
192053901Smckusick 	 */
192153901Smckusick 	if ((dp = im->im_tab.b_actf) == NULL)
192253901Smckusick 		return;
192357612Sutashiro 	if ((bp = dp->b_actf) == NULL)
192457612Sutashiro 		return;
192553901Smckusick 	/*
192653901Smckusick 	 * Mark controller busy, and
192753901Smckusick 	 * determine destination of this request.
192853901Smckusick 	 */
192953901Smckusick 	im->im_tab.b_active++;
193053901Smckusick 
193153901Smckusick 	sdexec(bp);
193253901Smckusick }
193353901Smckusick 
193453901Smckusick void
sdexec(bp)193553901Smckusick sdexec(bp)
193653901Smckusick 	register struct buf *bp;
193753901Smckusick {
193853901Smckusick 	register struct iop/**/_device *ii;
193953901Smckusick 	register struct buf_stat *bs;
194053901Smckusick 	register struct scsi *sc;
194153901Smckusick 	register int ssize;
194253901Smckusick 	register int unit;
194353901Smckusick 	register int intr;
194453901Smckusick 	register int bn;
194553901Smckusick 	struct sdc_softc *sdc;
194653901Smckusick 	struct sdd_softc *sdd;
194753901Smckusick 	struct sdst *st;
194853901Smckusick 	int sz;
194953901Smckusick 	int over;
195053901Smckusick 	struct sc_map *map;
195153901Smckusick 
195253901Smckusick 	unit = dev2unit(bp->b_dev);
195357612Sutashiro 	ii = sddinfo[unit];
195453901Smckusick 	intr = ii->ii_intr;
195553901Smckusick 	sdd = &sdd_softc[unit];
195653901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
195753901Smckusick 
195853901Smckusick 	sc = get_scsi(intr);
195953901Smckusick 
196053901Smckusick 	if (bp == &csdbuf[unit]) {	/* do sdcmd() */
196153901Smckusick 		bcopy((caddr_t)&kernscsi[unit],
196253901Smckusick 			(caddr_t)sc, sizeof(struct scsi));
196353901Smckusick 		if (bp->b_un.b_addr == NULL) {
196453901Smckusick 			map = 0;
196553901Smckusick 		} else {
196653901Smckusick 			map = get_sc_map(intr);
196753901Smckusick 			sc->sc_map = (struct sc_map *)ipc_phys(map);
196853901Smckusick 		}
196953901Smckusick 	} else {			/* R/W */
197053901Smckusick 		ssize = sdd->sdd_sectsize;
197153901Smckusick 
197253901Smckusick 		st = &sdstdrv[unit];
197353901Smckusick 		bn = dkblock(bp);
197453901Smckusick 		if (sdd->sdd_lastblk / st->nspc != bn / st->nspc)
197553901Smckusick 			dk_seek[ii->ii_dk]++;
197653901Smckusick 
197753901Smckusick 		st = &sdstdrv[unit];
197853901Smckusick 		bn = dkblock(bp);
197953901Smckusick 
198053901Smckusick 		/*
198153901Smckusick 		 * Setup for the transfer, and get in the IOP queue.
198253901Smckusick 		 */
198353901Smckusick 		scinit(sc, ii->ii_slave, ssize);
198453901Smckusick 		sc->sc_ctrnscnt = bp->b_bcount - bp->b_resid;
198553901Smckusick 		map = get_sc_map(intr);
198653901Smckusick 		sc->sc_map = (struct sc_map *)ipc_phys(map);
198753901Smckusick 
198853901Smckusick 		/* cdb */
198953901Smckusick 		sc->sc_cdb.un_type1.t1_opcode =
199053901Smckusick 				(bp->b_flags & B_READ) ?	SCOP_EREAD :
199153901Smckusick 				(ii->ii_flags & SD_F_WRTVRFY) ?	SCOP_WRTVRFY :
199253901Smckusick 								SCOP_EWRITE;
199353901Smckusick #ifdef mips
199453901Smckusick 		{
199553901Smckusick 		int v;
199653901Smckusick 
199753901Smckusick 		v = (bn + st->sizes[dev2part(bp->b_dev)].sd_blkoff)
199853901Smckusick 					* DEV_BSIZE / sdd->sdd_sectsize;
199953901Smckusick 		sc->sc_ladhi = v >> 16;
200053901Smckusick 		sc->sc_ladlo = v;
200153901Smckusick 
200253901Smckusick 		v = (sc->sc_ctrnscnt + ssize - 1) / ssize;
200353901Smckusick 		sc->sc_cdb.un_type1.t1_p2 = v >> 8;
200453901Smckusick 		sc->sc_cdb.un_type1.t1_p3 = v;
200553901Smckusick 		}
200653901Smckusick #else
200753901Smckusick 		*(u_int *)(&sc->sc_cdb.un_type1.t1_ladhi) =
200853901Smckusick 				(bn + st->sizes[dev2part(bp->b_dev)].sd_blkoff)
200953901Smckusick 					* DEV_BSIZE / sdd->sdd_sectsize;
201053901Smckusick 		*(u_short *)(&sc->sc_cdb.un_type1.t1_p2) =
201153901Smckusick 				    (sc->sc_ctrnscnt + ssize -1) / ssize;
201253901Smckusick #endif
201353901Smckusick 		if ((sdd->sdd_flags & SDDF_ERASEOFF)
201453901Smckusick 				&& ((bp->b_flags & B_READ) == 0)) {
201553901Smckusick 			sc->sc_ctrl = 0x40;
201653901Smckusick 		}
201753901Smckusick 	}
201853901Smckusick 
201953901Smckusick 	sdc->sdc_firmware |= SDCFW_BUSY;
202053901Smckusick 	iop/**/go(ii, map);
202153901Smckusick }
202253901Smckusick 
202353901Smckusick /*
202453901Smckusick  * Now all ready to go.
202553901Smckusick  */
sddgo(im)202653901Smckusick sddgo(im)
202753901Smckusick 	register struct iop/**/_ctlr *im;
202853901Smckusick {
202953901Smckusick 	register int intr;
203053901Smckusick 
203153901Smckusick 	im->im_tab.b_active = 2;
203253901Smckusick 	intr = im->im_intr;
203353901Smckusick 
203453901Smckusick 	sc_go(intr, get_scsi(intr), SCSI_INTEN);
203553901Smckusick }
203653901Smckusick 
203753901Smckusick /*
203853901Smckusick  * copyin(), copyout() can't use in the interrupt routine.
203953901Smckusick  *	because user process is changed.
204053901Smckusick  */
204153901Smckusick /*
204253901Smckusick  * Handle a disk interrupt.
204353901Smckusick  *	d: controller number
204453901Smckusick  */
sdintr(d)204553901Smckusick sdintr(d)
204653901Smckusick 	int d;
204753901Smckusick {
204853901Smckusick 	register struct iop/**/_ctlr *im;
204953901Smckusick 	register struct sdc_softc *sdc;
205053901Smckusick 	register struct sdd_softc *sdd;
205153901Smckusick 	register struct scsi *sc;
205253901Smckusick 	register int intr;
205353901Smckusick 	register int unit;
205453901Smckusick 	register int slave;
205553901Smckusick 	register int as;
205653901Smckusick 	struct iop/**/_device *ii;
205753901Smckusick 	struct sddevinfo *sdi;
205853901Smckusick 	struct sc_extnd *sce;
205953901Smckusick 	struct sdst *st;
206053901Smckusick 	struct buf *bp;
206153901Smckusick 	struct buf *dp;
206253901Smckusick 	char *erp_page;
206353901Smckusick 	int code;
206453901Smckusick 	int len;
206553901Smckusick 	int tstatus;
206653901Smckusick 	int delay_start();
206753901Smckusick 	int delay_medrmv();
206853901Smckusick 	int wait_re_init_done();
206953901Smckusick 
207053901Smckusick 	im = sdminfo[d];
207153901Smckusick 	sdc = &sdc_softc[im->im_ctlr];
207253901Smckusick 	intr = im->im_intr;
207353901Smckusick 	as = sdc->sdc_softas;
207453901Smckusick 
207553901Smckusick 	sdc->sdc_wticks = 0;
207653901Smckusick 	sc = get_scsi(intr);
207753901Smckusick 	/*
207853901Smckusick 	 * If SDCS_IOCTL bit is set, then don't check error.
207953901Smckusick 	 */
208053901Smckusick 	if (sdc->sdc_state & SDCS_IOCTL) {
208153901Smckusick 		sdc->sdc_state &= ~SDCS_IOCTL;
208253901Smckusick 		sdd = &sdd_softc[(sdip[d][sc->sc_identify & IDT_DRMASK])->ii_unit];
208353901Smckusick 
208453901Smckusick 		if (sdc->sdc_state & SDCS_SCUNLOCK) {
208553901Smckusick 			int s;
208653901Smckusick 
208753901Smckusick 			sdc->sdc_state &= ~SDCS_SCUNLOCK;
208853901Smckusick 			s = splclock();
208953901Smckusick 			if (sdc->sdc_state & SDCS_OPEN_WAIT) {
209053901Smckusick 				sdc->sdc_state &= ~SDCS_OPEN_WAIT;
209153901Smckusick 				wakeup((caddr_t)sdc);
209253901Smckusick 			}
209353901Smckusick 			splx(s);
209453901Smckusick 			/*
209553901Smckusick 			 * UNLOCK SCSI access
209653901Smckusick 			 */
209753901Smckusick 			sdc->sdc_firmware &= ~SDCFW_BUSY;
209853901Smckusick 		}
209953901Smckusick 		return;
210053901Smckusick 	}
210153901Smckusick 
210253901Smckusick 	im->im_tab.b_active = 1;
210353901Smckusick 	/*
210453901Smckusick 	 * Get device and block structures, and a pointer
210553901Smckusick 	 * to the iop_device for the drive.
210653901Smckusick 	 */
210753901Smckusick 	dp = im->im_tab.b_actf;
210853901Smckusick 	bp = dp->b_actf;
210953901Smckusick 	unit = dev2unit(bp->b_dev);
211053901Smckusick 
211153901Smckusick 	ii = sddinfo[unit];
211253901Smckusick 	slave = ii->ii_slave;
211353901Smckusick 	st = &sdstdrv[unit];
211453901Smckusick 	dk_busy &= ~(1 << ii->ii_dk);
211553901Smckusick 	sdd = &sdd_softc[unit];
211653901Smckusick 	sdi = &sddevinfo[ii->ii_type];
211753901Smckusick 	sce = (struct sc_extnd *)&sdc_rsense[ii->ii_ctlr][0];
211853901Smckusick 
211953901Smckusick 	/*
212053901Smckusick 	 * Check error on the drive.
212153901Smckusick 	 */
212253901Smckusick 	tstatus = sc->sc_tstatus & TGSTMASK;
212353901Smckusick 	if (sc->sc_istatus != INST_EP) {
212453901Smckusick 		/*
212553901Smckusick 		 * initiator status is bad.
212653901Smckusick 		 *	check & retry !!
212753901Smckusick 		 */
212853901Smckusick 		if ((sc->sc_istatus&(INST_EP|INST_PRE)) == (INST_EP|INST_PRE)) {
212953901Smckusick 			/* detect parity error or abnormal terminate */
213053901Smckusick 			if ((sc->sc_istatus & INST_LB) == 0)
213153901Smckusick 				printf("sd%d: SCSI bus parity error\n", unit);
213253901Smckusick 			sdc->sdc_countcc--;
213353901Smckusick 			goto sdintr_exec;
213453901Smckusick 		}
213553901Smckusick 		if ((sc->sc_istatus & INST_EP) == 0) {
213653901Smckusick 			if (sc->sc_istatus & (INST_WAIT | INST_IP | INST_WR)) {
213753901Smckusick 				if (++sdc->sdc_retrycnt < NRETRY) {
213853901Smckusick 					im->im_tab.b_active = 2;
213953901Smckusick 					/*
214053901Smckusick 					 * Konomama return sitemo,
214153901Smckusick 					 * lost interrupt ni narudake deha
214253901Smckusick 					 * naidarou ka ?
214353901Smckusick 					 * Isso error ni sitahou ga
214453901Smckusick 					 * ii nodeha naidarou ka ?
214553901Smckusick 					 */
214653901Smckusick 					return;
214753901Smckusick 				}
214853901Smckusick 			}
214953901Smckusick 			printf("SCSI%d: abnormal termination\n", intr);
215053901Smckusick 			printf("ISTAT = 0x%x, TSTAT = 0x%x\n",
215153901Smckusick 					sc->sc_istatus, sc->sc_tstatus);
215253901Smckusick 			if (++sdc->sdc_nhrderr >= MAXHRDERR) {
215353901Smckusick 				printf("SCSI%d: too many hard errors\n", intr);
215453901Smckusick 				sdc->sdc_nhrderr = 0;
215553901Smckusick 				goto sdintr_error;
215653901Smckusick 			}
215753901Smckusick 			screset(intr);
215853901Smckusick 			goto sdintr_exec;
215953901Smckusick 		}
216053901Smckusick 		if ((sc->sc_istatus & (INST_TO|INST_HE)) != 0) {
216153901Smckusick 			if (sc->sc_istatus & INST_HE) {
216253901Smckusick 				/*
216353901Smckusick 				 * SCSI bus reset is occured.
216453901Smckusick 				 *	to be continue --> hdreset()
216553901Smckusick 				 */
216653901Smckusick 				re_init_done = 0;
216753901Smckusick 				timeout(wait_re_init_done, bp, 10*hz);
216853901Smckusick 				return;
216953901Smckusick 			}
217053901Smckusick 			if (++sdc->sdc_nhrderr >= MAXHRDERR) {
217153901Smckusick 				printf("SCSI%d: too many hard errors (ISTAT=0x%x)\n",
217253901Smckusick 					intr, sc->sc_istatus);
217353901Smckusick 				sdc->sdc_nhrderr = 0;
217453901Smckusick 				goto sdintr_error;
217553901Smckusick 			}
217653901Smckusick 			if (++sdc->sdc_retrycnt >= NRETRY) {
217753901Smckusick 				printf("SCSI%d: too many initiator errors (ISTAT=0x%x)\n",
217853901Smckusick 					intr, sc->sc_istatus);
217953901Smckusick 				goto sdintr_error;
218053901Smckusick 			}
218153901Smckusick 			DELAY(D100MSEC * 10);
218253901Smckusick 			goto sdintr_exec;
218353901Smckusick 		}
218453901Smckusick 	}
218553901Smckusick 
218653901Smckusick 	if (sdd->sdd_flags & SDDF_SKIPCHECK)
218753901Smckusick 		goto sdintr_done;
218853901Smckusick 
218953901Smckusick check_target_status:
219053901Smckusick 	/*
219153901Smckusick 	 * check target status
219253901Smckusick 	 */
219353901Smckusick 	switch (sdc->sdc_state) {
219453901Smckusick 
219553901Smckusick 	/********************************/
219653901Smckusick 	/*				*/
219753901Smckusick 	/*	NORMAL OPERATION	*/
219853901Smckusick 	/*				*/
219953901Smckusick 	/********************************/
220053901Smckusick 	case SDCS_NORMAL:
220153901Smckusick 		switch (tstatus) {
220253901Smckusick 
220353901Smckusick 		case TGST_GOOD:
220453901Smckusick 			break;
220553901Smckusick 
220653901Smckusick 		case TGST_CC:
220753901Smckusick 			sdc->sdc_state |= SDCS_RSENSE;
220853901Smckusick sdintr_rsense:
220953901Smckusick 			im->im_tab.b_active = 2;
221053901Smckusick 			bzero((caddr_t)sce, RSEN_CNT);
221153901Smckusick 			scop_rsense(intr, sc, slave,
221253901Smckusick 					SCSI_INTEN, RSEN_CNT, (caddr_t)sce);
221353901Smckusick 			return;
221453901Smckusick 
221553901Smckusick 		case TGST_BUSY:
221653901Smckusick 			if (++sdc->sdc_retrycnt > MAXRETRYCNT) {
221753901Smckusick 				goto sdintr_error;
221853901Smckusick 			}
221953901Smckusick 			timeout(sdexec, (caddr_t)bp, hz);
222053901Smckusick 			return;
222153901Smckusick 
222253901Smckusick 		default:
222353901Smckusick 			printf("sd%d: bad target status 0x%x\n",
222453901Smckusick 						unit, sc->sc_tstatus);
222553901Smckusick 			goto sdintr_error;
222653901Smckusick 		}
222753901Smckusick 		break;
222853901Smckusick 
222953901Smckusick 	/****************************************/
223053901Smckusick 	/*					*/
223153901Smckusick 	/*	REQUEST SENSE analysis		*/
223253901Smckusick 	/*					*/
223353901Smckusick 	/****************************************/
223453901Smckusick 	case SDCS_RSENSE:
223553901Smckusick 	case SDCS_PREVRMB|SDCS_RSENSE:
223653901Smckusick 	case SDCS_ECC|SDCS_RASREAD|SDCS_RSENSE:
223753901Smckusick 	case SDCS_ECC|SDCS_RASWRITE|SDCS_RSENSE:
223853901Smckusick 	case SDCS_ECCOFF|SDCS_RSENSE:
223953901Smckusick 	case SDCS_ECCOFF|SDCS_RASBLK|SDCS_RSENSE:
224053901Smckusick 	case SDCS_ECCOFF|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE:
224153901Smckusick 	case SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE:
224253901Smckusick 	case SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE:
224353901Smckusick 		if (tstatus != TGST_GOOD) {
224453901Smckusick 			printf("sd%d: bad target status 0x%x\n",
224553901Smckusick 						unit, sc->sc_tstatus);
224653901Smckusick 			goto sdintr_error;
224753901Smckusick 		}
224853901Smckusick 		/*
224953901Smckusick 		 * error message print out
225053901Smckusick 		 */
225153901Smckusick 		code = sderrordisp(sce, ii);
225253901Smckusick 
225353901Smckusick 
225453901Smckusick 		if ((sdc->sdc_state == (SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE)) ||
225553901Smckusick 		    (sdc->sdc_state == (SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE))) {
225653901Smckusick 			printf("sd%d: cannot reassign block %d\n",
225753901Smckusick 						unit, sdd->sdd_badsect);
225853901Smckusick 			goto sdintr_error;
225953901Smckusick 		}
226053901Smckusick 		if (sdc->sdc_state == (SDCS_PREVRMB|SDCS_RSENSE)) {
226153901Smckusick 			if (sce->sce_skey == 0x2) {
226253901Smckusick 				/*
226353901Smckusick 				 * Not ready
226453901Smckusick 				 */
226553901Smckusick 				sdc->sdc_state = SDCS_PREVRMB;
226653901Smckusick 				timeout(delay_medrmv, (caddr_t)ii, hz);
226753901Smckusick 				return;
226853901Smckusick 			}
226953901Smckusick 		}
227053901Smckusick 
227153901Smckusick 		/*			*/
227253901Smckusick 		/* RSENSE error handler	*/
227353901Smckusick 		/*			*/
227453901Smckusick 		switch (code) {
227553901Smckusick 
227653901Smckusick 		/********************************/
227753901Smckusick 		/*	continue		*/
227853901Smckusick 		/********************************/
227953901Smckusick 		/* NO SENSE */
228053901Smckusick 		case 0x00:	/* No Additional Sense Information */
228153901Smckusick 		/* RECOVERED ERROR */
228253901Smckusick 		case 0x38:	/* Recovered with Auto-Reallocation */
228353901Smckusick 			sdc->sdc_state &= ~SDCS_RSENSE;
228453901Smckusick 			goto check_target_status;
228553901Smckusick 
228653901Smckusick 		/********************************/
228753901Smckusick 		/*	continue or error	*/
228853901Smckusick 		/********************************/
228953901Smckusick 		/* ILLEGAL REQUEST */
229053901Smckusick 
229153901Smckusick 		case 0x21:	/* illegal Logical Block Address */
229253901Smckusick 			if (&st->sizes[dev2part(bp->b_dev)] == NULL)
229353901Smckusick 				goto sdintr_error;
229453901Smckusick 			if (bp->b_bcount > 0) {
229553901Smckusick 				bp->b_resid = bp->b_bcount
229653901Smckusick 				    - (sdd->sdd_badsect * sdd->sdd_sectsize
229753901Smckusick 				    - (st->sizes[dev2part(bp->b_dev)].sd_blkoff
229853901Smckusick 				    + dkblock(bp)) * DEV_BSIZE);
229953901Smckusick 			}
230053901Smckusick 			if (bp->b_resid >= bp->b_bcount || bp->b_resid <= 0) {
230153901Smckusick 				/*
230253901Smckusick 				 * all I/O failure
230353901Smckusick 				 */
230453901Smckusick 				bp->b_resid = bp->b_bcount;
230553901Smckusick 				goto sdintr_error;
230653901Smckusick 			}
230753901Smckusick 			/* Ignore error */
230853901Smckusick 			break;
230953901Smckusick 
231053901Smckusick 		/* MEDIUM ERROR */
231153901Smckusick 		case 0x31:	/* Medium Format Corrupted */
231253901Smckusick 			sdd->sdd_flags |= SDDF_NONFMT;
231353901Smckusick 			/* Ignore error */
231453901Smckusick 			break;
231553901Smckusick 
231653901Smckusick 		/********************************/
231753901Smckusick 		/*	more retry		*/
231853901Smckusick 		/********************************/
231953901Smckusick 		/* MEDIUM or RECOVERED ERROR */
232053901Smckusick 		case 0x10:	/* ID CRC Error */
232153901Smckusick 		case 0x12:	/* No Address Mark found in ID field */
232253901Smckusick 		case 0x13:	/* No Address Mark found in Data field */
232353901Smckusick 		case 0x14:	/* No recode found */
232453901Smckusick 		/* H/W or MEDIUM or RECOVERED ERROR */
232553901Smckusick 		case 0x15:	/* Seek Positioning Error */
232653901Smckusick 			if (sd_ignore_error) {
232753901Smckusick 				sdc->sdc_state = SDCS_NORMAL;
232853901Smckusick 				goto check_target_status;
232953901Smckusick 			}
233053901Smckusick 			/* fall through */
233153901Smckusick 
233253901Smckusick 		/* H/W ERROR */
233353901Smckusick 		case 0x01:	/* No Index/Address Mark Found signal */
233453901Smckusick 		case 0x02:	/* No Seek Complete */
233553901Smckusick 		case 0x06:	/* No Track Zero found */
233653901Smckusick 		/* H/W ERROR or RECOVERED ERROR */
233753901Smckusick 		case 0x03:	/* Write Fault */
233853901Smckusick 		case 0x08:	/* Logical Unit Communication Failure */
233953901Smckusick 		case 0x09:	/* Track Following Error */
234053901Smckusick 		case 0x0b:	/* Load/Unload Failure */
234153901Smckusick 		case 0x0c:	/* Spindle Failure */
234253901Smckusick 		case 0x0d:	/* Focus Failure */
234353901Smckusick 		case 0x0e:	/* Tracking Failure */
234453901Smckusick 		case 0x0f:	/* Drive Initialization Failure */
234553901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_REZERO;
234653901Smckusick 
234753901Smckusick 			scinit(sc, slave, sdd->sdd_sectsize);
234853901Smckusick 			/* sc_cdb */
234953901Smckusick 			sc->sc_opcode = SCOP_REZERO;
235053901Smckusick 
235153901Smckusick 			sddgo(im);
235253901Smckusick 			return;
235353901Smckusick 
235453901Smckusick 		/********************************/
235553901Smckusick 		/*	re-allocate & retry	*/
235653901Smckusick 		/********************************/
235753901Smckusick 		/* MEDIUM or RECOVERED ERROR */
235853901Smckusick 		case 0x11:	/* Unrecovered Read Error */
235953901Smckusick 			if (sdc->sdc_state & SDCS_RASREAD) {
236053901Smckusick sdintr_lostdata:
236153901Smckusick 				sdc->sdc_state =
236253901Smckusick 					SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA;
236353901Smckusick 				im->im_tab.b_active = 2;
236453901Smckusick 				scop_rasblk(intr, sc, slave,
236553901Smckusick 					SCSI_INTEN, sdd->sdd_badsect);
236653901Smckusick 				sdd->sdd_flags &= ~SDDF_VBADSECT;
236753901Smckusick 				return;
236853901Smckusick 			}
236953901Smckusick 			/* fall through */
237053901Smckusick 
237153901Smckusick 		/* RECOVERED ERROR */
237253901Smckusick 		case 0x17:	/* Recovered read data with retries */
237353901Smckusick 		case 0x18:	/* Recovered read data with ECC */
237453901Smckusick 			/*
237553901Smckusick 			 * set ECC ON & more retry
237653901Smckusick 			 */
237753901Smckusick 			if (sdc->sdc_firmware & SDCFW_DEFMODE)
237853901Smckusick 				goto sdintr_ecc;
237953901Smckusick 
238053901Smckusick 			if (sdc->sdc_state & SDCS_RASREAD)
238153901Smckusick 				goto sdintr_rasblk;
238253901Smckusick 
238353901Smckusick 			sdc->sdc_state = SDCS_ECC;
238453901Smckusick 			goto sdintr_msel_set;
238553901Smckusick 
238653901Smckusick 		/********************************/
238753901Smckusick 		/*	unit start & retry	*/
238853901Smckusick 		/********************************/
238953901Smckusick 		/* NOT READY */
239053901Smckusick 		case 0x04:	/* Drive Not Ready */
239153901Smckusick 			if (sdc->sdc_state & SDCS_ECC)
239253901Smckusick 				sdc->sdc_state = SDCS_ECCOFF|SDCS_RETRY;
239353901Smckusick 			else
239453901Smckusick 				sdc->sdc_state = SDCS_RETRY;
239553901Smckusick 			goto sdintr_stst;
239653901Smckusick 
239753901Smckusick 		/********************************/
239853901Smckusick 		/*	retry			*/
239953901Smckusick 		/********************************/
240053901Smckusick 		/* UNIT ATTENTION */
240153901Smckusick 		case 0x28:	/* Medium Changed */
240253901Smckusick 			sdd->sdd_flags &= ~(SDDF_NONFMT
240353901Smckusick 					    |SDDF_SAMEDSK
240453901Smckusick 					    |SDDF_REQ_EJECT
240553901Smckusick 					    |SDDF_XUSE
240653901Smckusick 					    |SDDF_INHRMV
240753901Smckusick 					    |SDDF_ERASEOFF);
240853901Smckusick 			/* fall through */
240953901Smckusick 
241053901Smckusick 		case 0x29: /* Power On or Reset or Bus Device Reset */
241153901Smckusick 			if (sdc->sdc_firmware & SDCFW_RMB) {
241253901Smckusick 				/***************************/
241353901Smckusick 				/* medium removable device */
241453901Smckusick 				/***************************/
241553901Smckusick 				sdc->sdc_state = SDCS_PREVRMB;
241653901Smckusick 				im->im_tab.b_active = 2;
241753901Smckusick 				scop_medrmv(intr, sc, slave,
241853901Smckusick 					    SCSI_INTEN, SDRMV_PREV);
241953901Smckusick 				return;
242053901Smckusick 			}
242153901Smckusick 
242253901Smckusick 		case 0x2a:	/* Mode Select Parameter Changed */
242353901Smckusick 		case 0x47:	/* SCSI interface bus parity error */
242453901Smckusick 			if (sdc->sdc_state & SDCS_ECC) {
242553901Smckusick 				sdc->sdc_state = SDCS_RETRY;
242653901Smckusick 				goto sdintr_msel_reset;
242753901Smckusick 			}
242853901Smckusick 			sdc->sdc_state = SDCS_NORMAL;
242953901Smckusick 			goto sdintr_exec;
243053901Smckusick 
243153901Smckusick 		/********************************/
243253901Smckusick 		/*	set error flag		*/
243353901Smckusick 		/********************************/
243453901Smckusick 		case 0x40:	/* RAM failure */
243553901Smckusick 		case 0x41:	/* Data Path diagnostic failure */
243653901Smckusick 		case 0x42:	/* Power On diagnostic failure */
243753901Smckusick 
243853901Smckusick 		case 0xb2:	/* Caddy load/eject failed */
243953901Smckusick 		case 0xb4:	/* Focus servo failure */
244053901Smckusick 		case 0xb5:	/* Spindle servo failure */
244153901Smckusick 		case 0xb6:	/* Caddy load mechanism failed */
244253901Smckusick 			goto sdintr_error;
244353901Smckusick 
244453901Smckusick /*MO*/		case 0x80:	/* Limit Laser Life */
244553901Smckusick /*MO*/		case 0x81:	/* Focus Coil Over-current Failure */
244653901Smckusick /*MO*/		case 0x82:	/* Tracking Coil Over-current Failure */
244753901Smckusick /*MO*/		case 0x83:	/* Temperature Alarm */
244853901Smckusick /*CD*/	/*	case 0x80: */	/* Prevent bit is set */
244953901Smckusick /*CD*/	/*	case 0x81: */	/* Logical unit is reserved */
245053901Smckusick /*CD*/	/*	case 0x82: */	/* End of usr area encountered */
245153901Smckusick /*CD*/	/*	case 0x83: */	/* Overlapped commands attempted */
245253901Smckusick 			goto sdintr_error;
245353901Smckusick 
245453901Smckusick 		default:
245553901Smckusick 			/*
245653901Smckusick 			 *	error detect, but what shall we do ?
245753901Smckusick 			 */
245853901Smckusick 	/*	case 0x05: */	/* Drive Not Selected */
245953901Smckusick 	/*	case 0x07: */	/* Multiple Drives Selected */
246053901Smckusick 	/*	case 0x0a: */	/* No disk */
246153901Smckusick 	/*	case 0x1a: */	/* Parameter overrun */
246253901Smckusick 	/*	case 0x1b: */	/* Synchronous transfer error */
246353901Smckusick 	/*	case 0x1d: */	/* Compare error */
246453901Smckusick 	/*	case 0x22: */	/* Illegal function for device type */
246553901Smckusick 	/*	case 0x23: */	/* Illegal function for Medium type */
246653901Smckusick 	/*	case 0x25: */	/* Illegal LUN */
246753901Smckusick 	/*	case 0x27: */	/* Write Protected */
246853901Smckusick 	/*	case 0x2b: */	/* Firmware has been downloaded */
246953901Smckusick 	/*	case 0x39: */	/* Automatic Reallocation Failure */
247053901Smckusick 	/*	case 0x43: */	/* Message Reject Error */
247153901Smckusick 	/*	case 0x45: */	/* Selection/Reselection failure */
247253901Smckusick 	/*	case 0x48: */	/* Initiator detected error */
247353901Smckusick 	/*	case 0x49: */	/* Inappropriate/illegal message */
247453901Smckusick 	/*	case 0x60: */	/* COPY: STATUS error */
247553901Smckusick 	/*	case 0x85: */	/* Audio address not valid */
247653901Smckusick 	/*	case 0xb0: */	/* Caddy not inserted in drive */
247753901Smckusick 	/*	case 0xb1: */	/* Unable to recover TOC */
247853901Smckusick 	/*	case 0xb3: */	/* CIRC unrecovered data error(L-EC off) */
247953901Smckusick 	/*	case 0xc3: */	/* COPY: Illegale CDB length */
248053901Smckusick 	/*	case 0xc5: */	/* COPY: Catastrophic error */
248153901Smckusick 	/*	case 0xc6: */	/* COPY: Illegal phase change */
248253901Smckusick 	/*	case 0xfc: */	/* COPY: MODE SENSE failed */
248353901Smckusick 
248453901Smckusick 			/*
248553901Smckusick 			 *	medium error
248653901Smckusick 			 */
248753901Smckusick 	/*	case 0x19: */	/* Defect list error */
248853901Smckusick 	/*	case 0x1c: */	/* Primary Defect List not found */
248953901Smckusick 	/*	case 0x30: */	/* Incompatible Cartridge */
249053901Smckusick 	/*	case 0x32: */	/* No Spare Defect Location Available */
249153901Smckusick 	/*	case 0x3a: */	/* Defect List Update Failure */
249253901Smckusick 	/*	case 0x3d: */	/* Defect List Not Available */
249353901Smckusick 			goto sdintr_error;
249453901Smckusick 		}
249553901Smckusick 		/*
249653901Smckusick 		 * No error detected or ignored.
249753901Smckusick 		 */
249853901Smckusick 		break;
249953901Smckusick 
250053901Smckusick 	/************************************************/
250153901Smckusick 	/*						*/
250253901Smckusick 	/*	PREVENT MEDIUM REMOVABLE COMMAND	*/
250353901Smckusick 	/*						*/
250453901Smckusick 	/************************************************/
250553901Smckusick 	case SDCS_PREVRMB:
250653901Smckusick 		if (tstatus == TGST_CC) {
250753901Smckusick 			sdc->sdc_state = SDCS_PREVRMB|SDCS_RSENSE;
250853901Smckusick 			goto sdintr_rsense;
250953901Smckusick 		}
251053901Smckusick 		sdd->sdd_flags |= SDDF_INHRMV;
251153901Smckusick 		if (sdc->sdc_state & SDCS_ECC) {
251253901Smckusick 			sdc->sdc_state = SDCS_RETRY;
251353901Smckusick 			goto sdintr_msel_reset;
251453901Smckusick 		}
251553901Smckusick 		sdc->sdc_state = SDCS_NORMAL;
251653901Smckusick 		goto sdintr_exec;
251753901Smckusick 		break;
251853901Smckusick 
251953901Smckusick 	/****************************************/
252053901Smckusick 	/*					*/
252153901Smckusick 	/*	REZERO done & RETRY COMMAND	*/
252253901Smckusick 	/*					*/
252353901Smckusick 	/****************************************/
252453901Smckusick 	case SDCS_ECC|SDCS_ECC_HOLD|SDCS_REZERO:
252553901Smckusick 		if (sdc->sdc_firmware & SDCFW_DEFMODE) {
252653901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY;
252753901Smckusick 			goto sdintr_stst;
252853901Smckusick 		}
252953901Smckusick 
253053901Smckusick 		sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD;
253153901Smckusick 		goto sdintr_msel_set;
253253901Smckusick 
253353901Smckusick 	/********************************/
253453901Smckusick 	/*				*/
253553901Smckusick 	/*	RETRY COMMAND		*/
253653901Smckusick 	/*				*/
253753901Smckusick 	/********************************/
253853901Smckusick 	case SDCS_RETRY:
253953901Smckusick 		sdc->sdc_state = SDCS_NORMAL;
254053901Smckusick 		goto sdintr_exec;
254153901Smckusick 
254253901Smckusick 	/************************************************/
254353901Smckusick 	/*						*/
254453901Smckusick 	/*	ERROR CORRECTION ON MODE SELECT result	*/
254553901Smckusick 	/*						*/
254653901Smckusick 	/************************************************/
254753901Smckusick 	case SDCS_ECC:
254853901Smckusick 		if (tstatus != TGST_GOOD) {
254953901Smckusick 			printf("sd%d: bad target status 0x%x\n",
255053901Smckusick 						unit, sc->sc_tstatus);
255153901Smckusick 			goto sdintr_error;
255253901Smckusick 		}
255353901Smckusick sdintr_ecc:
255453901Smckusick 		if (bp->b_flags & B_READ) {
255553901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_RASREAD;
255653901Smckusick 			im->im_tab.b_active = 2;
255753901Smckusick 			scop_rdwr(intr, sc, slave, SCSI_INTEN,
255853901Smckusick 					B_READ, sdwork,
255953901Smckusick 					sdd->sdd_badsect, sdd->sdd_sectsize);
256053901Smckusick 			return;
256153901Smckusick 		}
256253901Smckusick 		goto sdintr_rasblk;
256353901Smckusick 
256453901Smckusick 	/************************************************/
256553901Smckusick 	/*						*/
256653901Smckusick 	/*	READ DATA from BAD BLOCK result		*/
256753901Smckusick 	/*						*/
256853901Smckusick 	/************************************************/
256953901Smckusick 	case SDCS_ECC|SDCS_RASREAD:
257053901Smckusick 		if (tstatus == TGST_CC) {
257153901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_RASREAD|SDCS_RSENSE;
257253901Smckusick 			goto sdintr_rsense;
257353901Smckusick 		} else if (tstatus != TGST_GOOD) {
257453901Smckusick 			printf("sd%d: bad target status 0x%x\n",
257553901Smckusick 						unit, sc->sc_tstatus);
257653901Smckusick 			printf("sd%d: cannot read block\n", unit);
257753901Smckusick 			goto sdintr_error;
257853901Smckusick 		}
257953901Smckusick sdintr_rasblk:
258053901Smckusick 		if (sdd->sdd_flags & SDDF_WPROTECT)
258153901Smckusick 			goto sdintr_error;
258253901Smckusick 		sdc->sdc_state = SDCS_ECC|SDCS_RASBLK;
258353901Smckusick 		im->im_tab.b_active = 2;
258453901Smckusick 		scop_rasblk(intr, sc, slave, SCSI_INTEN, sdd->sdd_badsect);
258553901Smckusick 		sdd->sdd_flags &= ~SDDF_VBADSECT;
258653901Smckusick 		return;
258753901Smckusick 
258853901Smckusick 	/****************************************/
258953901Smckusick 	/*					*/
259053901Smckusick 	/*	REASSIGN BLOCK result		*/
259153901Smckusick 	/*					*/
259253901Smckusick 	/****************************************/
259353901Smckusick 	case SDCS_ECC|SDCS_RASBLK:
259453901Smckusick 		if (tstatus == TGST_CC) {
259553901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_RASBLK|SDCS_RSENSE;
259653901Smckusick 			goto sdintr_rsense;
259753901Smckusick 		} else if (tstatus != TGST_GOOD) {
259853901Smckusick 			printf("sd%d: bad target status 0x%x\n",
259953901Smckusick 						unit, sc->sc_tstatus);
260053901Smckusick 			goto sdintr_error;
260153901Smckusick 		}
260253901Smckusick 		printf("sd%d: block %d is reassigned\n",
260353901Smckusick 			unit, sdd->sdd_badsect);
260453901Smckusick 		if (bp->b_flags & B_READ) {
260553901Smckusick sdintr_raswrite:
260653901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_RASWRITE;
260753901Smckusick 			im->im_tab.b_active = 2;
260853901Smckusick 			scop_rdwr(intr, sc, slave, SCSI_INTEN,
260953901Smckusick 					B_WRITE, sdwork,
261053901Smckusick 					sdd->sdd_badsect, sdd->sdd_sectsize);
261153901Smckusick 			return;
261253901Smckusick 		}
261353901Smckusick 		sdc->sdc_state = SDCS_RETRY;
261453901Smckusick 		goto sdintr_msel_reset;
261553901Smckusick 
261653901Smckusick 	/************************************************/
261753901Smckusick 	/*						*/
261853901Smckusick 	/*	WRITE DATA to REASSIGNED BLOCK result	*/
261953901Smckusick 	/*						*/
262053901Smckusick 	/************************************************/
262153901Smckusick 	case SDCS_ECC|SDCS_RASWRITE:
262253901Smckusick 		if (tstatus == TGST_CC) {
262353901Smckusick 			sdc->sdc_state = SDCS_ECC|SDCS_RASWRITE|SDCS_RSENSE;
262453901Smckusick 			goto sdintr_rsense;
262553901Smckusick 		} else if (tstatus != TGST_GOOD) {
262653901Smckusick 			printf("sd%d: bad target status 0x%x\n",
262753901Smckusick 						unit, sc->sc_tstatus);
262853901Smckusick 			goto sdintr_error;
262953901Smckusick 		}
263053901Smckusick 		sdc->sdc_state = SDCS_RETRY;
263153901Smckusick 		goto sdintr_msel_reset;
263253901Smckusick 
263353901Smckusick 	/****************************************/
263453901Smckusick 	/*					*/
263553901Smckusick 	/*	reset ECC & RETRY TIMES		*/
263653901Smckusick 	/*					*/
263753901Smckusick 	/****************************************/
263853901Smckusick 	case SDCS_ECCOFF|SDCS_RETRY:
263953901Smckusick 		sdc->sdc_state = SDCS_RETRY;
264053901Smckusick 		goto sdintr_msel_reset;
264153901Smckusick 
264253901Smckusick 	/********************************************************/
264353901Smckusick 	/*							*/
264453901Smckusick 	/*	READ DATA from BAD BLOCK result in faliure	*/
264553901Smckusick 	/*							*/
264653901Smckusick 	/********************************************************/
264753901Smckusick 	case SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA:
264853901Smckusick 		if (tstatus == TGST_CC) {
264953901Smckusick 			sdc->sdc_state =
265053901Smckusick 				SDCS_ECC|SDCS_RASBLK|SDCS_LOSTDATA|SDCS_RSENSE;
265153901Smckusick 			goto sdintr_rsense;
265253901Smckusick 		} else if (tstatus != TGST_GOOD) {
265353901Smckusick 			printf("sd%d: rasblk: bad target status 0x%x\n",
265453901Smckusick 				unit, sc->sc_tstatus);
265553901Smckusick 			goto sdintr_error;
265653901Smckusick 		}
265753901Smckusick 		bzero(sdwork, sdd->sdd_sectsize);
265853901Smckusick 		scop_rdwr(intr, sc, slave, SCSI_INTDIS,
265953901Smckusick 			B_WRITE, sdwork, sdd->sdd_badsect, sdd->sdd_sectsize);
266053901Smckusick 		printf("sd%d: block %d is reassigned (lost data)\n",
266153901Smckusick 			unit, sdd->sdd_badsect);
266253901Smckusick 		goto sdintr_error;
266353901Smckusick 
266453901Smckusick 	/****************************************/
266553901Smckusick 	/*					*/
266653901Smckusick 	/*	issue START UNIT command	*/
266753901Smckusick 	/*					*/
266853901Smckusick 	/****************************************/
266953901Smckusick 	case SDCS_ECC|SDCS_ECC_HOLD:
267053901Smckusick 		/*
267153901Smckusick 		 * Drive not ready... so start..
267253901Smckusick 		 */
267353901Smckusick 		sdc->sdc_state = SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY;
267453901Smckusick sdintr_stst:
267553901Smckusick 		timeout(delay_start, (caddr_t)ii, hz);
267653901Smckusick 		return;
267753901Smckusick 
267853901Smckusick 	/****************************************/
267953901Smckusick 	/*					*/
268053901Smckusick 	/*	RETRY with ECC & more RETRYS	*/
268153901Smckusick 	/*					*/
268253901Smckusick 	/****************************************/
268353901Smckusick 	case SDCS_ECC|SDCS_ECC_HOLD|SDCS_RETRY:
268453901Smckusick 		sdc->sdc_state = SDCS_ECCOFF;
268553901Smckusick sdintr_exec:
268653901Smckusick 		if (sdc->sdc_countcc++ > MAXRETRYCNT)
268753901Smckusick 			goto sdintr_error;
268853901Smckusick 		sdexec(bp);
268953901Smckusick 		return;
269053901Smckusick 
269153901Smckusick 	/****************************************/
269253901Smckusick 	/*					*/
269353901Smckusick 	/*	reset ECC & RETRY TIMES		*/
269453901Smckusick 	/*					*/
269553901Smckusick 	/****************************************/
269653901Smckusick 	case SDCS_ECCOFF:
269753901Smckusick 		if (tstatus == TGST_CC) {
269853901Smckusick 			sdc->sdc_state = SDCS_ECCOFF|SDCS_RSENSE;
269953901Smckusick 			goto sdintr_rsense;
270053901Smckusick 		} else if (tstatus != TGST_GOOD) {
270153901Smckusick 			printf("sd%d: bad target status 0x%x\n",
270253901Smckusick 				unit, sc->sc_tstatus);
270353901Smckusick 			goto sdintr_error;
270453901Smckusick 		}
270553901Smckusick 		sdc->sdc_state = SDCS_NORMAL;
270653901Smckusick 		goto sdintr_msel_reset;
270753901Smckusick 
270853901Smckusick sdintr_msel_set:
270953901Smckusick 		/*
271053901Smckusick 		 * set more ERROR RECOVERY PARAMETERS
271153901Smckusick 		 */
271253901Smckusick 		if ((erp_page = sdi->max_ERP_page) == NULL)
271353901Smckusick 			goto check_target_status;
271453901Smckusick 		bzero((caddr_t)sc->sc_param, 4);
271553901Smckusick 		len = *(erp_page + 1) + 2;
271653901Smckusick 		bcopy(erp_page, &sc->sc_param[4], len);
271753901Smckusick 
271853901Smckusick 		im->im_tab.b_active = 2;
271953901Smckusick 		scop_mselect(intr, sc, slave, SCSI_INTEN,
272053901Smckusick 				(SDM_PF<<24) + len +4, (caddr_t)0);
272153901Smckusick 		return;
272253901Smckusick 
272353901Smckusick sdintr_msel_reset:
272453901Smckusick 		if (sdc->sdc_firmware & SDCFW_DEFMODE)
272553901Smckusick 			goto sdintr_exec;
272653901Smckusick 
272753901Smckusick 		/*
272853901Smckusick 		 * set normal ERROR RECOVERY PARAMETERS
272953901Smckusick 		 */
273053901Smckusick 		erp_page = sdi->ERP_page;
273153901Smckusick 		bzero((caddr_t)sc->sc_param, 4);
273253901Smckusick 		len = *(erp_page + 1) + 2;
273353901Smckusick 		bcopy(erp_page, &sc->sc_param[4], len);
273453901Smckusick 
273553901Smckusick 		im->im_tab.b_active = 2;
273653901Smckusick 		scop_mselect(intr, sc, slave, SCSI_INTEN,
273753901Smckusick 				(SDM_PF<<24) + len +4, (caddr_t)0);
273853901Smckusick 		return;
273953901Smckusick 
274053901Smckusick sdintr_error:
274153901Smckusick 		bp->b_flags |= B_ERROR;
274253901Smckusick 		if (sdc->sdc_state & SDCS_ECC) {
274353901Smckusick 			sdc->sdc_state = SDCS_NORMAL;
274453901Smckusick 			goto sdintr_msel_reset;
274553901Smckusick 		}
274653901Smckusick 		break;
274753901Smckusick 
274853901Smckusick 	/*
274953901Smckusick 	 * UNKNOWN STATUS
275053901Smckusick 	 */
275153901Smckusick 	default:
275253901Smckusick 		printf("sd%d: unknown status (0x%x)\n", unit, sdc->sdc_state);
275353901Smckusick 		goto sdintr_error;
275453901Smckusick 	}
275553901Smckusick 
275653901Smckusick sdintr_done:
275753901Smckusick 
275853901Smckusick 	if (bp->b_flags & B_ERROR) {
275953901Smckusick         printf("%s%d%c: hard error sn%d ", "sd",
276053901Smckusick             minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno);
276153901Smckusick 		printf("\n");
276253901Smckusick 	}
276353901Smckusick 	sdd->sdd_lastblk = dkblock(bp) + btodb(bp->b_bcount - bp->b_resid);
276453901Smckusick 	sdc->sdc_countcc = 0;
276553901Smckusick 	sdc->sdc_retrycnt = 0;
276653901Smckusick 	sdd->sdd_flags &= ~SDDF_VBADSECT;
276753901Smckusick 
276853901Smckusick 	if (im->im_tab.b_active) {
276953901Smckusick 		im->im_tab.b_active = 0;
277053901Smckusick 		im->im_tab.b_errcnt = 0;
277157612Sutashiro 		im->im_tab.b_actf = 0;
277253901Smckusick 		dp->b_active = 0;
277353901Smckusick 		dp->b_errcnt = 0;
277457612Sutashiro 		dp->b_actf = bp->b_actf;
277553901Smckusick 		if (bp == &csdbuf[unit]) {
277653901Smckusick 			register struct scsi *ksc = &kernscsi[unit];
277753901Smckusick 			/* copy result */
277853901Smckusick 			bcopy((caddr_t)sc, (caddr_t)ksc, sizeof(struct scsi));
277953901Smckusick 		}
278053901Smckusick 
278153901Smckusick 		iodone(bp);
278253901Smckusick 
278353901Smckusick 		/*
278453901Smckusick 		 * If this unit has more work to do,
278553901Smckusick 		 * then start it up right away.
278653901Smckusick 		 */
278753901Smckusick 		if (dp->b_actf)
278853901Smckusick 			sdustart(ii);
278953901Smckusick 	}
279053901Smckusick 	as &= ~(1 << slave);
279153901Smckusick 
279253901Smckusick 	sdc->sdc_state = SDCS_NORMAL;
279353901Smckusick 
279453901Smckusick 	/*
279553901Smckusick 	 * UNLOCK SCSI access
279653901Smckusick 	 */
279753901Smckusick 	sdc->sdc_firmware &= ~SDCFW_BUSY;
279853901Smckusick 
279953901Smckusick start:
280053901Smckusick 	/*
280153901Smckusick 	 * Process other units which need attention.
280253901Smckusick 	 * For each unit which needs attention, call
280353901Smckusick 	 * the unit start routine to place the slave
280453901Smckusick 	 * on the controller device queue.
280553901Smckusick 	 */
280653901Smckusick 	sdc->sdc_softas = 0;
280753901Smckusick 	while (unit = ffs(as)) {
280853901Smckusick 		unit--;
280953901Smckusick 		as &= ~(1 << unit);
281053901Smckusick 		sdustart(sdip[im->im_ctlr][unit]);
281153901Smckusick 	}
281253901Smckusick 	/*
281353901Smckusick 	 * If the controller is not transferring,
281453901Smckusick 	 * but there are devices ready to transfer,
281553901Smckusick 	 * start the controller.
281653901Smckusick 	 */
281753901Smckusick 	if (im->im_tab.b_actf && im->im_tab.b_active == 0)
281853901Smckusick 		(void) sdstart(im);
281953901Smckusick }
282053901Smckusick 
wait_re_init_done(bp)282153901Smckusick wait_re_init_done(bp)
282253901Smckusick 	register struct buf *bp;
282353901Smckusick {
282453901Smckusick 	if (re_init_done >= 2)
282553901Smckusick 		sdexec(bp);
282653901Smckusick 	else
282753901Smckusick 		timeout(wait_re_init_done, bp, 10*hz);
282853901Smckusick }
282953901Smckusick 
283053901Smckusick delay_start(ii)
283153901Smckusick 	struct iop/**/_device *ii;
283253901Smckusick {
283353901Smckusick 	ii->ii_mi->im_tab.b_active = 2;
283453901Smckusick 	scop_stst(ii->ii_intr, get_scsi(ii->ii_intr), ii->ii_slave,
283553901Smckusick 			SCSI_INTEN, SDSS_START);
283653901Smckusick }
283753901Smckusick 
283853901Smckusick delay_medrmv(ii)
283953901Smckusick 	struct iop/**/_device *ii;
284053901Smckusick {
284153901Smckusick 	ii->ii_mi->im_tab.b_active = 2;
284253901Smckusick 	scop_medrmv(ii->ii_intr, get_scsi(ii->ii_intr), ii->ii_slave,
284353901Smckusick 			SCSI_INTEN, SDRMV_PREV);
284453901Smckusick }
284553901Smckusick 
sderrordisp(rsen_data,ii)284653901Smckusick sderrordisp(rsen_data, ii)
284753901Smckusick 	u_char *rsen_data;
284853901Smckusick 	struct iop/**/_device *ii;
284953901Smckusick {
285053901Smckusick 	register struct sc_extnd *sce;
285153901Smckusick 	register struct sdc_softc *sdc;
285253901Smckusick 	register struct sdd_softc *sdd;
285353901Smckusick 	register int unit;
285453901Smckusick 	register int code;
285553901Smckusick 	struct sc_nextnd *scn;
285653901Smckusick 	struct msg_list *ml;
285753901Smckusick 
285853901Smckusick 	unit = ii->ii_unit;
285953901Smckusick 	sdc = &sdc_softc[ii->ii_ctlr];
286053901Smckusick 	sdd = &sdd_softc[unit];
286153901Smckusick 
286253901Smckusick 	sce = (struct sc_extnd *)rsen_data;
286353901Smckusick 
286453901Smckusick 	if (sce->sce_extend == 0x70) {
286553901Smckusick 		/*
286653901Smckusick 		 * Extended Sense data
286753901Smckusick 		 */
286853901Smckusick 		code = sce->sce_sdecode;
286953901Smckusick 
287053901Smckusick 		if (code & 0x80)
287153901Smckusick 			ml = ecodelist_mo;
287253901Smckusick 		else
287353901Smckusick 			ml = ecodelist;
287453901Smckusick 
287553901Smckusick 		if (sce->sce_advalid) {
287653901Smckusick 			if ((sdd->sdd_flags & SDDF_VBADSECT) == 0) {
287753901Smckusick #ifdef mips
287853901Smckusick 				sdd->sdd_badsect = (sce->sce_infob1 << 24) +
287953901Smckusick 						   (sce->sce_infob2 << 16) +
288053901Smckusick 						   (sce->sce_infob3 <<  8) +
288153901Smckusick 						   (sce->sce_infob4);
288253901Smckusick #else
288353901Smckusick 				sdd->sdd_badsect = *((int *)&sce->sce_infob1);
288453901Smckusick #endif
288553901Smckusick 				sdd->sdd_flags |= SDDF_VBADSECT;
288653901Smckusick 			}
288753901Smckusick 		}
288853901Smckusick 
288953901Smckusick 		if (!rsense_msg_disp && !isdispmsg(code, ml, sdc->sdc_countcc))
289053901Smckusick 			return (code);
289153901Smckusick 
289253901Smckusick 		if (sce->sce_advalid) {
289353901Smckusick 			int sn;
289453901Smckusick #ifdef mips
289553901Smckusick 			sn = (sce->sce_infob1 << 24) +
289653901Smckusick 			     (sce->sce_infob2 << 16) +
289753901Smckusick 			     (sce->sce_infob3 <<  8) +
289853901Smckusick 			     (sce->sce_infob4);
289953901Smckusick #else
290053901Smckusick 			sn = *((int *)&sce->sce_infob1);
290153901Smckusick #endif
290253901Smckusick 			if (sce->sce_addlen >= 5) {
290353901Smckusick 				printf("sd%d(sn %d): skey=0x%x, code=0x%x\n",
290453901Smckusick 					unit, sn, sce->sce_skey, code);
290553901Smckusick 			} else {
290653901Smckusick 				printf("sd%d(sn %d): skey=0x%x\n",
290753901Smckusick 					unit, sn, sce->sce_skey);
290853901Smckusick 			}
290953901Smckusick 		} else {
291053901Smckusick 			if (sce->sce_addlen >= 5)
291153901Smckusick 				printf("sd%d: skey=0x%x, code=0x%x\n",
291253901Smckusick 					unit, sce->sce_skey, code);
291353901Smckusick 			else
291453901Smckusick 				printf("sd%d: skey=0x%x\n",
291553901Smckusick 					unit, sce->sce_skey);
291653901Smckusick 		}
291753901Smckusick 		if (sce->sce_addlen >= 6)
291853901Smckusick 			printf("sd%d: ASCQ=0x%x\n", unit, sce->sce_ascq);
291953901Smckusick 		{
292053901Smckusick 			u_char *p;
292153901Smckusick 			int len;
292253901Smckusick 
292353901Smckusick 			len = 8 + sce->sce_addlen;
292453901Smckusick 			if (len > RSEN_CNT)
292553901Smckusick 				len = RSEN_CNT;
292653901Smckusick 			p = (u_char *)sce;
292753901Smckusick 			printf("sd%d: ", unit);
292853901Smckusick 			while (len--)
292953901Smckusick 				printf("%x ", *p++);
293053901Smckusick 			printf("\n");
293153901Smckusick 		}
293253901Smckusick 	} else {
293353901Smckusick 		/*
293453901Smckusick 		 * Non-extended Sense data
293553901Smckusick 		 */
293653901Smckusick 		scn = (struct sc_nextnd *)rsen_data;
293753901Smckusick 
293853901Smckusick 		code = scn->scn_ecode;
293953901Smckusick 		ml = ecodelist;
294053901Smckusick 		if (sce->sce_advalid) {
294153901Smckusick 			if ((sdd->sdd_flags & SDDF_VBADSECT) == 0) {
294253901Smckusick 				sdd->sdd_badsect = scn->scn_secno;
294353901Smckusick 				sdd->sdd_flags |= SDDF_VBADSECT;
294453901Smckusick 			}
294553901Smckusick 		}
294653901Smckusick 		if (rsense_msg_disp || isdispmsg(code, ml, sdc->sdc_countcc)) {
294753901Smckusick 			if (sce->sce_advalid)
294853901Smckusick 				printf("sd%d(sn %d): code=0x%x\n",
294953901Smckusick 					unit, scn->scn_secno, code);
295053901Smckusick 			else
295153901Smckusick 				printf("sd%d: code=0x%x\n", unit, code);
295253901Smckusick 		}
295353901Smckusick 	}
295453901Smckusick 	return (code);
295553901Smckusick }
295653901Smckusick 
295753901Smckusick void
sdminphys(bp)295853901Smckusick sdminphys(bp)
295953901Smckusick 	struct buf *bp;
296053901Smckusick {
296153901Smckusick 	if (bp->b_bcount > MAXSDPHYS)
296253901Smckusick 		bp->b_bcount = MAXSDPHYS;
296353901Smckusick }
296453901Smckusick 
296553901Smckusick 
296653901Smckusick #define	sdphysio	physio
296753901Smckusick 
sdread(dev,uio,flag)296853901Smckusick sdread(dev, uio, flag)
296953901Smckusick 	register dev_t dev;
297053901Smckusick 	struct uio *uio;
297153901Smckusick 	int flag;
297253901Smckusick {
297353901Smckusick 	register struct iop/**/_device *ii;
297453901Smckusick 	register int unit;
297553901Smckusick 
297653901Smckusick 	unit = dev2unit(dev);
297753901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0)
297853901Smckusick 		return (ENXIO);
297953901Smckusick 
298053901Smckusick 	return (sdphysio(sdstrategy, &rsdbuf[unit], dev, B_READ, sdminphys, uio));
298153901Smckusick }
298253901Smckusick 
sdwrite(dev,uio,flag)298353901Smckusick sdwrite(dev, uio, flag)
298453901Smckusick 	register dev_t dev;
298553901Smckusick 	struct uio *uio;
298653901Smckusick 	int flag;
298753901Smckusick {
298853901Smckusick 	register struct iop/**/_device *ii;
298953901Smckusick 	register int unit;
299053901Smckusick 
299153901Smckusick 	unit = dev2unit(dev);
299253901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0)
299353901Smckusick 		return (ENXIO);
299453901Smckusick 
299553901Smckusick 	return (sdphysio(sdstrategy, &rsdbuf[unit], dev, B_WRITE, sdminphys, uio));
299653901Smckusick }
299753901Smckusick 
299853901Smckusick #define MAXBL 256
299953901Smckusick 
300058620Sutashiro struct Partinfo {
300158620Sutashiro /*00*/	daddr_t dp_nblocks;		/* partition size (sector #) */
300258620Sutashiro /*04*/	daddr_t dp_blkoff;		/* partition start block */
300358620Sutashiro /*08*/
300458620Sutashiro };
300558620Sutashiro 
300658620Sutashiro struct dkst {
300758620Sutashiro /*00*/	int dks_ncyl;			/* # cylinders / drive */
300858620Sutashiro /*04*/	int dks_ntrak;			/* # tracks / cylinder */
300958620Sutashiro /*08*/	int dks_nsect;			/* # sectors / track */
301058620Sutashiro /*0c*/	int dks_rps;			/* # revolutions / second */
301158620Sutashiro /*10*/
301258620Sutashiro };
301358620Sutashiro 
301453901Smckusick /*ARGSUSED*/
sdioctl(dev,cmd,data,flag)301553901Smckusick sdioctl(dev, cmd, data, flag)
301653901Smckusick 	dev_t dev;
301753901Smckusick 	int cmd;
301853901Smckusick 	caddr_t data;
301953901Smckusick 	int flag;
302053901Smckusick {
302153901Smckusick 	register struct iop/**/_device *ii;
302253901Smckusick 	register struct sc_ureq *scu;
302353901Smckusick 	register struct sdst *st;
302453901Smckusick 	register struct scsi *sc;
302553901Smckusick 	register int unit;
302653901Smckusick 	register int ctlr;
302753901Smckusick 	register int slave;
302853901Smckusick 	struct sdc_softc *sdc;
302953901Smckusick 	struct sdd_softc *sdd;
303053901Smckusick 	struct Partinfo *pi;
303153901Smckusick 	struct dkst *di;
303253901Smckusick 	struct buf *bp;
303353901Smckusick 	struct sddevinfo *sdi;
303453901Smckusick 	struct sdst *stp;
303553901Smckusick 	struct scsi uscsi;
303653901Smckusick 	int error;
303753901Smckusick 	int i;
303853901Smckusick 	int s;
303953901Smckusick 	int tstatus;
304053901Smckusick 	char *p;
304153901Smckusick 	int blkno, count;
304253901Smckusick 
304353901Smckusick 	unit = dev2unit(dev);
304453901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
304553901Smckusick 		return (ENXIO);
304653901Smckusick 
304753901Smckusick 	slave = ii->ii_slave;
304853901Smckusick 	ctlr = ii->ii_ctlr;
304953901Smckusick 	sdc = &sdc_softc[ctlr];
305053901Smckusick 	sdd = &sdd_softc[unit];
305153901Smckusick 	sc = &uscsi;
305253901Smckusick 
305353901Smckusick 	error = 0;
305453901Smckusick 	switch (cmd) {
305553901Smckusick 
305653901Smckusick 	case DIOCWLABEL:
305753901Smckusick 		if (*(int *)data & SD_F_ENW)
305853901Smckusick 			ii->ii_flags |= SD_F_ENW;
305953901Smckusick 		else
306053901Smckusick 			ii->ii_flags &= ~SD_F_ENW;
306153901Smckusick 		break;
306253901Smckusick 
306353901Smckusick 	case DIOCGDINFO:
306453901Smckusick 		*(struct disklabel *)data = sdlabel[unit];
306553901Smckusick 		break;
306653901Smckusick 
306753901Smckusick 	case DIOCSDINFO:
306853901Smckusick 		sdlabel[unit] = *(struct disklabel *)data;
306953901Smckusick 		disklabel2sdst(unit, &sdlabel[unit], &sdstdrv[unit]);
307053901Smckusick 		break;
307153901Smckusick 
307253901Smckusick 	case DIOCWDINFO:
307353901Smckusick 	case DKIOCRGEOM:
307453901Smckusick 		switch (cmd) {
307553901Smckusick 		case DKIOCRGEOM:
307653901Smckusick 			st = &sdstdrv[unit];
307753901Smckusick 			sdi = &sddevinfo[ii->ii_type];
307853901Smckusick 			stp = sdi->sdstp;
307953901Smckusick 
308053901Smckusick 			st->ncyl = stp->ncyl;	/* # cylinders / drive */
308153901Smckusick 			st->ntrak = stp->ntrak;	/* # tracks / cylinder */
308253901Smckusick 			st->nsect = stp->nsect;	/* # sectors / track */
308353901Smckusick 			st->rps = stp->rps;	/* # revolutions / second */
308453901Smckusick 
308553901Smckusick 			sdst2disklabel(unit, st, &sdlabel[unit]);
308653901Smckusick 
308753901Smckusick 			if (*(int *)data == RGEOM_SDINFO)
308853901Smckusick 				goto done;
308953901Smckusick 
309053901Smckusick 			break;
309153901Smckusick 
309253901Smckusick 		case DIOCWDINFO:
309353901Smckusick 			sdlabel[unit] = *(struct disklabel *)data;
309453901Smckusick 
309553901Smckusick 			break;
309653901Smckusick 		}
309753901Smckusick 
309853901Smckusick 		/*
309953901Smckusick 		 * Common code for DIOCWDINFO and DKIOCRGEOM
310053901Smckusick 		 */
310153901Smckusick 
310253901Smckusick 		/**** READ sector 0 ****/
310353901Smckusick 		/*
310453901Smckusick 		 * LOCK sdtmp buffer
310553901Smckusick 		 */
310653901Smckusick 		s = splclock();
310753901Smckusick 		while (sdtmp_stat & B_BUSY) {
310853901Smckusick 			sdtmp_stat |= B_WANTED;
310953901Smckusick 			sleep((caddr_t)sdtmp, PRIBIO);
311053901Smckusick 		}
311153901Smckusick 		sdtmp_stat |= B_BUSY;
311253901Smckusick 		splx(s);
311353901Smckusick 
311453901Smckusick 		bzero(sdtmp, DEV_BSIZE);
311553901Smckusick 
311653901Smckusick 		if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
311753901Smckusick 			scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
311853901Smckusick 			uscsi.sc_cpoint = sdtmp;
311953901Smckusick 			uscsi.sc_ctrnscnt = DEV_BSIZE;
312053901Smckusick 			uscsi.sc_opcode = SCOP_READ;
312153901Smckusick 			uscsi.sc_lad = 0;
312253901Smckusick 			uscsi.sc_count = 1;
312353901Smckusick 			error = sdcmd(dev, &uscsi);
312453901Smckusick 		} else {
312553901Smckusick 			error = EIO;
312653901Smckusick 		}
312753901Smckusick 
312853901Smckusick 		if (error) {
312953901Smckusick 			/*
313053901Smckusick 			 * UNLOCK sdtmp buffer
313153901Smckusick 			 */
313253901Smckusick 			s = splclock();
313353901Smckusick 			if (sdtmp_stat & B_WANTED)
313453901Smckusick 				wakeup((caddr_t)sdtmp);
313553901Smckusick 			sdtmp_stat &= ~(B_BUSY|B_WANTED);
313653901Smckusick 			splx(s);
313753901Smckusick 
313853901Smckusick 			break;
313953901Smckusick 		}
314053901Smckusick 
314153901Smckusick 		*(struct disklabel *)(sdtmp + LABELOFFSET) = sdlabel[unit];
314253901Smckusick 
314353901Smckusick 		/**** WRITE sector 0 ****/
314453901Smckusick 
314553901Smckusick 		if (error == 0) {
314653901Smckusick 			if ((sdd->sdd_flags & SDDF_NONFMT) == 0) {
314753901Smckusick 				scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
314853901Smckusick 				uscsi.sc_cpoint = sdtmp;
314953901Smckusick 				uscsi.sc_ctrnscnt = DEV_BSIZE;
315053901Smckusick 				uscsi.sc_opcode = SCOP_WRITE;
315153901Smckusick 
315253901Smckusick 				uscsi.sc_lad = 0;
315353901Smckusick 				uscsi.sc_count = 1;
315453901Smckusick 
315553901Smckusick 				error = sdcmd(dev, &uscsi);
315653901Smckusick 			} else
315753901Smckusick 				error = EIO;
315853901Smckusick 		}
315953901Smckusick 
316053901Smckusick 		/*
316153901Smckusick 		 * UNLOCK sdtmp buffer
316253901Smckusick 		 */
316353901Smckusick 		s = splclock();
316453901Smckusick 		if (sdtmp_stat & B_WANTED)
316553901Smckusick 			wakeup((caddr_t)sdtmp);
316653901Smckusick 		sdtmp_stat &= ~(B_BUSY|B_WANTED);
316753901Smckusick 		splx(s);
316853901Smckusick 
316953901Smckusick 		disklabel2sdst(unit, &sdlabel[unit], &sdstdrv[unit]);
317053901Smckusick 
317153901Smckusick 		break;
317253901Smckusick 
317353901Smckusick 	case DKIOCGGEOM:
317453901Smckusick 		st = &sdstdrv[unit];
317553901Smckusick 		di = (struct dkst *)data;
317653901Smckusick 
317753901Smckusick 		di->dks_ncyl = st->ncyl;	/* # cylinders / drive */
317853901Smckusick 		di->dks_ntrak = st->ntrak;	/* # tracks / cylinder */
317953901Smckusick 		di->dks_nsect = st->nsect;	/* # sectors / track */
318053901Smckusick 		di->dks_rps = st->rps;		/* # revolutions / second */
318153901Smckusick 
318253901Smckusick 		break;
318353901Smckusick 
318453901Smckusick 	case DKIOCSGEOM:
318553901Smckusick 		st = &sdstdrv[unit];
318653901Smckusick 		di = (struct dkst *)data;
318753901Smckusick 
318853901Smckusick 		st->ncyl = di->dks_ncyl;	/* # cylinders / drive */
318953901Smckusick 		st->ntrak = di->dks_ntrak;	/* # tracks / cylinder */
319053901Smckusick 		st->nsect = di->dks_nsect;	/* # sectors / track */
319153901Smckusick 		st->rps = di->dks_rps;		/* # revolutions / second */
319253901Smckusick 
319353901Smckusick 		sdst2disklabel(unit, st, &sdlabel[unit]);
319453901Smckusick 		break;
319553901Smckusick 
319653901Smckusick 	case DKIOCGPART:
319753901Smckusick 	case DKIOCSPART:
319853901Smckusick 		/*
319953901Smckusick 		 * partition information
320053901Smckusick 		 */
320153901Smckusick 		st = &sdstdrv[unit];
320253901Smckusick 		pi = (struct Partinfo *)data;
320353901Smckusick 
320453901Smckusick 		if (cmd == DKIOCGPART) {
320553901Smckusick 			pi->dp_nblocks = st->sizes[dev2part(dev)].sd_nblocks;
320653901Smckusick 			pi->dp_blkoff = st->sizes[dev2part(dev)].sd_blkoff;
320753901Smckusick 		} else {
320853901Smckusick 			st->sizes[dev2part(dev)].sd_nblocks = pi->dp_nblocks;
320953901Smckusick 			st->sizes[dev2part(dev)].sd_blkoff = pi->dp_blkoff;
321053901Smckusick 
321153901Smckusick 			sdst2disklabel(unit, st, &sdlabel[unit]);
321253901Smckusick 		}
321353901Smckusick 		break;
321453901Smckusick 
321553901Smckusick 	case DKIOCGUNIT:
321653901Smckusick 		*(int *)data = slave;
321753901Smckusick 		break;
321853901Smckusick 
321953901Smckusick 	case DKIOCGCHAN:
322053901Smckusick 		*(int *)data = ii->ii_intr;
322153901Smckusick 		break;
322253901Smckusick 
322353901Smckusick 	case DKIOCSEEK:
322453901Smckusick 		scinit(sc, slave, sdd->sdd_sectsize);
322553901Smckusick 		sc->sc_opcode = SCOP_SEEK;
322653901Smckusick 		sc->sc_lad = *(int *)data;
322753901Smckusick 
322853901Smckusick 		(void) sdcmd(dev, sc);
322953901Smckusick 		tstatus = sc->sc_tstatus & TGSTMASK;
323053901Smckusick 		if ((sc->sc_istatus != INST_EP) || (tstatus != TGST_GOOD))
323153901Smckusick 			error = ESPIPE;
323253901Smckusick 		break;
323353901Smckusick 
323453901Smckusick 	case DKIOCRSEC0:
323553901Smckusick 	case DKIOCRBOOT1:
323653901Smckusick 	case DKIOCRBOOT:
323753901Smckusick 		if (sdd->sdd_flags & SDDF_NONFMT) {
323853901Smckusick 			error = EIO;
323953901Smckusick 			break;
324053901Smckusick 		}
324153901Smckusick 		switch (cmd) {
324253901Smckusick 
324353901Smckusick 		case DKIOCRSEC0:
324453901Smckusick 			blkno = 0;
324553901Smckusick 			count = 1;
324653901Smckusick 			break;
324753901Smckusick 
324853901Smckusick 		case DKIOCRBOOT1:
324953901Smckusick 			blkno = 1;
325053901Smckusick 			count = 15;
325153901Smckusick 			break;
325253901Smckusick 
325353901Smckusick 		default:
325453901Smckusick 			blkno = 0;
325553901Smckusick 			count = 16;
325653901Smckusick 		}
325753901Smckusick 		p = (char *)*(int *)data;
325853901Smckusick 		for (i = 0; !error && i < count; i++) {
325953901Smckusick 			s = splclock();
326053901Smckusick 			while (sdtmp_stat & B_BUSY) {
326153901Smckusick 				sdtmp_stat |= B_WANTED;
326253901Smckusick 				sleep((caddr_t)sdtmp, PRIBIO);
326353901Smckusick 			}
326453901Smckusick 			sdtmp_stat |= B_BUSY;
326553901Smckusick 			splx(s);
326653901Smckusick 			scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
326753901Smckusick 			uscsi.sc_cpoint = sdtmp;
326853901Smckusick 			uscsi.sc_ctrnscnt = DEV_BSIZE;
326953901Smckusick 			uscsi.sc_opcode = SCOP_READ;
327053901Smckusick 			uscsi.sc_lad = blkno;
327153901Smckusick 			uscsi.sc_count = 1;
327253901Smckusick 			if (error = sdcmd(dev, &uscsi))
327353901Smckusick 				goto dkior_done;
327453901Smckusick 			if (error = copyout(sdtmp, p, DEV_BSIZE))
327553901Smckusick 				goto dkior_done;
327653901Smckusick 			blkno++;
327753901Smckusick 			p += DEV_BSIZE;
327853901Smckusick 
327953901Smckusick dkior_done:
328053901Smckusick 			s = splclock();
328153901Smckusick 			if (sdtmp_stat & B_WANTED)
328253901Smckusick 				wakeup((caddr_t)sdtmp);
328353901Smckusick 			sdtmp_stat &= ~(B_BUSY|B_WANTED);
328453901Smckusick 			splx(s);
328553901Smckusick 		}
328653901Smckusick 		break;
328753901Smckusick 
328853901Smckusick 	case DKIOCWSEC0:
328953901Smckusick 	case DKIOCWBOOT1:
329053901Smckusick 	case DKIOCWBOOT:
329153901Smckusick 		if (sdd->sdd_flags & SDDF_NONFMT) {
329253901Smckusick 			error = EIO;
329353901Smckusick 			break;
329453901Smckusick 		}
329553901Smckusick 		switch (cmd) {
329653901Smckusick 
329753901Smckusick 		case DKIOCWSEC0:
329853901Smckusick 			blkno = 0;
329953901Smckusick 			count = 1;
330053901Smckusick 			break;
330153901Smckusick 
330253901Smckusick 		case DKIOCWBOOT1:
330353901Smckusick 			blkno = 1;
330453901Smckusick 			count = 15;
330553901Smckusick 			break;
330653901Smckusick 
330753901Smckusick 		default:
330853901Smckusick 			blkno = 0;
330953901Smckusick 			count = 16;
331053901Smckusick 		}
331153901Smckusick 		p = (char *)*(int *)data;
331253901Smckusick 		for (i = 0; !error && i < count; i++) {
331353901Smckusick 			s = splclock();
331453901Smckusick 			while (sdtmp_stat & B_BUSY) {
331553901Smckusick 				sdtmp_stat |= B_WANTED;
331653901Smckusick 				sleep(sdtmp, PRIBIO);
331753901Smckusick 			}
331853901Smckusick 			sdtmp_stat |= B_BUSY;
331953901Smckusick 			splx(s);
332053901Smckusick 			if (error = copyin(p, sdtmp, DEV_BSIZE))
332153901Smckusick 				goto dkiow_done;
332253901Smckusick 			scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
332353901Smckusick 			uscsi.sc_cpoint = sdtmp;
332453901Smckusick 			uscsi.sc_ctrnscnt = DEV_BSIZE;
332553901Smckusick 			uscsi.sc_opcode = SCOP_WRITE;
332653901Smckusick 			uscsi.sc_lad = blkno;
332753901Smckusick 			uscsi.sc_count = 1;
332853901Smckusick 			if (error = sdcmd(dev, &uscsi))
332953901Smckusick 				goto dkiow_done;
333053901Smckusick 			blkno++;
333153901Smckusick 			p += DEV_BSIZE;
333253901Smckusick 
333353901Smckusick dkiow_done:
333453901Smckusick 			s = splclock();
333553901Smckusick 			if (sdtmp_stat & B_WANTED)
333653901Smckusick 				wakeup(sdtmp);
333753901Smckusick 			sdtmp_stat &= ~(B_BUSY|B_WANTED);
333853901Smckusick 			splx(s);
333953901Smckusick 		}
334053901Smckusick 		break;
334153901Smckusick 
334253901Smckusick 	case SDIOC_PRVRMV:
334353901Smckusick 	case SDIOC_ALWRMV:
334453901Smckusick 		/*
334553901Smckusick 		 * prevent/allow medium removal
334653901Smckusick 		 */
334753901Smckusick 		scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
334853901Smckusick 		sc->sc_opcode = SCOP_MEDRMV;
334953901Smckusick 		sc->sc_count = (cmd==SDIOC_PRVRMV)? SDRMV_PREV : SDRMV_ALLOW;
335053901Smckusick 		if (cmd == SDIOC_PRVRMV)
335153901Smckusick 			sdd->sdd_flags |= SDDF_INHRMV;
335253901Smckusick 		else
335353901Smckusick 			sdd->sdd_flags &= ~SDDF_INHRMV;
335453901Smckusick 
335553901Smckusick 		error = sdcmd(dev, sc);
335653901Smckusick 		break;
335753901Smckusick 
335853901Smckusick 	case SDIOC_SXUSE:
335953901Smckusick 		if (isalone(unit) != ONLY_ONE)
336053901Smckusick 			return (EBUSY);
336153901Smckusick 		sdd->sdd_flags |= SDDF_XUSE;
336253901Smckusick 		break;
336353901Smckusick 
336453901Smckusick 	case SDIOC_RXUSE:
336553901Smckusick 		sdd->sdd_flags &= ~SDDF_XUSE;
336653901Smckusick 		break;
336753901Smckusick 
336853901Smckusick 	case SDIOC_ERSON:
336953901Smckusick 		sdd->sdd_flags &= ~SDDF_ERASEOFF;
337053901Smckusick 		break;
337153901Smckusick 
337253901Smckusick 	case SDIOC_ERSOFF:
337353901Smckusick 		if ((sdd->sdd_flags & SDDF_XUSE) != 0)
337453901Smckusick 			return (EBUSY);
337553901Smckusick 		sdd->sdd_flags |= SDDF_ERASEOFF;
337653901Smckusick 		sdd->sdd_flags &= ~SDDF_NONFMT;
337753901Smckusick 		break;
337853901Smckusick 
337953901Smckusick 	case SDIOC_FORMAT:
338053901Smckusick 		/*
338153901Smckusick 		 * format unit
338253901Smckusick 		 */
338353901Smckusick 		if ((flag & FWRITE) == 0)
338453901Smckusick 			return (EINVAL);
338553901Smckusick 		if (isalone(unit) != ONLY_ONE)
338653901Smckusick 			return (EBUSY);
338753901Smckusick 		sdd->sdd_flags |= SDDF_XUSE;
338853901Smckusick 		sdd->sdd_flags &= ~(SDDF_NONFMT|SDDF_FMTDONE|SDDF_SAMEDSK);
338953901Smckusick 		scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
339053901Smckusick 		sc->sc_ctrnscnt = 4;
339153901Smckusick 		sc->sc_opcode = SCOP_FMT;
339253901Smckusick 
339353901Smckusick 		sc->sc_lad = ((sddevinfo[ii->ii_type].fmt_opts & FMT_DLFMT)
339453901Smckusick 				| SDF_FMTDAT) << 16;
339553901Smckusick 
339653901Smckusick 		switch (sddevinfo[ii->ii_type].type) {
339753901Smckusick 
339853901Smckusick 		case SMO_S501:
339953901Smckusick 		case SMO_S501_ISO:
340053901Smckusick 		case SMO_S501_ISO2:
340153901Smckusick 			sc->sc_lad |= ((SDF_MKCDA|SDF_MKPLST) << 8);
340253901Smckusick 			break;
340353901Smckusick 
340453901Smckusick 		default:
340553901Smckusick 			break;
340653901Smckusick 		}
340753901Smckusick 
340853901Smckusick 		{
340953901Smckusick 			struct fmt_data *fdata = (struct fmt_data *)data;
341053901Smckusick 
341153901Smckusick 			error = copyin((caddr_t)fdata->dlh, sc->sc_param, 4);
341253901Smckusick 			if (error != 0) {
341353901Smckusick 				sdd->sdd_flags &= ~SDDF_XUSE;
341453901Smckusick 				break;
341553901Smckusick 			}
341653901Smckusick 			if (fdata->noglist)
341753901Smckusick 				sc->sc_lad |= (SDF_CMPLST<<16);
341853901Smckusick 		}
341953901Smckusick 
342053901Smckusick 		if (sdd->sdd_flags & SDDF_ERASEOFF)
342153901Smckusick 			sc->sc_ctrl = 0x40;
342253901Smckusick 
342353901Smckusick 		error = sdcmd(dev, sc);
342453901Smckusick 		sdd->sdd_flags &= ~SDDF_XUSE;
342553901Smckusick 		break;
342653901Smckusick 
342753901Smckusick 	case SDIOC_FORMAT2:
342853901Smckusick 		/*
342953901Smckusick 		 * format unit
343053901Smckusick 		 */
343153901Smckusick 		if ((flag & FWRITE) == 0)
343253901Smckusick 			return (EINVAL);
343353901Smckusick 		if (isalone(unit) != ONLY_ONE)
343453901Smckusick 			return (EBUSY);
343553901Smckusick 		sdd->sdd_flags |= SDDF_XUSE;
343653901Smckusick 		sdd->sdd_flags &= ~(SDDF_NONFMT|SDDF_FMTDONE|SDDF_SAMEDSK);
343753901Smckusick 
343853901Smckusick 		scu = (struct sc_ureq *)data;
343953901Smckusick 		error = sd_scu_exec(dev, scu, sc);
344053901Smckusick 		sdd->sdd_flags &= ~SDDF_XUSE;
344153901Smckusick 		break;
344253901Smckusick 
344353901Smckusick 	case SDIOC_GSTOPT:
344453901Smckusick 	case SDIOC_SSTOPT:
344553901Smckusick 		/*
344653901Smckusick 		 * get/set stop-unit timer
344753901Smckusick 		 */
344853901Smckusick 		if (cmd == SDIOC_GSTOPT)
344953901Smckusick 			*(int *)data = sdd->sdd_stoptime;
345053901Smckusick 		else {
345153901Smckusick 			if (*(int *)data == 0)
345253901Smckusick 				return (EINVAL);
345353901Smckusick 			sdd->sdd_stoptime = *(int *)data;
345453901Smckusick 		}
345553901Smckusick 		break;
345653901Smckusick 
345753901Smckusick 	case SDIOC_SEJECT:
345853901Smckusick 		/*
345953901Smckusick 		 * set auto eject flag
346053901Smckusick 		 */
346153901Smckusick 		sdd->sdd_flags |= SDDF_REQ_EJECT;
346253901Smckusick 		break;
346353901Smckusick 
346453901Smckusick 	case SDIOC_GFLAGS:
346553901Smckusick 		/*
346653901Smckusick 		 * get ii->ii_flags
346753901Smckusick 		 */
346853901Smckusick 		*(int *)data = ii->ii_flags;
346953901Smckusick 		break;
347053901Smckusick 
347153901Smckusick 	case SDIOC_SFLAGS:
347253901Smckusick 		/*
347353901Smckusick 		 * set ii->ii_flags
347453901Smckusick 		 */
347553901Smckusick 		ii->ii_flags = *(int *)data;
347653901Smckusick 		break;
347753901Smckusick 
347853901Smckusick 	case SDIOC_RASBLK:
347953901Smckusick 		/*
348053901Smckusick 		 * reassign block
348153901Smckusick 		 */
348253901Smckusick 		{
348353901Smckusick 			struct sc_rab *sca = (struct sc_rab *)sc->sc_param;
348453901Smckusick 
348553901Smckusick 			scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
348653901Smckusick 			sc->sc_opcode = SCOP_RASBLK;
348753901Smckusick 			sc->sc_ctrnscnt = 8;
348853901Smckusick 
348953901Smckusick 			sca->sca_dllen = 4;
349053901Smckusick 			sca->sca_dlad[0] = *(int *)data;
349153901Smckusick 
349253901Smckusick 			error = sdcmd(dev, sc);
349353901Smckusick 		}
349453901Smckusick 		break;
349553901Smckusick 
349653901Smckusick 	case SDIOC_GNICKNAME:
349753901Smckusick 		{
349853901Smckusick 			int len;
349953901Smckusick 
350053901Smckusick 			len = strlen(sddevinfo[ii->ii_type].call_name);
350153901Smckusick 
350253901Smckusick 			if (len > IOCPARM_MASK)
350353901Smckusick 				len = IOCPARM_MASK;
350453901Smckusick 
350553901Smckusick 			error = copyout(
350653901Smckusick 				(caddr_t) sddevinfo[ii->ii_type].call_name,
350753901Smckusick 				(caddr_t) *(int *)data,
350853901Smckusick 				len);
350953901Smckusick 		}
351053901Smckusick 		break;
351153901Smckusick 
351253901Smckusick 	case SDIOC_GTYPINDEX:
351353901Smckusick 		*(int *)data = (int)ii->ii_type;
351453901Smckusick 		break;
351553901Smckusick 
351653901Smckusick #ifdef SDIOC_SSYNCPARAM
351753901Smckusick 	case SDIOC_SSYNCPARAM:
351853901Smckusick 		{
351953901Smckusick 		struct sync_param *syncp;
352053901Smckusick 
352153901Smckusick 		syncp = (struct sync_param *)data;
352253901Smckusick 		scinit(sc, ii->ii_slave, sdd->sdd_sectsize);
352353901Smckusick 		sc->sc_opcode = SCOP_TST;
352453901Smckusick 		sc->sc_message = MSG_EXTND;	/* extended message */
352553901Smckusick 		sc->sc_param[0] = MSG_EXTND;
352653901Smckusick 		sc->sc_param[1] = 0x03;
352753901Smckusick 		sc->sc_param[2] = 0x01;		/* synchronous transfer */
352853901Smckusick 		sc->sc_param[3] = syncp->tr_period;	/* transfer period */
352953901Smckusick 		sc->sc_param[4] = syncp->tr_offset;	/* REQ offset */
353053901Smckusick 
353153901Smckusick 		(void) sdcmd(dev, sc);
353253901Smckusick 
353353901Smckusick 		syncp = &sd_sync_param[unit];
353453901Smckusick 		syncp->tr_period = sc->sc_param[3];
353553901Smckusick 		syncp->tr_offset = sc->sc_param[4];
353653901Smckusick 
353753901Smckusick 		if (syncp->tr_offset)
353853901Smckusick 			sdd->sdd_flags |= SDDF_SYNCTR;
353953901Smckusick 		else
354053901Smckusick 			sdd->sdd_flags &= ~SDDF_SYNCTR;
354153901Smckusick 		}
354253901Smckusick 		break;
354353901Smckusick 
354453901Smckusick 	case SDIOC_GSYNCPARAM:
354553901Smckusick 		{
354653901Smckusick 		struct sync_param *syncp = (struct sync_param *)data;
354753901Smckusick 
354853901Smckusick 		syncp->tr_period = sd_sync_param[unit].tr_period;
354953901Smckusick 		syncp->tr_offset = sd_sync_param[unit].tr_offset;
355053901Smckusick 		}
355153901Smckusick 		break;
355253901Smckusick #endif /* SDIOC_SSYNCPARAM */
355353901Smckusick 
355453901Smckusick 	case MTIOCTOP:
355553901Smckusick 		{
355653901Smckusick 			register struct mtop *mtop = (struct mtop *)data;
355753901Smckusick 			register int lba;
355853901Smckusick 			int rest;
355953901Smckusick 			int blength;
356053901Smckusick 
356153901Smckusick 			switch (mtop->mt_op) {
356253901Smckusick 
356353901Smckusick 			case MTOFFL:
356453901Smckusick 				/*
356553901Smckusick 				 * set auto eject flag
356653901Smckusick 				 */
356753901Smckusick 				sdd->sdd_flags |= SDDF_REQ_EJECT;
356853901Smckusick 				break;
356953901Smckusick 
357053901Smckusick #ifdef MTERASE
357153901Smckusick 			case MTERASE:
357253901Smckusick 				if (isalone(unit) != ONLY_ONE)
357353901Smckusick 					return (EBUSY);
357453901Smckusick 				sdd->sdd_flags |= SDDF_XUSE;
357553901Smckusick 				st = &sdstdrv[unit];
357653901Smckusick 				/*
357753901Smckusick 				 * MO disk erase
357853901Smckusick 				 *	block 0 to end (C partition)
357953901Smckusick 				 */
358053901Smckusick 				lba = 0;
358153901Smckusick 				rest = sdd->sdd_nsect;	/* C part size */
358253901Smckusick 				while (rest > 0) {
358353901Smckusick 					blength = (rest > MAXBL)? MAXBL : rest;
358453901Smckusick 					scinit(sc, ii->ii_slave,
358553901Smckusick 							sdd->sdd_sectsize);
358653901Smckusick 					sc->sc_opcode = SCOP_MOERASE;
358753901Smckusick 					sc->sc_lad = lba;
358853901Smckusick 					sc->sc_count = (blength % MAXBL);
358953901Smckusick 
359053901Smckusick 					(void) sdcmd(dev, sc);
359153901Smckusick 					lba += blength;
359253901Smckusick 					rest -= blength;
359353901Smckusick 				}
359453901Smckusick 				sdd->sdd_flags &= ~SDDF_XUSE;
359553901Smckusick 				break;
359653901Smckusick #endif /* MTERASE */
359753901Smckusick 
359853901Smckusick 			default:
359953901Smckusick 				return (EINVAL);
360053901Smckusick 			}
360153901Smckusick 		}
360253901Smckusick 		break;
360353901Smckusick 
360453901Smckusick 	case SCSIIOCCMD:
360553901Smckusick 		scu = (struct sc_ureq *)data;
360653901Smckusick 		if ((scu->scu_count > 0) && scu->scu_addr) {
360753901Smckusick 			if (useracc(scu->scu_addr, scu->scu_count, B_WRITE)
360853901Smckusick 			    == NULL) {
360953901Smckusick 				error = EFAULT;
361053901Smckusick 				break;
361153901Smckusick 			}
361253901Smckusick 		}
361353901Smckusick 		error = sd_scu_exec(dev, scu, sc);
361453901Smckusick 		break;
361553901Smckusick 
361653901Smckusick 
361753901Smckusick 	case SDIOC_INQUIRY:
361853901Smckusick 		/*
361953901Smckusick 		 * LOCK sdtmp buffer
362053901Smckusick 		 */
362153901Smckusick 		s = splclock();
362253901Smckusick 		while (sdtmp_stat & B_BUSY) {
362353901Smckusick 			sdtmp_stat |= B_WANTED;
362453901Smckusick 			sleep((caddr_t)sdtmp, PRIBIO);
362553901Smckusick 		}
362653901Smckusick 		sdtmp_stat |= B_BUSY;
362753901Smckusick 		splx(s);
362853901Smckusick 
362953901Smckusick 		bzero((caddr_t)sdtmp, sizeof(struct sc_inq));
363053901Smckusick 		scinit(&uscsi, ii->ii_slave, sdd->sdd_sectsize);
363153901Smckusick 		uscsi.sc_cpoint = sdtmp;
363253901Smckusick 		uscsi.sc_ctrnscnt = sizeof(struct sc_inq);
363353901Smckusick 		uscsi.sc_opcode = SCOP_INQUIRY;
363453901Smckusick 		uscsi.sc_count = sizeof(struct sc_inq);
363553901Smckusick 
363653901Smckusick 		if ((error = sdcmd(dev, &uscsi)) == 0)
363753901Smckusick 			bcopy((caddr_t)sdtmp, data, sizeof(struct sc_inq));
363853901Smckusick 		/*
363953901Smckusick 		 * UNLOCK open
364053901Smckusick 		 */
364153901Smckusick 		s = splclock();
364253901Smckusick 		if (sdtmp_stat & B_WANTED)
364353901Smckusick 			wakeup((caddr_t)sdtmp);
364453901Smckusick 		sdtmp_stat &= ~(B_BUSY|B_WANTED);
364553901Smckusick 		splx(s);
364653901Smckusick 		break;
364753901Smckusick 
364853901Smckusick 
364953901Smckusick 	case SCSIIOCGTIMEO:
365053901Smckusick 		*(int *)data = sdc->sdc_timeo;
365153901Smckusick 		break;
365253901Smckusick 
365353901Smckusick 	case SCSIIOCSTIMEO:
365453901Smckusick 		if (*(int *)data == 0)
365553901Smckusick 			return (EINVAL);
365653901Smckusick 		sdc->sdc_timeo = *(int *)data;
365753901Smckusick 		sdc->sdc_wticks = 0;
365853901Smckusick 		break;
365953901Smckusick 
366053901Smckusick 	default:
366153901Smckusick 		error = EINVAL;
366253901Smckusick 		break;
366353901Smckusick 	}
366453901Smckusick 
366553901Smckusick done:
366653901Smckusick 	return (error);
366753901Smckusick }
366853901Smckusick 
366953901Smckusick static
sd_scu_exec(dev,scu,sc)367053901Smckusick sd_scu_exec(dev, scu, sc)
367153901Smckusick 	dev_t dev;
367253901Smckusick 	register struct sc_ureq *scu;
367353901Smckusick 	register struct scsi *sc;
367453901Smckusick {
367553901Smckusick 	struct sdd_softc *sdd;
367653901Smckusick 	int error;
367753901Smckusick 
367853901Smckusick 	sdd = &sdd_softc[dev2unit(dev)];
367953901Smckusick 
368053901Smckusick 	if (((scu->scu_identify & MSG_IDENT) == 0)
368153901Smckusick 		|| (scu->scu_identify & ~(MSG_IDENT|IDT_DISCON|IDT_DRMASK))
368253901Smckusick 		|| (scu->scu_addr && (scu->scu_bytesec == 0))) {
368353901Smckusick 		return (EINVAL);
368453901Smckusick 	}
368553901Smckusick 
368653901Smckusick 	bzero((caddr_t)sc, sizeof(struct scsi));
368753901Smckusick 	sc->sc_tstatus = scu->scu_tstatus;
368853901Smckusick 	sc->sc_identify = scu->scu_identify;
368953901Smckusick 	sc->sc_message = scu->scu_message;
369053901Smckusick 	sc->sc_bytesec = scu->scu_bytesec;
369153901Smckusick 	sc->sc_cpoint = scu->scu_addr;
369253901Smckusick 	sc->sc_ctrnscnt = scu->scu_count;
369353901Smckusick 	bcopy((caddr_t)scu->scu_cdb, &sc->sc_cdb, sizeof(sc->sc_cdb));
369453901Smckusick 
369553901Smckusick 	bcopy((caddr_t)scu->scu_param, (caddr_t)sc->sc_param,
369653901Smckusick 						sizeof(sc->sc_param));
369753901Smckusick 
369853901Smckusick 	sdd->sdd_flags |= SDDF_SKIPCHECK;
369953901Smckusick 	error = sdcmd(dev, sc);
370053901Smckusick 	sdd->sdd_flags &= ~SDDF_SKIPCHECK;
370153901Smckusick 
370253901Smckusick 	scu->scu_istatus = sc->sc_istatus;
370353901Smckusick 	scu->scu_tstatus = sc->sc_tstatus;
370453901Smckusick 	scu->scu_message = sc->sc_message;
370553901Smckusick 	bcopy((caddr_t)sc->sc_param, (caddr_t)scu->scu_param,
370653901Smckusick 		sizeof(sc->sc_param));
370753901Smckusick 	return (error);
370853901Smckusick }
370953901Smckusick 
371053901Smckusick /*ARGSUSED*/
sddump(dev)371153901Smckusick sddump(dev)
371253901Smckusick 	dev_t dev;
371353901Smckusick {
371453901Smckusick 	return (ENXIO);
371553901Smckusick }
371653901Smckusick 
sdsize(dev)371753901Smckusick sdsize(dev)
371853901Smckusick 	register dev_t dev;
371953901Smckusick {
372053901Smckusick 	register struct iop/**/_device *ii;
372153901Smckusick 	register struct sdd_softc *sdd;
372253901Smckusick 	register struct sdst *st;
372353901Smckusick 	register int unit;
372453901Smckusick 	int i;
372553901Smckusick 
372653901Smckusick 	unit = dev2unit(dev);
372753901Smckusick 	if (unit >= nsd || (ii = sddinfo[unit]) == 0 || ii->ii_alive == 0)
372853901Smckusick 		return (-1);
372953901Smckusick 
373053901Smckusick 	sdd = &sdd_softc[unit];
373153901Smckusick 	switch (sdc_softc[ii->ii_ctlr].sdc_firmware & SDCFW_DEVMASK) {
373253901Smckusick 
373353901Smckusick 	case SDCFW_HD:		/* Hard Disk */
373453901Smckusick 		st = &sdstdrv[unit];
373553901Smckusick 		break;
373653901Smckusick 
373753901Smckusick 	case SDCFW_MO:		/* MO only */
373853901Smckusick 		if ((sdd->sdd_flags & SDDF_SAMEDSK) == SDDF_DSKCHGD) {
373953901Smckusick 			/*
374053901Smckusick 			 * read partition information,
374153901Smckusick 			 *	and set up sdstdrv[unit]
374253901Smckusick 			 */
374353901Smckusick 			if (sd_b_open(dev, FREAD|FWRITE) != 0) {
374453901Smckusick 				/*
374553901Smckusick 				 * block device open error
374653901Smckusick 				 */
374753901Smckusick 				return (-1);
374853901Smckusick 			} else {
374953901Smckusick 				/*
375053901Smckusick 				 * use disk partition information
375153901Smckusick 				 */
375253901Smckusick 				st = &sdstdrv[unit];
375353901Smckusick 				if (isalone(unit) == ONLY_ONE)
375453901Smckusick 					sd_b_close(dev, 0);
375553901Smckusick 			}
375653901Smckusick 		} else if (sdd->sdd_flags & SDDF_NONFMT) {
375753901Smckusick 			/*
375853901Smckusick 			 * medium is not initialized.
375953901Smckusick 			 */
376053901Smckusick 			return (-1);
376153901Smckusick 		} else {
376253901Smckusick 			st = &sdstdrv[unit];
376353901Smckusick 		}
376453901Smckusick 		break;
376553901Smckusick 
376653901Smckusick 	default:
376753901Smckusick     /*  case SDCFW_CD: */
376853901Smckusick 		return (-1);
376953901Smckusick 
377053901Smckusick 	}
377153901Smckusick 
377253901Smckusick 	if (st->sizes == NULL)
377353901Smckusick 		return (-1);					/* XXX */
377453901Smckusick 	else
377553901Smckusick 		return (st->sizes[dev2part(dev)].sd_nblocks);	/* XXX */
377653901Smckusick }
377753901Smckusick 
377853901Smckusick /*
377953901Smckusick  * Reset driver.
378053901Smckusick  * Cancel software state of all pending transfers,
378153901Smckusick  * and restart all units and the controller.
378253901Smckusick  */
sdreset()378353901Smckusick sdreset()
378453901Smckusick {
378553901Smckusick 	register struct iop/**/_ctlr *im;
378653901Smckusick 	register struct iop/**/_device *ii;
378753901Smckusick 	register struct sdc_softc *sdc;
378853901Smckusick 	register struct sdd_softc *sdd;
378953901Smckusick 	register int i;
379053901Smckusick 	register int unit;
379153901Smckusick 
379253901Smckusick 	re_init_done = 1;
379353901Smckusick 	for (i = 0; i < nsdc; i++) {
379453901Smckusick 		im = sdminfo[i];
379553901Smckusick 		if (im == 0)
379653901Smckusick 			continue;
379753901Smckusick 		if (im->im_alive == 0)
379853901Smckusick 			continue;
379953901Smckusick 		printf(" sdc%d: ", i);
380053901Smckusick 		sdc = &sdc_softc[i];
380153901Smckusick 		sdc->sdc_wticks = 0;
380253901Smckusick 
380353901Smckusick 		/* scop_init() is already called by screset() */
380453901Smckusick 
380553901Smckusick 		sdtmp_stat &= ~B_BUSY;
380653901Smckusick 
380753901Smckusick 		for (unit = 0; unit < nsd; unit++) {
380853901Smckusick 			ii = sddinfo[unit];
380953901Smckusick 			if (ii == 0)
381053901Smckusick 				continue;
381153901Smckusick 			if (ii->ii_alive == 0)
381253901Smckusick 				continue;
381353901Smckusick 			if (ii->ii_mi != im)
381453901Smckusick 				continue;
381553901Smckusick 
381653901Smckusick 			csdbuf[unit].b_flags &= ~B_BUSY;
381753901Smckusick 
381853901Smckusick 			sdd = &sdd_softc[unit];
381953901Smckusick 			sdd->sdd_flags = 0;
382053901Smckusick 
382153901Smckusick 			/*
382253901Smckusick 			 * UNLOCK SCSI access
382353901Smckusick 			 */
382453901Smckusick 			sdc->sdc_firmware &= ~SDCFW_BUSY;
382553901Smckusick 
382653901Smckusick 			if (sdslave(ii, ii->ii_addr, im->im_intr) == 0) {
382753901Smckusick 				printf("sd%d: not ready\n", ii->ii_slave);
382853901Smckusick 				continue;
382953901Smckusick 			}
383053901Smckusick 			sdattach(ii);
383153901Smckusick 		}
383253901Smckusick 	}
383353901Smckusick 	re_init_done = 2;
383453901Smckusick }
383553901Smckusick 
383653901Smckusick int sd_long_timeout = 24 * 60 * 60;	/* 24 hours */
383753901Smckusick 
383853901Smckusick #define max(a, b) (((a)>(b))?(a):(b))
383953901Smckusick 
384053901Smckusick /*
384153901Smckusick  * Wake up every second and if interrupt is pending
384253901Smckusick  * but nothing has happened increment a counter.
384353901Smckusick  * If nothing happens for sdc_timeo seconds, reset the IOP
384453901Smckusick  * and begin anew.
384553901Smckusick  */
sdwatch()384653901Smckusick sdwatch()
384753901Smckusick {
384853901Smckusick 	register struct iop/**/_ctlr *im;
384953901Smckusick 	register struct sdc_softc *sdc;
385053901Smckusick 	register int i;
385153901Smckusick 	register int unit;
385253901Smckusick 	int timeo;
385353901Smckusick 
385453901Smckusick 	extern int Scsi_Disconnect;
385553901Smckusick 
385653901Smckusick 	timeout(sdwatch, (caddr_t)0, hz);
385753901Smckusick 	for (i = 0; i < nsdc; i++) {
385853901Smckusick 		im = sdminfo[i];
385953901Smckusick 		if (im == 0)
386053901Smckusick 			continue;
386153901Smckusick 		if (im->im_alive == 0)
386253901Smckusick 			continue;
386353901Smckusick 		sdc = &sdc_softc[i];
386453901Smckusick 
386553901Smckusick 		if (im->im_tab.b_active)
386653901Smckusick 			goto active;
386753901Smckusick 
386853901Smckusick 		for (unit = 0; unit < nsd; unit++)
386953901Smckusick 			if (sdutab[unit].b_active && sddinfo[unit]->ii_mi == im)
387053901Smckusick 				goto active;
387153901Smckusick 
387253901Smckusick 		sdc->sdc_wticks = 0;
387353901Smckusick 		continue;
387453901Smckusick active:
387553901Smckusick 		if (Scsi_Disconnect)
387653901Smckusick 			timeo = sdc->sdc_timeo;
387753901Smckusick 		else
387853901Smckusick 			timeo = max(sdc->sdc_timeo, sd_long_timeout);
387953901Smckusick 
388053901Smckusick 		if (sdc->sdc_wticks++ >= timeo) {
388153901Smckusick 			register struct scsi *sc;
388253901Smckusick 
388353901Smckusick 			sc = get_scsi(im->im_intr);
388453901Smckusick 			sdc->sdc_wticks = 0;
388553901Smckusick 			printf("sdc%d: lost interrupt\n", i);
388653901Smckusick 
388753901Smckusick 			screset(im->im_intr);
388853901Smckusick 		}
388953901Smckusick 	}
389053901Smckusick }
389153901Smckusick 
389253901Smckusick /*
389353901Smckusick  * sdstop() is timer interrupt routine.
389453901Smckusick  *	So, can't use sleep().
389553901Smckusick  */
sdstop()389653901Smckusick sdstop()
389753901Smckusick {
389853901Smckusick 	register struct iop/**/_ctlr *im;
389953901Smckusick 	register struct iop/**/_device *ii;
390053901Smckusick 	register struct sdc_softc *sdc;
390153901Smckusick 	register struct sdd_softc *sdd;
390253901Smckusick 	register int unit;
390353901Smckusick 	register int intr;
390453901Smckusick 	register int i;
390553901Smckusick 	struct scsi *sc;
390653901Smckusick 	int eject_sw;
390753901Smckusick 
390853901Smckusick 	timeout(sdstop, (caddr_t)0, hz);
390953901Smckusick 
391053901Smckusick 	for (i = 0; i < nsdc; i++) {
391153901Smckusick 		im = sdminfo[i];
391253901Smckusick 		if (im == 0)
391353901Smckusick 			continue;
391453901Smckusick 		if (im->im_alive == 0)
391553901Smckusick 			continue;
391653901Smckusick 		for (unit = 0; unit < nsd; unit++) {
391753901Smckusick 			if ((ii = sddinfo[unit]) == 0)
391853901Smckusick 				continue;
391953901Smckusick 			if (ii->ii_mi != im)
392053901Smckusick 				continue;
392153901Smckusick 			sdc = &sdc_softc[ii->ii_ctlr];
392253901Smckusick 			if ((sdc->sdc_firmware & SDCFW_RMB) == 0)
392353901Smckusick 				continue;
392453901Smckusick 			intr = ii->ii_intr;
392553901Smckusick 			if (isalone(unit))
392653901Smckusick 				continue;
392753901Smckusick 			/**********************/
392853901Smckusick 			/*    MO & CD-ROM     */
392953901Smckusick 			/**********************/
393053901Smckusick 			/*
393153901Smckusick 			 * there is no process which open the unit.
393253901Smckusick 			 */
393353901Smckusick 			sdd = &sdd_softc[unit];
393453901Smckusick 			sc = get_scsi(intr);
393553901Smckusick 			if (sdd->sdd_start > 0)
393653901Smckusick 				sdd->sdd_start--;
393753901Smckusick 			else if (sdd->sdd_start == 0) {
393853901Smckusick 				/*
393953901Smckusick 				 * Now stop the unit.
394053901Smckusick 				 * check SCSI access
394153901Smckusick 				 */
394253901Smckusick 				if (sdc->sdc_firmware & SDCFW_BUSY)
394353901Smckusick 					continue;
394453901Smckusick 				sdc->sdc_firmware |= SDCFW_BUSY;
394553901Smckusick 				sdc->sdc_state |= SDCS_IOCTL|SDCS_SCUNLOCK;
394653901Smckusick 
394753901Smckusick 				eject_sw = (sdd->sdd_flags & SDDF_REQ_EJECT) ?
394853901Smckusick 						SDSS_EJECT : SDSS_STOP;
394953901Smckusick 				scop_stst(intr, sc, ii->ii_slave,
395053901Smckusick 						SCSI_INTEN, eject_sw);
395153901Smckusick 				sdd->sdd_start = -2;
395253901Smckusick 			}
395353901Smckusick 		}
395453901Smckusick 	}
395553901Smckusick }
395653901Smckusick 
isalone(unit)395753901Smckusick isalone(unit)
395853901Smckusick 	register int unit;
395953901Smckusick {
396053901Smckusick 	register int i, n;
396153901Smckusick 
396253901Smckusick 	n = 0;
396353901Smckusick 	for (i = 0; i < PNUM; i++)
396453901Smckusick 		n += (sd_b_openf[unit][i] + sd_c_openf[unit][i]);
396553901Smckusick 	return (n);
396653901Smckusick }
396753901Smckusick 
396853901Smckusick /************************************************
396953901Smckusick  * Convert Hex and RS code table definition	*
397053901Smckusick  ************************************************/
397153901Smckusick 
397253901Smckusick #define	X8_L	0x001d
397353901Smckusick #define	X8_H	0x1d00
397453901Smckusick 
397553901Smckusick 
397653901Smckusick #define	hextors(data)	hxtable[(int)((data) & 0xff)]
397753901Smckusick #define	XORMASK(code)	xortable[(unsigned int)(code)]
397853901Smckusick 
397953901Smckusick int	hxtable[256] = {
398053901Smckusick 	0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
398153901Smckusick 	0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
398253901Smckusick 	0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
398353901Smckusick 	0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
398453901Smckusick 	0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
398553901Smckusick 	0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
398653901Smckusick 	0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
398753901Smckusick 	0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
398853901Smckusick 	0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
398953901Smckusick 	0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
399053901Smckusick 	0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
399153901Smckusick 	0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
399253901Smckusick 	0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
399353901Smckusick 	0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
399453901Smckusick 	0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
399553901Smckusick 	0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
399653901Smckusick 	0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
399753901Smckusick 	0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
399853901Smckusick 	0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
399953901Smckusick 	0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
400053901Smckusick 	0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
400153901Smckusick 	0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
400253901Smckusick 	0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
400353901Smckusick 	0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
400453901Smckusick 	0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
400553901Smckusick 	0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
400653901Smckusick 	0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
400753901Smckusick 	0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
400853901Smckusick 	0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
400953901Smckusick 	0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
401053901Smckusick 	0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
401153901Smckusick 	0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf,
401253901Smckusick };
401353901Smckusick 
401453901Smckusick int xortable[256] = {
401553901Smckusick 	0x00000000, 0x90910101, 0x91210201, 0x01b00300,
401653901Smckusick 	0x92410401, 0x02d00500, 0x03600600, 0x93f10701,
401753901Smckusick 	0x94810801, 0x04100900, 0x05a00a00, 0x95310b01,
401853901Smckusick 	0x06c00c00, 0x96510d01, 0x97e10e01, 0x07700f00,
401953901Smckusick 	0x99011001, 0x09901100, 0x08201200, 0x98b11301,
402053901Smckusick 	0x0b401400, 0x9bd11501, 0x9a611601, 0x0af01700,
402153901Smckusick 	0x0d801800, 0x9d111901, 0x9ca11a01, 0x0c301b00,
402253901Smckusick 	0x9fc11c01, 0x0f501d00, 0x0ee01e00, 0x9e711f01,
402353901Smckusick 	0x82012001, 0x12902100, 0x13202200, 0x83b12301,
402453901Smckusick 	0x10402400, 0x80d12501, 0x81612601, 0x11f02700,
402553901Smckusick 	0x16802800, 0x86112901, 0x87a12a01, 0x17302b00,
402653901Smckusick 	0x84c12c01, 0x14502d00, 0x15e02e00, 0x85712f01,
402753901Smckusick 	0x1b003000, 0x8b913101, 0x8a213201, 0x1ab03300,
402853901Smckusick 	0x89413401, 0x19d03500, 0x18603600, 0x88f13701,
402953901Smckusick 	0x8f813801, 0x1f103900, 0x1ea03a00, 0x8e313b01,
403053901Smckusick 	0x1dc03c00, 0x8d513d01, 0x8ce13e01, 0x1c703f00,
403153901Smckusick 	0xb4014001, 0x24904100, 0x25204200, 0xb5b14301,
403253901Smckusick 	0x26404400, 0xb6d14501, 0xb7614601, 0x27f04700,
403353901Smckusick 	0x20804800, 0xb0114901, 0xb1a14a01, 0x21304b00,
403453901Smckusick 	0xb2c14c01, 0x22504d00, 0x23e04e00, 0xb3714f01,
403553901Smckusick 	0x2d005000, 0xbd915101, 0xbc215201, 0x2cb05300,
403653901Smckusick 	0xbf415401, 0x2fd05500, 0x2e605600, 0xbef15701,
403753901Smckusick 	0xb9815801, 0x29105900, 0x28a05a00, 0xb8315b01,
403853901Smckusick 	0x2bc05c00, 0xbb515d01, 0xbae15e01, 0x2a705f00,
403953901Smckusick 	0x36006000, 0xa6916101, 0xa7216201, 0x37b06300,
404053901Smckusick 	0xa4416401, 0x34d06500, 0x35606600, 0xa5f16701,
404153901Smckusick 	0xa2816801, 0x32106900, 0x33a06a00, 0xa3316b01,
404253901Smckusick 	0x30c06c00, 0xa0516d01, 0xa1e16e01, 0x31706f00,
404353901Smckusick 	0xaf017001, 0x3f907100, 0x3e207200, 0xaeb17301,
404453901Smckusick 	0x3d407400, 0xadd17501, 0xac617601, 0x3cf07700,
404553901Smckusick 	0x3b807800, 0xab117901, 0xaaa17a01, 0x3a307b00,
404653901Smckusick 	0xa9c17c01, 0x39507d00, 0x38e07e00, 0xa8717f01,
404753901Smckusick 	0xd8018001, 0x48908100, 0x49208200, 0xd9b18301,
404853901Smckusick 	0x4a408400, 0xdad18501, 0xdb618601, 0x4bf08700,
404953901Smckusick 	0x4c808800, 0xdc118901, 0xdda18a01, 0x4d308b00,
405053901Smckusick 	0xdec18c01, 0x4e508d00, 0x4fe08e00, 0xdf718f01,
405153901Smckusick 	0x41009000, 0xd1919101, 0xd0219201, 0x40b09300,
405253901Smckusick 	0xd3419401, 0x43d09500, 0x42609600, 0xd2f19701,
405353901Smckusick 	0xd5819801, 0x45109900, 0x44a09a00, 0xd4319b01,
405453901Smckusick 	0x47c09c00, 0xd7519d01, 0xd6e19e01, 0x46709f00,
405553901Smckusick 	0x5a00a000, 0xca91a101, 0xcb21a201, 0x5bb0a300,
405653901Smckusick 	0xc841a401, 0x58d0a500, 0x5960a600, 0xc9f1a701,
405753901Smckusick 	0xce81a801, 0x5e10a900, 0x5fa0aa00, 0xcf31ab01,
405853901Smckusick 	0x5cc0ac00, 0xcc51ad01, 0xcde1ae01, 0x5d70af00,
405953901Smckusick 	0xc301b001, 0x5390b100, 0x5220b200, 0xc2b1b301,
406053901Smckusick 	0x5140b400, 0xc1d1b501, 0xc061b601, 0x50f0b700,
406153901Smckusick 	0x5780b800, 0xc711b901, 0xc6a1ba01, 0x5630bb00,
406253901Smckusick 	0xc5c1bc01, 0x5550bd00, 0x54e0be00, 0xc471bf01,
406353901Smckusick 	0x6c00c000, 0xfc91c101, 0xfd21c201, 0x6db0c300,
406453901Smckusick 	0xfe41c401, 0x6ed0c500, 0x6f60c600, 0xfff1c701,
406553901Smckusick 	0xf881c801, 0x6810c900, 0x69a0ca00, 0xf931cb01,
406653901Smckusick 	0x6ac0cc00, 0xfa51cd01, 0xfbe1ce01, 0x6b70cf00,
406753901Smckusick 	0xf501d001, 0x6590d100, 0x6420d200, 0xf4b1d301,
406853901Smckusick 	0x6740d400, 0xf7d1d501, 0xf661d601, 0x66f0d700,
406953901Smckusick 	0x6180d800, 0xf111d901, 0xf0a1da01, 0x6030db00,
407053901Smckusick 	0xf3c1dc01, 0x6350dd00, 0x62e0de00, 0xf271df01,
407153901Smckusick 	0xee01e001, 0x7e90e100, 0x7f20e200, 0xefb1e301,
407253901Smckusick 	0x7c40e400, 0xecd1e501, 0xed61e601, 0x7df0e700,
407353901Smckusick 	0x7a80e800, 0xea11e901, 0xeba1ea01, 0x7b30eb00,
407453901Smckusick 	0xe8c1ec01, 0x7850ed00, 0x79e0ee00, 0xe971ef01,
407553901Smckusick 	0x7700f000, 0xe791f101, 0xe621f201, 0x76b0f300,
407653901Smckusick 	0xe541f401, 0x75d0f500, 0x7460f600, 0xe4f1f701,
407753901Smckusick 	0xe381f801, 0x7310f900, 0x72a0fa00, 0xe231fb01,
407853901Smckusick 	0x71c0fc00, 0xe151fd01, 0xe0e1fe01, 0x7070ff00
407953901Smckusick };
408053901Smckusick 
408153901Smckusick /********************************************************
408253901Smckusick  * EDC (Error Detection Code) check			*
408353901Smckusick  *			(using CRC code)		*
408453901Smckusick  *	MODE 1 : Sync + Header + User data + edc	*
408553901Smckusick  *	MODE 2 : Sub header + User data + edc		*
408653901Smckusick  ********************************************************/
408753901Smckusick 
408853901Smckusick #define	SYNC_EDC	0x908eff4e	/* sector sync EDC value	*/
408953901Smckusick #define	HEADER		4		/* header length 4 bytes	*/
409053901Smckusick #define	SUB_H		8		/* Subheader length 8 bytes	*/
409153901Smckusick #define	USER_DATA	2048		/* User data length 2048 bytes	*/
409253901Smckusick #define	EDC_LEN		4		/* EDC code length 4 bytes	*/
409353901Smckusick 
cal_edc1(db,mode)409453901Smckusick cal_edc1(db, mode)
409553901Smckusick 	register unsigned char	*db;
409653901Smckusick 	int mode;
409753901Smckusick {
409853901Smckusick 	register int j;
409953901Smckusick 	register unsigned int work;
410053901Smckusick 
410153901Smckusick 	j = USER_DATA + EDC_LEN;
410253901Smckusick 	if (mode == 2) {
410353901Smckusick 		j += SUB_H;
410453901Smckusick 		work = 0;
410553901Smckusick 	} else {
410653901Smckusick 		j += HEADER;
410753901Smckusick 		work = SYNC_EDC;
410853901Smckusick 	}
410953901Smckusick 	while (--j >= 0)
411053901Smckusick 		work = ((work >> 8) | (*db++ << 24)) ^ XORMASK(work & 0xff);
411153901Smckusick 
411253901Smckusick 	return (work);
411353901Smckusick }
411453901Smckusick 
411553901Smckusick 
411653901Smckusick /************************************************/
411753901Smckusick /*	error detection & correction		*/
411853901Smckusick /*	if form 1				*/
411953901Smckusick /*	    header area should be zero		*/
412053901Smckusick /************************************************/
412153901Smckusick 
412253901Smckusick /*
412353901Smckusick  *	error detection & correction  P-direction
412453901Smckusick  */
p_dir(dbuf)412553901Smckusick p_dir(dbuf)
412653901Smckusick 	register unsigned short	*dbuf;
412753901Smckusick {
412853901Smckusick 	unsigned short	s0, s1, d;
412953901Smckusick 	register int	col, row;
413053901Smckusick 	register int	x;
413153901Smckusick 	unsigned char	s0l, s0h, s1l, s1h;
413253901Smckusick 
413353901Smckusick 	/*
413453901Smckusick 	 * calculate syndrome S0 S1
413553901Smckusick 	 */
413653901Smckusick 	for (col = 0; col < 43; col++) {
413753901Smckusick 		s0 = s1 = 0;
413853901Smckusick 
413953901Smckusick 		for (row = 0; row < 26; row++) {
414053901Smckusick 			d = dbuf[43 * row + col];
414153901Smckusick 			s0 ^= d;
414253901Smckusick 			s1 = rsshift(s1) ^ d;
414353901Smckusick 		}
414453901Smckusick 
414553901Smckusick 		s0h = s0 & 0x00ff;
414653901Smckusick 		s1h = s1 & 0x00ff;
414753901Smckusick 		s0l = (s0 >> 8) & 0x00ff;
414853901Smckusick 		s1l = (s1 >> 8) & 0x00ff;
414953901Smckusick 		/*
415053901Smckusick 		 * calculate error position & correction
415153901Smckusick 		 */
415253901Smckusick 		if (s0l != 0) {
415353901Smckusick 			if((x = hextors(s1l) - hextors(s0l)) < 0)
415453901Smckusick 				x += 255;
415553901Smckusick 			if ((x >= 0) && (x < 26)) {
415653901Smckusick 				x = 25 - x;
415753901Smckusick 				/*
415853901Smckusick 				 * correction
415953901Smckusick 				 */
416053901Smckusick 				dbuf[43 * x + col] ^= (s0 & 0xff00);
416153901Smckusick 			}
416253901Smckusick 		}
416353901Smckusick 
416453901Smckusick 		/*
416553901Smckusick 		 * calculate error position & correction
416653901Smckusick 		 */
416753901Smckusick 		if (s0h != 0) {
416853901Smckusick 			if((x = hextors(s1h) - hextors(s0h)) < 0)
416953901Smckusick 				x += 255;
417053901Smckusick 			if ((x >= 0) && (x < 26)) {
417153901Smckusick 				x = 25 - x;
417253901Smckusick 				/*
417353901Smckusick 				 * correction
417453901Smckusick 				 */
417553901Smckusick 				dbuf[43 * x + col] ^= (s0 & 0x00ff);
417653901Smckusick 			}
417753901Smckusick 		}
417853901Smckusick 	}
417953901Smckusick }
418053901Smckusick 
418153901Smckusick /*
418253901Smckusick  * error detection & correction  Q-direction
418353901Smckusick  */
q_dir(dbuf)418453901Smckusick q_dir(dbuf)
418553901Smckusick 	register unsigned short	*dbuf;
418653901Smckusick {
418753901Smckusick 	unsigned short s0, s1, d;
418853901Smckusick 	register int col, row;
418953901Smckusick 	register int x;
419053901Smckusick 	unsigned char s0l, s0h, s1l, s1h;
419153901Smckusick 
419253901Smckusick 	/*
419353901Smckusick 	 * calculate syndrome S0 S1
419453901Smckusick 	 */
419553901Smckusick 	for (row = 0; row < 26; row++) {
419653901Smckusick 		s0 = s1 = 0;
419753901Smckusick 
419853901Smckusick 		for (col = 0; col < 45; col++) {
419953901Smckusick 			if (col < 43)
420053901Smckusick 				d = dbuf[(44 * col + 43 * row) % 1118];
420153901Smckusick 			else if (col == 43)
420253901Smckusick 				d = dbuf[43 * 26 + row];
420353901Smckusick 			else
420453901Smckusick 				d = dbuf[44 * 26 + row];
420553901Smckusick 			s0 ^= d;
420653901Smckusick 			s1 = rsshift(s1) ^ d;
420753901Smckusick 		}
420853901Smckusick 
420953901Smckusick 		s0h = s0 & 0x00ff;
421053901Smckusick 		s1h = s1 & 0x00ff;
421153901Smckusick 		s0l = (s0 >> 8) & 0x00ff;
421253901Smckusick 		s1l = (s1 >> 8) & 0x00ff;
421353901Smckusick 		/*
421453901Smckusick 		 * calculate error position & correction
421553901Smckusick 		 */
421653901Smckusick 		if (s0l != 0) {
421753901Smckusick 			if((x = hextors(s1l) - hextors(s0l)) < 0)
421853901Smckusick 				x += 255;
421953901Smckusick 			if (x >= 0 && x < 45) {
422053901Smckusick 				x = 44 - x;
422153901Smckusick 				/*
422253901Smckusick 				 * correction
422353901Smckusick 				 */
422453901Smckusick 				if (x < 43)
422553901Smckusick 					dbuf[(44 * x + 43 * row) % 1118]
422653901Smckusick 						^= s0 & 0xff00;
422753901Smckusick 				else if (x == 43)
422853901Smckusick 					dbuf[43 * 26 + row] ^= s0 & 0xff00;
422953901Smckusick 				else
423053901Smckusick 					dbuf[44 * 26 + row] ^= s0 & 0xff00;
423153901Smckusick 			}
423253901Smckusick 		}
423353901Smckusick 
423453901Smckusick 		/*
423553901Smckusick 		 * calculate error position & correction
423653901Smckusick 		 */
423753901Smckusick 		if (s0h != 0) {
423853901Smckusick 			if((x = hextors(s1h) - hextors(s0h)) < 0)
423953901Smckusick 				x += 255;
424053901Smckusick 			if ((x >= 0) && (x < 45)) {
424153901Smckusick 				x = 44 - x;
424253901Smckusick 				/*
424353901Smckusick 				 * correction
424453901Smckusick 				 */
424553901Smckusick 				if (x < 43)
424653901Smckusick 					dbuf[(44 * x + 43 * row) % 1118]
424753901Smckusick 						^= s0 & 0x00ff;
424853901Smckusick 				else if ( x == 43)
424953901Smckusick 					dbuf[43 * 26 + row] ^= s0 & 0x00ff;
425053901Smckusick 				else
425153901Smckusick 					dbuf[44 * 26 + row] ^= s0 & 0x00ff;
425253901Smckusick 			}
425353901Smckusick 		}
425453901Smckusick 	}
425553901Smckusick }
425653901Smckusick 
425753901Smckusick /*
425853901Smckusick  *	shift high & low byte at the same time
425953901Smckusick  */
rsshift(d)426053901Smckusick rsshift(d)
426153901Smckusick 	unsigned short d;
426253901Smckusick {
426353901Smckusick 	register int x;
426453901Smckusick 	register int dmy;	/* This way is faster */
426553901Smckusick 
426653901Smckusick 	dmy = (int)d;
426753901Smckusick 	x = (dmy << 1) & 0xfefe;	/* clear LSB of high & low byte */
426853901Smckusick 	if ((dmy & 0x0080) != 0)
426953901Smckusick 		x ^= X8_L;
427053901Smckusick 	if ((dmy & 0x8000) != 0)
427153901Smckusick 		x ^= X8_H;
427253901Smckusick 	return(x);
427353901Smckusick }
427453901Smckusick #endif /* NSD > 0 */
4275