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