Commit | Line | Data |
---|---|---|
2149e3ac MK |
1 | /* |
2 | * Copyright (c) 1988 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
677067f0 MK |
5 | * This code is derived from software contributed to Berkeley by |
6 | * Computer Consoles Inc. | |
7 | * | |
1c15e888 C |
8 | * Redistribution is only permitted until one year after the first shipment |
9 | * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and | |
10 | * binary forms are permitted provided that: (1) source distributions retain | |
11 | * this entire copyright notice and comment, and (2) distributions including | |
12 | * binaries display the following acknowledgement: This product includes | |
13 | * software developed by the University of California, Berkeley and its | |
14 | * contributors'' in the documentation or other materials provided with the | |
15 | * distribution and in all advertising materials mentioning features or use | |
16 | * of this software. Neither the name of the University nor the names of | |
17 | * its contributors may be used to endorse or promote products derived from | |
18 | * this software without specific prior written permission. | |
19 | * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
20 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
2149e3ac | 22 | * |
1c15e888 | 23 | * @(#)vd.c 7.12 (Berkeley) 6/28/90 |
2149e3ac | 24 | */ |
210a9f40 | 25 | |
ad409ece | 26 | #include "dk.h" |
210a9f40 SL |
27 | #if NVD > 0 |
28 | /* | |
7bae1a62 | 29 | * Versabus VDDC/SMDE driver. |
9d915fad | 30 | */ |
9d915fad SL |
31 | #include "param.h" |
32 | #include "buf.h" | |
33 | #include "cmap.h" | |
34 | #include "conf.h" | |
ad409ece | 35 | #include "dkstat.h" |
7bae1a62 | 36 | #include "disklabel.h" |
9d915fad | 37 | #include "map.h" |
7bae1a62 | 38 | #include "file.h" |
9d915fad SL |
39 | #include "systm.h" |
40 | #include "user.h" | |
41 | #include "vmmac.h" | |
42 | #include "proc.h" | |
82bc5dc5 MK |
43 | #include "syslog.h" |
44 | #include "kernel.h" | |
7bae1a62 | 45 | #include "ioctl.h" |
d99b7c9d | 46 | #include "stat.h" |
9d915fad | 47 | |
997cf0e7 MK |
48 | #include "../tahoe/cpu.h" |
49 | #include "../tahoe/mtpr.h" | |
50 | #include "../tahoe/pte.h" | |
51 | ||
9d915fad | 52 | #include "../tahoevba/vbavar.h" |
c7c48d07 | 53 | #include "../tahoevba/vdreg.h" |
9d915fad | 54 | |
f9e93bbe | 55 | #ifndef COMPAT_42 |
7bae1a62 | 56 | #define COMPAT_42 |
f9e93bbe | 57 | #endif |
81304755 | 58 | #define B_FORMAT B_XXX /* XXX */ |
210a9f40 | 59 | |
7bae1a62 SL |
60 | #define vdunit(dev) (minor(dev) >> 3) |
61 | #define vdpart(dev) (minor(dev) & 0x07) | |
62 | #define vdminor(unit,part) (((unit) << 3) | (part)) | |
210a9f40 SL |
63 | |
64 | struct vba_ctlr *vdminfo[NVD]; | |
ad409ece | 65 | struct vba_device *vddinfo[NDK]; |
d99b7c9d | 66 | int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy(); |
2149e3ac | 67 | long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 }; |
9d915fad | 68 | struct vba_driver vddriver = |
2149e3ac | 69 | { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo }; |
7bae1a62 SL |
70 | |
71 | /* | |
72 | * Per-controller state. | |
73 | */ | |
74 | struct vdsoftc { | |
75 | u_short vd_flags; | |
261c73f6 | 76 | #define VD_PRINT 0x1 /* controller info printed */ |
7bae1a62 SL |
77 | #define VD_STARTED 0x2 /* start command issued */ |
78 | #define VD_DOSEEKS 0x4 /* should overlap seeks */ | |
d99b7c9d | 79 | #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */ |
2d1c4664 MK |
80 | #define VD_LOCKED 0x10 /* locked for direct controller access */ |
81 | #define VD_WAIT 0x20 /* someone needs direct controller access */ | |
7bae1a62 SL |
82 | u_short vd_type; /* controller type */ |
83 | u_short vd_wticks; /* timeout */ | |
261c73f6 | 84 | u_short vd_secsize; /* sector size for controller */ |
7bae1a62 SL |
85 | struct mdcb vd_mdcb; /* master command block */ |
86 | u_long vd_mdcbphys; /* physical address of vd_mdcb */ | |
87 | struct dcb vd_dcb; /* i/o command block */ | |
88 | u_long vd_dcbphys; /* physical address of vd_dcb */ | |
1f9a1539 | 89 | struct vb_buf vd_rbuf; /* vba resources */ |
7bae1a62 | 90 | } vdsoftc[NVD]; |
210a9f40 | 91 | |
81304755 MK |
92 | #define VDMAXTIME 20 /* max time for operation, sec. */ |
93 | ||
210a9f40 | 94 | /* |
9d915fad SL |
95 | * Per-drive state. |
96 | */ | |
7bae1a62 | 97 | struct dksoftc { |
60d9b6a0 | 98 | int dk_state; /* open fsm */ |
d99b7c9d MK |
99 | #ifndef SECSIZE |
100 | u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ | |
101 | #endif SECSIZE | |
60d9b6a0 | 102 | int dk_wlabel; /* label sector is currently writable */ |
7e9892e0 MK |
103 | u_long dk_copenpart; /* character units open on this drive */ |
104 | u_long dk_bopenpart; /* block units open on this drive */ | |
105 | u_long dk_openpart; /* all units open on this drive */ | |
7bae1a62 | 106 | u_int dk_curcyl; /* last selected cylinder */ |
d99b7c9d | 107 | struct skdcb dk_dcb; /* seek command block */ |
7bae1a62 | 108 | u_long dk_dcbphys; /* physical address of dk_dcb */ |
81304755 | 109 | int df_reg[3]; /* for formatting, in-out parameters */ |
7bae1a62 | 110 | } dksoftc[NDK]; |
210a9f40 SL |
111 | |
112 | /* | |
7bae1a62 SL |
113 | * Drive states. Used during steps of open/initialization. |
114 | * States < OPEN (> 0) are transient, during an open operation. | |
60d9b6a0 | 115 | * OPENRAW is used for unlabeled disks, to allow format operations. |
9d915fad | 116 | */ |
7bae1a62 SL |
117 | #define CLOSED 0 /* disk is closed */ |
118 | #define WANTOPEN 1 /* open requested, not started */ | |
119 | #define WANTOPENRAW 2 /* open requested, no label */ | |
120 | #define RDLABEL 3 /* reading pack label */ | |
121 | #define OPEN 4 /* intialized and ready */ | |
122 | #define OPENRAW 5 /* open, no label */ | |
123 | ||
7bae1a62 SL |
124 | struct buf dkutab[NDK]; /* i/o queue headers */ |
125 | struct disklabel dklabel[NDK]; /* pack labels */ | |
126 | ||
127 | #define b_cylin b_resid | |
2bb994d6 MK |
128 | #define b_track b_error /* used for seek commands */ |
129 | #define b_seekf b_forw /* second queue on um_tab */ | |
130 | #define b_seekl b_back /* second queue on um_tab */ | |
7bae1a62 SL |
131 | |
132 | int vdwstart, vdwatch(); | |
210a9f40 SL |
133 | |
134 | /* | |
9d915fad SL |
135 | * See if the controller is really there; if so, initialize it. |
136 | */ | |
336ca318 SL |
137 | vdprobe(reg, vm) |
138 | caddr_t reg; | |
139 | struct vba_ctlr *vm; | |
210a9f40 | 140 | { |
336ca318 | 141 | register br, cvec; /* must be r12, r11 */ |
7bae1a62 SL |
142 | register struct vddevice *vdaddr = (struct vddevice *)reg; |
143 | struct vdsoftc *vd; | |
4f42a6a1 | 144 | int s; |
336ca318 | 145 | |
82bc5dc5 MK |
146 | #ifdef lint |
147 | br = 0; cvec = br; br = cvec; | |
148 | vdintr(0); | |
149 | #endif | |
336ca318 | 150 | if (badaddr((caddr_t)reg, 2)) |
9d915fad | 151 | return (0); |
7bae1a62 SL |
152 | vd = &vdsoftc[vm->um_ctlr]; |
153 | vdaddr->vdreset = 0xffffffff; | |
9d915fad | 154 | DELAY(1000000); |
7bae1a62 SL |
155 | if (vdaddr->vdreset != (unsigned)0xffffffff) { |
156 | vd->vd_type = VDTYPE_VDDC; | |
157 | vd->vd_flags &= ~VD_DOSEEKS; | |
9d915fad SL |
158 | DELAY(1000000); |
159 | } else { | |
7bae1a62 SL |
160 | vd->vd_type = VDTYPE_SMDE; |
161 | vd->vd_flags |= VD_DOSEEKS; | |
162 | vdaddr->vdrstclr = 0; | |
9d915fad | 163 | DELAY(3000000); |
210a9f40 | 164 | } |
7bae1a62 SL |
165 | vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb); |
166 | vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb); | |
167 | vm->um_addr = reg; /* XXX */ | |
4f42a6a1 | 168 | s = spl7(); |
261c73f6 | 169 | if (vdinit_ctlr(vm, vd) == 0) { |
4f42a6a1 | 170 | splx(s); |
7bae1a62 SL |
171 | return (0); |
172 | } | |
d99b7c9d | 173 | if (vd->vd_type == VDTYPE_SMDE) { |
261c73f6 MK |
174 | #ifdef notdef |
175 | /* | |
176 | * Attempt PROBE to get all drive status; | |
177 | * we take advantage of this in vdreset_drive | |
178 | * to try to avoid guessing games. | |
179 | */ | |
180 | (void) vdcmd(vm, VDOP_PROBE, 5, 0); | |
181 | #endif | |
182 | /* | |
183 | * Check for scatter-gather by checking firmware date | |
184 | * with IDENT command. The date is printed when | |
185 | * vdslave is first called, thus this must be | |
186 | * the last controller operation in vdprobe. | |
187 | */ | |
d99b7c9d | 188 | vd->vd_dcb.trail.idtrail.date = 0; |
07cd2d63 | 189 | if (vdcmd(vm, VDOP_IDENT, 10, 0)) { |
d99b7c9d MK |
190 | uncache(&vd->vd_dcb.trail.idtrail.date); |
191 | if (vd->vd_dcb.trail.idtrail.date != 0) | |
192 | vd->vd_flags |= VD_SCATGATH; | |
193 | } | |
194 | } | |
4f42a6a1 | 195 | splx(s); |
7c4f3479 | 196 | /* |
f60fa697 | 197 | * Allocate page tables and i/o buffer. |
7c4f3479 | 198 | */ |
f9e93bbe MK |
199 | if (vbainit(&vd->vd_rbuf, MAXPHYS, |
200 | vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) { | |
201 | printf("vd%d: vbainit failed\n", vm->um_ctlr); | |
202 | return (0); | |
203 | } | |
336ca318 | 204 | br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */ |
7bae1a62 | 205 | return (sizeof (struct vddevice)); |
9d915fad | 206 | } |
210a9f40 SL |
207 | |
208 | /* | |
7bae1a62 SL |
209 | * See if a drive is really there. |
210 | * | |
211 | * Can't read pack label here as various data structures | |
212 | * aren't setup for doing a read in a straightforward | |
213 | * manner. Instead just probe for the drive and leave | |
214 | * the pack label stuff to the attach routine. | |
9d915fad | 215 | */ |
60d9b6a0 MK |
216 | /* ARGSUSED */ |
217 | vdslave(vi, vdaddr) | |
9d915fad | 218 | register struct vba_device *vi; |
7bae1a62 | 219 | struct vddevice *vdaddr; |
210a9f40 | 220 | { |
7bae1a62 | 221 | register struct disklabel *lp = &dklabel[vi->ui_unit]; |
f9e93bbe | 222 | register struct dksoftc *dk = &dksoftc[vi->ui_unit]; |
7bae1a62 | 223 | struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; |
261c73f6 | 224 | int bcd(); |
9d915fad | 225 | |
261c73f6 | 226 | if ((vd->vd_flags&VD_PRINT) == 0) { |
07cd2d63 MK |
227 | printf("vd%d: %s controller", vi->ui_ctlr, |
228 | vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE"); | |
229 | if (vd->vd_flags & VD_SCATGATH) { | |
230 | char rev[5]; | |
231 | ||
232 | bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev, | |
233 | sizeof(vd->vd_dcb.trail.idtrail.rev)); | |
234 | printf(" firmware rev %s (%d-%d-%d)", rev, | |
261c73f6 MK |
235 | bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff), |
236 | bcd(vd->vd_dcb.trail.idtrail.date & 0xff), | |
237 | bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff)); | |
07cd2d63 MK |
238 | } |
239 | printf("\n"); | |
261c73f6 | 240 | vd->vd_flags |= VD_PRINT; |
210a9f40 | 241 | } |
7bae1a62 | 242 | |
210a9f40 | 243 | /* |
7bae1a62 SL |
244 | * Initialize label enough to do a reset on |
245 | * the drive. The remainder of the default | |
246 | * label values will be filled in in vdinit | |
247 | * at attach time. | |
210a9f40 | 248 | */ |
f9e93bbe MK |
249 | if (vd->vd_type == VDTYPE_SMDE) |
250 | lp->d_secsize = VD_MAXSECSIZE; | |
251 | else | |
252 | lp->d_secsize = VDDC_SECSIZE; | |
81304755 | 253 | lp->d_nsectors = 66; /* only used on smd-e */ |
60d9b6a0 | 254 | lp->d_ntracks = 23; |
81304755 MK |
255 | lp->d_ncylinders = 850; |
256 | lp->d_secpercyl = 66*23; | |
07cd2d63 | 257 | lp->d_rpm = 3600; |
35841c05 MK |
258 | lp->d_npartitions = 1; |
259 | lp->d_partitions[0].p_offset = 0; | |
260 | lp->d_partitions[0].p_size = LABELSECTOR + 1; | |
7bae1a62 | 261 | |
7bae1a62 SL |
262 | /* |
263 | * Initialize invariant portion of | |
264 | * dcb used for overlapped seeks. | |
265 | */ | |
266 | dk->dk_dcb.opcode = VDOP_SEEK; | |
267 | dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA; | |
268 | dk->dk_dcb.devselect = vi->ui_slave; | |
d99b7c9d | 269 | dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long); |
7bae1a62 SL |
270 | dk->dk_dcb.trail.sktrail.skaddr.sector = 0; |
271 | dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb); | |
f9e93bbe MK |
272 | #ifndef SECSIZE |
273 | vd_setsecsize(dk, lp); | |
274 | #endif | |
275 | return (vdreset_drive(vi)); | |
276 | } | |
277 | ||
261c73f6 MK |
278 | static int |
279 | bcd(n) | |
280 | register u_int n; | |
281 | { | |
282 | register int bin = 0; | |
283 | register int mul = 1; | |
284 | ||
285 | while (n) { | |
286 | bin += (n & 0xf) * mul; | |
287 | n >>= 4; | |
288 | mul *= 10; | |
289 | } | |
290 | return (bin); | |
291 | } | |
292 | ||
f9e93bbe MK |
293 | vdattach(vi) |
294 | register struct vba_device *vi; | |
295 | { | |
296 | register int unit = vi->ui_unit; | |
297 | register struct disklabel *lp = &dklabel[unit]; | |
298 | ||
1f9a1539 MK |
299 | /* |
300 | * Try to initialize device and read pack label. | |
301 | */ | |
302 | if (vdinit(vdminor(unit, 0), 0) != 0) { | |
303 | printf(": unknown drive type"); | |
304 | return; | |
305 | } | |
f9e93bbe MK |
306 | if (dksoftc[unit].dk_state == OPEN) |
307 | printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", | |
308 | lp->d_typename, lp->d_secsize, | |
309 | lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors); | |
7bae1a62 SL |
310 | /* |
311 | * (60 / rpm) / (sectors per track * (bytes per sector / 2)) | |
312 | */ | |
313 | if (vi->ui_dk >= 0) | |
80b6b780 KM |
314 | dk_wpms[vi->ui_dk] = |
315 | (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; | |
7bae1a62 | 316 | #ifdef notyet |
4f42a6a1 | 317 | addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp); |
7bae1a62 | 318 | #endif |
9d915fad SL |
319 | } |
320 | ||
d99b7c9d | 321 | vdopen(dev, flags, fmt) |
7bae1a62 | 322 | dev_t dev; |
d99b7c9d | 323 | int flags, fmt; |
9d915fad | 324 | { |
7bae1a62 SL |
325 | register unit = vdunit(dev); |
326 | register struct disklabel *lp; | |
327 | register struct dksoftc *dk; | |
328 | register struct partition *pp; | |
329 | struct vba_device *vi; | |
261c73f6 | 330 | int s, error = 0, part = vdpart(dev), mask = 1 << part; |
7bae1a62 SL |
331 | daddr_t start, end; |
332 | ||
333 | if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) | |
334 | return (ENXIO); | |
335 | lp = &dklabel[unit]; | |
336 | dk = &dksoftc[unit]; | |
9d915fad | 337 | |
7bae1a62 SL |
338 | s = spl7(); |
339 | while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && | |
340 | dk->dk_state != CLOSED) | |
261c73f6 MK |
341 | if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0)) |
342 | break; | |
7bae1a62 | 343 | splx(s); |
261c73f6 MK |
344 | if (error) |
345 | return (error); | |
7bae1a62 SL |
346 | if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) |
347 | if (error = vdinit(dev, flags)) | |
348 | return (error); | |
4f42a6a1 MK |
349 | |
350 | if (vdwstart == 0) { | |
351 | timeout(vdwatch, (caddr_t)0, hz); | |
352 | vdwstart++; | |
353 | } | |
7bae1a62 SL |
354 | /* |
355 | * Warn if a partion is opened | |
356 | * that overlaps another partition which is open | |
357 | * unless one is the "raw" partition (whole disk). | |
358 | */ | |
f9e93bbe | 359 | #define RAWPART 8 /* 'x' partition */ /* XXX */ |
7e9892e0 | 360 | if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { |
7bae1a62 SL |
361 | pp = &lp->d_partitions[part]; |
362 | start = pp->p_offset; | |
363 | end = pp->p_offset + pp->p_size; | |
364 | for (pp = lp->d_partitions; | |
365 | pp < &lp->d_partitions[lp->d_npartitions]; pp++) { | |
366 | if (pp->p_offset + pp->p_size <= start || | |
367 | pp->p_offset >= end) | |
368 | continue; | |
369 | if (pp - lp->d_partitions == RAWPART) | |
370 | continue; | |
371 | if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) | |
372 | log(LOG_WARNING, | |
373 | "dk%d%c: overlaps open partition (%c)\n", | |
374 | unit, part + 'a', | |
375 | pp - lp->d_partitions + 'a'); | |
376 | } | |
9d915fad | 377 | } |
7bae1a62 SL |
378 | if (part >= lp->d_npartitions) |
379 | return (ENXIO); | |
d99b7c9d MK |
380 | dk->dk_openpart |= mask; |
381 | switch (fmt) { | |
382 | case S_IFCHR: | |
383 | dk->dk_copenpart |= mask; | |
384 | break; | |
385 | case S_IFBLK: | |
386 | dk->dk_bopenpart |= mask; | |
387 | break; | |
388 | } | |
7bae1a62 | 389 | return (0); |
9d915fad SL |
390 | } |
391 | ||
2149e3ac | 392 | /* ARGSUSED */ |
d99b7c9d | 393 | vdclose(dev, flags, fmt) |
7bae1a62 | 394 | dev_t dev; |
d99b7c9d | 395 | int flags, fmt; |
9d915fad | 396 | { |
7bae1a62 SL |
397 | register int unit = vdunit(dev); |
398 | register struct dksoftc *dk = &dksoftc[unit]; | |
d99b7c9d | 399 | int part = vdpart(dev), mask = 1 << part; |
7bae1a62 | 400 | |
d99b7c9d MK |
401 | switch (fmt) { |
402 | case S_IFCHR: | |
403 | dk->dk_copenpart &= ~mask; | |
404 | break; | |
405 | case S_IFBLK: | |
406 | dk->dk_bopenpart &= ~mask; | |
407 | break; | |
408 | } | |
409 | if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) | |
410 | dk->dk_openpart &= ~mask; | |
7bae1a62 SL |
411 | /* |
412 | * Should wait for i/o to complete on this partition | |
413 | * even if others are open, but wait for work on blkflush(). | |
414 | */ | |
415 | if (dk->dk_openpart == 0) { | |
4f42a6a1 MK |
416 | int s = spl7(); |
417 | while (dkutab[unit].b_actf) | |
418 | sleep((caddr_t)dk, PZERO-1); | |
7bae1a62 SL |
419 | splx(s); |
420 | dk->dk_state = CLOSED; | |
60d9b6a0 | 421 | dk->dk_wlabel = 0; |
210a9f40 | 422 | } |
d99b7c9d | 423 | return (0); |
210a9f40 SL |
424 | } |
425 | ||
7bae1a62 SL |
426 | vdinit(dev, flags) |
427 | dev_t dev; | |
428 | int flags; | |
210a9f40 | 429 | { |
7bae1a62 SL |
430 | register struct disklabel *lp; |
431 | register struct dksoftc *dk; | |
432 | struct vba_device *vi; | |
7bae1a62 | 433 | int unit = vdunit(dev), error = 0; |
d99b7c9d | 434 | char *msg, *readdisklabel(); |
7bae1a62 SL |
435 | extern int cold; |
436 | ||
437 | dk = &dksoftc[unit]; | |
438 | if (flags & O_NDELAY) { | |
439 | dk->dk_state = OPENRAW; | |
2149e3ac | 440 | return (0); |
7bae1a62 | 441 | } |
7bae1a62 SL |
442 | dk->dk_state = RDLABEL; |
443 | lp = &dklabel[unit]; | |
7bae1a62 | 444 | vi = vddinfo[unit]; |
d99b7c9d | 445 | if (msg = readdisklabel(dev, vdstrategy, lp)) { |
60d9b6a0 | 446 | if (cold) { |
1f9a1539 | 447 | printf(": %s", msg); |
60d9b6a0 MK |
448 | dk->dk_state = CLOSED; |
449 | } else { | |
f9e93bbe | 450 | log(LOG_ERR, "dk%d: %s\n", unit, msg); |
d99b7c9d | 451 | dk->dk_state = OPENRAW; |
60d9b6a0 MK |
452 | } |
453 | #ifdef COMPAT_42 | |
2d1c4664 | 454 | vdlock(vi->ui_ctlr); |
60d9b6a0 | 455 | if (vdmaptype(vi, lp)) |
7bae1a62 | 456 | dk->dk_state = OPEN; |
2d1c4664 | 457 | vdunlock(vi->ui_ctlr); |
7bae1a62 | 458 | #endif |
d99b7c9d MK |
459 | } else { |
460 | /* | |
461 | * Now that we have the label, configure | |
462 | * the correct drive parameters. | |
463 | */ | |
2d1c4664 | 464 | vdlock(vi->ui_ctlr); |
f9e93bbe MK |
465 | if (vdreset_drive(vi)) |
466 | dk->dk_state = OPEN; | |
467 | else { | |
d99b7c9d MK |
468 | dk->dk_state = CLOSED; |
469 | error = ENXIO; | |
f9e93bbe | 470 | } |
2d1c4664 | 471 | vdunlock(vi->ui_ctlr); |
9d915fad | 472 | } |
d99b7c9d | 473 | #ifndef SECSIZE |
f9e93bbe MK |
474 | vd_setsecsize(dk, lp); |
475 | #endif | |
7bae1a62 SL |
476 | wakeup((caddr_t)dk); |
477 | return (error); | |
210a9f40 SL |
478 | } |
479 | ||
f9e93bbe MK |
480 | #ifndef SECSIZE |
481 | vd_setsecsize(dk, lp) | |
482 | register struct dksoftc *dk; | |
483 | register struct disklabel *lp; | |
484 | { | |
485 | int mul; | |
486 | ||
487 | /* | |
488 | * Calculate scaling shift for mapping | |
489 | * DEV_BSIZE blocks to drive sectors. | |
490 | */ | |
491 | mul = DEV_BSIZE / lp->d_secsize; | |
492 | dk->dk_bshift = 0; | |
493 | while ((mul >>= 1) > 0) | |
494 | dk->dk_bshift++; | |
495 | } | |
496 | #endif SECSIZE | |
497 | ||
9d915fad | 498 | /*ARGSUSED*/ |
7bae1a62 SL |
499 | vddgo(vm) |
500 | struct vba_device *vm; | |
210a9f40 | 501 | { |
9d915fad | 502 | |
210a9f40 SL |
503 | } |
504 | ||
505 | vdstrategy(bp) | |
9d915fad | 506 | register struct buf *bp; |
210a9f40 | 507 | { |
7bae1a62 SL |
508 | register struct vba_device *vi; |
509 | register struct disklabel *lp; | |
510 | register struct dksoftc *dk; | |
511 | register int unit; | |
4f42a6a1 | 512 | register daddr_t sn; |
7bae1a62 | 513 | struct buf *dp; |
4f42a6a1 | 514 | daddr_t sz, maxsz; |
7bae1a62 SL |
515 | int part, s; |
516 | ||
7bae1a62 | 517 | unit = vdunit(bp->b_dev); |
f9e93bbe | 518 | if (unit >= NDK) { |
7bae1a62 SL |
519 | bp->b_error = ENXIO; |
520 | goto bad; | |
521 | } | |
522 | vi = vddinfo[unit]; | |
523 | lp = &dklabel[unit]; | |
524 | if (vi == 0 || vi->ui_alive == 0) { | |
1e9609f2 | 525 | bp->b_error = ENXIO; |
9d915fad | 526 | goto bad; |
1e9609f2 | 527 | } |
7bae1a62 | 528 | dk = &dksoftc[unit]; |
261c73f6 MK |
529 | if (dk->dk_state < OPEN) { |
530 | if (dk->dk_state == CLOSED) { | |
531 | bp->b_error = EIO; | |
532 | goto bad; | |
533 | } | |
7bae1a62 | 534 | goto q; |
261c73f6 | 535 | } |
60d9b6a0 MK |
536 | if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { |
537 | bp->b_error = EROFS; | |
538 | goto bad; | |
539 | } | |
7bae1a62 SL |
540 | part = vdpart(bp->b_dev); |
541 | if ((dk->dk_openpart & (1 << part)) == 0) { | |
542 | bp->b_error = ENODEV; | |
543 | goto bad; | |
544 | } | |
f9e93bbe | 545 | sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; |
7bae1a62 | 546 | maxsz = lp->d_partitions[part].p_size; |
d99b7c9d MK |
547 | #ifndef SECSIZE |
548 | sn = bp->b_blkno << dk->dk_bshift; | |
549 | #else SECSIZE | |
4f42a6a1 | 550 | sn = bp->b_blkno; |
d99b7c9d | 551 | #endif SECSIZE |
60d9b6a0 MK |
552 | if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && |
553 | #if LABELSECTOR != 0 | |
554 | sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && | |
555 | #endif | |
556 | (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { | |
557 | bp->b_error = EROFS; | |
558 | goto bad; | |
559 | } | |
7bae1a62 SL |
560 | if (sn < 0 || sn + sz > maxsz) { |
561 | if (sn == maxsz) { | |
1e9609f2 MK |
562 | bp->b_resid = bp->b_bcount; |
563 | goto done; | |
564 | } | |
d99b7c9d | 565 | sz = maxsz - sn; |
4f42a6a1 MK |
566 | if (sz <= 0) { |
567 | bp->b_error = EINVAL; | |
568 | goto bad; | |
569 | } | |
570 | bp->b_bcount = sz * lp->d_secsize; | |
210a9f40 | 571 | } |
7bae1a62 | 572 | bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; |
d99b7c9d MK |
573 | #ifdef SECSIZE |
574 | if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0) | |
575 | panic("vdstrat blksize"); | |
576 | #endif SECSIZE | |
7bae1a62 | 577 | q: |
9d915fad | 578 | s = spl7(); |
7bae1a62 SL |
579 | dp = &dkutab[vi->ui_unit]; |
580 | disksort(dp, bp); | |
581 | if (!dp->b_active) { | |
582 | (void) vdustart(vi); | |
4f42a6a1 | 583 | if (!vi->ui_mi->um_tab.b_active) |
7bae1a62 | 584 | vdstart(vi->ui_mi); |
9d915fad | 585 | } |
7bae1a62 | 586 | splx(s); |
210a9f40 | 587 | return; |
9d915fad | 588 | bad: |
1e9609f2 MK |
589 | bp->b_flags |= B_ERROR; |
590 | done: | |
7bae1a62 SL |
591 | biodone(bp); |
592 | return; | |
210a9f40 SL |
593 | } |
594 | ||
7bae1a62 SL |
595 | vdustart(vi) |
596 | register struct vba_device *vi; | |
9d915fad | 597 | { |
7bae1a62 SL |
598 | register struct buf *bp, *dp; |
599 | register struct vba_ctlr *vm; | |
600 | register int unit = vi->ui_unit; | |
601 | register struct dksoftc *dk; | |
602 | register struct vdsoftc *vd; | |
603 | struct disklabel *lp; | |
604 | ||
7bae1a62 SL |
605 | dp = &dkutab[unit]; |
606 | /* | |
607 | * If queue empty, nothing to do. | |
608 | */ | |
609 | if ((bp = dp->b_actf) == NULL) | |
610 | return; | |
611 | /* | |
2bb994d6 MK |
612 | * If drive is off-cylinder and controller supports seeks, |
613 | * place drive on seek queue for controller. | |
614 | * Otherwise, place on transfer queue. | |
7bae1a62 SL |
615 | */ |
616 | vd = &vdsoftc[vi->ui_ctlr]; | |
617 | dk = &dksoftc[unit]; | |
2bb994d6 | 618 | vm = vi->ui_mi; |
7bae1a62 | 619 | if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) { |
7bae1a62 | 620 | lp = &dklabel[unit]; |
2bb994d6 MK |
621 | bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors; |
622 | if (vm->um_tab.b_seekf == NULL) | |
623 | vm->um_tab.b_seekf = dp; | |
624 | else | |
625 | vm->um_tab.b_seekl->b_forw = dp; | |
626 | vm->um_tab.b_seekl = dp; | |
627 | } else { | |
628 | if (vm->um_tab.b_actf == NULL) | |
629 | vm->um_tab.b_actf = dp; | |
630 | else | |
631 | vm->um_tab.b_actl->b_forw = dp; | |
632 | vm->um_tab.b_actl = dp; | |
7bae1a62 | 633 | } |
4f42a6a1 | 634 | dp->b_forw = NULL; |
4f42a6a1 | 635 | dp->b_active++; |
9d915fad SL |
636 | } |
637 | ||
638 | /* | |
7bae1a62 | 639 | * Start next transfer on a controller. |
2bb994d6 MK |
640 | * There are two queues of drives, the first on-cylinder |
641 | * and the second off-cylinder from their next transfers. | |
642 | * Perform the first transfer for the first drive on the on-cylinder | |
643 | * queue, if any, otherwise the first transfer for the first drive | |
644 | * on the second queue. Initiate seeks on remaining drives on the | |
645 | * off-cylinder queue, then move them all to the on-cylinder queue. | |
9d915fad | 646 | */ |
7bae1a62 SL |
647 | vdstart(vm) |
648 | register struct vba_ctlr *vm; | |
9d915fad | 649 | { |
9d915fad | 650 | register struct buf *bp; |
7bae1a62 SL |
651 | register struct vba_device *vi; |
652 | register struct vdsoftc *vd; | |
653 | register struct dksoftc *dk; | |
654 | register struct disklabel *lp; | |
7bae1a62 | 655 | register struct dcb **dcbp; |
7bae1a62 SL |
656 | struct buf *dp; |
657 | int sn, tn; | |
658 | ||
659 | loop: | |
660 | /* | |
661 | * Pull a request off the controller queue. | |
662 | */ | |
2bb994d6 MK |
663 | if ((dp = vm->um_tab.b_actf) == NULL && |
664 | (dp = vm->um_tab.b_seekf) == NULL) | |
7bae1a62 SL |
665 | return; |
666 | if ((bp = dp->b_actf) == NULL) { | |
1f9a1539 MK |
667 | if (dp == vm->um_tab.b_actf) |
668 | vm->um_tab.b_actf = dp->b_forw; | |
669 | else | |
670 | vm->um_tab.b_seekf = dp->b_forw; | |
7bae1a62 SL |
671 | goto loop; |
672 | } | |
9d915fad | 673 | |
210a9f40 | 674 | /* |
7bae1a62 SL |
675 | * Mark controller busy, and determine |
676 | * destination of this request. | |
210a9f40 | 677 | */ |
7bae1a62 SL |
678 | vm->um_tab.b_active++; |
679 | vi = vddinfo[vdunit(bp->b_dev)]; | |
680 | dk = &dksoftc[vi->ui_unit]; | |
d99b7c9d MK |
681 | #ifndef SECSIZE |
682 | sn = bp->b_blkno << dk->dk_bshift; | |
683 | #else SECSIZE | |
4f42a6a1 | 684 | sn = bp->b_blkno; |
d99b7c9d | 685 | #endif SECSIZE |
7bae1a62 SL |
686 | lp = &dklabel[vi->ui_unit]; |
687 | sn %= lp->d_secpercyl; | |
688 | tn = sn / lp->d_nsectors; | |
689 | sn %= lp->d_nsectors; | |
210a9f40 | 690 | |
7bae1a62 SL |
691 | /* |
692 | * Construct dcb for read/write command. | |
693 | */ | |
694 | vd = &vdsoftc[vm->um_ctlr]; | |
7bae1a62 | 695 | vd->vd_dcb.intflg = DCBINT_DONE; |
f9e93bbe | 696 | vd->vd_dcb.devselect = dk->dk_dcb.devselect; |
7bae1a62 SL |
697 | vd->vd_dcb.operrsta = 0; |
698 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
7bae1a62 SL |
699 | vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin; |
700 | vd->vd_dcb.trail.rwtrail.disk.track = tn; | |
701 | vd->vd_dcb.trail.rwtrail.disk.sector = sn; | |
2bb994d6 MK |
702 | dk->dk_curcyl = bp->b_cylin; |
703 | bp->b_track = 0; /* init overloaded field */ | |
d99b7c9d | 704 | vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); |
81304755 MK |
705 | if (bp->b_flags & B_FORMAT) |
706 | vd->vd_dcb.opcode = dk->dk_op; | |
707 | else if (vd->vd_flags & VD_SCATGATH && | |
708 | ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) | |
d99b7c9d | 709 | vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW; |
81304755 | 710 | else |
d99b7c9d | 711 | vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD; |
81304755 MK |
712 | |
713 | switch (vd->vd_dcb.opcode) { | |
714 | case VDOP_FSECT: | |
261c73f6 | 715 | vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long); |
81304755 MK |
716 | vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount / |
717 | lp->d_secsize; | |
718 | vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr; | |
719 | vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags; | |
720 | goto setupaddr; | |
721 | ||
722 | case VDOP_RDRAW: | |
723 | case VDOP_RD: | |
261c73f6 | 724 | case VDOP_RHDE: |
81304755 MK |
725 | case VDOP_WD: |
726 | vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1; | |
727 | setupaddr: | |
d99b7c9d | 728 | vd->vd_dcb.trail.rwtrail.memadr = |
2149e3ac | 729 | vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize); |
81304755 MK |
730 | break; |
731 | ||
732 | case VDOP_RAS: | |
733 | case VDOP_GAW: | |
d44a0516 | 734 | vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf, |
81304755 MK |
735 | &vd->vd_dcb.trail.sgtrail); |
736 | break; | |
d99b7c9d | 737 | } |
2bb994d6 MK |
738 | if (vi->ui_dk >= 0) { |
739 | dk_busy |= 1<<vi->ui_dk; | |
740 | dk_xfer[vi->ui_dk]++; | |
741 | dk_wds[vi->ui_dk] += bp->b_bcount>>6; | |
742 | } | |
9d915fad | 743 | |
7bae1a62 SL |
744 | /* |
745 | * Look for any seeks to be performed on other drives on this | |
746 | * controller. If overlapped seeks exist, insert seek commands | |
747 | * on the controller's command queue before the transfer. | |
748 | */ | |
749 | dcbp = &vd->vd_mdcb.mdcb_head; | |
7bae1a62 | 750 | |
2bb994d6 MK |
751 | if (dp == vm->um_tab.b_seekf) |
752 | dp = dp->b_forw; | |
753 | else | |
754 | dp = vm->um_tab.b_seekf; | |
755 | for (; dp != NULL; dp = dp->b_forw) { | |
756 | if ((bp = dp->b_actf) == NULL) | |
757 | continue; | |
758 | vi = vddinfo[vdunit(bp->b_dev)]; | |
759 | dk = &dksoftc[vi->ui_unit]; | |
7bae1a62 | 760 | dk->dk_curcyl = bp->b_cylin; |
2bb994d6 MK |
761 | if (vi->ui_dk >= 0) |
762 | dk_seek[vi->ui_dk]++; | |
763 | dk->dk_dcb.operrsta = 0; | |
764 | dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin; | |
2bb994d6 | 765 | dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track; |
2bb994d6 MK |
766 | *dcbp = (struct dcb *)dk->dk_dcbphys; |
767 | dcbp = &dk->dk_dcb.nxtdcb; | |
9d915fad | 768 | } |
7bae1a62 | 769 | *dcbp = (struct dcb *)vd->vd_dcbphys; |
2bb994d6 MK |
770 | if (vm->um_tab.b_actf) |
771 | vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf; | |
772 | else | |
773 | vm->um_tab.b_actf = vm->um_tab.b_seekf; | |
1f9a1539 MK |
774 | if (vm->um_tab.b_seekf) |
775 | vm->um_tab.b_actl = vm->um_tab.b_seekl; | |
2bb994d6 | 776 | vm->um_tab.b_seekf = 0; |
7bae1a62 SL |
777 | |
778 | /* | |
779 | * Initiate operation. | |
780 | */ | |
7bae1a62 SL |
781 | vd->vd_mdcb.mdcb_status = 0; |
782 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
9d915fad | 783 | } |
210a9f40 | 784 | |
2d1c4664 MK |
785 | /* |
786 | * Wait for controller to finish current operation | |
787 | * so that direct controller accesses can be done. | |
788 | */ | |
789 | vdlock(ctlr) | |
790 | { | |
791 | register struct vba_ctlr *vm = vdminfo[ctlr]; | |
792 | register struct vdsoftc *vd = &vdsoftc[ctlr]; | |
793 | int s; | |
794 | ||
795 | s = spl7(); | |
796 | while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) { | |
797 | vd->vd_flags |= VD_WAIT; | |
798 | sleep((caddr_t)vd, PRIBIO); | |
799 | } | |
800 | vd->vd_flags |= VD_LOCKED; | |
801 | splx(s); | |
802 | } | |
803 | ||
804 | /* | |
805 | * Continue normal operations after pausing for | |
806 | * munging the controller directly. | |
807 | */ | |
808 | vdunlock(ctlr) | |
809 | { | |
810 | register struct vba_ctlr *vm = vdminfo[ctlr]; | |
811 | register struct vdsoftc *vd = &vdsoftc[ctlr]; | |
812 | ||
813 | vd->vd_flags &= ~VD_LOCKED; | |
814 | if (vd->vd_flags & VD_WAIT) { | |
815 | vd->vd_flags &= ~VD_WAIT; | |
816 | wakeup((caddr_t)vd); | |
817 | } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) | |
818 | vdstart(vm); | |
819 | } | |
820 | ||
7bae1a62 | 821 | #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE) |
210a9f40 SL |
822 | /* |
823 | * Handle a disk interrupt. | |
824 | */ | |
9d915fad | 825 | vdintr(ctlr) |
7bae1a62 | 826 | register ctlr; |
210a9f40 | 827 | { |
7bae1a62 SL |
828 | register struct buf *bp, *dp; |
829 | register struct vba_ctlr *vm = vdminfo[ctlr]; | |
830 | register struct vba_device *vi; | |
831 | register struct vdsoftc *vd = &vdsoftc[ctlr]; | |
832 | register status; | |
2149e3ac | 833 | int timedout; |
4f42a6a1 | 834 | struct dksoftc *dk; |
7bae1a62 | 835 | |
7bae1a62 | 836 | if (!vm->um_tab.b_active) { |
9d915fad | 837 | printf("vd%d: stray interrupt\n", ctlr); |
210a9f40 SL |
838 | return; |
839 | } | |
9d915fad | 840 | /* |
7bae1a62 SL |
841 | * Get device and block structures, and a pointer |
842 | * to the vba_device for the drive. | |
9d915fad | 843 | */ |
7bae1a62 SL |
844 | dp = vm->um_tab.b_actf; |
845 | bp = dp->b_actf; | |
846 | vi = vddinfo[vdunit(bp->b_dev)]; | |
2149e3ac | 847 | dk = &dksoftc[vi->ui_unit]; |
2bb994d6 MK |
848 | if (vi->ui_dk >= 0) |
849 | dk_busy &= ~(1<<vi->ui_dk); | |
81304755 | 850 | timedout = (vd->vd_wticks >= VDMAXTIME); |
7bae1a62 SL |
851 | /* |
852 | * Check for and process errors on | |
853 | * either the drive or the controller. | |
854 | */ | |
855 | uncache(&vd->vd_dcb.operrsta); | |
856 | status = vd->vd_dcb.operrsta; | |
81304755 MK |
857 | if (bp->b_flags & B_FORMAT) { |
858 | dk->dk_operrsta = status; | |
859 | uncache(&vd->vd_dcb.err_code); | |
261c73f6 MK |
860 | /* ecodecnt gets err_code + err_wcnt from the same longword */ |
861 | dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code; | |
862 | uncache(&vd->vd_dcb.err_trk); | |
863 | /* erraddr gets error trk/sec/cyl from the same longword */ | |
864 | dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk; | |
865 | } else if (status & VDERR_HARD || timedout) { | |
2149e3ac | 866 | if (vd->vd_type == VDTYPE_SMDE) |
1f9a1539 | 867 | uncache(&vd->vd_dcb.err_code); |
7bae1a62 SL |
868 | if (status & DCBS_WPT) { |
869 | /* | |
870 | * Give up on write locked devices immediately. | |
871 | */ | |
4f42a6a1 | 872 | printf("dk%d: write locked\n", vi->ui_unit); |
7bae1a62 | 873 | bp->b_flags |= B_ERROR; |
81304755 | 874 | } else if (status & VDERR_RETRY || timedout) { |
81304755 | 875 | if (status & VDERR_CTLR || timedout) { |
261c73f6 MK |
876 | vdharderr(timedout ? |
877 | "controller timeout" : "controller err", | |
81304755 MK |
878 | vd, bp, &vd->vd_dcb); |
879 | printf("; resetting controller..."); | |
880 | vdreset_ctlr(vm); | |
881 | } else if (status & VDERR_DRIVE) { | |
882 | vdharderr("drive err", vd, bp, &vd->vd_dcb); | |
883 | printf("; resetting drive..."); | |
7bae1a62 | 884 | if (!vdreset_drive(vi)) |
261c73f6 | 885 | dk->dk_state = CLOSED; |
f9e93bbe | 886 | } else |
261c73f6 | 887 | vdharderr("data err", vd, bp, &vd->vd_dcb); |
7bae1a62 SL |
888 | /* |
889 | * Retry transfer once, unless reset failed. | |
890 | */ | |
261c73f6 MK |
891 | if (!vi->ui_alive || dp->b_errcnt++ >= 1) { |
892 | printf("\n"); | |
7bae1a62 | 893 | goto hard; |
f9e93bbe MK |
894 | } |
895 | ||
261c73f6 | 896 | printf(" retrying\n"); |
7bae1a62 SL |
897 | vm->um_tab.b_active = 0; /* force retry */ |
898 | } else { | |
81304755 | 899 | vdharderr("hard error", vd, bp, &vd->vd_dcb); |
7bae1a62 | 900 | printf("\n"); |
261c73f6 MK |
901 | hard: |
902 | bp->b_flags |= B_ERROR; | |
9d915fad | 903 | } |
7bae1a62 | 904 | } else if (status & DCBS_SOFT) |
2149e3ac | 905 | vdsofterr(bp, &vd->vd_dcb); |
261c73f6 MK |
906 | if (vd->vd_wticks > 3) { |
907 | vd->vd_dcb.err_code = vd->vd_wticks; | |
908 | vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb); | |
909 | printf("\n"); | |
910 | } | |
81304755 | 911 | vd->vd_wticks = 0; |
7bae1a62 SL |
912 | if (vm->um_tab.b_active) { |
913 | vm->um_tab.b_active = 0; | |
7bae1a62 SL |
914 | vm->um_tab.b_actf = dp->b_forw; |
915 | dp->b_active = 0; | |
916 | dp->b_errcnt = 0; | |
917 | dp->b_actf = bp->av_forw; | |
9d915fad | 918 | bp->b_resid = 0; |
1f9a1539 | 919 | vbadone(bp, &vd->vd_rbuf); |
7bae1a62 SL |
920 | biodone(bp); |
921 | /* | |
922 | * If this unit has more work to do, | |
923 | * then start it up right away. | |
924 | */ | |
925 | if (dp->b_actf) | |
926 | vdustart(vi); | |
2149e3ac | 927 | else if (dk->dk_openpart == 0) |
4f42a6a1 | 928 | wakeup((caddr_t)dk); |
210a9f40 | 929 | } |
9d915fad | 930 | /* |
7bae1a62 SL |
931 | * If there are devices ready to |
932 | * transfer, start the controller. | |
9d915fad | 933 | */ |
2d1c4664 MK |
934 | if (vd->vd_flags & VD_WAIT) { |
935 | vd->vd_flags &= ~VD_WAIT; | |
936 | wakeup((caddr_t)vd); | |
937 | } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf) | |
7bae1a62 | 938 | vdstart(vm); |
210a9f40 SL |
939 | } |
940 | ||
81304755 MK |
941 | vdharderr(what, vd, bp, dcb) |
942 | char *what; | |
943 | struct vdsoftc *vd; | |
944 | register struct buf *bp; | |
945 | register struct dcb *dcb; | |
946 | { | |
947 | int unit = vdunit(bp->b_dev), status = dcb->operrsta; | |
81304755 | 948 | register struct disklabel *lp = &dklabel[unit]; |
2149e3ac | 949 | int blkdone; |
81304755 MK |
950 | |
951 | if (vd->vd_wticks < VDMAXTIME) | |
952 | status &= ~DONTCARE; | |
a3074845 MK |
953 | blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * |
954 | lp->d_nsectors + dcb->err_sec - | |
955 | lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> | |
956 | dksoftc[unit].dk_bshift) - bp->b_blkno; | |
2149e3ac MK |
957 | diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp); |
958 | printf(", status %b", status, VDERRBITS); | |
81304755 MK |
959 | if (vd->vd_type == VDTYPE_SMDE) |
960 | printf(" ecode %x", dcb->err_code); | |
81304755 MK |
961 | } |
962 | ||
2149e3ac | 963 | vdsofterr(bp, dcb) |
9d915fad | 964 | register struct buf *bp; |
7bae1a62 | 965 | register struct dcb *dcb; |
9d915fad | 966 | { |
f9d2ea8f MK |
967 | int unit = vdunit(bp->b_dev); |
968 | struct disklabel *lp = &dklabel[unit]; | |
2149e3ac MK |
969 | int status = dcb->operrsta; |
970 | int blkdone; | |
971 | ||
a3074845 MK |
972 | blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) * |
973 | lp->d_nsectors + dcb->err_sec - | |
974 | lp->d_partitions[vdpart(bp->b_dev)].p_offset) >> | |
975 | dksoftc[unit].dk_bshift) - bp->b_blkno; | |
2149e3ac MK |
976 | |
977 | if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) { | |
978 | diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp); | |
979 | addlog(", status %b ecode %x\n", status, VDERRBITS, | |
81304755 | 980 | dcb->err_code); |
2149e3ac MK |
981 | } else { |
982 | diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp); | |
983 | addlog("\n"); | |
984 | } | |
9d915fad | 985 | } |
210a9f40 | 986 | |
7bae1a62 | 987 | vdioctl(dev, cmd, data, flag) |
9d915fad | 988 | dev_t dev; |
7bae1a62 SL |
989 | int cmd; |
990 | caddr_t data; | |
991 | int flag; | |
210a9f40 | 992 | { |
7e9892e0 | 993 | register int unit = vdunit(dev); |
7bae1a62 | 994 | register struct disklabel *lp = &dklabel[unit]; |
60d9b6a0 | 995 | register struct dksoftc *dk = &dksoftc[unit]; |
045442ab | 996 | int error = 0, vdformat(); |
7bae1a62 SL |
997 | |
998 | switch (cmd) { | |
999 | ||
1000 | case DIOCGDINFO: | |
1001 | *(struct disklabel *)data = *lp; | |
1002 | break; | |
1003 | ||
4f42a6a1 MK |
1004 | case DIOCGPART: |
1005 | ((struct partinfo *)data)->disklab = lp; | |
1006 | ((struct partinfo *)data)->part = | |
1007 | &lp->d_partitions[vdpart(dev)]; | |
7bae1a62 SL |
1008 | break; |
1009 | ||
1010 | case DIOCSDINFO: | |
1011 | if ((flag & FWRITE) == 0) | |
1012 | error = EBADF; | |
1013 | else | |
7e9892e0 | 1014 | error = setdisklabel(lp, (struct disklabel *)data, |
60d9b6a0 | 1015 | (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); |
81304755 MK |
1016 | if (error == 0 && dk->dk_state == OPENRAW && |
1017 | vdreset_drive(vddinfo[unit])) | |
60d9b6a0 MK |
1018 | dk->dk_state = OPEN; |
1019 | break; | |
1020 | ||
1021 | case DIOCWLABEL: | |
1022 | if ((flag & FWRITE) == 0) | |
1023 | error = EBADF; | |
1024 | else | |
1025 | dk->dk_wlabel = *(int *)data; | |
7bae1a62 SL |
1026 | break; |
1027 | ||
7e9892e0 MK |
1028 | case DIOCWDINFO: |
1029 | if ((flag & FWRITE) == 0) | |
7bae1a62 | 1030 | error = EBADF; |
7e9892e0 | 1031 | else if ((error = setdisklabel(lp, (struct disklabel *)data, |
60d9b6a0 | 1032 | (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { |
045442ab MK |
1033 | int wlab; |
1034 | ||
07cd2d63 MK |
1035 | if (error == 0 && dk->dk_state == OPENRAW && |
1036 | vdreset_drive(vddinfo[unit])) | |
1037 | dk->dk_state = OPEN; | |
045442ab MK |
1038 | /* simulate opening partition 0 so write succeeds */ |
1039 | dk->dk_openpart |= (1 << 0); /* XXX */ | |
1040 | wlab = dk->dk_wlabel; | |
1041 | dk->dk_wlabel = 1; | |
7e9892e0 | 1042 | error = writedisklabel(dev, vdstrategy, lp); |
045442ab MK |
1043 | dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; |
1044 | dk->dk_wlabel = wlab; | |
60d9b6a0 | 1045 | } |
7bae1a62 | 1046 | break; |
7bae1a62 | 1047 | |
81304755 MK |
1048 | case DIOCWFORMAT: |
1049 | { | |
1050 | register struct format_op *fop; | |
1051 | struct uio auio; | |
1052 | struct iovec aiov; | |
1053 | ||
1054 | if ((flag & FWRITE) == 0) { | |
1055 | error = EBADF; | |
1056 | break; | |
1057 | } | |
1058 | fop = (struct format_op *)data; | |
1059 | aiov.iov_base = fop->df_buf; | |
1060 | aiov.iov_len = fop->df_count; | |
1061 | auio.uio_iov = &aiov; | |
1062 | auio.uio_iovcnt = 1; | |
1063 | auio.uio_resid = fop->df_count; | |
1064 | auio.uio_segflg = UIO_USERSPACE; | |
1065 | auio.uio_offset = fop->df_startblk * lp->d_secsize; | |
261c73f6 MK |
1066 | /* This assumes one active format operation per disk... */ |
1067 | dk->dk_op = fop->dk_op; | |
1068 | dk->dk_althdr = fop->dk_althdr; | |
1069 | dk->dk_fmtflags = fop->dk_fmtflags; | |
81304755 MK |
1070 | /* |
1071 | * Don't return errors, as the format op won't get copied | |
1072 | * out if we return nonzero. Callers must check the returned | |
261c73f6 | 1073 | * registers and count. |
81304755 | 1074 | */ |
261c73f6 MK |
1075 | error = physio(vdformat, (struct buf *)NULL, dev, |
1076 | B_WRITE, minphys, &auio); | |
1077 | if (error == EIO) | |
1078 | error = 0; | |
81304755 | 1079 | fop->df_count -= auio.uio_resid; |
261c73f6 | 1080 | /* This assumes one active format operation per disk... */ |
81304755 | 1081 | fop->dk_operrsta = dk->dk_operrsta; |
261c73f6 MK |
1082 | fop->dk_ecodecnt = dk->dk_ecodecnt; |
1083 | fop->dk_erraddr = dk->dk_erraddr; | |
81304755 MK |
1084 | break; |
1085 | } | |
1086 | ||
7bae1a62 SL |
1087 | default: |
1088 | error = ENOTTY; | |
1089 | break; | |
210a9f40 | 1090 | } |
2322c6bc | 1091 | return (error); |
210a9f40 SL |
1092 | } |
1093 | ||
81304755 MK |
1094 | vdformat(bp) |
1095 | struct buf *bp; | |
1096 | { | |
1097 | bp->b_flags |= B_FORMAT; | |
1098 | vdstrategy(bp); | |
1099 | } | |
1100 | ||
9d915fad | 1101 | /* |
7bae1a62 | 1102 | * Watch for lost interrupts. |
9d915fad | 1103 | */ |
7bae1a62 | 1104 | vdwatch() |
210a9f40 | 1105 | { |
7bae1a62 SL |
1106 | register struct vdsoftc *vd; |
1107 | register struct vba_ctlr *vm; | |
2149e3ac | 1108 | register int ctlr; |
81304755 | 1109 | int s; |
7bae1a62 SL |
1110 | |
1111 | timeout(vdwatch, (caddr_t)0, hz); | |
1112 | for (ctlr = 0; ctlr < NVD; ctlr++) { | |
1113 | vm = vdminfo[ctlr]; | |
1114 | if (vm == 0 || vm->um_alive == 0) | |
1115 | continue; | |
1116 | vd = &vdsoftc[ctlr]; | |
81304755 MK |
1117 | s = spl7(); |
1118 | if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) { | |
7bae1a62 | 1119 | printf("vd%d: lost interrupt\n", ctlr); |
81304755 MK |
1120 | #ifdef maybe |
1121 | VDABORT((struct vddevice *)vm->um_addr, vd->vd_type); | |
1122 | #endif | |
1123 | vdintr(ctlr); | |
7bae1a62 | 1124 | } |
81304755 | 1125 | splx(s); |
9d915fad | 1126 | } |
7bae1a62 SL |
1127 | } |
1128 | ||
1129 | #define DBSIZE 64 /* controller limit with 1K sectors */ | |
1130 | /* | |
1131 | * Crash dump. | |
1132 | */ | |
1133 | vddump(dev) | |
1134 | dev_t dev; | |
1135 | { | |
1136 | register struct vba_device *vi; | |
1137 | register struct vba_ctlr *vm; | |
1138 | register struct disklabel *lp; | |
1139 | register struct vdsoftc *vd; | |
1140 | struct dksoftc *dk; | |
1141 | int part, unit, num; | |
1f9a1539 | 1142 | u_long start; |
7bae1a62 SL |
1143 | |
1144 | start = 0; | |
1145 | unit = vdunit(dev); | |
1146 | if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0) | |
1147 | return (ENXIO); | |
1148 | dk = &dksoftc[unit]; | |
60d9b6a0 MK |
1149 | if (dk->dk_state != OPEN && dk->dk_state != OPENRAW && |
1150 | vdinit(vdminor(unit, 0), 0) != 0) | |
7bae1a62 SL |
1151 | return (ENXIO); |
1152 | lp = &dklabel[unit]; | |
1153 | part = vdpart(dev); | |
1154 | if (part >= lp->d_npartitions) | |
1155 | return (ENXIO); | |
f9e93bbe | 1156 | vm = vi->ui_mi; |
7bae1a62 SL |
1157 | vdreset_ctlr(vm); |
1158 | if (dumplo < 0) | |
1159 | return (EINVAL); | |
1160 | /* | |
d99b7c9d | 1161 | * Maxfree is in pages, dumplo is in DEV_BSIZE units. |
7bae1a62 SL |
1162 | */ |
1163 | num = maxfree * (NBPG / lp->d_secsize); | |
d99b7c9d | 1164 | dumplo *= DEV_BSIZE / lp->d_secsize; |
7bae1a62 SL |
1165 | if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size) |
1166 | num = lp->d_partitions[vdpart(dev)].p_size - dumplo; | |
1167 | vd = &vdsoftc[vm->um_ctlr]; | |
1168 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1169 | vd->vd_dcb.opcode = VDOP_WD; | |
f9e93bbe | 1170 | vd->vd_dcb.devselect = dk->dk_dcb.devselect; |
d99b7c9d | 1171 | vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); |
7bae1a62 SL |
1172 | while (num > 0) { |
1173 | int nsec, cn, sn, tn; | |
1174 | ||
1175 | nsec = MIN(num, DBSIZE); | |
1f9a1539 | 1176 | sn = dumplo + start / lp->d_secsize; |
7bae1a62 SL |
1177 | cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) / |
1178 | lp->d_secpercyl; | |
1179 | sn %= lp->d_secpercyl; | |
1180 | tn = sn / lp->d_nsectors; | |
1181 | sn %= lp->d_nsectors; | |
1182 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1183 | vd->vd_dcb.trail.rwtrail.memadr = start; | |
1184 | vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1; | |
1185 | vd->vd_dcb.trail.rwtrail.disk.cylinder = cn; | |
1186 | vd->vd_dcb.trail.rwtrail.disk.track = tn; | |
1187 | vd->vd_dcb.trail.rwtrail.disk.sector = sn; | |
1188 | vd->vd_dcb.operrsta = 0; | |
1189 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
1190 | if (!vdpoll(vm, 5)) { | |
1191 | printf(" during dump\n"); | |
1192 | return (EIO); | |
1193 | } | |
1194 | if (vd->vd_dcb.operrsta & VDERR_HARD) { | |
1195 | printf("dk%d: hard error, status=%b\n", unit, | |
1196 | vd->vd_dcb.operrsta, VDERRBITS); | |
1197 | return (EIO); | |
1198 | } | |
1199 | start += nsec * lp->d_secsize; | |
1200 | num -= nsec; | |
9d915fad | 1201 | } |
7bae1a62 | 1202 | return (0); |
210a9f40 SL |
1203 | } |
1204 | ||
1205 | vdsize(dev) | |
9d915fad | 1206 | dev_t dev; |
210a9f40 | 1207 | { |
7bae1a62 SL |
1208 | register int unit = vdunit(dev); |
1209 | register struct dksoftc *dk; | |
1210 | struct vba_device *vi; | |
1211 | struct disklabel *lp; | |
210a9f40 | 1212 | |
7bae1a62 SL |
1213 | if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 || |
1214 | (dk = &dksoftc[unit])->dk_state != OPEN) | |
9d915fad | 1215 | return (-1); |
7bae1a62 | 1216 | lp = &dklabel[unit]; |
d99b7c9d | 1217 | #ifdef SECSIZE |
4f42a6a1 | 1218 | return ((int)lp->d_partitions[vdpart(dev)].p_size); |
d99b7c9d MK |
1219 | #else SECSIZE |
1220 | return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift); | |
1221 | #endif SECSIZE | |
210a9f40 SL |
1222 | } |
1223 | ||
9d915fad | 1224 | /* |
261c73f6 | 1225 | * Initialize controller. |
9d915fad | 1226 | */ |
261c73f6 MK |
1227 | vdinit_ctlr(vm, vd) |
1228 | struct vba_ctlr *vm; | |
1229 | struct vdsoftc *vd; | |
210a9f40 | 1230 | { |
7bae1a62 | 1231 | register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; |
261c73f6 | 1232 | |
7bae1a62 SL |
1233 | if (vd->vd_type == VDTYPE_SMDE) { |
1234 | vdaddr->vdcsr = 0; | |
1235 | vdaddr->vdtcf_mdcb = AM_ENPDA; | |
1236 | vdaddr->vdtcf_dcb = AM_ENPDA; | |
1237 | vdaddr->vdtcf_trail = AM_ENPDA; | |
1238 | vdaddr->vdtcf_data = AM_ENPDA; | |
261c73f6 MK |
1239 | vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE | |
1240 | XMD_32BIT | BSZ_16WRD | | |
9d915fad SL |
1241 | CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR; |
1242 | } | |
07cd2d63 | 1243 | if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) { |
261c73f6 | 1244 | printf("vd%d: %s cmd failed\n", vm->um_ctlr, |
7bae1a62 | 1245 | vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag"); |
261c73f6 | 1246 | return (0); |
9d915fad | 1247 | } |
261c73f6 MK |
1248 | vd->vd_secsize = vdaddr->vdsecsize << 1; |
1249 | return (1); | |
1250 | } | |
1251 | ||
1252 | /* | |
1253 | * Perform a controller reset. | |
1254 | */ | |
1255 | vdreset_ctlr(vm) | |
1256 | register struct vba_ctlr *vm; | |
1257 | { | |
1258 | register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; | |
1259 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; | |
1260 | register int unit; | |
1261 | struct vba_device *vi; | |
1262 | ||
1263 | VDRESET(vdaddr, vd->vd_type); | |
1264 | if (vdinit_ctlr(vm, vd) == 0) | |
1265 | return; | |
7bae1a62 SL |
1266 | for (unit = 0; unit < NDK; unit++) |
1267 | if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive) | |
1268 | (void) vdreset_drive(vi); | |
1269 | } | |
1270 | ||
1271 | vdreset_drive(vi) | |
1272 | register struct vba_device *vi; | |
1273 | { | |
1274 | register struct disklabel *lp = &dklabel[vi->ui_unit]; | |
1275 | struct vba_ctlr *vm = vdminfo[vi->ui_ctlr]; | |
1276 | struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; | |
f9e93bbe MK |
1277 | register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr]; |
1278 | register struct dksoftc *dk = &dksoftc[vi->ui_unit]; | |
261c73f6 | 1279 | int config_status, config_ecode, saw_drive = 0; |
7bae1a62 | 1280 | |
261c73f6 MK |
1281 | #ifdef notdef |
1282 | /* | |
1283 | * check for ESDI distribution panel already configured, | |
1284 | * e.g. on boot drive, or if PROBE on controller actually | |
1285 | * worked. Status will be zero if drive hasn't | |
1286 | * been probed yet. | |
1287 | */ | |
1288 | #if STA_ESDI != 0 | |
1289 | if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI) | |
1290 | lp->d_devflags |= VD_ESDI; | |
1291 | #endif | |
1292 | #endif | |
7bae1a62 SL |
1293 | top: |
1294 | vd->vd_dcb.opcode = VDOP_CONFIG; /* command */ | |
1295 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1296 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
1297 | vd->vd_dcb.operrsta = 0; | |
f9e93bbe | 1298 | vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags; |
7bae1a62 SL |
1299 | vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders; |
1300 | vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks; | |
1301 | if (vd->vd_type == VDTYPE_SMDE) { | |
d99b7c9d | 1302 | vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long); |
7bae1a62 | 1303 | vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors; |
1f9a1539 | 1304 | vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack; |
261c73f6 MK |
1305 | vd->vd_dcb.trail.rstrail.recovery = |
1306 | (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL : | |
1307 | (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM)); | |
7bae1a62 SL |
1308 | } else |
1309 | vd->vd_dcb.trailcnt = 2; /* XXX */ | |
1310 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1311 | vd->vd_mdcb.mdcb_status = 0; | |
1312 | VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type); | |
1313 | if (!vdpoll(vm, 5)) { | |
1314 | printf(" during config\n"); | |
1315 | return (0); | |
9d915fad | 1316 | } |
261c73f6 MK |
1317 | config_status = vd->vd_dcb.operrsta; |
1318 | config_ecode = (u_char)vd->vd_dcb.err_code; | |
1319 | if (config_status & VDERR_HARD) { | |
f9e93bbe | 1320 | if (vd->vd_type == VDTYPE_SMDE) { |
261c73f6 MK |
1321 | /* |
1322 | * If drive status was updated successfully, | |
1323 | * STA_US (unit selected) should be set | |
1324 | * if the drive is attached and powered up. | |
1325 | * (But only if we've guessed right on SMD | |
1326 | * vs. ESDI; if that flag is wrong, we won't | |
1327 | * see the drive.) If we don't see STA_US | |
1328 | * with either SMD or ESDI set for the unit, | |
1329 | * we assume that the drive doesn't exist, | |
1330 | * and don't wait for it to spin up. | |
1331 | */ | |
1332 | (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave); | |
1333 | uncache(&vdaddr->vdstatus[vi->ui_slave]); | |
1334 | if (vdaddr->vdstatus[vi->ui_slave] & STA_US) | |
1335 | saw_drive = 1; | |
1336 | else if (lp->d_devflags == 0) { | |
f9e93bbe MK |
1337 | lp->d_devflags = VD_ESDI; |
1338 | goto top; | |
1339 | } | |
261c73f6 MK |
1340 | } else |
1341 | saw_drive = 1; | |
1342 | if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0) | |
f9e93bbe | 1343 | printf("dk%d: config error %b ecode %x\n", vi->ui_unit, |
261c73f6 MK |
1344 | config_status, VDERRBITS, config_ecode); |
1345 | else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) { | |
7bae1a62 SL |
1346 | int started; |
1347 | ||
f9e93bbe | 1348 | printf(" starting drives, wait ... "); |
7bae1a62 SL |
1349 | vd->vd_flags |= VD_STARTED; |
1350 | started = (vdcmd(vm, VDOP_START, 10) == 1); | |
1351 | DELAY(62000000); | |
07cd2d63 | 1352 | printf("done\n"); |
f9e93bbe | 1353 | lp->d_devflags = 0; |
7bae1a62 SL |
1354 | if (started) |
1355 | goto top; | |
1356 | } | |
1357 | return (0); | |
1358 | } | |
f9e93bbe | 1359 | dk->dk_dcb.devselect |= lp->d_devflags; |
7bae1a62 | 1360 | return (1); |
9d915fad | 1361 | } |
210a9f40 | 1362 | |
9d915fad | 1363 | /* |
7bae1a62 | 1364 | * Perform a command w/o trailer. |
9d915fad | 1365 | */ |
07cd2d63 | 1366 | vdcmd(vm, cmd, t, slave) |
7bae1a62 | 1367 | register struct vba_ctlr *vm; |
9d915fad | 1368 | { |
7bae1a62 SL |
1369 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; |
1370 | ||
1371 | vd->vd_dcb.opcode = cmd; /* command */ | |
1372 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1373 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
1374 | vd->vd_dcb.operrsta = 0; | |
07cd2d63 | 1375 | vd->vd_dcb.devselect = slave; |
7bae1a62 SL |
1376 | vd->vd_dcb.trailcnt = 0; |
1377 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1378 | vd->vd_mdcb.mdcb_status = 0; | |
1379 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
1380 | if (!vdpoll(vm, t)) { | |
1381 | printf(" during init\n"); | |
82bc5dc5 MK |
1382 | return (0); |
1383 | } | |
7bae1a62 | 1384 | return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0); |
9d915fad SL |
1385 | } |
1386 | ||
7c4f3479 | 1387 | /* |
7bae1a62 SL |
1388 | * Poll controller until operation |
1389 | * completes or timeout expires. | |
7c4f3479 | 1390 | */ |
7bae1a62 SL |
1391 | vdpoll(vm, t) |
1392 | register struct vba_ctlr *vm; | |
7c4f3479 SL |
1393 | register int t; |
1394 | { | |
7bae1a62 SL |
1395 | register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr]; |
1396 | register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr; | |
7c4f3479 SL |
1397 | |
1398 | t *= 1000; | |
82bc5dc5 | 1399 | for (;;) { |
7bae1a62 SL |
1400 | uncache(&vd->vd_dcb.operrsta); |
1401 | if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT)) | |
82bc5dc5 | 1402 | break; |
7c4f3479 | 1403 | if (--t <= 0) { |
7bae1a62 SL |
1404 | printf("vd%d: controller timeout", vm->um_ctlr); |
1405 | VDABORT(vdaddr, vd->vd_type); | |
7c4f3479 SL |
1406 | return (0); |
1407 | } | |
82bc5dc5 | 1408 | DELAY(1000); |
7c4f3479 | 1409 | } |
7bae1a62 SL |
1410 | if (vd->vd_type == VDTYPE_SMDE) { |
1411 | do { | |
82bc5dc5 | 1412 | DELAY(50); |
7bae1a62 SL |
1413 | uncache(&vdaddr->vdcsr); |
1414 | } while (vdaddr->vdcsr & CS_GO); | |
f9e93bbe MK |
1415 | DELAY(300); |
1416 | uncache(&vd->vd_dcb.err_code); | |
7c4f3479 SL |
1417 | } |
1418 | DELAY(200); | |
7bae1a62 | 1419 | uncache(&vd->vd_dcb.operrsta); |
7c4f3479 SL |
1420 | return (1); |
1421 | } | |
1422 | ||
7bae1a62 SL |
1423 | #ifdef COMPAT_42 |
1424 | struct vdst { | |
1425 | int nsec; /* sectors/track */ | |
1426 | int ntrack; /* tracks/cylinder */ | |
1427 | int ncyl; /* cylinders */ | |
f9e93bbe | 1428 | int secsize; /* sector size */ |
7bae1a62 SL |
1429 | char *name; /* type name */ |
1430 | struct { | |
1431 | int off; /* partition offset in sectors */ | |
1432 | int size; /* partition size in sectors */ | |
4f42a6a1 | 1433 | } parts[8]; |
7bae1a62 | 1434 | } vdst[] = { |
f9e93bbe MK |
1435 | { 66, 23, 850, 512, "NEC 800", |
1436 | {0, 1290300}, /* a cyl 0 - 849 */ | |
1437 | }, | |
ef960e6f KB |
1438 | { 64, 20, 842, 512, "2361a", |
1439 | {0, 61440}, /* a cyl 0 - 47 */ | |
1440 | {61440, 67840}, /* b cyl 48 - 100 */ | |
1441 | {129280, 942080}, /* c cyl 101 - 836 */ | |
1442 | {0, 1071360}, /* d cyl 0 - 836 */ | |
1443 | {449280, 311040}, /* e cyl 351 - 593 */ | |
1444 | {760320, 311040}, /* f cyl 594 - 836 */ | |
1445 | {449280, 622080}, /* g cyl 351 - 836 */ | |
1446 | {129280, 320000} /* h cyl 101 - 350 */ | |
1447 | }, | |
f9e93bbe | 1448 | { 48, 24, 711, 512, "xsd", |
451160eb MK |
1449 | {0, 61056}, /* a cyl 0 - 52 */ |
1450 | {61056, 61056}, /* b cyl 53 - 105 */ | |
1451 | {122112, 691200}, /* c cyl 106 - 705 */ | |
1452 | {237312, 576000}, /* d cyl 206 - 705 */ | |
1453 | {352512, 460800}, /* e cyl 306 - 705 */ | |
1454 | {467712, 345600}, /* f cyl 406 - 705 */ | |
1455 | {582912, 230400}, /* g cyl 506 - 705 */ | |
1456 | {698112, 115200} /* h cyl 606 - 705 */ | |
4f42a6a1 | 1457 | }, |
f9e93bbe | 1458 | { 44, 20, 842, 512, "eagle", |
1f9a1539 MK |
1459 | {0, 52800}, /* egl0a cyl 0 - 59 */ |
1460 | {52800, 66000}, /* egl0b cyl 60 - 134 */ | |
1461 | {118800, 617760}, /* egl0c cyl 135 - 836 */ | |
d99b7c9d | 1462 | {736560, 4400}, /* egl0d cyl 837 - 841 */ |
451160eb MK |
1463 | {0, 736560}, /* egl0e cyl 0 - 836 */ |
1464 | {0, 740960}, /* egl0f cyl 0 - 841 */ | |
1f9a1539 MK |
1465 | {118800, 310640}, /* egl0g cyl 135 - 487 */ |
1466 | {429440, 307120} /* egl0h cyl 488 - 836 */ | |
4f42a6a1 | 1467 | }, |
f9e93bbe | 1468 | { 64, 10, 823, 512, "fuj", |
451160eb MK |
1469 | {0, 38400}, /* fuj0a cyl 0 - 59 */ |
1470 | {38400, 48000}, /* fuj0b cyl 60 - 134 */ | |
1471 | {86400, 437120}, /* fuj0c cyl 135 - 817 */ | |
1472 | {159360, 364160}, /* fuj0d cyl 249 - 817 */ | |
1473 | {232320, 291200}, /* fuj0e cyl 363 - 817 */ | |
1474 | {305280, 218240}, /* fuj0f cyl 477 - 817 */ | |
1475 | {378240, 145280}, /* fuj0g cyl 591 - 817 */ | |
1476 | {451200, 72320} /* fug0h cyl 705 - 817 */ | |
4f42a6a1 | 1477 | }, |
f9e93bbe | 1478 | { 32, 24, 711, 512, "xfd", |
d99b7c9d MK |
1479 | { 0, 40704 }, /* a cyl 0 - 52 */ |
1480 | { 40704, 40704 }, /* b cyl 53 - 105 */ | |
1481 | { 81408, 460800 }, /* c cyl 106 - 705 */ | |
1482 | { 0, 81408 }, /* d cyl 709 - 710 (a & b) */ | |
1483 | { 0, 542208 }, /* e cyl 0 - 705 */ | |
1484 | { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */ | |
1485 | { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */ | |
1486 | { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */ | |
4f42a6a1 | 1487 | }, |
f9e93bbe | 1488 | { 32, 19, 823, 512, "smd", |
451160eb MK |
1489 | {0, 40128}, /* a cyl 0-65 */ |
1490 | {40128, 27360}, /* b cyl 66-110 */ | |
1491 | {67488, 429856}, /* c cyl 111-817 */ | |
1492 | {139232, 358112}, /* d cyl 229 - 817 */ | |
1493 | {210976, 286368}, /* e cyl 347 - 817 */ | |
1494 | {282720, 214624}, /* f cyl 465 - 817 */ | |
1495 | {354464, 142880}, /* g cyl 583 - 817 */ | |
1496 | {426208, 71136} /* h cyl 701 - 817 */ | |
4f42a6a1 | 1497 | }, |
f9e93bbe MK |
1498 | { 18, 15, 1224, 1024, "mxd", |
1499 | {0, 21600}, /* a cyl 0-79 */ | |
1500 | {21600, 22410}, /* b cyl 80-162 */ | |
1501 | {44010, 285120}, /* c cyl 163-1217 */ | |
1502 | #ifdef notyet | |
1503 | {x, 237600}, /* d cyl y - 1217 */ | |
1504 | {x, 190080}, /* e cyl y - 1217 */ | |
1505 | {x, 142560}, /* f cyl y - 1217 */ | |
1506 | {x, 95040}, /* g cyl y - 1217 */ | |
1507 | {x, 47520} /* h cyl 701 - 817 */ | |
1508 | #endif | |
1509 | }, | |
1510 | { 32, 10, 823, 512, "fsd", | |
d99b7c9d MK |
1511 | {0, 19200}, /* a cyl 0 - 59 */ |
1512 | {19200, 24000}, /* b cyl 60 - 134 */ | |
1513 | {43200, 218560}, /* c cyl 135 - 817 */ | |
4f42a6a1 | 1514 | } |
7bae1a62 SL |
1515 | }; |
1516 | #define NVDST (sizeof (vdst) / sizeof (vdst[0])) | |
1517 | ||
9d915fad | 1518 | /* |
7bae1a62 SL |
1519 | * Construct a label for an unlabeled pack. We |
1520 | * deduce the drive type by reading from the last | |
1521 | * track on successively smaller drives until we | |
1522 | * don't get an error. | |
9d915fad | 1523 | */ |
7bae1a62 SL |
1524 | vdmaptype(vi, lp) |
1525 | register struct vba_device *vi; | |
1526 | register struct disklabel *lp; | |
9d915fad | 1527 | { |
7bae1a62 SL |
1528 | register struct vdsoftc *vd; |
1529 | register struct vdst *p; | |
f9e93bbe | 1530 | struct vba_ctlr *vm = vi->ui_mi; |
7bae1a62 | 1531 | int i; |
9d915fad | 1532 | |
7bae1a62 SL |
1533 | vd = &vdsoftc[vi->ui_ctlr]; |
1534 | for (p = vdst; p < &vdst[NVDST]; p++) { | |
1535 | if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32) | |
1536 | continue; | |
1537 | lp->d_nsectors = p->nsec; | |
1538 | lp->d_ntracks = p->ntrack; | |
1539 | lp->d_ncylinders = p->ncyl; | |
f9e93bbe | 1540 | lp->d_secsize = p->secsize; |
07cd2d63 | 1541 | DELAY(100000); |
7bae1a62 SL |
1542 | if (!vdreset_drive(vi)) |
1543 | return (0); | |
07cd2d63 | 1544 | DELAY(100000); |
7bae1a62 SL |
1545 | vd->vd_dcb.opcode = VDOP_RD; |
1546 | vd->vd_dcb.intflg = DCBINT_NONE; | |
1547 | vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */ | |
f9e93bbe | 1548 | vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect; |
d99b7c9d | 1549 | vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long); |
1f9a1539 MK |
1550 | vd->vd_dcb.trail.rwtrail.memadr = |
1551 | vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf); | |
f9e93bbe | 1552 | vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short); |
7bae1a62 SL |
1553 | vd->vd_dcb.operrsta = 0; |
1554 | vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2; | |
1555 | vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1; | |
1556 | vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1; | |
1557 | vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys; | |
1558 | vd->vd_mdcb.mdcb_status = 0; | |
1559 | VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type); | |
1560 | if (!vdpoll(vm, 60)) | |
1561 | printf(" during probe\n"); | |
1562 | if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0) | |
1563 | break; | |
210a9f40 | 1564 | } |
f9e93bbe | 1565 | if (p >= &vdst[NVDST]) |
7bae1a62 | 1566 | return (0); |
f9e93bbe | 1567 | |
4f42a6a1 | 1568 | for (i = 0; i < 8; i++) { |
7bae1a62 SL |
1569 | lp->d_partitions[i].p_offset = p->parts[i].off; |
1570 | lp->d_partitions[i].p_size = p->parts[i].size; | |
1571 | } | |
4f42a6a1 | 1572 | lp->d_npartitions = 8; |
7bae1a62 | 1573 | lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; |
7bae1a62 SL |
1574 | bcopy(p->name, lp->d_typename, 4); |
1575 | return (1); | |
210a9f40 | 1576 | } |
7bae1a62 | 1577 | #endif COMPAT_42 |
9d915fad | 1578 | #endif |