xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 33164)
132529Sbostic /*
232529Sbostic  * Stand alone driver for the HDC controller
332557Sbostic  *
4*33164Sbostic  *	@(#)hd.c	7.4 (Berkeley) 12/28/87
532529Sbostic  */
632557Sbostic #define	KERNEL
732529Sbostic 
832557Sbostic #include "machine/mtpr.h"
9*33164Sbostic 
1032557Sbostic #include "param.h"
1132557Sbostic #include "inode.h"
1232557Sbostic #include "fs.h"
13*33164Sbostic #include "buf.h"
1432557Sbostic #include "ioctl.h"
15*33164Sbostic #include "disklabel.h"
1632557Sbostic #include "saio.h"
1732529Sbostic 
18*33164Sbostic #include "../tahoevba/dsk.h"
19*33164Sbostic #include "../tahoevba/dskio.h"
20*33164Sbostic #include "../tahoevba/hdc.h"
21*33164Sbostic 
2232557Sbostic #define	NHD		4
2332557Sbostic #define	NDRIVE		8		/* drives per controller */
2432557Sbostic #define	HDSLAVE(x)	((x) % NDRIVE)
2532557Sbostic #define	HDCTLR(x)	((x) / NDRIVE)
2632529Sbostic 
27*33164Sbostic #define	HDC_DEFBUS	0		/* we only handle bus zero, for now */
2832557Sbostic #define	HDREG(x)	(ctlr_addr->x)	/* standalone io to an hdc register */
2932557Sbostic #define	HID_HDC		0x01		/* hvme_id for HDC */
3032529Sbostic 
3132529Sbostic /*
3232529Sbostic  * hdc controller table. It contains information about the hdc controller.
3332529Sbostic  */
3432529Sbostic typedef struct {
35*33164Sbostic 	int		ctlr;		/* controller number (0-15) */
3632529Sbostic 	hdc_regs_type	*registers;	/* base address of hdc io registers */
37*33164Sbostic 	hdc_mid_type	mid;		/* the module id is read to here */
38*33164Sbostic 	master_mcb_type	master_mcb;	/* the master mcb for this hdc */
3932529Sbostic 	mcb_type	mcb;		/* an mcb for i/o to the controller */
4032529Sbostic } hdctlr_type;
4132529Sbostic 
4232529Sbostic hdctlr_type hdc_ctlr[HDC_MAXCTLR][HDC_MAXBUS];
4332529Sbostic 
4432529Sbostic /*
4532529Sbostic  * hdc unit table. It contains information about the hdc drive.
4632529Sbostic  * Some information is obtained from the profile prom and geometry block.
4732529Sbostic  */
4832529Sbostic typedef struct {
49*33164Sbostic 	par_tab	partition[GB_MAXPART];	/* partition definitions */
50*33164Sbostic 	int	ctlr;			/* the controller number (0-15) */
51*33164Sbostic 	int	slave;			/* the slave number (0-4) */
52*33164Sbostic 	int	unit;			/* the unit number (0-31) */
53*33164Sbostic 	int	id;			/* identifies the disk model */
54*33164Sbostic  	int	cylinders;		/* number of logical cylinders */
55*33164Sbostic 	int	heads;			/* number of logical heads */
56*33164Sbostic 	int	sectors;		/* number of logical sectors/track */
57*33164Sbostic 	int	phys_cylinders;		/* number of physical cylinders */
58*33164Sbostic 	int	phys_heads;		/* number of physical heads */
5932560Sbostic 	int	phys_sectors;		/* number of physical sectors/track */
60*33164Sbostic 	int	def_cyl;		/* logical cylinder of drive def */
61*33164Sbostic 	int	def_cyl_count;		/* number of logical def cylinders */
62*33164Sbostic 	int	diag_cyl;		/* logical cylinder of diag area */
6332560Sbostic 	int	diag_cyl_count;		/* number of logical diag cylinders */
64*33164Sbostic 	int	rpm;			/* disk rpm */
65*33164Sbostic 	int	bytes_per_sec;		/* bytes/sector -vendorflaw conversn */
66*33164Sbostic 	int	format;			/* format program is active */
67*33164Sbostic 	u_long	phio_data[HDC_PHIO_SIZE];	/* data for physical io */
6832529Sbostic } hdunit_type;
6932529Sbostic 
70*33164Sbostic hdunit_type	hdc_unit [HDC_MAXDRIVE] [HDC_MAXCTLR] [HDC_MAXBUS];
7132529Sbostic 
72*33164Sbostic /*
73*33164Sbostic  * hdopen --
74*33164Sbostic  *	initialize the hdc and read the disk label
75*33164Sbostic  */
7632529Sbostic hdopen(io)
7732560Sbostic 	register struct iob	*io;	/* i/o block */
7832529Sbostic {
79*33164Sbostic 	drive_stat_type	status;		/* the hdc status is read to here */
80*33164Sbostic 	hdc_mid_type	*id;		/* the hdc module id */
81*33164Sbostic 	hdc_regs_type	*ctlr_addr;	/* hdc i/o registers */
82*33164Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table */
83*33164Sbostic 	hdunit_type	*hu;		/* disk unit information table */
84*33164Sbostic 	geometry_sector	geometry;	/* the geometry block sector */
85*33164Sbostic 	geometry_block	*geo;		/* the geometry block */
86*33164Sbostic 	mcb_type	*mcb;		/* an mcb to send commands to hdc */
87*33164Sbostic 	long	junk = 0;		/* badaddr will write junk here */
88*33164Sbostic 	int	par;			/* partition number */
89*33164Sbostic 	int	bus, ctlr, drive, error, i, unit;
9032529Sbostic 
91*33164Sbostic 	/* validate the device specification */
92*33164Sbostic 	if ((ctlr = HDCTLR(io->i_unit)) >= HDC_MAXCTLR) {
9332557Sbostic 		printf("invalid controller number\n");
9432560Sbostic 		return(ENXIO);
9532557Sbostic 	}
96*33164Sbostic 	if ((drive = HDSLAVE(io->i_unit)) < 0 || drive > HDC_MAXDRIVE - 1) {
9732529Sbostic 		printf("hdc: bad drive number.\n");
9832560Sbostic 		return(EUNIT);
9932529Sbostic 	}
100*33164Sbostic 	if ((par = io->i_boff) < 0 || par > 7) {
10132529Sbostic 		printf("hdc: bad partition number.\n");
10232560Sbostic 		return(EUNIT);
10332529Sbostic 	}
104*33164Sbostic 	bus = HDC_DEFBUS;
10532529Sbostic 
106*33164Sbostic 	ctlr_addr = (hdc_regs_type *)(bus ?
107*33164Sbostic 		0x80000000 | ctlr << 24 | HDC_MID << 16 :
108*33164Sbostic 		0xC0000000 | ctlr << 24 | HDC_MID << 16);
109*33164Sbostic 
110*33164Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
111*33164Sbostic 	hc = &hdc_ctlr[ctlr][bus];
112*33164Sbostic 	mcb = &hc->mcb;
113*33164Sbostic 
114*33164Sbostic 	/* init drive structure. */
11532529Sbostic 	hu->slave = drive;
11632529Sbostic 	hc->registers = ctlr_addr;
11732529Sbostic 
118*33164Sbostic 	/* insure that this is an hdc, then reset the hdc. */
11932557Sbostic 	if (wbadaddr(&ctlr_addr->module_id_reg, 4, &junk)) {
12032560Sbostic 		printf("hd%d: %x: invalid csr\n", ctlr, (u_int)ctlr_addr);
12132560Sbostic 		return(ENXIO);
12232557Sbostic 	}
12332529Sbostic 	HDREG(soft_reset_reg) = 0;
12432529Sbostic 	DELAY(1000000);
12532529Sbostic 
12632529Sbostic 	/*
12732560Sbostic 	 * Read in the hdc module id word.  The controller is bad if the
12832560Sbostic 	 * hdc's writeable control store is not loaded or if the hdc failed
12932560Sbostic 	 * the functional integrity test for any reason.
13032529Sbostic 	 */
13132529Sbostic 	id = &hc->mid;
13232560Sbostic 	HDREG(module_id_reg) = (u_long)id;
13332529Sbostic 	DELAY(10000);
13432557Sbostic 	mtpr(PADC, 0);
135*33164Sbostic 
13632560Sbostic 	if (id->module_id != (u_char)HDC_MID) {
13732560Sbostic 		printf("hdc: Controller bad module id: id = %x\n",
13832560Sbostic 		    id->module_id);
139*33164Sbostic 		return(ENXIO);
14032529Sbostic 	}
14132560Sbostic 	if (id->code_rev == (u_char)0xFF) {
14232560Sbostic 		printf("hdc: Controller micro-code is not loaded.\n");
14332560Sbostic 		return(ENXIO);
14432529Sbostic 	}
14532560Sbostic 	if (id->fit != (u_char)0xFF) {
14632560Sbostic 		printf("hdc:  Controller FIT test failed: error= %x\n",
14732560Sbostic 		    id->fit);
14832560Sbostic 		return(ENXIO);
14932529Sbostic 	}
15032529Sbostic 
151*33164Sbostic 	/* Read the drive status. Save important info. */
15232529Sbostic 	mcb->command = HCMD_STATUS;
15332529Sbostic 	mcb->drive = drive;
15432529Sbostic 	mcb->cyl = 0;
15532529Sbostic 	mcb->head = 0;
15632529Sbostic 	mcb->sector = 0;
157*33164Sbostic 	mcb->chain[0].lwc = (long)sizeof(drive_stat_type) / sizeof(long);
15832560Sbostic 	mcb->chain[0].ta  = (long)&status;
15932529Sbostic 	if (hdmcb(mcb, io))
16032560Sbostic 		return(EIO);
161*33164Sbostic 
162*33164Sbostic 	/*
163*33164Sbostic 	 * Report drive down if anything in the drive status is bad.
164*33164Sbostic 	 * If fault condition, reading will try to clear the fault.
165*33164Sbostic 	 */
166*33164Sbostic 	if (status.drs & DRS_FAULT)
167*33164Sbostic 		printf("hdc: clearing drive fault.\n");
168*33164Sbostic 	if (!(status.drs & DRS_ONLINE)) {
169*33164Sbostic 		printf("hdc: drive is not online.\n");
170*33164Sbostic 		return(EIO);
171*33164Sbostic 	}
172*33164Sbostic 
17332529Sbostic 	hu->cylinders = status.max_cyl+1;
17432529Sbostic 	hu->heads = status.max_head+1;
17532529Sbostic 	hu->sectors = status.max_sector+1;
17632529Sbostic 	hu->def_cyl = status.def_cyl;
17732529Sbostic 	hu->def_cyl_count = status.def_cyl_count;
17832529Sbostic 	hu->diag_cyl = status.diag_cyl;
17932529Sbostic 	hu->diag_cyl_count = status.diag_cyl_count;
18032529Sbostic 	hu->phys_cylinders = status.max_phys_cyl+1;
18132529Sbostic 	hu->phys_heads = status.max_phys_head+1;
18232529Sbostic 	hu->phys_sectors = status.max_phys_sector+1;
18332529Sbostic 	hu->bytes_per_sec = status.bytes_per_sec;
18432529Sbostic 	hu->id = status.id;
18532529Sbostic 	hu->rpm = status.rpm;
18632529Sbostic 	hu->partition[HDC_DEFPART].start=
18732529Sbostic 		hu->def_cyl * hu->sectors * hu->heads / HDC_SPB;
18832529Sbostic 	hu->partition[HDC_DEFPART].length =
18932529Sbostic 		hu->def_cyl_count * hu->sectors * hu->heads / HDC_SPB;
19032529Sbostic 
19132529Sbostic 	/*
19232529Sbostic 	 * Read the geometry block (at head=0 sector=0 of the drive
19332529Sbostic 	 * definition cylinder), validate it (must have the correct
19432529Sbostic 	 * version number, header, and checksum).
19532529Sbostic 	 */
19632529Sbostic 	geo = &geometry.geometry_block;
19732529Sbostic 	mcb->command = HCMD_READ;
19832529Sbostic 	mcb->drive = drive;
199*33164Sbostic 	mcb->cyl = hu->def_cyl;
20032529Sbostic 	mcb->head = 0;
20132529Sbostic 	mcb->sector = 0;
202*33164Sbostic 	mcb->chain[0].lwc = sizeof(geometry_sector) / sizeof(long);
20332560Sbostic 	mcb->chain[0].ta  = (long)&geometry;
204*33164Sbostic 	io->i_boff = hu->partition[HDC_DEFPART].start;		/* default */
20532529Sbostic 	if (hdmcb(mcb, io)) {
20632529Sbostic  		printf("hdc: could not read geometry block\n");
20732560Sbostic 		return(EIO);
20832529Sbostic 	}
20932529Sbostic 	io->i_boff = 0;
21032560Sbostic  	if (geo->version > 64000  ||  geo->version < 0) {
21132529Sbostic  		printf("hdc: bad geometry block version#\n");
21232560Sbostic 		return(ENXIO);
21332529Sbostic 	}
21432560Sbostic  	if (strcmp(&geo->id[0], GB_ID) != 0) {
21532529Sbostic  		printf("hdc: bad geometry block header\n");
21632560Sbostic 		return(ENXIO);
21732529Sbostic 	}
21832560Sbostic 	GB_CHECKSUM(geo, i);
21932529Sbostic 	if (geometry.checksum != i) {
22032529Sbostic 		printf("hdc: bad geometry block checksum\n");
22132560Sbostic 		return(ENXIO);
22232529Sbostic 	}
22332529Sbostic 
22432529Sbostic 	/*
22532529Sbostic 	 * Set the partition start/size info.
22632529Sbostic 	 * Note: this info was already defaulted to be the disk
22732529Sbostic 	 * definition partition.
22832529Sbostic 	 */
22932560Sbostic 	if (par != HDC_DEFPART)
230*33164Sbostic 		if (geo->partition[par].length == 0) {	/* XXX */
231*33164Sbostic 			printf("hdc: null partition\n");
23232560Sbostic 			return(ENXIO);
23332557Sbostic 		}
23432529Sbostic 		else {
23532529Sbostic 			hu->partition[par].start  = geo->partition[par].start;
23632529Sbostic 			hu->partition[par].length = geo->partition[par].length;
23732529Sbostic 			io->i_boff = hu->partition[par].start;
23832529Sbostic 		}
23932560Sbostic 	return(0);
24032529Sbostic }
24132529Sbostic 
242*33164Sbostic /*
243*33164Sbostic  * hdstrategy --
244*33164Sbostic  *	The hdc strategy routine. This routine does the disk reads/writes. If
245*33164Sbostic  *	this is the format program, read/writes are forced to be within the
246*33164Sbostic  *	disk definition partition.  Returns the number of bytes transferred.
247*33164Sbostic  */
24832560Sbostic hdstrategy(io, cmd)
24932560Sbostic 	register struct iob	*io;	/* i/o block */
25032560Sbostic 	int	cmd;			/* i/o operation to perform */
25132529Sbostic {
252*33164Sbostic 	mcb_type	*mcb;		/* mcb to send to the hdc */
253*33164Sbostic 	hdunit_type	*hu;		/* disk unit information table */
254*33164Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table */
255*33164Sbostic 	long		err;		/* error code */
256*33164Sbostic 	long		sector;		/* sector number for i/o */
257*33164Sbostic 	int		partstart;	/* block number of partition start */
258*33164Sbostic 	int		partlen;	/* number of blocks in partition */
259*33164Sbostic 	int		bytes;		/* number of bytes to transfer */
260*33164Sbostic 	int		bus, ctlr, drive;
26132529Sbostic 
262*33164Sbostic 	bus = HDC_DEFBUS;
263*33164Sbostic 	ctlr = HDCTLR(io->i_unit);
264*33164Sbostic 	drive = HDSLAVE(io->i_unit);
26532529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
26632529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
26732529Sbostic 
26832529Sbostic 	/*
26932529Sbostic 	 * Only the format program can access the disk definition tracks.
27032529Sbostic 	 */
27132560Sbostic 	if (io->i_boff == HDC_DEFPART && !hu->format) {
27232560Sbostic 		printf("hdc: partition 7 is protected\n");
27332560Sbostic 		return(0);
27432560Sbostic 	}
27532529Sbostic 
27632529Sbostic 	/*
27732529Sbostic 	 * Insure the transfer fits in the partition.
27832529Sbostic 	 * Set and validate transfer size.
27932529Sbostic 	 */
28032560Sbostic 	partstart = hu->partition[io->i_boff].start;
28132560Sbostic 	partlen = hu->partition[io->i_boff].length;
28232560Sbostic 	if (io->i_bn < partstart || io->i_bn >= partstart + partlen)
28332560Sbostic 		return(0);
28432560Sbostic 	bytes = MIN(io->i_cc, DEV_BSIZE * (partstart + partlen-io->i_bn));
28532529Sbostic 	if (io->i_cc & 3) {
28632560Sbostic 		printf("hdc: i/o not a longword multiple\n");
28732560Sbostic 		return(0);
28832529Sbostic 	}
28932529Sbostic 
29032529Sbostic 	/*
29132529Sbostic 	 * Set up the mcb and send it to the hdc.
29232529Sbostic 	 */
29332529Sbostic 	mcb = &hc->mcb;
29432529Sbostic 	sector = io->i_bn * HDC_SPB;
29532560Sbostic 	mcb->command = (cmd == READ) ? HCMD_READ : HCMD_WRITE;
29632529Sbostic 	mcb->drive = hu->slave;
29732529Sbostic 	mcb->cyl = sector / (hu->sectors * hu->heads);
29832560Sbostic 	mcb->head = (sector / hu->sectors) % hu->heads;
29932529Sbostic 	mcb->sector = sector % hu->sectors;
30032560Sbostic 	mcb->chain[0].ta  = (u_long)io->i_ma;
301*33164Sbostic 	mcb->chain[0].lwc = (bytes + 3) / sizeof(long);
30232529Sbostic 	err = hdmcb(mcb, io);
30332529Sbostic 	io->i_error = err;
30432560Sbostic 	return(err ? 0 : bytes);
30532529Sbostic }
30632529Sbostic 
30732529Sbostic hdioctl(io, command, arg)
30832560Sbostic 	struct iob	*io; 		/* i/o block */
309*33164Sbostic 	int	command;		/* ioctl commmand */
310*33164Sbostic 	int	arg;			/* data; format depends on ioctl */
31132529Sbostic {
31232560Sbostic 	register int	i;
31332529Sbostic 	mcb_type	*mcb;
314*33164Sbostic 	hdunit_type	*hu;		/* disk unit information table */
315*33164Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table */
316*33164Sbostic 	int	bus, ctlr, drive;
31732529Sbostic 
318*33164Sbostic 	bus = HDC_DEFBUS;
319*33164Sbostic 	ctlr = HDCTLR(io->i_unit);
320*33164Sbostic 	drive = HDSLAVE(io->i_unit);
32132529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
32232529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
32332529Sbostic 
32432529Sbostic 	switch (command) {
32532529Sbostic 
32632529Sbostic 	case DSKIOCFORMAT: {
32732529Sbostic 
32832529Sbostic 		/*
32932529Sbostic 		 * Format a disk track. The received argument is a pointer
33032529Sbostic 		 * to a "formatop" structure describing the track to format.
33132529Sbostic 		 *
33232529Sbostic 		 * Set up a buffer with each longword corresponding to a
33332529Sbostic 		 * sector on the track; a 1 means no flaw, a 0 means a flaw.
33432529Sbostic 		 * Send an mcb to the hdc to format the track.
33532529Sbostic 		 */
33632529Sbostic 
33732529Sbostic 		register struct formatop *track;
33832529Sbostic 
33932529Sbostic 		if (!hu->format)
34032529Sbostic 			return(1);
34132560Sbostic 		track = (struct formatop *)arg;
34232529Sbostic 		mcb = &hc->mcb;
34332560Sbostic 		for (i = 0; i < hu->phys_sectors; i++)
34432529Sbostic 			hu->phio_data[i] = 1;
34532560Sbostic 		for (i = 0; i < track->flaw_count; i++)
34632560Sbostic 			hu->phio_data[track->flaw[i]] = 0;
34732529Sbostic 		mcb->command = HCMD_FORMAT;
34832529Sbostic 		mcb->drive = hu->slave;
34932560Sbostic 		mcb->chain[0].ta  = (u_long)hu->phio_data;
35032529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
35132529Sbostic 		mcb->cyl = track->cylinder;
35232529Sbostic 		mcb->head = track->head;
35332529Sbostic 		mcb->sector = 0;
35432529Sbostic 		if (hdmcb(mcb, io))
35532560Sbostic 			return(EIO);
35632529Sbostic 		break;
35732529Sbostic 	}
35832529Sbostic 
35932529Sbostic 	case DSKIOCCERTIFY: {
36032529Sbostic 
36132529Sbostic 		/*
36232529Sbostic 		 * Certify a disk track. The received argument is a pointer
36332529Sbostic 		 * to a "formatop" structure describing the track to certify.
36432529Sbostic 		 *
36532529Sbostic 		 * Send an mcb to the hdc to certify the track.
36632529Sbostic 		 * The controller returns data in which each longword
36732529Sbostic 		 * corresponds to a sector on the track; a 1 means no flaw,
36832529Sbostic 		 * a 0 means a flaw.
36932529Sbostic 		 */
37032529Sbostic 
37132529Sbostic 		register struct formatop *track;
37232529Sbostic 
37332529Sbostic 		if (!hu->format)
37432560Sbostic 			return(1);
37532560Sbostic 		track = (struct formatop *)arg;
37632529Sbostic 		mcb = &hc->mcb;
37732529Sbostic 		mcb->command = HCMD_CERTIFY;
37832529Sbostic 		mcb->drive = hu->slave;
37932560Sbostic 		mcb->chain[0].ta  = (u_long)hu->phio_data;
38032529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
38132529Sbostic 		mcb->cyl = track->cylinder;
38232529Sbostic 		mcb->head = track->head;
38332529Sbostic 		mcb->sector = 0;
38432529Sbostic 		if (hdmcb(mcb, io))
38532560Sbostic 			return(EIO);
38632529Sbostic 		track->flaw_count = 0;
38732560Sbostic 		for (i = 0; i < hu->phys_sectors; i++) {
38832560Sbostic 			if (track->flaw_count >= MAXVFLAW)
38932560Sbostic 				break;
39032560Sbostic 			if (hu->phio_data[i] == 0) {
39132529Sbostic 				track->flaw[track->flaw_count] = i;
39232529Sbostic 				track->flaw_count++;
39332529Sbostic 			}
39432529Sbostic 		}
39532529Sbostic 		break;
39632529Sbostic 	}
39732529Sbostic 
39832529Sbostic 	case DSKIOCVERIFY: {
39932529Sbostic 
40032529Sbostic 		/*
40132529Sbostic 		 * Verify a disk track. The received argument is a pointer
40232529Sbostic 		 * to a "formatop" structure describing the track to verify.
40332529Sbostic 		 */
40432529Sbostic 
40532529Sbostic 		register struct formatop *track;
40632529Sbostic 
40732529Sbostic 		if (!hu->format)
40832529Sbostic 			return(1);
40932560Sbostic 		track = (struct formatop *)arg;
41032529Sbostic 		mcb = &hc->mcb;
41132529Sbostic 		mcb->command = HCMD_VERIFY;
41232529Sbostic 		mcb->drive = hu->slave;
41332529Sbostic 		mcb->chain[0].ta  = 0;
41432529Sbostic 		mcb->chain[0].lwc = 0;
41532529Sbostic 		mcb->cyl = track->cylinder;
41632529Sbostic 		mcb->head = track->head;
41732529Sbostic 		mcb->sector = 0;
41832529Sbostic 		if (hdmcb(mcb, io))
41932560Sbostic 			return(EIO);
42032529Sbostic 		break;
42132529Sbostic 	}
42232529Sbostic 
42332529Sbostic 	case DSKIOCFORMATCTL: {
42432529Sbostic 
42532529Sbostic 		/*
42632529Sbostic 		 * This ioctl provides special format control.
42732529Sbostic 		 * Currently the valid arguments are:
42832529Sbostic 		 *
42932560Sbostic 		 * arg = 0	disable formatting;
43032529Sbostic 		 *
43132560Sbostic 		 * arg = 1	enable formatting (allow privileged access);
43232560Sbostic 		 *		formatting must not already be enabled;
43332560Sbostic 		 *		For formatting, change to use partition 7.
43432529Sbostic 		 */
43532529Sbostic 
43632560Sbostic 		if (arg < 0 || arg > 1)
43732560Sbostic 			return(1);
43832560Sbostic 		if (arg == 1) {
43932560Sbostic 			if (hu->format)
44032560Sbostic 				return(1);
44132529Sbostic 			/* If not already formatting.... */
44232560Sbostic 			hu->format = 1;
44332557Sbostic 			/* io->i_part = HDC_DEFPART; */
44432529Sbostic 			io->i_boff = hu->partition[HDC_DEFPART].start;
44532529Sbostic 		}
44632529Sbostic 		else
44732560Sbostic 			hu->format = 0;
44832529Sbostic 		break;
44932529Sbostic 	}
45032529Sbostic 
45132529Sbostic 	case DSKIOCSTATUS: {
45232529Sbostic 
45332529Sbostic 		/*
45432529Sbostic 		 * Return info about the disk. Caller's parameter is a
45532529Sbostic 		 * pointer to a dsk_status structure.
45632529Sbostic 		 */
45732529Sbostic 
45832529Sbostic 		register dsk_status *status;
45932529Sbostic 
46032560Sbostic 		status = (dsk_status *)arg;
46132560Sbostic 		status->id = hu->id;
46232560Sbostic 		status->drive_status = 0;
46332560Sbostic 		status->rpm = hu->rpm;
46432529Sbostic 		status->bytes_per_sec = hu->bytes_per_sec;
46532560Sbostic 		status->cylinders = hu->cylinders;
46632560Sbostic 		status->heads = hu->heads;
46732560Sbostic 		status->sectors = hu->sectors;
46832560Sbostic 		status->phys_cylinders = hu->phys_cylinders;
46932560Sbostic 		status->phys_heads = hu->phys_heads;
47032560Sbostic 		status->phys_sectors = hu->phys_sectors;
47132560Sbostic 		status->diag_cyl = hu->diag_cyl;
47232560Sbostic 		status->diag_cylinders = hu->diag_cyl_count;
47332560Sbostic 		status->def_cyl = hu->def_cyl;
47432560Sbostic 		status->def_cylinders = hu->def_cyl_count;
47532529Sbostic 		break;
47632529Sbostic 	}
47732529Sbostic 
47832529Sbostic 	case DSKIOCVENDORFLAW: {
47932529Sbostic 
48032529Sbostic 		/*
48132529Sbostic 		 * Return vendor flaw info.
48232529Sbostic 		 *
48332529Sbostic 		 * Read in the vendor data (data for each track is at
48432529Sbostic 		 * relative sector 0 of the track); then copy the
48532529Sbostic 		 * vendor flaw data to the caller's buffer.
48632529Sbostic 		 */
48732529Sbostic 
48832529Sbostic 		register vflaw_type *vflaw;
48932529Sbostic 		register struct flaw *vendor;
49032529Sbostic 
49132529Sbostic 		if (!hu->format)
49232529Sbostic 			return(1);
49332560Sbostic 		vflaw = (vflaw_type *)arg;
49432529Sbostic 		mcb = &hc->mcb;
49532529Sbostic 		mcb->command = HCMD_VENDOR;
49632529Sbostic 		mcb->drive = hu->slave;
49732529Sbostic 		mcb->chain[0].lwc = HDC_VDATA_SIZE;
49832560Sbostic 		mcb->chain[0].ta  = (u_long)hu->phio_data;
49932529Sbostic 		mcb->cyl = vflaw->cylinder;
50032529Sbostic 		mcb->head = vflaw->head;
50132529Sbostic 		mcb->sector = 0;
50232529Sbostic 		if (hdmcb(mcb, io))
50332560Sbostic 			return(EIO);
50432560Sbostic 		vendor = (struct flaw *)&hu->phio_data[0];
50532560Sbostic 		for (i = 0; i < MAXVFLAW; i++) {
50632529Sbostic 			vflaw->flaw[i].offset = vendor[i].offset;
50732529Sbostic 			vflaw->flaw[i].length = vendor[i].length;
50832529Sbostic 		}
50932529Sbostic 		break;
51032529Sbostic 	}
51132529Sbostic 	}
51232560Sbostic 	return(0);
51332529Sbostic }
51432529Sbostic 
515*33164Sbostic /*
516*33164Sbostic  * hdmcb --
517*33164Sbostic  *	internal routine used to send mcb's to the hdc
518*33164Sbostic  */
519*33164Sbostic static
52032529Sbostic hdmcb(mcb, io)
521*33164Sbostic 	register mcb_type	*mcb;	/* mcb to send to the hdc */
522*33164Sbostic 	register struct iob	*io;	/* i/o block */
52332529Sbostic {
524*33164Sbostic 	register u_int	*ptr;
525*33164Sbostic 	master_mcb_type	*master_mcb;	/* the hdc's master mcb */
526*33164Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table */
527*33164Sbostic 	hdc_regs_type	*ctlr_addr;	/* pointer to hdc i/o registers */
528*33164Sbostic 	int	timeout;		/* used to timeout the mcb */
529*33164Sbostic 	int	bus, ctlr, i, end;
53032529Sbostic 
531*33164Sbostic 	bus = HDC_DEFBUS;
532*33164Sbostic 	ctlr = HDCTLR(io->i_unit);
53332529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
53432529Sbostic 
53532529Sbostic 	mcb->interrupt = FALSE;
53632529Sbostic 	mcb->priority = 0;
53732529Sbostic 	mcb->forw_phaddr = 0;
53832529Sbostic 	mcb->context = 0;
53932529Sbostic 	mcb->reserved[0] = 0;
54032529Sbostic 	mcb->reserved[1] = 0;
54132529Sbostic 	master_mcb = &hc->master_mcb;
54232560Sbostic 	master_mcb->forw_phaddr = (long)&mcb->forw_phaddr;
54332529Sbostic 	master_mcb->mcs = 0;
54432529Sbostic 	master_mcb->interrupt = 0;
54532560Sbostic 	master_mcb->reserve1 = 0;
54632560Sbostic 	master_mcb->reserve2 = 0;
54732560Sbostic 	master_mcb->context = 0;
54832529Sbostic 	master_mcb->mcl = MCL_IMMEDIATE;
54932560Sbostic 	for (i = 0; i < HDC_XSTAT_SIZE; i++)
55032560Sbostic 		master_mcb->xstatus[i] = 0;
55132560Sbostic 	ctlr_addr = hc->registers;
55232560Sbostic 	HDREG(master_mcb_reg) = (u_long)master_mcb;
55332529Sbostic 	timeout = 15000;
55432560Sbostic 	for (;;) {
55532529Sbostic 		DELAY(1000);
55632557Sbostic 		mtpr(PADC, 0);
55732560Sbostic 		if (master_mcb->mcs & MCS_DONE &&
55832560Sbostic 		    !(master_mcb->mcs & MCS_FATALERROR))
55932560Sbostic 			return(0);
560*33164Sbostic 		if (--timeout > 0 && !(master_mcb->mcs & MCS_FATALERROR))
56132560Sbostic 			continue;
56232560Sbostic 		if (master_mcb->mcs & MCS_FATALERROR)
56332529Sbostic 			printf("hdc: controller fatal error\n");
56432529Sbostic 		else
56532529Sbostic 			printf("hdc: controller timed out\n");
56632529Sbostic 
56732529Sbostic 		printf("mmcb: ");
56832560Sbostic 		ptr = (u_int *)master_mcb;
56932560Sbostic 		for (i = 0; i < 8; i++)
57032560Sbostic 			printf(" %x", ptr[i]);
57132560Sbostic 		for (i = 7 + HDC_XSTAT_SIZE; i > 7; i--) {
57232529Sbostic 			end = i;
57332560Sbostic 			if (ptr[i] != 0)
57432560Sbostic 				break;
57532529Sbostic 		}
57632560Sbostic 		for (i = 8; i <= end; i++)
57732560Sbostic 			printf(" %x", ptr[i]);
57832529Sbostic 
579*33164Sbostic 		printf("\nmcb:  ");
58032560Sbostic 		ptr = (u_int *)&mcb->forw_phaddr;
58132560Sbostic 		for (i = 0; i < 6; i++)
58232560Sbostic 			printf(" %x", ptr[i]);
58332560Sbostic 		for (i = 6; i < 72; i += 2) {
58432529Sbostic 			printf("  %x %x", ptr[i], ptr[i+1]);
58532560Sbostic 			if (!(ptr[i] & 0x80000000))
58632560Sbostic 				break;
58732529Sbostic 		}
58832529Sbostic 		printf("\n");
58932529Sbostic 		return(1);
59032529Sbostic 	}
59132529Sbostic }
592