Commit | Line | Data |
---|---|---|
60f56dfc KM |
1 | /* |
2 | * Copyright (c) 1988 University of Utah. | |
3 | * Copyright (c) 1982, 1990 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Systems Programming Group of the University of Utah Computer | |
8 | * Science Department. | |
9 | * | |
10 | * %sccs.include.redist.c% | |
11 | * | |
12 | * from: Utah $Hdr: rd.c 1.30 89/09/17$ | |
13 | * | |
339a5f2c | 14 | * @(#)rd.c 7.3 (Berkeley) %G% |
60f56dfc KM |
15 | */ |
16 | ||
17 | /* | |
18 | * CS80/SS80 disk driver | |
19 | */ | |
20 | #include "rd.h" | |
21 | #if NRD > 0 | |
22 | ||
23 | #include "param.h" | |
24 | #include "systm.h" | |
25 | #include "errno.h" | |
26 | #include "dkstat.h" | |
27 | #include "disklabel.h" | |
28 | #include "buf.h" | |
29 | #include "uio.h" | |
30 | ||
31 | #include "device.h" | |
32 | #include "rdreg.h" | |
33 | ||
34 | int rdinit(), rdstart(), rdgo(), rdintr(); | |
35 | struct driver rddriver = { | |
36 | rdinit, "rd", rdstart, rdgo, rdintr, | |
37 | }; | |
38 | ||
39 | struct rd_softc { | |
40 | struct hp_device *sc_hd; | |
339a5f2c KM |
41 | int sc_flags; |
42 | short sc_type; | |
43 | short sc_punit; | |
44 | char *sc_addr; | |
45 | int sc_resid; | |
46 | u_int sc_wpms; | |
47 | struct rdinfo *sc_info; | |
48 | struct devqueue sc_dq; | |
60f56dfc KM |
49 | struct rd_iocmd sc_ioc; |
50 | struct rd_rscmd sc_rsc; | |
51 | struct rd_stat sc_stat; | |
52 | struct rd_ssmcmd sc_ssmc; | |
53 | struct rd_srcmd sc_src; | |
54 | struct rd_clearcmd sc_clear; | |
60f56dfc KM |
55 | } rd_softc[NRD]; |
56 | ||
57 | /* sc_flags values */ | |
58 | #define RDF_ALIVE 0x1 | |
59 | #define RDF_SEEK 0x2 | |
60 | #define RDF_SWAIT 0x4 | |
61 | ||
62 | struct size { | |
63 | daddr_t nblocks; | |
64 | int cyloff; | |
65 | }; | |
66 | ||
67 | #ifdef DEBUG | |
68 | int rddebug = 0x80; | |
69 | #define RDB_FOLLOW 0x01 | |
70 | #define RDB_STATUS 0x02 | |
71 | #define RDB_IDENT 0x04 | |
72 | #define RDB_IO 0x08 | |
73 | #define RDB_ASYNC 0x10 | |
74 | #define RDB_ERROR 0x80 | |
75 | #define RDB_DUMP 0x80000000 | |
76 | ||
77 | struct rdstats { | |
78 | long rdretries; | |
79 | long rdresets; | |
80 | long rdtimeouts; | |
81 | long rdpolltries; | |
82 | long rdpollwaits; | |
83 | } rdstats[NRD]; | |
84 | ||
85 | /* error message tables */ | |
86 | char *err_reject[] = { | |
87 | 0, 0, | |
88 | "channel parity error", /* 0x2000 */ | |
89 | 0, 0, | |
90 | "illegal opcode", /* 0x0400 */ | |
91 | "module addressing", /* 0x0200 */ | |
92 | "address bounds", /* 0x0100 */ | |
93 | "parameter bounds", /* 0x0080 */ | |
94 | "illegal parameter", /* 0x0040 */ | |
95 | "message sequence", /* 0x0020 */ | |
96 | 0, | |
97 | "message length", /* 0x0008 */ | |
98 | 0, 0, 0 | |
99 | }; | |
100 | ||
101 | char *err_fault[] = { | |
102 | 0, | |
103 | "cross unit", /* 0x4000 */ | |
104 | 0, | |
105 | "controller fault", /* 0x1000 */ | |
106 | 0, 0, | |
107 | "unit fault", /* 0x0200 */ | |
108 | 0, | |
109 | "diagnostic result", /* 0x0080 */ | |
110 | 0, | |
111 | "operator release request", /* 0x0020 */ | |
112 | "diagnostic release request", /* 0x0010 */ | |
113 | "internal maintenance release request", /* 0x0008 */ | |
114 | 0, | |
115 | "power fail", /* 0x0002 */ | |
116 | "retransmit" /* 0x0001 */ | |
117 | }; | |
118 | ||
119 | char *err_access[] = { | |
120 | "illegal parallel operation", /* 0x8000 */ | |
121 | "uninitialized media", /* 0x4000 */ | |
122 | "no spares available", /* 0x2000 */ | |
123 | "not ready", /* 0x1000 */ | |
124 | "write protect", /* 0x0800 */ | |
125 | "no data found", /* 0x0400 */ | |
126 | 0, 0, | |
127 | "unrecoverable data overflow", /* 0x0080 */ | |
128 | "unrecoverable data", /* 0x0040 */ | |
129 | 0, | |
130 | "end of file", /* 0x0010 */ | |
131 | "end of volume", /* 0x0008 */ | |
132 | 0, 0, 0 | |
133 | }; | |
134 | ||
135 | char *err_info[] = { | |
136 | "operator release request", /* 0x8000 */ | |
137 | "diagnostic release request", /* 0x4000 */ | |
138 | "internal maintenance release request", /* 0x2000 */ | |
139 | "media wear", /* 0x1000 */ | |
140 | "latency induced", /* 0x0800 */ | |
141 | 0, 0, | |
142 | "auto sparing invoked", /* 0x0100 */ | |
143 | 0, | |
144 | "recoverable data overflow", /* 0x0040 */ | |
145 | "marginal data", /* 0x0020 */ | |
146 | "recoverable data", /* 0x0010 */ | |
147 | 0, | |
148 | "maintenance track overflow", /* 0x0004 */ | |
149 | 0, 0 | |
150 | }; | |
151 | #endif | |
152 | ||
153 | /* | |
154 | * CS/80 partitions. We reserve the first cylinder for a LIF | |
155 | * style boot directory (the 8k allowed in the BSD filesystem | |
156 | * is just way too small). This boot area is outside of all but | |
157 | * the C partition. This implies that you cannot use the C | |
158 | * partition on a bootable disk since the filesystem would overlay | |
159 | * the boot area. You must use the A partition. | |
160 | * | |
161 | * These maps support four basic layouts: | |
162 | * | |
163 | * A/B/G: This is the "traditional" setup for a bootable disk. | |
164 | * A is the root partition, B the swap, and G a user partition. | |
165 | * A/D/H: This is a setup for bootable systems requiring more swap | |
166 | * (e.g. those who use HPCL). It has A as the root, D as a | |
167 | * larger swap, and H as a smaller user partition. | |
168 | * A/D/E/F: Similar to A/D/H with E and F breaking H into two partitions. | |
169 | * E could be used for /usr and F for users. | |
170 | * C: This gives a single, non-bootable, large user filesystem. | |
171 | * Good for second drives on a machine (e.g. /usr/src). | |
172 | */ | |
173 | struct size rd7945A_sizes[8] = { | |
174 | RDSZ(15904), 1, /* A=cyl 1 thru 142 */ | |
175 | RDSZ(20160), 143, /* B=cyl 143 thru 322 */ | |
176 | RDSZ(108416), 0, /* C=cyl 0 thru 967 */ | |
177 | RDSZ(40320), 143, /* D=cyl 143 thru 502 */ | |
178 | RDSZ(0), 0, /* E=<undefined> */ | |
179 | RDSZ(0), 0, /* F=<undefined> */ | |
180 | RDSZ(72240), 323, /* G=cyl 323 thru 967 */ | |
181 | RDSZ(52080), 503, /* H=cyl 503 thru 967 */ | |
182 | }, rd9134D_sizes[8] = { | |
183 | RDSZ(15936), 1, /* A=cyl 1 thru 166 */ | |
184 | RDSZ(13056), 167, /* B=cyl 167 thru 302 */ | |
185 | RDSZ(29088), 0, /* C=cyl 0 thru 302 */ | |
186 | RDSZ(0), 0, /* D=<undefined> */ | |
187 | RDSZ(0), 0, /* E=<undefined> */ | |
188 | RDSZ(0), 0, /* F=<undefined> */ | |
189 | RDSZ(0), 0, /* G=<undefined> */ | |
190 | RDSZ(0), 0, /* H=<undefined> */ | |
191 | }, rd9122S_sizes[8] = { | |
192 | RDSZ(0), 0, /* A=<undefined> */ | |
193 | RDSZ(0), 0, /* B=<undefined> */ | |
194 | RDSZ(1232), 0, /* C=cyl 0 thru 76 */ | |
195 | RDSZ(0), 0, /* D=<undefined> */ | |
196 | RDSZ(0), 0, /* E=<undefined> */ | |
197 | RDSZ(0), 0, /* F=<undefined> */ | |
198 | RDSZ(0), 0, /* G=<undefined> */ | |
199 | RDSZ(0), 0, /* H=<undefined> */ | |
200 | }, rd7912P_sizes[8] = { | |
201 | RDSZ(15904), 0, /* A=cyl 1 thru 71 */ | |
202 | RDSZ(22400), 72, /* B=cyl 72 thru 171 */ | |
203 | RDSZ(128128), 0, /* C=cyl 0 thru 571 */ | |
204 | RDSZ(42560), 72, /* D=cyl 72 thru 261 */ | |
205 | RDSZ(0), 292, /* E=<undefined> */ | |
206 | RDSZ(0), 542, /* F=<undefined> */ | |
207 | RDSZ(89600), 172, /* G=cyl 221 thru 571 */ | |
208 | RDSZ(69440), 262, /* H=cyl 262 thru 571 */ | |
209 | }, rd7914P_sizes[8] = { | |
210 | RDSZ(15904), 1, /* A=cyl 1 thru 71 */ | |
211 | RDSZ(40320), 72, /* B=cyl 72 thru 251 */ | |
212 | RDSZ(258048), 0, /* C=cyl 0 thru 1151 */ | |
213 | RDSZ(64960), 72, /* D=cyl 72 thru 361 */ | |
214 | RDSZ(98560), 362, /* E=cyl 362 thru 801 */ | |
215 | RDSZ(78400), 802, /* F=cyl 802 thru 1151 */ | |
216 | RDSZ(201600), 252, /* G=cyl 221 thru 1151 */ | |
217 | RDSZ(176960), 362, /* H=cyl 362 thru 1151 */ | |
218 | }, rd7933H_sizes[8] = { | |
219 | RDSZ(16146), 1, /* A=cyl 1 thru 27 */ | |
220 | RDSZ(66976), 28, /* B=cyl 28 thru 139 */ | |
221 | RDSZ(789958), 0, /* C=cyl 0 thru 1320 */ | |
222 | RDSZ(16146), 140, /* D=cyl 140 thru 166 */ | |
223 | RDSZ(165646), 167, /* E=cyl 167 thru 443 */ | |
224 | RDSZ(165646), 444, /* F=cyl 444 thru 720 */ | |
225 | RDSZ(706238), 140, /* G=cyl 140 thru 1320 */ | |
226 | RDSZ(358800), 721, /* H=cyl 721 thru 1320 */ | |
227 | }, rd9134L_sizes[8] = { | |
228 | RDSZ(15920), 1, /* A=cyl 1 thru 199 */ | |
229 | RDSZ(20000), 200, /* B=cyl 200 thru 449 */ | |
230 | RDSZ(77840), 0, /* C=cyl 0 thru 972 */ | |
231 | RDSZ(32000), 200, /* D=cyl 200 thru 599 */ | |
232 | RDSZ(0), 0, /* E=<undefined> */ | |
233 | RDSZ(0), 0, /* F=<undefined> */ | |
234 | RDSZ(41840), 450, /* G=cyl 450 thru 972 */ | |
235 | RDSZ(29840), 600, /* H=cyl 600 thru 972 */ | |
236 | }, rd7957A_sizes[8] = { | |
237 | RDSZ(16016), 1, /* A=cyl 1 thru 104 */ | |
238 | RDSZ(24640), 105, /* B=cyl 105 thru 264 */ | |
239 | RDSZ(159544), 0, /* C=cyl 0 thru 1035 */ | |
240 | RDSZ(42350), 105, /* D=cyl 105 thru 379 */ | |
241 | RDSZ(54824), 380, /* E=cyl 380 thru 735 */ | |
242 | RDSZ(46200), 736, /* F=cyl 736 thru 1035 */ | |
243 | RDSZ(118734), 265, /* G=cyl 265 thru 1035 */ | |
244 | RDSZ(101024), 380, /* H=cyl 380 thru 1035 */ | |
245 | }, rd7958A_sizes[8] = { | |
246 | RDSZ(16128), 1, /* A=cyl 1 thru 64 */ | |
247 | RDSZ(32256), 65, /* B=cyl 65 thru 192 */ | |
248 | RDSZ(255276), 0, /* C=cyl 0 thru 1012 */ | |
249 | RDSZ(48384), 65, /* D=cyl 65 thru 256 */ | |
250 | RDSZ(100800), 257, /* E=cyl 257 thru 656 */ | |
251 | RDSZ(89712), 657, /* F=cyl 657 thru 1012 */ | |
252 | RDSZ(206640), 193, /* G=cyl 193 thru 1012 */ | |
253 | RDSZ(190512), 257, /* H=cyl 257 thru 1012 */ | |
254 | }, rd7957B_sizes[8] = { | |
255 | RDSZ(16002), 1, /* A=cyl 1 thru 127 */ | |
256 | RDSZ(32760), 128, /* B=cyl 128 thru 387 */ | |
257 | RDSZ(159894), 0, /* C=cyl 0 thru 1268 */ | |
258 | RDSZ(49140), 128, /* D=cyl 128 thru 517 */ | |
259 | RDSZ(50400), 518, /* E=cyl 518 thru 917 */ | |
260 | RDSZ(44226), 918, /* F=cyl 918 thru 1268 */ | |
261 | RDSZ(111006), 388, /* G=cyl 388 thru 1268 */ | |
262 | RDSZ(94626), 518, /* H=cyl 518 thru 1268 */ | |
263 | }, rd7958B_sizes[8] = { | |
264 | RDSZ(16254), 1, /* A=cyl 1 thru 43 */ | |
265 | RDSZ(32886), 44, /* B=cyl 44 thru 130 */ | |
266 | RDSZ(297108), 0, /* C=cyl 0 thru 785 */ | |
267 | RDSZ(49140), 44, /* D=cyl 44 thru 173 */ | |
268 | RDSZ(121716), 174, /* E=cyl 174 thru 495 */ | |
269 | RDSZ(109620), 496, /* F=cyl 496 thru 785 */ | |
270 | RDSZ(247590), 131, /* G=cyl 131 thru 785 */ | |
271 | RDSZ(231336), 174, /* H=cyl 174 thru 785 */ | |
272 | }, rd7959B_sizes[8] = { | |
273 | RDSZ(16254), 1, /* A=cyl 1 thru 43 */ | |
274 | RDSZ(49140), 44, /* B=cyl 44 thru 173 */ | |
275 | RDSZ(594216), 0, /* C=cyl 0 thru 1571 */ | |
276 | RDSZ(65772), 44, /* D=cyl 44 thru 217 */ | |
277 | RDSZ(303912), 218, /* E=cyl 218 thru 1021 */ | |
278 | RDSZ(207900), 1022, /* F=cyl 1022 thru 1571 */ | |
279 | RDSZ(528444), 174, /* G=cyl 174 thru 1571 */ | |
280 | RDSZ(511812), 218, /* H=cyl 218 thru 1571 */ | |
281 | ||
282 | #if DEV_BSIZE == 512 | |
283 | /* | |
284 | * These values would not work for 1k, | |
285 | * since the number of cylinders would be different. | |
286 | */ | |
287 | }, rd7936H_sizes[8] = { | |
288 | RDSZ(16359), 1, /* A=cyl 1 thru 19 */ | |
289 | RDSZ(67158), 20, /* B=cyl 20 thru 97 */ | |
290 | RDSZ(600978), 0, /* C=cyl 0 thru 697 */ | |
291 | RDSZ(16359), 98, /* D=cyl 98 thru 116 */ | |
292 | RDSZ(120540), 117, /* E=cyl 117 thru 256 */ | |
293 | RDSZ(120540), 256, /* F=cyl 256 thru 396 */ | |
294 | RDSZ(516600), 98, /* G=cyl 98 thru 697 */ | |
295 | RDSZ(259161), 397, /* H=cyl 397 thru 697 */ | |
296 | }, rd7937H_sizes[8] = { | |
297 | #ifdef UTAH | |
298 | RDSZ(15990), 1, /* A=cyl 1 thru 10 */ | |
299 | RDSZ(67158), 11, /* B=cyl 11 thru 52 */ | |
300 | RDSZ(1116102), 0, /* C=cyl 0 thru 697 */ | |
301 | RDSZ(124722), 53, /* D=cyl 53 thru 130 */ | |
302 | RDSZ(163098), 131, /* E=cyl 131 thru 232 */ | |
303 | RDSZ(287820), 233, /* F=cyl 233 thru 412 */ | |
304 | RDSZ(1031355), 53, /* G=cyl 53 thru 697 */ | |
305 | RDSZ(455715), 413, /* H=cyl 413 thru 697 */ | |
306 | #else | |
307 | RDSZ(15990), 1, /* A=cyl 1 thru 10 */ | |
308 | RDSZ(67158), 11, /* B=cyl 11 thru 52 */ | |
309 | RDSZ(1116102), 0, /* C=cyl 0 thru 697 */ | |
310 | RDSZ(15990), 53, /* D=cyl 53 thru 62 */ | |
311 | RDSZ(246246), 63, /* E=cyl 63 thru 216 */ | |
312 | RDSZ(246246), 217, /* F=cyl 217 thru 370 */ | |
313 | RDSZ(1031355), 53, /* G=cyl 53 thru 697 */ | |
314 | RDSZ(522873), 371, /* H=cyl 371 thru 697 */ | |
315 | #endif | |
316 | #endif | |
317 | }; | |
318 | ||
319 | struct rdinfo { | |
320 | int nbpt; /* DEV_BSIZE blocks per track */ | |
321 | int ntpc; /* tracks per cylinder */ | |
322 | int nbpc; /* blocks per cylinder */ | |
323 | struct size *sizes; /* default partition info (if no disklabel) */ | |
324 | short hwid; /* 2 byte HW id */ | |
325 | short maxunum; /* maximum allowed unit number */ | |
326 | char *desc; /* drive type description */ | |
327 | }; | |
328 | ||
329 | struct rdinfo rdinfo[] = { | |
330 | NRD7945ABPT, NRD7945ATRK, NRD7945ABPT * NRD7945ATRK, | |
331 | rd7945A_sizes, RD7946AID, 0, "7945A", | |
332 | NRD9134DBPT, NRD9134DTRK, NRD9134DBPT * NRD9134DTRK, | |
333 | rd9134D_sizes, RD9134DID, 1, "9134D", | |
334 | NRD9122SBPT, NRD9122STRK, NRD9122SBPT * NRD9122STRK, | |
335 | rd9122S_sizes, RD9134LID, 1, "9122S", | |
336 | NRD7912PBPT, NRD7912PTRK, NRD7912PBPT * NRD7912PTRK, | |
337 | rd7912P_sizes, RD7912PID, 0, "7912P", | |
338 | NRD7914PBPT, NRD7914PTRK, NRD7914PBPT * NRD7914PTRK, | |
339 | rd7914P_sizes, RD7914PID, 0, "7914P", | |
340 | NRD7958ABPT, NRD7958ATRK, NRD7958ABPT * NRD7958ATRK, | |
341 | rd7958A_sizes, RD7958AID, 0, "7958A", | |
342 | NRD7957ABPT, NRD7957ATRK, NRD7957ABPT * NRD7957ATRK, | |
343 | rd7957A_sizes, RD7957AID, 0, "7957A", | |
344 | NRD7933HBPT, NRD7933HTRK, NRD7933HBPT * NRD7933HTRK, | |
345 | rd7933H_sizes, RD7933HID, 0, "7933H", | |
346 | NRD9134LBPT, NRD9134LTRK, NRD9134LBPT * NRD9134LTRK, | |
347 | rd9134L_sizes, RD9134LID, 1, "9134L", | |
348 | NRD7936HBPT, NRD7936HTRK, NRD7936HBPT * NRD7936HTRK, | |
349 | rd7936H_sizes, RD7936HID, 0, "7936H", | |
350 | NRD7937HBPT, NRD7937HTRK, NRD7937HBPT * NRD7937HTRK, | |
351 | rd7937H_sizes, RD7937HID, 0, "7937H", | |
352 | NRD7914PBPT, NRD7914PTRK, NRD7914PBPT * NRD7914PTRK, | |
353 | rd7914P_sizes, RD7914CTID, 0, "7914CT", | |
354 | NRD7945ABPT, NRD7945ATRK, NRD7945ABPT * NRD7945ATRK, | |
355 | rd7945A_sizes, RD7946AID, 0, "7946A", | |
356 | NRD9122SBPT, NRD9122STRK, NRD9122SBPT * NRD9122STRK, | |
357 | rd9122S_sizes, RD9134LID, 1, "9122D", | |
358 | NRD7957BBPT, NRD7957BTRK, NRD7957BBPT * NRD7957BTRK, | |
359 | rd7957B_sizes, RD7957BID, 0, "7957B", | |
360 | NRD7958BBPT, NRD7958BTRK, NRD7958BBPT * NRD7958BTRK, | |
361 | rd7958B_sizes, RD7958BID, 0, "7958B", | |
362 | NRD7959BBPT, NRD7959BTRK, NRD7959BBPT * NRD7959BTRK, | |
363 | rd7959B_sizes, RD7959BID, 0, "7959B", | |
364 | }; | |
365 | int nrdinfo = sizeof(rdinfo) / sizeof(rdinfo[0]); | |
366 | ||
367 | struct buf rdtab[NRD]; | |
368 | struct buf rdbuf[NRD]; | |
369 | ||
370 | #define rdunit(x) ((minor(x) >> 3) & 0xf) | |
371 | #define rdpart(x) (minor(x) & 0x7) | |
372 | #define rdpunit(x) ((x) & 7) | |
373 | #define b_cylin b_resid | |
374 | #define RDRETRY 5 | |
375 | #define RDWAITC 1 /* min time for timeout in seconds */ | |
376 | ||
339a5f2c KM |
377 | int rderrthresh = RDRETRY-1; /* when to start reporting errors */ |
378 | ||
60f56dfc KM |
379 | rdinit(hd) |
380 | register struct hp_device *hd; | |
381 | { | |
382 | register struct rd_softc *rs = &rd_softc[hd->hp_unit]; | |
383 | ||
384 | rs->sc_hd = hd; | |
385 | rs->sc_punit = rdpunit(hd->hp_flags); | |
386 | rs->sc_type = rdident(rs, hd); | |
387 | if (rs->sc_type < 0) | |
388 | return(0); | |
389 | rs->sc_dq.dq_ctlr = hd->hp_ctlr; | |
390 | rs->sc_dq.dq_unit = hd->hp_unit; | |
391 | rs->sc_dq.dq_slave = hd->hp_slave; | |
392 | rs->sc_dq.dq_driver = &rddriver; | |
393 | rs->sc_info = &rdinfo[rs->sc_type]; | |
394 | rs->sc_flags = RDF_ALIVE; | |
339a5f2c KM |
395 | #ifdef DEBUG |
396 | /* always report errors */ | |
397 | if (rddebug & RDB_ERROR) | |
398 | rderrthresh = 0; | |
399 | #endif | |
60f56dfc KM |
400 | return(1); |
401 | } | |
402 | ||
403 | rdident(rs, hd) | |
404 | struct rd_softc *rs; | |
405 | struct hp_device *hd; | |
406 | { | |
407 | struct rd_describe desc; | |
408 | u_char stat, cmd[3]; | |
409 | int unit, lunit; | |
410 | char name[7]; | |
411 | register int ctlr, slave, id, i; | |
412 | ||
413 | ctlr = hd->hp_ctlr; | |
414 | slave = hd->hp_slave; | |
415 | unit = rs->sc_punit; | |
416 | lunit = hd->hp_unit; | |
417 | ||
418 | /* | |
419 | * Grab device id and make sure: | |
420 | * 1. It is a CS80 device. | |
421 | * 2. It is one of the types we support. | |
422 | * 3. If it is a 7946, we are accessing the disk unit (0) | |
423 | */ | |
424 | id = hpibid(ctlr, slave); | |
425 | if ((id & 0x200) == 0) | |
426 | return(-1); | |
427 | for (i = 0; i < nrdinfo; i++) | |
428 | if (id == rdinfo[i].hwid) | |
429 | break; | |
430 | if (i == nrdinfo || unit > rdinfo[i].maxunum) | |
431 | return(-1); | |
432 | id = i; | |
433 | ||
434 | /* | |
435 | * Reset drive and collect device description. | |
436 | * Don't really use the description info right now but | |
437 | * might come in handy in the future (for disk labels). | |
438 | */ | |
439 | rdreset(rs, hd); | |
440 | cmd[0] = C_SUNIT(unit); | |
441 | cmd[1] = C_SVOL(0); | |
442 | cmd[2] = C_DESC; | |
443 | hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd)); | |
444 | hpibrecv(ctlr, slave, C_EXEC, &desc, 37); | |
445 | hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat)); | |
446 | bzero(name, sizeof(name)); | |
447 | if (!stat) { | |
448 | register int n = desc.d_name; | |
449 | for (i = 5; i >= 0; i--) { | |
450 | name[i] = (n & 0xf) + '0'; | |
451 | n >>= 4; | |
452 | } | |
339a5f2c KM |
453 | /* use drive characteristics to calculate xfer rate */ |
454 | rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime; | |
60f56dfc KM |
455 | } |
456 | #ifdef DEBUG | |
457 | if (rddebug & RDB_IDENT) { | |
458 | printf("rd%d: name: %x ('%s')\n", | |
459 | lunit, desc.d_name, name); | |
460 | printf(" iuw %x, maxxfr %d, ctype %d\n", | |
461 | desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype); | |
462 | printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n", | |
463 | desc.d_utype, desc.d_sectsize, | |
464 | desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime); | |
465 | printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n", | |
466 | desc.d_uavexfr, desc.d_retry, desc.d_access, | |
467 | desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte); | |
468 | printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n", | |
469 | desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect, | |
470 | desc.d_maxvsectl, desc.d_interleave); | |
471 | } | |
472 | #endif | |
473 | /* | |
474 | * Take care of a couple of anomolies: | |
475 | * 1. 7945A and 7946A both return same HW id | |
476 | * 2. 9122S and 9134D both return same HW id | |
477 | * 3. 9122D and 9134L both return same HW id | |
478 | */ | |
479 | switch (rdinfo[id].hwid) { | |
480 | case RD7946AID: | |
481 | if (bcmp(name, "079450", 6) == 0) | |
482 | id = RD7945A; | |
483 | else | |
484 | id = RD7946A; | |
485 | break; | |
486 | ||
487 | case RD9134LID: | |
488 | if (bcmp(name, "091340", 6) == 0) | |
489 | id = RD9134L; | |
490 | else | |
491 | id = RD9122D; | |
492 | break; | |
493 | ||
494 | case RD9134DID: | |
495 | if (bcmp(name, "091220", 6) == 0) | |
496 | id = RD9122S; | |
497 | else | |
498 | id = RD9134D; | |
499 | break; | |
500 | } | |
501 | printf("rd%d: %s\n", lunit, rdinfo[id].desc); | |
502 | return(id); | |
503 | } | |
504 | ||
505 | rdreset(rs, hd) | |
506 | register struct rd_softc *rs; | |
507 | register struct hp_device *hd; | |
508 | { | |
509 | u_char stat; | |
510 | ||
511 | rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit); | |
512 | rs->sc_clear.c_cmd = C_CLEAR; | |
513 | hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear, | |
514 | sizeof(rs->sc_clear)); | |
515 | hpibswait(hd->hp_ctlr, hd->hp_slave); | |
516 | hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); | |
517 | rs->sc_src.c_unit = C_SUNIT(RDCTLR); | |
518 | rs->sc_src.c_nop = C_NOP; | |
519 | rs->sc_src.c_cmd = C_SREL; | |
520 | rs->sc_src.c_param = C_REL; | |
521 | hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src, | |
522 | sizeof(rs->sc_src)); | |
523 | hpibswait(hd->hp_ctlr, hd->hp_slave); | |
524 | hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); | |
525 | rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit); | |
526 | rs->sc_ssmc.c_cmd = C_SSM; | |
527 | rs->sc_ssmc.c_refm = REF_MASK; | |
528 | rs->sc_ssmc.c_fefm = FEF_MASK; | |
529 | rs->sc_ssmc.c_aefm = AEF_MASK; | |
530 | rs->sc_ssmc.c_iefm = IEF_MASK; | |
531 | hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc, | |
532 | sizeof(rs->sc_ssmc)); | |
533 | hpibswait(hd->hp_ctlr, hd->hp_slave); | |
534 | hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat)); | |
535 | #ifdef DEBUG | |
536 | rdstats[hd->hp_unit].rdresets++; | |
537 | #endif | |
538 | } | |
539 | ||
540 | /*ARGSUSED*/ | |
541 | rdopen(dev, flags) | |
542 | dev_t dev; | |
543 | { | |
544 | register int unit = rdunit(dev); | |
545 | register struct rd_softc *rs = &rd_softc[unit]; | |
546 | ||
547 | if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) | |
548 | return(ENXIO); | |
339a5f2c KM |
549 | if (rs->sc_hd->hp_dk >= 0) { |
550 | /* guess at xfer rate based on 3600 rpm (60 rps) */ | |
551 | if (rs->sc_wpms == 0) | |
552 | rs->sc_wpms = 60 * rs->sc_info->nbpt * DEV_BSIZE / 2; | |
553 | dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms; | |
554 | } | |
60f56dfc KM |
555 | return(0); |
556 | } | |
557 | ||
558 | rdstrategy(bp) | |
559 | register struct buf *bp; | |
560 | { | |
561 | register int part = rdpart(bp->b_dev); | |
562 | register int unit = rdunit(bp->b_dev); | |
563 | register int bn, sz; | |
564 | register struct rd_softc *rs = &rd_softc[unit]; | |
565 | register struct buf *dp = &rdtab[unit]; | |
566 | int s; | |
567 | ||
568 | #ifdef DEBUG | |
569 | if (rddebug & RDB_FOLLOW) | |
570 | printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n", | |
571 | bp, bp->b_dev, bp->b_blkno, bp->b_bcount, | |
572 | (bp->b_flags & B_READ) ? 'R' : 'W'); | |
573 | #endif | |
574 | bn = bp->b_blkno; | |
575 | sz = (bp->b_bcount + (DEV_BSIZE - 1)) >> DEV_BSHIFT; | |
576 | if (bn < 0 || bn + sz > rs->sc_info->sizes[part].nblocks) { | |
577 | if (bn == rs->sc_info->sizes[part].nblocks) { | |
578 | bp->b_resid = bp->b_bcount; | |
579 | goto done; | |
580 | } | |
581 | bp->b_error = EINVAL; | |
582 | goto bad; | |
583 | } | |
584 | bp->b_cylin = bn / rs->sc_info->nbpc + rs->sc_info->sizes[part].cyloff; | |
585 | s = splbio(); | |
586 | disksort(dp, bp); | |
587 | if (dp->b_active == 0) { | |
588 | dp->b_active = 1; | |
589 | rdustart(unit); | |
590 | } | |
591 | splx(s); | |
592 | return; | |
593 | bad: | |
594 | bp->b_flags |= B_ERROR; | |
595 | done: | |
596 | biodone(bp); | |
597 | } | |
598 | ||
599 | /* | |
600 | * Called from timeout() when handling maintenance releases | |
601 | */ | |
602 | rdrestart(unit) | |
603 | int unit; | |
604 | { | |
605 | int s = splbio(); | |
606 | rdustart(unit); | |
607 | splx(s); | |
608 | } | |
609 | ||
610 | rdustart(unit) | |
611 | register int unit; | |
612 | { | |
613 | register struct buf *bp; | |
614 | register struct rd_softc *rs = &rd_softc[unit]; | |
615 | ||
616 | bp = rdtab[unit].b_actf; | |
617 | rs->sc_addr = bp->b_un.b_addr; | |
618 | rs->sc_resid = bp->b_bcount; | |
619 | if (hpibreq(&rs->sc_dq)) | |
620 | rdstart(unit); | |
621 | } | |
622 | ||
623 | rdstart(unit) | |
624 | register int unit; | |
625 | { | |
626 | register struct rd_softc *rs = &rd_softc[unit]; | |
627 | register struct buf *bp = rdtab[unit].b_actf; | |
628 | register struct hp_device *hp = rs->sc_hd; | |
629 | register int part; | |
630 | ||
631 | again: | |
632 | #ifdef DEBUG | |
633 | if (rddebug & RDB_FOLLOW) | |
634 | printf("rdstart(%d): bp %x, %c\n", unit, bp, | |
635 | (bp->b_flags & B_READ) ? 'R' : 'W'); | |
636 | #endif | |
637 | part = rdpart(bp->b_dev); | |
638 | rs->sc_flags |= RDF_SEEK; | |
639 | rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); | |
640 | rs->sc_ioc.c_volume = C_SVOL(0); | |
641 | rs->sc_ioc.c_saddr = C_SADDR; | |
642 | rs->sc_ioc.c_hiaddr = 0; | |
643 | rs->sc_ioc.c_addr = RDBTOS(bp->b_blkno + rs->sc_info->nbpc * | |
644 | rs->sc_info->sizes[part].cyloff); | |
645 | rs->sc_ioc.c_nop2 = C_NOP; | |
646 | rs->sc_ioc.c_slen = C_SLEN; | |
647 | rs->sc_ioc.c_len = rs->sc_resid; | |
648 | rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE; | |
649 | #ifdef DEBUG | |
650 | if (rddebug & RDB_IO) | |
651 | printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n", | |
652 | hp->hp_ctlr, hp->hp_slave, C_CMD, | |
653 | &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); | |
654 | #endif | |
655 | if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit, | |
656 | sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) { | |
657 | if (hp->hp_dk >= 0) { | |
658 | dk_busy |= 1 << hp->hp_dk; | |
659 | dk_seek[hp->hp_dk]++; | |
660 | } | |
661 | #ifdef DEBUG | |
662 | if (rddebug & RDB_IO) | |
663 | printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr); | |
664 | #endif | |
665 | hpibawait(hp->hp_ctlr); | |
666 | return; | |
667 | } | |
668 | /* | |
669 | * Experience has shown that the hpibwait in this hpibsend will | |
670 | * occasionally timeout. It appears to occur mostly on old 7914 | |
671 | * drives with full maintenance tracks. We should probably | |
672 | * integrate this with the backoff code in rderror. | |
673 | */ | |
674 | #ifdef DEBUG | |
675 | if (rddebug & RDB_ERROR) | |
676 | printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n", | |
677 | unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, | |
678 | bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt); | |
679 | rdstats[unit].rdretries++; | |
680 | #endif | |
681 | rs->sc_flags &= ~RDF_SEEK; | |
682 | rdreset(rs, hp); | |
683 | if (rdtab[unit].b_errcnt++ < RDRETRY) | |
684 | goto again; | |
685 | printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n", | |
686 | unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr, | |
687 | bp->b_blkno, rs->sc_resid); | |
688 | rdtab[unit].b_errcnt = 0; | |
689 | rdtab[unit].b_actf = bp->b_actf; | |
690 | bp->b_flags |= B_ERROR; | |
691 | bp->b_error = EIO; | |
692 | bp->b_resid = 0; | |
693 | biodone(bp); | |
694 | hpibfree(&rs->sc_dq); | |
695 | bp = rdtab[unit].b_actf; | |
696 | if (bp == NULL) { | |
697 | rdtab[unit].b_active = 0; | |
698 | return; | |
699 | } | |
700 | rs->sc_addr = bp->b_un.b_addr; | |
701 | rs->sc_resid = bp->b_bcount; | |
702 | if (hpibreq(&rs->sc_dq)) | |
703 | goto again; | |
704 | } | |
705 | ||
706 | rdgo(unit) | |
707 | register int unit; | |
708 | { | |
709 | register struct rd_softc *rs = &rd_softc[unit]; | |
710 | register struct hp_device *hp = rs->sc_hd; | |
711 | struct buf *bp = rdtab[unit].b_actf; | |
712 | ||
713 | if (hp->hp_dk >= 0) { | |
714 | dk_busy |= 1 << hp->hp_dk; | |
715 | dk_xfer[hp->hp_dk]++; | |
716 | dk_wds[hp->hp_dk] += rs->sc_resid >> 6; | |
717 | } | |
718 | hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC, | |
719 | rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ); | |
720 | } | |
721 | ||
722 | rdintr(unit) | |
723 | register int unit; | |
724 | { | |
725 | register struct rd_softc *rs = &rd_softc[unit]; | |
726 | register struct buf *bp = rdtab[unit].b_actf; | |
727 | register struct hp_device *hp = rs->sc_hd; | |
728 | u_char stat = 13; /* in case hpibrecv fails */ | |
729 | int restart; | |
730 | ||
731 | #ifdef DEBUG | |
732 | if (rddebug & RDB_FOLLOW) | |
733 | printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp, | |
734 | (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags); | |
735 | if (bp == NULL) { | |
736 | printf("rd%d: bp == NULL\n", unit); | |
737 | return; | |
738 | } | |
739 | #endif | |
740 | if (hp->hp_dk >= 0) | |
741 | dk_busy &= ~(1 << hp->hp_dk); | |
742 | if (rs->sc_flags & RDF_SEEK) { | |
743 | rs->sc_flags &= ~RDF_SEEK; | |
744 | if (hpibustart(hp->hp_ctlr)) | |
745 | rdgo(unit); | |
746 | return; | |
747 | } | |
748 | if ((rs->sc_flags & RDF_SWAIT) == 0) { | |
749 | #ifdef DEBUG | |
750 | rdstats[unit].rdpolltries++; | |
751 | #endif | |
752 | if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) { | |
753 | #ifdef DEBUG | |
754 | rdstats[unit].rdpollwaits++; | |
755 | #endif | |
756 | if (hp->hp_dk >= 0) | |
757 | dk_busy |= 1 << hp->hp_dk; | |
758 | rs->sc_flags |= RDF_SWAIT; | |
759 | hpibawait(hp->hp_ctlr); | |
760 | return; | |
761 | } | |
762 | } else | |
763 | rs->sc_flags &= ~RDF_SWAIT; | |
764 | if (!hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1) || stat) { | |
765 | #ifdef DEBUG | |
766 | if (rddebug & RDB_ERROR) | |
767 | printf("rdintr: recv failed or bad stat %d\n", stat); | |
768 | #endif | |
769 | restart = rderror(unit); | |
770 | #ifdef DEBUG | |
771 | rdstats[unit].rdretries++; | |
772 | #endif | |
773 | if (rdtab[unit].b_errcnt++ < RDRETRY) { | |
774 | if (restart) | |
775 | rdstart(unit); | |
776 | return; | |
777 | } | |
778 | bp->b_flags |= B_ERROR; | |
779 | bp->b_error = EIO; | |
780 | } | |
781 | rdtab[unit].b_errcnt = 0; | |
782 | rdtab[unit].b_actf = bp->b_actf; | |
783 | bp->b_resid = 0; | |
784 | biodone(bp); | |
785 | hpibfree(&rs->sc_dq); | |
786 | if (rdtab[unit].b_actf) | |
787 | rdustart(unit); | |
788 | else | |
789 | rdtab[unit].b_active = 0; | |
790 | } | |
791 | ||
792 | rdstatus(rs) | |
793 | register struct rd_softc *rs; | |
794 | { | |
795 | register int c, s; | |
796 | u_char stat; | |
797 | int rv; | |
798 | ||
799 | c = rs->sc_hd->hp_ctlr; | |
800 | s = rs->sc_hd->hp_slave; | |
801 | rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit); | |
802 | rs->sc_rsc.c_sram = C_SRAM; | |
803 | rs->sc_rsc.c_ram = C_RAM; | |
804 | rs->sc_rsc.c_cmd = C_STATUS; | |
805 | bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat)); | |
806 | rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc)); | |
807 | if (rv != sizeof(rs->sc_rsc)) { | |
808 | #ifdef DEBUG | |
809 | if (rddebug & RDB_STATUS) | |
810 | printf("rdstatus: send C_CMD failed %d != %d\n", | |
811 | rv, sizeof(rs->sc_rsc)); | |
812 | #endif | |
813 | return(1); | |
814 | } | |
815 | rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat)); | |
816 | if (rv != sizeof(rs->sc_stat)) { | |
817 | #ifdef DEBUG | |
818 | if (rddebug & RDB_STATUS) | |
819 | printf("rdstatus: send C_EXEC failed %d != %d\n", | |
820 | rv, sizeof(rs->sc_stat)); | |
821 | #endif | |
822 | return(1); | |
823 | } | |
824 | rv = hpibrecv(c, s, C_QSTAT, &stat, 1); | |
825 | if (rv != 1 || stat) { | |
826 | #ifdef DEBUG | |
827 | if (rddebug & RDB_STATUS) | |
828 | printf("rdstatus: recv failed %d or bad stat %d\n", | |
829 | rv, stat); | |
830 | #endif | |
831 | return(1); | |
832 | } | |
833 | return(0); | |
834 | } | |
835 | ||
836 | /* | |
837 | * Deal with errors. | |
838 | * Returns 1 if request should be restarted, | |
839 | * 0 if we should just quietly give up. | |
840 | */ | |
841 | rderror(unit) | |
842 | int unit; | |
843 | { | |
844 | struct rd_softc *rs = &rd_softc[unit]; | |
845 | register struct rd_stat *sp; | |
846 | struct buf *bp; | |
339a5f2c | 847 | daddr_t hwbn, pbn; |
60f56dfc KM |
848 | |
849 | if (rdstatus(rs)) { | |
850 | #ifdef DEBUG | |
851 | printf("rd%d: couldn't get status\n", unit); | |
852 | #endif | |
853 | rdreset(rs, rs->sc_hd); | |
854 | return(1); | |
855 | } | |
856 | sp = &rs->sc_stat; | |
857 | if (sp->c_fef & FEF_REXMT) | |
858 | return(1); | |
859 | if (sp->c_fef & FEF_PF) { | |
860 | rdreset(rs, rs->sc_hd); | |
861 | return(1); | |
862 | } | |
863 | /* | |
864 | * Unit requests release for internal maintenance. | |
865 | * We just delay awhile and try again later. Use expontially | |
866 | * increasing backoff ala ethernet drivers since we don't really | |
867 | * know how long the maintenance will take. With RDWAITC and | |
868 | * RDRETRY as defined, the range is 1 to 32 seconds. | |
869 | */ | |
870 | if (sp->c_fef & FEF_IMR) { | |
871 | extern int hz; | |
872 | int rdtimo = RDWAITC << rdtab[unit].b_errcnt; | |
873 | #ifdef DEBUG | |
874 | printf("rd%d: internal maintenance, %d second timeout\n", | |
875 | unit, rdtimo); | |
876 | rdstats[unit].rdtimeouts++; | |
877 | #endif | |
878 | hpibfree(&rs->sc_dq); | |
879 | timeout(rdrestart, unit, rdtimo*hz); | |
880 | return(0); | |
881 | } | |
339a5f2c KM |
882 | /* |
883 | * Only report error if we have reached the error reporting | |
884 | * threshhold. By default, this will only report after the | |
885 | * retry limit has been exceeded. | |
886 | */ | |
887 | if (rdtab[unit].b_errcnt < rderrthresh) | |
888 | return(1); | |
889 | ||
60f56dfc KM |
890 | /* |
891 | * First conjure up the block number at which the error occured. | |
892 | * Note that not all errors report a block number, in that case | |
893 | * we just use b_blkno. | |
894 | */ | |
339a5f2c KM |
895 | bp = rdtab[unit].b_actf; |
896 | pbn = rs->sc_info->nbpc * | |
897 | rs->sc_info->sizes[rdpart(bp->b_dev)].cyloff; | |
60f56dfc KM |
898 | if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) || |
899 | (sp->c_ief & IEF_RRMASK)) { | |
339a5f2c | 900 | hwbn = RDBTOS(pbn + bp->b_blkno); |
60f56dfc KM |
901 | pbn = bp->b_blkno; |
902 | } else { | |
339a5f2c KM |
903 | hwbn = sp->c_blk; |
904 | pbn = RDSTOB(hwbn) - pbn; | |
60f56dfc KM |
905 | } |
906 | /* | |
907 | * Now output a generic message suitable for badsect. | |
908 | * Note that we don't use harderr cuz it just prints | |
909 | * out b_blkno which is just the beginning block number | |
910 | * of the transfer, not necessary where the error occured. | |
911 | */ | |
912 | printf("rd%d%c: hard error sn%d\n", | |
913 | rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn); | |
914 | /* | |
915 | * Now report the status as returned by the hardware with | |
916 | * attempt at interpretation (unless debugging). | |
917 | */ | |
918 | printf("rd%d %s error:", | |
919 | unit, (bp->b_flags & B_READ) ? "read" : "write"); | |
920 | #ifdef DEBUG | |
921 | if (rddebug & RDB_ERROR) { | |
922 | /* status info */ | |
923 | printf("\n volume: %d, unit: %d\n", | |
924 | (sp->c_vu>>4)&0xF, sp->c_vu&0xF); | |
925 | rdprinterr("reject", sp->c_ref, err_reject); | |
926 | rdprinterr("fault", sp->c_fef, err_fault); | |
927 | rdprinterr("access", sp->c_aef, err_access); | |
928 | rdprinterr("info", sp->c_ief, err_info); | |
339a5f2c | 929 | printf(" block: %d, P1-P10: ", hwbn); |
60f56dfc KM |
930 | printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); |
931 | printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); | |
932 | printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); | |
933 | /* command */ | |
934 | printf(" ioc: "); | |
935 | printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8)); | |
936 | printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4)); | |
937 | printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8)); | |
938 | printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4)); | |
939 | printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8)); | |
940 | printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4)); | |
941 | return(1); | |
942 | } | |
943 | #endif | |
944 | printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n", | |
945 | (sp->c_vu>>4)&0xF, sp->c_vu&0xF, | |
946 | sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief); | |
947 | printf("P1-P10: "); | |
948 | printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8)); | |
949 | printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8)); | |
950 | printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4)); | |
951 | return(1); | |
952 | } | |
953 | ||
954 | rdread(dev, uio) | |
955 | dev_t dev; | |
956 | struct uio *uio; | |
957 | { | |
958 | register int unit = rdunit(dev); | |
959 | ||
960 | return(physio(rdstrategy, &rdbuf[unit], dev, B_READ, minphys, uio)); | |
961 | } | |
962 | ||
963 | rdwrite(dev, uio) | |
964 | dev_t dev; | |
965 | struct uio *uio; | |
966 | { | |
967 | register int unit = rdunit(dev); | |
968 | ||
969 | return(physio(rdstrategy, &rdbuf[unit], dev, B_WRITE, minphys, uio)); | |
970 | } | |
971 | ||
972 | /*ARGSUSED*/ | |
973 | rdioctl(dev, cmd, data, flag) | |
974 | dev_t dev; | |
975 | int cmd; | |
976 | caddr_t data; | |
977 | int flag; | |
978 | { | |
979 | return(EINVAL); | |
980 | } | |
981 | ||
982 | rdsize(dev) | |
983 | dev_t dev; | |
984 | { | |
985 | register int unit = rdunit(dev); | |
986 | register struct rd_softc *rs = &rd_softc[unit]; | |
987 | ||
988 | if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) | |
989 | return(-1); | |
990 | return(rs->sc_info->sizes[rdpart(dev)].nblocks); | |
991 | } | |
992 | ||
993 | #ifdef DEBUG | |
994 | rdprinterr(str, err, tab) | |
995 | char *str; | |
996 | short err; | |
997 | char *tab[]; | |
998 | { | |
999 | register int i; | |
1000 | int printed; | |
1001 | ||
1002 | if (err == 0) | |
1003 | return; | |
1004 | printf(" %s error field:", str, err); | |
1005 | printed = 0; | |
1006 | for (i = 0; i < 16; i++) | |
1007 | if (err & (0x8000 >> i)) | |
1008 | printf("%s%s", printed++ ? " + " : " ", tab[i]); | |
1009 | printf("\n"); | |
1010 | } | |
1011 | #endif | |
1012 | ||
1013 | #include "machine/pte.h" | |
1014 | #include "machine/vmparam.h" | |
029e208f | 1015 | #include "../sys/vmmac.h" |
60f56dfc KM |
1016 | |
1017 | /* | |
1018 | * Non-interrupt driven, non-dma dump routine. | |
1019 | */ | |
1020 | rddump(dev) | |
1021 | dev_t dev; | |
1022 | { | |
1023 | int part = rdpart(dev); | |
1024 | int unit = rdunit(dev); | |
1025 | register struct rd_softc *rs = &rd_softc[unit]; | |
1026 | register struct hp_device *hp = rs->sc_hd; | |
1027 | register daddr_t baddr; | |
1028 | register int maddr; | |
1029 | register int pages, i; | |
1030 | char stat; | |
1031 | extern int lowram, dumpsize; | |
1032 | ||
1033 | pages = dumpsize; | |
1034 | #ifdef DEBUG | |
1035 | if (rddebug & RDB_DUMP) | |
1036 | printf("rddump(%x): u %d p %d dumplo %d ram %x pmem %d\n", | |
1037 | dev, unit, part, dumplo, lowram, ctod(pages)); | |
1038 | #endif | |
1039 | /* is drive ok? */ | |
1040 | if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0) | |
1041 | return (ENXIO); | |
1042 | /* HPIB idle? */ | |
1043 | if (!hpibreq(&rs->sc_dq)) { | |
1044 | #ifdef DEBUG | |
1045 | /* is this a safe thing to do?? */ | |
1046 | hpibreset(hp->hp_ctlr); | |
1047 | rdreset(rs, rs->sc_hd); | |
1048 | printf("[ drive %d reset ] ", unit); | |
1049 | #else | |
1050 | return (EFAULT); | |
1051 | #endif | |
1052 | } | |
1053 | /* dump parameters in range? */ | |
1054 | if (dumplo < 0 || dumplo >= rs->sc_info->sizes[part].nblocks) | |
1055 | return (EINVAL); | |
1056 | if (dumplo + ctod(pages) > rs->sc_info->sizes[part].nblocks) | |
1057 | pages = dtoc(rs->sc_info->sizes[part].nblocks - dumplo); | |
1058 | maddr = lowram; | |
1059 | baddr = dumplo + rs->sc_info->nbpc * rs->sc_info->sizes[part].cyloff; | |
1060 | #ifdef DEBUG | |
1061 | if (rddebug & RDB_DUMP) | |
1062 | printf("rddump: dumping %d pages from %x to disk block %d\n", | |
1063 | pages, maddr, baddr); | |
1064 | #endif | |
1065 | for (i = 0; i < pages; i++) { | |
1066 | #ifdef DEBUG | |
1067 | #define NPGMB (1024*1024/NBPG) | |
1068 | /* print out how many Mbs we have dumped */ | |
1069 | if (i && (i % NPGMB) == 0) | |
1070 | printf("%d ", i / NPGMB); | |
1071 | #undef NPBMG | |
1072 | #endif | |
1073 | rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit); | |
1074 | rs->sc_ioc.c_volume = C_SVOL(0); | |
1075 | rs->sc_ioc.c_saddr = C_SADDR; | |
1076 | rs->sc_ioc.c_hiaddr = 0; | |
1077 | rs->sc_ioc.c_addr = RDBTOS(baddr); | |
1078 | rs->sc_ioc.c_nop2 = C_NOP; | |
1079 | rs->sc_ioc.c_slen = C_SLEN; | |
1080 | rs->sc_ioc.c_len = NBPG; | |
1081 | rs->sc_ioc.c_cmd = C_WRITE; | |
1082 | hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, | |
1083 | &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2); | |
1084 | if (hpibswait(hp->hp_ctlr, hp->hp_slave)) { | |
1085 | #ifdef DEBUG | |
1086 | if (rddebug & RDB_DUMP) | |
1087 | printf("rddump: IOC wait timeout\n"); | |
1088 | #endif | |
1089 | return (EIO); | |
1090 | } | |
1091 | mapin(mmap, (u_int)vmmap, btop(maddr), PG_URKR|PG_CI|PG_V); | |
1092 | hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG); | |
1093 | if (hpibswait(hp->hp_ctlr, hp->hp_slave)) { | |
1094 | #ifdef DEBUG | |
1095 | if (rddebug & RDB_DUMP) | |
1096 | printf("rddump: write wait timeout\n"); | |
1097 | #endif | |
1098 | } | |
1099 | hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1); | |
1100 | if (stat) { | |
1101 | #ifdef DEBUG | |
1102 | if (rddebug & RDB_DUMP) | |
1103 | printf("rddump: write failed, status %x\n", | |
1104 | stat); | |
1105 | #endif | |
1106 | return (EIO); | |
1107 | } | |
1108 | maddr += NBPG; | |
1109 | baddr += ctod(1); | |
1110 | } | |
1111 | return (0); | |
1112 | } | |
1113 | #endif |