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