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