xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 36193)
132529Sbostic /*
2*36193Sbostic  * Copyright (c) 1988 The Regents of the University of California.
3*36193Sbostic  * All rights reserved.
432557Sbostic  *
5*36193Sbostic  * This code is derived from software contributed to Berkeley by
6*36193Sbostic  * Harris Corp.
7*36193Sbostic  *
8*36193Sbostic  * Redistribution and use in source and binary forms are permitted
9*36193Sbostic  * provided that the above copyright notice and this paragraph are
10*36193Sbostic  * duplicated in all such forms and that any documentation,
11*36193Sbostic  * advertising materials, and other materials related to such
12*36193Sbostic  * distribution and use acknowledge that the software was developed
13*36193Sbostic  * by the University of California, Berkeley.  The name of the
14*36193Sbostic  * University may not be used to endorse or promote products derived
15*36193Sbostic  * from this software without specific prior written permission.
16*36193Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*36193Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*36193Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*36193Sbostic  *
20*36193Sbostic  *	@(#)hd.c	7.5 (Berkeley) 11/01/88
2132529Sbostic  */
2232529Sbostic 
2332557Sbostic #include "param.h"
2432557Sbostic #include "inode.h"
2532557Sbostic #include "fs.h"
2633164Sbostic #include "buf.h"
2732557Sbostic #include "ioctl.h"
2833164Sbostic #include "disklabel.h"
2932557Sbostic #include "saio.h"
30*36193Sbostic #include "../tahoe/mtpr.h"
31*36193Sbostic #include "../tahoevba/hdreg.h"
3232529Sbostic 
33*36193Sbostic static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS];
34*36193Sbostic static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS];
3533164Sbostic 
3632529Sbostic hdopen(io)
37*36193Sbostic 	register struct iob *io;
3832529Sbostic {
39*36193Sbostic 	register struct disklabel *dlp;
40*36193Sbostic 	struct status status;
41*36193Sbostic 	struct module_id id;
42*36193Sbostic 	struct registers *hr;
43*36193Sbostic 	struct mcb mcb;
44*36193Sbostic 	long junk, dlbuf[DEV_BSIZE/sizeof(long)];
4532529Sbostic 
4633164Sbostic 	/* validate the device specification */
47*36193Sbostic 	if ((u_int)io->i_bus >= HDC_MAXBUS)
48*36193Sbostic 		return(EADAPT);
49*36193Sbostic 	if ((u_int)io->i_ctlr >= HDC_MAXCTLR)
50*36193Sbostic 		return(ECTLR);
51*36193Sbostic 	if ((u_int)io->i_unit >= HDC_MAXDRIVE)
5232560Sbostic 		return(EUNIT);
53*36193Sbostic 	if ((u_int)io->i_part > 7)
54*36193Sbostic 		return(EPART);
5532529Sbostic 
5633164Sbostic 	/* init drive structure. */
57*36193Sbostic 	hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ?
58*36193Sbostic 	    0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 :
59*36193Sbostic 	    0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16);
6032529Sbostic 
6133164Sbostic 	/* insure that this is an hdc, then reset the hdc. */
62*36193Sbostic 	if (wbadaddr(&hr->module_id, 4, &junk)) {
63*36193Sbostic 		printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr);
6432560Sbostic 		return(ENXIO);
6532557Sbostic 	}
66*36193Sbostic 	hr->soft_reset = 0;
6732529Sbostic 	DELAY(1000000);
6832529Sbostic 
6932529Sbostic 	/*
70*36193Sbostic 	 * read in the hdc module id word.  The controller is bad if the
7132560Sbostic 	 * hdc's writeable control store is not loaded or if the hdc failed
7232560Sbostic 	 * the functional integrity test for any reason.
7332529Sbostic 	 */
74*36193Sbostic 	hr->module_id = (u_long)&id;
7532529Sbostic 	DELAY(10000);
7632557Sbostic 	mtpr(PADC, 0);
77*36193Sbostic 	if (id.module_id != (u_char)HDC_MID) {
78*36193Sbostic 		printf("hdc: controller bad module id: id = %x\n",
79*36193Sbostic 		    id.module_id);
8033164Sbostic 		return(ENXIO);
8132529Sbostic 	}
82*36193Sbostic 	if (id.code_rev == (u_char)0xff) {
83*36193Sbostic 		printf("hdc: controller micro-code is not loaded.\n");
8432560Sbostic 		return(ENXIO);
8532529Sbostic 	}
86*36193Sbostic 	if (id.fit != (u_char)0xff) {
87*36193Sbostic 		printf("hdc: controller FIT test failed: error= %x\n",
88*36193Sbostic 		    id.fit);
8932560Sbostic 		return(ENXIO);
9032529Sbostic 	}
9132529Sbostic 
92*36193Sbostic 	/* read the drive status */
93*36193Sbostic 	mcb.command = HCMD_STATUS;
94*36193Sbostic 	mcb.drive = io->i_unit;
95*36193Sbostic 	mcb.cyl = 0;
96*36193Sbostic 	mcb.head = 0;
97*36193Sbostic 	mcb.sector = 0;
98*36193Sbostic 	mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long));
99*36193Sbostic 	mcb.chain[0].memadr = (long)&status;
100*36193Sbostic 	if (hdimcb(&mcb, io))
10132560Sbostic 		return(EIO);
10233164Sbostic 
10333164Sbostic 	/*
10433164Sbostic 	 * Report drive down if anything in the drive status is bad.
10533164Sbostic 	 * If fault condition, reading will try to clear the fault.
10633164Sbostic 	 */
107*36193Sbostic 	if (status.drs&DRS_FAULT)
10833164Sbostic 		printf("hdc: clearing drive fault.\n");
109*36193Sbostic 	if (!(status.drs&DRS_ONLINE)) {
11033164Sbostic 		printf("hdc: drive is not online.\n");
11133164Sbostic 		return(EIO);
11233164Sbostic 	}
11333164Sbostic 
114*36193Sbostic 	/* read in the pack label */
115*36193Sbostic 	mcb.command = HCMD_READ;
116*36193Sbostic 	mcb.drive = io->i_unit;
117*36193Sbostic 	mcb.cyl = 0;
118*36193Sbostic 	mcb.head = 0;
119*36193Sbostic 	mcb.sector = LABELSECTOR;
120*36193Sbostic 	mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long));
121*36193Sbostic 	mcb.chain[0].memadr = (long)dlbuf;
122*36193Sbostic 	if (hdimcb(&mcb, io))
123*36193Sbostic 		return(ERDLAB);
124*36193Sbostic 	dlp = (struct disklabel *)(dlbuf + LABELOFFSET);
125*36193Sbostic 	if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
126*36193Sbostic #ifdef COMPAT_42
127*36193Sbostic 	{
128*36193Sbostic 		int error;
12932529Sbostic 
130*36193Sbostic 		if (error = hdmaptype(io, dlp, &status, io->i_unit))
131*36193Sbostic 			return(error);
13232529Sbostic 	}
133*36193Sbostic #else
134*36193Sbostic 		return(EUNLAB);
135*36193Sbostic #endif
136*36193Sbostic 	dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp;
137*36193Sbostic 	if (io->i_part >= dlp->d_npartitions ||
138*36193Sbostic 	    dlp->d_partitions[io->i_part].p_size == 0)
139*36193Sbostic 		return(EPART);
140*36193Sbostic 	io->i_boff = (dlp->d_partitions[io->i_part].p_offset *
141*36193Sbostic 	    dlp->d_secsize) / DEV_BSIZE;
14232560Sbostic 	return(0);
14332529Sbostic }
14432529Sbostic 
14532560Sbostic hdstrategy(io, cmd)
146*36193Sbostic 	register struct iob *io;
147*36193Sbostic 	int cmd;
14832529Sbostic {
149*36193Sbostic 	register struct disklabel *dlp;
150*36193Sbostic 	struct mcb mcb;
151*36193Sbostic 	long sector;
15232529Sbostic 
153*36193Sbostic 	if (io->i_cc&3) {
154*36193Sbostic 		printf("hd%d: i/o not a longword multiple.\n", io->i_unit);
15532560Sbostic 		return(0);
15632560Sbostic 	}
157*36193Sbostic 	dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus];
15832529Sbostic 	sector = io->i_bn * HDC_SPB;
159*36193Sbostic 	mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE;
160*36193Sbostic 	mcb.drive = io->i_unit;
161*36193Sbostic 	mcb.cyl = sector / dlp->d_secpercyl;
162*36193Sbostic 	mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks;
163*36193Sbostic 	mcb.sector = sector % dlp->d_nsectors;
164*36193Sbostic 	mcb.chain[0].wcount = io->i_cc / sizeof(long);
165*36193Sbostic 	mcb.chain[0].memadr  = (u_long)io->i_ma;
166*36193Sbostic 	return(hdimcb(&mcb, io) ? -1 : io->i_cc);
16732529Sbostic }
16832529Sbostic 
169*36193Sbostic hdimcb(mcb, io)
170*36193Sbostic 	register struct mcb *mcb;
171*36193Sbostic 	register struct iob *io;
17232529Sbostic {
173*36193Sbostic 	struct master_mcb master;
174*36193Sbostic 	int timeout;
17532529Sbostic 
176*36193Sbostic 	/* fill in mcb */
177*36193Sbostic 	mcb->interrupt = 0;
178*36193Sbostic 	mcb->forw_phaddr = 0;
17932529Sbostic 
180*36193Sbostic 	/* fill in master mcb */
181*36193Sbostic 	master.mcw = MCL_IMMEDIATE;
182*36193Sbostic 	master.forw_phaddr = (u_long)mcb;
183*36193Sbostic 	master.mcs = 0;
18432529Sbostic 
185*36193Sbostic 	hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master;
186*36193Sbostic 	for (timeout = 15000; timeout; --timeout) {
187*36193Sbostic 		DELAY(1000);
188*36193Sbostic 		mtpr(PADC, 0);
189*36193Sbostic 		if (master.mcs&MCS_FATALERROR) {
190*36193Sbostic 			printf("hdc%d: fatal error.\n", io->i_ctlr);
19132529Sbostic 			return(1);
19232529Sbostic 		}
193*36193Sbostic 		if (master.mcs&MCS_DONE)
194*36193Sbostic 			return(0);
19532529Sbostic 	}
196*36193Sbostic 	printf("hdc: controller timed out.\n");
197*36193Sbostic 	return(1);
198*36193Sbostic }
19932529Sbostic 
200*36193Sbostic #ifdef COMPAT_42
201*36193Sbostic hdmaptype(io, dlp, status, unit)
202*36193Sbostic 	register struct iob *io;
203*36193Sbostic 	register struct disklabel *dlp;
204*36193Sbostic 	struct status *status;
205*36193Sbostic 	int unit;
206*36193Sbostic {
207*36193Sbostic 	geometry_sector geometry;
208*36193Sbostic 	geometry_block *geo;
209*36193Sbostic 	struct mcb mcb;
210*36193Sbostic 	int cnt;
211*36193Sbostic 	char *strcpy();
21232529Sbostic 
213*36193Sbostic 	printf("hd%d: unlabeled\n", unit);
214*36193Sbostic 	/*
215*36193Sbostic 	 * Read the geometry block (at head = 0 sector = 0 of the drive
216*36193Sbostic 	 * definition cylinder), validate it (must have the correct version
217*36193Sbostic 	 * number, header, and checksum).
218*36193Sbostic 	 */
219*36193Sbostic 	mcb.command = HCMD_READ;
220*36193Sbostic 	mcb.drive = unit;
221*36193Sbostic 	mcb.cyl = status->def_cyl;
222*36193Sbostic 	mcb.head = 0;
223*36193Sbostic 	mcb.sector = 0;
224*36193Sbostic 	mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long));
225*36193Sbostic 	mcb.chain[0].memadr = (long)&geometry;
226*36193Sbostic 	if (hdimcb(&mcb, io)) {
227*36193Sbostic  		printf("hd%d: can't read default geometry.\n", io->i_unit);
228*36193Sbostic 		return(ERDLAB);
22932529Sbostic 	}
230*36193Sbostic 	geo = &geometry.geometry_block;
231*36193Sbostic  	if (geo->version > 64000  ||  geo->version < 0) {
232*36193Sbostic  		printf("hd%d: bad default geometry version#.\n", io->i_unit);
233*36193Sbostic 		return(ENXIO);
23432529Sbostic 	}
235*36193Sbostic  	if (strcmp(&geo->id[0], GB_ID)) {
236*36193Sbostic  		printf("hd%d: bad default geometry header.\n", io->i_unit);
237*36193Sbostic 		return(ENXIO);
23832529Sbostic 	}
239*36193Sbostic 	GB_CHECKSUM(geo, cnt);
240*36193Sbostic 	if (geometry.checksum != cnt) {
241*36193Sbostic 		printf("hd%d: bad default geometry checksum.\n", io->i_unit);
242*36193Sbostic 		return(ENXIO);
24332529Sbostic 	}
244*36193Sbostic 	for (cnt = 0; cnt < GB_MAXPART; cnt++) {
245*36193Sbostic 		dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start;
246*36193Sbostic 		dlp->d_partitions[cnt].p_size = geo->partition[cnt].length;
24732529Sbostic 	}
248*36193Sbostic #ifdef RAW_SIZE
249*36193Sbostic 	dlp->d_secsize = status->bytes_per_sec;
250*36193Sbostic #else
251*36193Sbostic 	dlp->d_secsize = 512;
252*36193Sbostic #endif
253*36193Sbostic 	dlp->d_nsectors = status->max_sector + 1;
254*36193Sbostic 	dlp->d_ncylinders = status->max_cyl + 1;
255*36193Sbostic 	dlp->d_ntracks = status->max_head + 1;
256*36193Sbostic 	dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors;
257*36193Sbostic 	dlp->d_npartitions = GB_MAXPART;
258*36193Sbostic 	dlp->d_rpm = status->rpm;
259*36193Sbostic 	(void)strcpy(dlp->d_typename, "hdc (prom)");
26032560Sbostic 	return(0);
26132529Sbostic }
262*36193Sbostic #endif /* COMPAT_42 */
263