xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 32529)
1*32529Sbostic /*
2*32529Sbostic  * Stand alone driver for the HDC controller
3*32529Sbostic  */
4*32529Sbostic 
5*32529Sbostic #define KERNEL
6*32529Sbostic 
7*32529Sbostic #include "../uts/machine/ml/mtpr.h"
8*32529Sbostic #include "../uts/machine/sys/param.h"
9*32529Sbostic #include "../uts/machine/sys/systm.h"
10*32529Sbostic #include "../uts/machine/sys/buf.h"
11*32529Sbostic #include "../uts/machine/sys/time.h"
12*32529Sbostic #include "../uts/machine/sys/vnode.h"
13*32529Sbostic #include "../uts/machine/ufs/inode.h"
14*32529Sbostic #include "../uts/machine/ufs/fs.h"
15*32529Sbostic #include "../uts/machine/sys/vbavar.h"
16*32529Sbostic #include "../uts/machine/sys/ioctl.h"
17*32529Sbostic #include "../uts/machine/sys/dsk.h"
18*32529Sbostic #include "../uts/machine/sys/dskio.h"
19*32529Sbostic #include "../uts/machine/sys/hdc.h"
20*32529Sbostic #include "../stand/saio.h"
21*32529Sbostic 
22*32529Sbostic #define HDREG(x)	(ctlr_addr->x)	/* standalone io to an hdc register */
23*32529Sbostic 
24*32529Sbostic /*
25*32529Sbostic  * hdc controller table. It contains information about the hdc controller.
26*32529Sbostic  */
27*32529Sbostic 
28*32529Sbostic typedef struct {
29*32529Sbostic 	int		ctlr;		/* controller number (0-15)         */
30*32529Sbostic 	hdc_regs_type	*registers;	/* base address of hdc io registers */
31*32529Sbostic 	hdc_mid_type	mid;		/* the module id is read to here    */
32*32529Sbostic 	master_mcb_type master_mcb;	/* the master mcb for this hdc      */
33*32529Sbostic 	mcb_type	mcb;		/* an mcb for i/o to the controller */
34*32529Sbostic } hdctlr_type;
35*32529Sbostic 
36*32529Sbostic hdctlr_type hdc_ctlr[HDC_MAXCTLR][HDC_MAXBUS];
37*32529Sbostic 
38*32529Sbostic /*
39*32529Sbostic  * hdc unit table. It contains information about the hdc drive.
40*32529Sbostic  * Some information is obtained from the profile prom and geometry block.
41*32529Sbostic  */
42*32529Sbostic 
43*32529Sbostic typedef struct {
44*32529Sbostic 	par_tab		partition[GB_MAXPART]; /* partition definitions     */
45*32529Sbostic 	int		ctlr;		/* the controller number (0-15)     */
46*32529Sbostic 	int		slave;		/* the slave number (0-4)           */
47*32529Sbostic 	int		unit;		/* the unit number (0-31)           */
48*32529Sbostic 	int		id;		/* identifies the disk model        */
49*32529Sbostic  	int		cylinders;	/* number of logical cylinders      */
50*32529Sbostic 	int		heads;		/* number of logical heads          */
51*32529Sbostic 	int		sectors;	/* number of logical sectors/track  */
52*32529Sbostic 	int		phys_cylinders;	/* number of physical cylinders     */
53*32529Sbostic 	int		phys_heads;	/* number of physical heads         */
54*32529Sbostic 	int		phys_sectors;	/* number of physical sectors/track */
55*32529Sbostic 	int		def_cyl;	/* logical cylinder of drive def    */
56*32529Sbostic 	int		def_cyl_count;	/* number of logical def cylinders  */
57*32529Sbostic 	int		diag_cyl;	/* logical cylinder of diag area    */
58*32529Sbostic 	int		diag_cyl_count;	/* number of logical diag cylinders */
59*32529Sbostic 	int		rpm;		/* disk rpm                         */
60*32529Sbostic 	int		bytes_per_sec;	/* bytes/sector -vendorflaw conversn*/
61*32529Sbostic 	int		format;		/* format program is active         */
62*32529Sbostic 	unsigned long	phio_data[HDC_PHIO_SIZE]; /* data for physical io   */
63*32529Sbostic } hdunit_type;
64*32529Sbostic 
65*32529Sbostic hdunit_type hdc_unit [HDC_MAXDRIVE] [HDC_MAXCTLR] [HDC_MAXBUS] ;
66*32529Sbostic 
67*32529Sbostic /*************************************************************************
68*32529Sbostic *  Procedure:	hdopen
69*32529Sbostic *
70*32529Sbostic *  Description: The hdc open routine. Initializes the hdc and reads the
71*32529Sbostic *               hdc status and the geometry block.
72*32529Sbostic *
73*32529Sbostic *  Returns:     0   open was not successful
74*32529Sbostic *               1   open was successful
75*32529Sbostic *               -1  this is not an hdc controller
76*32529Sbostic **************************************************************************/
77*32529Sbostic 
78*32529Sbostic hdopen(io)
79*32529Sbostic 
80*32529Sbostic register struct iob	*io ;	/* i/o block
81*32529Sbostic 				 */
82*32529Sbostic {
83*32529Sbostic 	mcb_type	*mcb;		/* an mcb to send commands to hdc   */
84*32529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
85*32529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
86*32529Sbostic 	hdc_mid_type	*id;		/* the hdc module id                */
87*32529Sbostic 	geometry_sector geometry;	/* the geometry block sector        */
88*32529Sbostic 	geometry_block	*geo;		/* the geometry block               */
89*32529Sbostic 	drive_stat_type	status;		/* the hdc status is read to here   */
90*32529Sbostic 	int		par;		/* partition number                 */
91*32529Sbostic 	int	        ctlr;		/* the controller number            */
92*32529Sbostic 	int	        drive;		/* the drive number                 */
93*32529Sbostic 	int	        bus;		/* the bus number                   */
94*32529Sbostic 	int		unit;		/* the unit number		    */
95*32529Sbostic 	int	        i;		/* temp                             */
96*32529Sbostic 	hdc_regs_type	*ctlr_addr;	/* hdc i/o registers                */
97*32529Sbostic 	int		junk;		/* badaddr will write junk here     */
98*32529Sbostic 
99*32529Sbostic 	par = io->i_part;
100*32529Sbostic 	bus = io->i_bus;
101*32529Sbostic 	ctlr = io->i_ctlr;
102*32529Sbostic 	drive = io->i_drive;
103*32529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
104*32529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
105*32529Sbostic 	mcb = &hc->mcb;
106*32529Sbostic 
107*32529Sbostic 	/*
108*32529Sbostic 	 * Validate the device specification
109*32529Sbostic 	 */
110*32529Sbostic 
111*32529Sbostic 	if (ctlr < 1 || ctlr > HDC_MAXCTLR)
112*32529Sbostic 		return( -1 );
113*32529Sbostic 	if (drive < 0 || drive > (HDC_MAXDRIVE-1)) {
114*32529Sbostic 		printf("hdc: bad drive number.\n");
115*32529Sbostic 		return( 0 );
116*32529Sbostic 	}
117*32529Sbostic 	if (par < 0 || par > 7) {
118*32529Sbostic 		printf("hdc: bad partition number.\n");
119*32529Sbostic 		return( 0 );
120*32529Sbostic 	}
121*32529Sbostic 	io->i_ctlr_addr =    bus == 0 ?
122*32529Sbostic 		0xC0000000 | ctlr << 24 | HDC_MID << 16  :
123*32529Sbostic 		0x80000000 | ctlr << 24 | HDC_MID << 16;
124*32529Sbostic 	ctlr_addr = (hdc_regs_type *) io->i_ctlr_addr;
125*32529Sbostic 
126*32529Sbostic 	/*
127*32529Sbostic 	 * Init drive structure.
128*32529Sbostic 	 */
129*32529Sbostic 
130*32529Sbostic 	hu->slave = drive;
131*32529Sbostic 	hc->registers = ctlr_addr;
132*32529Sbostic 
133*32529Sbostic 	/*
134*32529Sbostic 	 * Insure that this is an hdc, then reset the hdc.
135*32529Sbostic 	 */
136*32529Sbostic 
137*32529Sbostic 	if (badaddr(&ctlr_addr->module_id_reg,4,&junk))
138*32529Sbostic   		return( -1 );
139*32529Sbostic 	HDREG(soft_reset_reg) = 0;
140*32529Sbostic 	DELAY(1000000);
141*32529Sbostic 
142*32529Sbostic 	/*
143*32529Sbostic 	 * Read in the hdc module id word.
144*32529Sbostic 	 * The controller is bad if the hdc's writeable control
145*32529Sbostic 	 * store is not loaded or if the hdc failed the
146*32529Sbostic 	 * functional integrity test for any reason.
147*32529Sbostic 	 */
148*32529Sbostic 
149*32529Sbostic 	id = &hc->mid;
150*32529Sbostic 	HDREG(module_id_reg) = (unsigned long) id;
151*32529Sbostic 	DELAY(10000);
152*32529Sbostic 	mtpr(0,PADC);
153*32529Sbostic 	if (id->module_id != (unsigned char) HDC_MID) {
154*32529Sbostic 		printf("hdc: Controller bad module id: id= %x\n",id->module_id);
155*32529Sbostic 		return( -1 );
156*32529Sbostic 	}
157*32529Sbostic 	if (id->code_rev == (unsigned char) 0xFF ) {
158*32529Sbostic 		printf("hdc:  Controller micro-code is not loaded.\n");
159*32529Sbostic 		return( 0 );
160*32529Sbostic 	}
161*32529Sbostic 	if (id->fit != (unsigned char) 0xFF ) {
162*32529Sbostic 		printf("hdc:  Controller FIT test failed: error= %x\n",id->fit);
163*32529Sbostic 		return( 0 );
164*32529Sbostic 	}
165*32529Sbostic 
166*32529Sbostic 	/*
167*32529Sbostic 	 * Read the drive status. Save important info.
168*32529Sbostic 	 */
169*32529Sbostic 
170*32529Sbostic 	mcb->command = HCMD_STATUS;
171*32529Sbostic 	mcb->drive = drive;
172*32529Sbostic 	mcb->cyl = 0;
173*32529Sbostic 	mcb->head = 0;
174*32529Sbostic 	mcb->sector = 0;
175*32529Sbostic 	mcb->chain[0].lwc = (long) sizeof(drive_stat_type) / 4;
176*32529Sbostic 	mcb->chain[0].ta  = (long) &status;
177*32529Sbostic 	if (hdmcb(mcb, io))
178*32529Sbostic 		return( 0 );
179*32529Sbostic 	hu->cylinders = status.max_cyl+1;
180*32529Sbostic 	hu->heads = status.max_head+1;
181*32529Sbostic 	hu->sectors = status.max_sector+1;
182*32529Sbostic 	hu->def_cyl = status.def_cyl;
183*32529Sbostic 	hu->def_cyl_count = status.def_cyl_count;
184*32529Sbostic 	hu->diag_cyl = status.diag_cyl;
185*32529Sbostic 	hu->diag_cyl_count = status.diag_cyl_count;
186*32529Sbostic 	hu->phys_cylinders = status.max_phys_cyl+1;
187*32529Sbostic 	hu->phys_heads = status.max_phys_head+1;
188*32529Sbostic 	hu->phys_sectors = status.max_phys_sector+1;
189*32529Sbostic 	hu->bytes_per_sec = status.bytes_per_sec;
190*32529Sbostic 	hu->id = status.id;
191*32529Sbostic 	hu->rpm = status.rpm;
192*32529Sbostic 	hu->partition[HDC_DEFPART].start=
193*32529Sbostic 		hu->def_cyl * hu->sectors * hu->heads / HDC_SPB;
194*32529Sbostic 	hu->partition[HDC_DEFPART].length =
195*32529Sbostic 		hu->def_cyl_count * hu->sectors * hu->heads / HDC_SPB;
196*32529Sbostic 	io->i_boff = hu->partition[HDC_DEFPART].start; /* default */
197*32529Sbostic 
198*32529Sbostic 	/*
199*32529Sbostic 	 * Report drive down if anything in the drive status is bad.
200*32529Sbostic 	 * If fault condition, reading geo will try to clear the fault.
201*32529Sbostic 	 */
202*32529Sbostic 
203*32529Sbostic 	if (status.drs & DRS_FAULT)
204*32529Sbostic 		printf("hdc: clearing drive fault.\n");
205*32529Sbostic 	if ( !(status.drs & DRS_ONLINE)) {
206*32529Sbostic 		printf("hdc: drive is not online.\n");
207*32529Sbostic 		return( 0 );
208*32529Sbostic 	}
209*32529Sbostic 
210*32529Sbostic 	/*
211*32529Sbostic 	 * Read the geometry block (at head=0 sector=0 of the drive
212*32529Sbostic 	 * definition cylinder), validate it (must have the correct
213*32529Sbostic 	 * version number, header, and checksum).
214*32529Sbostic 	 */
215*32529Sbostic 
216*32529Sbostic 	geo = &geometry.geometry_block;
217*32529Sbostic 	mcb->command = HCMD_READ;
218*32529Sbostic 	mcb->drive = drive;
219*32529Sbostic 	mcb->cyl = status.def_cyl;
220*32529Sbostic 	mcb->head = 0;
221*32529Sbostic 	mcb->sector = 0;
222*32529Sbostic 	mcb->chain[0].lwc = sizeof(geometry_sector) / 4;
223*32529Sbostic 	mcb->chain[0].ta  = (long) &geometry;
224*32529Sbostic 	if (hdmcb(mcb, io)) {
225*32529Sbostic  		printf("hdc: could not read geometry block\n");
226*32529Sbostic 		return( 1 );
227*32529Sbostic 	}
228*32529Sbostic 	io->i_boff = 0;
229*32529Sbostic  	if ( geo->version > 64000  ||  geo->version < 0 ) {
230*32529Sbostic  		printf("hdc: bad geometry block version#\n");
231*32529Sbostic 		return( 1 );
232*32529Sbostic 	}
233*32529Sbostic  	if (strcmp(&geo->id[0],GB_ID) != 0) {
234*32529Sbostic  		printf("hdc: bad geometry block header\n");
235*32529Sbostic 		return( 1 );
236*32529Sbostic 	}
237*32529Sbostic 	GB_CHECKSUM( geo, i );
238*32529Sbostic 	if (geometry.checksum != i) {
239*32529Sbostic 		printf("hdc: bad geometry block checksum\n");
240*32529Sbostic 		return( 1 );
241*32529Sbostic 	}
242*32529Sbostic 
243*32529Sbostic 	/*
244*32529Sbostic 	 * Set the partition start/size info.
245*32529Sbostic 	 * Note: this info was already defaulted to be the disk
246*32529Sbostic 	 * definition partition.
247*32529Sbostic 	 */
248*32529Sbostic 
249*32529Sbostic 	if (par != HDC_DEFPART) {
250*32529Sbostic 		if (geo->partition[par].length == 0)
251*32529Sbostic 			printf("hdc:  null partition\n");
252*32529Sbostic 		else {
253*32529Sbostic 			hu->partition[par].start  = geo->partition[par].start;
254*32529Sbostic 			hu->partition[par].length = geo->partition[par].length;
255*32529Sbostic 			io->i_boff = hu->partition[par].start;
256*32529Sbostic 		}
257*32529Sbostic 	}
258*32529Sbostic 	return( 1 ) ;
259*32529Sbostic }
260*32529Sbostic 
261*32529Sbostic /*************************************************************************
262*32529Sbostic *  Procedure:	hdstrategy
263*32529Sbostic *
264*32529Sbostic *  Description: The hdc strategy routine. This routine does the disk
265*32529Sbostic *               reads/writes. If this is the format program, read/writes
266*32529Sbostic *               are forced to be within the disk definition partition.
267*32529Sbostic *
268*32529Sbostic *  Returns:     The number of bytes transfered.
269*32529Sbostic **************************************************************************/
270*32529Sbostic 
271*32529Sbostic hdstrategy(io,func)
272*32529Sbostic 
273*32529Sbostic register struct iob	*io ;	/* i/o block
274*32529Sbostic 				 */
275*32529Sbostic long			func ;	/* i/o operation to perform
276*32529Sbostic 				 */
277*32529Sbostic {
278*32529Sbostic 	mcb_type	*mcb;		/* mcb to send to the hdc           */
279*32529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
280*32529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
281*32529Sbostic 	long		err;		/* error code                       */
282*32529Sbostic 	long		sector;		/* sector number for i/o            */
283*32529Sbostic 	int		partstart;      /* block number of partition start  */
284*32529Sbostic 	int		partlen;        /* number of blocks in partition    */
285*32529Sbostic 	int		bytes;          /* number of bytes to transfer      */
286*32529Sbostic 	int		bus;		/* bus number	                    */
287*32529Sbostic 	int	        ctlr;		/* the controller number            */
288*32529Sbostic 	int	        drive;		/* the drive number                 */
289*32529Sbostic 
290*32529Sbostic 	bus = io->i_bus;
291*32529Sbostic 	ctlr = io->i_ctlr;
292*32529Sbostic 	drive = io->i_drive;
293*32529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
294*32529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
295*32529Sbostic 
296*32529Sbostic 	/*
297*32529Sbostic 	 * Only the format program can access the disk definition tracks.
298*32529Sbostic 	 */
299*32529Sbostic 
300*32529Sbostic 	if (io->i_part == HDC_DEFPART)
301*32529Sbostic 		if (!hu->format) {
302*32529Sbostic 			printf("hdc: partition 7 is protected\n");
303*32529Sbostic 			return 0;
304*32529Sbostic 		};
305*32529Sbostic 
306*32529Sbostic 	/*
307*32529Sbostic 	 * Insure the transfer fits in the partition.
308*32529Sbostic 	 * Set and validate transfer size.
309*32529Sbostic 	 */
310*32529Sbostic 
311*32529Sbostic 	partstart = hu->partition[io->i_part].start ;
312*32529Sbostic 	partlen = hu->partition[io->i_part].length ;
313*32529Sbostic 	if ( (io->i_bn < partstart) || (io->i_bn >= partstart+partlen) )
314*32529Sbostic 		return( 0 ) ;
315*32529Sbostic 	bytes = min( io->i_cc, DEV_BSIZE*(partstart+partlen-io->i_bn) );
316*32529Sbostic 	if (io->i_cc & 3) {
317*32529Sbostic 		printf("hdc:  i/o not a longword multiple\n");
318*32529Sbostic 		return 0;
319*32529Sbostic 	}
320*32529Sbostic 
321*32529Sbostic 	/*
322*32529Sbostic 	 * Set up the mcb and send it to the hdc.
323*32529Sbostic 	 */
324*32529Sbostic 
325*32529Sbostic 	mcb = &hc->mcb;
326*32529Sbostic 	sector = io->i_bn * HDC_SPB;
327*32529Sbostic 	mcb->command = (func == READ) ? HCMD_READ : HCMD_WRITE;
328*32529Sbostic 	mcb->drive = hu->slave;
329*32529Sbostic 	mcb->cyl = sector / (hu->sectors * hu->heads);
330*32529Sbostic 	mcb->head = (sector/hu->sectors) % hu->heads;
331*32529Sbostic 	mcb->sector = sector % hu->sectors;
332*32529Sbostic 	mcb->chain[0].ta  = (unsigned long) io->i_ma;
333*32529Sbostic 	mcb->chain[0].lwc = (bytes + 3) / 4;
334*32529Sbostic 	err = hdmcb(mcb, io);
335*32529Sbostic 	io->i_error = err;
336*32529Sbostic 	return (err ? 0 : bytes );
337*32529Sbostic }
338*32529Sbostic 
339*32529Sbostic /*************************************************************************
340*32529Sbostic *  Procedure:	hdioctl
341*32529Sbostic *
342*32529Sbostic *  Description: ioctl routine.
343*32529Sbostic *
344*32529Sbostic *  Returns:     0       no errors
345*32529Sbostic *               non-0    error
346*32529Sbostic **************************************************************************/
347*32529Sbostic 
348*32529Sbostic int
349*32529Sbostic hdioctl(io, command, arg)
350*32529Sbostic 
351*32529Sbostic struct iob	*io ; 		/* i/o block.
352*32529Sbostic 				 */
353*32529Sbostic int		command ;	/* The ioctl commmand.
354*32529Sbostic 				 */
355*32529Sbostic int		arg ; 		/* Data. Format depends on ioctl.
356*32529Sbostic 				 */
357*32529Sbostic {
358*32529Sbostic 	mcb_type	*mcb;
359*32529Sbostic 	hdunit_type	*hu;		/* disk unit information table      */
360*32529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
361*32529Sbostic 	register int	i;
362*32529Sbostic 	int		bus;		/* bus number	                    */
363*32529Sbostic 	int	        ctlr;		/* the controller number            */
364*32529Sbostic 	int	        drive;		/* the drive number                 */
365*32529Sbostic 
366*32529Sbostic 	bus = io->i_bus;
367*32529Sbostic 	ctlr = io->i_ctlr;
368*32529Sbostic 	drive = io->i_drive;
369*32529Sbostic 	hu = &hdc_unit[drive][ctlr][bus];
370*32529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
371*32529Sbostic 
372*32529Sbostic 	switch (command) {
373*32529Sbostic 
374*32529Sbostic 	case DSKIOCFORMAT: {
375*32529Sbostic 
376*32529Sbostic 		/*
377*32529Sbostic 		 * Format a disk track. The received argument is a pointer
378*32529Sbostic 		 * to a "formatop" structure describing the track to format.
379*32529Sbostic 		 *
380*32529Sbostic 		 * Set up a buffer with each longword corresponding to a
381*32529Sbostic 		 * sector on the track; a 1 means no flaw, a 0 means a flaw.
382*32529Sbostic 		 * Send an mcb to the hdc to format the track.
383*32529Sbostic 		 */
384*32529Sbostic 
385*32529Sbostic 		register struct formatop *track;
386*32529Sbostic 
387*32529Sbostic 		if (!hu->format)
388*32529Sbostic 			return(1);
389*32529Sbostic 		track = (struct formatop *) arg;
390*32529Sbostic 		mcb = &hc->mcb;
391*32529Sbostic 		for (i=0; i<hu->phys_sectors; i++)
392*32529Sbostic 			hu->phio_data[i] = 1;
393*32529Sbostic 		for (i=0; i<track->flaw_count; i++)
394*32529Sbostic 			hu->phio_data[track->flaw[i]]=0;
395*32529Sbostic 		mcb->command = HCMD_FORMAT;
396*32529Sbostic 		mcb->drive = hu->slave;
397*32529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
398*32529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
399*32529Sbostic 		mcb->cyl = track->cylinder;
400*32529Sbostic 		mcb->head = track->head;
401*32529Sbostic 		mcb->sector = 0;
402*32529Sbostic 		if (hdmcb(mcb, io))
403*32529Sbostic 			return EIO;
404*32529Sbostic 		break;
405*32529Sbostic 	}
406*32529Sbostic 
407*32529Sbostic 	case DSKIOCCERTIFY: {
408*32529Sbostic 
409*32529Sbostic 		/*
410*32529Sbostic 		 * Certify a disk track. The received argument is a pointer
411*32529Sbostic 		 * to a "formatop" structure describing the track to certify.
412*32529Sbostic 		 *
413*32529Sbostic 		 * Send an mcb to the hdc to certify the track.
414*32529Sbostic 		 * The controller returns data in which each longword
415*32529Sbostic 		 * corresponds to a sector on the track; a 1 means no flaw,
416*32529Sbostic 		 * a 0 means a flaw.
417*32529Sbostic 		 */
418*32529Sbostic 
419*32529Sbostic 		register struct formatop *track;
420*32529Sbostic 
421*32529Sbostic 		if (!hu->format)
422*32529Sbostic 			return 1;
423*32529Sbostic 		track = (struct formatop *) arg;
424*32529Sbostic 		mcb = &hc->mcb;
425*32529Sbostic 		mcb->command = HCMD_CERTIFY;
426*32529Sbostic 		mcb->drive = hu->slave;
427*32529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
428*32529Sbostic 		mcb->chain[0].lwc = hu->phys_sectors;
429*32529Sbostic 		mcb->cyl = track->cylinder;
430*32529Sbostic 		mcb->head = track->head;
431*32529Sbostic 		mcb->sector = 0;
432*32529Sbostic 		if (hdmcb(mcb, io))
433*32529Sbostic 			return EIO;
434*32529Sbostic 		track->flaw_count = 0;
435*32529Sbostic 		for (i=0; i<hu->phys_sectors; i++) {
436*32529Sbostic 			if (track->flaw_count >= MAXVFLAW) break;
437*32529Sbostic 			if (hu->phio_data[i]==0) {
438*32529Sbostic 				track->flaw[track->flaw_count] = i;
439*32529Sbostic 				track->flaw_count++;
440*32529Sbostic 			}
441*32529Sbostic 		}
442*32529Sbostic 		break;
443*32529Sbostic 	}
444*32529Sbostic 
445*32529Sbostic 	case DSKIOCVERIFY: {
446*32529Sbostic 
447*32529Sbostic 		/*
448*32529Sbostic 		 * Verify a disk track. The received argument is a pointer
449*32529Sbostic 		 * to a "formatop" structure describing the track to verify.
450*32529Sbostic 		 */
451*32529Sbostic 
452*32529Sbostic 		register struct formatop *track;
453*32529Sbostic 
454*32529Sbostic 		if (!hu->format)
455*32529Sbostic 			return(1);
456*32529Sbostic 		track = (struct formatop *) arg;
457*32529Sbostic 		mcb = &hc->mcb;
458*32529Sbostic 		mcb->command = HCMD_VERIFY;
459*32529Sbostic 		mcb->drive = hu->slave;
460*32529Sbostic 		mcb->chain[0].ta  = 0;
461*32529Sbostic 		mcb->chain[0].lwc = 0;
462*32529Sbostic 		mcb->cyl = track->cylinder;
463*32529Sbostic 		mcb->head = track->head;
464*32529Sbostic 		mcb->sector = 0;
465*32529Sbostic 		if (hdmcb(mcb, io))
466*32529Sbostic 			return EIO;
467*32529Sbostic 		break;
468*32529Sbostic 	}
469*32529Sbostic 
470*32529Sbostic 	case DSKIOCFORMATCTL: {
471*32529Sbostic 
472*32529Sbostic 		/*
473*32529Sbostic 		 * This ioctl provides special format control.
474*32529Sbostic 		 * Currently the valid arguments are:
475*32529Sbostic 		 *
476*32529Sbostic 		 * arg= 0  disable formatting;
477*32529Sbostic 		 *
478*32529Sbostic 		 * arg= 1  enable formatting (allow privileged access);
479*32529Sbostic 		 *         formatting must not already be enabled;
480*32529Sbostic 		 *         For formatting, change to use partition 7.
481*32529Sbostic 		 */
482*32529Sbostic 
483*32529Sbostic 		if (arg<0 || arg>1)
484*32529Sbostic 			return (1);
485*32529Sbostic 		if (arg==1) {
486*32529Sbostic 			if (hu->format) return (1);
487*32529Sbostic 			/* If not already formatting.... */
488*32529Sbostic 			hu->format = 1 ;
489*32529Sbostic 			io->i_part = HDC_DEFPART;
490*32529Sbostic 			io->i_boff = hu->partition[HDC_DEFPART].start;
491*32529Sbostic 		}
492*32529Sbostic 		else
493*32529Sbostic 			hu->format = 0 ;
494*32529Sbostic 		break;
495*32529Sbostic 	}
496*32529Sbostic 
497*32529Sbostic 	case DSKIOCSTATUS: {
498*32529Sbostic 
499*32529Sbostic 		/*
500*32529Sbostic 		 * Return info about the disk. Caller's parameter is a
501*32529Sbostic 		 * pointer to a dsk_status structure.
502*32529Sbostic 		 */
503*32529Sbostic 
504*32529Sbostic 		register dsk_status *status;
505*32529Sbostic 
506*32529Sbostic 		status = (dsk_status *) arg;
507*32529Sbostic 		status->id =		hu->id;
508*32529Sbostic 		status->drive_status =	0;
509*32529Sbostic 		status->rpm =		hu->rpm;
510*32529Sbostic 		status->bytes_per_sec = hu->bytes_per_sec;
511*32529Sbostic 		status->cylinders =	hu->cylinders;
512*32529Sbostic 		status->heads =		hu->heads;
513*32529Sbostic 		status->sectors =	hu->sectors;
514*32529Sbostic 		status->phys_cylinders= hu->phys_cylinders;
515*32529Sbostic 		status->phys_heads =	hu->phys_heads;
516*32529Sbostic 		status->phys_sectors =	hu->phys_sectors;
517*32529Sbostic 		status->diag_cyl =	hu->diag_cyl;
518*32529Sbostic 		status->diag_cylinders= hu->diag_cyl_count;
519*32529Sbostic 		status->def_cyl =	hu->def_cyl;
520*32529Sbostic 		status->def_cylinders =	hu->def_cyl_count;
521*32529Sbostic 		break;
522*32529Sbostic 	}
523*32529Sbostic 
524*32529Sbostic 	case DSKIOCVENDORFLAW: {
525*32529Sbostic 
526*32529Sbostic 		/*
527*32529Sbostic 		 * Return vendor flaw info.
528*32529Sbostic 		 *
529*32529Sbostic 		 * Read in the vendor data (data for each track is at
530*32529Sbostic 		 * relative sector 0 of the track); then copy the
531*32529Sbostic 		 * vendor flaw data to the caller's buffer.
532*32529Sbostic 		 */
533*32529Sbostic 
534*32529Sbostic 		register vflaw_type *vflaw;
535*32529Sbostic 		register struct flaw *vendor;
536*32529Sbostic 
537*32529Sbostic 		if (!hu->format)
538*32529Sbostic 			return(1);
539*32529Sbostic 		vflaw = (vflaw_type *) arg;
540*32529Sbostic 		mcb = &hc->mcb;
541*32529Sbostic 		mcb->command = HCMD_VENDOR;
542*32529Sbostic 		mcb->drive = hu->slave;
543*32529Sbostic 		mcb->chain[0].lwc = HDC_VDATA_SIZE;
544*32529Sbostic 		mcb->chain[0].ta  = (unsigned long) hu->phio_data;
545*32529Sbostic 		mcb->cyl = vflaw->cylinder;
546*32529Sbostic 		mcb->head = vflaw->head;
547*32529Sbostic 		mcb->sector = 0;
548*32529Sbostic 		if (hdmcb(mcb, io))
549*32529Sbostic 			return EIO;
550*32529Sbostic 		vendor = (struct flaw *) &hu->phio_data[0];
551*32529Sbostic 		for (i=0; i<MAXVFLAW; i++) {
552*32529Sbostic 			vflaw->flaw[i].offset = vendor[i].offset;
553*32529Sbostic 			vflaw->flaw[i].length = vendor[i].length;
554*32529Sbostic 		}
555*32529Sbostic 		break;
556*32529Sbostic 	}
557*32529Sbostic 	}
558*32529Sbostic 	return 0;
559*32529Sbostic }
560*32529Sbostic 
561*32529Sbostic /*************************************************************************
562*32529Sbostic *  Procedure:	hdmcb
563*32529Sbostic *
564*32529Sbostic *  Description: Internal routine used to send mcb's to the hdc.
565*32529Sbostic *
566*32529Sbostic *  Returns:     0          normal
567*32529Sbostic *               non-zero   error occurred
568*32529Sbostic **************************************************************************/
569*32529Sbostic 
570*32529Sbostic int
571*32529Sbostic hdmcb(mcb, io)
572*32529Sbostic 
573*32529Sbostic register mcb_type	*mcb ;	/* mcb to send to the hdc		    */
574*32529Sbostic register struct iob	*io ;	/* i/o block				    */
575*32529Sbostic 
576*32529Sbostic {
577*32529Sbostic 	master_mcb_type *master_mcb;	/* the hdc's master mcb             */
578*32529Sbostic 	hdctlr_type	*hc;		/* hdc ctlr information table       */
579*32529Sbostic 	hdc_regs_type	*ctlr_addr;	/* pointer to hdc i/o registers     */
580*32529Sbostic 	int		timeout;	/* used to timeout the mcb          */
581*32529Sbostic 	int		bus;		/* bus number	                    */
582*32529Sbostic 	int	        ctlr;		/* the controller number            */
583*32529Sbostic 	int		i,end;
584*32529Sbostic 	unsigned int	*ptr;
585*32529Sbostic 
586*32529Sbostic 	bus = io->i_bus;
587*32529Sbostic 	ctlr = io->i_ctlr;
588*32529Sbostic 	hc = &hdc_ctlr[ctlr][bus];
589*32529Sbostic 
590*32529Sbostic 	mcb->interrupt = FALSE;
591*32529Sbostic 	mcb->priority = 0;
592*32529Sbostic 	mcb->forw_phaddr = 0;
593*32529Sbostic 	mcb->context = 0;
594*32529Sbostic 	mcb->reserved[0] = 0;
595*32529Sbostic 	mcb->reserved[1] = 0;
596*32529Sbostic 	master_mcb = &hc->master_mcb;
597*32529Sbostic 	master_mcb->forw_phaddr = (long) &mcb->forw_phaddr;
598*32529Sbostic 	master_mcb->mcs = 0;
599*32529Sbostic 	master_mcb->interrupt = 0;
600*32529Sbostic 	master_mcb->reserve1  = 0;
601*32529Sbostic 	master_mcb->reserve2  = 0;
602*32529Sbostic 	master_mcb->context   = 0;
603*32529Sbostic 	master_mcb->mcl = MCL_IMMEDIATE;
604*32529Sbostic 	for (i=0;i<HDC_XSTAT_SIZE;i++) master_mcb->xstatus[i] = 0;
605*32529Sbostic         ctlr_addr = hc->registers;
606*32529Sbostic 	HDREG(master_mcb_reg) = (unsigned long) master_mcb;
607*32529Sbostic 	timeout = 15000;
608*32529Sbostic 	while (TRUE) {
609*32529Sbostic 		DELAY(1000);
610*32529Sbostic 		mtpr(0,PADC);
611*32529Sbostic 		if ( (master_mcb->mcs & MCS_DONE) &&
612*32529Sbostic 			!(master_mcb->mcs & MCS_FATALERROR) ) return 0;
613*32529Sbostic 		timeout--;
614*32529Sbostic 		if ( timeout > 0   &&
615*32529Sbostic 			!(master_mcb->mcs & MCS_FATALERROR) ) continue;
616*32529Sbostic 		if ( master_mcb->mcs & MCS_FATALERROR )
617*32529Sbostic 			printf("hdc: controller fatal error\n");
618*32529Sbostic 		else
619*32529Sbostic 			printf("hdc: controller timed out\n");
620*32529Sbostic 
621*32529Sbostic 		printf("mmcb: ");
622*32529Sbostic 		ptr = (unsigned int *) master_mcb;
623*32529Sbostic 		for (i=0;i<8;i++)
624*32529Sbostic 			printf(" %x",ptr[i]);
625*32529Sbostic 		for (i=7+HDC_XSTAT_SIZE; i>7; i--) {
626*32529Sbostic 			end = i;
627*32529Sbostic 			if (ptr[i] != 0) break;
628*32529Sbostic 		}
629*32529Sbostic 		for (i=8;i<=end;i++)
630*32529Sbostic 			printf(" %x",ptr[i]);
631*32529Sbostic 		printf("\n");
632*32529Sbostic 
633*32529Sbostic 		printf("mcb:  ");
634*32529Sbostic 		ptr = (unsigned int *) &mcb->forw_phaddr;
635*32529Sbostic 		for (i=0; i<6; i++)
636*32529Sbostic 			printf(" %x",ptr[i]);
637*32529Sbostic 		for (i=6; i<72; i+=2) {
638*32529Sbostic 			printf("  %x %x", ptr[i], ptr[i+1]);
639*32529Sbostic 			if ( !(ptr[i] & 0x80000000)) break;
640*32529Sbostic 		}
641*32529Sbostic 		printf("\n");
642*32529Sbostic 		return(1);
643*32529Sbostic 	}
644*32529Sbostic }
645