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