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