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