1 /* $NetBSD: ed_mca.c,v 1.41 2008/05/04 13:11:14 martin 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.41 2008/05/04 13:11:14 martin 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 (struct device *, struct cfdata *, void *); 82 static void ed_mca_attach (struct device *, struct device *, 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(struct device *parent, struct cfdata *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(parent, self, aux) 139 struct device *parent, *self; 140 void *aux; 141 { 142 struct ed_softc *ed = device_private(self); 143 struct edc_mca_softc *sc = device_private(parent); 144 struct ed_attach_args *eda = (struct ed_attach_args *) aux; 145 char pbuf[8]; 146 int drv_flags; 147 148 ed->edc_softc = sc; 149 ed->sc_devno = eda->edc_drive; 150 edc_add_disk(sc, ed); 151 152 bufq_alloc(&ed->sc_q, "disksort", BUFQ_SORT_RAWBLOCK); 153 simple_lock_init(&ed->sc_q_lock); 154 155 if (ed_get_params(ed, &drv_flags)) { 156 printf(": IDENTIFY failed, no disk found\n"); 157 return; 158 } 159 160 format_bytes(pbuf, sizeof(pbuf), 161 (u_int64_t) ed->sc_capacity * DEV_BSIZE); 162 printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n", 163 pbuf, 164 ed->cyl, ed->heads, ed->sectors, 165 ed->sc_capacity); 166 167 printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n", 168 device_xname(&ed->sc_dev), ed->spares, 169 (drv_flags & (1 << 0)) ? "NoRetries" : "Retries", 170 (drv_flags & (1 << 1)) ? "Removable" : "Fixed", 171 (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew", 172 (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects", 173 (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK" 174 ); 175 176 /* 177 * Initialize and attach the disk structure. 178 */ 179 disk_init(&ed->sc_dk, device_xname(&ed->sc_dev), &eddkdriver); 180 disk_attach(&ed->sc_dk); 181 #if NRND > 0 182 rnd_attach_source(&ed->rnd_source, device_xname(&ed->sc_dev), 183 RND_TYPE_DISK, 0); 184 #endif 185 186 ed->sc_flags |= EDF_INIT; 187 188 /* 189 * XXX We should try to discovery wedges here, but 190 * XXX that would mean being able to do I/O. Should 191 * XXX use config_defer() here. 192 */ 193 } 194 195 /* 196 * Read/write routine for a buffer. Validates the arguments and schedules the 197 * transfer. Does not wait for the transfer to complete. 198 */ 199 void 200 edmcastrategy(bp) 201 struct buf *bp; 202 { 203 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(bp->b_dev)); 204 struct disklabel *lp = ed->sc_dk.dk_label; 205 daddr_t blkno; 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(&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(&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(ed, lp) 393 struct ed_softc *ed; 394 struct disklabel *lp; 395 { 396 ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 397 memset(lp, 0, sizeof(struct disklabel)); 398 399 lp->d_secsize = DEV_BSIZE; 400 lp->d_ntracks = ed->heads; 401 lp->d_nsectors = ed->sectors; 402 lp->d_ncylinders = ed->cyl; 403 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 404 405 lp->d_type = DTYPE_ESDI; 406 407 strncpy(lp->d_typename, "ESDI", 16); 408 strncpy(lp->d_packname, "fictitious", 16); 409 lp->d_secperunit = ed->sc_capacity; 410 lp->d_rpm = 3600; 411 lp->d_interleave = 1; 412 lp->d_flags = 0; 413 414 lp->d_partitions[RAW_PART].p_offset = 0; 415 lp->d_partitions[RAW_PART].p_size = 416 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 417 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 418 lp->d_npartitions = RAW_PART + 1; 419 420 lp->d_magic = DISKMAGIC; 421 lp->d_magic2 = DISKMAGIC; 422 lp->d_checksum = dkcksum(lp); 423 } 424 425 /* 426 * Fabricate a default disk label, and try to read the correct one. 427 */ 428 static void 429 edgetdisklabel(dev, ed) 430 dev_t dev; 431 struct ed_softc *ed; 432 { 433 struct disklabel *lp = ed->sc_dk.dk_label; 434 const char *errstring; 435 436 ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 437 438 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 439 440 edgetdefaultlabel(ed, lp); 441 442 errstring = readdisklabel( 443 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 444 if (errstring) { 445 /* 446 * This probably happened because the drive's default 447 * geometry doesn't match the DOS geometry. We 448 * assume the DOS geometry is now in the label and try 449 * again. XXX This is a kluge. 450 */ 451 #if 0 452 if (wd->drvp->state > RECAL) 453 wd->drvp->drive_flags |= DRIVE_RESET; 454 #endif 455 errstring = readdisklabel(EDLABELDEV(dev), 456 edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 457 } 458 if (errstring) { 459 printf("%s: %s\n", device_xname(&ed->sc_dev), errstring); 460 return; 461 } 462 } 463 464 int 465 edmcaioctl(dev, xfer, addr, flag, l) 466 dev_t dev; 467 u_long xfer; 468 void *addr; 469 int flag; 470 struct lwp *l; 471 { 472 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev)); 473 int error; 474 475 ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 476 477 if ((ed->sc_flags & WDF_LOADED) == 0) 478 return EIO; 479 480 switch (xfer) { 481 case DIOCGDINFO: 482 *(struct disklabel *)addr = *(ed->sc_dk.dk_label); 483 return 0; 484 485 case DIOCGPART: 486 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label; 487 ((struct partinfo *)addr)->part = 488 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 489 return 0; 490 491 case DIOCWDINFO: 492 case DIOCSDINFO: 493 { 494 struct disklabel *lp; 495 496 lp = (struct disklabel *)addr; 497 498 if ((flag & FWRITE) == 0) 499 return EBADF; 500 501 mutex_enter(&ed->sc_dk.dk_openlock); 502 ed->sc_flags |= WDF_LABELLING; 503 504 error = setdisklabel(ed->sc_dk.dk_label, 505 lp, /*wd->sc_dk.dk_openmask : */0, 506 ed->sc_dk.dk_cpulabel); 507 if (error == 0) { 508 #if 0 509 if (wd->drvp->state > RECAL) 510 wd->drvp->drive_flags |= DRIVE_RESET; 511 #endif 512 if (xfer == DIOCWDINFO) 513 error = writedisklabel(EDLABELDEV(dev), 514 edmcastrategy, ed->sc_dk.dk_label, 515 ed->sc_dk.dk_cpulabel); 516 } 517 518 ed->sc_flags &= ~WDF_LABELLING; 519 mutex_exit(&ed->sc_dk.dk_openlock); 520 return (error); 521 } 522 523 case DIOCKLABEL: 524 if (*(int *)addr) 525 ed->sc_flags |= WDF_KLABEL; 526 else 527 ed->sc_flags &= ~WDF_KLABEL; 528 return 0; 529 530 case DIOCWLABEL: 531 if ((flag & FWRITE) == 0) 532 return EBADF; 533 if (*(int *)addr) 534 ed->sc_flags |= WDF_WLABEL; 535 else 536 ed->sc_flags &= ~WDF_WLABEL; 537 return 0; 538 539 case DIOCGDEFLABEL: 540 edgetdefaultlabel(ed, (struct disklabel *)addr); 541 return 0; 542 543 #if 0 544 case DIOCWFORMAT: 545 if ((flag & FWRITE) == 0) 546 return EBADF; 547 { 548 register struct format_op *fop; 549 struct iovec aiov; 550 struct uio auio; 551 552 fop = (struct format_op *)addr; 553 aiov.iov_base = fop->df_buf; 554 aiov.iov_len = fop->df_count; 555 auio.uio_iov = &aiov; 556 auio.uio_iovcnt = 1; 557 auio.uio_resid = fop->df_count; 558 auio.uio_segflg = 0; 559 auio.uio_offset = 560 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 561 auio.uio_lwp = l; 562 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 563 &auio); 564 fop->df_count -= auio.uio_resid; 565 fop->df_reg[0] = wdc->sc_status; 566 fop->df_reg[1] = wdc->sc_error; 567 return error; 568 } 569 #endif 570 571 case DIOCAWEDGE: 572 { 573 struct dkwedge_info *dkw = (void *) addr; 574 575 if ((flag & FWRITE) == 0) 576 return (EBADF); 577 578 /* If the ioctl happens here, the parent is us. */ 579 strlcpy(dkw->dkw_parent, device_xname(&ed->sc_dev), 580 sizeof(dkw->dkw_parent)); 581 return (dkwedge_add(dkw)); 582 } 583 584 case DIOCDWEDGE: 585 { 586 struct dkwedge_info *dkw = (void *) addr; 587 588 if ((flag & FWRITE) == 0) 589 return (EBADF); 590 591 /* If the ioctl happens here, the parent is us. */ 592 strlcpy(dkw->dkw_parent, device_xname(&ed->sc_dev), 593 sizeof(dkw->dkw_parent)); 594 return (dkwedge_del(dkw)); 595 } 596 597 case DIOCLWEDGES: 598 { 599 struct dkwedge_list *dkwl = (void *) addr; 600 601 return (dkwedge_list(&ed->sc_dk, dkwl, l)); 602 } 603 604 default: 605 return ENOTTY; 606 } 607 608 #ifdef DIAGNOSTIC 609 panic("edioctl: impossible"); 610 #endif 611 } 612 613 int 614 edmcasize(dev) 615 dev_t dev; 616 { 617 struct ed_softc *wd; 618 int part, omask; 619 int size; 620 621 ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 622 623 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 624 if (wd == NULL) 625 return (-1); 626 627 part = DISKPART(dev); 628 omask = wd->sc_dk.dk_openmask & (1 << part); 629 630 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 631 return (-1); 632 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 633 size = -1; 634 else 635 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 636 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 637 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 638 return (-1); 639 return (size); 640 } 641 642 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 643 static int eddoingadump = 0; 644 static int eddumprecalibrated = 0; 645 static int eddumpmulti = 1; 646 647 /* 648 * Dump core after a system crash. 649 */ 650 int 651 edmcadump(dev, blkno, va, size) 652 dev_t dev; 653 daddr_t blkno; 654 void *va; 655 size_t size; 656 { 657 struct ed_softc *ed; /* disk unit to do the I/O */ 658 struct disklabel *lp; /* disk's disklabel */ 659 int part; 660 int nblks; /* total number of sectors left to write */ 661 int error; 662 663 /* Check if recursive dump; if so, punt. */ 664 if (eddoingadump) 665 return EFAULT; 666 eddoingadump = 1; 667 668 ed = device_lookup(&ed_cd, DISKUNIT(dev)); 669 if (ed == NULL) 670 return (ENXIO); 671 672 part = DISKPART(dev); 673 674 /* Make sure it was initialized. */ 675 if ((ed->sc_flags & EDF_INIT) == 0) 676 return ENXIO; 677 678 /* Convert to disk sectors. Request must be a multiple of size. */ 679 lp = ed->sc_dk.dk_label; 680 if ((size % lp->d_secsize) != 0) 681 return EFAULT; 682 nblks = size / lp->d_secsize; 683 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 684 685 /* Check transfer bounds against partition size. */ 686 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 687 return EINVAL; 688 689 /* Offset block number to start of partition. */ 690 blkno += lp->d_partitions[part].p_offset; 691 692 /* Recalibrate, if first dump transfer. */ 693 if (eddumprecalibrated == 0) { 694 eddumprecalibrated = 1; 695 eddumpmulti = 8; 696 #if 0 697 wd->drvp->state = RESET; 698 #endif 699 } 700 701 while (nblks > 0) { 702 error = edc_bio(ed->edc_softc, ed, va, blkno, 703 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 704 if (error) 705 return (error); 706 707 /* update block count */ 708 nblks -= min(nblks, eddumpmulti); 709 blkno += min(nblks, eddumpmulti); 710 va = (char *)va + min(nblks, eddumpmulti) * lp->d_secsize; 711 } 712 713 eddoingadump = 0; 714 return (0); 715 } 716 717 static int 718 ed_get_params(ed, drv_flags) 719 struct ed_softc *ed; 720 int *drv_flags; 721 { 722 u_int16_t cmd_args[2]; 723 724 /* 725 * Get Device Configuration (09). 726 */ 727 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 728 cmd_args[1] = 0; 729 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 730 cmd_args, 2, 1)) 731 return (1); 732 733 ed->spares = ed->sense_data[1] >> 8; 734 if (drv_flags) 735 *drv_flags = ed->sense_data[1] & 0x1f; 736 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 737 /* Instead of using: 738 ed->cyl = ed->sense_data[4]; 739 ed->heads = ed->sense_data[5] & 0xff; 740 ed->sectors = ed->sense_data[5] >> 8; 741 * we fabricate the numbers from RBA count, so that 742 * number of sectors is 32 and heads 64. This seems 743 * to be necessary for integrated ESDI controller. 744 */ 745 ed->sectors = 32; 746 ed->heads = 64; 747 ed->cyl = ed->rba / (ed->heads * ed->sectors); 748 ed->sc_capacity = ed->rba; 749 750 return (0); 751 } 752