1 /* $NetBSD: ed_mca.c,v 1.10 2001/11/23 22:53:10 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.10 2001/11/23 22:53:10 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 int s; 205 206 WDCDEBUG_PRINT(("edmcastrategy (%s)\n", ed->sc_dev.dv_xname), 207 DEBUG_XFERS); 208 209 /* Valid request? */ 210 if (bp->b_blkno < 0 || 211 (bp->b_bcount % lp->d_secsize) != 0 || 212 (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { 213 bp->b_error = EINVAL; 214 goto bad; 215 } 216 217 /* If device invalidated (e.g. media change, door open), error. */ 218 if ((ed->sc_flags & WDF_LOADED) == 0) { 219 bp->b_error = EIO; 220 goto bad; 221 } 222 223 /* If it's a null transfer, return immediately. */ 224 if (bp->b_bcount == 0) 225 goto done; 226 227 /* 228 * Do bounds checking, adjust transfer. if error, process. 229 * If end of partition, just return. 230 */ 231 if (DISKPART(bp->b_dev) != RAW_PART && 232 bounds_check_with_label(bp, ed->sc_dk.dk_label, 233 (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) 234 goto done; 235 236 /* 237 * Now convert the block number to absolute and put it in 238 * terms of the device's logical block size. 239 */ 240 if (lp->d_secsize >= DEV_BSIZE) 241 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 242 else 243 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); 244 245 if (DISKPART(bp->b_dev) != RAW_PART) 246 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 247 248 bp->b_rawblkno = blkno; 249 250 /* Queue transfer on drive, activate drive and controller if idle. */ 251 s = splbio(); 252 simple_lock(&ed->sc_q_lock); 253 disksort_blkno(&ed->sc_q, bp); 254 simple_unlock(&ed->sc_q_lock); 255 256 /* Ring the worker thread */ 257 wakeup_one(ed->edc_softc); 258 259 splx(s); 260 return; 261 bad: 262 bp->b_flags |= B_ERROR; 263 done: 264 /* Toss transfer; we're done early. */ 265 bp->b_resid = bp->b_bcount; 266 biodone(bp); 267 } 268 269 int 270 edmcaread(dev, uio, flags) 271 dev_t dev; 272 struct uio *uio; 273 int flags; 274 { 275 WDCDEBUG_PRINT(("edread\n"), DEBUG_XFERS); 276 return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio)); 277 } 278 279 int 280 edmcawrite(dev, uio, flags) 281 dev_t dev; 282 struct uio *uio; 283 int flags; 284 { 285 WDCDEBUG_PRINT(("edwrite\n"), DEBUG_XFERS); 286 return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio)); 287 } 288 289 /* 290 * Wait interruptibly for an exclusive lock. 291 */ 292 static int 293 ed_lock(ed) 294 struct ed_softc *ed; 295 { 296 int error; 297 int s; 298 299 WDCDEBUG_PRINT(("ed_lock\n"), DEBUG_FUNCS); 300 301 s = splbio(); 302 error = lockmgr(&ed->sc_lock, LK_EXCLUSIVE, NULL); 303 splx(s); 304 305 return (error); 306 } 307 308 /* 309 * Unlock and wake up any waiters. 310 */ 311 static void 312 ed_unlock(ed) 313 struct ed_softc *ed; 314 { 315 WDCDEBUG_PRINT(("ed_unlock\n"), DEBUG_FUNCS); 316 317 (void) lockmgr(&ed->sc_lock, LK_RELEASE, NULL); 318 } 319 320 int 321 edmcaopen(dev, flag, fmt, p) 322 dev_t dev; 323 int flag, fmt; 324 struct proc *p; 325 { 326 struct ed_softc *wd; 327 int part, error; 328 329 WDCDEBUG_PRINT(("edopen\n"), DEBUG_FUNCS); 330 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 331 if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0) 332 return (ENXIO); 333 334 if ((error = ed_lock(wd)) != 0) 335 goto bad4; 336 337 if (wd->sc_dk.dk_openmask != 0) { 338 /* 339 * If any partition is open, but the disk has been invalidated, 340 * disallow further opens. 341 */ 342 if ((wd->sc_flags & WDF_LOADED) == 0) { 343 error = EIO; 344 goto bad3; 345 } 346 } else { 347 if ((wd->sc_flags & WDF_LOADED) == 0) { 348 int s; 349 350 wd->sc_flags |= WDF_LOADED; 351 352 /* Load the physical device parameters. */ 353 s = splbio(); 354 ed_get_params(wd, NULL); 355 splx(s); 356 357 /* Load the partition info if not already loaded. */ 358 edgetdisklabel(dev, wd); 359 } 360 } 361 362 part = DISKPART(dev); 363 364 /* Check that the partition exists. */ 365 if (part != RAW_PART && 366 (part >= wd->sc_dk.dk_label->d_npartitions || 367 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 368 error = ENXIO; 369 goto bad; 370 } 371 372 /* Insure only one open at a time. */ 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 ed_unlock(wd); 385 return 0; 386 387 bad: 388 if (wd->sc_dk.dk_openmask == 0) { 389 } 390 391 bad3: 392 ed_unlock(wd); 393 bad4: 394 return (error); 395 } 396 397 int 398 edmcaclose(dev, flag, fmt, p) 399 dev_t dev; 400 int flag, fmt; 401 struct proc *p; 402 { 403 struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev)); 404 int part = DISKPART(dev); 405 int error; 406 407 WDCDEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS); 408 if ((error = ed_lock(wd)) != 0) 409 return error; 410 411 switch (fmt) { 412 case S_IFCHR: 413 wd->sc_dk.dk_copenmask &= ~(1 << part); 414 break; 415 case S_IFBLK: 416 wd->sc_dk.dk_bopenmask &= ~(1 << part); 417 break; 418 } 419 wd->sc_dk.dk_openmask = 420 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 421 422 if (wd->sc_dk.dk_openmask == 0) { 423 #if 0 424 wd_flushcache(wd, AT_WAIT); 425 #endif 426 /* XXXX Must wait for I/O to complete! */ 427 428 if (! (wd->sc_flags & WDF_KLABEL)) 429 wd->sc_flags &= ~WDF_LOADED; 430 } 431 432 ed_unlock(wd); 433 434 return 0; 435 } 436 437 static void 438 edgetdefaultlabel(ed, lp) 439 struct ed_softc *ed; 440 struct disklabel *lp; 441 { 442 WDCDEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 443 memset(lp, 0, sizeof(struct disklabel)); 444 445 lp->d_secsize = DEV_BSIZE; 446 lp->d_ntracks = ed->heads; 447 lp->d_nsectors = ed->sectors; 448 lp->d_ncylinders = ed->cyl; 449 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 450 451 lp->d_type = DTYPE_ESDI; 452 453 strncpy(lp->d_typename, "ESDI", 16); 454 strncpy(lp->d_packname, "fictitious", 16); 455 lp->d_secperunit = ed->sc_capacity; 456 lp->d_rpm = 3600; 457 lp->d_interleave = 1; 458 lp->d_flags = 0; 459 460 lp->d_partitions[RAW_PART].p_offset = 0; 461 lp->d_partitions[RAW_PART].p_size = 462 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 463 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 464 lp->d_npartitions = RAW_PART + 1; 465 466 lp->d_magic = DISKMAGIC; 467 lp->d_magic2 = DISKMAGIC; 468 lp->d_checksum = dkcksum(lp); 469 } 470 471 /* 472 * Fabricate a default disk label, and try to read the correct one. 473 */ 474 static void 475 edgetdisklabel(dev, ed) 476 dev_t dev; 477 struct ed_softc *ed; 478 { 479 struct disklabel *lp = ed->sc_dk.dk_label; 480 char *errstring; 481 482 WDCDEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 483 484 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 485 486 edgetdefaultlabel(ed, lp); 487 488 errstring = readdisklabel( 489 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 490 if (errstring) { 491 /* 492 * This probably happened because the drive's default 493 * geometry doesn't match the DOS geometry. We 494 * assume the DOS geometry is now in the label and try 495 * again. XXX This is a kluge. 496 */ 497 #if 0 498 if (wd->drvp->state > RECAL) 499 wd->drvp->drive_flags |= DRIVE_RESET; 500 #endif 501 errstring = readdisklabel(EDLABELDEV(dev), 502 edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 503 } 504 if (errstring) { 505 printf("%s: %s\n", ed->sc_dev.dv_xname, errstring); 506 return; 507 } 508 } 509 510 int 511 edmcaioctl(dev, xfer, addr, flag, p) 512 dev_t dev; 513 u_long xfer; 514 caddr_t addr; 515 int flag; 516 struct proc *p; 517 { 518 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev)); 519 int error; 520 521 WDCDEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 522 523 if ((ed->sc_flags & WDF_LOADED) == 0) 524 return EIO; 525 526 switch (xfer) { 527 case DIOCGDINFO: 528 *(struct disklabel *)addr = *(ed->sc_dk.dk_label); 529 return 0; 530 531 case DIOCGPART: 532 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label; 533 ((struct partinfo *)addr)->part = 534 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 535 return 0; 536 537 case DIOCWDINFO: 538 case DIOCSDINFO: 539 { 540 struct disklabel *lp; 541 542 lp = (struct disklabel *)addr; 543 544 if ((flag & FWRITE) == 0) 545 return EBADF; 546 547 if ((error = ed_lock(ed)) != 0) 548 return error; 549 ed->sc_flags |= WDF_LABELLING; 550 551 error = setdisklabel(ed->sc_dk.dk_label, 552 lp, /*wd->sc_dk.dk_openmask : */0, 553 ed->sc_dk.dk_cpulabel); 554 if (error == 0) { 555 #if 0 556 if (wd->drvp->state > RECAL) 557 wd->drvp->drive_flags |= DRIVE_RESET; 558 #endif 559 if (xfer == DIOCWDINFO) 560 error = writedisklabel(EDLABELDEV(dev), 561 edmcastrategy, ed->sc_dk.dk_label, 562 ed->sc_dk.dk_cpulabel); 563 } 564 565 ed->sc_flags &= ~WDF_LABELLING; 566 ed_unlock(ed); 567 return (error); 568 } 569 570 case DIOCKLABEL: 571 if (*(int *)addr) 572 ed->sc_flags |= WDF_KLABEL; 573 else 574 ed->sc_flags &= ~WDF_KLABEL; 575 return 0; 576 577 case DIOCWLABEL: 578 if ((flag & FWRITE) == 0) 579 return EBADF; 580 if (*(int *)addr) 581 ed->sc_flags |= WDF_WLABEL; 582 else 583 ed->sc_flags &= ~WDF_WLABEL; 584 return 0; 585 586 case DIOCGDEFLABEL: 587 edgetdefaultlabel(ed, (struct disklabel *)addr); 588 return 0; 589 590 #if 0 591 case DIOCWFORMAT: 592 if ((flag & FWRITE) == 0) 593 return EBADF; 594 { 595 register struct format_op *fop; 596 struct iovec aiov; 597 struct uio auio; 598 599 fop = (struct format_op *)addr; 600 aiov.iov_base = fop->df_buf; 601 aiov.iov_len = fop->df_count; 602 auio.uio_iov = &aiov; 603 auio.uio_iovcnt = 1; 604 auio.uio_resid = fop->df_count; 605 auio.uio_segflg = 0; 606 auio.uio_offset = 607 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 608 auio.uio_procp = p; 609 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 610 &auio); 611 fop->df_count -= auio.uio_resid; 612 fop->df_reg[0] = wdc->sc_status; 613 fop->df_reg[1] = wdc->sc_error; 614 return error; 615 } 616 #endif 617 618 default: 619 return ENOTTY; 620 } 621 622 #ifdef DIAGNOSTIC 623 panic("edioctl: impossible"); 624 #endif 625 } 626 627 int 628 edmcasize(dev) 629 dev_t dev; 630 { 631 struct ed_softc *wd; 632 int part, omask; 633 int size; 634 635 WDCDEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 636 637 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 638 if (wd == NULL) 639 return (-1); 640 641 part = DISKPART(dev); 642 omask = wd->sc_dk.dk_openmask & (1 << part); 643 644 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 645 return (-1); 646 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 647 size = -1; 648 else 649 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 650 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 651 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 652 return (-1); 653 return (size); 654 } 655 656 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 657 static int eddoingadump = 0; 658 static int eddumprecalibrated = 0; 659 static int eddumpmulti = 1; 660 661 /* 662 * Dump core after a system crash. 663 */ 664 int 665 edmcadump(dev, blkno, va, size) 666 dev_t dev; 667 daddr_t blkno; 668 caddr_t va; 669 size_t size; 670 { 671 struct ed_softc *ed; /* disk unit to do the I/O */ 672 struct disklabel *lp; /* disk's disklabel */ 673 int part; 674 int nblks; /* total number of sectors left to write */ 675 int error; 676 677 /* Check if recursive dump; if so, punt. */ 678 if (eddoingadump) 679 return EFAULT; 680 eddoingadump = 1; 681 682 ed = device_lookup(&ed_cd, DISKUNIT(dev)); 683 if (ed == NULL) 684 return (ENXIO); 685 686 part = DISKPART(dev); 687 688 /* Make sure it was initialized. */ 689 if ((ed->sc_flags & EDF_INIT) == 0) 690 return ENXIO; 691 692 /* Convert to disk sectors. Request must be a multiple of size. */ 693 lp = ed->sc_dk.dk_label; 694 if ((size % lp->d_secsize) != 0) 695 return EFAULT; 696 nblks = size / lp->d_secsize; 697 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 698 699 /* Check transfer bounds against partition size. */ 700 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 701 return EINVAL; 702 703 /* Offset block number to start of partition. */ 704 blkno += lp->d_partitions[part].p_offset; 705 706 /* Recalibrate, if first dump transfer. */ 707 if (eddumprecalibrated == 0) { 708 eddumprecalibrated = 1; 709 eddumpmulti = 8; 710 #if 0 711 wd->drvp->state = RESET; 712 #endif 713 } 714 715 while (nblks > 0) { 716 error = edc_bio(ed->edc_softc, ed, va, blkno, 717 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 718 if (error) 719 return (error); 720 721 /* update block count */ 722 nblks -= min(nblks, eddumpmulti); 723 blkno += min(nblks, eddumpmulti); 724 va += min(nblks, eddumpmulti) * lp->d_secsize; 725 } 726 727 eddoingadump = 0; 728 return (0); 729 } 730 731 static int 732 ed_get_params(ed, drv_flags) 733 struct ed_softc *ed; 734 int *drv_flags; 735 { 736 u_int16_t cmd_args[2]; 737 738 /* 739 * Get Device Configuration (09). 740 */ 741 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 742 cmd_args[1] = 0; 743 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 744 cmd_args, 2, 1)) 745 return (1); 746 747 ed->spares = ed->sense_data[1] >> 8; 748 if (drv_flags) 749 *drv_flags = ed->sense_data[1] & 0x1f; 750 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 751 /* Instead of using: 752 ed->cyl = ed->sense_data[4]; 753 ed->heads = ed->sense_data[5] & 0xff; 754 ed->sectors = ed->sense_data[5] >> 8; 755 * we fabricate the numbers from RBA count, so that 756 * number of sectors is 32 and heads 64. This seems 757 * to be necessary for integrated ESDI controller. 758 */ 759 ed->sectors = 32; 760 ed->heads = 64; 761 ed->cyl = ed->rba / (ed->heads * ed->sectors); 762 ed->sc_capacity = ed->rba; 763 764 return (0); 765 } 766