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