1 /* $NetBSD: ed_mca.c,v 1.27 2004/10/28 07:07:40 yamt Exp $ */ 2 3 /* 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Jaromir Dolecek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* 37 * Disk drive goo for MCA ESDI controller driver. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: ed_mca.c,v 1.27 2004/10/28 07:07:40 yamt Exp $"); 42 43 #include "rnd.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/conf.h> 49 #include <sys/file.h> 50 #include <sys/stat.h> 51 #include <sys/ioctl.h> 52 #include <sys/buf.h> 53 #include <sys/bufq.h> 54 #include <sys/uio.h> 55 #include <sys/malloc.h> 56 #include <sys/device.h> 57 #include <sys/disklabel.h> 58 #include <sys/disk.h> 59 #include <sys/syslog.h> 60 #include <sys/proc.h> 61 #include <sys/vnode.h> 62 #if NRND > 0 63 #include <sys/rnd.h> 64 #endif 65 66 #include <machine/intr.h> 67 #include <machine/bus.h> 68 69 #include <dev/mca/mcavar.h> 70 71 #include <dev/mca/edcreg.h> 72 #include <dev/mca/edvar.h> 73 #include <dev/mca/edcvar.h> 74 75 /* #define ATADEBUG */ 76 77 #ifdef ATADEBUG 78 #define ATADEBUG_PRINT(args, level) printf args 79 #else 80 #define ATADEBUG_PRINT(args, level) 81 #endif 82 83 #define EDLABELDEV(dev) (MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART)) 84 85 static int ed_mca_probe __P((struct device *, struct cfdata *, void *)); 86 static void ed_mca_attach __P((struct device *, struct device *, void *)); 87 88 CFATTACH_DECL(ed_mca, sizeof(struct ed_softc), 89 ed_mca_probe, ed_mca_attach, NULL, NULL); 90 91 extern struct cfdriver ed_cd; 92 93 static int ed_get_params __P((struct ed_softc *, int *)); 94 static void edgetdisklabel __P((dev_t, struct ed_softc *)); 95 static void edgetdefaultlabel __P((struct ed_softc *, struct disklabel *)); 96 97 dev_type_open(edmcaopen); 98 dev_type_close(edmcaclose); 99 dev_type_read(edmcaread); 100 dev_type_write(edmcawrite); 101 dev_type_ioctl(edmcaioctl); 102 dev_type_strategy(edmcastrategy); 103 dev_type_dump(edmcadump); 104 dev_type_size(edmcasize); 105 106 const struct bdevsw ed_bdevsw = { 107 edmcaopen, edmcaclose, edmcastrategy, edmcaioctl, 108 edmcadump, edmcasize, D_DISK 109 }; 110 111 const struct cdevsw ed_cdevsw = { 112 edmcaopen, edmcaclose, edmcaread, edmcawrite, edmcaioctl, 113 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 114 }; 115 116 static struct dkdriver eddkdriver = { edmcastrategy, minphys }; 117 118 /* 119 * Just check if it's possible to identify the disk. 120 */ 121 static int 122 ed_mca_probe(parent, cf, aux) 123 struct device *parent; 124 struct cfdata *cf; 125 void *aux; 126 { 127 u_int16_t cmd_args[2]; 128 struct edc_mca_softc *sc = (void *) parent; 129 struct ed_attach_args *eda = (struct ed_attach_args *) aux; 130 int found = 1; 131 132 /* 133 * Get Device Configuration (09). 134 */ 135 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 136 cmd_args[1] = 0; 137 if (edc_run_cmd(sc, CMD_GET_DEV_CONF, eda->edc_drive, cmd_args, 2, 1)) 138 found = 0; 139 140 return (found); 141 } 142 143 static void 144 ed_mca_attach(parent, self, aux) 145 struct device *parent, *self; 146 void *aux; 147 { 148 struct ed_softc *ed = (void *) self; 149 struct edc_mca_softc *sc = (void *) parent; 150 struct ed_attach_args *eda = (struct ed_attach_args *) aux; 151 char pbuf[8]; 152 int drv_flags; 153 154 ed->edc_softc = sc; 155 ed->sc_devno = eda->edc_drive; 156 edc_add_disk(sc, ed); 157 158 bufq_alloc(&ed->sc_q, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK); 159 simple_lock_init(&ed->sc_q_lock); 160 161 if (ed_get_params(ed, &drv_flags)) { 162 printf(": IDENTIFY failed, no disk found\n"); 163 return; 164 } 165 166 format_bytes(pbuf, sizeof(pbuf), 167 (u_int64_t) ed->sc_capacity * DEV_BSIZE); 168 printf(": %s, %u cyl, %u head, %u sec, 512 bytes/sect x %u sectors\n", 169 pbuf, 170 ed->cyl, ed->heads, ed->sectors, 171 ed->sc_capacity); 172 173 printf("%s: %u spares/cyl, %s, %s, %s, %s, %s\n", 174 ed->sc_dev.dv_xname, ed->spares, 175 (drv_flags & (1 << 0)) ? "NoRetries" : "Retries", 176 (drv_flags & (1 << 1)) ? "Removable" : "Fixed", 177 (drv_flags & (1 << 2)) ? "SkewedFormat" : "NoSkew", 178 (drv_flags & (1 << 3)) ? "ZeroDefect" : "Defects", 179 (drv_flags & (1 << 4)) ? "InvalidSecondary" : "SecondaryOK" 180 ); 181 182 /* 183 * Initialize and attach the disk structure. 184 */ 185 ed->sc_dk.dk_driver = &eddkdriver; 186 ed->sc_dk.dk_name = ed->sc_dev.dv_xname; 187 disk_attach(&ed->sc_dk); 188 #if NRND > 0 189 rnd_attach_source(&ed->rnd_source, ed->sc_dev.dv_xname, 190 RND_TYPE_DISK, 0); 191 #endif 192 193 ed->sc_flags |= EDF_INIT; 194 195 /* 196 * XXX We should try to discovery wedges here, but 197 * XXX that would mean being able to do I/O. Should 198 * XXX use config_defer() here. 199 */ 200 } 201 202 /* 203 * Read/write routine for a buffer. Validates the arguments and schedules the 204 * transfer. Does not wait for the transfer to complete. 205 */ 206 void 207 edmcastrategy(bp) 208 struct buf *bp; 209 { 210 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(bp->b_dev)); 211 struct disklabel *lp = ed->sc_dk.dk_label; 212 daddr_t blkno; 213 214 ATADEBUG_PRINT(("edmcastrategy (%s)\n", ed->sc_dev.dv_xname), 215 DEBUG_XFERS); 216 217 /* Valid request? */ 218 if (bp->b_blkno < 0 || 219 (bp->b_bcount % lp->d_secsize) != 0 || 220 (bp->b_bcount / lp->d_secsize) >= (1 << NBBY)) { 221 bp->b_error = EINVAL; 222 goto bad; 223 } 224 225 /* If device invalidated (e.g. media change, door open), error. */ 226 if ((ed->sc_flags & WDF_LOADED) == 0) { 227 bp->b_error = EIO; 228 goto bad; 229 } 230 231 /* If it's a null transfer, return immediately. */ 232 if (bp->b_bcount == 0) 233 goto done; 234 235 /* 236 * Do bounds checking, adjust transfer. if error, process. 237 * If end of partition, just return. 238 */ 239 if (DISKPART(bp->b_dev) != RAW_PART && 240 bounds_check_with_label(&ed->sc_dk, bp, 241 (ed->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) 242 goto done; 243 244 /* 245 * Now convert the block number to absolute and put it in 246 * terms of the device's logical block size. 247 */ 248 if (lp->d_secsize >= DEV_BSIZE) 249 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE); 250 else 251 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize); 252 253 if (DISKPART(bp->b_dev) != RAW_PART) 254 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset; 255 256 bp->b_rawblkno = blkno; 257 258 /* Queue transfer on drive, activate drive and controller if idle. */ 259 simple_lock(&ed->sc_q_lock); 260 BUFQ_PUT(&ed->sc_q, bp); 261 simple_unlock(&ed->sc_q_lock); 262 263 /* Ring the worker thread */ 264 wakeup_one(ed->edc_softc); 265 266 return; 267 bad: 268 bp->b_flags |= B_ERROR; 269 done: 270 /* Toss transfer; we're done early. */ 271 bp->b_resid = bp->b_bcount; 272 biodone(bp); 273 } 274 275 int 276 edmcaread(dev, uio, flags) 277 dev_t dev; 278 struct uio *uio; 279 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, uio, flags) 287 dev_t dev; 288 struct uio *uio; 289 int flags; 290 { 291 ATADEBUG_PRINT(("edwrite\n"), DEBUG_XFERS); 292 return (physio(edmcastrategy, NULL, dev, B_WRITE, minphys, uio)); 293 } 294 295 int 296 edmcaopen(dev, flag, fmt, p) 297 dev_t dev; 298 int flag, fmt; 299 struct proc *p; 300 { 301 struct ed_softc *wd; 302 int part, error; 303 304 ATADEBUG_PRINT(("edopen\n"), DEBUG_FUNCS); 305 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 306 if (wd == NULL || (wd->sc_flags & EDF_INIT) == 0) 307 return (ENXIO); 308 309 part = DISKPART(dev); 310 311 if ((error = lockmgr(&wd->sc_dk.dk_openlock, LK_EXCLUSIVE, NULL)) != 0) 312 return (error); 313 314 /* 315 * If there are wedges, and this is not RAW_PART, then we 316 * need to fail. 317 */ 318 if (wd->sc_dk.dk_nwedges != 0 && part != RAW_PART) { 319 error = EBUSY; 320 goto bad1; 321 } 322 323 if (wd->sc_dk.dk_openmask != 0) { 324 /* 325 * If any partition is open, but the disk has been invalidated, 326 * disallow further opens. 327 */ 328 if ((wd->sc_flags & WDF_LOADED) == 0) { 329 error = EIO; 330 goto bad1; 331 } 332 } else { 333 if ((wd->sc_flags & WDF_LOADED) == 0) { 334 int s; 335 336 wd->sc_flags |= WDF_LOADED; 337 338 /* Load the physical device parameters. */ 339 s = splbio(); 340 ed_get_params(wd, NULL); 341 splx(s); 342 343 /* Load the partition info if not already loaded. */ 344 edgetdisklabel(dev, wd); 345 } 346 } 347 348 /* Check that the partition exists. */ 349 if (part != RAW_PART && 350 (part >= wd->sc_dk.dk_label->d_npartitions || 351 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 352 error = ENXIO; 353 goto bad1; 354 } 355 356 /* Insure only one open at a time. */ 357 switch (fmt) { 358 case S_IFCHR: 359 wd->sc_dk.dk_copenmask |= (1 << part); 360 break; 361 case S_IFBLK: 362 wd->sc_dk.dk_bopenmask |= (1 << part); 363 break; 364 } 365 wd->sc_dk.dk_openmask = 366 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 367 368 (void) lockmgr(&wd->sc_dk.dk_openlock, LK_RELEASE, NULL); 369 return 0; 370 371 bad1: 372 (void) lockmgr(&wd->sc_dk.dk_openlock, LK_RELEASE, NULL); 373 return (error); 374 } 375 376 int 377 edmcaclose(dev, flag, fmt, p) 378 dev_t dev; 379 int flag, fmt; 380 struct proc *p; 381 { 382 struct ed_softc *wd = device_lookup(&ed_cd, DISKUNIT(dev)); 383 int part = DISKPART(dev); 384 int error; 385 386 ATADEBUG_PRINT(("edmcaclose\n"), DEBUG_FUNCS); 387 388 if ((error = lockmgr(&wd->sc_dk.dk_openlock, LK_EXCLUSIVE, NULL)) != 0) 389 return (error); 390 391 switch (fmt) { 392 case S_IFCHR: 393 wd->sc_dk.dk_copenmask &= ~(1 << part); 394 break; 395 case S_IFBLK: 396 wd->sc_dk.dk_bopenmask &= ~(1 << part); 397 break; 398 } 399 wd->sc_dk.dk_openmask = 400 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 401 402 if (wd->sc_dk.dk_openmask == 0) { 403 #if 0 404 wd_flushcache(wd, AT_WAIT); 405 #endif 406 /* XXXX Must wait for I/O to complete! */ 407 408 if (! (wd->sc_flags & WDF_KLABEL)) 409 wd->sc_flags &= ~WDF_LOADED; 410 } 411 412 (void) lockmgr(&wd->sc_dk.dk_openlock, LK_RELEASE, NULL); 413 414 return 0; 415 } 416 417 static void 418 edgetdefaultlabel(ed, lp) 419 struct ed_softc *ed; 420 struct disklabel *lp; 421 { 422 ATADEBUG_PRINT(("edgetdefaultlabel\n"), DEBUG_FUNCS); 423 memset(lp, 0, sizeof(struct disklabel)); 424 425 lp->d_secsize = DEV_BSIZE; 426 lp->d_ntracks = ed->heads; 427 lp->d_nsectors = ed->sectors; 428 lp->d_ncylinders = ed->cyl; 429 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 430 431 lp->d_type = DTYPE_ESDI; 432 433 strncpy(lp->d_typename, "ESDI", 16); 434 strncpy(lp->d_packname, "fictitious", 16); 435 lp->d_secperunit = ed->sc_capacity; 436 lp->d_rpm = 3600; 437 lp->d_interleave = 1; 438 lp->d_flags = 0; 439 440 lp->d_partitions[RAW_PART].p_offset = 0; 441 lp->d_partitions[RAW_PART].p_size = 442 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 443 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 444 lp->d_npartitions = RAW_PART + 1; 445 446 lp->d_magic = DISKMAGIC; 447 lp->d_magic2 = DISKMAGIC; 448 lp->d_checksum = dkcksum(lp); 449 } 450 451 /* 452 * Fabricate a default disk label, and try to read the correct one. 453 */ 454 static void 455 edgetdisklabel(dev, ed) 456 dev_t dev; 457 struct ed_softc *ed; 458 { 459 struct disklabel *lp = ed->sc_dk.dk_label; 460 const char *errstring; 461 462 ATADEBUG_PRINT(("edgetdisklabel\n"), DEBUG_FUNCS); 463 464 memset(ed->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel)); 465 466 edgetdefaultlabel(ed, lp); 467 468 errstring = readdisklabel( 469 EDLABELDEV(dev), edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 470 if (errstring) { 471 /* 472 * This probably happened because the drive's default 473 * geometry doesn't match the DOS geometry. We 474 * assume the DOS geometry is now in the label and try 475 * again. XXX This is a kluge. 476 */ 477 #if 0 478 if (wd->drvp->state > RECAL) 479 wd->drvp->drive_flags |= DRIVE_RESET; 480 #endif 481 errstring = readdisklabel(EDLABELDEV(dev), 482 edmcastrategy, lp, ed->sc_dk.dk_cpulabel); 483 } 484 if (errstring) { 485 printf("%s: %s\n", ed->sc_dev.dv_xname, errstring); 486 return; 487 } 488 } 489 490 int 491 edmcaioctl(dev, xfer, addr, flag, p) 492 dev_t dev; 493 u_long xfer; 494 caddr_t addr; 495 int flag; 496 struct proc *p; 497 { 498 struct ed_softc *ed = device_lookup(&ed_cd, DISKUNIT(dev)); 499 int error; 500 501 ATADEBUG_PRINT(("edioctl\n"), DEBUG_FUNCS); 502 503 if ((ed->sc_flags & WDF_LOADED) == 0) 504 return EIO; 505 506 switch (xfer) { 507 case DIOCGDINFO: 508 *(struct disklabel *)addr = *(ed->sc_dk.dk_label); 509 return 0; 510 511 case DIOCGPART: 512 ((struct partinfo *)addr)->disklab = ed->sc_dk.dk_label; 513 ((struct partinfo *)addr)->part = 514 &ed->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 515 return 0; 516 517 case DIOCWDINFO: 518 case DIOCSDINFO: 519 { 520 struct disklabel *lp; 521 522 lp = (struct disklabel *)addr; 523 524 if ((flag & FWRITE) == 0) 525 return EBADF; 526 527 if ((error = lockmgr(&ed->sc_dk.dk_openlock, LK_EXCLUSIVE, 528 NULL)) != 0) 529 return (error); 530 ed->sc_flags |= WDF_LABELLING; 531 532 error = setdisklabel(ed->sc_dk.dk_label, 533 lp, /*wd->sc_dk.dk_openmask : */0, 534 ed->sc_dk.dk_cpulabel); 535 if (error == 0) { 536 #if 0 537 if (wd->drvp->state > RECAL) 538 wd->drvp->drive_flags |= DRIVE_RESET; 539 #endif 540 if (xfer == DIOCWDINFO) 541 error = writedisklabel(EDLABELDEV(dev), 542 edmcastrategy, ed->sc_dk.dk_label, 543 ed->sc_dk.dk_cpulabel); 544 } 545 546 ed->sc_flags &= ~WDF_LABELLING; 547 (void) lockmgr(&ed->sc_dk.dk_openlock, LK_RELEASE, NULL); 548 return (error); 549 } 550 551 case DIOCKLABEL: 552 if (*(int *)addr) 553 ed->sc_flags |= WDF_KLABEL; 554 else 555 ed->sc_flags &= ~WDF_KLABEL; 556 return 0; 557 558 case DIOCWLABEL: 559 if ((flag & FWRITE) == 0) 560 return EBADF; 561 if (*(int *)addr) 562 ed->sc_flags |= WDF_WLABEL; 563 else 564 ed->sc_flags &= ~WDF_WLABEL; 565 return 0; 566 567 case DIOCGDEFLABEL: 568 edgetdefaultlabel(ed, (struct disklabel *)addr); 569 return 0; 570 571 #if 0 572 case DIOCWFORMAT: 573 if ((flag & FWRITE) == 0) 574 return EBADF; 575 { 576 register struct format_op *fop; 577 struct iovec aiov; 578 struct uio auio; 579 580 fop = (struct format_op *)addr; 581 aiov.iov_base = fop->df_buf; 582 aiov.iov_len = fop->df_count; 583 auio.uio_iov = &aiov; 584 auio.uio_iovcnt = 1; 585 auio.uio_resid = fop->df_count; 586 auio.uio_segflg = 0; 587 auio.uio_offset = 588 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 589 auio.uio_procp = p; 590 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 591 &auio); 592 fop->df_count -= auio.uio_resid; 593 fop->df_reg[0] = wdc->sc_status; 594 fop->df_reg[1] = wdc->sc_error; 595 return error; 596 } 597 #endif 598 599 case DIOCAWEDGE: 600 { 601 struct dkwedge_info *dkw = (void *) addr; 602 603 if ((flag & FWRITE) == 0) 604 return (EBADF); 605 606 /* If the ioctl happens here, the parent is us. */ 607 strcpy(dkw->dkw_parent, ed->sc_dev.dv_xname); 608 return (dkwedge_add(dkw)); 609 } 610 611 case DIOCDWEDGE: 612 { 613 struct dkwedge_info *dkw = (void *) addr; 614 615 if ((flag & FWRITE) == 0) 616 return (EBADF); 617 618 /* If the ioctl happens here, the parent is us. */ 619 strcpy(dkw->dkw_parent, ed->sc_dev.dv_xname); 620 return (dkwedge_del(dkw)); 621 } 622 623 case DIOCLWEDGES: 624 { 625 struct dkwedge_list *dkwl = (void *) addr; 626 627 return (dkwedge_list(&ed->sc_dk, dkwl, p)); 628 } 629 630 default: 631 return ENOTTY; 632 } 633 634 #ifdef DIAGNOSTIC 635 panic("edioctl: impossible"); 636 #endif 637 } 638 639 int 640 edmcasize(dev) 641 dev_t dev; 642 { 643 struct ed_softc *wd; 644 int part, omask; 645 int size; 646 647 ATADEBUG_PRINT(("edsize\n"), DEBUG_FUNCS); 648 649 wd = device_lookup(&ed_cd, DISKUNIT(dev)); 650 if (wd == NULL) 651 return (-1); 652 653 part = DISKPART(dev); 654 omask = wd->sc_dk.dk_openmask & (1 << part); 655 656 if (omask == 0 && edmcaopen(dev, 0, S_IFBLK, NULL) != 0) 657 return (-1); 658 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 659 size = -1; 660 else 661 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 662 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 663 if (omask == 0 && edmcaclose(dev, 0, S_IFBLK, NULL) != 0) 664 return (-1); 665 return (size); 666 } 667 668 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 669 static int eddoingadump = 0; 670 static int eddumprecalibrated = 0; 671 static int eddumpmulti = 1; 672 673 /* 674 * Dump core after a system crash. 675 */ 676 int 677 edmcadump(dev, blkno, va, size) 678 dev_t dev; 679 daddr_t blkno; 680 caddr_t va; 681 size_t size; 682 { 683 struct ed_softc *ed; /* disk unit to do the I/O */ 684 struct disklabel *lp; /* disk's disklabel */ 685 int part; 686 int nblks; /* total number of sectors left to write */ 687 int error; 688 689 /* Check if recursive dump; if so, punt. */ 690 if (eddoingadump) 691 return EFAULT; 692 eddoingadump = 1; 693 694 ed = device_lookup(&ed_cd, DISKUNIT(dev)); 695 if (ed == NULL) 696 return (ENXIO); 697 698 part = DISKPART(dev); 699 700 /* Make sure it was initialized. */ 701 if ((ed->sc_flags & EDF_INIT) == 0) 702 return ENXIO; 703 704 /* Convert to disk sectors. Request must be a multiple of size. */ 705 lp = ed->sc_dk.dk_label; 706 if ((size % lp->d_secsize) != 0) 707 return EFAULT; 708 nblks = size / lp->d_secsize; 709 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 710 711 /* Check transfer bounds against partition size. */ 712 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 713 return EINVAL; 714 715 /* Offset block number to start of partition. */ 716 blkno += lp->d_partitions[part].p_offset; 717 718 /* Recalibrate, if first dump transfer. */ 719 if (eddumprecalibrated == 0) { 720 eddumprecalibrated = 1; 721 eddumpmulti = 8; 722 #if 0 723 wd->drvp->state = RESET; 724 #endif 725 } 726 727 while (nblks > 0) { 728 error = edc_bio(ed->edc_softc, ed, va, blkno, 729 min(nblks, eddumpmulti) * lp->d_secsize, 0, 1); 730 if (error) 731 return (error); 732 733 /* update block count */ 734 nblks -= min(nblks, eddumpmulti); 735 blkno += min(nblks, eddumpmulti); 736 va += min(nblks, eddumpmulti) * lp->d_secsize; 737 } 738 739 eddoingadump = 0; 740 return (0); 741 } 742 743 static int 744 ed_get_params(ed, drv_flags) 745 struct ed_softc *ed; 746 int *drv_flags; 747 { 748 u_int16_t cmd_args[2]; 749 750 /* 751 * Get Device Configuration (09). 752 */ 753 cmd_args[0] = 14; /* Options: 00s110, s: 0=Physical 1=Pseudo */ 754 cmd_args[1] = 0; 755 if (edc_run_cmd(ed->edc_softc, CMD_GET_DEV_CONF, ed->sc_devno, 756 cmd_args, 2, 1)) 757 return (1); 758 759 ed->spares = ed->sense_data[1] >> 8; 760 if (drv_flags) 761 *drv_flags = ed->sense_data[1] & 0x1f; 762 ed->rba = ed->sense_data[2] | (ed->sense_data[3] << 16); 763 /* Instead of using: 764 ed->cyl = ed->sense_data[4]; 765 ed->heads = ed->sense_data[5] & 0xff; 766 ed->sectors = ed->sense_data[5] >> 8; 767 * we fabricate the numbers from RBA count, so that 768 * number of sectors is 32 and heads 64. This seems 769 * to be necessary for integrated ESDI controller. 770 */ 771 ed->sectors = 32; 772 ed->heads = 64; 773 ed->cyl = ed->rba / (ed->heads * ed->sectors); 774 ed->sc_capacity = ed->rba; 775 776 return (0); 777 } 778