twe_freebsd.c revision 67684
1/*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/twe/twe_freebsd.c 67684 2000-10-27 05:58:45Z msmith $ 28 */ 29 30/* 31 * FreeBSD-specific code. 32 */ 33 34#include <dev/twe/twe_compat.h> 35#include <dev/twe/twereg.h> 36#include <dev/twe/tweio.h> 37#include <dev/twe/twevar.h> 38#include <dev/twe/twe_tables.h> 39 40#include <sys/devicestat.h> 41 42static devclass_t twe_devclass; 43 44/******************************************************************************** 45 ******************************************************************************** 46 Control device interface 47 ******************************************************************************** 48 ********************************************************************************/ 49 50static d_open_t twe_open; 51static d_close_t twe_close; 52static d_ioctl_t twe_ioctl_wrapper; 53 54#define TWE_CDEV_MAJOR 146 55 56static struct cdevsw twe_cdevsw = { 57 twe_open, 58 twe_close, 59 noread, 60 nowrite, 61 twe_ioctl_wrapper, 62 nopoll, 63 nommap, 64 nostrategy, 65 "twe", 66 TWE_CDEV_MAJOR, 67 nodump, 68 nopsize, 69 0, 70 -1 71}; 72 73/******************************************************************************** 74 * Accept an open operation on the control device. 75 */ 76static int 77twe_open(dev_t dev, int flags, int fmt, struct proc *p) 78{ 79 int unit = minor(dev); 80 struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); 81 82 sc->twe_state |= TWE_STATE_OPEN; 83 return(0); 84} 85 86/******************************************************************************** 87 * Accept the last close on the control device. 88 */ 89static int 90twe_close(dev_t dev, int flags, int fmt, struct proc *p) 91{ 92 int unit = minor(dev); 93 struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); 94 95 sc->twe_state &= ~TWE_STATE_OPEN; 96 return (0); 97} 98 99/******************************************************************************** 100 * Handle controller-specific control operations. 101 */ 102static int 103twe_ioctl_wrapper(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) 104{ 105 struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; 106 107 return(twe_ioctl(sc, cmd, addr)); 108} 109 110/******************************************************************************** 111 ******************************************************************************** 112 PCI device interface 113 ******************************************************************************** 114 ********************************************************************************/ 115 116static int twe_probe(device_t dev); 117static int twe_attach(device_t dev); 118static void twe_free(struct twe_softc *sc); 119static int twe_detach(device_t dev); 120static int twe_shutdown(device_t dev); 121static int twe_suspend(device_t dev); 122static int twe_resume(device_t dev); 123static void twe_pci_intr(void *arg); 124static void twe_intrhook(void *arg); 125 126static device_method_t twe_methods[] = { 127 /* Device interface */ 128 DEVMETHOD(device_probe, twe_probe), 129 DEVMETHOD(device_attach, twe_attach), 130 DEVMETHOD(device_detach, twe_detach), 131 DEVMETHOD(device_shutdown, twe_shutdown), 132 DEVMETHOD(device_suspend, twe_suspend), 133 DEVMETHOD(device_resume, twe_resume), 134 135 DEVMETHOD(bus_print_child, bus_generic_print_child), 136 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 137 { 0, 0 } 138}; 139 140static driver_t twe_pci_driver = { 141 "twe", 142 twe_methods, 143 sizeof(struct twe_softc) 144}; 145 146#ifdef TWE_OVERRIDE 147DRIVER_MODULE(Xtwe, pci, twe_pci_driver, twe_devclass, 0, 0); 148#else 149DRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0); 150#endif 151 152/******************************************************************************** 153 * Match a 3ware Escalade ATA RAID controller. 154 */ 155static int 156twe_probe(device_t dev) 157{ 158 159 debug_called(4); 160 161 if ((pci_get_vendor(dev) == TWE_VENDOR_ID) && 162 ((pci_get_device(dev) == TWE_DEVICE_ID) || 163 (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) { 164 device_set_desc(dev, TWE_DEVICE_NAME); 165#ifdef TWE_OVERRIDE 166 return(0); 167#else 168 return(-10); 169#endif 170 } 171 return(ENXIO); 172} 173 174/******************************************************************************** 175 * Allocate resources, initialise the controller. 176 */ 177static int 178twe_attach(device_t dev) 179{ 180 struct twe_softc *sc; 181 int rid, error; 182 u_int32_t command; 183 184 debug_called(4); 185 186 /* 187 * Initialise the softc structure. 188 */ 189 sc = device_get_softc(dev); 190 sc->twe_dev = dev; 191 192 /* 193 * Make sure we are going to be able to talk to this board. 194 */ 195 command = pci_read_config(dev, PCIR_COMMAND, 2); 196 if ((command & PCIM_CMD_PORTEN) == 0) { 197 twe_printf(sc, "register window not available\n"); 198 return(ENXIO); 199 } 200 /* 201 * Force the busmaster enable bit on, in case the BIOS forgot. 202 */ 203 command |= PCIM_CMD_BUSMASTEREN; 204 pci_write_config(dev, PCIR_COMMAND, command, 2); 205 206 /* 207 * Allocate the PCI register window. 208 */ 209 rid = TWE_IO_CONFIG_REG; 210 if ((sc->twe_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE)) == NULL) { 211 twe_printf(sc, "can't allocate register window\n"); 212 twe_free(sc); 213 return(ENXIO); 214 } 215 sc->twe_btag = rman_get_bustag(sc->twe_io); 216 sc->twe_bhandle = rman_get_bushandle(sc->twe_io); 217 218 /* 219 * Allocate the parent bus DMA tag appropriate for PCI. 220 */ 221 if (bus_dma_tag_create(NULL, /* parent */ 222 1, 0, /* alignment, boundary */ 223 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 224 BUS_SPACE_MAXADDR, /* highaddr */ 225 NULL, NULL, /* filter, filterarg */ 226 MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */ 227 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 228 BUS_DMA_ALLOCNOW, /* flags */ 229 &sc->twe_parent_dmat)) { 230 twe_printf(sc, "can't allocate parent DMA tag\n"); 231 twe_free(sc); 232 return(ENOMEM); 233 } 234 235 /* 236 * Allocate and connect our interrupt. 237 */ 238 rid = 0; 239 if ((sc->twe_irq = bus_alloc_resource(sc->twe_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 240 twe_printf(sc, "can't allocate interrupt\n"); 241 twe_free(sc); 242 return(ENXIO); 243 } 244 if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO, twe_pci_intr, sc, &sc->twe_intr)) { 245 twe_printf(sc, "can't set up interrupt\n"); 246 twe_free(sc); 247 return(ENXIO); 248 } 249 250 /* 251 * Create DMA tag for mapping objects into controller-addressable space. 252 */ 253 if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ 254 1, 0, /* alignment, boundary */ 255 BUS_SPACE_MAXADDR, /* lowaddr */ 256 BUS_SPACE_MAXADDR, /* highaddr */ 257 NULL, NULL, /* filter, filterarg */ 258 MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */ 259 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 260 0, /* flags */ 261 &sc->twe_buffer_dmat)) { 262 twe_printf(sc, "can't allocate data buffer DMA tag\n"); 263 twe_free(sc); 264 return(ENOMEM); 265 } 266 267 /* 268 * Initialise the controller and driver core. 269 */ 270 if ((error = twe_setup(sc))) 271 return(error); 272 273 /* 274 * Print some information about the controller and configuration. 275 */ 276 twe_describe_controller(sc); 277 278 /* 279 * Create the control device. 280 */ 281 sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), UID_ROOT, GID_OPERATOR, 282 S_IRUSR | S_IWUSR, "twe%d", device_get_unit(sc->twe_dev)); 283 sc->twe_dev_t->si_drv1 = sc; 284 /* 285 * Schedule ourselves to bring the controller up once interrupts are available. 286 * This isn't strictly necessary, since we disable interrupts while probing the 287 * controller, but it is more in keeping with common practice for other disk 288 * devices. 289 */ 290 sc->twe_ich.ich_func = twe_intrhook; 291 sc->twe_ich.ich_arg = sc; 292 if (config_intrhook_establish(&sc->twe_ich) != 0) { 293 twe_printf(sc, "can't establish configuration hook\n"); 294 twe_free(sc); 295 return(ENXIO); 296 } 297 298 return(0); 299} 300 301/******************************************************************************** 302 * Free all of the resources associated with (sc). 303 * 304 * Should not be called if the controller is active. 305 */ 306static void 307twe_free(struct twe_softc *sc) 308{ 309 struct twe_request *tr; 310 311 debug_called(4); 312 313 /* throw away any command buffers */ 314 while ((tr = twe_dequeue_free(sc)) != NULL) 315 twe_free_request(tr); 316 317 /* destroy the data-transfer DMA tag */ 318 if (sc->twe_buffer_dmat) 319 bus_dma_tag_destroy(sc->twe_buffer_dmat); 320 321 /* disconnect the interrupt handler */ 322 if (sc->twe_intr) 323 bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr); 324 if (sc->twe_irq != NULL) 325 bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq); 326 327 /* destroy the parent DMA tag */ 328 if (sc->twe_parent_dmat) 329 bus_dma_tag_destroy(sc->twe_parent_dmat); 330 331 /* release the register window mapping */ 332 if (sc->twe_io != NULL) 333 bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io); 334 335 /* destroy control device */ 336 if (sc->twe_dev_t != (dev_t)NULL) 337 destroy_dev(sc->twe_dev_t); 338} 339 340/******************************************************************************** 341 * Disconnect from the controller completely, in preparation for unload. 342 */ 343static int 344twe_detach(device_t dev) 345{ 346 struct twe_softc *sc = device_get_softc(dev); 347 int s, error; 348 349 debug_called(4); 350 351 error = EBUSY; 352 s = splbio(); 353 if (sc->twe_state & TWE_STATE_OPEN) 354 goto out; 355 356 /* 357 * Shut the controller down. 358 */ 359 if ((error = twe_shutdown(dev))) 360 goto out; 361 362 twe_free(sc); 363 364 error = 0; 365 out: 366 splx(s); 367 return(error); 368} 369 370/******************************************************************************** 371 * Bring the controller down to a dormant state and detach all child devices. 372 * 373 * Note that we can assume that the bioq on the controller is empty, as we won't 374 * allow shutdown if any device is open. 375 */ 376static int 377twe_shutdown(device_t dev) 378{ 379 struct twe_softc *sc = device_get_softc(dev); 380 int i, s, error; 381 382 debug_called(4); 383 384 s = splbio(); 385 error = 0; 386 387 /* 388 * Delete all our child devices. 389 */ 390 for (i = 0; i < TWE_MAX_UNITS; i++) { 391 if (sc->twe_drive[i].td_disk != 0) { 392 if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[i].td_disk)) != 0) 393 goto out; 394 sc->twe_drive[i].td_disk = 0; 395 } 396 } 397 398 /* 399 * Bring the controller down. 400 */ 401 twe_deinit(sc); 402 403 out: 404 splx(s); 405 return(error); 406} 407 408/******************************************************************************** 409 * Bring the controller to a quiescent state, ready for system suspend. 410 */ 411static int 412twe_suspend(device_t dev) 413{ 414 struct twe_softc *sc = device_get_softc(dev); 415 int s; 416 417 debug_called(4); 418 419 s = splbio(); 420 sc->twe_state |= TWE_STATE_SUSPEND; 421 422 twe_disable_interrupts(sc); 423 splx(s); 424 425 return(0); 426} 427 428/******************************************************************************** 429 * Bring the controller back to a state ready for operation. 430 */ 431static int 432twe_resume(device_t dev) 433{ 434 struct twe_softc *sc = device_get_softc(dev); 435 436 debug_called(4); 437 438 sc->twe_state &= ~TWE_STATE_SUSPEND; 439 twe_enable_interrupts(sc); 440 441 return(0); 442} 443 444/******************************************************************************* 445 * Take an interrupt, or be poked by other code to look for interrupt-worthy 446 * status. 447 */ 448static void 449twe_pci_intr(void *arg) 450{ 451 twe_intr((struct twe_softc *)arg); 452} 453 454/******************************************************************************** 455 * Delayed-startup hook 456 */ 457static void 458twe_intrhook(void *arg) 459{ 460 struct twe_softc *sc = (struct twe_softc *)arg; 461 462 /* pull ourselves off the intrhook chain */ 463 config_intrhook_disestablish(&sc->twe_ich); 464 465 /* call core startup routine */ 466 twe_init(sc); 467} 468 469/******************************************************************************** 470 * Given a detected drive, attach it to the bio interface. 471 * 472 * This is called from twe_init. 473 */ 474void 475twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) 476{ 477 char buf[80]; 478 int error; 479 480 dr->td_disk = device_add_child(sc->twe_dev, NULL, -1); 481 if (dr->td_disk == NULL) { 482 twe_printf(sc, "device_add_child failed\n"); 483 return; 484 } 485 device_set_ivars(dr->td_disk, dr); 486 487 /* 488 * XXX It would make sense to test the online/initialising bits, but they seem to be 489 * always set... 490 */ 491 sprintf(buf, "%s, %s", twe_describe_code(twe_table_unittype, dr->td_type), 492 twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK)); 493 device_set_desc_copy(dr->td_disk, buf); 494 495 if ((error = bus_generic_attach(sc->twe_dev)) != 0) 496 twe_printf(sc, "bus_generic_attach returned %d\n", error); 497} 498 499/******************************************************************************** 500 ******************************************************************************** 501 Disk device 502 ******************************************************************************** 503 ********************************************************************************/ 504 505/* 506 * Disk device softc 507 */ 508struct twed_softc 509{ 510 device_t twed_dev; 511 dev_t twed_dev_t; 512 struct twe_softc *twed_controller; /* parent device softc */ 513 struct twe_drive *twed_drive; /* drive data in parent softc */ 514 struct disk twed_disk; /* generic disk handle */ 515 struct devstat twed_stats; /* accounting */ 516 struct disklabel twed_label; /* synthetic label */ 517 int twed_flags; 518#define TWED_OPEN (1<<0) /* drive is open (can't shut down) */ 519}; 520 521/* 522 * Disk device bus interface 523 */ 524static int twed_probe(device_t dev); 525static int twed_attach(device_t dev); 526static int twed_detach(device_t dev); 527 528static device_method_t twed_methods[] = { 529 DEVMETHOD(device_probe, twed_probe), 530 DEVMETHOD(device_attach, twed_attach), 531 DEVMETHOD(device_detach, twed_detach), 532 { 0, 0 } 533}; 534 535static driver_t twed_driver = { 536 "twed", 537 twed_methods, 538 sizeof(struct twed_softc) 539}; 540 541static devclass_t twed_devclass; 542#ifdef TWE_OVERRIDE 543DRIVER_MODULE(Xtwed, Xtwe, twed_driver, twed_devclass, 0, 0); 544#else 545DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0); 546#endif 547 548/* 549 * Disk device control interface. 550 */ 551static d_open_t twed_open; 552static d_close_t twed_close; 553static d_strategy_t twed_strategy; 554 555#define TWED_CDEV_MAJOR 147 556 557static struct cdevsw twed_cdevsw = { 558 twed_open, 559 twed_close, 560 physread, 561 physwrite, 562 noioctl, 563 nopoll, 564 nommap, 565 twed_strategy, 566 "twed", 567 TWED_CDEV_MAJOR, 568 nodump, 569 nopsize, 570 D_DISK, 571 -1 572}; 573 574static struct cdevsw tweddisk_cdevsw; 575#ifdef FREEBSD_4 576static int disks_registered = 0; 577#endif 578 579/******************************************************************************** 580 * Handle open from generic layer. 581 * 582 * Note that this is typically only called by the diskslice code, and not 583 * for opens on subdevices (eg. slices, partitions). 584 */ 585static int 586twed_open(dev_t dev, int flags, int fmt, struct proc *p) 587{ 588 struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; 589 struct disklabel *label; 590 591 debug_called(4); 592 593 if (sc == NULL) 594 return (ENXIO); 595 596 /* check that the controller is up and running */ 597 if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN) 598 return(ENXIO); 599 600 /* build synthetic label */ 601 label = &sc->twed_disk.d_label; 602 bzero(label, sizeof(*label)); 603 label->d_type = DTYPE_ESDI; 604 label->d_secsize = TWE_BLOCK_SIZE; 605 label->d_nsectors = sc->twed_drive->td_sectors; 606 label->d_ntracks = sc->twed_drive->td_heads; 607 label->d_ncylinders = sc->twed_drive->td_cylinders; 608 label->d_secpercyl = sc->twed_drive->td_sectors * sc->twed_drive->td_heads; 609 label->d_secperunit = sc->twed_drive->td_size; 610 611 sc->twed_flags |= TWED_OPEN; 612 return (0); 613} 614 615/******************************************************************************** 616 * Handle last close of the disk device. 617 */ 618static int 619twed_close(dev_t dev, int flags, int fmt, struct proc *p) 620{ 621 struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; 622 623 debug_called(4); 624 625 if (sc == NULL) 626 return (ENXIO); 627 628 sc->twed_flags &= ~TWED_OPEN; 629 return (0); 630} 631 632/******************************************************************************** 633 * Handle an I/O request. 634 */ 635static void 636twed_strategy(twe_bio *bp) 637{ 638 struct twed_softc *sc = (struct twed_softc *)TWE_BIO_SOFTC(bp); 639 640 debug_called(4); 641 642 /* bogus disk? */ 643 if (sc == NULL) { 644 TWE_BIO_SET_ERROR(bp, EINVAL); 645 return; 646 } 647 648 /* do-nothing operation? */ 649 if (TWE_BIO_LENGTH(bp) == 0) { 650 TWE_BIO_RESID(bp) = 0; 651 TWE_BIO_DONE(bp); 652 return; 653 } 654 655 /* perform accounting */ 656 TWE_BIO_STATS_START(bp); 657 658 /* pass the bio to the controller - it can work out who we are */ 659 twe_submit_bio(sc->twed_controller, bp); 660 return; 661} 662 663/******************************************************************************** 664 * Handle completion of an I/O request. 665 */ 666void 667twed_intr(twe_bio *bp) 668{ 669 debug_called(4); 670 671 /* if no error, transfer completed */ 672 if (!TWE_BIO_HAS_ERROR(bp)) 673 TWE_BIO_RESID(bp) = 0; 674 675 TWE_BIO_STATS_END(bp); 676 TWE_BIO_DONE(bp); 677} 678 679/******************************************************************************** 680 * Default probe stub. 681 */ 682static int 683twed_probe(device_t dev) 684{ 685 return (0); 686} 687 688/******************************************************************************** 689 * Attach a unit to the controller. 690 */ 691static int 692twed_attach(device_t dev) 693{ 694 struct twed_softc *sc; 695 device_t parent; 696 dev_t dsk; 697 698 debug_called(4); 699 700 /* initialise our softc */ 701 sc = device_get_softc(dev); 702 parent = device_get_parent(dev); 703 sc->twed_controller = (struct twe_softc *)device_get_softc(parent); 704 sc->twed_drive = device_get_ivars(dev); 705 sc->twed_dev = dev; 706 707 /* report the drive */ 708 twed_printf(sc, "%uMB (%u sectors)\n", 709 sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE), 710 sc->twed_drive->td_size); 711 712 devstat_add_entry(&sc->twed_stats, "twed", device_get_unit(dev), TWE_BLOCK_SIZE, 713 DEVSTAT_NO_ORDERED_TAGS, 714 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 715 DEVSTAT_PRIORITY_ARRAY); 716 717 /* attach a generic disk device to ourselves */ 718 dsk = disk_create(device_get_unit(dev), &sc->twed_disk, 0, &twed_cdevsw, &tweddisk_cdevsw); 719 dsk->si_drv1 = sc; 720 dsk->si_drv2 = &sc->twed_drive->td_unit; 721 sc->twed_dev_t = dsk; 722#ifdef FREEBSD_4 723 disks_registered++; 724#endif 725 726 /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */ 727 dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE; 728 729 return (0); 730} 731 732/******************************************************************************** 733 * Disconnect ourselves from the system. 734 */ 735static int 736twed_detach(device_t dev) 737{ 738 struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev); 739 740 debug_called(4); 741 742 if (sc->twed_flags & TWED_OPEN) 743 return(EBUSY); 744 745 devstat_remove_entry(&sc->twed_stats); 746#ifdef FREEBSD_4 747 if (--disks_registered == 0) 748 cdevsw_remove(&tweddisk_cdevsw); 749#else 750 disk_destroy(sc->twed_dev_t); 751#endif 752 753 return(0); 754} 755 756/******************************************************************************** 757 ******************************************************************************** 758 Misc 759 ******************************************************************************** 760 ********************************************************************************/ 761 762static void twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 763static void twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); 764 765/******************************************************************************** 766 * Allocate a command buffer 767 */ 768MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands"); 769 770struct twe_request * 771twe_allocate_request(struct twe_softc *sc) 772{ 773 struct twe_request *tr; 774 775 if ((tr = malloc(sizeof(struct twe_request), TWE_MALLOC_CLASS, M_NOWAIT)) == NULL) 776 return(NULL); 777 bzero(tr, sizeof(*tr)); 778 tr->tr_sc = sc; 779 if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_cmdmap)) { 780 twe_free_request(tr); 781 return(NULL); 782 } 783 if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) { 784 bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); 785 twe_free_request(tr); 786 return(NULL); 787 } 788 return(tr); 789} 790 791/******************************************************************************** 792 * Permanently discard a command buffer. 793 */ 794void 795twe_free_request(struct twe_request *tr) 796{ 797 struct twe_softc *sc = tr->tr_sc; 798 799 debug_called(4); 800 801 bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); 802 bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap); 803 free(tr, TWE_MALLOC_CLASS); 804} 805 806/******************************************************************************** 807 * Map/unmap (tr)'s command and data in the controller's addressable space. 808 * 809 * These routines ensure that the data which the controller is going to try to 810 * access is actually visible to the controller, in a machine-independant 811 * fasion. Due to a hardware limitation, I/O buffers must be 512-byte aligned 812 * and we take care of that here as well. 813 */ 814static void 815twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 816{ 817 struct twe_request *tr = (struct twe_request *)arg; 818 TWE_Command *cmd = &tr->tr_command; 819 int i; 820 821 debug_called(4); 822 823 /* save base of first segment in command (applicable if there only one segment) */ 824 tr->tr_dataphys = segs[0].ds_addr; 825 826 /* correct command size for s/g list size */ 827 tr->tr_command.generic.size += 2 * nsegments; 828 829 /* 830 * Due to the fact that parameter and I/O commands have the scatter/gather list in 831 * different places, we need to determine which sort of command this actually is 832 * before we can populate it correctly. 833 */ 834 switch(cmd->generic.opcode) { 835 case TWE_OP_GET_PARAM: 836 case TWE_OP_SET_PARAM: 837 cmd->generic.sgl_offset = 2; 838 for (i = 0; i < nsegments; i++) { 839 cmd->param.sgl[i].address = segs[i].ds_addr; 840 cmd->param.sgl[i].length = segs[i].ds_len; 841 } 842 for (; i < TWE_MAX_SGL_LENGTH; i++) { /* XXX necessary? */ 843 cmd->param.sgl[i].address = 0; 844 cmd->param.sgl[i].length = 0; 845 } 846 break; 847 case TWE_OP_READ: 848 case TWE_OP_WRITE: 849 cmd->generic.sgl_offset = 3; 850 for (i = 0; i < nsegments; i++) { 851 cmd->io.sgl[i].address = segs[i].ds_addr; 852 cmd->io.sgl[i].length = segs[i].ds_len; 853 } 854 for (; i < TWE_MAX_SGL_LENGTH; i++) { /* XXX necessary? */ 855 cmd->io.sgl[i].address = 0; 856 cmd->io.sgl[i].length = 0; 857 } 858 break; 859 default: 860 /* no s/g list, nothing to do */ 861 } 862} 863 864static void 865twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) 866{ 867 struct twe_request *tr = (struct twe_request *)arg; 868 869 debug_called(4); 870 871 /* command can't cross a page boundary */ 872 tr->tr_cmdphys = segs[0].ds_addr; 873} 874 875void 876twe_map_request(struct twe_request *tr) 877{ 878 struct twe_softc *sc = tr->tr_sc; 879 880 debug_called(4); 881 882 883 /* 884 * Map the command into bus space. 885 */ 886 bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command, sizeof(tr->tr_command), 887 twe_setup_request_dmamap, tr, 0); 888 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_PREWRITE); 889 890 /* 891 * If the command involves data, map that too. 892 */ 893 if (tr->tr_data != NULL) { 894 895 /* 896 * Data must be 64-byte aligned; allocate a fixup buffer if it's not. 897 */ 898 if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) { 899 tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */ 900 tr->tr_flags |= TWE_CMD_ALIGNBUF; 901 tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT); /* XXX check result here */ 902 } 903 904 /* 905 * Map the data buffer into bus space and build the s/g list. 906 */ 907 bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length, 908 twe_setup_data_dmamap, tr, 0); 909 if (tr->tr_flags & TWE_CMD_DATAIN) 910 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD); 911 if (tr->tr_flags & TWE_CMD_DATAOUT) { 912 /* if we're using an alignment buffer, and we're writing data, copy the real data out */ 913 if (tr->tr_flags & TWE_CMD_ALIGNBUF) 914 bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length); 915 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE); 916 } 917 } 918} 919 920void 921twe_unmap_request(struct twe_request *tr) 922{ 923 struct twe_softc *sc = tr->tr_sc; 924 925 debug_called(4); 926 927 /* 928 * Unmap the command from bus space. 929 */ 930 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_POSTWRITE); 931 bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap); 932 933 /* 934 * If the command involved data, unmap that too. 935 */ 936 if (tr->tr_data != NULL) { 937 938 if (tr->tr_flags & TWE_CMD_DATAIN) { 939 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTREAD); 940 /* if we're using an alignment buffer, and we're reading data, copy the real data in */ 941 if (tr->tr_flags & TWE_CMD_ALIGNBUF) 942 bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length); 943 } 944 if (tr->tr_flags & TWE_CMD_DATAOUT) 945 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTWRITE); 946 947 bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap); 948 } 949 950 /* free alignment buffer if it was used */ 951 if (tr->tr_flags & TWE_CMD_ALIGNBUF) { 952 free(tr->tr_data, TWE_MALLOC_CLASS); 953 tr->tr_data = tr->tr_realdata; /* restore 'real' data pointer */ 954 } 955} 956 957#ifdef TWE_DEBUG 958/******************************************************************************** 959 * Print current controller status, call from DDB. 960 */ 961void 962twe_report(void) 963{ 964 struct twe_softc *sc; 965 int i, s; 966 967 s = splbio(); 968 for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++) 969 twe_print_controller(sc); 970 splx(s); 971} 972#endif 973