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