xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 32557)
132529Sbostic /*
232529Sbostic  * Stand alone driver for the HDC controller
3*32557Sbostic  *
4*32557Sbostic  *	@(#)hd.c	7.2 (Berkeley) 10/27/87
532529Sbostic  */
6*32557Sbostic #define	KERNEL
732529Sbostic 
8*32557Sbostic #include "machine/mtpr.h"
9*32557Sbostic #include "param.h"
10*32557Sbostic #include "systm.h"
11*32557Sbostic #include "buf.h"
12*32557Sbostic #include "time.h"
13*32557Sbostic #include "inode.h"
14*32557Sbostic #include "fs.h"
15*32557Sbostic #include "ioctl.h"
16*32557Sbostic #include "tahoevba/dsk.h"
17*32557Sbostic #include "tahoevba/dskio.h"
18*32557Sbostic #include "tahoevba/hdc.h"
19*32557Sbostic #include "saio.h"
2032529Sbostic 
21*32557Sbostic #define	NHD		4
22*32557Sbostic #define	NDRIVE		8		/* drives per controller */
23*32557Sbostic #define	HDSLAVE(x)	((x) % NDRIVE)
24*32557Sbostic #define	HDCTLR(x)	((x) / NDRIVE)
2532529Sbostic 
26*32557Sbostic #define	HDREG(x)	(ctlr_addr->x)	/* standalone io to an hdc register */
27*32557Sbostic #define	HID_HDC		0x01		/* hvme_id for HDC */
2832529Sbostic 
2932529Sbostic /*
3032529Sbostic  * hdc controller table. It contains information about the hdc controller.
3132529Sbostic  */
3232529Sbostic 
3332529Sbostic typedef struct {
3432529Sbostic 	int		ctlr;		/* controller number (0-15)         */
3532529Sbostic 	hdc_regs_type	*registers;	/* base address of hdc io registers */
3632529Sbostic 	hdc_mid_type	mid;		/* the module id is read to here    */
3732529Sbostic 	master_mcb_type master_mcb;	/* the master mcb for this hdc      */
3832529Sbostic 	mcb_type	mcb;		/* an mcb for i/o to the controller */
3932529Sbostic } hdctlr_type;
4032529Sbostic 
4132529Sbostic hdctlr_type hdc_ctlr[HDC_MAXCTLR][HDC_MAXBUS];
4232529Sbostic 
4332529Sbostic /*
4432529Sbostic  * hdc unit table. It contains information about the hdc drive.
4532529Sbostic  * Some information is obtained from the profile prom and geometry block.
4632529Sbostic  */
4732529Sbostic 
4832529Sbostic typedef struct {
4932529Sbostic 	par_tab		partition[GB_MAXPART]; /* partition definitions     */
5032529Sbostic 	int		ctlr;		/* the controller number (0-15)     */
5132529Sbostic 	int		slave;		/* the slave number (0-4)           */
5232529Sbostic 	int		unit;		/* the unit number (0-31)           */
5332529Sbostic 	int		id;		/* identifies the disk model        */
5432529Sbostic  	int		cylinders;	/* number of logical cylinders      */
5532529Sbostic 	int		heads;		/* number of logical heads          */
5632529Sbostic 	int		sectors;	/* number of logical sectors/track  */
5732529Sbostic 	int		phys_cylinders;	/* number of physical cylinders     */
5832529Sbostic 	int		phys_heads;	/* number of physical heads         */
5932529Sbostic 	int		phys_sectors;	/* number of physical sectors/track */
6032529Sbostic 	int		def_cyl;	/* logical cylinder of drive def    */
6132529Sbostic 	int		def_cyl_count;	/* number of logical def cylinders  */
6232529Sbostic 	int		diag_cyl;	/* logical cylinder of diag area    */
6332529Sbostic 	int		diag_cyl_count;	/* number of logical diag cylinders */
6432529Sbostic 	int		rpm;		/* disk rpm                         */
6532529Sbostic 	int		bytes_per_sec;	/* bytes/sector -vendorflaw conversn*/
6632529Sbostic 	int		format;		/* format program is active         */
6732529Sbostic 	unsigned long	phio_data[HDC_PHIO_SIZE]; /* data for physical io   */
6832529Sbostic } hdunit_type;
6932529Sbostic 
7032529Sbostic hdunit_type hdc_unit [HDC_MAXDRIVE] [HDC_MAXCTLR] [HDC_MAXBUS] ;
7132529Sbostic 
7232529Sbostic /*************************************************************************
7332529Sbostic *  Procedure:	hdopen
7432529Sbostic *
7532529Sbostic *  Description: The hdc open routine. Initializes the hdc and reads the
7632529Sbostic *               hdc status and the geometry block.
7732529Sbostic *
7832529Sbostic *  Returns:     0   open was not successful
7932529Sbostic *               1   open was successful
8032529Sbostic *               -1  this is not an hdc controller
8132529Sbostic **************************************************************************/
8232529Sbostic 
8332529Sbostic hdopen(io)
8432529Sbostic 
8532529Sbostic register struct iob	*io ;	/* i/o block
8632529Sbostic 				 */
8732529Sbostic {
8832529Sbostic 	mcb_type	*mcb;		/* an mcb to send commands to hdc   */
8932529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
9032529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
9132529Sbostic 	hdc_mid_type	*id;		/* the hdc module id                */
9232529Sbostic 	geometry_sector geometry;	/* the geometry block sector        */
9332529Sbostic 	geometry_block	*geo;		/* the geometry block               */
9432529Sbostic 	drive_stat_type	status;		/* the hdc status is read to here   */
9532529Sbostic 	int		par;		/* partition number                 */
9632529Sbostic 	int	        ctlr;		/* the controller number            */
9732529Sbostic 	int	        drive;		/* the drive number                 */
9832529Sbostic 	int	        bus;		/* the bus number                   */
9932529Sbostic 	int		unit;		/* the unit number		    */
10032529Sbostic 	int	        i;		/* temp                             */
101*32557Sbostic 	long		junk;		/* badaddr will write junk here     */
10232529Sbostic 	hdc_regs_type	*ctlr_addr;	/* hdc i/o registers                */
10332529Sbostic 
104*32557Sbostic 	par = io->i_boff;		/* io->i_part; */
105*32557Sbostic 	bus = 0;			/* io->i_bus; */
106*32557Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr; */
107*32557Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive; */
10832529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
10932529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
11032529Sbostic 	mcb = &hc->mcb;
11132529Sbostic 
11232529Sbostic 	/*
11332529Sbostic 	 * Validate the device specification
11432529Sbostic 	 */
11532529Sbostic 
116*32557Sbostic 	if (ctlr >= HDC_MAXCTLR) {
117*32557Sbostic 		printf("invalid controller number\n");
118*32557Sbostic 		return (ENXIO);
119*32557Sbostic 	}
12032529Sbostic 	if (drive < 0 || drive > (HDC_MAXDRIVE-1)) {
12132529Sbostic 		printf("hdc: bad drive number.\n");
122*32557Sbostic 		return( 1 );
12332529Sbostic 	}
12432529Sbostic 	if (par < 0 || par > 7) {
12532529Sbostic 		printf("hdc: bad partition number.\n");
126*32557Sbostic 		return( 1 );
12732529Sbostic 	}
128*32557Sbostic 	ctlr_addr = (hdc_regs_type *)(bus == 0 ?
12932529Sbostic 		0xC0000000 | ctlr << 24 | HDC_MID << 16  :
130*32557Sbostic 		0x80000000 | ctlr << 24 | HDC_MID << 16);
131*32557Sbostic 	/* ctlr_addr = (hdc_regs_type *) io->i_ctlr_addr; */
13232529Sbostic 
13332529Sbostic 	/*
13432529Sbostic 	 * Init drive structure.
13532529Sbostic 	 */
13632529Sbostic 
13732529Sbostic 	hu->slave = drive;
13832529Sbostic 	hc->registers = ctlr_addr;
13932529Sbostic 
14032529Sbostic 	/*
14132529Sbostic 	 * Insure that this is an hdc, then reset the hdc.
14232529Sbostic 	 */
143*32557Sbostic 	junk = 0;
144*32557Sbostic 	if (wbadaddr(&ctlr_addr->module_id_reg, 4, &junk)) {
145*32557Sbostic 		printf("hd%d: %x: invalid csr\n", ctlr, ctlr_addr);
146*32557Sbostic 		return (ENXIO);
147*32557Sbostic 	}
14832529Sbostic 	HDREG(soft_reset_reg) = 0;
14932529Sbostic 	DELAY(1000000);
15032529Sbostic 
15132529Sbostic 	/*
15232529Sbostic 	 * Read in the hdc module id word.
15332529Sbostic 	 * The controller is bad if the hdc's writeable control
15432529Sbostic 	 * store is not loaded or if the hdc failed the
15532529Sbostic 	 * functional integrity test for any reason.
15632529Sbostic 	 */
15732529Sbostic 
15832529Sbostic 	id = &hc->mid;
15932529Sbostic 	HDREG(module_id_reg) = (unsigned long) id;
16032529Sbostic 	DELAY(10000);
161*32557Sbostic 	mtpr(PADC, 0);
16232529Sbostic 	if (id->module_id != (unsigned char) HDC_MID) {
16332529Sbostic 		printf("hdc: Controller bad module id: id= %x\n",id->module_id);
16432529Sbostic 		return( -1 );
16532529Sbostic 	}
16632529Sbostic 	if (id->code_rev == (unsigned char) 0xFF ) {
16732529Sbostic 		printf("hdc:  Controller micro-code is not loaded.\n");
168*32557Sbostic 		return( 1 );
16932529Sbostic 	}
17032529Sbostic 	if (id->fit != (unsigned char) 0xFF ) {
17132529Sbostic 		printf("hdc:  Controller FIT test failed: error= %x\n",id->fit);
172*32557Sbostic 		return( 1 );
17332529Sbostic 	}
17432529Sbostic 
17532529Sbostic 	/*
17632529Sbostic 	 * Read the drive status. Save important info.
17732529Sbostic 	 */
17832529Sbostic 
17932529Sbostic 	mcb->command = HCMD_STATUS;
18032529Sbostic 	mcb->drive = drive;
18132529Sbostic 	mcb->cyl = 0;
18232529Sbostic 	mcb->head = 0;
18332529Sbostic 	mcb->sector = 0;
18432529Sbostic 	mcb->chain[0].lwc = (long) sizeof(drive_stat_type) / 4;
18532529Sbostic 	mcb->chain[0].ta  = (long) &status;
18632529Sbostic 	if (hdmcb(mcb, io))
187*32557Sbostic 		return( 1 );
18832529Sbostic 	hu->cylinders = status.max_cyl+1;
18932529Sbostic 	hu->heads = status.max_head+1;
19032529Sbostic 	hu->sectors = status.max_sector+1;
19132529Sbostic 	hu->def_cyl = status.def_cyl;
19232529Sbostic 	hu->def_cyl_count = status.def_cyl_count;
19332529Sbostic 	hu->diag_cyl = status.diag_cyl;
19432529Sbostic 	hu->diag_cyl_count = status.diag_cyl_count;
19532529Sbostic 	hu->phys_cylinders = status.max_phys_cyl+1;
19632529Sbostic 	hu->phys_heads = status.max_phys_head+1;
19732529Sbostic 	hu->phys_sectors = status.max_phys_sector+1;
19832529Sbostic 	hu->bytes_per_sec = status.bytes_per_sec;
19932529Sbostic 	hu->id = status.id;
20032529Sbostic 	hu->rpm = status.rpm;
20132529Sbostic 	hu->partition[HDC_DEFPART].start=
20232529Sbostic 		hu->def_cyl * hu->sectors * hu->heads / HDC_SPB;
20332529Sbostic 	hu->partition[HDC_DEFPART].length =
20432529Sbostic 		hu->def_cyl_count * hu->sectors * hu->heads / HDC_SPB;
20532529Sbostic 	io->i_boff = hu->partition[HDC_DEFPART].start; /* default */
20632529Sbostic 
20732529Sbostic 	/*
20832529Sbostic 	 * Report drive down if anything in the drive status is bad.
20932529Sbostic 	 * If fault condition, reading geo will try to clear the fault.
21032529Sbostic 	 */
21132529Sbostic 
21232529Sbostic 	if (status.drs & DRS_FAULT)
21332529Sbostic 		printf("hdc: clearing drive fault.\n");
21432529Sbostic 	if ( !(status.drs & DRS_ONLINE)) {
21532529Sbostic 		printf("hdc: drive is not online.\n");
216*32557Sbostic 		return( 1 );
21732529Sbostic 	}
21832529Sbostic 
21932529Sbostic 	/*
22032529Sbostic 	 * Read the geometry block (at head=0 sector=0 of the drive
22132529Sbostic 	 * definition cylinder), validate it (must have the correct
22232529Sbostic 	 * version number, header, and checksum).
22332529Sbostic 	 */
22432529Sbostic 
22532529Sbostic 	geo = &geometry.geometry_block;
22632529Sbostic 	mcb->command = HCMD_READ;
22732529Sbostic 	mcb->drive = drive;
22832529Sbostic 	mcb->cyl = status.def_cyl;
22932529Sbostic 	mcb->head = 0;
23032529Sbostic 	mcb->sector = 0;
23132529Sbostic 	mcb->chain[0].lwc = sizeof(geometry_sector) / 4;
23232529Sbostic 	mcb->chain[0].ta  = (long) &geometry;
23332529Sbostic 	if (hdmcb(mcb, io)) {
23432529Sbostic  		printf("hdc: could not read geometry block\n");
23532529Sbostic 		return( 1 );
23632529Sbostic 	}
23732529Sbostic 	io->i_boff = 0;
23832529Sbostic  	if ( geo->version > 64000  ||  geo->version < 0 ) {
23932529Sbostic  		printf("hdc: bad geometry block version#\n");
24032529Sbostic 		return( 1 );
24132529Sbostic 	}
24232529Sbostic  	if (strcmp(&geo->id[0],GB_ID) != 0) {
24332529Sbostic  		printf("hdc: bad geometry block header\n");
24432529Sbostic 		return( 1 );
24532529Sbostic 	}
24632529Sbostic 	GB_CHECKSUM( geo, i );
24732529Sbostic 	if (geometry.checksum != i) {
24832529Sbostic 		printf("hdc: bad geometry block checksum\n");
24932529Sbostic 		return( 1 );
25032529Sbostic 	}
25132529Sbostic 
25232529Sbostic 	/*
25332529Sbostic 	 * Set the partition start/size info.
25432529Sbostic 	 * Note: this info was already defaulted to be the disk
25532529Sbostic 	 * definition partition.
25632529Sbostic 	 */
25732529Sbostic 
25832529Sbostic 	if (par != HDC_DEFPART) {
259*32557Sbostic 		if (geo->partition[par].length == 0) {
26032529Sbostic 			printf("hdc:  null partition\n");
261*32557Sbostic 			return ( 1 );
262*32557Sbostic 		}
26332529Sbostic 		else {
26432529Sbostic 			hu->partition[par].start  = geo->partition[par].start;
26532529Sbostic 			hu->partition[par].length = geo->partition[par].length;
26632529Sbostic 			io->i_boff = hu->partition[par].start;
26732529Sbostic 		}
26832529Sbostic 	}
269*32557Sbostic 	return( 0 ) ;
27032529Sbostic }
27132529Sbostic 
27232529Sbostic /*************************************************************************
27332529Sbostic *  Procedure:	hdstrategy
27432529Sbostic *
27532529Sbostic *  Description: The hdc strategy routine. This routine does the disk
27632529Sbostic *               reads/writes. If this is the format program, read/writes
27732529Sbostic *               are forced to be within the disk definition partition.
27832529Sbostic *
27932529Sbostic *  Returns:     The number of bytes transfered.
28032529Sbostic **************************************************************************/
28132529Sbostic 
28232529Sbostic hdstrategy(io,func)
28332529Sbostic 
28432529Sbostic register struct iob	*io ;	/* i/o block
28532529Sbostic 				 */
28632529Sbostic long			func ;	/* i/o operation to perform
28732529Sbostic 				 */
28832529Sbostic {
28932529Sbostic 	mcb_type	*mcb;		/* mcb to send to the hdc           */
29032529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
29132529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
29232529Sbostic 	long		err;		/* error code                       */
29332529Sbostic 	long		sector;		/* sector number for i/o            */
29432529Sbostic 	int		partstart;      /* block number of partition start  */
29532529Sbostic 	int		partlen;        /* number of blocks in partition    */
29632529Sbostic 	int		bytes;          /* number of bytes to transfer      */
29732529Sbostic 	int		bus;		/* bus number	                    */
29832529Sbostic 	int	        ctlr;		/* the controller number            */
29932529Sbostic 	int	        drive;		/* the drive number                 */
30032529Sbostic 
301*32557Sbostic 	bus = 0;			/* io->i_bus; */
302*32557Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr; */
303*32557Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive; */
30432529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
30532529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
30632529Sbostic 
30732529Sbostic 	/*
30832529Sbostic 	 * Only the format program can access the disk definition tracks.
30932529Sbostic 	 */
31032529Sbostic 
311*32557Sbostic 	if (io->i_boff == HDC_DEFPART)
31232529Sbostic 		if (!hu->format) {
31332529Sbostic 			printf("hdc: partition 7 is protected\n");
31432529Sbostic 			return 0;
31532529Sbostic 		};
31632529Sbostic 
31732529Sbostic 	/*
31832529Sbostic 	 * Insure the transfer fits in the partition.
31932529Sbostic 	 * Set and validate transfer size.
32032529Sbostic 	 */
32132529Sbostic 
322*32557Sbostic 	partstart = hu->partition[io->i_boff].start ;
323*32557Sbostic 	partlen = hu->partition[io->i_boff].length ;
32432529Sbostic 	if ( (io->i_bn < partstart) || (io->i_bn >= partstart+partlen) )
32532529Sbostic 		return( 0 ) ;
326*32557Sbostic 	bytes = MIN( io->i_cc, DEV_BSIZE*(partstart+partlen-io->i_bn) );
32732529Sbostic 	if (io->i_cc & 3) {
32832529Sbostic 		printf("hdc:  i/o not a longword multiple\n");
32932529Sbostic 		return 0;
33032529Sbostic 	}
33132529Sbostic 
33232529Sbostic 	/*
33332529Sbostic 	 * Set up the mcb and send it to the hdc.
33432529Sbostic 	 */
33532529Sbostic 
33632529Sbostic 	mcb = &hc->mcb;
33732529Sbostic 	sector = io->i_bn * HDC_SPB;
33832529Sbostic 	mcb->command = (func == READ) ? HCMD_READ : HCMD_WRITE;
33932529Sbostic 	mcb->drive = hu->slave;
34032529Sbostic 	mcb->cyl = sector / (hu->sectors * hu->heads);
34132529Sbostic 	mcb->head = (sector/hu->sectors) % hu->heads;
34232529Sbostic 	mcb->sector = sector % hu->sectors;
34332529Sbostic 	mcb->chain[0].ta  = (unsigned long) io->i_ma;
34432529Sbostic 	mcb->chain[0].lwc = (bytes + 3) / 4;
34532529Sbostic 	err = hdmcb(mcb, io);
34632529Sbostic 	io->i_error = err;
34732529Sbostic 	return (err ? 0 : bytes );
34832529Sbostic }
34932529Sbostic 
35032529Sbostic /*************************************************************************
35132529Sbostic *  Procedure:	hdioctl
35232529Sbostic *
35332529Sbostic *  Description: ioctl routine.
35432529Sbostic *
35532529Sbostic *  Returns:     0       no errors
35632529Sbostic *               non-0    error
35732529Sbostic **************************************************************************/
35832529Sbostic 
35932529Sbostic int
36032529Sbostic hdioctl(io, command, arg)
36132529Sbostic 
36232529Sbostic struct iob	*io ; 		/* i/o block.
36332529Sbostic 				 */
36432529Sbostic int		command ;	/* The ioctl commmand.
36532529Sbostic 				 */
36632529Sbostic int		arg ; 		/* Data. Format depends on ioctl.
36732529Sbostic 				 */
36832529Sbostic {
36932529Sbostic 	mcb_type	*mcb;
37032529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
37132529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
37232529Sbostic 	register int	i;
37332529Sbostic 	int		bus;		/* bus number	                    */
37432529Sbostic 	int	        ctlr;		/* the controller number            */
37532529Sbostic 	int	        drive;		/* the drive number                 */
37632529Sbostic 
377*32557Sbostic 	bus = 0;			/* io->i_bus; */
378*32557Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr; */
379*32557Sbostic 	drive = HDSLAVE(io->i_unit);	/* io->i_drive; */
38032529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
38132529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
38232529Sbostic 
38332529Sbostic 	switch (command) {
38432529Sbostic 
38532529Sbostic 	case DSKIOCFORMAT: {
38632529Sbostic 
38732529Sbostic 		/*
38832529Sbostic 		 * Format a disk track. The received argument is a pointer
38932529Sbostic 		 * to a "formatop" structure describing the track to format.
39032529Sbostic 		 *
39132529Sbostic 		 * Set up a buffer with each longword corresponding to a
39232529Sbostic 		 * sector on the track; a 1 means no flaw, a 0 means a flaw.
39332529Sbostic 		 * Send an mcb to the hdc to format the track.
39432529Sbostic 		 */
39532529Sbostic 
39632529Sbostic 		register struct formatop *track;
39732529Sbostic 
39832529Sbostic 		if (!hu->format)
39932529Sbostic 			return(1);
40032529Sbostic 		track = (struct formatop *) arg;
40132529Sbostic 		mcb = &hc->mcb;
40232529Sbostic 		for (i=0; i<hu->phys_sectors; i++)
40332529Sbostic 			hu->phio_data[i] = 1;
40432529Sbostic 		for (i=0; i<track->flaw_count; i++)
40532529Sbostic 			hu->phio_data[track->flaw[i]]=0;
40632529Sbostic 		mcb->command = HCMD_FORMAT;
40732529Sbostic 		mcb->drive = hu->slave;
40832529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
40932529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
41032529Sbostic 		mcb->cyl = track->cylinder;
41132529Sbostic 		mcb->head = track->head;
41232529Sbostic 		mcb->sector = 0;
41332529Sbostic 		if (hdmcb(mcb, io))
41432529Sbostic 			return EIO;
41532529Sbostic 		break;
41632529Sbostic 	}
41732529Sbostic 
41832529Sbostic 	case DSKIOCCERTIFY: {
41932529Sbostic 
42032529Sbostic 		/*
42132529Sbostic 		 * Certify a disk track. The received argument is a pointer
42232529Sbostic 		 * to a "formatop" structure describing the track to certify.
42332529Sbostic 		 *
42432529Sbostic 		 * Send an mcb to the hdc to certify the track.
42532529Sbostic 		 * The controller returns data in which each longword
42632529Sbostic 		 * corresponds to a sector on the track; a 1 means no flaw,
42732529Sbostic 		 * a 0 means a flaw.
42832529Sbostic 		 */
42932529Sbostic 
43032529Sbostic 		register struct formatop *track;
43132529Sbostic 
43232529Sbostic 		if (!hu->format)
43332529Sbostic 			return 1;
43432529Sbostic 		track = (struct formatop *) arg;
43532529Sbostic 		mcb = &hc->mcb;
43632529Sbostic 		mcb->command = HCMD_CERTIFY;
43732529Sbostic 		mcb->drive = hu->slave;
43832529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
43932529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
44032529Sbostic 		mcb->cyl = track->cylinder;
44132529Sbostic 		mcb->head = track->head;
44232529Sbostic 		mcb->sector = 0;
44332529Sbostic 		if (hdmcb(mcb, io))
44432529Sbostic 			return EIO;
44532529Sbostic 		track->flaw_count = 0;
44632529Sbostic 		for (i=0; i<hu->phys_sectors; i++) {
44732529Sbostic 			if (track->flaw_count >= MAXVFLAW) break;
44832529Sbostic 			if (hu->phio_data[i]==0) {
44932529Sbostic 				track->flaw[track->flaw_count] = i;
45032529Sbostic 				track->flaw_count++;
45132529Sbostic 			}
45232529Sbostic 		}
45332529Sbostic 		break;
45432529Sbostic 	}
45532529Sbostic 
45632529Sbostic 	case DSKIOCVERIFY: {
45732529Sbostic 
45832529Sbostic 		/*
45932529Sbostic 		 * Verify a disk track. The received argument is a pointer
46032529Sbostic 		 * to a "formatop" structure describing the track to verify.
46132529Sbostic 		 */
46232529Sbostic 
46332529Sbostic 		register struct formatop *track;
46432529Sbostic 
46532529Sbostic 		if (!hu->format)
46632529Sbostic 			return(1);
46732529Sbostic 		track = (struct formatop *) arg;
46832529Sbostic 		mcb = &hc->mcb;
46932529Sbostic 		mcb->command = HCMD_VERIFY;
47032529Sbostic 		mcb->drive = hu->slave;
47132529Sbostic 		mcb->chain[0].ta  = 0;
47232529Sbostic 		mcb->chain[0].lwc = 0;
47332529Sbostic 		mcb->cyl = track->cylinder;
47432529Sbostic 		mcb->head = track->head;
47532529Sbostic 		mcb->sector = 0;
47632529Sbostic 		if (hdmcb(mcb, io))
47732529Sbostic 			return EIO;
47832529Sbostic 		break;
47932529Sbostic 	}
48032529Sbostic 
48132529Sbostic 	case DSKIOCFORMATCTL: {
48232529Sbostic 
48332529Sbostic 		/*
48432529Sbostic 		 * This ioctl provides special format control.
48532529Sbostic 		 * Currently the valid arguments are:
48632529Sbostic 		 *
48732529Sbostic 		 * arg= 0  disable formatting;
48832529Sbostic 		 *
48932529Sbostic 		 * arg= 1  enable formatting (allow privileged access);
49032529Sbostic 		 *         formatting must not already be enabled;
49132529Sbostic 		 *         For formatting, change to use partition 7.
49232529Sbostic 		 */
49332529Sbostic 
49432529Sbostic 		if (arg<0 || arg>1)
49532529Sbostic 			return (1);
49632529Sbostic 		if (arg==1) {
49732529Sbostic 			if (hu->format) return (1);
49832529Sbostic 			/* If not already formatting.... */
49932529Sbostic 			hu->format = 1 ;
500*32557Sbostic 			/* io->i_part = HDC_DEFPART; */
50132529Sbostic 			io->i_boff = hu->partition[HDC_DEFPART].start;
50232529Sbostic 		}
50332529Sbostic 		else
50432529Sbostic 			hu->format = 0 ;
50532529Sbostic 		break;
50632529Sbostic 	}
50732529Sbostic 
50832529Sbostic 	case DSKIOCSTATUS: {
50932529Sbostic 
51032529Sbostic 		/*
51132529Sbostic 		 * Return info about the disk. Caller's parameter is a
51232529Sbostic 		 * pointer to a dsk_status structure.
51332529Sbostic 		 */
51432529Sbostic 
51532529Sbostic 		register dsk_status *status;
51632529Sbostic 
51732529Sbostic 		status = (dsk_status *) arg;
51832529Sbostic 		status->id =		hu->id;
51932529Sbostic 		status->drive_status =	0;
52032529Sbostic 		status->rpm =		hu->rpm;
52132529Sbostic 		status->bytes_per_sec = hu->bytes_per_sec;
52232529Sbostic 		status->cylinders =	hu->cylinders;
52332529Sbostic 		status->heads =		hu->heads;
52432529Sbostic 		status->sectors =	hu->sectors;
52532529Sbostic 		status->phys_cylinders= hu->phys_cylinders;
52632529Sbostic 		status->phys_heads =	hu->phys_heads;
52732529Sbostic 		status->phys_sectors =	hu->phys_sectors;
52832529Sbostic 		status->diag_cyl =	hu->diag_cyl;
52932529Sbostic 		status->diag_cylinders= hu->diag_cyl_count;
53032529Sbostic 		status->def_cyl =	hu->def_cyl;
53132529Sbostic 		status->def_cylinders =	hu->def_cyl_count;
53232529Sbostic 		break;
53332529Sbostic 	}
53432529Sbostic 
53532529Sbostic 	case DSKIOCVENDORFLAW: {
53632529Sbostic 
53732529Sbostic 		/*
53832529Sbostic 		 * Return vendor flaw info.
53932529Sbostic 		 *
54032529Sbostic 		 * Read in the vendor data (data for each track is at
54132529Sbostic 		 * relative sector 0 of the track); then copy the
54232529Sbostic 		 * vendor flaw data to the caller's buffer.
54332529Sbostic 		 */
54432529Sbostic 
54532529Sbostic 		register vflaw_type *vflaw;
54632529Sbostic 		register struct flaw *vendor;
54732529Sbostic 
54832529Sbostic 		if (!hu->format)
54932529Sbostic 			return(1);
55032529Sbostic 		vflaw = (vflaw_type *) arg;
55132529Sbostic 		mcb = &hc->mcb;
55232529Sbostic 		mcb->command = HCMD_VENDOR;
55332529Sbostic 		mcb->drive = hu->slave;
55432529Sbostic 		mcb->chain[0].lwc = HDC_VDATA_SIZE;
55532529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
55632529Sbostic 		mcb->cyl = vflaw->cylinder;
55732529Sbostic 		mcb->head = vflaw->head;
55832529Sbostic 		mcb->sector = 0;
55932529Sbostic 		if (hdmcb(mcb, io))
56032529Sbostic 			return EIO;
56132529Sbostic 		vendor = (struct flaw *) &hu->phio_data[0];
56232529Sbostic 		for (i=0; i<MAXVFLAW; i++) {
56332529Sbostic 			vflaw->flaw[i].offset = vendor[i].offset;
56432529Sbostic 			vflaw->flaw[i].length = vendor[i].length;
56532529Sbostic 		}
56632529Sbostic 		break;
56732529Sbostic 	}
56832529Sbostic 	}
56932529Sbostic 	return 0;
57032529Sbostic }
57132529Sbostic 
57232529Sbostic /*************************************************************************
57332529Sbostic *  Procedure:	hdmcb
57432529Sbostic *
57532529Sbostic *  Description: Internal routine used to send mcb's to the hdc.
57632529Sbostic *
57732529Sbostic *  Returns:     0          normal
57832529Sbostic *               non-zero   error occurred
57932529Sbostic **************************************************************************/
58032529Sbostic 
58132529Sbostic int
58232529Sbostic hdmcb(mcb, io)
58332529Sbostic 
58432529Sbostic register mcb_type	*mcb ;	/* mcb to send to the hdc		    */
58532529Sbostic register struct iob	*io ;	/* i/o block				    */
58632529Sbostic 
58732529Sbostic {
58832529Sbostic 	master_mcb_type *master_mcb;	/* the hdc's master mcb             */
58932529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
59032529Sbostic 	hdc_regs_type	*ctlr_addr;	/* pointer to hdc i/o registers     */
59132529Sbostic 	int		timeout;	/* used to timeout the mcb          */
59232529Sbostic 	int		bus;		/* bus number	                    */
59332529Sbostic 	int	        ctlr;		/* the controller number            */
59432529Sbostic 	int		i,end;
59532529Sbostic 	unsigned int	*ptr;
59632529Sbostic 
597*32557Sbostic 	bus = 0;			/* io->i_bus; */
598*32557Sbostic 	ctlr = HDCTLR(io->i_unit);	/* io->i_ctlr; */
59932529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
60032529Sbostic 
60132529Sbostic 	mcb->interrupt = FALSE;
60232529Sbostic 	mcb->priority = 0;
60332529Sbostic 	mcb->forw_phaddr = 0;
60432529Sbostic 	mcb->context = 0;
60532529Sbostic 	mcb->reserved[0] = 0;
60632529Sbostic 	mcb->reserved[1] = 0;
60732529Sbostic 	master_mcb = &hc->master_mcb;
60832529Sbostic 	master_mcb->forw_phaddr = (long) &mcb->forw_phaddr;
60932529Sbostic 	master_mcb->mcs = 0;
61032529Sbostic 	master_mcb->interrupt = 0;
61132529Sbostic 	master_mcb->reserve1  = 0;
61232529Sbostic 	master_mcb->reserve2  = 0;
61332529Sbostic 	master_mcb->context   = 0;
61432529Sbostic 	master_mcb->mcl = MCL_IMMEDIATE;
61532529Sbostic 	for (i=0;i<HDC_XSTAT_SIZE;i++) master_mcb->xstatus[i] = 0;
61632529Sbostic         ctlr_addr = hc->registers;
61732529Sbostic 	HDREG(master_mcb_reg) = (unsigned long) master_mcb;
61832529Sbostic 	timeout = 15000;
61932529Sbostic 	while (TRUE) {
62032529Sbostic 		DELAY(1000);
621*32557Sbostic 		mtpr(PADC, 0);
62232529Sbostic 		if ( (master_mcb->mcs & MCS_DONE) &&
62332529Sbostic 			!(master_mcb->mcs & MCS_FATALERROR) ) return 0;
62432529Sbostic 		timeout--;
62532529Sbostic 		if ( timeout > 0   &&
62632529Sbostic 			!(master_mcb->mcs & MCS_FATALERROR) ) continue;
62732529Sbostic 		if ( master_mcb->mcs & MCS_FATALERROR )
62832529Sbostic 			printf("hdc: controller fatal error\n");
62932529Sbostic 		else
63032529Sbostic 			printf("hdc: controller timed out\n");
63132529Sbostic 
63232529Sbostic 		printf("mmcb: ");
63332529Sbostic 		ptr = (unsigned int *) master_mcb;
63432529Sbostic 		for (i=0;i<8;i++)
63532529Sbostic 			printf(" %x",ptr[i]);
63632529Sbostic 		for (i=7+HDC_XSTAT_SIZE; i>7; i--) {
63732529Sbostic 			end = i;
63832529Sbostic 			if (ptr[i] != 0) break;
63932529Sbostic 		}
64032529Sbostic 		for (i=8;i<=end;i++)
64132529Sbostic 			printf(" %x",ptr[i]);
64232529Sbostic 		printf("\n");
64332529Sbostic 
64432529Sbostic 		printf("mcb:  ");
64532529Sbostic 		ptr = (unsigned int *) &mcb->forw_phaddr;
64632529Sbostic 		for (i=0; i<6; i++)
64732529Sbostic 			printf(" %x",ptr[i]);
64832529Sbostic 		for (i=6; i<72; i+=2) {
64932529Sbostic 			printf("  %x %x", ptr[i], ptr[i+1]);
65032529Sbostic 			if ( !(ptr[i] & 0x80000000)) break;
65132529Sbostic 		}
65232529Sbostic 		printf("\n");
65332529Sbostic 		return(1);
65432529Sbostic 	}
65532529Sbostic }
656