xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 32560)
132529Sbostic /*
232529Sbostic  * Stand alone driver for the HDC controller
332557Sbostic  *
4*32560Sbostic  *	@(#)hd.c	7.3 (Berkeley) 10/28/87
532529Sbostic  */
632557Sbostic #define	KERNEL
732529Sbostic 
832557Sbostic #include "machine/mtpr.h"
932557Sbostic #include "param.h"
1032557Sbostic #include "systm.h"
1132557Sbostic #include "buf.h"
1232557Sbostic #include "time.h"
1332557Sbostic #include "inode.h"
1432557Sbostic #include "fs.h"
1532557Sbostic #include "ioctl.h"
1632557Sbostic #include "tahoevba/dsk.h"
1732557Sbostic #include "tahoevba/dskio.h"
1832557Sbostic #include "tahoevba/hdc.h"
1932557Sbostic #include "saio.h"
2032529Sbostic 
2132557Sbostic #define	NHD		4
2232557Sbostic #define	NDRIVE		8		/* drives per controller */
2332557Sbostic #define	HDSLAVE(x)	((x) % NDRIVE)
2432557Sbostic #define	HDCTLR(x)	((x) / NDRIVE)
2532529Sbostic 
2632557Sbostic #define	HDREG(x)	(ctlr_addr->x)	/* standalone io to an hdc register */
2732557Sbostic #define	HID_HDC		0x01		/* hvme_id for HDC */
2832529Sbostic 
2932529Sbostic /*
3032529Sbostic  * hdc controller table. It contains information about the hdc controller.
3132529Sbostic  */
3232529Sbostic typedef struct {
3332529Sbostic 	int		ctlr;		/* controller number (0-15)         */
3432529Sbostic 	hdc_regs_type	*registers;	/* base address of hdc io registers */
3532529Sbostic 	hdc_mid_type	mid;		/* the module id is read to here    */
36*32560Sbostic 	master_mcb_type	master_mcb;	/* the master mcb for this hdc      */
3732529Sbostic 	mcb_type	mcb;		/* an mcb for i/o to the controller */
3832529Sbostic } hdctlr_type;
3932529Sbostic 
4032529Sbostic hdctlr_type hdc_ctlr[HDC_MAXCTLR][HDC_MAXBUS];
4132529Sbostic 
4232529Sbostic /*
4332529Sbostic  * hdc unit table. It contains information about the hdc drive.
4432529Sbostic  * Some information is obtained from the profile prom and geometry block.
4532529Sbostic  */
4632529Sbostic typedef struct {
47*32560Sbostic 	par_tab	partition[GB_MAXPART];	/* partition definitions            */
48*32560Sbostic 	int	ctlr;			/* the controller number (0-15)     */
49*32560Sbostic 	int	slave;			/* the slave number (0-4)           */
50*32560Sbostic 	int	unit;			/* the unit number (0-31)           */
51*32560Sbostic 	int	id;			/* identifies the disk model        */
52*32560Sbostic  	int	cylinders;		/* number of logical cylinders      */
53*32560Sbostic 	int	heads;			/* number of logical heads          */
54*32560Sbostic 	int	sectors;		/* number of logical sectors/track  */
55*32560Sbostic 	int	phys_cylinders;		/* number of physical cylinders     */
56*32560Sbostic 	int	phys_heads;		/* number of physical heads         */
57*32560Sbostic 	int	phys_sectors;		/* number of physical sectors/track */
58*32560Sbostic 	int	def_cyl;		/* logical cylinder of drive def    */
59*32560Sbostic 	int	def_cyl_count;		/* number of logical def cylinders  */
60*32560Sbostic 	int	diag_cyl;		/* logical cylinder of diag area    */
61*32560Sbostic 	int	diag_cyl_count;		/* number of logical diag cylinders */
62*32560Sbostic 	int	rpm;			/* disk rpm                         */
63*32560Sbostic 	int	bytes_per_sec;		/* bytes/sector -vendorflaw conversn*/
64*32560Sbostic 	int	format;			/* format program is active         */
65*32560Sbostic 	u_long	phio_data[HDC_PHIO_SIZE];	/* data for physical io     */
6632529Sbostic } hdunit_type;
6732529Sbostic 
68*32560Sbostic hdunit_type hdc_unit [HDC_MAXDRIVE] [HDC_MAXCTLR] [HDC_MAXBUS];
6932529Sbostic 
7032529Sbostic /*************************************************************************
7132529Sbostic *  Procedure:	hdopen
7232529Sbostic *
73*32560Sbostic *  Description:	The hdc open routine. Initializes the hdc and reads the
74*32560Sbostic *		hdc status and the geometry block.
7532529Sbostic *
76*32560Sbostic *  Returns:	 0  open was successful
77*32560Sbostic *		-1  this is not an hdc controller
7832529Sbostic **************************************************************************/
7932529Sbostic hdopen(io)
80*32560Sbostic 	register struct iob	*io;	/* i/o block */
8132529Sbostic {
8232529Sbostic 	mcb_type	*mcb;		/* an mcb to send commands to hdc   */
8332529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
8432529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
8532529Sbostic 	hdc_mid_type	*id;		/* the hdc module id                */
86*32560Sbostic 	geometry_sector	geometry;	/* the geometry block sector        */
8732529Sbostic 	geometry_block	*geo;		/* the geometry block               */
8832529Sbostic 	drive_stat_type	status;		/* the hdc status is read to here   */
89*32560Sbostic 	long		ctlr;		/* the controller number            */
90*32560Sbostic 	long		junk;		/* badaddr will write junk here     */
9132529Sbostic 	int		par;		/* partition number                 */
92*32560Sbostic 	int		drive;		/* the drive number                 */
93*32560Sbostic 	int		bus;		/* the bus number                   */
94*32560Sbostic 	int		i;		/* temp                             */
9532529Sbostic 	hdc_regs_type	*ctlr_addr;	/* hdc i/o registers                */
9632529Sbostic 
97*32560Sbostic 	par = io->i_boff;		/* io->i_part;	*/
98*32560Sbostic 	bus = 0;			/* io->i_bus;	*/
99*32560Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr;	*/
100*32560Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive;	*/
10132529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
10232529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
10332529Sbostic 	mcb = &hc->mcb;
10432529Sbostic 
10532529Sbostic 	/*
10632529Sbostic 	 * Validate the device specification
10732529Sbostic 	 */
10832557Sbostic 	if (ctlr >= HDC_MAXCTLR) {
10932557Sbostic 		printf("invalid controller number\n");
110*32560Sbostic 		return(ENXIO);
11132557Sbostic 	}
112*32560Sbostic 	if (drive < 0 || drive > HDC_MAXDRIVE - 1) {
11332529Sbostic 		printf("hdc: bad drive number.\n");
114*32560Sbostic 		return(EUNIT);
11532529Sbostic 	}
11632529Sbostic 	if (par < 0 || par > 7) {
11732529Sbostic 		printf("hdc: bad partition number.\n");
118*32560Sbostic 		return(EUNIT);
11932529Sbostic 	}
12032557Sbostic 	ctlr_addr = (hdc_regs_type *)(bus == 0 ?
12132529Sbostic 		0xC0000000 | ctlr << 24 | HDC_MID << 16  :
12232557Sbostic 		0x80000000 | ctlr << 24 | HDC_MID << 16);
12332529Sbostic 
12432529Sbostic 	/*
12532529Sbostic 	 * Init drive structure.
12632529Sbostic 	 */
12732529Sbostic 	hu->slave = drive;
12832529Sbostic 	hc->registers = ctlr_addr;
12932529Sbostic 
13032529Sbostic 	/*
13132529Sbostic 	 * Insure that this is an hdc, then reset the hdc.
13232529Sbostic 	 */
13332557Sbostic 	junk = 0;
13432557Sbostic 	if (wbadaddr(&ctlr_addr->module_id_reg, 4, &junk)) {
135*32560Sbostic 		printf("hd%d: %x: invalid csr\n", ctlr, (u_int)ctlr_addr);
136*32560Sbostic 		return(ENXIO);
13732557Sbostic 	}
13832529Sbostic 	HDREG(soft_reset_reg) = 0;
13932529Sbostic 	DELAY(1000000);
14032529Sbostic 
14132529Sbostic 	/*
142*32560Sbostic 	 * Read in the hdc module id word.  The controller is bad if the
143*32560Sbostic 	 * hdc's writeable control store is not loaded or if the hdc failed
144*32560Sbostic 	 * the functional integrity test for any reason.
14532529Sbostic 	 */
14632529Sbostic 	id = &hc->mid;
147*32560Sbostic 	HDREG(module_id_reg) = (u_long)id;
14832529Sbostic 	DELAY(10000);
14932557Sbostic 	mtpr(PADC, 0);
150*32560Sbostic 	if (id->module_id != (u_char)HDC_MID) {
151*32560Sbostic 		printf("hdc: Controller bad module id: id = %x\n",
152*32560Sbostic 		    id->module_id);
153*32560Sbostic 		return(-1);
15432529Sbostic 	}
155*32560Sbostic 	if (id->code_rev == (u_char)0xFF) {
156*32560Sbostic 		printf("hdc: Controller micro-code is not loaded.\n");
157*32560Sbostic 		return(ENXIO);
15832529Sbostic 	}
159*32560Sbostic 	if (id->fit != (u_char)0xFF) {
160*32560Sbostic 		printf("hdc:  Controller FIT test failed: error= %x\n",
161*32560Sbostic 		    id->fit);
162*32560Sbostic 		return(ENXIO);
16332529Sbostic 	}
16432529Sbostic 
16532529Sbostic 	/*
16632529Sbostic 	 * Read the drive status. Save important info.
16732529Sbostic 	 */
16832529Sbostic 	mcb->command = HCMD_STATUS;
16932529Sbostic 	mcb->drive = drive;
17032529Sbostic 	mcb->cyl = 0;
17132529Sbostic 	mcb->head = 0;
17232529Sbostic 	mcb->sector = 0;
173*32560Sbostic 	mcb->chain[0].lwc = (long)sizeof(drive_stat_type) / 4;
174*32560Sbostic 	mcb->chain[0].ta  = (long)&status;
17532529Sbostic 	if (hdmcb(mcb, io))
176*32560Sbostic 		return(EIO);
17732529Sbostic 	hu->cylinders = status.max_cyl+1;
17832529Sbostic 	hu->heads = status.max_head+1;
17932529Sbostic 	hu->sectors = status.max_sector+1;
18032529Sbostic 	hu->def_cyl = status.def_cyl;
18132529Sbostic 	hu->def_cyl_count = status.def_cyl_count;
18232529Sbostic 	hu->diag_cyl = status.diag_cyl;
18332529Sbostic 	hu->diag_cyl_count = status.diag_cyl_count;
18432529Sbostic 	hu->phys_cylinders = status.max_phys_cyl+1;
18532529Sbostic 	hu->phys_heads = status.max_phys_head+1;
18632529Sbostic 	hu->phys_sectors = status.max_phys_sector+1;
18732529Sbostic 	hu->bytes_per_sec = status.bytes_per_sec;
18832529Sbostic 	hu->id = status.id;
18932529Sbostic 	hu->rpm = status.rpm;
19032529Sbostic 	hu->partition[HDC_DEFPART].start=
19132529Sbostic 		hu->def_cyl * hu->sectors * hu->heads / HDC_SPB;
19232529Sbostic 	hu->partition[HDC_DEFPART].length =
19332529Sbostic 		hu->def_cyl_count * hu->sectors * hu->heads / HDC_SPB;
194*32560Sbostic 	io->i_boff = hu->partition[HDC_DEFPART].start;	/* default */
19532529Sbostic 
19632529Sbostic 	/*
19732529Sbostic 	 * Report drive down if anything in the drive status is bad.
19832529Sbostic 	 * If fault condition, reading geo will try to clear the fault.
19932529Sbostic 	 */
20032529Sbostic 	if (status.drs & DRS_FAULT)
20132529Sbostic 		printf("hdc: clearing drive fault.\n");
202*32560Sbostic 	if (!(status.drs & DRS_ONLINE)) {
20332529Sbostic 		printf("hdc: drive is not online.\n");
204*32560Sbostic 		return(EIO);
20532529Sbostic 	}
20632529Sbostic 
20732529Sbostic 	/*
20832529Sbostic 	 * Read the geometry block (at head=0 sector=0 of the drive
20932529Sbostic 	 * definition cylinder), validate it (must have the correct
21032529Sbostic 	 * version number, header, and checksum).
21132529Sbostic 	 */
21232529Sbostic 	geo = &geometry.geometry_block;
21332529Sbostic 	mcb->command = HCMD_READ;
21432529Sbostic 	mcb->drive = drive;
21532529Sbostic 	mcb->cyl = status.def_cyl;
21632529Sbostic 	mcb->head = 0;
21732529Sbostic 	mcb->sector = 0;
21832529Sbostic 	mcb->chain[0].lwc = sizeof(geometry_sector) / 4;
219*32560Sbostic 	mcb->chain[0].ta  = (long)&geometry;
22032529Sbostic 	if (hdmcb(mcb, io)) {
22132529Sbostic  		printf("hdc: could not read geometry block\n");
222*32560Sbostic 		return(EIO);
22332529Sbostic 	}
22432529Sbostic 	io->i_boff = 0;
225*32560Sbostic  	if (geo->version > 64000  ||  geo->version < 0) {
22632529Sbostic  		printf("hdc: bad geometry block version#\n");
227*32560Sbostic 		return(ENXIO);
22832529Sbostic 	}
229*32560Sbostic  	if (strcmp(&geo->id[0], GB_ID) != 0) {
23032529Sbostic  		printf("hdc: bad geometry block header\n");
231*32560Sbostic 		return(ENXIO);
23232529Sbostic 	}
233*32560Sbostic 	GB_CHECKSUM(geo, i);
23432529Sbostic 	if (geometry.checksum != i) {
23532529Sbostic 		printf("hdc: bad geometry block checksum\n");
236*32560Sbostic 		return(ENXIO);
23732529Sbostic 	}
23832529Sbostic 
23932529Sbostic 	/*
24032529Sbostic 	 * Set the partition start/size info.
24132529Sbostic 	 * Note: this info was already defaulted to be the disk
24232529Sbostic 	 * definition partition.
24332529Sbostic 	 */
244*32560Sbostic 	if (par != HDC_DEFPART)
24532557Sbostic 		if (geo->partition[par].length == 0) {
24632529Sbostic 			printf("hdc:  null partition\n");
247*32560Sbostic 			return(ENXIO);
24832557Sbostic 		}
24932529Sbostic 		else {
25032529Sbostic 			hu->partition[par].start  = geo->partition[par].start;
25132529Sbostic 			hu->partition[par].length = geo->partition[par].length;
25232529Sbostic 			io->i_boff = hu->partition[par].start;
25332529Sbostic 		}
254*32560Sbostic 	return(0);
25532529Sbostic }
25632529Sbostic 
25732529Sbostic /*************************************************************************
25832529Sbostic *  Procedure:	hdstrategy
25932529Sbostic *
260*32560Sbostic *  Description:	The hdc strategy routine. This routine does the disk
261*32560Sbostic *		reads/writes. If this is the format program, read/writes
262*32560Sbostic *		are forced to be within the disk definition partition.
26332529Sbostic *
264*32560Sbostic *  Returns:	The number of bytes transfered.
26532529Sbostic **************************************************************************/
266*32560Sbostic hdstrategy(io, cmd)
267*32560Sbostic 	register struct iob	*io;	/* i/o block */
268*32560Sbostic 	int	cmd;			/* i/o operation to perform */
26932529Sbostic {
27032529Sbostic 	mcb_type	*mcb;		/* mcb to send to the hdc           */
27132529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
27232529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
27332529Sbostic 	long		err;		/* error code                       */
27432529Sbostic 	long		sector;		/* sector number for i/o            */
275*32560Sbostic 	int		partstart;	/* block number of partition start  */
276*32560Sbostic 	int		partlen;	/* number of blocks in partition    */
277*32560Sbostic 	int		bytes;		/* number of bytes to transfer      */
27832529Sbostic 	int		bus;		/* bus number	                    */
279*32560Sbostic 	int		ctlr;		/* the controller number            */
280*32560Sbostic 	int		drive;		/* the drive number                 */
28132529Sbostic 
282*32560Sbostic 	bus = 0;			/* io->i_bus;	*/
283*32560Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr;	*/
284*32560Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive;	*/
28532529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
28632529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
28732529Sbostic 
28832529Sbostic 	/*
28932529Sbostic 	 * Only the format program can access the disk definition tracks.
29032529Sbostic 	 */
291*32560Sbostic 	if (io->i_boff == HDC_DEFPART && !hu->format) {
292*32560Sbostic 		printf("hdc: partition 7 is protected\n");
293*32560Sbostic 		return(0);
294*32560Sbostic 	}
29532529Sbostic 
29632529Sbostic 	/*
29732529Sbostic 	 * Insure the transfer fits in the partition.
29832529Sbostic 	 * Set and validate transfer size.
29932529Sbostic 	 */
300*32560Sbostic 	partstart = hu->partition[io->i_boff].start;
301*32560Sbostic 	partlen = hu->partition[io->i_boff].length;
302*32560Sbostic 	if (io->i_bn < partstart || io->i_bn >= partstart + partlen)
303*32560Sbostic 		return(0);
304*32560Sbostic 	bytes = MIN(io->i_cc, DEV_BSIZE * (partstart + partlen-io->i_bn));
30532529Sbostic 	if (io->i_cc & 3) {
306*32560Sbostic 		printf("hdc: i/o not a longword multiple\n");
307*32560Sbostic 		return(0);
30832529Sbostic 	}
30932529Sbostic 
31032529Sbostic 	/*
31132529Sbostic 	 * Set up the mcb and send it to the hdc.
31232529Sbostic 	 */
31332529Sbostic 	mcb = &hc->mcb;
31432529Sbostic 	sector = io->i_bn * HDC_SPB;
315*32560Sbostic 	mcb->command = (cmd == READ) ? HCMD_READ : HCMD_WRITE;
31632529Sbostic 	mcb->drive = hu->slave;
31732529Sbostic 	mcb->cyl = sector / (hu->sectors * hu->heads);
318*32560Sbostic 	mcb->head = (sector / hu->sectors) % hu->heads;
31932529Sbostic 	mcb->sector = sector % hu->sectors;
320*32560Sbostic 	mcb->chain[0].ta  = (u_long)io->i_ma;
32132529Sbostic 	mcb->chain[0].lwc = (bytes + 3) / 4;
32232529Sbostic 	err = hdmcb(mcb, io);
32332529Sbostic 	io->i_error = err;
324*32560Sbostic 	return(err ? 0 : bytes);
32532529Sbostic }
32632529Sbostic 
32732529Sbostic /*************************************************************************
32832529Sbostic *  Procedure:	hdioctl
32932529Sbostic *
330*32560Sbostic *  Description:	ioctl routine.
33132529Sbostic *
332*32560Sbostic *  Returns:	0	no errors
333*32560Sbostic *		non-0	error
33432529Sbostic **************************************************************************/
33532529Sbostic hdioctl(io, command, arg)
336*32560Sbostic 	struct iob	*io; 		/* i/o block */
337*32560Sbostic 	int	command;		/* The ioctl commmand */
338*32560Sbostic 	int	arg;			/* Data.  Format depends on ioctl */
33932529Sbostic {
340*32560Sbostic 	register int	i;
34132529Sbostic 	mcb_type	*mcb;
342*32560Sbostic 	hdunit_type	*hu;		/* disk unit information table	*/
343*32560Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table	*/
344*32560Sbostic 	int		bus;		/* bus number			*/
345*32560Sbostic 	int		ctlr;		/* the controller number	*/
346*32560Sbostic 	int		drive;		/* the drive number		*/
34732529Sbostic 
348*32560Sbostic 	bus = 0;			/* io->i_bus;	*/
349*32560Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr;	*/
350*32560Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive;	*/
35132529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
35232529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
35332529Sbostic 
35432529Sbostic 	switch (command) {
35532529Sbostic 
35632529Sbostic 	case DSKIOCFORMAT: {
35732529Sbostic 
35832529Sbostic 		/*
35932529Sbostic 		 * Format a disk track. The received argument is a pointer
36032529Sbostic 		 * to a "formatop" structure describing the track to format.
36132529Sbostic 		 *
36232529Sbostic 		 * Set up a buffer with each longword corresponding to a
36332529Sbostic 		 * sector on the track; a 1 means no flaw, a 0 means a flaw.
36432529Sbostic 		 * Send an mcb to the hdc to format the track.
36532529Sbostic 		 */
36632529Sbostic 
36732529Sbostic 		register struct formatop *track;
36832529Sbostic 
36932529Sbostic 		if (!hu->format)
37032529Sbostic 			return(1);
371*32560Sbostic 		track = (struct formatop *)arg;
37232529Sbostic 		mcb = &hc->mcb;
373*32560Sbostic 		for (i = 0; i < hu->phys_sectors; i++)
37432529Sbostic 			hu->phio_data[i] = 1;
375*32560Sbostic 		for (i = 0; i < track->flaw_count; i++)
376*32560Sbostic 			hu->phio_data[track->flaw[i]] = 0;
37732529Sbostic 		mcb->command = HCMD_FORMAT;
37832529Sbostic 		mcb->drive = hu->slave;
379*32560Sbostic 		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))
385*32560Sbostic 			return(EIO);
38632529Sbostic 		break;
38732529Sbostic 	}
38832529Sbostic 
38932529Sbostic 	case DSKIOCCERTIFY: {
39032529Sbostic 
39132529Sbostic 		/*
39232529Sbostic 		 * Certify a disk track. The received argument is a pointer
39332529Sbostic 		 * to a "formatop" structure describing the track to certify.
39432529Sbostic 		 *
39532529Sbostic 		 * Send an mcb to the hdc to certify the track.
39632529Sbostic 		 * The controller returns data in which each longword
39732529Sbostic 		 * corresponds to a sector on the track; a 1 means no flaw,
39832529Sbostic 		 * a 0 means a flaw.
39932529Sbostic 		 */
40032529Sbostic 
40132529Sbostic 		register struct formatop *track;
40232529Sbostic 
40332529Sbostic 		if (!hu->format)
404*32560Sbostic 			return(1);
405*32560Sbostic 		track = (struct formatop *)arg;
40632529Sbostic 		mcb = &hc->mcb;
40732529Sbostic 		mcb->command = HCMD_CERTIFY;
40832529Sbostic 		mcb->drive = hu->slave;
409*32560Sbostic 		mcb->chain[0].ta  = (u_long)hu->phio_data;
41032529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
41132529Sbostic 		mcb->cyl = track->cylinder;
41232529Sbostic 		mcb->head = track->head;
41332529Sbostic 		mcb->sector = 0;
41432529Sbostic 		if (hdmcb(mcb, io))
415*32560Sbostic 			return(EIO);
41632529Sbostic 		track->flaw_count = 0;
417*32560Sbostic 		for (i = 0; i < hu->phys_sectors; i++) {
418*32560Sbostic 			if (track->flaw_count >= MAXVFLAW)
419*32560Sbostic 				break;
420*32560Sbostic 			if (hu->phio_data[i] == 0) {
42132529Sbostic 				track->flaw[track->flaw_count] = i;
42232529Sbostic 				track->flaw_count++;
42332529Sbostic 			}
42432529Sbostic 		}
42532529Sbostic 		break;
42632529Sbostic 	}
42732529Sbostic 
42832529Sbostic 	case DSKIOCVERIFY: {
42932529Sbostic 
43032529Sbostic 		/*
43132529Sbostic 		 * Verify a disk track. The received argument is a pointer
43232529Sbostic 		 * to a "formatop" structure describing the track to verify.
43332529Sbostic 		 */
43432529Sbostic 
43532529Sbostic 		register struct formatop *track;
43632529Sbostic 
43732529Sbostic 		if (!hu->format)
43832529Sbostic 			return(1);
439*32560Sbostic 		track = (struct formatop *)arg;
44032529Sbostic 		mcb = &hc->mcb;
44132529Sbostic 		mcb->command = HCMD_VERIFY;
44232529Sbostic 		mcb->drive = hu->slave;
44332529Sbostic 		mcb->chain[0].ta  = 0;
44432529Sbostic 		mcb->chain[0].lwc = 0;
44532529Sbostic 		mcb->cyl = track->cylinder;
44632529Sbostic 		mcb->head = track->head;
44732529Sbostic 		mcb->sector = 0;
44832529Sbostic 		if (hdmcb(mcb, io))
449*32560Sbostic 			return(EIO);
45032529Sbostic 		break;
45132529Sbostic 	}
45232529Sbostic 
45332529Sbostic 	case DSKIOCFORMATCTL: {
45432529Sbostic 
45532529Sbostic 		/*
45632529Sbostic 		 * This ioctl provides special format control.
45732529Sbostic 		 * Currently the valid arguments are:
45832529Sbostic 		 *
459*32560Sbostic 		 * arg = 0	disable formatting;
46032529Sbostic 		 *
461*32560Sbostic 		 * arg = 1	enable formatting (allow privileged access);
462*32560Sbostic 		 *		formatting must not already be enabled;
463*32560Sbostic 		 *		For formatting, change to use partition 7.
46432529Sbostic 		 */
46532529Sbostic 
466*32560Sbostic 		if (arg < 0 || arg > 1)
467*32560Sbostic 			return(1);
468*32560Sbostic 		if (arg == 1) {
469*32560Sbostic 			if (hu->format)
470*32560Sbostic 				return(1);
47132529Sbostic 			/* If not already formatting.... */
472*32560Sbostic 			hu->format = 1;
47332557Sbostic 			/* io->i_part = HDC_DEFPART; */
47432529Sbostic 			io->i_boff = hu->partition[HDC_DEFPART].start;
47532529Sbostic 		}
47632529Sbostic 		else
477*32560Sbostic 			hu->format = 0;
47832529Sbostic 		break;
47932529Sbostic 	}
48032529Sbostic 
48132529Sbostic 	case DSKIOCSTATUS: {
48232529Sbostic 
48332529Sbostic 		/*
48432529Sbostic 		 * Return info about the disk. Caller's parameter is a
48532529Sbostic 		 * pointer to a dsk_status structure.
48632529Sbostic 		 */
48732529Sbostic 
48832529Sbostic 		register dsk_status *status;
48932529Sbostic 
490*32560Sbostic 		status = (dsk_status *)arg;
491*32560Sbostic 		status->id = hu->id;
492*32560Sbostic 		status->drive_status = 0;
493*32560Sbostic 		status->rpm = hu->rpm;
49432529Sbostic 		status->bytes_per_sec = hu->bytes_per_sec;
495*32560Sbostic 		status->cylinders = hu->cylinders;
496*32560Sbostic 		status->heads = hu->heads;
497*32560Sbostic 		status->sectors = hu->sectors;
498*32560Sbostic 		status->phys_cylinders = hu->phys_cylinders;
499*32560Sbostic 		status->phys_heads = hu->phys_heads;
500*32560Sbostic 		status->phys_sectors = hu->phys_sectors;
501*32560Sbostic 		status->diag_cyl = hu->diag_cyl;
502*32560Sbostic 		status->diag_cylinders = hu->diag_cyl_count;
503*32560Sbostic 		status->def_cyl = hu->def_cyl;
504*32560Sbostic 		status->def_cylinders = hu->def_cyl_count;
50532529Sbostic 		break;
50632529Sbostic 	}
50732529Sbostic 
50832529Sbostic 	case DSKIOCVENDORFLAW: {
50932529Sbostic 
51032529Sbostic 		/*
51132529Sbostic 		 * Return vendor flaw info.
51232529Sbostic 		 *
51332529Sbostic 		 * Read in the vendor data (data for each track is at
51432529Sbostic 		 * relative sector 0 of the track); then copy the
51532529Sbostic 		 * vendor flaw data to the caller's buffer.
51632529Sbostic 		 */
51732529Sbostic 
51832529Sbostic 		register vflaw_type *vflaw;
51932529Sbostic 		register struct flaw *vendor;
52032529Sbostic 
52132529Sbostic 		if (!hu->format)
52232529Sbostic 			return(1);
523*32560Sbostic 		vflaw = (vflaw_type *)arg;
52432529Sbostic 		mcb = &hc->mcb;
52532529Sbostic 		mcb->command = HCMD_VENDOR;
52632529Sbostic 		mcb->drive = hu->slave;
52732529Sbostic 		mcb->chain[0].lwc = HDC_VDATA_SIZE;
528*32560Sbostic 		mcb->chain[0].ta  = (u_long)hu->phio_data;
52932529Sbostic 		mcb->cyl = vflaw->cylinder;
53032529Sbostic 		mcb->head = vflaw->head;
53132529Sbostic 		mcb->sector = 0;
53232529Sbostic 		if (hdmcb(mcb, io))
533*32560Sbostic 			return(EIO);
534*32560Sbostic 		vendor = (struct flaw *)&hu->phio_data[0];
535*32560Sbostic 		for (i = 0; i < MAXVFLAW; i++) {
53632529Sbostic 			vflaw->flaw[i].offset = vendor[i].offset;
53732529Sbostic 			vflaw->flaw[i].length = vendor[i].length;
53832529Sbostic 		}
53932529Sbostic 		break;
54032529Sbostic 	}
54132529Sbostic 	}
542*32560Sbostic 	return(0);
54332529Sbostic }
54432529Sbostic 
54532529Sbostic /*************************************************************************
54632529Sbostic *  Procedure:	hdmcb
54732529Sbostic *
548*32560Sbostic *  Description:	Internal routine used to send mcb's to the hdc.
54932529Sbostic *
550*32560Sbostic *  Returns:	0		normal
551*32560Sbostic *		non-zero	error occurred
55232529Sbostic **************************************************************************/
55332529Sbostic hdmcb(mcb, io)
554*32560Sbostic 	register mcb_type	*mcb;	/* mcb to send to the hdc	*/
555*32560Sbostic 	register struct iob	*io;	/* i/o block			*/
55632529Sbostic {
557*32560Sbostic 	master_mcb_type	*master_mcb;	/* the hdc's master mcb		*/
558*32560Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table	*/
559*32560Sbostic 	hdc_regs_type	*ctlr_addr;	/* pointer to hdc i/o registers	*/
560*32560Sbostic 	int		timeout;	/* used to timeout the mcb	*/
561*32560Sbostic 	int		bus;		/* bus number			*/
562*32560Sbostic 	int		ctlr;		/* the controller number	*/
563*32560Sbostic 	int		i, end;
564*32560Sbostic 	u_int		*ptr;
56532529Sbostic 
566*32560Sbostic 	bus = 0;			/* io->i_bus;	*/
567*32560Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr;	*/
56832529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
56932529Sbostic 
57032529Sbostic 	mcb->interrupt = FALSE;
57132529Sbostic 	mcb->priority = 0;
57232529Sbostic 	mcb->forw_phaddr = 0;
57332529Sbostic 	mcb->context = 0;
57432529Sbostic 	mcb->reserved[0] = 0;
57532529Sbostic 	mcb->reserved[1] = 0;
57632529Sbostic 	master_mcb = &hc->master_mcb;
577*32560Sbostic 	master_mcb->forw_phaddr = (long)&mcb->forw_phaddr;
57832529Sbostic 	master_mcb->mcs = 0;
57932529Sbostic 	master_mcb->interrupt = 0;
580*32560Sbostic 	master_mcb->reserve1 = 0;
581*32560Sbostic 	master_mcb->reserve2 = 0;
582*32560Sbostic 	master_mcb->context = 0;
58332529Sbostic 	master_mcb->mcl = MCL_IMMEDIATE;
584*32560Sbostic 	for (i = 0; i < HDC_XSTAT_SIZE; i++)
585*32560Sbostic 		master_mcb->xstatus[i] = 0;
586*32560Sbostic 	ctlr_addr = hc->registers;
587*32560Sbostic 	HDREG(master_mcb_reg) = (u_long)master_mcb;
58832529Sbostic 	timeout = 15000;
589*32560Sbostic 	for (;;) {
59032529Sbostic 		DELAY(1000);
59132557Sbostic 		mtpr(PADC, 0);
592*32560Sbostic 		if (master_mcb->mcs & MCS_DONE &&
593*32560Sbostic 		    !(master_mcb->mcs & MCS_FATALERROR))
594*32560Sbostic 			return(0);
59532529Sbostic 		timeout--;
596*32560Sbostic 		if (timeout > 0   && !(master_mcb->mcs & MCS_FATALERROR))
597*32560Sbostic 			continue;
598*32560Sbostic 		if (master_mcb->mcs & MCS_FATALERROR)
59932529Sbostic 			printf("hdc: controller fatal error\n");
60032529Sbostic 		else
60132529Sbostic 			printf("hdc: controller timed out\n");
60232529Sbostic 
60332529Sbostic 		printf("mmcb: ");
604*32560Sbostic 		ptr = (u_int *)master_mcb;
605*32560Sbostic 		for (i = 0; i < 8; i++)
606*32560Sbostic 			printf(" %x", ptr[i]);
607*32560Sbostic 		for (i = 7 + HDC_XSTAT_SIZE; i > 7; i--) {
60832529Sbostic 			end = i;
609*32560Sbostic 			if (ptr[i] != 0)
610*32560Sbostic 				break;
61132529Sbostic 		}
612*32560Sbostic 		for (i = 8; i <= end; i++)
613*32560Sbostic 			printf(" %x", ptr[i]);
61432529Sbostic 		printf("\n");
61532529Sbostic 
61632529Sbostic 		printf("mcb:  ");
617*32560Sbostic 		ptr = (u_int *)&mcb->forw_phaddr;
618*32560Sbostic 		for (i = 0; i < 6; i++)
619*32560Sbostic 			printf(" %x", ptr[i]);
620*32560Sbostic 		for (i = 6; i < 72; i += 2) {
62132529Sbostic 			printf("  %x %x", ptr[i], ptr[i+1]);
622*32560Sbostic 			if (!(ptr[i] & 0x80000000))
623*32560Sbostic 				break;
62432529Sbostic 		}
62532529Sbostic 		printf("\n");
62632529Sbostic 		return(1);
62732529Sbostic 	}
62832529Sbostic }
629