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