ed_mca.c revision 1.55.2.1 1 /* $NetBSD: ed_mca.c,v 1.55.2.1 2014/04/07 03:37:33 tls Exp $ */
2
3 /*
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jaromir Dolecek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Disk drive goo for MCA ESDI controller driver.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.55.2.1 2014/04/07 03:37:33 tls Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/conf.h>
43 #include <sys/file.h>
44 #include <sys/stat.h>
45 #include <sys/ioctl.h>
46 #include <sys/buf.h>
47 #include <sys/bufq.h>
48 #include <sys/uio.h>
49 #include <sys/malloc.h>
50 #include <sys/device.h>
51 #include <sys/disklabel.h>
52 #include <sys/disk.h>
53 #include <sys/syslog.h>
54 #include <sys/proc.h>
55 #include <sys/vnode.h>
56 #include <sys/rnd.h>
57
58 #include <sys/intr.h>
59 #include <sys/bus.h>
60
61 #include <dev/mca/mcavar.h>
62
63 #include <dev/mca/edcreg.h>
64 #include <dev/mca/edvar.h>
65 #include <dev/mca/edcvar.h>
66
67 /* #define ATADEBUG */
68
69 #ifdef ATADEBUG
70 #define ATADEBUG_PRINT(args, level) printf args
71 #else
72 #define ATADEBUG_PRINT(args, level)
73 #endif
74
75 #define EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART))
76
77 static int ed_mca_probe (device_t, cfdata_t, void *);
78 static void ed_mca_attach (device_t, device_t, void *);
79
80 CFATTACH_DECL_NEW(ed_mca, sizeof(struct ed_softc),
81 ed_mca_probe, ed_mca_attach, NULL, NULL);
82
83 extern struct cfdriver ed_cd;
84
85 static int ed_get_params(struct ed_softc *, int *);
86 static void edgetdisklabel(dev_t, struct ed_softc *);
87 static void edgetdefaultlabel(struct ed_softc *, struct disklabel *);
88
89 dev_type_open(edmcaopen);
90 dev_type_close(edmcaclose);
91 dev_type_read(edmcaread);
92 dev_type_write(edmcawrite);
93 dev_type_ioctl(edmcaioctl);
94 dev_type_strategy(edmcastrategy);
95 dev_type_dump(edmcadump);
96 dev_type_size(edmcasize);
97
98 const struct bdevsw ed_bdevsw = {
99 .d_open = edmcaopen,
100 .d_close = edmcaclose,
101 .d_strategy = edmcastrategy,
102 .d_ioctl = edmcaioctl,
103 .d_dump = edmcadump,
104 .d_psize = edmcasize,
105 .d_flag = D_DISK
106 };
107
108 const struct cdevsw ed_cdevsw = {
109 .d_open = edmcaopen,
110 .d_close = edmcaclose,
111 .d_read = edmcaread,
112 .d_write = edmcawrite,
113 .d_ioctl = edmcaioctl,
114 .d_stop = nostop,
115 .d_tty = notty,
116 .d_poll = nopoll,
117 .d_mmap = nommap,
118 .d_kqfilter = nokqfilter,
119 .d_flag = D_DISK
120 };
121
122 static struct dkdriver eddkdriver = { edmcastrategy, minphys };
123
124 /*
125 * Just check if it's possible to identify the disk.
126 */
127 static int
128 ed_mca_probe(device_t parent, cfdata_t cf, void *aux)
129 {
130 struct edc_mca_softc *sc = device_private(parent);
131 struct ed_attach_args *eda = aux;
132 u_int16_t cmd_args[2];
133 int found = 1;
134
135 /*
136 * Get Device Configuration (09).
137 */
138 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */
139 cmd_args[1] = 0;
140 if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1))
141 found = 0;
142
143 return (found);
144 }
145
146 static void
147 ed_mca_attach(device_t parent, device_t self, void *aux)
148 {
149 struct ed_softc *ed = device_private(self);
150 struct edc_mca_softc *sc = device_private(parent);
151 struct ed_attach_args *eda = aux;
152 char pbuf[8];
153 int drv_flags;
154
155 ed->sc_dev = self;
156 ed->edc_softc = sc;
157 ed->sc_devno = eda->edc_drive;
158 edc_add_disk(sc, ed);
159
160 bufq_alloc(&ed->sc_q, "disksort", BUFQ_SORT_RAWBLOCK);
161 mutex_init(&ed->sc_q_lock, MUTEX_DEFAULT, IPL_VM);
162
163 if (ed_get_params(ed, &drv_flags)) {
164 printf(": IDENTIFY failed, no disk found\n");
165 return;
166 }
167
168 format_bytes(pbuf, sizeof(pbuf),
169 (u_int64_t) ed->sc_capacity * DEV_BSIZE);
170 printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n",
171 pbuf,
172 ed->cyl, ed->heads, ed->sectors,
173 ed->sc_capacity);
174
175 printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n",
176 device_xname(ed->sc_dev), ed->spares,
177 (drv_flags & (1 << 0)) ? "NoRetries" : "Retries",
178 (drv_flags & (1 << 1)) ? "Removable" : "Fixed",
179 (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew",
180 (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects",
181 (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK"
182 );
183
184 /*
185 * Initialize and attach the disk structure.
186 */
187 disk_init(&ed->sc_dk, device_xname(ed->sc_dev), &eddkdriver);
188 disk_attach(&ed->sc_dk);
189 rnd_attach_source(&ed->rnd_source, device_xname(ed->sc_dev),
190 RND_TYPE_DISK, RND_FLAG_DEFAULT);
191
192 ed->sc_flags |= EDF_INIT;
193
194 /*
195 * XXX We should try to discovery wedges here, but
196 * XXX that would mean being able to do I/O. Should
197 * XXX use config_defer() here.
198 */
199 }
200
201 /*
202 * Read/write routine for a buffer. Validates the arguments and schedules the
203 * transfer. Does not wait for the transfer to complete.
204 */
205 void
206 edmcastrategy(struct buf *bp)
207 {
208 struct ed_softc *ed;
209 struct disklabel *lp;
210 daddr_t blkno;
211
212 ed = device_lookup_private(&ed_cd, DISKUNIT(bp->b_dev));
213 lp = ed->sc_dk.dk_label;
214
215 ATADEBUG_PRINT(("edmcastrategy (%s)\n", device_xname(ed->sc_dev)),
216 DEBUG_XFERS);
217
218 /* Valid request? */
219 if (bp->b_blkno < 0 ||
220 (bp->b_bcount % lp->d_secsize) != 0 ||
221 (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) {
222 bp->b_error = EINVAL;
223 goto done;
224 }
225
226 /* If device invalidated (e.g. media change, door open), error. */
227 if ((ed->sc_flags & WDF_LOADED) == 0) {
228 bp->b_error = EIO;
229 goto done;
230 }
231
232 /* If it's a null transfer, return immediately. */
233 if (bp->b_bcount == 0)
234 goto done;
235
236 /*
237 * Do bounds checking, adjust transfer. if error, process.
238 * If end of partition, just return.
239 */
240 if (DISKPART(bp->b_dev) != RAW_PART &&
241 bounds_check_with_label(&ed->sc_dk, bp,
242 (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
243 goto done;
244
245 /*
246 * Now convert the block number to absolute and put it in
247 * terms of the device's logical block size.
248 */
249 if (lp->d_secsize >= DEV_BSIZE)
250 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
251 else
252 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
253
254 if (DISKPART(bp->b_dev) != RAW_PART)
255 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
256
257 bp->b_rawblkno = blkno;
258
259 /* Queue transfer on drive, activate drive and controller if idle. */
260 mutex_enter(&ed->sc_q_lock);
261 bufq_put(ed->sc_q, bp);
262 mutex_exit(&ed->sc_q_lock);
263
264 /* Ring the worker thread */
265 wakeup(ed->edc_softc);
266
267 return;
268 done:
269 /* Toss transfer; we're done early. */
270 bp->b_resid = bp->b_bcount;
271 biodone(bp);
272 }
273
274 int
275 edmcaread(dev_t dev, struct uio *uio, int flags)
276 {
277 ATADEBUG_PRINT(("edread\n"), DEBUG_XFERS);
278 return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio));
279 }
280
281 int
282 edmcawrite(dev_t dev, struct uio *uio, int flags)
283 {
284 ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS);
285 return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio));
286 }
287
288 int
289 edmcaopen(dev_t dev, int flag, int fmt, struct lwp *l)
290 {
291 struct ed_softc *wd;
292 int part, error;
293
294 ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS);
295 wd = device_lookup_private(&ed_cd, DISKUNIT(dev));
296 if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0)
297 return (ENXIO);
298
299 part = DISKPART(dev);
300
301 mutex_enter(&wd->sc_dk.dk_openlock);
302
303 /*
304 * If there are wedges, and this is not RAW_PART, then we
305 * need to fail.
306 */
307 if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) {
308 error = EBUSY;
309 goto bad1;
310 }
311
312 if (wd->sc_dk.dk_openmask != 0) {
313 /*
314 * If any partition is open, but the disk has been invalidated,
315 * disallow further opens.
316 */
317 if ((wd->sc_flags & WDF_LOADED) == 0) {
318 error = EIO;
319 goto bad1;
320 }
321 } else {
322 if ((wd->sc_flags & WDF_LOADED) == 0) {
323 int s;
324
325 wd->sc_flags |= WDF_LOADED;
326
327 /* Load the physical device parameters. */
328 s = splbio();
329 ed_get_params(wd, NULL);
330 splx(s);
331
332 /* Load the partition info if not already loaded. */
333 edgetdisklabel(dev, wd);
334 }
335 }
336
337 /* Check that the partition exists. */
338 if (part != RAW_PART &&
339 (part >= wd->sc_dk.dk_label->d_npartitions ||
340 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
341 error = ENXIO;
342 goto bad1;
343 }
344
345 /* Insure only one open at a time. */
346 switch (fmt) {
347 case S_IFCHR:
348 wd->sc_dk.dk_copenmask |= (1 << part);
349 break;
350 case S_IFBLK:
351 wd->sc_dk.dk_bopenmask |= (1 << part);
352 break;
353 }
354 wd->sc_dk.dk_openmask =
355 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
356
357 error = 0;
358 bad1:
359 mutex_exit(&wd->sc_dk.dk_openlock);
360 return (error);
361 }
362
363 int
364 edmcaclose(dev_t dev, int flag, int fmt, struct lwp *l)
365 {
366 struct ed_softc *wd = device_lookup_private(&ed_cd, DISKUNIT(dev));
367 int part = DISKPART(dev);
368
369 ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS);
370
371 mutex_enter(&wd->sc_dk.dk_openlock);
372
373 switch (fmt) {
374 case S_IFCHR:
375 wd->sc_dk.dk_copenmask &= ~(1 << part);
376 break;
377 case S_IFBLK:
378 wd->sc_dk.dk_bopenmask &= ~(1 << part);
379 break;
380 }
381 wd->sc_dk.dk_openmask =
382 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
383
384 if (wd->sc_dk.dk_openmask == 0) {
385 #if 0
386 wd_flushcache(wd, AT_WAIT);
387 #endif
388 /* XXXX Must wait for I/O to complete! */
389
390 if (! (wd->sc_flags & WDF_KLABEL))
391 wd->sc_flags &= ~WDF_LOADED;
392 }
393
394 mutex_exit(&wd->sc_dk.dk_openlock);
395
396 return 0;
397 }
398
399 static void
400 edgetdefaultlabel(struct ed_softc *ed, struct disklabel *lp)
401 {
402 ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS);
403 memset(lp, 0, sizeof(struct disklabel));
404
405 lp->d_secsize = DEV_BSIZE;
406 lp->d_ntracks = ed->heads;
407 lp->d_nsectors = ed->sectors;
408 lp->d_ncylinders = ed->cyl;
409 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
410
411 lp->d_type = DTYPE_ESDI;
412
413 strncpy(lp->d_typename, "ESDI", 16);
414 strncpy(lp->d_packname, "fictitious", 16);
415 lp->d_secperunit = ed->sc_capacity;
416 lp->d_rpm = 3600;
417 lp->d_interleave = 1;
418 lp->d_flags = 0;
419
420 lp->d_partitions[RAW_PART].p_offset = 0;
421 lp->d_partitions[RAW_PART].p_size =
422 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
423 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
424 lp->d_npartitions = RAW_PART + 1;
425
426 lp->d_magic = DISKMAGIC;
427 lp->d_magic2 = DISKMAGIC;
428 lp->d_checksum = dkcksum(lp);
429 }
430
431 /*
432 * Fabricate a default disk label, and try to read the correct one.
433 */
434 static void
435 edgetdisklabel(dev_t dev, struct ed_softc *ed)
436 {
437 struct disklabel *lp = ed->sc_dk.dk_label;
438 const char *errstring;
439
440 ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS);
441
442 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
443
444 edgetdefaultlabel(ed, lp);
445
446 errstring = readdisklabel(
447 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
448 if (errstring) {
449 /*
450 * This probably happened because the drive's default
451 * geometry doesn't match the DOS geometry. We
452 * assume the DOS geometry is now in the label and try
453 * again. XXX This is a kluge.
454 */
455 #if 0
456 if (wd->drvp->state > RECAL)
457 wd->drvp->drive_flags |= ATA_DRIVE_RESET;
458 #endif
459 errstring = readdisklabel(EDLABELDEV(dev),
460 edmcastrategy, lp, ed->sc_dk.dk_cpulabel);
461 }
462 if (errstring) {
463 printf("%s: %s\n", device_xname(ed->sc_dev), errstring);
464 return;
465 }
466 }
467
468 int
469 edmcaioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l)
470 {
471 struct ed_softc *ed = device_lookup_private(&ed_cd, DISKUNIT(dev));
472 int error;
473
474 ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS);
475
476 if ((ed->sc_flags & WDF_LOADED) == 0)
477 return EIO;
478
479 switch (xfer) {
480 case DIOCGDINFO:
481 *(struct disklabel *)addr = *(ed->sc_dk.dk_label);
482 return 0;
483
484 case DIOCGPART:
485 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label;
486 ((struct partinfo *)addr)->part =
487 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)];
488 return 0;
489
490 case DIOCWDINFO:
491 case DIOCSDINFO:
492 {
493 struct disklabel *lp;
494
495 lp = (struct disklabel *)addr;
496
497 if ((flag & FWRITE) == 0)
498 return EBADF;
499
500 mutex_enter(&ed->sc_dk.dk_openlock);
501 ed->sc_flags |= WDF_LABELLING;
502
503 error = setdisklabel(ed->sc_dk.dk_label,
504 lp, /*wd->sc_dk.dk_openmask : */0,
505 ed->sc_dk.dk_cpulabel);
506 if (error == 0) {
507 #if 0
508 if (wd->drvp->state > RECAL)
509 wd->drvp->drive_flags |= ATA_DRIVE_RESET;
510 #endif
511 if (xfer == DIOCWDINFO)
512 error = writedisklabel(EDLABELDEV(dev),
513 edmcastrategy, ed->sc_dk.dk_label,
514 ed->sc_dk.dk_cpulabel);
515 }
516
517 ed->sc_flags &= ~WDF_LABELLING;
518 mutex_exit(&ed->sc_dk.dk_openlock);
519 return (error);
520 }
521
522 case DIOCKLABEL:
523 if (*(int *)addr)
524 ed->sc_flags |= WDF_KLABEL;
525 else
526 ed->sc_flags &= ~WDF_KLABEL;
527 return 0;
528
529 case DIOCWLABEL:
530 if ((flag & FWRITE) == 0)
531 return EBADF;
532 if (*(int *)addr)
533 ed->sc_flags |= WDF_WLABEL;
534 else
535 ed->sc_flags &= ~WDF_WLABEL;
536 return 0;
537
538 case DIOCGDEFLABEL:
539 edgetdefaultlabel(ed, (struct disklabel *)addr);
540 return 0;
541
542 #if 0
543 case DIOCWFORMAT:
544 if ((flag & FWRITE) == 0)
545 return EBADF;
546 {
547 register struct format_op *fop;
548 struct iovec aiov;
549 struct uio auio;
550
551 fop = (struct format_op *)addr;
552 aiov.iov_base = fop->df_buf;
553 aiov.iov_len = fop->df_count;
554 auio.uio_iov = &aiov;
555 auio.uio_iovcnt = 1;
556 auio.uio_resid = fop->df_count;
557 auio.uio_segflg = 0;
558 auio.uio_offset =
559 fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
560 auio.uio_lwp = l;
561 error = physio(wdformat, NULL, dev, B_WRITE, minphys,
562 &auio);
563 fop->df_count -= auio.uio_resid;
564 fop->df_reg[0] = wdc->sc_status;
565 fop->df_reg[1] = wdc->sc_error;
566 return error;
567 }
568 #endif
569
570 case DIOCAWEDGE:
571 {
572 struct dkwedge_info *dkw = (void *) addr;
573
574 if ((flag & FWRITE) == 0)
575 return (EBADF);
576
577 /* If the ioctl happens here, the parent is us. */
578 strlcpy(dkw->dkw_parent, device_xname(ed->sc_dev),
579 sizeof(dkw->dkw_parent));
580 return (dkwedge_add(dkw));
581 }
582
583 case DIOCDWEDGE:
584 {
585 struct dkwedge_info *dkw = (void *) addr;
586
587 if ((flag & FWRITE) == 0)
588 return (EBADF);
589
590 /* If the ioctl happens here, the parent is us. */
591 strlcpy(dkw->dkw_parent, device_xname(ed->sc_dev),
592 sizeof(dkw->dkw_parent));
593 return (dkwedge_del(dkw));
594 }
595
596 case DIOCLWEDGES:
597 {
598 struct dkwedge_list *dkwl = (void *) addr;
599
600 return (dkwedge_list(&ed->sc_dk, dkwl, l));
601 }
602
603 default:
604 return ENOTTY;
605 }
606
607 #ifdef DIAGNOSTIC
608 panic("edioctl: impossible");
609 #endif
610 }
611
612 int
613 edmcasize(dev_t dev)
614 {
615 struct ed_softc *wd;
616 int part, omask;
617 int size;
618
619 ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS);
620
621 wd = device_lookup_private(&ed_cd, DISKUNIT(dev));
622 if (wd == NULL)
623 return (-1);
624
625 part = DISKPART(dev);
626 omask = wd->sc_dk.dk_openmask & (1 << part);
627
628 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0)
629 return (-1);
630 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
631 size = -1;
632 else
633 size = wd->sc_dk.dk_label->d_partitions[part].p_size *
634 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
635 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0)
636 return (-1);
637 return (size);
638 }
639
640 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
641 static int eddoingadump = 0;
642 static int eddumprecalibrated = 0;
643 static int eddumpmulti = 1;
644
645 /*
646 * Dump core after a system crash.
647 */
648 int
649 edmcadump(dev_t dev, daddr_t blkno, void *va, size_t size)
650 {
651 struct ed_softc *ed; /* disk unit to do the I/O */
652 struct disklabel *lp; /* disk's disklabel */
653 int part;
654 int nblks; /* total number of sectors left to write */
655 int error;
656
657 /* Check if recursive dump; if so, punt. */
658 if (eddoingadump)
659 return EFAULT;
660 eddoingadump = 1;
661
662 ed = device_lookup_private(&ed_cd, DISKUNIT(dev));
663 if (ed == NULL)
664 return (ENXIO);
665
666 part = DISKPART(dev);
667
668 /* Make sure it was initialized. */
669 if ((ed->sc_flags & EDF_INIT) == 0)
670 return ENXIO;
671
672 /* Convert to disk sectors. Request must be a multiple of size. */
673 lp = ed->sc_dk.dk_label;
674 if ((size % lp->d_secsize) != 0)
675 return EFAULT;
676 nblks = size / lp->d_secsize;
677 blkno = blkno / (lp->d_secsize / DEV_BSIZE);
678
679 /* Check transfer bounds against partition size. */
680 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))
681 return EINVAL;
682
683 /* Offset block number to start of partition. */
684 blkno += lp->d_partitions[part].p_offset;
685
686 /* Recalibrate, if first dump transfer. */
687 if (eddumprecalibrated == 0) {
688 eddumprecalibrated = 1;
689 eddumpmulti = 8;
690 #if 0
691 wd->drvp->state = RESET;
692 #endif
693 }
694
695 while (nblks > 0) {
696 error = edc_bio(ed->edc_softc, ed, va, blkno,
697 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1);
698 if (error)
699 return (error);
700
701 /* update block count */
702 nblks -= min(nblks, eddumpmulti);
703 blkno += min(nblks, eddumpmulti);
704 va = (char *)va + min(nblks, eddumpmulti) * lp->d_secsize;
705 }
706
707 eddoingadump = 0;
708 return (0);
709 }
710
711 static int
712 ed_get_params(struct ed_softc *ed, int *drv_flags)
713 {
714 u_int16_t cmd_args[2];
715
716 /*
717 * Get Device Configuration (09).
718 */
719 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */
720 cmd_args[1] = 0;
721 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno,
722 cmd_args, 2, 1))
723 return (1);
724
725 ed->spares = ed->sense_data[1] >> 8;
726 if (drv_flags)
727 *drv_flags = ed->sense_data[1] & 0x1f;
728 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16);
729 /* Instead of using:
730 ed->cyl = ed->sense_data[4];
731 ed->heads = ed->sense_data[5] & 0xff;
732 ed->sectors = ed->sense_data[5] >> 8;
733 * we fabricate the numbers from RBA count, so that
734 * number of sectors is 32 and heads 64. This seems
735 * to be necessary for integrated ESDI controller.
736 */
737 ed->sectors = 32;
738 ed->heads = 64;
739 ed->cyl = ed->rba / (ed->heads * ed->sectors);
740 ed->sc_capacity = ed->rba;
741
742 return (0);
743 }
744