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