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