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