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