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