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