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