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