xref: /csrg-svn/sys/tahoe/stand/hd.c (revision 44532)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Harris Corp.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)hd.c	7.8 (Berkeley) 06/28/90
11  */
12 
13 #include "sys/param.h"
14 #include "sys/time.h"
15 #include "sys/vnode.h"
16 #include "ufs/inode.h"
17 #include "ufs/fs.h"
18 #include "sys/buf.h"
19 #include "sys/ioctl.h"
20 #include "sys/disklabel.h"
21 #include "saio.h"
22 #include "tahoe/mtpr.h"
23 #include "tahoevba/hdreg.h"
24 
25 static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS];
26 static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS];
27 
28 hdopen(io)
29 	register struct iob *io;
30 {
31 	register struct disklabel *dlp;
32 	struct status status;
33 	struct module_id id;
34 	struct registers *hr;
35 	struct mcb mcb;
36 	long junk, dlbuf[DEV_BSIZE/sizeof(long)];
37 
38 	/* validate the device specification */
39 	if ((u_int)io->i_bus >= HDC_MAXBUS)
40 		return(EADAPT);
41 	if ((u_int)io->i_ctlr >= HDC_MAXCTLR)
42 		return(ECTLR);
43 	if ((u_int)io->i_unit >= HDC_MAXDRIVE)
44 		return(EUNIT);
45 	if ((u_int)io->i_part > 7)
46 		return(EPART);
47 
48 	/* init drive structure. */
49 	hdc_regs[io->i_ctlr][io->i_bus] = hr = (struct registers *)(io->i_bus ?
50 	    0x80000000 | io->i_ctlr << 24 | HDC_MID << 16 :
51 	    0xC0000000 | io->i_ctlr << 24 | HDC_MID << 16);
52 
53 	/* insure that this is an hdc, then reset the hdc. */
54 	if (wbadaddr(&hr->module_id, 4, &junk)) {
55 		printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr);
56 		return(ENXIO);
57 	}
58 	hr->soft_reset = 0;
59 	DELAY(1000000);
60 
61 	/*
62 	 * read in the hdc module id word.  The controller is bad if the
63 	 * hdc's writeable control store is not loaded or if the hdc failed
64 	 * the functional integrity test for any reason.
65 	 */
66 	hr->module_id = (u_long)&id;
67 	DELAY(10000);
68 	mtpr(PADC, 0);
69 	if (id.module_id != (u_char)HDC_MID) {
70 		printf("hdc: controller bad module id: id = %x\n",
71 		    id.module_id);
72 		return(ENXIO);
73 	}
74 	if (id.code_rev == (u_char)0xff) {
75 		printf("hdc: controller micro-code is not loaded.\n");
76 		return(ENXIO);
77 	}
78 	if (id.fit != (u_char)0xff) {
79 		printf("hdc: controller FIT test failed: error= %x\n",
80 		    id.fit);
81 		return(ENXIO);
82 	}
83 
84 	/* read the drive status */
85 	mcb.command = HCMD_STATUS;
86 	mcb.drive = io->i_unit;
87 	mcb.cyl = 0;
88 	mcb.head = 0;
89 	mcb.sector = 0;
90 	mcb.chain[0].wcount = (long)(sizeof(struct status) / sizeof(long));
91 	mcb.chain[0].memadr = (long)&status;
92 	if (hdimcb(&mcb, io))
93 		return(EIO);
94 
95 	/*
96 	 * Report drive down if anything in the drive status is bad.
97 	 * If fault condition, reading will try to clear the fault.
98 	 */
99 	if (status.drs&DRS_FAULT)
100 		printf("hdc: clearing drive fault.\n");
101 	if (!(status.drs&DRS_ONLINE)) {
102 		printf("hdc: drive is not online.\n");
103 		return(EIO);
104 	}
105 
106 	/* read in the pack label */
107 	mcb.command = HCMD_READ;
108 	mcb.drive = io->i_unit;
109 	mcb.cyl = 0;
110 	mcb.head = 0;
111 	mcb.sector = LABELSECTOR;
112 	mcb.chain[0].wcount = (long)(DEV_BSIZE / sizeof(long));
113 	mcb.chain[0].memadr = (long)dlbuf;
114 	if (hdimcb(&mcb, io))
115 		return(ERDLAB);
116 	dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long)));
117 	if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
118 #ifdef COMPAT_42
119 	{
120 		int error;
121 
122 		if (error = hdmaptype(io, dlp, &status, io->i_unit))
123 			return(error);
124 	}
125 #else
126 		return(EUNLAB);
127 #endif
128 	dklabel[io->i_unit][io->i_ctlr][io->i_bus] = *dlp;
129 	if (io->i_part >= dlp->d_npartitions ||
130 	    dlp->d_partitions[io->i_part].p_size == 0)
131 		return(EPART);
132 	io->i_boff = (dlp->d_partitions[io->i_part].p_offset *
133 	    dlp->d_secsize) / DEV_BSIZE;
134 	return(0);
135 }
136 
137 hdstrategy(io, cmd)
138 	register struct iob *io;
139 	int cmd;
140 {
141 	register struct disklabel *dlp;
142 	struct mcb mcb;
143 	long sector;
144 
145 	if (io->i_cc&3) {
146 		printf("hd%d: i/o not a longword multiple.\n", io->i_unit);
147 		return(0);
148 	}
149 	dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus];
150 	sector = io->i_bn * HDC_SPB;
151 	mcb.command = (cmd == READ) ? HCMD_READ : HCMD_WRITE;
152 	mcb.drive = io->i_unit;
153 	mcb.cyl = sector / dlp->d_secpercyl;
154 	mcb.head = (sector / dlp->d_nsectors) % dlp->d_ntracks;
155 	mcb.sector = sector % dlp->d_nsectors;
156 	mcb.chain[0].wcount = io->i_cc / sizeof(long);
157 	mcb.chain[0].memadr  = (u_long)io->i_ma;
158 	return(hdimcb(&mcb, io) ? -1 : io->i_cc);
159 }
160 
161 hdimcb(mcb, io)
162 	register struct mcb *mcb;
163 	register struct iob *io;
164 {
165 	struct master_mcb master;
166 	int timeout;
167 
168 	/* fill in mcb */
169 	mcb->interrupt = 0;
170 	mcb->forw_phaddr = 0;
171 
172 	/* fill in master mcb */
173 	master.mcw = MCL_IMMEDIATE;
174 	master.forw_phaddr = (u_long)mcb;
175 	master.mcs = 0;
176 
177 	hdc_regs[io->i_ctlr][io->i_bus]->master_mcb = (u_long)&master;
178 	for (timeout = 15000; timeout; --timeout) {
179 		DELAY(1000);
180 		mtpr(PADC, 0);
181 		if (master.mcs&MCS_FATALERROR) {
182 			printf("hdc%d: fatal error.\n", io->i_ctlr);
183 			return(1);
184 		}
185 		if (master.mcs&MCS_DONE)
186 			return(0);
187 	}
188 	printf("hdc%d: timed out.\n", io->i_ctlr);
189 	return(1);
190 }
191 
192 #ifdef COMPAT_42
193 hdmaptype(io, dlp, status, unit)
194 	register struct iob *io;
195 	register struct disklabel *dlp;
196 	struct status *status;
197 	int unit;
198 {
199 	geometry_sector geometry;
200 	geometry_block *geo;
201 	struct mcb mcb;
202 	int cnt;
203 	char *strcpy();
204 
205 	printf("hd%d: unlabeled\n", unit);
206 	/*
207 	 * Read the geometry block (at head = 0 sector = 0 of the drive
208 	 * definition cylinder), validate it (must have the correct version
209 	 * number, header, and checksum).
210 	 */
211 	mcb.command = HCMD_READ;
212 	mcb.drive = unit;
213 	mcb.cyl = status->def_cyl;
214 	mcb.head = 0;
215 	mcb.sector = 0;
216 	mcb.chain[0].wcount = (long)(sizeof(geometry_sector) / sizeof(long));
217 	mcb.chain[0].memadr = (long)&geometry;
218 	if (hdimcb(&mcb, io)) {
219  		printf("hd%d: can't read default geometry.\n", io->i_unit);
220 		return(ERDLAB);
221 	}
222 	geo = &geometry.geometry_block;
223  	if (geo->version > 64000  ||  geo->version < 0) {
224  		printf("hd%d: bad default geometry version#.\n", io->i_unit);
225 		return(ENXIO);
226 	}
227  	if (strcmp(&geo->id[0], GB_ID)) {
228  		printf("hd%d: bad default geometry header.\n", io->i_unit);
229 		return(ENXIO);
230 	}
231 	GB_CHECKSUM(geo, cnt);
232 	if (geometry.checksum != cnt) {
233 		printf("hd%d: bad default geometry checksum.\n", io->i_unit);
234 		return(ENXIO);
235 	}
236 	for (cnt = 0; cnt < GB_MAXPART; cnt++) {
237 		dlp->d_partitions[cnt].p_offset = geo->partition[cnt].start;
238 		dlp->d_partitions[cnt].p_size = geo->partition[cnt].length;
239 	}
240 #ifdef RAW_SIZE
241 	dlp->d_secsize = status->bytes_per_sec;
242 #else
243 	dlp->d_secsize = 512;
244 #endif
245 	dlp->d_nsectors = status->max_sector + 1;
246 	dlp->d_ncylinders = status->max_cyl + 1;
247 	dlp->d_ntracks = status->max_head + 1;
248 	dlp->d_secpercyl = dlp->d_ntracks * dlp->d_nsectors;
249 	dlp->d_npartitions = GB_MAXPART;
250 	dlp->d_rpm = status->rpm;
251 	(void)strcpy(dlp->d_typename, "hdc (prom)");
252 	return(0);
253 }
254 #endif /* COMPAT_42 */
255