1 /* $NetBSD: twe.c,v 1.37 2003/06/29 22:30:28 fvdl Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /*- 40 * Copyright (c) 2000 Michael Smith 41 * Copyright (c) 2000 BSDi 42 * All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * from FreeBSD: twe.c,v 1.1 2000/05/24 23:35:23 msmith Exp 66 */ 67 68 /* 69 * Driver for the 3ware Escalade family of RAID controllers. 70 */ 71 72 #include <sys/cdefs.h> 73 __KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.37 2003/06/29 22:30:28 fvdl Exp $"); 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/kernel.h> 78 #include <sys/device.h> 79 #include <sys/queue.h> 80 #include <sys/proc.h> 81 #include <sys/buf.h> 82 #include <sys/endian.h> 83 #include <sys/malloc.h> 84 #include <sys/conf.h> 85 #include <sys/disk.h> 86 87 #include <uvm/uvm_extern.h> 88 89 #include <machine/bswap.h> 90 #include <machine/bus.h> 91 92 #include <dev/pci/pcireg.h> 93 #include <dev/pci/pcivar.h> 94 #include <dev/pci/pcidevs.h> 95 #include <dev/pci/twereg.h> 96 #include <dev/pci/twevar.h> 97 #include <dev/pci/tweio.h> 98 99 #define PCI_CBIO 0x10 100 101 static void twe_aen_handler(struct twe_ccb *, int); 102 static void twe_attach(struct device *, struct device *, void *); 103 static int twe_init_connection(struct twe_softc *); 104 static int twe_intr(void *); 105 static int twe_match(struct device *, struct cfdata *, void *); 106 static int twe_param_get(struct twe_softc *, int, int, size_t, 107 void (*)(struct twe_ccb *, int), void **); 108 static int twe_param_set(struct twe_softc *, int, int, size_t, void *); 109 static void twe_poll(struct twe_softc *); 110 static int twe_print(void *, const char *); 111 static int twe_reset(struct twe_softc *); 112 static int twe_submatch(struct device *, struct cfdata *, void *); 113 static int twe_status_check(struct twe_softc *, u_int); 114 static int twe_status_wait(struct twe_softc *, u_int, int); 115 116 static inline u_int32_t twe_inl(struct twe_softc *, int); 117 static inline void twe_outl(struct twe_softc *, int, u_int32_t); 118 119 dev_type_open(tweopen); 120 dev_type_close(tweclose); 121 dev_type_ioctl(tweioctl); 122 123 const struct cdevsw twe_cdevsw = { 124 tweopen, tweclose, noread, nowrite, tweioctl, 125 nostop, notty, nopoll, nommap, 126 }; 127 128 extern struct cfdriver twe_cd; 129 130 CFATTACH_DECL(twe, sizeof(struct twe_softc), 131 twe_match, twe_attach, NULL, NULL); 132 133 struct { 134 const u_int aen; /* High byte indicates type of message */ 135 const char *desc; 136 } static const twe_aen_names[] = { 137 { 0x0000, "queue empty" }, 138 { 0x0001, "soft reset" }, 139 { 0x0102, "degraded mirror" }, 140 { 0x0003, "controller error" }, 141 { 0x0104, "rebuild fail" }, 142 { 0x0105, "rebuild done" }, 143 { 0x0106, "incompatible unit" }, 144 { 0x0107, "initialisation done" }, 145 { 0x0108, "unclean shutdown detected" }, 146 { 0x0109, "drive timeout" }, 147 { 0x010a, "drive error" }, 148 { 0x010b, "rebuild started" }, 149 { 0x010c, "init started" }, 150 { 0x010d, "logical unit deleted" }, 151 { 0x020f, "SMART threshold exceeded" }, 152 { 0x0015, "table undefined" }, /* XXX: Not in FreeBSD's table */ 153 { 0x0221, "ATA UDMA downgrade" }, 154 { 0x0222, "ATA UDMA upgrade" }, 155 { 0x0222, "ATA UDMA upgrade" }, 156 { 0x0223, "Sector repair occurred" }, 157 { 0x0024, "SBUF integrity check failure" }, 158 { 0x0225, "lost cached write" }, 159 { 0x0226, "drive ECC error detected" }, 160 { 0x0227, "DCB checksum error" }, 161 { 0x0228, "DCB unsupported version" }, 162 { 0x0129, "verify started" }, 163 { 0x012a, "verify failed" }, 164 { 0x012b, "verify complete" }, 165 { 0x022c, "overwrote bad sector during rebuild" }, 166 { 0x022d, "encountered bad sector during rebuild" }, 167 { 0x00ff, "aen queue full" }, 168 }; 169 170 /* 171 * The high byte of the message above determines the format, 172 * currently we know about format 0 (no unit/port specific) 173 * format 1 (unit specific message), and format 2 (port specific message). 174 */ 175 static const char *aenfmt[] = { 176 "", /* No message */ 177 "unit %d: ", /* Unit message */ 178 "port %d: " /* Port message */ 179 }; 180 181 182 static inline u_int32_t 183 twe_inl(struct twe_softc *sc, int off) 184 { 185 186 bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4, 187 BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ); 188 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off)); 189 } 190 191 static inline void 192 twe_outl(struct twe_softc *sc, int off, u_int32_t val) 193 { 194 195 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); 196 bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4, 197 BUS_SPACE_BARRIER_WRITE); 198 } 199 200 /* 201 * Match a supported board. 202 */ 203 static int 204 twe_match(struct device *parent, struct cfdata *cfdata, void *aux) 205 { 206 struct pci_attach_args *pa; 207 208 pa = aux; 209 210 return (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3WARE && 211 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE || 212 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE_ASIC)); 213 } 214 215 /* 216 * Attach a supported board. 217 * 218 * XXX This doesn't fail gracefully. 219 */ 220 static void 221 twe_attach(struct device *parent, struct device *self, void *aux) 222 { 223 struct pci_attach_args *pa; 224 struct twe_softc *sc; 225 pci_chipset_tag_t pc; 226 pci_intr_handle_t ih; 227 pcireg_t csr; 228 const char *intrstr; 229 int size, i, rv, rseg; 230 size_t max_segs, max_xfer; 231 struct twe_param *dtp, *ctp; 232 bus_dma_segment_t seg; 233 struct twe_cmd *tc; 234 struct twe_attach_args twea; 235 struct twe_ccb *ccb; 236 237 sc = (struct twe_softc *)self; 238 pa = aux; 239 pc = pa->pa_pc; 240 sc->sc_dmat = pa->pa_dmat; 241 SIMPLEQ_INIT(&sc->sc_ccb_queue); 242 SLIST_INIT(&sc->sc_ccb_freelist); 243 244 printf(": 3ware Escalade\n"); 245 246 ccb = malloc(sizeof(*ccb) * TWE_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT); 247 if (ccb == NULL) { 248 printf("%s: unable to allocate memory for ccbs\n", 249 sc->sc_dv.dv_xname); 250 return; 251 } 252 253 if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, 254 &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { 255 printf("%s: can't map i/o space\n", sc->sc_dv.dv_xname); 256 return; 257 } 258 259 /* Enable the device. */ 260 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 261 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 262 csr | PCI_COMMAND_MASTER_ENABLE); 263 264 /* Map and establish the interrupt. */ 265 if (pci_intr_map(pa, &ih)) { 266 printf("%s: can't map interrupt\n", sc->sc_dv.dv_xname); 267 return; 268 } 269 intrstr = pci_intr_string(pc, ih); 270 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, twe_intr, sc); 271 if (sc->sc_ih == NULL) { 272 printf("%s: can't establish interrupt", sc->sc_dv.dv_xname); 273 if (intrstr != NULL) 274 printf(" at %s", intrstr); 275 printf("\n"); 276 return; 277 } 278 if (intrstr != NULL) 279 printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr); 280 281 /* 282 * Allocate and initialise the command blocks and CCBs. 283 */ 284 size = sizeof(struct twe_cmd) * TWE_MAX_QUEUECNT; 285 286 if ((rv = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 287 &rseg, BUS_DMA_NOWAIT)) != 0) { 288 printf("%s: unable to allocate commands, rv = %d\n", 289 sc->sc_dv.dv_xname, rv); 290 return; 291 } 292 293 if ((rv = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 294 (caddr_t *)&sc->sc_cmds, 295 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 296 printf("%s: unable to map commands, rv = %d\n", 297 sc->sc_dv.dv_xname, rv); 298 return; 299 } 300 301 if ((rv = bus_dmamap_create(sc->sc_dmat, size, size, 1, 0, 302 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 303 printf("%s: unable to create command DMA map, rv = %d\n", 304 sc->sc_dv.dv_xname, rv); 305 return; 306 } 307 308 if ((rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_cmds, 309 size, NULL, BUS_DMA_NOWAIT)) != 0) { 310 printf("%s: unable to load command DMA map, rv = %d\n", 311 sc->sc_dv.dv_xname, rv); 312 return; 313 } 314 315 sc->sc_cmds_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 316 memset(sc->sc_cmds, 0, size); 317 318 sc->sc_ccbs = ccb; 319 tc = (struct twe_cmd *)sc->sc_cmds; 320 max_segs = twe_get_maxsegs(); 321 max_xfer = twe_get_maxxfer(max_segs); 322 323 for (i = 0; i < TWE_MAX_QUEUECNT; i++, tc++, ccb++) { 324 ccb->ccb_cmd = tc; 325 ccb->ccb_cmdid = i; 326 ccb->ccb_flags = 0; 327 rv = bus_dmamap_create(sc->sc_dmat, max_xfer, 328 max_segs, PAGE_SIZE, 0, 329 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 330 &ccb->ccb_dmamap_xfer); 331 if (rv != 0) { 332 printf("%s: can't create dmamap, rv = %d\n", 333 sc->sc_dv.dv_xname, rv); 334 return; 335 } 336 /* Save one CCB for parameter retrieval. */ 337 if (i != 0) 338 SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb, 339 ccb_chain.slist); 340 } 341 342 /* Wait for the controller to become ready. */ 343 if (twe_status_wait(sc, TWE_STS_MICROCONTROLLER_READY, 6)) { 344 printf("%s: microcontroller not ready\n", sc->sc_dv.dv_xname); 345 return; 346 } 347 348 twe_outl(sc, TWE_REG_CTL, TWE_CTL_DISABLE_INTRS); 349 350 /* Reset the controller. */ 351 if (twe_reset(sc)) { 352 printf("%s: reset failed\n", sc->sc_dv.dv_xname); 353 return; 354 } 355 356 /* Find attached units. */ 357 rv = twe_param_get(sc, TWE_PARAM_UNITSUMMARY, 358 TWE_PARAM_UNITSUMMARY_Status, TWE_MAX_UNITS, NULL, (void *)&dtp); 359 if (rv != 0) { 360 printf("%s: can't detect attached units (%d)\n", 361 sc->sc_dv.dv_xname, rv); 362 return; 363 } 364 365 /* For each detected unit, collect size and store in an array. */ 366 for (i = 0, sc->sc_nunits = 0; i < TWE_MAX_UNITS; i++) { 367 /* Unit present? */ 368 if ((dtp->tp_data[i] & TWE_PARAM_UNITSTATUS_Online) == 0) { 369 sc->sc_dsize[i] = 0; 370 continue; 371 } 372 373 rv = twe_param_get(sc, TWE_PARAM_UNITINFO + i, 374 TWE_PARAM_UNITINFO_Capacity, 4, NULL, (void *)&ctp); 375 if (rv != 0) { 376 printf("%s: error %d fetching capacity for unit %d\n", 377 sc->sc_dv.dv_xname, rv, i); 378 continue; 379 } 380 381 sc->sc_dsize[i] = le32toh(*(u_int32_t *)ctp->tp_data); 382 free(ctp, M_DEVBUF); 383 sc->sc_nunits++; 384 } 385 free(dtp, M_DEVBUF); 386 387 /* Initialise connection with controller and enable interrupts. */ 388 twe_init_connection(sc); 389 twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR | 390 TWE_CTL_UNMASK_RESP_INTR | 391 TWE_CTL_ENABLE_INTRS); 392 393 /* Attach sub-devices. */ 394 for (i = 0; i < TWE_MAX_UNITS; i++) { 395 if (sc->sc_dsize[i] == 0) 396 continue; 397 twea.twea_unit = i; 398 config_found_sm(&sc->sc_dv, &twea, twe_print, twe_submatch); 399 } 400 } 401 402 /* 403 * Reset the controller. Currently only useful at attach time; must be 404 * called with interrupts blocked. 405 */ 406 static int 407 twe_reset(struct twe_softc *sc) 408 { 409 struct twe_param *tp; 410 u_int aen, status; 411 volatile u_int32_t junk; 412 int got, rv; 413 414 /* Issue a soft reset. */ 415 twe_outl(sc, TWE_REG_CTL, TWE_CTL_ISSUE_SOFT_RESET | 416 TWE_CTL_CLEAR_HOST_INTR | 417 TWE_CTL_CLEAR_ATTN_INTR | 418 TWE_CTL_MASK_CMD_INTR | 419 TWE_CTL_MASK_RESP_INTR | 420 TWE_CTL_CLEAR_ERROR_STS | 421 TWE_CTL_DISABLE_INTRS); 422 423 if (twe_status_wait(sc, TWE_STS_ATTN_INTR, 15)) { 424 printf("%s: no attention interrupt\n", 425 sc->sc_dv.dv_xname); 426 return (-1); 427 } 428 429 /* Pull AENs out of the controller; look for a soft reset AEN. */ 430 for (got = 0;;) { 431 rv = twe_param_get(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 432 2, NULL, (void *)&tp); 433 if (rv != 0) 434 printf("%s: error %d while draining response queue\n", 435 sc->sc_dv.dv_xname, rv); 436 aen = TWE_AEN_CODE(le16toh(*(u_int16_t *)tp->tp_data)); 437 free(tp, M_DEVBUF); 438 if (aen == TWE_AEN_QUEUE_EMPTY) 439 break; 440 if (aen == TWE_AEN_SOFT_RESET) 441 got = 1; 442 } 443 if (!got) { 444 printf("%s: reset not reported\n", sc->sc_dv.dv_xname); 445 return (-1); 446 } 447 448 /* Check controller status. */ 449 status = twe_inl(sc, TWE_REG_STS); 450 if (twe_status_check(sc, status)) { 451 printf("%s: controller errors detected\n", 452 sc->sc_dv.dv_xname); 453 return (-1); 454 } 455 456 /* Drain the response queue. */ 457 for (;;) { 458 status = twe_inl(sc, TWE_REG_STS); 459 if (twe_status_check(sc, status) != 0) { 460 printf("%s: can't drain response queue\n", 461 sc->sc_dv.dv_xname); 462 return (-1); 463 } 464 if ((status & TWE_STS_RESP_QUEUE_EMPTY) != 0) 465 break; 466 junk = twe_inl(sc, TWE_REG_RESP_QUEUE); 467 } 468 469 return (0); 470 } 471 472 /* 473 * Print autoconfiguration message for a sub-device. 474 */ 475 static int 476 twe_print(void *aux, const char *pnp) 477 { 478 struct twe_attach_args *twea; 479 480 twea = aux; 481 482 if (pnp != NULL) 483 aprint_normal("block device at %s", pnp); 484 aprint_normal(" unit %d", twea->twea_unit); 485 return (UNCONF); 486 } 487 488 /* 489 * Match a sub-device. 490 */ 491 static int 492 twe_submatch(struct device *parent, struct cfdata *cf, void *aux) 493 { 494 struct twe_attach_args *twea; 495 496 twea = aux; 497 498 if (cf->tweacf_unit != TWECF_UNIT_DEFAULT && 499 cf->tweacf_unit != twea->twea_unit) 500 return (0); 501 502 return (config_match(parent, cf, aux)); 503 } 504 505 /* 506 * Interrupt service routine. 507 */ 508 static int 509 twe_intr(void *arg) 510 { 511 struct twe_softc *sc; 512 u_int status; 513 int caught, rv; 514 515 sc = arg; 516 caught = 0; 517 status = twe_inl(sc, TWE_REG_STS); 518 twe_status_check(sc, status); 519 520 /* Host interrupts - purpose unknown. */ 521 if ((status & TWE_STS_HOST_INTR) != 0) { 522 #ifdef DIAGNOSTIC 523 printf("%s: host interrupt\n", sc->sc_dv.dv_xname); 524 #endif 525 twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_HOST_INTR); 526 caught = 1; 527 } 528 529 /* 530 * Attention interrupts, signalled when a controller or child device 531 * state change has occurred. 532 */ 533 if ((status & TWE_STS_ATTN_INTR) != 0) { 534 if ((sc->sc_flags & TWEF_AEN) == 0) { 535 rv = twe_param_get(sc, TWE_PARAM_AEN, 536 TWE_PARAM_AEN_UnitCode, 2, twe_aen_handler, 537 NULL); 538 if (rv != 0) { 539 printf("%s: unable to retrieve AEN (%d)\n", 540 sc->sc_dv.dv_xname, rv); 541 twe_outl(sc, TWE_REG_CTL, 542 TWE_CTL_CLEAR_ATTN_INTR); 543 } else 544 sc->sc_flags |= TWEF_AEN; 545 } 546 caught = 1; 547 } 548 549 /* 550 * Command interrupts, signalled when the controller can accept more 551 * commands. We don't use this; instead, we try to submit commands 552 * when we receive them, and when other commands have completed. 553 * Mask it so we don't get another one. 554 */ 555 if ((status & TWE_STS_CMD_INTR) != 0) { 556 #ifdef DIAGNOSTIC 557 printf("%s: command interrupt\n", sc->sc_dv.dv_xname); 558 #endif 559 twe_outl(sc, TWE_REG_CTL, TWE_CTL_MASK_CMD_INTR); 560 caught = 1; 561 } 562 563 if ((status & TWE_STS_RESP_INTR) != 0) { 564 twe_poll(sc); 565 caught = 1; 566 } 567 568 return (caught); 569 } 570 571 /* 572 * Handle an AEN returned by the controller. 573 */ 574 static void 575 twe_aen_handler(struct twe_ccb *ccb, int error) 576 { 577 struct twe_softc *sc; 578 struct twe_param *tp; 579 const char *str; 580 u_int aen; 581 int i, hu, rv; 582 583 sc = (struct twe_softc *)ccb->ccb_tx.tx_dv; 584 tp = ccb->ccb_tx.tx_context; 585 twe_ccb_unmap(sc, ccb); 586 587 if (error) { 588 printf("%s: error retrieving AEN\n", sc->sc_dv.dv_xname); 589 aen = TWE_AEN_QUEUE_EMPTY; 590 } else 591 aen = le16toh(*(u_int16_t *)tp->tp_data); 592 free(tp, M_DEVBUF); 593 twe_ccb_free(sc, ccb); 594 595 if (TWE_AEN_CODE(aen) == TWE_AEN_QUEUE_EMPTY) { 596 twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR); 597 sc->sc_flags &= ~TWEF_AEN; 598 return; 599 } 600 601 str = "<unknown>"; 602 i = 0; 603 hu = 0; 604 605 while (i < sizeof(twe_aen_names) / sizeof(twe_aen_names[0])) { 606 if (TWE_AEN_CODE(twe_aen_names[i].aen) == TWE_AEN_CODE(aen)) { 607 str = twe_aen_names[i].desc; 608 hu = TWE_AEN_UNIT(twe_aen_names[i].aen); 609 break; 610 } 611 i++; 612 } 613 printf("%s: ", sc->sc_dv.dv_xname); 614 printf(aenfmt[hu], TWE_AEN_UNIT(aen)); 615 printf("AEN 0x%04x (%s) received\n", TWE_AEN_CODE(aen), str); 616 617 /* 618 * Chain another retrieval in case interrupts have been 619 * coalesced. 620 */ 621 rv = twe_param_get(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 2, 622 twe_aen_handler, NULL); 623 if (rv != 0) 624 printf("%s: unable to retrieve AEN (%d)\n", 625 sc->sc_dv.dv_xname, rv); 626 } 627 628 /* 629 * Execute a TWE_OP_GET_PARAM command. If a callback function is provided, 630 * it will be called with generated context when the command has completed. 631 * If no callback is provided, the command will be executed synchronously 632 * and a pointer to a buffer containing the data returned. 633 * 634 * The caller or callback is responsible for freeing the buffer. 635 */ 636 static int 637 twe_param_get(struct twe_softc *sc, int table_id, int param_id, size_t size, 638 void (*func)(struct twe_ccb *, int), void **pbuf) 639 { 640 struct twe_ccb *ccb; 641 struct twe_cmd *tc; 642 struct twe_param *tp; 643 int rv, s; 644 645 tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT); 646 if (tp == NULL) 647 return ENOMEM; 648 649 rv = twe_ccb_alloc(sc, &ccb, 650 TWE_CCB_PARAM | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT); 651 if (rv != 0) 652 goto done; 653 654 ccb->ccb_data = tp; 655 ccb->ccb_datasize = TWE_SECTOR_SIZE; 656 ccb->ccb_tx.tx_handler = func; 657 ccb->ccb_tx.tx_context = tp; 658 ccb->ccb_tx.tx_dv = &sc->sc_dv; 659 660 tc = ccb->ccb_cmd; 661 tc->tc_size = 2; 662 tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5); 663 tc->tc_unit = 0; 664 tc->tc_count = htole16(1); 665 666 /* Fill in the outbound parameter data. */ 667 tp->tp_table_id = htole16(table_id); 668 tp->tp_param_id = param_id; 669 tp->tp_param_size = size; 670 671 /* Map the transfer. */ 672 if ((rv = twe_ccb_map(sc, ccb)) != 0) { 673 twe_ccb_free(sc, ccb); 674 goto done; 675 } 676 677 /* Submit the command and either wait or let the callback handle it. */ 678 if (func == NULL) { 679 s = splbio(); 680 rv = twe_ccb_poll(sc, ccb, 5); 681 twe_ccb_unmap(sc, ccb); 682 twe_ccb_free(sc, ccb); 683 splx(s); 684 } else { 685 #ifdef DIAGNOSTIC 686 if (pbuf != NULL) 687 panic("both func and pbuf defined"); 688 #endif 689 twe_ccb_enqueue(sc, ccb); 690 return 0; 691 } 692 693 done: 694 if (pbuf == NULL || rv != 0) 695 free(tp, M_DEVBUF); 696 else if (pbuf != NULL && rv == 0) 697 *pbuf = tp; 698 return rv; 699 } 700 701 /* 702 * Execute a TWE_OP_SET_PARAM command. 703 */ 704 static int 705 twe_param_set(struct twe_softc *sc, int table_id, int param_id, size_t size, 706 void *buf) 707 { 708 struct twe_ccb *ccb; 709 struct twe_cmd *tc; 710 struct twe_param *tp; 711 int rv, s; 712 713 tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT); 714 if (tp == NULL) 715 return ENOMEM; 716 717 rv = twe_ccb_alloc(sc, &ccb, 718 TWE_CCB_PARAM | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT); 719 if (rv != 0) 720 goto done; 721 722 ccb->ccb_data = tp; 723 ccb->ccb_datasize = TWE_SECTOR_SIZE; 724 ccb->ccb_tx.tx_handler = 0; 725 ccb->ccb_tx.tx_context = tp; 726 ccb->ccb_tx.tx_dv = &sc->sc_dv; 727 728 tc = ccb->ccb_cmd; 729 tc->tc_size = 2; 730 tc->tc_opcode = TWE_OP_SET_PARAM | (tc->tc_size << 5); 731 tc->tc_unit = 0; 732 tc->tc_count = htole16(1); 733 734 /* Fill in the outbound parameter data. */ 735 tp->tp_table_id = htole16(table_id); 736 tp->tp_param_id = param_id; 737 tp->tp_param_size = size; 738 memcpy(tp->tp_data, buf, size); 739 740 /* Map the transfer. */ 741 if ((rv = twe_ccb_map(sc, ccb)) != 0) { 742 twe_ccb_free(sc, ccb); 743 goto done; 744 } 745 746 /* Submit the command and wait. */ 747 s = splbio(); 748 rv = twe_ccb_poll(sc, ccb, 5); 749 twe_ccb_unmap(sc, ccb); 750 twe_ccb_free(sc, ccb); 751 splx(s); 752 done: 753 free(tp, M_DEVBUF); 754 return (rv); 755 } 756 757 /* 758 * Execute a TWE_OP_INIT_CONNECTION command. Return non-zero on error. 759 * Must be called with interrupts blocked. 760 */ 761 static int 762 twe_init_connection(struct twe_softc *sc) 763 /*###762 [cc] warning: `twe_init_connection' was used with no prototype before its definition%%%*/ 764 /*###762 [cc] warning: `twe_init_connection' was declared implicitly `extern' and later `static'%%%*/ 765 { 766 struct twe_ccb *ccb; 767 struct twe_cmd *tc; 768 int rv; 769 770 if ((rv = twe_ccb_alloc(sc, &ccb, 0)) != 0) 771 return (rv); 772 773 /* Build the command. */ 774 tc = ccb->ccb_cmd; 775 tc->tc_size = 3; 776 tc->tc_opcode = TWE_OP_INIT_CONNECTION; 777 tc->tc_unit = 0; 778 tc->tc_count = htole16(TWE_MAX_CMDS); 779 tc->tc_args.init_connection.response_queue_pointer = 0; 780 781 /* Submit the command for immediate execution. */ 782 rv = twe_ccb_poll(sc, ccb, 5); 783 twe_ccb_free(sc, ccb); 784 return (rv); 785 } 786 787 /* 788 * Poll the controller for completed commands. Must be called with 789 * interrupts blocked. 790 */ 791 static void 792 twe_poll(struct twe_softc *sc) 793 { 794 struct twe_ccb *ccb; 795 int found; 796 u_int status, cmdid; 797 798 found = 0; 799 800 for (;;) { 801 status = twe_inl(sc, TWE_REG_STS); 802 twe_status_check(sc, status); 803 804 if ((status & TWE_STS_RESP_QUEUE_EMPTY)) 805 break; 806 807 found = 1; 808 cmdid = twe_inl(sc, TWE_REG_RESP_QUEUE); 809 cmdid = (cmdid & TWE_RESP_MASK) >> TWE_RESP_SHIFT; 810 if (cmdid >= TWE_MAX_QUEUECNT) { 811 printf("%s: bad completion\n", sc->sc_dv.dv_xname); 812 continue; 813 } 814 815 ccb = sc->sc_ccbs + cmdid; 816 if ((ccb->ccb_flags & TWE_CCB_ACTIVE) == 0) { 817 printf("%s: bad completion (not active)\n", 818 sc->sc_dv.dv_xname); 819 continue; 820 } 821 ccb->ccb_flags ^= TWE_CCB_COMPLETE | TWE_CCB_ACTIVE; 822 823 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 824 (caddr_t)ccb->ccb_cmd - sc->sc_cmds, 825 sizeof(struct twe_cmd), 826 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 827 828 /* Pass notification to upper layers. */ 829 if (ccb->ccb_tx.tx_handler != NULL) 830 (*ccb->ccb_tx.tx_handler)(ccb, 831 ccb->ccb_cmd->tc_status != 0 ? EIO : 0); 832 } 833 834 /* If any commands have completed, run the software queue. */ 835 if (found) 836 twe_ccb_enqueue(sc, NULL); 837 } 838 839 /* 840 * Wait for `status' to be set in the controller status register. Return 841 * zero if found, non-zero if the operation timed out. 842 */ 843 static int 844 twe_status_wait(struct twe_softc *sc, u_int32_t status, int timo) 845 { 846 847 for (timo *= 10; timo != 0; timo--) { 848 if ((twe_inl(sc, TWE_REG_STS) & status) == status) 849 break; 850 delay(100000); 851 } 852 853 return (timo == 0); 854 } 855 856 /* 857 * Complain if the status bits aren't what we expect. 858 */ 859 static int 860 twe_status_check(struct twe_softc *sc, u_int status) 861 { 862 int rv; 863 864 rv = 0; 865 866 if ((status & TWE_STS_EXPECTED_BITS) != TWE_STS_EXPECTED_BITS) { 867 printf("%s: missing status bits: 0x%08x\n", sc->sc_dv.dv_xname, 868 status & ~TWE_STS_EXPECTED_BITS); 869 rv = -1; 870 } 871 872 if ((status & TWE_STS_UNEXPECTED_BITS) != 0) { 873 printf("%s: unexpected status bits: 0x%08x\n", 874 sc->sc_dv.dv_xname, status & TWE_STS_UNEXPECTED_BITS); 875 rv = -1; 876 } 877 878 return (rv); 879 } 880 881 /* 882 * Allocate and initialise a CCB. 883 */ 884 int 885 twe_ccb_alloc(struct twe_softc *sc, struct twe_ccb **ccbp, int flags) 886 { 887 struct twe_cmd *tc; 888 struct twe_ccb *ccb; 889 int s; 890 891 s = splbio(); 892 if ((flags & TWE_CCB_PARAM) != 0) 893 ccb = sc->sc_ccbs; 894 else { 895 /* Allocate a CCB and command block. */ 896 if (SLIST_FIRST(&sc->sc_ccb_freelist) == NULL) { 897 splx(s); 898 return (EAGAIN); 899 } 900 ccb = SLIST_FIRST(&sc->sc_ccb_freelist); 901 SLIST_REMOVE_HEAD(&sc->sc_ccb_freelist, ccb_chain.slist); 902 } 903 #ifdef DIAGNOSTIC 904 if ((ccb->ccb_flags & TWE_CCB_ALLOCED) != 0) 905 panic("twe_ccb_alloc: CCB already allocated"); 906 flags |= TWE_CCB_ALLOCED; 907 #endif 908 splx(s); 909 910 /* Initialise some fields and return. */ 911 ccb->ccb_tx.tx_handler = NULL; 912 ccb->ccb_flags = flags; 913 tc = ccb->ccb_cmd; 914 tc->tc_status = 0; 915 tc->tc_flags = 0; 916 tc->tc_cmdid = ccb->ccb_cmdid; 917 *ccbp = ccb; 918 919 return (0); 920 } 921 922 /* 923 * Free a CCB. 924 */ 925 void 926 twe_ccb_free(struct twe_softc *sc, struct twe_ccb *ccb) 927 { 928 int s; 929 930 s = splbio(); 931 if ((ccb->ccb_flags & TWE_CCB_PARAM) == 0) 932 SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb, ccb_chain.slist); 933 ccb->ccb_flags = 0; 934 splx(s); 935 } 936 937 /* 938 * Map the specified CCB's command block and data buffer (if any) into 939 * controller visible space. Perform DMA synchronisation. 940 */ 941 int 942 twe_ccb_map(struct twe_softc *sc, struct twe_ccb *ccb) 943 { 944 struct twe_cmd *tc; 945 int flags, nsegs, i, s, rv; 946 void *data; 947 948 /* 949 * The data as a whole must be 512-byte aligned. 950 */ 951 if (((u_long)ccb->ccb_data & (TWE_ALIGNMENT - 1)) != 0) { 952 s = splvm(); 953 /* XXX */ 954 ccb->ccb_abuf = uvm_km_kmemalloc(kmem_map, NULL, 955 ccb->ccb_datasize, UVM_KMF_NOWAIT); 956 splx(s); 957 data = (void *)ccb->ccb_abuf; 958 if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0) 959 memcpy(data, ccb->ccb_data, ccb->ccb_datasize); 960 } else { 961 ccb->ccb_abuf = (vaddr_t)0; 962 data = ccb->ccb_data; 963 } 964 965 /* 966 * Map the data buffer into bus space and build the S/G list. 967 */ 968 rv = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, data, 969 ccb->ccb_datasize, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING | 970 ((ccb->ccb_flags & TWE_CCB_DATA_IN) ? 971 BUS_DMA_READ : BUS_DMA_WRITE)); 972 if (rv != 0) { 973 if (ccb->ccb_abuf != (vaddr_t)0) { 974 s = splvm(); 975 /* XXX */ 976 uvm_km_free(kmem_map, ccb->ccb_abuf, 977 ccb->ccb_datasize); 978 splx(s); 979 } 980 return (rv); 981 } 982 983 nsegs = ccb->ccb_dmamap_xfer->dm_nsegs; 984 tc = ccb->ccb_cmd; 985 tc->tc_size += 2 * nsegs; 986 987 /* The location of the S/G list is dependant upon command type. */ 988 switch (tc->tc_opcode >> 5) { 989 case 2: 990 for (i = 0; i < nsegs; i++) { 991 tc->tc_args.param.sgl[i].tsg_address = 992 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 993 tc->tc_args.param.sgl[i].tsg_length = 994 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 995 } 996 /* XXX Needed? */ 997 for (; i < TWE_SG_SIZE; i++) { 998 tc->tc_args.param.sgl[i].tsg_address = 0; 999 tc->tc_args.param.sgl[i].tsg_length = 0; 1000 } 1001 break; 1002 case 3: 1003 for (i = 0; i < nsegs; i++) { 1004 tc->tc_args.io.sgl[i].tsg_address = 1005 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 1006 tc->tc_args.io.sgl[i].tsg_length = 1007 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 1008 } 1009 /* XXX Needed? */ 1010 for (; i < TWE_SG_SIZE; i++) { 1011 tc->tc_args.io.sgl[i].tsg_address = 0; 1012 tc->tc_args.io.sgl[i].tsg_length = 0; 1013 } 1014 break; 1015 #ifdef DEBUG 1016 default: 1017 panic("twe_ccb_map: oops"); 1018 #endif 1019 } 1020 1021 if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0) 1022 flags = BUS_DMASYNC_PREREAD; 1023 else 1024 flags = 0; 1025 if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0) 1026 flags |= BUS_DMASYNC_PREWRITE; 1027 1028 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 1029 ccb->ccb_datasize, flags); 1030 return (0); 1031 } 1032 1033 /* 1034 * Unmap the specified CCB's command block and data buffer (if any) and 1035 * perform DMA synchronisation. 1036 */ 1037 void 1038 twe_ccb_unmap(struct twe_softc *sc, struct twe_ccb *ccb) 1039 { 1040 int flags, s; 1041 1042 if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0) 1043 flags = BUS_DMASYNC_POSTREAD; 1044 else 1045 flags = 0; 1046 if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0) 1047 flags |= BUS_DMASYNC_POSTWRITE; 1048 1049 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 1050 ccb->ccb_datasize, flags); 1051 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 1052 1053 if (ccb->ccb_abuf != (vaddr_t)0) { 1054 if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0) 1055 memcpy(ccb->ccb_data, (void *)ccb->ccb_abuf, 1056 ccb->ccb_datasize); 1057 s = splvm(); 1058 /* XXX */ 1059 uvm_km_free(kmem_map, ccb->ccb_abuf, ccb->ccb_datasize); 1060 splx(s); 1061 } 1062 } 1063 1064 /* 1065 * Submit a command to the controller and poll on completion. Return 1066 * non-zero on timeout (but don't check status, as some command types don't 1067 * return status). Must be called with interrupts blocked. 1068 */ 1069 int 1070 twe_ccb_poll(struct twe_softc *sc, struct twe_ccb *ccb, int timo) 1071 { 1072 int rv; 1073 1074 if ((rv = twe_ccb_submit(sc, ccb)) != 0) 1075 return (rv); 1076 1077 for (timo *= 1000; timo != 0; timo--) { 1078 twe_poll(sc); 1079 if ((ccb->ccb_flags & TWE_CCB_COMPLETE) != 0) 1080 break; 1081 DELAY(100); 1082 } 1083 1084 return (timo == 0); 1085 } 1086 1087 /* 1088 * If a CCB is specified, enqueue it. Pull CCBs off the software queue in 1089 * the order that they were enqueued and try to submit their command blocks 1090 * to the controller for execution. 1091 */ 1092 void 1093 twe_ccb_enqueue(struct twe_softc *sc, struct twe_ccb *ccb) 1094 { 1095 int s; 1096 1097 s = splbio(); 1098 1099 if (ccb != NULL) 1100 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain.simpleq); 1101 1102 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 1103 if (twe_ccb_submit(sc, ccb)) 1104 break; 1105 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain.simpleq); 1106 } 1107 1108 splx(s); 1109 } 1110 1111 /* 1112 * Submit the command block associated with the specified CCB to the 1113 * controller for execution. Must be called with interrupts blocked. 1114 */ 1115 int 1116 twe_ccb_submit(struct twe_softc *sc, struct twe_ccb *ccb) 1117 { 1118 bus_addr_t pa; 1119 int rv; 1120 u_int status; 1121 1122 /* Check to see if we can post a command. */ 1123 status = twe_inl(sc, TWE_REG_STS); 1124 twe_status_check(sc, status); 1125 1126 if ((status & TWE_STS_CMD_QUEUE_FULL) == 0) { 1127 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1128 (caddr_t)ccb->ccb_cmd - sc->sc_cmds, sizeof(struct twe_cmd), 1129 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1130 ccb->ccb_flags |= TWE_CCB_ACTIVE; 1131 pa = sc->sc_cmds_paddr + 1132 ccb->ccb_cmdid * sizeof(struct twe_cmd); 1133 twe_outl(sc, TWE_REG_CMD_QUEUE, (u_int32_t)pa); 1134 rv = 0; 1135 } else 1136 rv = EBUSY; 1137 1138 return (rv); 1139 } 1140 1141 1142 /* 1143 * Accept an open operation on the control device. 1144 */ 1145 int 1146 tweopen(dev_t dev, int flag, int mode, struct proc *p) 1147 { 1148 struct twe_softc *twe; 1149 1150 if ((twe = device_lookup(&twe_cd, minor(dev))) == NULL) 1151 return (ENXIO); 1152 if ((twe->sc_flags & TWEF_OPEN) != 0) 1153 return (EBUSY); 1154 1155 twe->sc_flags |= TWEF_OPEN; 1156 return (0); 1157 } 1158 1159 /* 1160 * Accept the last close on the control device. 1161 */ 1162 int 1163 tweclose(dev_t dev, int flag, int mode, struct proc *p) 1164 { 1165 struct twe_softc *twe; 1166 1167 twe = device_lookup(&twe_cd, minor(dev)); 1168 twe->sc_flags &= ~TWEF_OPEN; 1169 return (0); 1170 } 1171 1172 /* 1173 * Handle control operations. 1174 */ 1175 int 1176 tweioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 1177 { 1178 struct twe_softc *twe; 1179 struct twe_ccb *ccb; 1180 struct twe_param *param; 1181 struct twe_usercommand *tu; 1182 struct twe_paramcommand *tp; 1183 union twe_statrequest *ts; 1184 void *pdata = NULL; 1185 int rv, s, error = 0; 1186 u_int8_t cmdid; 1187 1188 if (securelevel >= 2) 1189 return (EPERM); 1190 1191 twe = device_lookup(&twe_cd, minor(dev)); 1192 tu = (struct twe_usercommand *)data; 1193 tp = (struct twe_paramcommand *)data; 1194 ts = (union twe_statrequest *)data; 1195 1196 /* Hmm, compatible with FreeBSD */ 1197 switch (cmd) { 1198 case TWEIO_COMMAND: 1199 if (tu->tu_size > 0) { 1200 if (tu->tu_size > TWE_SECTOR_SIZE) 1201 return EINVAL; 1202 pdata = malloc(tu->tu_size, M_DEVBUF, M_WAITOK); 1203 error = copyin(tu->tu_data, pdata, tu->tu_size); 1204 if (error != 0) 1205 goto done; 1206 error = twe_ccb_alloc(twe, &ccb, TWE_CCB_PARAM | 1207 TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT); 1208 } else { 1209 error = twe_ccb_alloc(twe, &ccb, 0); 1210 } 1211 if (rv != 0) 1212 goto done; 1213 cmdid = ccb->ccb_cmdid; 1214 memcpy(ccb->ccb_cmd, &tu->tu_cmd, sizeof(struct twe_cmd)); 1215 ccb->ccb_cmdid = cmdid; 1216 if (ccb->ccb_flags & TWE_CCB_PARAM) { 1217 ccb->ccb_data = pdata; 1218 ccb->ccb_datasize = TWE_SECTOR_SIZE; 1219 ccb->ccb_tx.tx_handler = 0; 1220 ccb->ccb_tx.tx_context = pdata; 1221 ccb->ccb_tx.tx_dv = &twe->sc_dv; 1222 } 1223 /* Map the transfer. */ 1224 if ((error = twe_ccb_map(twe, ccb)) != 0) { 1225 twe_ccb_free(twe, ccb); 1226 goto done; 1227 } 1228 1229 /* Submit the command and wait. */ 1230 s = splbio(); 1231 rv = twe_ccb_poll(twe, ccb, 5); 1232 twe_ccb_unmap(twe, ccb); 1233 twe_ccb_free(twe, ccb); 1234 splx(s); 1235 1236 if (tu->tu_size > 0) 1237 error = copyout(pdata, tu->tu_data, tu->tu_size); 1238 goto done; 1239 1240 case TWEIO_STATS: 1241 return (ENOENT); 1242 1243 case TWEIO_AEN_POLL: 1244 if ((twe->sc_flags & TWEF_AEN) == 0) 1245 return (ENOENT); 1246 return (0); 1247 1248 case TWEIO_AEN_WAIT: 1249 s = splbio(); 1250 while ((twe->sc_flags & TWEF_AEN) == 0) { 1251 /* tsleep(); */ 1252 } 1253 splx(s); 1254 return (0); 1255 1256 case TWEIO_GET_PARAM: 1257 error = twe_param_get(twe, tp->tp_table_id, tp->tp_param_id, 1258 tp->tp_size, 0, &pdata); 1259 if (error != 0) 1260 return (error); 1261 param = pdata; 1262 if (param->tp_param_size > tp->tp_size) { 1263 error = EFAULT; 1264 goto done; 1265 } 1266 error = copyout(param->tp_data, tp->tp_data, 1267 param->tp_param_size); 1268 goto done; 1269 1270 case TWEIO_SET_PARAM: 1271 pdata = malloc(tp->tp_size, M_DEVBUF, M_WAITOK); 1272 if ((error = copyin(tp->tp_data, pdata, tp->tp_size)) != 0) 1273 goto done; 1274 error = twe_param_set(twe, tp->tp_table_id, tp->tp_param_id, 1275 tp->tp_size, pdata); 1276 goto done; 1277 1278 case TWEIO_RESET: 1279 twe_reset(twe); 1280 return (0); 1281 1282 default: 1283 return EINVAL; 1284 } 1285 done: 1286 if (pdata) 1287 free(pdata, M_DEVBUF); 1288 return error; 1289 } 1290