| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 2000 Michael Smith | |
| a062d8a7 HP |
3 | * Copyright (c) 2003 Paul Saab |
| 4 | * Copyright (c) 2003 Vinod Kashyap | |
| 984263bc MD |
5 | * Copyright (c) 2000 BSDi |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in the | |
| 15 | * documentation and/or other materials provided with the distribution. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 27 | * SUCH DAMAGE. | |
| 28 | * | |
| a062d8a7 | 29 | * $FreeBSD: src/sys/dev/twe/twe_freebsd.c,v 1.2.2.9 2004/06/11 18:57:31 vkashyap Exp $ |
| ba0cc1ab | 30 | * $DragonFly: src/sys/dev/raid/twe/twe_freebsd.c,v 1.27 2007/06/17 23:50:16 dillon Exp $ |
| 984263bc MD |
31 | */ |
| 32 | ||
| 33 | /* | |
| 34 | * FreeBSD-specific code. | |
| 35 | */ | |
| 36 | ||
| a062d8a7 HP |
37 | #include <dev/raid/twe/twe_compat.h> |
| 38 | #include <dev/raid/twe/twereg.h> | |
| 39 | #include <dev/raid/twe/twe_tables.h> | |
| 40 | #include <dev/raid/twe/tweio.h> | |
| 41 | #include <dev/raid/twe/twevar.h> | |
| ba0cc1ab | 42 | #include <sys/dtype.h> |
| 984263bc MD |
43 | |
| 44 | static devclass_t twe_devclass; | |
| 45 | ||
| 46 | #ifdef TWE_DEBUG | |
| 47 | static u_int32_t twed_bio_in; | |
| 48 | #define TWED_BIO_IN twed_bio_in++ | |
| 49 | static u_int32_t twed_bio_out; | |
| 50 | #define TWED_BIO_OUT twed_bio_out++ | |
| 51 | #else | |
| 52 | #define TWED_BIO_IN | |
| 53 | #define TWED_BIO_OUT | |
| 54 | #endif | |
| 55 | ||
| 56 | /******************************************************************************** | |
| 57 | ******************************************************************************** | |
| 58 | Control device interface | |
| 59 | ******************************************************************************** | |
| 60 | ********************************************************************************/ | |
| 61 | ||
| 62 | static d_open_t twe_open; | |
| 63 | static d_close_t twe_close; | |
| 64 | static d_ioctl_t twe_ioctl_wrapper; | |
| 65 | ||
| fef8985e MD |
66 | static struct dev_ops twe_ops = { |
| 67 | { "twe", TWE_CDEV_MAJOR, 0 }, | |
| 68 | .d_open = twe_open, | |
| 69 | .d_close = twe_close, | |
| 70 | .d_ioctl = twe_ioctl_wrapper, | |
| 984263bc MD |
71 | }; |
| 72 | ||
| 73 | /******************************************************************************** | |
| 74 | * Accept an open operation on the control device. | |
| 75 | */ | |
| 76 | static int | |
| fef8985e | 77 | twe_open(struct dev_open_args *ap) |
| 984263bc | 78 | { |
| b13267a5 | 79 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
80 | int unit = minor(dev); |
| 81 | struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); | |
| 82 | ||
| 83 | sc->twe_state |= TWE_STATE_OPEN; | |
| 84 | return(0); | |
| 85 | } | |
| 86 | ||
| 87 | /******************************************************************************** | |
| 88 | * Accept the last close on the control device. | |
| 89 | */ | |
| 90 | static int | |
| fef8985e | 91 | twe_close(struct dev_close_args *ap) |
| 984263bc | 92 | { |
| b13267a5 | 93 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
94 | int unit = minor(dev); |
| 95 | struct twe_softc *sc = devclass_get_softc(twe_devclass, unit); | |
| 96 | ||
| 97 | sc->twe_state &= ~TWE_STATE_OPEN; | |
| 98 | return (0); | |
| 99 | } | |
| 100 | ||
| 101 | /******************************************************************************** | |
| 102 | * Handle controller-specific control operations. | |
| 103 | */ | |
| 104 | static int | |
| fef8985e | 105 | twe_ioctl_wrapper(struct dev_ioctl_args *ap) |
| 984263bc | 106 | { |
| b13267a5 | 107 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 108 | struct twe_softc *sc = (struct twe_softc *)dev->si_drv1; |
| 984263bc | 109 | |
| fef8985e | 110 | return(twe_ioctl(sc, ap->a_cmd, ap->a_data)); |
| 984263bc MD |
111 | } |
| 112 | ||
| 113 | /******************************************************************************** | |
| 114 | ******************************************************************************** | |
| 115 | PCI device interface | |
| 116 | ******************************************************************************** | |
| 117 | ********************************************************************************/ | |
| 118 | ||
| 119 | static int twe_probe(device_t dev); | |
| 120 | static int twe_attach(device_t dev); | |
| 121 | static void twe_free(struct twe_softc *sc); | |
| 122 | static int twe_detach(device_t dev); | |
| a062d8a7 | 123 | static int twe_shutdown(device_t dev); |
| 984263bc MD |
124 | static int twe_suspend(device_t dev); |
| 125 | static int twe_resume(device_t dev); | |
| 126 | static void twe_pci_intr(void *arg); | |
| 127 | static void twe_intrhook(void *arg); | |
| a062d8a7 HP |
128 | static void twe_free_request(struct twe_request *tr); |
| 129 | static void twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, | |
| 130 | int nsegments, int error); | |
| 131 | static void twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, | |
| 132 | int nsegments, int error); | |
| 984263bc MD |
133 | |
| 134 | static device_method_t twe_methods[] = { | |
| 135 | /* Device interface */ | |
| 136 | DEVMETHOD(device_probe, twe_probe), | |
| 137 | DEVMETHOD(device_attach, twe_attach), | |
| 138 | DEVMETHOD(device_detach, twe_detach), | |
| 139 | DEVMETHOD(device_shutdown, twe_shutdown), | |
| 140 | DEVMETHOD(device_suspend, twe_suspend), | |
| 141 | DEVMETHOD(device_resume, twe_resume), | |
| 142 | ||
| 143 | DEVMETHOD(bus_print_child, bus_generic_print_child), | |
| 144 | DEVMETHOD(bus_driver_added, bus_generic_driver_added), | |
| 145 | { 0, 0 } | |
| 146 | }; | |
| 147 | ||
| 148 | static driver_t twe_pci_driver = { | |
| 149 | "twe", | |
| 150 | twe_methods, | |
| 151 | sizeof(struct twe_softc) | |
| 152 | }; | |
| 153 | ||
| 154 | #ifdef TWE_OVERRIDE | |
| 155 | DRIVER_MODULE(Xtwe, pci, twe_pci_driver, twe_devclass, 0, 0); | |
| 156 | #else | |
| 157 | DRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0); | |
| 158 | #endif | |
| 159 | ||
| 160 | /******************************************************************************** | |
| 161 | * Match a 3ware Escalade ATA RAID controller. | |
| 162 | */ | |
| 163 | static int | |
| 164 | twe_probe(device_t dev) | |
| 165 | { | |
| 166 | ||
| 167 | debug_called(4); | |
| 168 | ||
| 169 | if ((pci_get_vendor(dev) == TWE_VENDOR_ID) && | |
| 170 | ((pci_get_device(dev) == TWE_DEVICE_ID) || | |
| 171 | (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) { | |
| a062d8a7 | 172 | device_set_desc(dev, TWE_DEVICE_NAME " driver ver. " TWE_DRIVER_VERSION_STRING); |
| 984263bc MD |
173 | #ifdef TWE_OVERRIDE |
| 174 | return(0); | |
| 175 | #else | |
| 176 | return(-10); | |
| 177 | #endif | |
| 178 | } | |
| 179 | return(ENXIO); | |
| 180 | } | |
| 181 | ||
| 182 | /******************************************************************************** | |
| 183 | * Allocate resources, initialise the controller. | |
| 184 | */ | |
| 185 | static int | |
| 186 | twe_attach(device_t dev) | |
| 187 | { | |
| 188 | struct twe_softc *sc; | |
| 189 | int rid, error; | |
| 190 | u_int32_t command; | |
| 191 | ||
| 192 | debug_called(4); | |
| 193 | ||
| 194 | /* | |
| 195 | * Initialise the softc structure. | |
| 196 | */ | |
| 197 | sc = device_get_softc(dev); | |
| 198 | sc->twe_dev = dev; | |
| 199 | ||
| 0a62b1be DR |
200 | sysctl_ctx_init(&sc->sysctl_ctx); |
| 201 | sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, | |
| 202 | SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, | |
| 203 | device_get_nameunit(dev), CTLFLAG_RD, 0, ""); | |
| 204 | if (sc->sysctl_tree == NULL) { | |
| 205 | twe_printf(sc, "cannot add sysctl tree node\n"); | |
| 206 | return (ENXIO); | |
| 207 | } | |
| 208 | SYSCTL_ADD_STRING(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), | |
| a062d8a7 | 209 | OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0, |
| 0a62b1be DR |
210 | "TWE driver version"); |
| 211 | ||
| 984263bc MD |
212 | /* |
| 213 | * Make sure we are going to be able to talk to this board. | |
| 214 | */ | |
| 215 | command = pci_read_config(dev, PCIR_COMMAND, 2); | |
| 216 | if ((command & PCIM_CMD_PORTEN) == 0) { | |
| 217 | twe_printf(sc, "register window not available\n"); | |
| 218 | return(ENXIO); | |
| 219 | } | |
| 220 | /* | |
| 221 | * Force the busmaster enable bit on, in case the BIOS forgot. | |
| 222 | */ | |
| 223 | command |= PCIM_CMD_BUSMASTEREN; | |
| 224 | pci_write_config(dev, PCIR_COMMAND, command, 2); | |
| 225 | ||
| 226 | /* | |
| 227 | * Allocate the PCI register window. | |
| 228 | */ | |
| 229 | rid = TWE_IO_CONFIG_REG; | |
| 230 | if ((sc->twe_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE)) == NULL) { | |
| 231 | twe_printf(sc, "can't allocate register window\n"); | |
| 232 | twe_free(sc); | |
| 233 | return(ENXIO); | |
| 234 | } | |
| 235 | sc->twe_btag = rman_get_bustag(sc->twe_io); | |
| 236 | sc->twe_bhandle = rman_get_bushandle(sc->twe_io); | |
| 237 | ||
| 238 | /* | |
| 239 | * Allocate the parent bus DMA tag appropriate for PCI. | |
| 240 | */ | |
| 241 | if (bus_dma_tag_create(NULL, /* parent */ | |
| 242 | 1, 0, /* alignment, boundary */ | |
| 243 | BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ | |
| 244 | BUS_SPACE_MAXADDR, /* highaddr */ | |
| 245 | NULL, NULL, /* filter, filterarg */ | |
| 246 | MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */ | |
| 247 | BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ | |
| 248 | BUS_DMA_ALLOCNOW, /* flags */ | |
| 249 | &sc->twe_parent_dmat)) { | |
| 250 | twe_printf(sc, "can't allocate parent DMA tag\n"); | |
| 251 | twe_free(sc); | |
| 252 | return(ENOMEM); | |
| 253 | } | |
| 254 | ||
| 255 | /* | |
| 256 | * Allocate and connect our interrupt. | |
| 257 | */ | |
| 258 | rid = 0; | |
| 259 | if ((sc->twe_irq = bus_alloc_resource(sc->twe_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { | |
| 260 | twe_printf(sc, "can't allocate interrupt\n"); | |
| 261 | twe_free(sc); | |
| 262 | return(ENXIO); | |
| 263 | } | |
| 8b3ec75a | 264 | if (bus_setup_intr(sc->twe_dev, sc->twe_irq, 0, |
| ee61f228 | 265 | twe_pci_intr, sc, &sc->twe_intr, NULL)) { |
| 984263bc MD |
266 | twe_printf(sc, "can't set up interrupt\n"); |
| 267 | twe_free(sc); | |
| 268 | return(ENXIO); | |
| 269 | } | |
| 270 | ||
| 271 | /* | |
| 272 | * Create DMA tag for mapping objects into controller-addressable space. | |
| 273 | */ | |
| 274 | if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */ | |
| 275 | 1, 0, /* alignment, boundary */ | |
| 276 | BUS_SPACE_MAXADDR, /* lowaddr */ | |
| 277 | BUS_SPACE_MAXADDR, /* highaddr */ | |
| 278 | NULL, NULL, /* filter, filterarg */ | |
| 279 | MAXBSIZE, TWE_MAX_SGL_LENGTH,/* maxsize, nsegments */ | |
| 280 | BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ | |
| 281 | 0, /* flags */ | |
| 282 | &sc->twe_buffer_dmat)) { | |
| 283 | twe_printf(sc, "can't allocate data buffer DMA tag\n"); | |
| 284 | twe_free(sc); | |
| 285 | return(ENOMEM); | |
| 286 | } | |
| 287 | ||
| 288 | /* | |
| 289 | * Initialise the controller and driver core. | |
| 290 | */ | |
| a062d8a7 HP |
291 | if ((error = twe_setup(sc))) { |
| 292 | twe_free(sc); | |
| 984263bc | 293 | return(error); |
| a062d8a7 | 294 | } |
| 984263bc MD |
295 | |
| 296 | /* | |
| 297 | * Print some information about the controller and configuration. | |
| 298 | */ | |
| 299 | twe_describe_controller(sc); | |
| 300 | ||
| 301 | /* | |
| 302 | * Create the control device. | |
| 303 | */ | |
| fef8985e | 304 | sc->twe_dev_t = make_dev(&twe_ops, device_get_unit(sc->twe_dev), |
| 3e82b46c MD |
305 | UID_ROOT, GID_OPERATOR, |
| 306 | S_IRUSR | S_IWUSR, "twe%d", | |
| 307 | device_get_unit(sc->twe_dev)); | |
| a062d8a7 | 308 | sc->twe_dev_t->si_drv1 = sc; |
| 3e82b46c | 309 | |
| 984263bc | 310 | /* |
| 3e82b46c MD |
311 | * Schedule ourselves to bring the controller up once interrupts are |
| 312 | * available. This isn't strictly necessary, since we disable | |
| 313 | * interrupts while probing the controller, but it is more in keeping | |
| 314 | * with common practice for other disk devices. | |
| 984263bc MD |
315 | */ |
| 316 | sc->twe_ich.ich_func = twe_intrhook; | |
| 317 | sc->twe_ich.ich_arg = sc; | |
| 318 | if (config_intrhook_establish(&sc->twe_ich) != 0) { | |
| 319 | twe_printf(sc, "can't establish configuration hook\n"); | |
| 320 | twe_free(sc); | |
| 321 | return(ENXIO); | |
| 322 | } | |
| 323 | ||
| 324 | return(0); | |
| 325 | } | |
| 326 | ||
| 327 | /******************************************************************************** | |
| 328 | * Free all of the resources associated with (sc). | |
| 329 | * | |
| 330 | * Should not be called if the controller is active. | |
| 331 | */ | |
| 332 | static void | |
| 333 | twe_free(struct twe_softc *sc) | |
| 334 | { | |
| 335 | struct twe_request *tr; | |
| 336 | ||
| 337 | debug_called(4); | |
| 338 | ||
| 339 | /* throw away any command buffers */ | |
| 340 | while ((tr = twe_dequeue_free(sc)) != NULL) | |
| 341 | twe_free_request(tr); | |
| 342 | ||
| 343 | /* destroy the data-transfer DMA tag */ | |
| 344 | if (sc->twe_buffer_dmat) | |
| 345 | bus_dma_tag_destroy(sc->twe_buffer_dmat); | |
| 346 | ||
| 347 | /* disconnect the interrupt handler */ | |
| 348 | if (sc->twe_intr) | |
| 349 | bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr); | |
| 350 | if (sc->twe_irq != NULL) | |
| 351 | bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq); | |
| 352 | ||
| 353 | /* destroy the parent DMA tag */ | |
| 354 | if (sc->twe_parent_dmat) | |
| 355 | bus_dma_tag_destroy(sc->twe_parent_dmat); | |
| 356 | ||
| 357 | /* release the register window mapping */ | |
| 358 | if (sc->twe_io != NULL) | |
| 359 | bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io); | |
| 360 | ||
| cd29885a | 361 | dev_ops_remove_minor(&twe_ops, device_get_unit(sc->twe_dev)); |
| a062d8a7 | 362 | /* destroy control device */ |
| b13267a5 | 363 | if (sc->twe_dev_t != (cdev_t)NULL) |
| a062d8a7 | 364 | destroy_dev(sc->twe_dev_t); |
| 0a62b1be DR |
365 | |
| 366 | sysctl_ctx_free(&sc->sysctl_ctx); | |
| 984263bc MD |
367 | } |
| 368 | ||
| 369 | /******************************************************************************** | |
| 370 | * Disconnect from the controller completely, in preparation for unload. | |
| 371 | */ | |
| 372 | static int | |
| 373 | twe_detach(device_t dev) | |
| 374 | { | |
| 375 | struct twe_softc *sc = device_get_softc(dev); | |
| 5eb77fd5 | 376 | int error; |
| 984263bc MD |
377 | |
| 378 | debug_called(4); | |
| 379 | ||
| 380 | error = EBUSY; | |
| 5eb77fd5 | 381 | crit_enter(); |
| 984263bc MD |
382 | if (sc->twe_state & TWE_STATE_OPEN) |
| 383 | goto out; | |
| 384 | ||
| 385 | /* | |
| 386 | * Shut the controller down. | |
| 387 | */ | |
| a062d8a7 HP |
388 | if ((error = twe_shutdown(dev))) |
| 389 | goto out; | |
| 984263bc MD |
390 | |
| 391 | twe_free(sc); | |
| 392 | ||
| 393 | error = 0; | |
| 394 | out: | |
| 5eb77fd5 | 395 | crit_exit(); |
| 984263bc MD |
396 | return(error); |
| 397 | } | |
| 398 | ||
| 399 | /******************************************************************************** | |
| 400 | * Bring the controller down to a dormant state and detach all child devices. | |
| 401 | * | |
| 402 | * Note that we can assume that the bioq on the controller is empty, as we won't | |
| 403 | * allow shutdown if any device is open. | |
| 404 | */ | |
| a062d8a7 | 405 | static int |
| 984263bc MD |
406 | twe_shutdown(device_t dev) |
| 407 | { | |
| 408 | struct twe_softc *sc = device_get_softc(dev); | |
| a062d8a7 | 409 | int i, error = 0; |
| 984263bc MD |
410 | |
| 411 | debug_called(4); | |
| 412 | ||
| 5eb77fd5 | 413 | crit_enter(); |
| 984263bc MD |
414 | |
| 415 | /* | |
| 416 | * Delete all our child devices. | |
| 417 | */ | |
| 418 | for (i = 0; i < TWE_MAX_UNITS; i++) { | |
| a062d8a7 HP |
419 | if (sc->twe_drive[i].td_disk != 0) |
| 420 | if ((error = twe_detach_drive(sc, i)) != 0) | |
| 421 | goto out; | |
| 984263bc MD |
422 | } |
| 423 | ||
| 424 | /* | |
| 425 | * Bring the controller down. | |
| 426 | */ | |
| 427 | twe_deinit(sc); | |
| 428 | ||
| a062d8a7 | 429 | out: |
| 5eb77fd5 | 430 | crit_exit(); |
| a062d8a7 | 431 | return(error); |
| 984263bc MD |
432 | } |
| 433 | ||
| 434 | /******************************************************************************** | |
| 435 | * Bring the controller to a quiescent state, ready for system suspend. | |
| 436 | */ | |
| 437 | static int | |
| 438 | twe_suspend(device_t dev) | |
| 439 | { | |
| 440 | struct twe_softc *sc = device_get_softc(dev); | |
| 984263bc MD |
441 | |
| 442 | debug_called(4); | |
| 443 | ||
| 5eb77fd5 | 444 | crit_enter(); |
| 984263bc MD |
445 | sc->twe_state |= TWE_STATE_SUSPEND; |
| 446 | ||
| 447 | twe_disable_interrupts(sc); | |
| 5eb77fd5 | 448 | crit_exit(); |
| 984263bc MD |
449 | |
| 450 | return(0); | |
| 451 | } | |
| 452 | ||
| 453 | /******************************************************************************** | |
| 454 | * Bring the controller back to a state ready for operation. | |
| 455 | */ | |
| 456 | static int | |
| 457 | twe_resume(device_t dev) | |
| 458 | { | |
| 459 | struct twe_softc *sc = device_get_softc(dev); | |
| 460 | ||
| 461 | debug_called(4); | |
| 462 | ||
| 463 | sc->twe_state &= ~TWE_STATE_SUSPEND; | |
| 464 | twe_enable_interrupts(sc); | |
| 465 | ||
| 466 | return(0); | |
| 467 | } | |
| 468 | ||
| 469 | /******************************************************************************* | |
| 470 | * Take an interrupt, or be poked by other code to look for interrupt-worthy | |
| 471 | * status. | |
| 472 | */ | |
| 473 | static void | |
| 474 | twe_pci_intr(void *arg) | |
| 475 | { | |
| 476 | twe_intr((struct twe_softc *)arg); | |
| 477 | } | |
| 478 | ||
| 479 | /******************************************************************************** | |
| 480 | * Delayed-startup hook | |
| 481 | */ | |
| 482 | static void | |
| 483 | twe_intrhook(void *arg) | |
| 484 | { | |
| 485 | struct twe_softc *sc = (struct twe_softc *)arg; | |
| 486 | ||
| 487 | /* pull ourselves off the intrhook chain */ | |
| 488 | config_intrhook_disestablish(&sc->twe_ich); | |
| 489 | ||
| 490 | /* call core startup routine */ | |
| 491 | twe_init(sc); | |
| 492 | } | |
| 493 | ||
| 494 | /******************************************************************************** | |
| 495 | * Given a detected drive, attach it to the bio interface. | |
| 496 | * | |
| 0a62b1be | 497 | * This is called from twe_add_unit. |
| 984263bc | 498 | */ |
| a062d8a7 | 499 | int |
| 984263bc MD |
500 | twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr) |
| 501 | { | |
| 502 | char buf[80]; | |
| a062d8a7 | 503 | int error = 0; |
| 984263bc MD |
504 | |
| 505 | dr->td_disk = device_add_child(sc->twe_dev, NULL, -1); | |
| 506 | if (dr->td_disk == NULL) { | |
| a062d8a7 HP |
507 | twe_printf(sc, "Cannot add unit\n"); |
| 508 | return (EIO); | |
| 984263bc MD |
509 | } |
| 510 | device_set_ivars(dr->td_disk, dr); | |
| 511 | ||
| 512 | /* | |
| 513 | * XXX It would make sense to test the online/initialising bits, but they seem to be | |
| 514 | * always set... | |
| 515 | */ | |
| f8c7a42d | 516 | ksprintf(buf, "Unit %d, %s, %s", |
| a062d8a7 | 517 | dr->td_twe_unit, |
| 0a62b1be | 518 | twe_describe_code(twe_table_unittype, dr->td_type), |
| 984263bc MD |
519 | twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK)); |
| 520 | device_set_desc_copy(dr->td_disk, buf); | |
| 521 | ||
| a062d8a7 HP |
522 | if ((error = bus_generic_attach(sc->twe_dev)) != 0) { |
| 523 | twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error); | |
| 524 | error = EIO; | |
| 525 | } | |
| 526 | return (error); | |
| 984263bc MD |
527 | } |
| 528 | ||
| 529 | /******************************************************************************** | |
| 0a62b1be DR |
530 | * Detach the specified unit if it exsists |
| 531 | * | |
| 532 | * This is called from twe_del_unit. | |
| 533 | */ | |
| a062d8a7 | 534 | int |
| 0a62b1be DR |
535 | twe_detach_drive(struct twe_softc *sc, int unit) |
| 536 | { | |
| a062d8a7 | 537 | int error = 0; |
| 0a62b1be | 538 | |
| a062d8a7 HP |
539 | if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk))) { |
| 540 | twe_printf(sc, "Cannot delete unit. error = %d\n", error); | |
| 541 | return (error); | |
| 0a62b1be | 542 | } |
| a062d8a7 HP |
543 | bzero(&sc->twe_drive[unit], sizeof(sc->twe_drive[unit])); |
| 544 | return (error); | |
| 0a62b1be DR |
545 | } |
| 546 | ||
| 547 | /******************************************************************************** | |
| 984263bc MD |
548 | * Clear a PCI parity error. |
| 549 | */ | |
| 550 | void | |
| 551 | twe_clear_pci_parity_error(struct twe_softc *sc) | |
| 552 | { | |
| 553 | TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PARITY_ERROR); | |
| 554 | pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PARITY_ERROR, 2); | |
| 555 | } | |
| 556 | ||
| 557 | /******************************************************************************** | |
| 558 | * Clear a PCI abort. | |
| 559 | */ | |
| 560 | void | |
| 561 | twe_clear_pci_abort(struct twe_softc *sc) | |
| 562 | { | |
| 563 | TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PCI_ABORT); | |
| 564 | pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PCI_ABORT, 2); | |
| 565 | } | |
| 566 | ||
| 567 | /******************************************************************************** | |
| 568 | ******************************************************************************** | |
| 569 | Disk device | |
| 570 | ******************************************************************************** | |
| 571 | ********************************************************************************/ | |
| 572 | ||
| 573 | /* | |
| 984263bc MD |
574 | * Disk device bus interface |
| 575 | */ | |
| 576 | static int twed_probe(device_t dev); | |
| 577 | static int twed_attach(device_t dev); | |
| 578 | static int twed_detach(device_t dev); | |
| 579 | ||
| 580 | static device_method_t twed_methods[] = { | |
| 581 | DEVMETHOD(device_probe, twed_probe), | |
| 582 | DEVMETHOD(device_attach, twed_attach), | |
| 583 | DEVMETHOD(device_detach, twed_detach), | |
| 584 | { 0, 0 } | |
| 585 | }; | |
| 586 | ||
| 587 | static driver_t twed_driver = { | |
| 588 | "twed", | |
| 589 | twed_methods, | |
| 590 | sizeof(struct twed_softc) | |
| 591 | }; | |
| 592 | ||
| 593 | static devclass_t twed_devclass; | |
| 594 | #ifdef TWE_OVERRIDE | |
| 595 | DRIVER_MODULE(Xtwed, Xtwe, twed_driver, twed_devclass, 0, 0); | |
| 596 | #else | |
| 597 | DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0); | |
| 598 | #endif | |
| 599 | ||
| 600 | /* | |
| 601 | * Disk device control interface. | |
| 602 | */ | |
| 603 | static d_open_t twed_open; | |
| 604 | static d_close_t twed_close; | |
| 605 | static d_strategy_t twed_strategy; | |
| 606 | static d_dump_t twed_dump; | |
| 607 | ||
| fef8985e MD |
608 | static struct dev_ops twed_ops = { |
| 609 | { "twed", TWED_CDEV_MAJOR, D_DISK }, | |
| 610 | .d_open = twed_open, | |
| 611 | .d_close = twed_close, | |
| 612 | .d_read = physread, | |
| 613 | .d_write = physwrite, | |
| 614 | .d_strategy = twed_strategy, | |
| 615 | .d_dump = twed_dump, | |
| 984263bc MD |
616 | }; |
| 617 | ||
| a062d8a7 HP |
618 | #ifdef FREEBSD_4 |
| 619 | static int disks_registered = 0; | |
| 620 | #endif | |
| 0a62b1be | 621 | |
| 984263bc MD |
622 | /******************************************************************************** |
| 623 | * Handle open from generic layer. | |
| 624 | * | |
| 625 | * Note that this is typically only called by the diskslice code, and not | |
| 626 | * for opens on subdevices (eg. slices, partitions). | |
| 627 | */ | |
| 628 | static int | |
| fef8985e | 629 | twed_open(struct dev_open_args *ap) |
| 984263bc | 630 | { |
| b13267a5 | 631 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc | 632 | struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; |
| 984263bc MD |
633 | |
| 634 | debug_called(4); | |
| 635 | ||
| 636 | if (sc == NULL) | |
| 637 | return (ENXIO); | |
| 638 | ||
| 639 | /* check that the controller is up and running */ | |
| 640 | if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN) | |
| 641 | return(ENXIO); | |
| cd29885a | 642 | #if 0 |
| a688b15c MD |
643 | /* build disk info */ |
| 644 | bzero(&info, sizeof(info)); | |
| 645 | info.d_media_blksize = TWE_BLOCK_SIZE; /* mandatory */ | |
| 646 | info.d_media_blocks = sc->twed_drive->td_size; | |
| 647 | ||
| 648 | info.d_type = DTYPE_ESDI; /* optional */ | |
| 649 | info.d_secpertrack = sc->twed_drive->td_sectors; | |
| 650 | info.d_nheads = sc->twed_drive->td_heads; | |
| 651 | info.d_ncylinders = sc->twed_drive->td_cylinders; | |
| 652 | info.d_secpercyl = sc->twed_drive->td_sectors * sc->twed_drive->td_heads; | |
| 653 | ||
| 654 | disk_setdiskinfo(&sc->twed_disk, &info); | |
| cd29885a | 655 | #endif |
| 984263bc MD |
656 | sc->twed_flags |= TWED_OPEN; |
| 657 | return (0); | |
| 658 | } | |
| 659 | ||
| 660 | /******************************************************************************** | |
| 661 | * Handle last close of the disk device. | |
| 662 | */ | |
| 663 | static int | |
| fef8985e | 664 | twed_close(struct dev_close_args *ap) |
| 984263bc | 665 | { |
| b13267a5 | 666 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
667 | struct twed_softc *sc = (struct twed_softc *)dev->si_drv1; |
| 668 | ||
| 669 | debug_called(4); | |
| 670 | ||
| 671 | if (sc == NULL) | |
| 672 | return (ENXIO); | |
| 673 | ||
| 674 | sc->twed_flags &= ~TWED_OPEN; | |
| 675 | return (0); | |
| 676 | } | |
| 677 | ||
| 678 | /******************************************************************************** | |
| 679 | * Handle an I/O request. | |
| 680 | */ | |
| fef8985e MD |
681 | static int |
| 682 | twed_strategy(struct dev_strategy_args *ap) | |
| 984263bc | 683 | { |
| b13267a5 | 684 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 685 | struct bio *bio = ap->a_bio; |
| 81b5c339 MD |
686 | struct twed_softc *sc = dev->si_drv1; |
| 687 | struct buf *bp = bio->bio_buf; | |
| 688 | ||
| 689 | bio->bio_driver_info = sc; | |
| 984263bc MD |
690 | |
| 691 | debug_called(4); | |
| 692 | ||
| 693 | TWED_BIO_IN; | |
| 694 | ||
| 695 | /* bogus disk? */ | |
| a062d8a7 | 696 | if ((sc == NULL) || (!sc->twed_drive->td_disk)) { |
| 81b5c339 MD |
697 | bp->b_error = EINVAL; |
| 698 | bp->b_flags |= B_ERROR; | |
| e3869ec7 | 699 | kprintf("twe: bio for invalid disk!\n"); |
| 81b5c339 | 700 | biodone(bio); |
| 984263bc | 701 | TWED_BIO_OUT; |
| fef8985e | 702 | return(0); |
| 984263bc MD |
703 | } |
| 704 | ||
| 705 | /* perform accounting */ | |
| 81b5c339 | 706 | devstat_start_transaction(&sc->twed_stats); |
| 984263bc MD |
707 | |
| 708 | /* queue the bio on the controller */ | |
| 81b5c339 | 709 | twe_enqueue_bio(sc->twed_controller, bio); |
| 984263bc MD |
710 | |
| 711 | /* poke the controller to start I/O */ | |
| 712 | twe_startio(sc->twed_controller); | |
| fef8985e | 713 | return(0); |
| 984263bc MD |
714 | } |
| 715 | ||
| 716 | /******************************************************************************** | |
| 717 | * System crashdump support | |
| 718 | */ | |
| a062d8a7 | 719 | static int |
| fef8985e | 720 | twed_dump(struct dev_dump_args *ap) |
| 984263bc | 721 | { |
| b13267a5 | 722 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
723 | struct twed_softc *twed_sc = (struct twed_softc *)dev->si_drv1; |
| 724 | struct twe_softc *twe_sc = (struct twe_softc *)twed_sc->twed_controller; | |
| 0a62b1be | 725 | vm_paddr_t addr = 0; |
| 984263bc MD |
726 | long blkcnt; |
| 727 | int dumppages = MAXDUMPPGS; | |
| 728 | int error; | |
| 729 | int i; | |
| 730 | ||
| 984263bc MD |
731 | if (!twed_sc || !twe_sc) |
| 732 | return(ENXIO); | |
| 733 | ||
| fef8985e | 734 | blkcnt = howmany(PAGE_SIZE, ap->a_secsize); |
| 984263bc | 735 | |
| fef8985e | 736 | while (ap->a_count > 0) { |
| 984263bc MD |
737 | caddr_t va = NULL; |
| 738 | ||
| fef8985e MD |
739 | if ((ap->a_count / blkcnt) < dumppages) |
| 740 | dumppages = ap->a_count / blkcnt; | |
| 984263bc MD |
741 | |
| 742 | for (i = 0; i < dumppages; ++i) { | |
| 0a62b1be | 743 | vm_paddr_t a = addr + (i * PAGE_SIZE); |
| 984263bc MD |
744 | if (is_physical_memory(a)) |
| 745 | va = pmap_kenter_temporary(trunc_page(a), i); | |
| 746 | else | |
| 747 | va = pmap_kenter_temporary(trunc_page(0), i); | |
| 748 | } | |
| 749 | ||
| fef8985e | 750 | if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, ap->a_blkno, va, |
| 984263bc MD |
751 | (PAGE_SIZE * dumppages) / TWE_BLOCK_SIZE)) != 0) |
| 752 | return(error); | |
| 753 | ||
| 754 | ||
| fef8985e | 755 | if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0) |
| 984263bc MD |
756 | return(EINTR); |
| 757 | ||
| fef8985e MD |
758 | ap->a_blkno += blkcnt * dumppages; |
| 759 | ap->a_count -= blkcnt * dumppages; | |
| 984263bc MD |
760 | addr += PAGE_SIZE * dumppages; |
| 761 | } | |
| 762 | return(0); | |
| 763 | } | |
| 764 | ||
| 765 | /******************************************************************************** | |
| 766 | * Handle completion of an I/O request. | |
| 767 | */ | |
| 768 | void | |
| 81b5c339 | 769 | twed_intr(struct bio *bio) |
| 984263bc | 770 | { |
| 81b5c339 MD |
771 | struct buf *bp = bio->bio_buf; |
| 772 | struct twed_softc *sc = bio->bio_driver_info; | |
| 984263bc MD |
773 | debug_called(4); |
| 774 | ||
| 775 | /* if no error, transfer completed */ | |
| 24aa53aa | 776 | if ((bp->b_flags & B_ERROR) == 0) |
| 81b5c339 MD |
777 | bp->b_resid = 0; |
| 778 | devstat_end_transaction_buf(&sc->twed_stats, bp); | |
| 779 | biodone(bio); | |
| 984263bc MD |
780 | TWED_BIO_OUT; |
| 781 | } | |
| 782 | ||
| 783 | /******************************************************************************** | |
| 784 | * Default probe stub. | |
| 785 | */ | |
| 786 | static int | |
| 787 | twed_probe(device_t dev) | |
| 788 | { | |
| 789 | return (0); | |
| 790 | } | |
| 791 | ||
| 792 | /******************************************************************************** | |
| 793 | * Attach a unit to the controller. | |
| 794 | */ | |
| 795 | static int | |
| 796 | twed_attach(device_t dev) | |
| 797 | { | |
| 798 | struct twed_softc *sc; | |
| cd29885a | 799 | struct disk_info info; |
| 984263bc | 800 | device_t parent; |
| b13267a5 | 801 | cdev_t dsk; |
| 984263bc MD |
802 | |
| 803 | debug_called(4); | |
| 804 | ||
| 805 | /* initialise our softc */ | |
| 806 | sc = device_get_softc(dev); | |
| 807 | parent = device_get_parent(dev); | |
| 808 | sc->twed_controller = (struct twe_softc *)device_get_softc(parent); | |
| 809 | sc->twed_drive = device_get_ivars(dev); | |
| a062d8a7 | 810 | sc->twed_drive->td_sys_unit = device_get_unit(dev); |
| 984263bc MD |
811 | sc->twed_dev = dev; |
| 812 | ||
| 813 | /* report the drive */ | |
| 814 | twed_printf(sc, "%uMB (%u sectors)\n", | |
| 815 | sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE), | |
| 816 | sc->twed_drive->td_size); | |
| 817 | ||
| a062d8a7 HP |
818 | devstat_add_entry(&sc->twed_stats, "twed", sc->twed_drive->td_sys_unit, |
| 819 | TWE_BLOCK_SIZE, | |
| 820 | DEVSTAT_NO_ORDERED_TAGS, | |
| 821 | DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, | |
| 822 | DEVSTAT_PRIORITY_ARRAY); | |
| 984263bc MD |
823 | |
| 824 | /* attach a generic disk device to ourselves */ | |
| a688b15c | 825 | dsk = disk_create(sc->twed_drive->td_sys_unit, &sc->twed_disk, &twed_ops); |
| 984263bc | 826 | dsk->si_drv1 = sc; |
| a062d8a7 | 827 | /* dsk->si_drv2 = sc->twed_drive;*/ |
| 984263bc | 828 | sc->twed_dev_t = dsk; |
| a062d8a7 HP |
829 | #ifdef FREEBSD_4 |
| 830 | disks_registered++; | |
| 831 | #endif | |
| 984263bc MD |
832 | |
| 833 | /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */ | |
| 834 | dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE; | |
| 835 | ||
| cd29885a MD |
836 | /* |
| 837 | * Set disk info, as it appears that all needed data is available already. | |
| 838 | * Setting the disk info will also cause the probing to start. | |
| 839 | */ | |
| 840 | bzero(&info, sizeof(info)); | |
| 841 | info.d_media_blksize = TWE_BLOCK_SIZE; /* mandatory */ | |
| 842 | info.d_media_blocks = sc->twed_drive->td_size; | |
| 843 | ||
| 844 | info.d_type = DTYPE_ESDI; /* optional */ | |
| 845 | info.d_secpertrack = sc->twed_drive->td_sectors; | |
| 846 | info.d_nheads = sc->twed_drive->td_heads; | |
| 847 | info.d_ncylinders = sc->twed_drive->td_cylinders; | |
| 848 | info.d_secpercyl = sc->twed_drive->td_sectors * sc->twed_drive->td_heads; | |
| 849 | ||
| 850 | disk_setdiskinfo(&sc->twed_disk, &info); | |
| 851 | ||
| 984263bc MD |
852 | return (0); |
| 853 | } | |
| 854 | ||
| 855 | /******************************************************************************** | |
| 856 | * Disconnect ourselves from the system. | |
| 857 | */ | |
| 858 | static int | |
| 859 | twed_detach(device_t dev) | |
| 860 | { | |
| 861 | struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev); | |
| 862 | ||
| 863 | debug_called(4); | |
| 864 | ||
| 865 | if (sc->twed_flags & TWED_OPEN) | |
| 866 | return(EBUSY); | |
| 867 | ||
| 868 | devstat_remove_entry(&sc->twed_stats); | |
| 335dda38 | 869 | disk_destroy(&sc->twed_disk); |
| a062d8a7 | 870 | #ifdef FREEBSD_4 |
| e3869ec7 | 871 | kprintf("Disks registered: %d\n", disks_registered); |
| a062d8a7 HP |
872 | #if 0 |
| 873 | if (--disks_registered == 0) | |
| cd29885a | 874 | dev_ops_remove_all(&tweddisk_ops); |
| a062d8a7 HP |
875 | #endif |
| 876 | #endif | |
| 984263bc MD |
877 | |
| 878 | return(0); | |
| 879 | } | |
| 880 | ||
| 881 | /******************************************************************************** | |
| 882 | ******************************************************************************** | |
| 883 | Misc | |
| 884 | ******************************************************************************** | |
| 885 | ********************************************************************************/ | |
| 886 | ||
| a062d8a7 | 887 | MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands"); |
| 984263bc | 888 | /******************************************************************************** |
| a062d8a7 | 889 | * Allocate a command buffer |
| 984263bc | 890 | */ |
| 984263bc MD |
891 | struct twe_request * |
| 892 | twe_allocate_request(struct twe_softc *sc) | |
| 893 | { | |
| 894 | struct twe_request *tr; | |
| a062d8a7 | 895 | int aligned_size; |
| 984263bc | 896 | |
| c4f9937c MD |
897 | /* |
| 898 | * TWE requires requests to be 512-byte aligned. Depend on malloc() | |
| 899 | * guarenteeing alignment for power-of-2 requests. Note that the old | |
| 900 | * (FreeBSD-4.x) malloc code aligned all requests, but the new slab | |
| 901 | * allocator only guarentees same-size alignment for power-of-2 requests. | |
| 902 | */ | |
| 903 | aligned_size = (sizeof(struct twe_request) + TWE_ALIGNMASK) & | |
| a062d8a7 | 904 | ~TWE_ALIGNMASK; |
| efda3bd0 | 905 | tr = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT|M_ZERO); |
| 984263bc MD |
906 | tr->tr_sc = sc; |
| 907 | if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_cmdmap)) { | |
| 908 | twe_free_request(tr); | |
| 909 | return(NULL); | |
| 910 | } | |
| a062d8a7 HP |
911 | bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command, |
| 912 | sizeof(tr->tr_command), twe_setup_request_dmamap, tr, 0); | |
| 984263bc MD |
913 | if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) { |
| 914 | bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); | |
| 915 | twe_free_request(tr); | |
| 916 | return(NULL); | |
| 917 | } | |
| 918 | return(tr); | |
| 919 | } | |
| 920 | ||
| 921 | /******************************************************************************** | |
| 922 | * Permanently discard a command buffer. | |
| 923 | */ | |
| a062d8a7 | 924 | static void |
| 984263bc MD |
925 | twe_free_request(struct twe_request *tr) |
| 926 | { | |
| 927 | struct twe_softc *sc = tr->tr_sc; | |
| 928 | ||
| 929 | debug_called(4); | |
| 930 | ||
| a062d8a7 | 931 | bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap); |
| 984263bc MD |
932 | bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap); |
| 933 | bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap); | |
| efda3bd0 | 934 | kfree(tr, TWE_MALLOC_CLASS); |
| 984263bc MD |
935 | } |
| 936 | ||
| 937 | /******************************************************************************** | |
| 938 | * Map/unmap (tr)'s command and data in the controller's addressable space. | |
| 939 | * | |
| 940 | * These routines ensure that the data which the controller is going to try to | |
| 941 | * access is actually visible to the controller, in a machine-independant | |
| 942 | * fashion. Due to a hardware limitation, I/O buffers must be 512-byte aligned | |
| 943 | * and we take care of that here as well. | |
| 944 | */ | |
| 945 | static void | |
| 0a62b1be DR |
946 | twe_fillin_sgl(TWE_SG_Entry *sgl, bus_dma_segment_t *segs, int nsegments, int max_sgl) |
| 947 | { | |
| 948 | int i; | |
| 949 | ||
| 950 | for (i = 0; i < nsegments; i++) { | |
| 951 | sgl[i].address = segs[i].ds_addr; | |
| 952 | sgl[i].length = segs[i].ds_len; | |
| 953 | } | |
| 954 | for (; i < max_sgl; i++) { /* XXX necessary? */ | |
| 955 | sgl[i].address = 0; | |
| 956 | sgl[i].length = 0; | |
| 957 | } | |
| 958 | } | |
| 959 | ||
| 960 | static void | |
| 984263bc MD |
961 | twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) |
| 962 | { | |
| 963 | struct twe_request *tr = (struct twe_request *)arg; | |
| 964 | TWE_Command *cmd = &tr->tr_command; | |
| 984263bc MD |
965 | |
| 966 | debug_called(4); | |
| 967 | ||
| a062d8a7 HP |
968 | if (tr->tr_flags & TWE_CMD_MAPPED) |
| 969 | panic("already mapped command"); | |
| 970 | ||
| 971 | tr->tr_flags |= TWE_CMD_MAPPED; | |
| 972 | ||
| 973 | if (tr->tr_flags & TWE_CMD_IN_PROGRESS) | |
| 974 | tr->tr_sc->twe_state &= ~TWE_STATE_FRZN; | |
| 984263bc MD |
975 | /* save base of first segment in command (applicable if there only one segment) */ |
| 976 | tr->tr_dataphys = segs[0].ds_addr; | |
| 977 | ||
| 978 | /* correct command size for s/g list size */ | |
| 979 | tr->tr_command.generic.size += 2 * nsegments; | |
| 980 | ||
| 981 | /* | |
| 982 | * Due to the fact that parameter and I/O commands have the scatter/gather list in | |
| 983 | * different places, we need to determine which sort of command this actually is | |
| 984 | * before we can populate it correctly. | |
| 985 | */ | |
| 986 | switch(cmd->generic.opcode) { | |
| 987 | case TWE_OP_GET_PARAM: | |
| 988 | case TWE_OP_SET_PARAM: | |
| 989 | cmd->generic.sgl_offset = 2; | |
| 0a62b1be | 990 | twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); |
| 984263bc MD |
991 | break; |
| 992 | case TWE_OP_READ: | |
| 993 | case TWE_OP_WRITE: | |
| 994 | cmd->generic.sgl_offset = 3; | |
| 0a62b1be | 995 | twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); |
| 984263bc | 996 | break; |
| 0a62b1be DR |
997 | case TWE_OP_ATA_PASSTHROUGH: |
| 998 | cmd->generic.sgl_offset = 5; | |
| 999 | twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH); | |
| 6b08710e | 1000 | break; |
| 0a62b1be DR |
1001 | default: |
| 1002 | /* | |
| 1003 | * Fall back to what the linux driver does. | |
| 1004 | * Do this because the API may send an opcode | |
| 1005 | * the driver knows nothing about and this will | |
| 1006 | * at least stop PCIABRT's from hosing us. | |
| 1007 | */ | |
| 1008 | switch (cmd->generic.sgl_offset) { | |
| 1009 | case 2: | |
| 1010 | twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); | |
| 1011 | break; | |
| 1012 | case 3: | |
| 1013 | twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH); | |
| 1014 | break; | |
| 1015 | case 5: | |
| 1016 | twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH); | |
| 1017 | break; | |
| 1018 | } | |
| 984263bc | 1019 | } |
| a062d8a7 HP |
1020 | if (tr->tr_flags & TWE_CMD_DATAIN) |
| 1021 | bus_dmamap_sync(tr->tr_sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD); | |
| 1022 | if (tr->tr_flags & TWE_CMD_DATAOUT) { | |
| 1023 | /* if we're using an alignment buffer, and we're writing data, copy the real data out */ | |
| 1024 | if (tr->tr_flags & TWE_CMD_ALIGNBUF) | |
| 1025 | bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length); | |
| 1026 | bus_dmamap_sync(tr->tr_sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE); | |
| 1027 | } | |
| 1028 | if (twe_start(tr) == EBUSY) { | |
| 1029 | tr->tr_sc->twe_state |= TWE_STATE_CTLR_BUSY; | |
| 1030 | twe_requeue_ready(tr); | |
| 1031 | } | |
| 984263bc MD |
1032 | } |
| 1033 | ||
| 1034 | static void | |
| 1035 | twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) | |
| 1036 | { | |
| 1037 | struct twe_request *tr = (struct twe_request *)arg; | |
| 1038 | ||
| 1039 | debug_called(4); | |
| 1040 | ||
| 1041 | /* command can't cross a page boundary */ | |
| 1042 | tr->tr_cmdphys = segs[0].ds_addr; | |
| 1043 | } | |
| 1044 | ||
| a062d8a7 | 1045 | int |
| 984263bc MD |
1046 | twe_map_request(struct twe_request *tr) |
| 1047 | { | |
| 1048 | struct twe_softc *sc = tr->tr_sc; | |
| a062d8a7 | 1049 | int error = 0; |
| 984263bc MD |
1050 | |
| 1051 | debug_called(4); | |
| 1052 | ||
| a062d8a7 HP |
1053 | if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) { |
| 1054 | twe_requeue_ready(tr); | |
| 1055 | return (EBUSY); | |
| 1056 | } | |
| 984263bc MD |
1057 | |
| 1058 | /* | |
| 1059 | * Map the command into bus space. | |
| 1060 | */ | |
| 984263bc MD |
1061 | bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_PREWRITE); |
| 1062 | ||
| 1063 | /* | |
| 1064 | * If the command involves data, map that too. | |
| 1065 | */ | |
| a062d8a7 | 1066 | if ((tr->tr_data != NULL) && ((tr->tr_flags & TWE_CMD_MAPPED) == 0)) { |
| 984263bc MD |
1067 | |
| 1068 | /* | |
| c4f9937c | 1069 | * Data must be 512-byte aligned; allocate a fixup buffer if it's not. |
| a2f0dcc5 MD |
1070 | * |
| 1071 | * DragonFly's malloc only guarentees alignment for requests which | |
| 1072 | * are power-of-2 sized. | |
| 984263bc MD |
1073 | */ |
| 1074 | if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) { | |
| a2f0dcc5 | 1075 | int aligned_size; |
| c4f9937c | 1076 | |
| a062d8a7 | 1077 | tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */ |
| a2f0dcc5 MD |
1078 | aligned_size = TWE_ALIGNMENT; |
| 1079 | while (aligned_size < tr->tr_length) | |
| 1080 | aligned_size <<= 1; | |
| 984263bc | 1081 | tr->tr_flags |= TWE_CMD_ALIGNBUF; |
| efda3bd0 | 1082 | tr->tr_data = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT); |
| a062d8a7 HP |
1083 | if (tr->tr_data == NULL) { |
| 1084 | twe_printf(sc, "%s: malloc failed\n", __func__); | |
| 1085 | tr->tr_data = tr->tr_realdata; /* restore original data pointer */ | |
| 1086 | return(ENOMEM); | |
| 1087 | } | |
| 984263bc MD |
1088 | } |
| 1089 | ||
| 1090 | /* | |
| 1091 | * Map the data buffer into bus space and build the s/g list. | |
| 1092 | */ | |
| a062d8a7 HP |
1093 | if ((error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, |
| 1094 | tr->tr_length, twe_setup_data_dmamap, tr, BUS_DMA_NOWAIT) | |
| 1095 | == EINPROGRESS)) { | |
| 1096 | tr->tr_flags |= TWE_CMD_IN_PROGRESS; | |
| 1097 | sc->twe_state |= TWE_STATE_FRZN; | |
| 1098 | error = 0; | |
| 1099 | } | |
| 1100 | } else { | |
| 1101 | if ((error = twe_start(tr)) == EBUSY) { | |
| 1102 | sc->twe_state |= TWE_STATE_CTLR_BUSY; | |
| 1103 | twe_requeue_ready(tr); | |
| 984263bc MD |
1104 | } |
| 1105 | } | |
| a062d8a7 HP |
1106 | |
| 1107 | return(error); | |
| 984263bc MD |
1108 | } |
| 1109 | ||
| 1110 | void | |
| 1111 | twe_unmap_request(struct twe_request *tr) | |
| 1112 | { | |
| 1113 | struct twe_softc *sc = tr->tr_sc; | |
| 984263bc MD |
1114 | debug_called(4); |
| 1115 | ||
| 1116 | /* | |
| 1117 | * Unmap the command from bus space. | |
| 1118 | */ | |
| 1119 | bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_POSTWRITE); | |
| 984263bc MD |
1120 | |
| 1121 | /* | |
| 1122 | * If the command involved data, unmap that too. | |
| 1123 | */ | |
| 1124 | if (tr->tr_data != NULL) { | |
| 1125 | ||
| 1126 | if (tr->tr_flags & TWE_CMD_DATAIN) { | |
| 1127 | bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTREAD); | |
| 1128 | /* if we're using an alignment buffer, and we're reading data, copy the real data in */ | |
| 1129 | if (tr->tr_flags & TWE_CMD_ALIGNBUF) | |
| 1130 | bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length); | |
| 1131 | } | |
| 1132 | if (tr->tr_flags & TWE_CMD_DATAOUT) | |
| 1133 | bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTWRITE); | |
| 1134 | ||
| 1135 | bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap); | |
| 1136 | } | |
| 1137 | ||
| 1138 | /* free alignment buffer if it was used */ | |
| 1139 | if (tr->tr_flags & TWE_CMD_ALIGNBUF) { | |
| efda3bd0 | 1140 | kfree(tr->tr_data, TWE_MALLOC_CLASS); |
| 984263bc MD |
1141 | tr->tr_data = tr->tr_realdata; /* restore 'real' data pointer */ |
| 1142 | } | |
| 1143 | } | |
| 1144 | ||
| 1145 | #ifdef TWE_DEBUG | |
| a062d8a7 | 1146 | void twe_report(void); |
| 984263bc MD |
1147 | /******************************************************************************** |
| 1148 | * Print current controller status, call from DDB. | |
| 1149 | */ | |
| 1150 | void | |
| 1151 | twe_report(void) | |
| 1152 | { | |
| 1153 | struct twe_softc *sc; | |
| 5eb77fd5 | 1154 | int i; |
| 984263bc | 1155 | |
| 5eb77fd5 | 1156 | crit_enter(); |
| 984263bc MD |
1157 | for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++) |
| 1158 | twe_print_controller(sc); | |
| e3869ec7 | 1159 | kprintf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out); |
| 5eb77fd5 | 1160 | crit_exit(); |
| 984263bc MD |
1161 | } |
| 1162 | #endif |