1 /* $NetBSD: ed_mca.c,v 1.24 2004/09/01 20:57:58 drochner 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.24 2004/09/01 20:57:58 drochner 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/uio.h> 54 #include <sys/malloc.h> 55 #include <sys/device.h> 56 #include <sys/disklabel.h> 57 #include <sys/disk.h> 58 #include <sys/syslog.h> 59 #include <sys/proc.h> 60 #include <sys/vnode.h> 61 #if NRND > 0 62 #include <sys/rnd.h> 63 #endif 64 65 #include <machine/intr.h> 66 #include <machine/bus.h> 67 68 #include <dev/mca/mcavar.h> 69 70 #include <dev/mca/edcreg.h> 71 #include <dev/mca/edvar.h> 72 #include <dev/mca/edcvar.h> 73 74 /* #define ATADEBUG */ 75 76 #ifdef ATADEBUG 77 #define ATADEBUG_PRINT(args, level) printf args 78 #else 79 #define ATADEBUG_PRINT(args, level) 80 #endif 81 82 #define EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART)) 83 84 static int ed_mca_probe __P((struct device *, struct cfdata *, void *)); 85 static void ed_mca_attach __P((struct device *, struct device *, void *)); 86 87 CFATTACH_DECL(ed_mca, sizeof(struct ed_softc), 88 ed_mca_probe, ed_mca_attach, NULL, NULL); 89 90 extern struct cfdriver ed_cd; 91 92 static int ed_get_params __P((struct ed_softc *, int *)); 93 static int ed_lock __P((struct ed_softc *)); 94 static void ed_unlock __P((struct ed_softc *)); 95 static void edgetdisklabel __P((dev_t, struct ed_softc *)); 96 static void edgetdefaultlabel __P((struct ed_softc *, struct disklabel *)); 97 98 dev_type_open(edmcaopen); 99 dev_type_close(edmcaclose); 100 dev_type_read(edmcaread); 101 dev_type_write(edmcawrite); 102 dev_type_ioctl(edmcaioctl); 103 dev_type_strategy(edmcastrategy); 104 dev_type_dump(edmcadump); 105 dev_type_size(edmcasize); 106 107 const struct bdevsw ed_bdevsw = { 108 edmcaopen, edmcaclose, edmcastrategy, edmcaioctl, 109 edmcadump, edmcasize, D_DISK 110 }; 111 112 const struct cdevsw ed_cdevsw = { 113 edmcaopen, edmcaclose, edmcaread, edmcawrite, edmcaioctl, 114 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 115 }; 116 117 static struct dkdriver eddkdriver = { edmcastrategy }; 118 119 /* 120 * Just check if it's possible to identify the disk. 121 */ 122 static int 123 ed_mca_probe(parent, cf, aux) 124 struct device *parent; 125 struct cfdata *cf; 126 void *aux; 127 { 128 u_int16_t cmd_args[2]; 129 struct edc_mca_softc *sc = (void *) parent; 130 struct ed_attach_args *eda = (struct ed_attach_args *) aux; 131 int found = 1; 132 133 /* 134 * Get Device Configuration (09). 135 */ 136 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 137 cmd_args[1] = 0; 138 if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1)) 139 found = 0; 140 141 return (found); 142 } 143 144 static void 145 ed_mca_attach(parent, self, aux) 146 struct device *parent, *self; 147 void *aux; 148 { 149 struct ed_softc *ed = (void *) self; 150 struct edc_mca_softc *sc = (void *) parent; 151 struct ed_attach_args *eda = (struct ed_attach_args *) aux; 152 char pbuf[8], lckname[10]; 153 int drv_flags; 154 155 ed->edc_softc = sc; 156 ed->sc_devno = eda->edc_drive; 157 edc_add_disk(sc, ed); 158 159 bufq_alloc(&ed->sc_q, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK); 160 simple_lock_init(&ed->sc_q_lock); 161 snprintf(lckname, sizeof(lckname), "%slck", ed->sc_dev.dv_xname); 162 lockinit(&ed->sc_lock, PRIBIO | PCATCH, lckname, 0, 0); 163 164 if (ed_get_params(ed, &drv_flags)) { 165 printf(": IDENTIFY failed, no disk found\n"); 166 return; 167 } 168 169 format_bytes(pbuf, sizeof(pbuf), 170 (u_int64_t) ed->sc_capacity * DEV_BSIZE); 171 printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n", 172 pbuf, 173 ed->cyl, ed->heads, ed->sectors, 174 ed->sc_capacity); 175 176 printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n", 177 ed->sc_dev.dv_xname, ed->spares, 178 (drv_flags & (1 << 0)) ? "NoRetries" : "Retries", 179 (drv_flags & (1 << 1)) ? "Removable" : "Fixed", 180 (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew", 181 (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects", 182 (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK" 183 ); 184 185 /* 186 * Initialize and attach the disk structure. 187 */ 188 ed->sc_dk.dk_driver = &eddkdriver; 189 ed->sc_dk.dk_name = ed->sc_dev.dv_xname; 190 disk_attach(&ed->sc_dk); 191 #if NRND > 0 192 rnd_attach_source(&ed->rnd_source, ed->sc_dev.dv_xname, 193 RND_TYPE_DISK, 0); 194 #endif 195 196 ed->sc_flags |= EDF_INIT; 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 bad; 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 bad; 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 bad: 265 bp->b_flags |= B_ERROR; 266 done: 267 /* Toss transfer; we're done early. */ 268 bp->b_resid = bp->b_bcount; 269 biodone(bp); 270 } 271 272 int 273 edmcaread(dev, uio, flags) 274 dev_t dev; 275 struct uio *uio; 276 int flags; 277 { 278 ATADEBUG_PRINT(("edread\n"), DEBUG_XFERS); 279 return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio)); 280 } 281 282 int 283 edmcawrite(dev, uio, flags) 284 dev_t dev; 285 struct uio *uio; 286 int flags; 287 { 288 ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS); 289 return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio)); 290 } 291 292 /* 293 * Wait interruptibly for an exclusive lock. 294 */ 295 static int 296 ed_lock(ed) 297 struct ed_softc *ed; 298 { 299 int error; 300 int s; 301 302 ATADEBUG_PRINT(("ed_lock\n"), DEBUG_FUNCS); 303 304 s = splbio(); 305 error = lockmgr(&ed->sc_lock, LK_EXCLUSIVE, NULL); 306 splx(s); 307 308 return (error); 309 } 310 311 /* 312 * Unlock and wake up any waiters. 313 */ 314 static void 315 ed_unlock(ed) 316 struct ed_softc *ed; 317 { 318 ATADEBUG_PRINT(("ed_unlock\n"), DEBUG_FUNCS); 319 320 (void) lockmgr(&ed->sc_lock, LK_RELEASE, NULL); 321 } 322 323 int 324 edmcaopen(dev, flag, fmt, p) 325 dev_t dev; 326 int flag, fmt; 327 struct proc *p; 328 { 329 struct ed_softc *wd; 330 int part, error; 331 332 ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS); 333 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 334 if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0) 335 return (ENXIO); 336 337 if ((error = ed_lock(wd)) != 0) 338 goto bad4; 339 340 if (wd->sc_dk.dk_openmask != 0) { 341 /* 342 * If any partition is open, but the disk has been invalidated, 343 * disallow further opens. 344 */ 345 if ((wd->sc_flags & WDF_LOADED) == 0) { 346 error = EIO; 347 goto bad3; 348 } 349 } else { 350 if ((wd->sc_flags & WDF_LOADED) == 0) { 351 int s; 352 353 wd->sc_flags |= WDF_LOADED; 354 355 /* Load the physical device parameters. */ 356 s = splbio(); 357 ed_get_params(wd, NULL); 358 splx(s); 359 360 /* Load the partition info if not already loaded. */ 361 edgetdisklabel(dev, wd); 362 } 363 } 364 365 part = DISKPART(dev); 366 367 /* Check that the partition exists. */ 368 if (part != RAW_PART && 369 (part >= wd->sc_dk.dk_label->d_npartitions || 370 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 371 error = ENXIO; 372 goto bad; 373 } 374 375 /* Insure only one open at a time. */ 376 switch (fmt) { 377 case S_IFCHR: 378 wd->sc_dk.dk_copenmask |= (1 << part); 379 break; 380 case S_IFBLK: 381 wd->sc_dk.dk_bopenmask |= (1 << part); 382 break; 383 } 384 wd->sc_dk.dk_openmask = 385 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 386 387 ed_unlock(wd); 388 return 0; 389 390 bad: 391 if (wd->sc_dk.dk_openmask == 0) { 392 } 393 394 bad3: 395 ed_unlock(wd); 396 bad4: 397 return (error); 398 } 399 400 int 401 edmcaclose(dev, flag, fmt, p) 402 dev_t dev; 403 int flag, fmt; 404 struct proc *p; 405 { 406 struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev)); 407 int part = DISKPART(dev); 408 int error; 409 410 ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS); 411 if ((error = ed_lock(wd)) != 0) 412 return error; 413 414 switch (fmt) { 415 case S_IFCHR: 416 wd->sc_dk.dk_copenmask &= ~(1 << part); 417 break; 418 case S_IFBLK: 419 wd->sc_dk.dk_bopenmask &= ~(1 << part); 420 break; 421 } 422 wd->sc_dk.dk_openmask = 423 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 424 425 if (wd->sc_dk.dk_openmask == 0) { 426 #if 0 427 wd_flushcache(wd, AT_WAIT); 428 #endif 429 /* XXXX Must wait for I/O to complete! */ 430 431 if (! (wd->sc_flags & WDF_KLABEL)) 432 wd->sc_flags &= ~WDF_LOADED; 433 } 434 435 ed_unlock(wd); 436 437 return 0; 438 } 439 440 static void 441 edgetdefaultlabel(ed, lp) 442 struct ed_softc *ed; 443 struct disklabel *lp; 444 { 445 ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 446 memset(lp, 0, sizeof(struct disklabel)); 447 448 lp->d_secsize = DEV_BSIZE; 449 lp->d_ntracks = ed->heads; 450 lp->d_nsectors = ed->sectors; 451 lp->d_ncylinders = ed->cyl; 452 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 453 454 lp->d_type = DTYPE_ESDI; 455 456 strncpy(lp->d_typename, "ESDI", 16); 457 strncpy(lp->d_packname, "fictitious", 16); 458 lp->d_secperunit = ed->sc_capacity; 459 lp->d_rpm = 3600; 460 lp->d_interleave = 1; 461 lp->d_flags = 0; 462 463 lp->d_partitions[RAW_PART].p_offset = 0; 464 lp->d_partitions[RAW_PART].p_size = 465 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 466 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 467 lp->d_npartitions = RAW_PART + 1; 468 469 lp->d_magic = DISKMAGIC; 470 lp->d_magic2 = DISKMAGIC; 471 lp->d_checksum = dkcksum(lp); 472 } 473 474 /* 475 * Fabricate a default disk label, and try to read the correct one. 476 */ 477 static void 478 edgetdisklabel(dev, ed) 479 dev_t dev; 480 struct ed_softc *ed; 481 { 482 struct disklabel *lp = ed->sc_dk.dk_label; 483 const char *errstring; 484 485 ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 486 487 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 488 489 edgetdefaultlabel(ed, lp); 490 491 errstring = readdisklabel( 492 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 493 if (errstring) { 494 /* 495 * This probably happened because the drive's default 496 * geometry doesn't match the DOS geometry. We 497 * assume the DOS geometry is now in the label and try 498 * again. XXX This is a kluge. 499 */ 500 #if 0 501 if (wd->drvp->state > RECAL) 502 wd->drvp->drive_flags |= DRIVE_RESET; 503 #endif 504 errstring = readdisklabel(EDLABELDEV(dev), 505 edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 506 } 507 if (errstring) { 508 printf("%s: %s\n", ed->sc_dev.dv_xname, errstring); 509 return; 510 } 511 } 512 513 int 514 edmcaioctl(dev, xfer, addr, flag, p) 515 dev_t dev; 516 u_long xfer; 517 caddr_t addr; 518 int flag; 519 struct proc *p; 520 { 521 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev)); 522 int error; 523 524 ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 525 526 if ((ed->sc_flags & WDF_LOADED) == 0) 527 return EIO; 528 529 switch (xfer) { 530 case DIOCGDINFO: 531 *(struct disklabel *)addr = *(ed->sc_dk.dk_label); 532 return 0; 533 534 case DIOCGPART: 535 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label; 536 ((struct partinfo *)addr)->part = 537 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 538 return 0; 539 540 case DIOCWDINFO: 541 case DIOCSDINFO: 542 { 543 struct disklabel *lp; 544 545 lp = (struct disklabel *)addr; 546 547 if ((flag & FWRITE) == 0) 548 return EBADF; 549 550 if ((error = ed_lock(ed)) != 0) 551 return error; 552 ed->sc_flags |= WDF_LABELLING; 553 554 error = setdisklabel(ed->sc_dk.dk_label, 555 lp, /*wd->sc_dk.dk_openmask : */0, 556 ed->sc_dk.dk_cpulabel); 557 if (error == 0) { 558 #if 0 559 if (wd->drvp->state > RECAL) 560 wd->drvp->drive_flags |= DRIVE_RESET; 561 #endif 562 if (xfer == DIOCWDINFO) 563 error = writedisklabel(EDLABELDEV(dev), 564 edmcastrategy, ed->sc_dk.dk_label, 565 ed->sc_dk.dk_cpulabel); 566 } 567 568 ed->sc_flags &= ~WDF_LABELLING; 569 ed_unlock(ed); 570 return (error); 571 } 572 573 case DIOCKLABEL: 574 if (*(int *)addr) 575 ed->sc_flags |= WDF_KLABEL; 576 else 577 ed->sc_flags &= ~WDF_KLABEL; 578 return 0; 579 580 case DIOCWLABEL: 581 if ((flag & FWRITE) == 0) 582 return EBADF; 583 if (*(int *)addr) 584 ed->sc_flags |= WDF_WLABEL; 585 else 586 ed->sc_flags &= ~WDF_WLABEL; 587 return 0; 588 589 case DIOCGDEFLABEL: 590 edgetdefaultlabel(ed, (struct disklabel *)addr); 591 return 0; 592 593 #if 0 594 case DIOCWFORMAT: 595 if ((flag & FWRITE) == 0) 596 return EBADF; 597 { 598 register struct format_op *fop; 599 struct iovec aiov; 600 struct uio auio; 601 602 fop = (struct format_op *)addr; 603 aiov.iov_base = fop->df_buf; 604 aiov.iov_len = fop->df_count; 605 auio.uio_iov = &aiov; 606 auio.uio_iovcnt = 1; 607 auio.uio_resid = fop->df_count; 608 auio.uio_segflg = 0; 609 auio.uio_offset = 610 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 611 auio.uio_procp = p; 612 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 613 &auio); 614 fop->df_count -= auio.uio_resid; 615 fop->df_reg[0] = wdc->sc_status; 616 fop->df_reg[1] = wdc->sc_error; 617 return error; 618 } 619 #endif 620 621 default: 622 return ENOTTY; 623 } 624 625 #ifdef DIAGNOSTIC 626 panic("edioctl: impossible"); 627 #endif 628 } 629 630 int 631 edmcasize(dev) 632 dev_t dev; 633 { 634 struct ed_softc *wd; 635 int part, omask; 636 int size; 637 638 ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 639 640 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 641 if (wd == NULL) 642 return (-1); 643 644 part = DISKPART(dev); 645 omask = wd->sc_dk.dk_openmask & (1 << part); 646 647 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 648 return (-1); 649 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 650 size = -1; 651 else 652 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 653 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 654 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 655 return (-1); 656 return (size); 657 } 658 659 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 660 static int eddoingadump = 0; 661 static int eddumprecalibrated = 0; 662 static int eddumpmulti = 1; 663 664 /* 665 * Dump core after a system crash. 666 */ 667 int 668 edmcadump(dev, blkno, va, size) 669 dev_t dev; 670 daddr_t blkno; 671 caddr_t va; 672 size_t size; 673 { 674 struct ed_softc *ed; /* disk unit to do the I/O */ 675 struct disklabel *lp; /* disk's disklabel */ 676 int part; 677 int nblks; /* total number of sectors left to write */ 678 int error; 679 680 /* Check if recursive dump; if so, punt. */ 681 if (eddoingadump) 682 return EFAULT; 683 eddoingadump = 1; 684 685 ed = device_lookup(&ed_cd, DISKUNIT(dev)); 686 if (ed == NULL) 687 return (ENXIO); 688 689 part = DISKPART(dev); 690 691 /* Make sure it was initialized. */ 692 if ((ed->sc_flags & EDF_INIT) == 0) 693 return ENXIO; 694 695 /* Convert to disk sectors. Request must be a multiple of size. */ 696 lp = ed->sc_dk.dk_label; 697 if ((size % lp->d_secsize) != 0) 698 return EFAULT; 699 nblks = size / lp->d_secsize; 700 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 701 702 /* Check transfer bounds against partition size. */ 703 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 704 return EINVAL; 705 706 /* Offset block number to start of partition. */ 707 blkno += lp->d_partitions[part].p_offset; 708 709 /* Recalibrate, if first dump transfer. */ 710 if (eddumprecalibrated == 0) { 711 eddumprecalibrated = 1; 712 eddumpmulti = 8; 713 #if 0 714 wd->drvp->state = RESET; 715 #endif 716 } 717 718 while (nblks > 0) { 719 error = edc_bio(ed->edc_softc, ed, va, blkno, 720 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 721 if (error) 722 return (error); 723 724 /* update block count */ 725 nblks -= min(nblks, eddumpmulti); 726 blkno += min(nblks, eddumpmulti); 727 va += min(nblks, eddumpmulti) * lp->d_secsize; 728 } 729 730 eddoingadump = 0; 731 return (0); 732 } 733 734 static int 735 ed_get_params(ed, drv_flags) 736 struct ed_softc *ed; 737 int *drv_flags; 738 { 739 u_int16_t cmd_args[2]; 740 741 /* 742 * Get Device Configuration (09). 743 */ 744 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 745 cmd_args[1] = 0; 746 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 747 cmd_args, 2, 1)) 748 return (1); 749 750 ed->spares = ed->sense_data[1] >> 8; 751 if (drv_flags) 752 *drv_flags = ed->sense_data[1] & 0x1f; 753 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 754 /* Instead of using: 755 ed->cyl = ed->sense_data[4]; 756 ed->heads = ed->sense_data[5] & 0xff; 757 ed->sectors = ed->sense_data[5] >> 8; 758 * we fabricate the numbers from RBA count, so that 759 * number of sectors is 32 and heads 64. This seems 760 * to be necessary for integrated ESDI controller. 761 */ 762 ed->sectors = 32; 763 ed->heads = 64; 764 ed->cyl = ed->rba / (ed->heads * ed->sectors); 765 ed->sc_capacity = ed->rba; 766 767 return (0); 768 } 769