1 /* $NetBSD: ed_mca.c,v 1.42 2008/06/08 12:43:52 tsutsui 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.42 2008/06/08 12:43:52 tsutsui 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; 204 struct disklabel *lp; 205 daddr_t blkno; 206 207 ed = device_lookup_private(&ed_cd, DISKUNIT(bp->b_dev)); 208 lp = ed->sc_dk.dk_label; 209 210 ATADEBUG_PRINT(("edmcastrategy (%s)\n", device_xname(&ed->sc_dev)), 211 DEBUG_XFERS); 212 213 /* Valid request? */ 214 if (bp->b_blkno < 0 || 215 (bp->b_bcount % lp->d_secsize) != 0 || 216 (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { 217 bp->b_error = EINVAL; 218 goto done; 219 } 220 221 /* If device invalidated (e.g. media change, door open), error. */ 222 if ((ed->sc_flags & WDF_LOADED) == 0) { 223 bp->b_error = EIO; 224 goto done; 225 } 226 227 /* If it's a null transfer, return immediately. */ 228 if (bp->b_bcount == 0) 229 goto done; 230 231 /* 232 * Do bounds checking, adjust transfer. if error, process. 233 * If end of partition, just return. 234 */ 235 if (DISKPART(bp->b_dev) != RAW_PART && 236 bounds_check_with_label(&ed->sc_dk, bp, 237 (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) 238 goto done; 239 240 /* 241 * Now convert the block number to absolute and put it in 242 * terms of the device's logical block size. 243 */ 244 if (lp->d_secsize >= DEV_BSIZE) 245 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 246 else 247 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); 248 249 if (DISKPART(bp->b_dev) != RAW_PART) 250 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 251 252 bp->b_rawblkno = blkno; 253 254 /* Queue transfer on drive, activate drive and controller if idle. */ 255 simple_lock(&ed->sc_q_lock); 256 BUFQ_PUT(ed->sc_q, bp); 257 simple_unlock(&ed->sc_q_lock); 258 259 /* Ring the worker thread */ 260 wakeup_one(ed->edc_softc); 261 262 return; 263 done: 264 /* Toss transfer; we're done early. */ 265 bp->b_resid = bp->b_bcount; 266 biodone(bp); 267 } 268 269 int 270 edmcaread(dev_t dev, struct uio *uio, int flags) 271 { 272 ATADEBUG_PRINT(("edread\n"), DEBUG_XFERS); 273 return (physio(edmcastrategy, NULL, dev, B_READ, minphys, uio)); 274 } 275 276 int 277 edmcawrite(dev_t dev, struct uio *uio, int flags) 278 { 279 ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS); 280 return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio)); 281 } 282 283 int 284 edmcaopen(dev_t dev, int flag, int fmt, struct lwp *l) 285 { 286 struct ed_softc *wd; 287 int part, error; 288 289 ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS); 290 wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 291 if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0) 292 return (ENXIO); 293 294 part = DISKPART(dev); 295 296 mutex_enter(&wd->sc_dk.dk_openlock); 297 298 /* 299 * If there are wedges, and this is not RAW_PART, then we 300 * need to fail. 301 */ 302 if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { 303 error = EBUSY; 304 goto bad1; 305 } 306 307 if (wd->sc_dk.dk_openmask != 0) { 308 /* 309 * If any partition is open, but the disk has been invalidated, 310 * disallow further opens. 311 */ 312 if ((wd->sc_flags & WDF_LOADED) == 0) { 313 error = EIO; 314 goto bad1; 315 } 316 } else { 317 if ((wd->sc_flags & WDF_LOADED) == 0) { 318 int s; 319 320 wd->sc_flags |= WDF_LOADED; 321 322 /* Load the physical device parameters. */ 323 s = splbio(); 324 ed_get_params(wd, NULL); 325 splx(s); 326 327 /* Load the partition info if not already loaded. */ 328 edgetdisklabel(dev, wd); 329 } 330 } 331 332 /* Check that the partition exists. */ 333 if (part != RAW_PART && 334 (part >= wd->sc_dk.dk_label->d_npartitions || 335 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 336 error = ENXIO; 337 goto bad1; 338 } 339 340 /* Insure only one open at a time. */ 341 switch (fmt) { 342 case S_IFCHR: 343 wd->sc_dk.dk_copenmask |= (1 << part); 344 break; 345 case S_IFBLK: 346 wd->sc_dk.dk_bopenmask |= (1 << part); 347 break; 348 } 349 wd->sc_dk.dk_openmask = 350 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 351 352 error = 0; 353 bad1: 354 mutex_exit(&wd->sc_dk.dk_openlock); 355 return (error); 356 } 357 358 int 359 edmcaclose(dev_t dev, int flag, int fmt, struct lwp *l) 360 { 361 struct ed_softc *wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 362 int part = DISKPART(dev); 363 364 ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS); 365 366 mutex_enter(&wd->sc_dk.dk_openlock); 367 368 switch (fmt) { 369 case S_IFCHR: 370 wd->sc_dk.dk_copenmask &= ~(1 << part); 371 break; 372 case S_IFBLK: 373 wd->sc_dk.dk_bopenmask &= ~(1 << part); 374 break; 375 } 376 wd->sc_dk.dk_openmask = 377 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 378 379 if (wd->sc_dk.dk_openmask == 0) { 380 #if 0 381 wd_flushcache(wd, AT_WAIT); 382 #endif 383 /* XXXX Must wait for I/O to complete! */ 384 385 if (! (wd->sc_flags & WDF_KLABEL)) 386 wd->sc_flags &= ~WDF_LOADED; 387 } 388 389 mutex_exit(&wd->sc_dk.dk_openlock); 390 391 return 0; 392 } 393 394 static void 395 edgetdefaultlabel(ed, lp) 396 struct ed_softc *ed; 397 struct disklabel *lp; 398 { 399 ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 400 memset(lp, 0, sizeof(struct disklabel)); 401 402 lp->d_secsize = DEV_BSIZE; 403 lp->d_ntracks = ed->heads; 404 lp->d_nsectors = ed->sectors; 405 lp->d_ncylinders = ed->cyl; 406 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 407 408 lp->d_type = DTYPE_ESDI; 409 410 strncpy(lp->d_typename, "ESDI", 16); 411 strncpy(lp->d_packname, "fictitious", 16); 412 lp->d_secperunit = ed->sc_capacity; 413 lp->d_rpm = 3600; 414 lp->d_interleave = 1; 415 lp->d_flags = 0; 416 417 lp->d_partitions[RAW_PART].p_offset = 0; 418 lp->d_partitions[RAW_PART].p_size = 419 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 420 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 421 lp->d_npartitions = RAW_PART + 1; 422 423 lp->d_magic = DISKMAGIC; 424 lp->d_magic2 = DISKMAGIC; 425 lp->d_checksum = dkcksum(lp); 426 } 427 428 /* 429 * Fabricate a default disk label, and try to read the correct one. 430 */ 431 static void 432 edgetdisklabel(dev, ed) 433 dev_t dev; 434 struct ed_softc *ed; 435 { 436 struct disklabel *lp = ed->sc_dk.dk_label; 437 const char *errstring; 438 439 ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 440 441 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 442 443 edgetdefaultlabel(ed, lp); 444 445 errstring = readdisklabel( 446 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 447 if (errstring) { 448 /* 449 * This probably happened because the drive's default 450 * geometry doesn't match the DOS geometry. We 451 * assume the DOS geometry is now in the label and try 452 * again. XXX This is a kluge. 453 */ 454 #if 0 455 if (wd->drvp->state > RECAL) 456 wd->drvp->drive_flags |= DRIVE_RESET; 457 #endif 458 errstring = readdisklabel(EDLABELDEV(dev), 459 edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 460 } 461 if (errstring) { 462 printf("%s: %s\n", device_xname(&ed->sc_dev), errstring); 463 return; 464 } 465 } 466 467 int 468 edmcaioctl(dev, xfer, addr, flag, l) 469 dev_t dev; 470 u_long xfer; 471 void *addr; 472 int flag; 473 struct lwp *l; 474 { 475 struct ed_softc *ed = device_lookup_private(&ed_cd, DISKUNIT(dev)); 476 int error; 477 478 ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 479 480 if ((ed->sc_flags & WDF_LOADED) == 0) 481 return EIO; 482 483 switch (xfer) { 484 case DIOCGDINFO: 485 *(struct disklabel *)addr = *(ed->sc_dk.dk_label); 486 return 0; 487 488 case DIOCGPART: 489 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label; 490 ((struct partinfo *)addr)->part = 491 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 492 return 0; 493 494 case DIOCWDINFO: 495 case DIOCSDINFO: 496 { 497 struct disklabel *lp; 498 499 lp = (struct disklabel *)addr; 500 501 if ((flag & FWRITE) == 0) 502 return EBADF; 503 504 mutex_enter(&ed->sc_dk.dk_openlock); 505 ed->sc_flags |= WDF_LABELLING; 506 507 error = setdisklabel(ed->sc_dk.dk_label, 508 lp, /*wd->sc_dk.dk_openmask : */0, 509 ed->sc_dk.dk_cpulabel); 510 if (error == 0) { 511 #if 0 512 if (wd->drvp->state > RECAL) 513 wd->drvp->drive_flags |= DRIVE_RESET; 514 #endif 515 if (xfer == DIOCWDINFO) 516 error = writedisklabel(EDLABELDEV(dev), 517 edmcastrategy, ed->sc_dk.dk_label, 518 ed->sc_dk.dk_cpulabel); 519 } 520 521 ed->sc_flags &= ~WDF_LABELLING; 522 mutex_exit(&ed->sc_dk.dk_openlock); 523 return (error); 524 } 525 526 case DIOCKLABEL: 527 if (*(int *)addr) 528 ed->sc_flags |= WDF_KLABEL; 529 else 530 ed->sc_flags &= ~WDF_KLABEL; 531 return 0; 532 533 case DIOCWLABEL: 534 if ((flag & FWRITE) == 0) 535 return EBADF; 536 if (*(int *)addr) 537 ed->sc_flags |= WDF_WLABEL; 538 else 539 ed->sc_flags &= ~WDF_WLABEL; 540 return 0; 541 542 case DIOCGDEFLABEL: 543 edgetdefaultlabel(ed, (struct disklabel *)addr); 544 return 0; 545 546 #if 0 547 case DIOCWFORMAT: 548 if ((flag & FWRITE) == 0) 549 return EBADF; 550 { 551 register struct format_op *fop; 552 struct iovec aiov; 553 struct uio auio; 554 555 fop = (struct format_op *)addr; 556 aiov.iov_base = fop->df_buf; 557 aiov.iov_len = fop->df_count; 558 auio.uio_iov = &aiov; 559 auio.uio_iovcnt = 1; 560 auio.uio_resid = fop->df_count; 561 auio.uio_segflg = 0; 562 auio.uio_offset = 563 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 564 auio.uio_lwp = l; 565 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 566 &auio); 567 fop->df_count -= auio.uio_resid; 568 fop->df_reg[0] = wdc->sc_status; 569 fop->df_reg[1] = wdc->sc_error; 570 return error; 571 } 572 #endif 573 574 case DIOCAWEDGE: 575 { 576 struct dkwedge_info *dkw = (void *) addr; 577 578 if ((flag & FWRITE) == 0) 579 return (EBADF); 580 581 /* If the ioctl happens here, the parent is us. */ 582 strlcpy(dkw->dkw_parent, device_xname(&ed->sc_dev), 583 sizeof(dkw->dkw_parent)); 584 return (dkwedge_add(dkw)); 585 } 586 587 case DIOCDWEDGE: 588 { 589 struct dkwedge_info *dkw = (void *) addr; 590 591 if ((flag & FWRITE) == 0) 592 return (EBADF); 593 594 /* If the ioctl happens here, the parent is us. */ 595 strlcpy(dkw->dkw_parent, device_xname(&ed->sc_dev), 596 sizeof(dkw->dkw_parent)); 597 return (dkwedge_del(dkw)); 598 } 599 600 case DIOCLWEDGES: 601 { 602 struct dkwedge_list *dkwl = (void *) addr; 603 604 return (dkwedge_list(&ed->sc_dk, dkwl, l)); 605 } 606 607 default: 608 return ENOTTY; 609 } 610 611 #ifdef DIAGNOSTIC 612 panic("edioctl: impossible"); 613 #endif 614 } 615 616 int 617 edmcasize(dev) 618 dev_t dev; 619 { 620 struct ed_softc *wd; 621 int part, omask; 622 int size; 623 624 ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 625 626 wd = device_lookup_private(&ed_cd, DISKUNIT(dev)); 627 if (wd == NULL) 628 return (-1); 629 630 part = DISKPART(dev); 631 omask = wd->sc_dk.dk_openmask & (1 << part); 632 633 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 634 return (-1); 635 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 636 size = -1; 637 else 638 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 639 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 640 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 641 return (-1); 642 return (size); 643 } 644 645 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 646 static int eddoingadump = 0; 647 static int eddumprecalibrated = 0; 648 static int eddumpmulti = 1; 649 650 /* 651 * Dump core after a system crash. 652 */ 653 int 654 edmcadump(dev, blkno, va, size) 655 dev_t dev; 656 daddr_t blkno; 657 void *va; 658 size_t size; 659 { 660 struct ed_softc *ed; /* disk unit to do the I/O */ 661 struct disklabel *lp; /* disk's disklabel */ 662 int part; 663 int nblks; /* total number of sectors left to write */ 664 int error; 665 666 /* Check if recursive dump; if so, punt. */ 667 if (eddoingadump) 668 return EFAULT; 669 eddoingadump = 1; 670 671 ed = device_lookup_private(&ed_cd, DISKUNIT(dev)); 672 if (ed == NULL) 673 return (ENXIO); 674 675 part = DISKPART(dev); 676 677 /* Make sure it was initialized. */ 678 if ((ed->sc_flags & EDF_INIT) == 0) 679 return ENXIO; 680 681 /* Convert to disk sectors. Request must be a multiple of size. */ 682 lp = ed->sc_dk.dk_label; 683 if ((size % lp->d_secsize) != 0) 684 return EFAULT; 685 nblks = size / lp->d_secsize; 686 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 687 688 /* Check transfer bounds against partition size. */ 689 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 690 return EINVAL; 691 692 /* Offset block number to start of partition. */ 693 blkno += lp->d_partitions[part].p_offset; 694 695 /* Recalibrate, if first dump transfer. */ 696 if (eddumprecalibrated == 0) { 697 eddumprecalibrated = 1; 698 eddumpmulti = 8; 699 #if 0 700 wd->drvp->state = RESET; 701 #endif 702 } 703 704 while (nblks > 0) { 705 error = edc_bio(ed->edc_softc, ed, va, blkno, 706 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 707 if (error) 708 return (error); 709 710 /* update block count */ 711 nblks -= min(nblks, eddumpmulti); 712 blkno += min(nblks, eddumpmulti); 713 va = (char *)va + min(nblks, eddumpmulti) * lp->d_secsize; 714 } 715 716 eddoingadump = 0; 717 return (0); 718 } 719 720 static int 721 ed_get_params(ed, drv_flags) 722 struct ed_softc *ed; 723 int *drv_flags; 724 { 725 u_int16_t cmd_args[2]; 726 727 /* 728 * Get Device Configuration (09). 729 */ 730 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 731 cmd_args[1] = 0; 732 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 733 cmd_args, 2, 1)) 734 return (1); 735 736 ed->spares = ed->sense_data[1] >> 8; 737 if (drv_flags) 738 *drv_flags = ed->sense_data[1] & 0x1f; 739 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 740 /* Instead of using: 741 ed->cyl = ed->sense_data[4]; 742 ed->heads = ed->sense_data[5] & 0xff; 743 ed->sectors = ed->sense_data[5] >> 8; 744 * we fabricate the numbers from RBA count, so that 745 * number of sectors is 32 and heads 64. This seems 746 * to be necessary for integrated ESDI controller. 747 */ 748 ed->sectors = 32; 749 ed->heads = 64; 750 ed->cyl = ed->rba / (ed->heads * ed->sectors); 751 ed->sc_capacity = ed->rba; 752 753 return (0); 754 } 755