Commit | Line | Data |
---|---|---|
2839b724 | 1 | /* |
ce062630 KB |
2 | * Copyright (c) 1988 The Regents of the University of California. |
3 | * All rights reserved. | |
3b94e226 | 4 | * |
ce062630 KB |
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 | * | |
ca67e7b4 | 20 | * @(#)hd.c 7.6 (Berkeley) 5/1/89 |
2839b724 | 21 | */ |
d2ed10da | 22 | |
3b94e226 | 23 | #include "param.h" |
3b94e226 KB |
24 | #include "inode.h" |
25 | #include "fs.h" | |
d2ed10da | 26 | #include "buf.h" |
3b94e226 | 27 | #include "ioctl.h" |
d2ed10da | 28 | #include "disklabel.h" |
3b94e226 | 29 | #include "saio.h" |
ce062630 KB |
30 | #include "../tahoe/mtpr.h" |
31 | #include "../tahoevba/hdreg.h" | |
3b94e226 | 32 | |
ce062630 KB |
33 | static struct registers *hdc_regs[HDC_MAXCTLR][HDC_MAXBUS]; |
34 | static struct disklabel dklabel[HDC_MAXDRIVE][HDC_MAXCTLR][HDC_MAXBUS]; | |
2839b724 | 35 | |
2839b724 | 36 | hdopen(io) |
ce062630 | 37 | register struct iob *io; |
2839b724 | 38 | { |
ce062630 KB |
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)]; | |
d2ed10da KB |
45 | |
46 | /* validate the device specification */ | |
ce062630 KB |
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) | |
d1de3d34 | 52 | return(EUNIT); |
ce062630 KB |
53 | if ((u_int)io->i_part > 7) |
54 | return(EPART); | |
d2ed10da KB |
55 | |
56 | /* init drive structure. */ | |
ce062630 KB |
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); | |
2839b724 | 60 | |
d2ed10da | 61 | /* insure that this is an hdc, then reset the hdc. */ |
ce062630 KB |
62 | if (wbadaddr(&hr->module_id, 4, &junk)) { |
63 | printf("hd%d: %x: invalid csr\n", io->i_ctlr, (u_int)hr); | |
d1de3d34 | 64 | return(ENXIO); |
3b94e226 | 65 | } |
ce062630 | 66 | hr->soft_reset = 0; |
2839b724 KB |
67 | DELAY(1000000); |
68 | ||
69 | /* | |
ce062630 | 70 | * read in the hdc module id word. The controller is bad if the |
d1de3d34 KB |
71 | * hdc's writeable control store is not loaded or if the hdc failed |
72 | * the functional integrity test for any reason. | |
2839b724 | 73 | */ |
ce062630 | 74 | hr->module_id = (u_long)&id; |
2839b724 | 75 | DELAY(10000); |
3b94e226 | 76 | mtpr(PADC, 0); |
ce062630 KB |
77 | if (id.module_id != (u_char)HDC_MID) { |
78 | printf("hdc: controller bad module id: id = %x\n", | |
79 | id.module_id); | |
d2ed10da | 80 | return(ENXIO); |
2839b724 | 81 | } |
ce062630 KB |
82 | if (id.code_rev == (u_char)0xff) { |
83 | printf("hdc: controller micro-code is not loaded.\n"); | |
d1de3d34 | 84 | return(ENXIO); |
2839b724 | 85 | } |
ce062630 KB |
86 | if (id.fit != (u_char)0xff) { |
87 | printf("hdc: controller FIT test failed: error= %x\n", | |
88 | id.fit); | |
d1de3d34 | 89 | return(ENXIO); |
2839b724 KB |
90 | } |
91 | ||
ce062630 KB |
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)) | |
d1de3d34 | 101 | return(EIO); |
d2ed10da KB |
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 | */ | |
ce062630 | 107 | if (status.drs&DRS_FAULT) |
d2ed10da | 108 | printf("hdc: clearing drive fault.\n"); |
ce062630 | 109 | if (!(status.drs&DRS_ONLINE)) { |
d2ed10da KB |
110 | printf("hdc: drive is not online.\n"); |
111 | return(EIO); | |
112 | } | |
113 | ||
ce062630 KB |
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); | |
3b7697ff | 124 | dlp = (struct disklabel *)(dlbuf + (LABELOFFSET / sizeof(long))); |
ce062630 KB |
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); | |
2839b724 | 132 | } |
ce062630 KB |
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; | |
d1de3d34 | 142 | return(0); |
2839b724 KB |
143 | } |
144 | ||
d1de3d34 | 145 | hdstrategy(io, cmd) |
ce062630 KB |
146 | register struct iob *io; |
147 | int cmd; | |
2839b724 | 148 | { |
ce062630 KB |
149 | register struct disklabel *dlp; |
150 | struct mcb mcb; | |
151 | long sector; | |
d2ed10da | 152 | |
ce062630 KB |
153 | if (io->i_cc&3) { |
154 | printf("hd%d: i/o not a longword multiple.\n", io->i_unit); | |
d1de3d34 KB |
155 | return(0); |
156 | } | |
ce062630 | 157 | dlp = &dklabel[io->i_unit][io->i_ctlr][io->i_bus]; |
2839b724 | 158 | sector = io->i_bn * HDC_SPB; |
ce062630 KB |
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); | |
2839b724 KB |
167 | } |
168 | ||
ce062630 KB |
169 | hdimcb(mcb, io) |
170 | register struct mcb *mcb; | |
171 | register struct iob *io; | |
2839b724 | 172 | { |
ce062630 KB |
173 | struct master_mcb master; |
174 | int timeout; | |
2839b724 | 175 | |
ce062630 KB |
176 | /* fill in mcb */ |
177 | mcb->interrupt = 0; | |
178 | mcb->forw_phaddr = 0; | |
2839b724 | 179 | |
ce062630 KB |
180 | /* fill in master mcb */ |
181 | master.mcw = MCL_IMMEDIATE; | |
182 | master.forw_phaddr = (u_long)mcb; | |
183 | master.mcs = 0; | |
2839b724 | 184 | |
ce062630 KB |
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); | |
d1de3d34 | 191 | return(1); |
2839b724 | 192 | } |
ce062630 KB |
193 | if (master.mcs&MCS_DONE) |
194 | return(0); | |
2839b724 | 195 | } |
3b7697ff | 196 | printf("hdc%d: timed out.\n", io->i_ctlr); |
ce062630 KB |
197 | return(1); |
198 | } | |
2839b724 | 199 | |
ce062630 KB |
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(); | |
2839b724 | 212 | |
ce062630 KB |
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); | |
2839b724 | 229 | } |
ce062630 KB |
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); | |
2839b724 | 234 | } |
ce062630 KB |
235 | if (strcmp(&geo->id[0], GB_ID)) { |
236 | printf("hd%d: bad default geometry header.\n", io->i_unit); | |
237 | return(ENXIO); | |
2839b724 | 238 | } |
ce062630 KB |
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); | |
2839b724 | 243 | } |
ce062630 KB |
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; | |
2839b724 | 247 | } |
ce062630 KB |
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)"); | |
d1de3d34 | 260 | return(0); |
2839b724 | 261 | } |
ce062630 | 262 | #endif /* COMPAT_42 */ |