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