160894Smsmith/*- 260894Smsmith * Copyright (c) 2000 Michael Smith 3123103Sps * Copyright (c) 2003 Paul Saab 4123103Sps * Copyright (c) 2003 Vinod Kashyap 560894Smsmith * Copyright (c) 2000 BSDi 660894Smsmith * All rights reserved. 760894Smsmith * 860894Smsmith * Redistribution and use in source and binary forms, with or without 960894Smsmith * modification, are permitted provided that the following conditions 1060894Smsmith * are met: 1160894Smsmith * 1. Redistributions of source code must retain the above copyright 1260894Smsmith * notice, this list of conditions and the following disclaimer. 1360894Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1460894Smsmith * notice, this list of conditions and the following disclaimer in the 1560894Smsmith * documentation and/or other materials provided with the distribution. 1660894Smsmith * 1760894Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1860894Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1960894Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2060894Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2160894Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2260894Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2360894Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2460894Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2560894Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2660894Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2760894Smsmith * SUCH DAMAGE. 2860894Smsmith * 2960894Smsmith * $FreeBSD$ 3060894Smsmith */ 3160894Smsmith 3260894Smsmith/* 3360894Smsmith * Driver for the 3ware Escalade family of IDE RAID controllers. 3460894Smsmith */ 3560894Smsmith 3667555Smsmith#include <dev/twe/twe_compat.h> 3760894Smsmith#include <dev/twe/twereg.h> 3867555Smsmith#include <dev/twe/tweio.h> 3960894Smsmith#include <dev/twe/twevar.h> 4067555Smsmith#define TWE_DEFINE_TABLES 4167555Smsmith#include <dev/twe/twe_tables.h> 4260894Smsmith 4360894Smsmith/* 4460894Smsmith * Command submission. 4560894Smsmith */ 4667555Smsmithstatic int twe_get_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t *result); 4767555Smsmithstatic int twe_get_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t *result); 4867555Smsmithstatic int twe_get_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t *result); 4967555Smsmithstatic void *twe_get_param(struct twe_softc *sc, int table_id, int parameter_id, size_t size, 5060894Smsmith void (* func)(struct twe_request *tr)); 5191449Speter#ifdef TWE_SHUTDOWN_NOTIFICATION 5267555Smsmithstatic int twe_set_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t value); 5391449Speter#endif 5491449Speter#if 0 5567555Smsmithstatic int twe_set_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t value); 5667555Smsmithstatic int twe_set_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t value); 5791449Speter#endif 5867555Smsmithstatic int twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, 5967555Smsmith void *data); 6067555Smsmithstatic int twe_init_connection(struct twe_softc *sc, int mode); 6167555Smsmithstatic int twe_wait_request(struct twe_request *tr); 62141492Sscottlstatic int twe_immediate_request(struct twe_request *tr, int usetmp); 6367555Smsmithstatic void twe_completeio(struct twe_request *tr); 6467555Smsmithstatic void twe_reset(struct twe_softc *sc); 65123103Spsstatic int twe_add_unit(struct twe_softc *sc, int unit); 66123103Spsstatic int twe_del_unit(struct twe_softc *sc, int unit); 6760894Smsmith 6860894Smsmith/* 6960894Smsmith * Command I/O to controller. 7060894Smsmith */ 71240137Sjhbstatic void twe_done(struct twe_softc *sc, int startio); 7267555Smsmithstatic void twe_complete(struct twe_softc *sc); 7367555Smsmithstatic int twe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout); 7467555Smsmithstatic int twe_drain_response_queue(struct twe_softc *sc); 7567555Smsmithstatic int twe_check_bits(struct twe_softc *sc, u_int32_t status_reg); 7667555Smsmithstatic int twe_soft_reset(struct twe_softc *sc); 7760894Smsmith 7860894Smsmith/* 7960894Smsmith * Interrupt handling. 8060894Smsmith */ 8167555Smsmithstatic void twe_host_intr(struct twe_softc *sc); 8267555Smsmithstatic void twe_attention_intr(struct twe_softc *sc); 8367555Smsmithstatic void twe_command_intr(struct twe_softc *sc); 8460894Smsmith 8560894Smsmith/* 8660894Smsmith * Asynchronous event handling. 8760894Smsmith */ 8867555Smsmithstatic int twe_fetch_aen(struct twe_softc *sc); 8967555Smsmithstatic void twe_handle_aen(struct twe_request *tr); 9067555Smsmithstatic void twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen); 91123103Spsstatic u_int16_t twe_dequeue_aen(struct twe_softc *sc); 9267555Smsmithstatic int twe_drain_aen_queue(struct twe_softc *sc); 9367555Smsmithstatic int twe_find_aen(struct twe_softc *sc, u_int16_t aen); 9460894Smsmith 9560894Smsmith/* 9660894Smsmith * Command buffer management. 9760894Smsmith */ 9867555Smsmithstatic int twe_get_request(struct twe_softc *sc, struct twe_request **tr); 9967555Smsmithstatic void twe_release_request(struct twe_request *tr); 10060894Smsmith 10160894Smsmith/* 10260894Smsmith * Debugging. 10360894Smsmith */ 10467555Smsmithstatic char *twe_format_aen(struct twe_softc *sc, u_int16_t aen); 10569543Smsmithstatic int twe_report_request(struct twe_request *tr); 10667555Smsmithstatic void twe_panic(struct twe_softc *sc, char *reason); 10760894Smsmith 10860894Smsmith/******************************************************************************** 10960894Smsmith ******************************************************************************** 11060894Smsmith Public Interfaces 11160894Smsmith ******************************************************************************** 11260894Smsmith ********************************************************************************/ 11360894Smsmith 11460894Smsmith/******************************************************************************** 11567555Smsmith * Initialise the controller, set up driver data structures. 11660894Smsmith */ 11767555Smsmithint 11867555Smsmithtwe_setup(struct twe_softc *sc) 11960894Smsmith{ 12060894Smsmith struct twe_request *tr; 121118816Sps TWE_Command *cmd; 12291790Smsmith u_int32_t status_reg; 12367555Smsmith int i; 12460894Smsmith 12560894Smsmith debug_called(4); 12660894Smsmith 12760894Smsmith /* 12867555Smsmith * Initialise request queues. 12960894Smsmith */ 13067555Smsmith twe_initq_free(sc); 13167555Smsmith twe_initq_bio(sc); 13267555Smsmith twe_initq_ready(sc); 13367555Smsmith twe_initq_busy(sc); 13467555Smsmith twe_initq_complete(sc); 13567555Smsmith sc->twe_wait_aen = -1; 13660894Smsmith 13760894Smsmith /* 13867555Smsmith * Allocate request structures up front. 13960894Smsmith */ 14067555Smsmith for (i = 0; i < TWE_Q_LENGTH; i++) { 141118816Sps if ((tr = twe_allocate_request(sc, i)) == NULL) 14267555Smsmith return(ENOMEM); 14367555Smsmith /* 14467555Smsmith * Set global defaults that won't change. 14567555Smsmith */ 146118816Sps cmd = TWE_FIND_COMMAND(tr); 147118816Sps cmd->generic.host_id = sc->twe_host_id; /* controller-assigned host ID */ 148118816Sps cmd->generic.request_id = i; /* our index number */ 14967555Smsmith sc->twe_lookup[i] = tr; 15060894Smsmith 15167555Smsmith /* 15267555Smsmith * Put command onto the freelist. 15367555Smsmith */ 154239244Sjhb TWE_IO_LOCK(sc); 15567555Smsmith twe_release_request(tr); 156239244Sjhb TWE_IO_UNLOCK(sc); 15760894Smsmith } 158239244Sjhb TWE_IO_LOCK(sc); 15960894Smsmith 16060894Smsmith /* 16191790Smsmith * Check status register for errors, clear them. 16291790Smsmith */ 16391790Smsmith status_reg = TWE_STATUS(sc); 16491790Smsmith twe_check_bits(sc, status_reg); 16591790Smsmith 16691790Smsmith /* 16767555Smsmith * Wait for the controller to come ready. 16860894Smsmith */ 16967555Smsmith if (twe_wait_status(sc, TWE_STATUS_MICROCONTROLLER_READY, 60)) { 170239244Sjhb TWE_IO_UNLOCK(sc); 17167555Smsmith twe_printf(sc, "microcontroller not ready\n"); 17260894Smsmith return(ENXIO); 17360894Smsmith } 17460894Smsmith 17560894Smsmith /* 17667555Smsmith * Disable interrupts from the card. 17760894Smsmith */ 17867555Smsmith twe_disable_interrupts(sc); 17960894Smsmith 18060894Smsmith /* 18167555Smsmith * Soft reset the controller, look for the AEN acknowledging the reset, 18267555Smsmith * check for errors, drain the response queue. 18360894Smsmith */ 18467555Smsmith for (i = 0; i < TWE_MAX_RESET_TRIES; i++) { 18560894Smsmith 18667555Smsmith if (i > 0) 18767555Smsmith twe_printf(sc, "reset %d failed, trying again\n", i); 18867555Smsmith 18967555Smsmith if (!twe_soft_reset(sc)) 19067555Smsmith break; /* reset process complete */ 19167555Smsmith } 192239244Sjhb TWE_IO_UNLOCK(sc); 19367555Smsmith /* did we give up? */ 19467555Smsmith if (i >= TWE_MAX_RESET_TRIES) { 19567555Smsmith twe_printf(sc, "can't initialise controller, giving up\n"); 19660894Smsmith return(ENXIO); 19760894Smsmith } 19860894Smsmith 19960894Smsmith return(0); 20060894Smsmith} 20160894Smsmith 202123103Spsstatic int 203118508Spstwe_add_unit(struct twe_softc *sc, int unit) 20460894Smsmith{ 20560894Smsmith struct twe_drive *dr; 206123103Sps int table, error = 0; 20767555Smsmith u_int16_t dsize; 208118508Sps TWE_Param *drives = NULL, *param = NULL; 209200991Smav TWE_Array_Descriptor *ud; 21060894Smsmith 211239244Sjhb TWE_CONFIG_ASSERT_LOCKED(sc); 212118508Sps if (unit < 0 || unit > TWE_MAX_UNITS) 213123103Sps return (EINVAL); 21460894Smsmith 21560894Smsmith /* 21667555Smsmith * The controller is in a safe state, so try to find drives attached to it. 21760894Smsmith */ 218239244Sjhb TWE_IO_LOCK(sc); 21967555Smsmith if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status, 22067555Smsmith TWE_MAX_UNITS, NULL)) == NULL) { 221239244Sjhb TWE_IO_UNLOCK(sc); 22267555Smsmith twe_printf(sc, "can't detect attached units\n"); 223123103Sps return (EIO); 22460894Smsmith } 22560894Smsmith 226118508Sps dr = &sc->twe_drive[unit]; 227118508Sps /* check that the drive is online */ 228123103Sps if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online)) { 229239244Sjhb TWE_IO_UNLOCK(sc); 230123103Sps error = ENXIO; 231118508Sps goto out; 232123103Sps } 23360894Smsmith 234118508Sps table = TWE_PARAM_UNITINFO + unit; 23560894Smsmith 236118508Sps if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) { 237239244Sjhb TWE_IO_UNLOCK(sc); 238118508Sps twe_printf(sc, "error fetching capacity for unit %d\n", unit); 239123103Sps error = EIO; 240118508Sps goto out; 241118508Sps } 242118508Sps if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) { 243239244Sjhb TWE_IO_UNLOCK(sc); 244118508Sps twe_printf(sc, "error fetching state for unit %d\n", unit); 245123103Sps error = EIO; 246118508Sps goto out; 247118508Sps } 248118508Sps if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) { 249239244Sjhb TWE_IO_UNLOCK(sc); 250118508Sps twe_printf(sc, "error fetching descriptor size for unit %d\n", unit); 251123103Sps error = EIO; 252118508Sps goto out; 253118508Sps } 254118508Sps if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) { 255239244Sjhb TWE_IO_UNLOCK(sc); 256118508Sps twe_printf(sc, "error fetching descriptor for unit %d\n", unit); 257123103Sps error = EIO; 258118508Sps goto out; 259118508Sps } 260200991Smav ud = (TWE_Array_Descriptor *)param->data; 261118508Sps dr->td_type = ud->configuration; 262200991Smav dr->td_stripe = ud->stripe_size; 263118508Sps 264118508Sps /* build synthetic geometry as per controller internal rules */ 265118508Sps if (dr->td_size > 0x200000) { 266118508Sps dr->td_heads = 255; 267118508Sps dr->td_sectors = 63; 268118508Sps } else { 269118508Sps dr->td_heads = 64; 270118508Sps dr->td_sectors = 32; 271118508Sps } 272118508Sps dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors); 273123103Sps dr->td_twe_unit = unit; 274239244Sjhb TWE_IO_UNLOCK(sc); 275118508Sps 276123103Sps error = twe_attach_drive(sc, dr); 277118508Sps 278118508Spsout: 279118508Sps if (param != NULL) 28067555Smsmith free(param, M_DEVBUF); 281118508Sps if (drives != NULL) 282118508Sps free(drives, M_DEVBUF); 283123103Sps return (error); 284118508Sps} 28560894Smsmith 286123103Spsstatic int 287118508Spstwe_del_unit(struct twe_softc *sc, int unit) 288118508Sps{ 289123103Sps int error; 29060894Smsmith 291239244Sjhb TWE_CONFIG_ASSERT_LOCKED(sc); 292126099Scperciva if (unit < 0 || unit >= TWE_MAX_UNITS) 293123103Sps return (ENXIO); 29460894Smsmith 295123103Sps if (sc->twe_drive[unit].td_disk == NULL) 296123103Sps return (ENXIO); 297123103Sps 298123103Sps error = twe_detach_drive(sc, unit); 299123103Sps return (error); 300118508Sps} 301118508Sps 302118508Sps/******************************************************************************** 303118508Sps * Locate disk devices and attach children to them. 304118508Sps */ 305118508Spsvoid 306118508Spstwe_init(struct twe_softc *sc) 307118508Sps{ 308118508Sps int i; 309118508Sps 31060894Smsmith /* 311118508Sps * Scan for drives 312118508Sps */ 313239244Sjhb TWE_CONFIG_LOCK(sc); 314118508Sps for (i = 0; i < TWE_MAX_UNITS; i++) 315118508Sps twe_add_unit(sc, i); 316239244Sjhb TWE_CONFIG_UNLOCK(sc); 317118508Sps 318118508Sps /* 31960894Smsmith * Initialise connection with controller. 32060894Smsmith */ 321239244Sjhb TWE_IO_LOCK(sc); 32267555Smsmith twe_init_connection(sc, TWE_INIT_MESSAGE_CREDITS); 32360894Smsmith 32467555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION 32567555Smsmith /* 32667555Smsmith * Tell the controller we support shutdown notification. 32767555Smsmith */ 32867555Smsmith twe_set_param_1(sc, TWE_PARAM_FEATURES, TWE_PARAM_FEATURES_DriverShutdown, 1); 32967555Smsmith#endif 33067555Smsmith 33160894Smsmith /* 33260894Smsmith * Mark controller up and ready to run. 33360894Smsmith */ 33460894Smsmith sc->twe_state &= ~TWE_STATE_SHUTDOWN; 33560894Smsmith 33660894Smsmith /* 33767555Smsmith * Finally enable interrupts. 33860894Smsmith */ 33960894Smsmith twe_enable_interrupts(sc); 340239244Sjhb TWE_IO_UNLOCK(sc); 34160894Smsmith} 34260894Smsmith 34360894Smsmith/******************************************************************************** 34467555Smsmith * Stop the controller 34560894Smsmith */ 34667555Smsmithvoid 34767555Smsmithtwe_deinit(struct twe_softc *sc) 34860894Smsmith{ 34960894Smsmith /* 35060894Smsmith * Mark the controller as shutting down, and disable any further interrupts. 35160894Smsmith */ 352239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 35360894Smsmith sc->twe_state |= TWE_STATE_SHUTDOWN; 35460894Smsmith twe_disable_interrupts(sc); 35560894Smsmith 35667555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION 35767555Smsmith /* 35867555Smsmith * Disconnect from the controller 35960894Smsmith */ 36067555Smsmith twe_init_connection(sc, TWE_SHUTDOWN_MESSAGE_CREDITS); 36167555Smsmith#endif 36260894Smsmith} 36360894Smsmith 36460894Smsmith/******************************************************************************* 36560894Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 36660894Smsmith * status. 36760894Smsmith */ 36867555Smsmithvoid 36967555Smsmithtwe_intr(struct twe_softc *sc) 37060894Smsmith{ 37160894Smsmith u_int32_t status_reg; 37260894Smsmith 37360894Smsmith debug_called(4); 37460894Smsmith 37560894Smsmith /* 37660894Smsmith * Collect current interrupt status. 37760894Smsmith */ 37860894Smsmith status_reg = TWE_STATUS(sc); 37960894Smsmith twe_check_bits(sc, status_reg); 38060894Smsmith 38160894Smsmith /* 38260894Smsmith * Dispatch based on interrupt status 38360894Smsmith */ 38460894Smsmith if (status_reg & TWE_STATUS_HOST_INTERRUPT) 38560894Smsmith twe_host_intr(sc); 38660894Smsmith if (status_reg & TWE_STATUS_ATTENTION_INTERRUPT) 38760894Smsmith twe_attention_intr(sc); 38860894Smsmith if (status_reg & TWE_STATUS_COMMAND_INTERRUPT) 38960894Smsmith twe_command_intr(sc); 39073104Smsmith if (status_reg & TWE_STATUS_RESPONSE_INTERRUPT) 391240137Sjhb twe_done(sc, 1); 39260894Smsmith}; 39360894Smsmith 39469543Smsmith/******************************************************************************** 39569543Smsmith * Pull as much work off the softc's work queue as possible and give it to the 39669543Smsmith * controller. 39760894Smsmith */ 39869543Smsmithvoid 39969543Smsmithtwe_startio(struct twe_softc *sc) 40060894Smsmith{ 40169543Smsmith struct twe_request *tr; 40269543Smsmith TWE_Command *cmd; 403240209Sjhb struct bio *bp; 40469543Smsmith int error; 40569543Smsmith 40667555Smsmith debug_called(4); 40760894Smsmith 408239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 409130358Svkashyap if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) 410118816Sps return; 411118816Sps 41269543Smsmith /* spin until something prevents us from doing any work */ 41369543Smsmith for (;;) { 41467555Smsmith 41569543Smsmith /* try to get a command that's already ready to go */ 41669543Smsmith tr = twe_dequeue_ready(sc); 41769543Smsmith 41869543Smsmith /* build a command from an outstanding bio */ 41969543Smsmith if (tr == NULL) { 42069543Smsmith 421129144Svkashyap /* get a command to handle the bio with */ 422129144Svkashyap if (twe_get_request(sc, &tr)) 42369543Smsmith break; 42469543Smsmith 425129144Svkashyap /* see if there's work to be done */ 426129144Svkashyap if ((bp = twe_dequeue_bio(sc)) == NULL) { 427129144Svkashyap twe_release_request(tr); 42869543Smsmith break; 42969543Smsmith } 43069543Smsmith 43169543Smsmith /* connect the bio to the command */ 43269543Smsmith tr->tr_complete = twe_completeio; 43369543Smsmith tr->tr_private = bp; 434240209Sjhb tr->tr_data = bp->bio_data; 435240209Sjhb tr->tr_length = bp->bio_bcount; 436118816Sps cmd = TWE_FIND_COMMAND(tr); 437240209Sjhb if (bp->bio_cmd == BIO_READ) { 43869543Smsmith tr->tr_flags |= TWE_CMD_DATAIN; 43969543Smsmith cmd->io.opcode = TWE_OP_READ; 44069543Smsmith } else { 44169543Smsmith tr->tr_flags |= TWE_CMD_DATAOUT; 44269543Smsmith cmd->io.opcode = TWE_OP_WRITE; 44369543Smsmith } 44469543Smsmith 44569543Smsmith /* build a suitable I/O command (assumes 512-byte rounded transfers) */ 44669543Smsmith cmd->io.size = 3; 447240209Sjhb cmd->io.unit = *(int *)(bp->bio_driver1); 44869543Smsmith cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE; 449240209Sjhb cmd->io.lba = bp->bio_pblkno; 45069543Smsmith } 45169543Smsmith 45269543Smsmith /* did we find something to do? */ 45369543Smsmith if (tr == NULL) 45469543Smsmith break; 45569543Smsmith 456127415Svkashyap /* try to map and submit the command to controller */ 457118816Sps error = twe_map_request(tr); 458127415Svkashyap 45969543Smsmith if (error != 0) { 460130358Svkashyap if (error == EBUSY) 461130358Svkashyap break; 462127415Svkashyap tr->tr_status = TWE_CMD_ERROR; 463127415Svkashyap if (tr->tr_private != NULL) { 464240209Sjhb bp = (struct bio *)(tr->tr_private); 465240209Sjhb bp->bio_error = error; 466240209Sjhb bp->bio_flags |= BIO_ERROR; 467127415Svkashyap tr->tr_private = NULL; 468127415Svkashyap twed_intr(bp); 469127415Svkashyap twe_release_request(tr); 470127415Svkashyap } else if (tr->tr_flags & TWE_CMD_SLEEPER) 471127415Svkashyap wakeup_one(tr); /* wakeup the sleeping owner */ 47269543Smsmith } 47369543Smsmith } 47460894Smsmith} 47560894Smsmith 47660894Smsmith/******************************************************************************** 47769543Smsmith * Write blocks from memory to disk, for system crash dumps. 47869543Smsmith */ 47969543Smsmithint 48069543Smsmithtwe_dump_blocks(struct twe_softc *sc, int unit, u_int32_t lba, void *data, int nblks) 48169543Smsmith{ 48269543Smsmith struct twe_request *tr; 48369543Smsmith TWE_Command *cmd; 48469543Smsmith int error; 48569543Smsmith 48669543Smsmith if (twe_get_request(sc, &tr)) 48769543Smsmith return(ENOMEM); 48869543Smsmith 48969543Smsmith tr->tr_data = data; 49069543Smsmith tr->tr_status = TWE_CMD_SETUP; 49169543Smsmith tr->tr_length = nblks * TWE_BLOCK_SIZE; 49269543Smsmith tr->tr_flags = TWE_CMD_DATAOUT; 49369543Smsmith 494118816Sps cmd = TWE_FIND_COMMAND(tr); 49569543Smsmith cmd->io.opcode = TWE_OP_WRITE; 49669543Smsmith cmd->io.size = 3; 49769543Smsmith cmd->io.unit = unit; 49869543Smsmith cmd->io.block_count = nblks; 49969543Smsmith cmd->io.lba = lba; 50069543Smsmith 501141492Sscottl error = twe_immediate_request(tr, 0); 50269543Smsmith if (error == 0) 50369543Smsmith if (twe_report_request(tr)) 50469543Smsmith error = EIO; 50569543Smsmith twe_release_request(tr); 50669543Smsmith return(error); 50769543Smsmith} 50869543Smsmith 50969543Smsmith/******************************************************************************** 51067555Smsmith * Handle controller-specific control operations. 51160894Smsmith */ 51267555Smsmithint 513197409Srdivackytwe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr) 51460894Smsmith{ 51567555Smsmith struct twe_usercommand *tu = (struct twe_usercommand *)addr; 51667555Smsmith struct twe_paramcommand *tp = (struct twe_paramcommand *)addr; 517118508Sps struct twe_drivecommand *td = (struct twe_drivecommand *)addr; 51867555Smsmith union twe_statrequest *ts = (union twe_statrequest *)addr; 51967555Smsmith TWE_Param *param; 520118816Sps TWE_Command *cmd; 52167555Smsmith void *data; 522123103Sps u_int16_t *aen_code = (u_int16_t *)addr; 52367555Smsmith struct twe_request *tr; 52469543Smsmith u_int8_t srid; 525239244Sjhb int error; 526239244Sjhb size_t tr_length; 52760894Smsmith 52867555Smsmith error = 0; 529118816Sps switch(ioctlcmd) { 53067555Smsmith /* handle a command from userspace */ 53167555Smsmith case TWEIO_COMMAND: 532239244Sjhb /* 533239244Sjhb * if there's a data buffer, allocate and copy it in. 534298955Spfg * Must be in multiplied of 512 bytes. 535239244Sjhb */ 536239244Sjhb tr_length = roundup2(tu->tu_size, 512); 537239244Sjhb if (tr_length > 0) { 538239244Sjhb data = malloc(tr_length, M_DEVBUF, M_WAITOK); 539239244Sjhb error = copyin(tu->tu_data, data, tu->tu_size); 540239244Sjhb if (error) { 541239244Sjhb free(data, M_DEVBUF); 542239244Sjhb break; 543239244Sjhb } 544239244Sjhb } else 545239244Sjhb data = NULL; 546239244Sjhb 54767555Smsmith /* get a request */ 548239244Sjhb TWE_IO_LOCK(sc); 549118508Sps while (twe_get_request(sc, &tr)) 550239244Sjhb mtx_sleep(sc, &sc->twe_io_lock, PPAUSE, "twioctl", hz); 55167555Smsmith 55269543Smsmith /* 55369543Smsmith * Save the command's request ID, copy the user-supplied command in, 55469543Smsmith * restore the request ID. 55569543Smsmith */ 556118816Sps cmd = TWE_FIND_COMMAND(tr); 557118816Sps srid = cmd->generic.request_id; 558118816Sps bcopy(&tu->tu_command, cmd, sizeof(TWE_Command)); 559118816Sps cmd->generic.request_id = srid; 56067555Smsmith 561239244Sjhb tr->tr_length = tr_length; 562239244Sjhb tr->tr_data = data; 56367555Smsmith if (tr->tr_length > 0) { 56467555Smsmith tr->tr_flags |= TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 56567555Smsmith } 56667555Smsmith 56767555Smsmith /* run the command */ 568127415Svkashyap error = twe_wait_request(tr); 569239244Sjhb TWE_IO_UNLOCK(sc); 570127415Svkashyap if (error) 571127415Svkashyap goto cmd_done; 57267555Smsmith 57367555Smsmith /* copy the command out again */ 574118816Sps bcopy(cmd, &tu->tu_command, sizeof(TWE_Command)); 57567555Smsmith 57667555Smsmith /* if there was a data buffer, copy it out */ 57767555Smsmith if (tr->tr_length > 0) 578118508Sps error = copyout(tr->tr_data, tu->tu_data, tu->tu_size); 57967555Smsmith 58067555Smsmith cmd_done: 58167555Smsmith /* free resources */ 58267555Smsmith if (tr->tr_data != NULL) 58367555Smsmith free(tr->tr_data, M_DEVBUF); 584239244Sjhb TWE_IO_LOCK(sc); 585239244Sjhb twe_release_request(tr); 586239244Sjhb TWE_IO_UNLOCK(sc); 58767555Smsmith 58867555Smsmith break; 58967555Smsmith 59067555Smsmith /* fetch statistics counter */ 59167555Smsmith case TWEIO_STATS: 59267555Smsmith switch (ts->ts_item) { 59367555Smsmith#ifdef TWE_PERFORMANCE_MONITOR 59467555Smsmith case TWEQ_FREE: 59567555Smsmith case TWEQ_BIO: 59667555Smsmith case TWEQ_READY: 59767555Smsmith case TWEQ_BUSY: 59867555Smsmith case TWEQ_COMPLETE: 599239244Sjhb TWE_IO_LOCK(sc); 60067555Smsmith bcopy(&sc->twe_qstat[ts->ts_item], &ts->ts_qstat, sizeof(struct twe_qstat)); 601239244Sjhb TWE_IO_UNLOCK(sc); 60267555Smsmith break; 60367555Smsmith#endif 60467555Smsmith default: 60567555Smsmith error = ENOENT; 60667555Smsmith break; 60767555Smsmith } 60867555Smsmith break; 60967555Smsmith 61067555Smsmith /* poll for an AEN */ 61167555Smsmith case TWEIO_AEN_POLL: 612239244Sjhb TWE_IO_LOCK(sc); 613123103Sps *aen_code = twe_dequeue_aen(sc); 614239244Sjhb TWE_IO_UNLOCK(sc); 61567555Smsmith break; 61667555Smsmith 61767555Smsmith /* wait for another AEN to show up */ 61867555Smsmith case TWEIO_AEN_WAIT: 619239244Sjhb TWE_IO_LOCK(sc); 620123103Sps while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) { 621239244Sjhb error = mtx_sleep(&sc->twe_aen_queue, &sc->twe_io_lock, PRIBIO | PCATCH, 622239244Sjhb "tweaen", 0); 62367555Smsmith if (error == EINTR) 62467555Smsmith break; 62567555Smsmith } 626239244Sjhb TWE_IO_UNLOCK(sc); 62767555Smsmith break; 62867555Smsmith 62967555Smsmith case TWEIO_GET_PARAM: 630239244Sjhb TWE_IO_LOCK(sc); 631239244Sjhb param = twe_get_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, NULL); 632239244Sjhb TWE_IO_UNLOCK(sc); 633239244Sjhb if (param == NULL) { 63467555Smsmith twe_printf(sc, "TWEIO_GET_PARAM failed for 0x%x/0x%x/%d\n", 63567555Smsmith tp->tp_table_id, tp->tp_param_id, tp->tp_size); 63667555Smsmith error = EINVAL; 63767555Smsmith } else { 63867555Smsmith if (param->parameter_size_bytes > tp->tp_size) { 63967555Smsmith twe_printf(sc, "TWEIO_GET_PARAM parameter too large (%d > %d)\n", 64067555Smsmith param->parameter_size_bytes, tp->tp_size); 64167555Smsmith error = EFAULT; 64267555Smsmith } else { 64367555Smsmith error = copyout(param->data, tp->tp_data, param->parameter_size_bytes); 64467555Smsmith } 64567555Smsmith free(param, M_DEVBUF); 64667555Smsmith } 64767555Smsmith break; 64867555Smsmith 64967555Smsmith case TWEIO_SET_PARAM: 650239244Sjhb data = malloc(tp->tp_size, M_DEVBUF, M_WAITOK); 651239244Sjhb error = copyin(tp->tp_data, data, tp->tp_size); 652239244Sjhb if (error == 0) { 653239244Sjhb TWE_IO_LOCK(sc); 654239244Sjhb error = twe_set_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, data); 655239244Sjhb TWE_IO_UNLOCK(sc); 65667555Smsmith } 657239244Sjhb free(data, M_DEVBUF); 65867555Smsmith break; 65967555Smsmith 66067555Smsmith case TWEIO_RESET: 661239244Sjhb TWE_IO_LOCK(sc); 66267555Smsmith twe_reset(sc); 663239244Sjhb TWE_IO_UNLOCK(sc); 66467555Smsmith break; 66567555Smsmith 666118508Sps case TWEIO_ADD_UNIT: 667239244Sjhb TWE_CONFIG_LOCK(sc); 668123103Sps error = twe_add_unit(sc, td->td_unit); 669239244Sjhb TWE_CONFIG_UNLOCK(sc); 670118508Sps break; 671118508Sps 672118508Sps case TWEIO_DEL_UNIT: 673239244Sjhb TWE_CONFIG_LOCK(sc); 674123103Sps error = twe_del_unit(sc, td->td_unit); 675239244Sjhb TWE_CONFIG_UNLOCK(sc); 676118508Sps break; 677118508Sps 67891790Smsmith /* XXX implement ATA PASSTHROUGH */ 67991790Smsmith 68067555Smsmith /* nothing we understand */ 68167555Smsmith default: 68267555Smsmith error = ENOTTY; 68367555Smsmith } 68467555Smsmith 68567555Smsmith return(error); 68660894Smsmith} 68760894Smsmith 68860894Smsmith/******************************************************************************** 68967555Smsmith * Enable the useful interrupts from the controller. 69060894Smsmith */ 69167555Smsmithvoid 69267555Smsmithtwe_enable_interrupts(struct twe_softc *sc) 69360894Smsmith{ 69467555Smsmith sc->twe_state |= TWE_STATE_INTEN; 69567555Smsmith TWE_CONTROL(sc, 69667555Smsmith TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT | 69767555Smsmith TWE_CONTROL_UNMASK_RESPONSE_INTERRUPT | 69867555Smsmith TWE_CONTROL_ENABLE_INTERRUPTS); 69960894Smsmith} 70060894Smsmith 70160894Smsmith/******************************************************************************** 70267555Smsmith * Disable interrupts from the controller. 70367555Smsmith */ 70467555Smsmithvoid 70567555Smsmithtwe_disable_interrupts(struct twe_softc *sc) 70667555Smsmith{ 70767555Smsmith TWE_CONTROL(sc, TWE_CONTROL_DISABLE_INTERRUPTS); 70867555Smsmith sc->twe_state &= ~TWE_STATE_INTEN; 70967555Smsmith} 71067555Smsmith 71167555Smsmith/******************************************************************************** 71260894Smsmith ******************************************************************************** 71360894Smsmith Command Submission 71460894Smsmith ******************************************************************************** 71560894Smsmith ********************************************************************************/ 71660894Smsmith 71767555Smsmith/******************************************************************************** 71867555Smsmith * Read integer parameter table entries. 71960894Smsmith */ 72067555Smsmithstatic int 72167555Smsmithtwe_get_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t *result) 72260894Smsmith{ 72367555Smsmith TWE_Param *param; 72460894Smsmith 72567555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 1, NULL)) == NULL) 72667555Smsmith return(ENOENT); 72767555Smsmith *result = *(u_int8_t *)param->data; 72867555Smsmith free(param, M_DEVBUF); 72967555Smsmith return(0); 73067555Smsmith} 73160894Smsmith 73267555Smsmithstatic int 73367555Smsmithtwe_get_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t *result) 73467555Smsmith{ 73567555Smsmith TWE_Param *param; 73667555Smsmith 73767555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 2, NULL)) == NULL) 73867555Smsmith return(ENOENT); 73967555Smsmith *result = *(u_int16_t *)param->data; 74067555Smsmith free(param, M_DEVBUF); 74160894Smsmith return(0); 74260894Smsmith} 74360894Smsmith 74467555Smsmithstatic int 74567555Smsmithtwe_get_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t *result) 74667555Smsmith{ 74767555Smsmith TWE_Param *param; 74867555Smsmith 74967555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 4, NULL)) == NULL) 75067555Smsmith return(ENOENT); 75167555Smsmith *result = *(u_int32_t *)param->data; 75267555Smsmith free(param, M_DEVBUF); 75367555Smsmith return(0); 75467555Smsmith} 75567555Smsmith 75660894Smsmith/******************************************************************************** 75760894Smsmith * Perform a TWE_OP_GET_PARAM command. If a callback function is provided, it 75860894Smsmith * will be called with the command when it's completed. If no callback is 75960894Smsmith * provided, we will wait for the command to complete and then return just the data. 76060894Smsmith * The caller is responsible for freeing the data when done with it. 76160894Smsmith */ 76260894Smsmithstatic void * 76367555Smsmithtwe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_size, 76467555Smsmith void (* func)(struct twe_request *tr)) 76560894Smsmith{ 76660894Smsmith struct twe_request *tr; 76760894Smsmith TWE_Command *cmd; 76860894Smsmith TWE_Param *param; 76960894Smsmith int error; 77060894Smsmith 77160894Smsmith debug_called(4); 77260894Smsmith 773239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 77460894Smsmith tr = NULL; 77560894Smsmith param = NULL; 77660894Smsmith 77760894Smsmith /* get a command */ 77867555Smsmith if (twe_get_request(sc, &tr)) 77960894Smsmith goto err; 78060894Smsmith 78160894Smsmith /* get a buffer */ 78260894Smsmith if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 78360894Smsmith goto err; 78460894Smsmith tr->tr_data = param; 78560894Smsmith tr->tr_length = TWE_SECTOR_SIZE; 78660894Smsmith tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 78760894Smsmith 78860894Smsmith /* build the command for the controller */ 789118816Sps cmd = TWE_FIND_COMMAND(tr); 79067555Smsmith cmd->param.opcode = TWE_OP_GET_PARAM; 79167555Smsmith cmd->param.size = 2; 79267555Smsmith cmd->param.unit = 0; 79367555Smsmith cmd->param.param_count = 1; 79460894Smsmith 79560894Smsmith /* fill in the outbound parameter data */ 79660894Smsmith param->table_id = table_id; 79767555Smsmith param->parameter_id = param_id; 79867555Smsmith param->parameter_size_bytes = param_size; 79960894Smsmith 80060894Smsmith /* submit the command and either wait or let the callback handle it */ 80160894Smsmith if (func == NULL) { 80260894Smsmith /* XXX could use twe_wait_request here if interrupts were enabled? */ 803141492Sscottl error = twe_immediate_request(tr, 1 /* usetmp */); 80460894Smsmith if (error == 0) { 80569543Smsmith if (twe_report_request(tr)) 80660894Smsmith goto err; 807123103Sps } else { 808123103Sps goto err; 80960894Smsmith } 81067555Smsmith twe_release_request(tr); 81167555Smsmith return(param); 81260894Smsmith } else { 81360894Smsmith tr->tr_complete = func; 814118816Sps error = twe_map_request(tr); 815130358Svkashyap if ((error == 0) || (error == EBUSY)) 81660894Smsmith return(func); 81760894Smsmith } 81860894Smsmith 81960894Smsmith /* something failed */ 82060894Smsmitherr: 82160894Smsmith debug(1, "failed"); 82260894Smsmith if (tr != NULL) 82360894Smsmith twe_release_request(tr); 82460894Smsmith if (param != NULL) 82560894Smsmith free(param, M_DEVBUF); 82660894Smsmith return(NULL); 82760894Smsmith} 82860894Smsmith 82960894Smsmith/******************************************************************************** 83067555Smsmith * Set integer parameter table entries. 83167555Smsmith */ 83291449Speter#ifdef TWE_SHUTDOWN_NOTIFICATION 83367555Smsmithstatic int 83467555Smsmithtwe_set_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t value) 83567555Smsmith{ 83667555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 83767555Smsmith} 83891449Speter#endif 83967555Smsmith 84091449Speter#if 0 84167555Smsmithstatic int 84267555Smsmithtwe_set_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t value) 84367555Smsmith{ 84467555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 84567555Smsmith} 84667555Smsmith 84767555Smsmithstatic int 84867555Smsmithtwe_set_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t value) 84967555Smsmith{ 85067555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 85167555Smsmith} 85291449Speter#endif 85367555Smsmith 85467555Smsmith/******************************************************************************** 85567555Smsmith * Perform a TWE_OP_SET_PARAM command, returns nonzero on error. 85667555Smsmith */ 85767555Smsmithstatic int 85867555Smsmithtwe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, void *data) 85967555Smsmith{ 86067555Smsmith struct twe_request *tr; 86167555Smsmith TWE_Command *cmd; 86267555Smsmith TWE_Param *param; 86367555Smsmith int error; 86467555Smsmith 86567555Smsmith debug_called(4); 86667555Smsmith 867239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 86867555Smsmith tr = NULL; 86967555Smsmith param = NULL; 87067555Smsmith error = ENOMEM; 87167555Smsmith 87267555Smsmith /* get a command */ 87367555Smsmith if (twe_get_request(sc, &tr)) 87467555Smsmith goto out; 87567555Smsmith 87667555Smsmith /* get a buffer */ 87767555Smsmith if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 87867555Smsmith goto out; 87967555Smsmith tr->tr_data = param; 88067555Smsmith tr->tr_length = TWE_SECTOR_SIZE; 88167555Smsmith tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 88267555Smsmith 88367555Smsmith /* build the command for the controller */ 884118816Sps cmd = TWE_FIND_COMMAND(tr); 88567555Smsmith cmd->param.opcode = TWE_OP_SET_PARAM; 88667555Smsmith cmd->param.size = 2; 88767555Smsmith cmd->param.unit = 0; 88867555Smsmith cmd->param.param_count = 1; 88967555Smsmith 89067555Smsmith /* fill in the outbound parameter data */ 89167555Smsmith param->table_id = table_id; 89267555Smsmith param->parameter_id = param_id; 89367555Smsmith param->parameter_size_bytes = param_size; 89467555Smsmith bcopy(data, param->data, param_size); 89567555Smsmith 89667555Smsmith /* XXX could use twe_wait_request here if interrupts were enabled? */ 897141492Sscottl error = twe_immediate_request(tr, 1 /* usetmp */); 89867555Smsmith if (error == 0) { 89969543Smsmith if (twe_report_request(tr)) 90067555Smsmith error = EIO; 90167555Smsmith } 90267555Smsmith 90367555Smsmithout: 90467555Smsmith if (tr != NULL) 90567555Smsmith twe_release_request(tr); 90667555Smsmith if (param != NULL) 90767555Smsmith free(param, M_DEVBUF); 90867555Smsmith return(error); 90967555Smsmith} 91067555Smsmith 91167555Smsmith/******************************************************************************** 91260894Smsmith * Perform a TWE_OP_INIT_CONNECTION command, returns nonzero on error. 91360894Smsmith * 91460894Smsmith * Typically called with interrupts disabled. 91560894Smsmith */ 91660894Smsmithstatic int 91767555Smsmithtwe_init_connection(struct twe_softc *sc, int mode) 91860894Smsmith{ 91960894Smsmith struct twe_request *tr; 92060894Smsmith TWE_Command *cmd; 92160894Smsmith int error; 92260894Smsmith 92360894Smsmith debug_called(4); 92460894Smsmith 925239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 926239244Sjhb 92760894Smsmith /* get a command */ 92867555Smsmith if (twe_get_request(sc, &tr)) 929102291Sarchie return(0); 93060894Smsmith 93160894Smsmith /* build the command */ 932118816Sps cmd = TWE_FIND_COMMAND(tr); 93367555Smsmith cmd->initconnection.opcode = TWE_OP_INIT_CONNECTION; 93467555Smsmith cmd->initconnection.size = 3; 93567555Smsmith cmd->initconnection.host_id = 0; 93667555Smsmith cmd->initconnection.message_credits = mode; 93767555Smsmith cmd->initconnection.response_queue_pointer = 0; 93860894Smsmith 93960894Smsmith /* submit the command */ 940141492Sscottl error = twe_immediate_request(tr, 0 /* usetmp */); 94160894Smsmith twe_release_request(tr); 94260894Smsmith 94367555Smsmith if (mode == TWE_INIT_MESSAGE_CREDITS) 94467555Smsmith sc->twe_host_id = cmd->initconnection.host_id; 94560894Smsmith return(error); 94660894Smsmith} 94760894Smsmith 94860894Smsmith/******************************************************************************** 94960894Smsmith * Start the command (tr) and sleep waiting for it to complete. 95060894Smsmith * 95160894Smsmith * Successfully completed commands are dequeued. 95260894Smsmith */ 95360894Smsmithstatic int 95460894Smsmithtwe_wait_request(struct twe_request *tr) 95560894Smsmith{ 95660894Smsmith 95760894Smsmith debug_called(4); 95860894Smsmith 959239244Sjhb TWE_IO_ASSERT_LOCKED(tr->tr_sc); 96067555Smsmith tr->tr_flags |= TWE_CMD_SLEEPER; 96167555Smsmith tr->tr_status = TWE_CMD_BUSY; 96267555Smsmith twe_enqueue_ready(tr); 96367555Smsmith twe_startio(tr->tr_sc); 96467555Smsmith while (tr->tr_status == TWE_CMD_BUSY) 965239244Sjhb mtx_sleep(tr, &tr->tr_sc->twe_io_lock, PRIBIO, "twewait", 0); 96667555Smsmith 967127415Svkashyap return(tr->tr_status != TWE_CMD_COMPLETE); 96860894Smsmith} 96960894Smsmith 97060894Smsmith/******************************************************************************** 97160894Smsmith * Start the command (tr) and busy-wait for it to complete. 97260894Smsmith * This should only be used when interrupts are actually disabled (although it 97360894Smsmith * will work if they are not). 97460894Smsmith */ 97560894Smsmithstatic int 976141492Sscottltwe_immediate_request(struct twe_request *tr, int usetmp) 97760894Smsmith{ 978141492Sscottl struct twe_softc *sc; 979127415Svkashyap int error; 980141492Sscottl int count = 0; 98160894Smsmith 98260894Smsmith debug_called(4); 98360894Smsmith 984141492Sscottl sc = tr->tr_sc; 985141492Sscottl 986141492Sscottl if (usetmp && (tr->tr_data != NULL)) { 987141492Sscottl tr->tr_flags |= TWE_CMD_IMMEDIATE; 988280347Smav if (tr->tr_length > DFLTPHYS) 989141492Sscottl return (EINVAL); 990141492Sscottl bcopy(tr->tr_data, sc->twe_immediate, tr->tr_length); 991141492Sscottl } 992118816Sps tr->tr_status = TWE_CMD_BUSY; 993127415Svkashyap if ((error = twe_map_request(tr)) != 0) 994130358Svkashyap if (error != EBUSY) 995130358Svkashyap return(error); 996141492Sscottl 997141492Sscottl /* Wait up to 5 seconds for the command to complete */ 998141492Sscottl while ((count++ < 5000) && (tr->tr_status == TWE_CMD_BUSY)){ 999141492Sscottl DELAY(1000); 1000240137Sjhb twe_done(sc, 1); 100160894Smsmith } 1002141492Sscottl if (usetmp && (tr->tr_data != NULL)) 1003141492Sscottl bcopy(sc->twe_immediate, tr->tr_data, tr->tr_length); 1004141492Sscottl 100560894Smsmith return(tr->tr_status != TWE_CMD_COMPLETE); 100660894Smsmith} 100760894Smsmith 100860894Smsmith/******************************************************************************** 100960894Smsmith * Handle completion of an I/O command. 101060894Smsmith */ 101160894Smsmithstatic void 101260894Smsmithtwe_completeio(struct twe_request *tr) 101360894Smsmith{ 1014123103Sps TWE_Command *cmd = TWE_FIND_COMMAND(tr); 101560894Smsmith struct twe_softc *sc = tr->tr_sc; 1016240209Sjhb struct bio *bp = tr->tr_private; 101760894Smsmith 101860894Smsmith debug_called(4); 101960894Smsmith 102060894Smsmith if (tr->tr_status == TWE_CMD_COMPLETE) { 102167555Smsmith 1022123103Sps if (cmd->generic.status) 1023240209Sjhb if (twe_report_request(tr)) { 1024240209Sjhb bp->bio_error = EIO; 1025240209Sjhb bp->bio_flags |= BIO_ERROR; 1026240209Sjhb } 102767555Smsmith 102869543Smsmith } else { 102969543Smsmith twe_panic(sc, "twe_completeio on incomplete command"); 103060894Smsmith } 103169543Smsmith tr->tr_private = NULL; 103269543Smsmith twed_intr(bp); 103360894Smsmith twe_release_request(tr); 103460894Smsmith} 103560894Smsmith 103660894Smsmith/******************************************************************************** 103767555Smsmith * Reset the controller and pull all the active commands back onto the ready 103867555Smsmith * queue. Used to restart a controller that's exhibiting bad behaviour. 103967555Smsmith */ 104067555Smsmithstatic void 104167555Smsmithtwe_reset(struct twe_softc *sc) 104267555Smsmith{ 104367555Smsmith struct twe_request *tr; 1044239244Sjhb int i; 104567555Smsmith 104691790Smsmith /* 104791790Smsmith * Sleep for a short period to allow AENs to be signalled. 104891790Smsmith */ 1049239244Sjhb mtx_sleep(sc, &sc->twe_io_lock, PRIBIO, "twereset", hz); 105067555Smsmith 105167555Smsmith /* 105267555Smsmith * Disable interrupts from the controller, and mask any accidental entry 105367555Smsmith * into our interrupt handler. 105467555Smsmith */ 105591790Smsmith twe_printf(sc, "controller reset in progress...\n"); 105667555Smsmith twe_disable_interrupts(sc); 105767555Smsmith 105867555Smsmith /* 105967555Smsmith * Try to soft-reset the controller. 106067555Smsmith */ 106167555Smsmith for (i = 0; i < TWE_MAX_RESET_TRIES; i++) { 106267555Smsmith 106367555Smsmith if (i > 0) 106467555Smsmith twe_printf(sc, "reset %d failed, trying again\n", i); 106567555Smsmith 106667555Smsmith if (!twe_soft_reset(sc)) 106767555Smsmith break; /* reset process complete */ 106867555Smsmith } 106967555Smsmith /* did we give up? */ 107067555Smsmith if (i >= TWE_MAX_RESET_TRIES) { 107167555Smsmith twe_printf(sc, "can't reset controller, giving up\n"); 107267555Smsmith goto out; 107367555Smsmith } 107467555Smsmith 107567555Smsmith /* 107667555Smsmith * Move all of the commands that were busy back to the ready queue. 107767555Smsmith */ 107867555Smsmith i = 0; 107967555Smsmith while ((tr = twe_dequeue_busy(sc)) != NULL) { 108067555Smsmith twe_enqueue_ready(tr); 108167555Smsmith i++; 108267555Smsmith } 108367555Smsmith 108467555Smsmith /* 108567555Smsmith * Kick the controller to start things going again, then re-enable interrupts. 108667555Smsmith */ 108767555Smsmith twe_startio(sc); 108867555Smsmith twe_printf(sc, "controller reset done, %d commands restarted\n", i); 108967555Smsmith 109067555Smsmithout: 109167555Smsmith twe_enable_interrupts(sc); 109267555Smsmith} 109367555Smsmith 109467555Smsmith/******************************************************************************** 109560894Smsmith ******************************************************************************** 109660894Smsmith Command I/O to Controller 109760894Smsmith ******************************************************************************** 109860894Smsmith ********************************************************************************/ 109960894Smsmith 110060894Smsmith/******************************************************************************** 110160894Smsmith * Try to deliver (tr) to the controller. 110260894Smsmith * 110360894Smsmith * Can be called at any interrupt level, with or without interrupts enabled. 110460894Smsmith */ 1105118816Spsint 110660894Smsmithtwe_start(struct twe_request *tr) 110760894Smsmith{ 110860894Smsmith struct twe_softc *sc = tr->tr_sc; 1109118816Sps TWE_Command *cmd; 1110239244Sjhb int i; 111160894Smsmith u_int32_t status_reg; 111260894Smsmith 111360894Smsmith debug_called(4); 111460894Smsmith 1115239244Sjhb if (!dumping) 1116239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 1117239244Sjhb 111860894Smsmith /* mark the command as currently being processed */ 111960894Smsmith tr->tr_status = TWE_CMD_BUSY; 1120118816Sps cmd = TWE_FIND_COMMAND(tr); 112160894Smsmith 112267555Smsmith /* 112367555Smsmith * Spin briefly waiting for the controller to come ready 112467555Smsmith * 112567555Smsmith * XXX it might be more efficient to return EBUSY immediately 112667555Smsmith * and let the command be rescheduled. 112767555Smsmith */ 1128239244Sjhb for (i = 100000; (i > 0); i--) { 112960894Smsmith 113060894Smsmith /* check to see if we can post a command */ 113160894Smsmith status_reg = TWE_STATUS(sc); 113260894Smsmith twe_check_bits(sc, status_reg); 113360894Smsmith 113460894Smsmith if (!(status_reg & TWE_STATUS_COMMAND_QUEUE_FULL)) { 1135118816Sps twe_enqueue_busy(tr); 1136118816Sps 1137118816Sps TWE_COMMAND_QUEUE(sc, TWE_FIND_COMMANDPHYS(tr)); 1138239244Sjhb 113960894Smsmith /* move command to work queue */ 114067555Smsmith#ifdef TWE_DEBUG 114160894Smsmith if (tr->tr_complete != NULL) { 1142118816Sps debug(3, "queued request %d with callback %p", cmd->generic.request_id, tr->tr_complete); 114367555Smsmith } else if (tr->tr_flags & TWE_CMD_SLEEPER) { 1144118816Sps debug(3, "queued request %d with wait channel %p", cmd->generic.request_id, tr); 114560894Smsmith } else { 1146118816Sps debug(3, "queued request %d for polling caller", cmd->generic.request_id); 114760894Smsmith } 114867555Smsmith#endif 1149239244Sjhb return(0); 1150240137Sjhb } else if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY) && i > 1) 1151240137Sjhb twe_done(sc, 0); 115260894Smsmith } 115360894Smsmith 115460894Smsmith /* 115560894Smsmith * We couldn't get the controller to take the command; try submitting it again later. 115660894Smsmith * This should only happen if something is wrong with the controller, or if we have 115760894Smsmith * overestimated the number of commands it can accept. (Should we actually reject 115860894Smsmith * the command at this point?) 115960894Smsmith */ 116060894Smsmith return(EBUSY); 116160894Smsmith} 116260894Smsmith 116360894Smsmith/******************************************************************************** 116460894Smsmith * Poll the controller (sc) for completed commands. 116560894Smsmith * 116660894Smsmith * Can be called at any interrupt level, with or without interrupts enabled. 116760894Smsmith */ 116860894Smsmithstatic void 1169240137Sjhbtwe_done(struct twe_softc *sc, int startio) 117060894Smsmith{ 117160894Smsmith TWE_Response_Queue rq; 1172118816Sps TWE_Command *cmd; 117360894Smsmith struct twe_request *tr; 1174239244Sjhb int found; 117560894Smsmith u_int32_t status_reg; 117660894Smsmith 117760894Smsmith debug_called(5); 117860894Smsmith 117960894Smsmith /* loop collecting completed commands */ 118060894Smsmith found = 0; 118160894Smsmith for (;;) { 118260894Smsmith status_reg = TWE_STATUS(sc); 118360894Smsmith twe_check_bits(sc, status_reg); /* XXX should this fail? */ 118460894Smsmith 118560894Smsmith if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) { 118660894Smsmith found = 1; 118760894Smsmith rq = TWE_RESPONSE_QUEUE(sc); 118867555Smsmith tr = sc->twe_lookup[rq.u.response_id]; /* find command */ 1189118816Sps cmd = TWE_FIND_COMMAND(tr); 119069543Smsmith if (tr->tr_status != TWE_CMD_BUSY) 119169543Smsmith twe_printf(sc, "completion event for nonbusy command\n"); 119269543Smsmith tr->tr_status = TWE_CMD_COMPLETE; 119369543Smsmith debug(3, "completed request id %d with status %d", 1194118816Sps cmd->generic.request_id, cmd->generic.status); 119569543Smsmith /* move to completed queue */ 119669543Smsmith twe_remove_busy(tr); 119769543Smsmith twe_enqueue_complete(tr); 1198130358Svkashyap sc->twe_state &= ~TWE_STATE_CTLR_BUSY; 119960894Smsmith } else { 120060894Smsmith break; /* no response ready */ 120160894Smsmith } 120260894Smsmith } 120360894Smsmith 120460894Smsmith /* if we've completed any commands, try posting some more */ 1205240137Sjhb if (found && startio) 120660894Smsmith twe_startio(sc); 120760894Smsmith 120860894Smsmith /* handle completion and timeouts */ 120967555Smsmith twe_complete(sc); /* XXX use deferred completion? */ 121060894Smsmith} 121160894Smsmith 121260894Smsmith/******************************************************************************** 121360894Smsmith * Perform post-completion processing for commands on (sc). 121460894Smsmith * 121560894Smsmith * This is split from twe_done as it can be safely deferred and run at a lower 121660894Smsmith * priority level should facilities for such a thing become available. 121760894Smsmith */ 121860894Smsmithstatic void 121960894Smsmithtwe_complete(struct twe_softc *sc) 122060894Smsmith{ 122167555Smsmith struct twe_request *tr; 122260894Smsmith 122360894Smsmith debug_called(5); 122460894Smsmith 122560894Smsmith /* 122667555Smsmith * Pull commands off the completed list, dispatch them appropriately 122760894Smsmith */ 122867555Smsmith while ((tr = twe_dequeue_complete(sc)) != NULL) { 122967555Smsmith /* unmap the command's data buffer */ 123067555Smsmith twe_unmap_request(tr); 123160894Smsmith 123267555Smsmith /* dispatch to suit command originator */ 123367555Smsmith if (tr->tr_complete != NULL) { /* completion callback */ 123467555Smsmith debug(2, "call completion handler %p", tr->tr_complete); 123567555Smsmith tr->tr_complete(tr); 123660894Smsmith 123767555Smsmith } else if (tr->tr_flags & TWE_CMD_SLEEPER) { /* caller is asleep waiting */ 123867555Smsmith debug(2, "wake up command owner on %p", tr); 123967555Smsmith wakeup_one(tr); 124060894Smsmith 124167555Smsmith } else { /* caller is polling command */ 124267555Smsmith debug(2, "command left for owner"); 124360894Smsmith } 124467555Smsmith } 124560894Smsmith} 124660894Smsmith 124760894Smsmith/******************************************************************************** 124860894Smsmith * Wait for (status) to be set in the controller status register for up to 124960894Smsmith * (timeout) seconds. Returns 0 if found, nonzero if we time out. 125060894Smsmith * 125160894Smsmith * Note: this busy-waits, rather than sleeping, since we may be called with 125260894Smsmith * eg. clock interrupts masked. 125360894Smsmith */ 125460894Smsmithstatic int 125560894Smsmithtwe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout) 125660894Smsmith{ 125760894Smsmith time_t expiry; 125860894Smsmith u_int32_t status_reg; 125960894Smsmith 126060894Smsmith debug_called(4); 126160894Smsmith 126260894Smsmith expiry = time_second + timeout; 126360894Smsmith 126460894Smsmith do { 126560894Smsmith status_reg = TWE_STATUS(sc); 126660894Smsmith if (status_reg & status) /* got the required bit(s)? */ 126760894Smsmith return(0); 126860894Smsmith DELAY(100000); 126960894Smsmith } while (time_second <= expiry); 127060894Smsmith 127160894Smsmith return(1); 127260894Smsmith} 127360894Smsmith 127460894Smsmith/******************************************************************************** 127560894Smsmith * Drain the response queue, which may contain responses to commands we know 127660894Smsmith * nothing about. 127760894Smsmith */ 127860894Smsmithstatic int 127960894Smsmithtwe_drain_response_queue(struct twe_softc *sc) 128060894Smsmith{ 128160894Smsmith TWE_Response_Queue rq; 128260894Smsmith u_int32_t status_reg; 128360894Smsmith 128460894Smsmith debug_called(4); 128560894Smsmith 128660894Smsmith for (;;) { /* XXX give up eventually? */ 128760894Smsmith status_reg = TWE_STATUS(sc); 128860894Smsmith if (twe_check_bits(sc, status_reg)) 128960894Smsmith return(1); 129060894Smsmith if (status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY) 129160894Smsmith return(0); 129260894Smsmith rq = TWE_RESPONSE_QUEUE(sc); 129360894Smsmith } 129460894Smsmith} 129560894Smsmith 129660894Smsmith/******************************************************************************** 129767555Smsmith * Soft-reset the controller 129867555Smsmith */ 129967555Smsmithstatic int 130067555Smsmithtwe_soft_reset(struct twe_softc *sc) 130167555Smsmith{ 130267555Smsmith u_int32_t status_reg; 130367555Smsmith 130467555Smsmith debug_called(2); 130567555Smsmith 1306239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 130767555Smsmith TWE_SOFT_RESET(sc); 130867555Smsmith 130991790Smsmith if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 30)) { 131067683Smsmith twe_printf(sc, "no attention interrupt\n"); 131167555Smsmith return(1); 131267555Smsmith } 131391790Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT); 131467555Smsmith if (twe_drain_aen_queue(sc)) { 131567555Smsmith twe_printf(sc, "can't drain AEN queue\n"); 131667555Smsmith return(1); 131767555Smsmith } 131867555Smsmith if (twe_find_aen(sc, TWE_AEN_SOFT_RESET)) { 131967555Smsmith twe_printf(sc, "reset not reported\n"); 132067555Smsmith return(1); 132167555Smsmith } 132267555Smsmith status_reg = TWE_STATUS(sc); 132367555Smsmith if (TWE_STATUS_ERRORS(status_reg) || twe_check_bits(sc, status_reg)) { 132467555Smsmith twe_printf(sc, "controller errors detected\n"); 132567555Smsmith return(1); 132667555Smsmith } 132767555Smsmith if (twe_drain_response_queue(sc)) { 132867555Smsmith twe_printf(sc, "can't drain response queue\n"); 132967555Smsmith return(1); 133067555Smsmith } 133167555Smsmith return(0); 133267555Smsmith} 133367555Smsmith 133467555Smsmith/******************************************************************************** 133560894Smsmith ******************************************************************************** 133660894Smsmith Interrupt Handling 133760894Smsmith ******************************************************************************** 133860894Smsmith ********************************************************************************/ 133960894Smsmith 134060894Smsmith/******************************************************************************** 134160894Smsmith * Host interrupt. 134260894Smsmith * 134360894Smsmith * XXX what does this mean? 134460894Smsmith */ 134560894Smsmithstatic void 134660894Smsmithtwe_host_intr(struct twe_softc *sc) 134760894Smsmith{ 134860894Smsmith debug_called(4); 134960894Smsmith 135067555Smsmith twe_printf(sc, "host interrupt\n"); 135160894Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_HOST_INTERRUPT); 135260894Smsmith} 135360894Smsmith 135460894Smsmith/******************************************************************************** 135560894Smsmith * Attention interrupt. 135660894Smsmith * 135760894Smsmith * Signalled when the controller has one or more AENs for us. 135860894Smsmith */ 135960894Smsmithstatic void 136060894Smsmithtwe_attention_intr(struct twe_softc *sc) 136160894Smsmith{ 136260894Smsmith debug_called(4); 136360894Smsmith 136460894Smsmith /* instigate a poll for AENs */ 136560894Smsmith if (twe_fetch_aen(sc)) { 136667555Smsmith twe_printf(sc, "error polling for signalled AEN\n"); 136760894Smsmith } else { 136860894Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT); 136960894Smsmith } 137060894Smsmith} 137160894Smsmith 137260894Smsmith/******************************************************************************** 137360894Smsmith * Command interrupt. 137460894Smsmith * 137560894Smsmith * Signalled when the controller can handle more commands. 137660894Smsmith */ 137760894Smsmithstatic void 137860894Smsmithtwe_command_intr(struct twe_softc *sc) 137960894Smsmith{ 138060894Smsmith debug_called(4); 138160894Smsmith 138260894Smsmith /* 138360894Smsmith * We don't use this, rather we try to submit commands when we receive 138460894Smsmith * them, and when other commands have completed. Mask it so we don't get 138560894Smsmith * another one. 138660894Smsmith */ 138760894Smsmith TWE_CONTROL(sc, TWE_CONTROL_MASK_COMMAND_INTERRUPT); 138860894Smsmith} 138960894Smsmith 139060894Smsmith/******************************************************************************** 139160894Smsmith ******************************************************************************** 139260894Smsmith Asynchronous Event Handling 139360894Smsmith ******************************************************************************** 139460894Smsmith ********************************************************************************/ 139560894Smsmith 139660894Smsmith/******************************************************************************** 139760894Smsmith * Request an AEN from the controller. 139860894Smsmith */ 139960894Smsmithstatic int 140060894Smsmithtwe_fetch_aen(struct twe_softc *sc) 140160894Smsmith{ 140260894Smsmith 140360894Smsmith debug_called(4); 140460894Smsmith 140567555Smsmith if ((twe_get_param(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 2, twe_handle_aen)) == NULL) 140660894Smsmith return(EIO); 140760894Smsmith return(0); 140860894Smsmith} 140960894Smsmith 141060894Smsmith/******************************************************************************** 141160894Smsmith * Handle an AEN returned by the controller. 141260894Smsmith */ 141360894Smsmithstatic void 141460894Smsmithtwe_handle_aen(struct twe_request *tr) 141560894Smsmith{ 141660894Smsmith struct twe_softc *sc = tr->tr_sc; 141760894Smsmith TWE_Param *param; 141860894Smsmith u_int16_t aen; 141960894Smsmith 142060894Smsmith debug_called(4); 142160894Smsmith 142260894Smsmith /* XXX check for command success somehow? */ 142360894Smsmith 142460894Smsmith param = (TWE_Param *)tr->tr_data; 142560894Smsmith aen = *(u_int16_t *)(param->data); 142660894Smsmith 142760894Smsmith free(tr->tr_data, M_DEVBUF); 142860894Smsmith twe_release_request(tr); 142960894Smsmith twe_enqueue_aen(sc, aen); 143060894Smsmith 143160894Smsmith /* XXX poll for more AENs? */ 143260894Smsmith} 143360894Smsmith 143460894Smsmith/******************************************************************************** 143560894Smsmith * Pull AENs out of the controller and park them in the queue, in a context where 143660894Smsmith * interrupts aren't active. Return nonzero if we encounter any errors in the 143760894Smsmith * process of obtaining all the available AENs. 143860894Smsmith */ 143960894Smsmithstatic int 144060894Smsmithtwe_drain_aen_queue(struct twe_softc *sc) 144160894Smsmith{ 144260894Smsmith u_int16_t aen; 144360894Smsmith 1444239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 144560894Smsmith for (;;) { 144667555Smsmith if (twe_get_param_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, &aen)) 144760894Smsmith return(1); 144860894Smsmith if (aen == TWE_AEN_QUEUE_EMPTY) 144960894Smsmith return(0); 145060894Smsmith twe_enqueue_aen(sc, aen); 145160894Smsmith } 145260894Smsmith} 145360894Smsmith 145460894Smsmith/******************************************************************************** 145560894Smsmith * Push an AEN that we've received onto the queue. 145660894Smsmith * 145760894Smsmith * Note that we have to lock this against reentrance, since it may be called 145860894Smsmith * from both interrupt and non-interrupt context. 145960894Smsmith * 146060894Smsmith * If someone is waiting for the AEN we have, wake them up. 146160894Smsmith */ 146260894Smsmithstatic void 146360894Smsmithtwe_enqueue_aen(struct twe_softc *sc, u_int16_t aen) 146460894Smsmith{ 146567555Smsmith char *msg; 1466239244Sjhb int next, nextnext; 146760894Smsmith 146860894Smsmith debug_called(4); 146960894Smsmith 1470239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 147167555Smsmith if ((msg = twe_format_aen(sc, aen)) != NULL) 147267555Smsmith twe_printf(sc, "AEN: <%s>\n", msg); 147360894Smsmith 147460894Smsmith /* enqueue the AEN */ 147560894Smsmith next = ((sc->twe_aen_head + 1) % TWE_Q_LENGTH); 147667555Smsmith nextnext = ((sc->twe_aen_head + 2) % TWE_Q_LENGTH); 147767555Smsmith 147867555Smsmith /* check to see if this is the last free slot, and subvert the AEN if it is */ 147967555Smsmith if (nextnext == sc->twe_aen_tail) 148067555Smsmith aen = TWE_AEN_QUEUE_FULL; 148167555Smsmith 148267555Smsmith /* look to see if there's room for this AEN */ 148360894Smsmith if (next != sc->twe_aen_tail) { 148460894Smsmith sc->twe_aen_queue[sc->twe_aen_head] = aen; 148560894Smsmith sc->twe_aen_head = next; 148660894Smsmith } 148760894Smsmith 148867555Smsmith /* wake up anyone asleep on the queue */ 148967555Smsmith wakeup(&sc->twe_aen_queue); 149067555Smsmith 149160894Smsmith /* anyone looking for this AEN? */ 149260894Smsmith if (sc->twe_wait_aen == aen) { 149360894Smsmith sc->twe_wait_aen = -1; 149460894Smsmith wakeup(&sc->twe_wait_aen); 149560894Smsmith } 149660894Smsmith} 149760894Smsmith 149860894Smsmith/******************************************************************************** 149960894Smsmith * Pop an AEN off the queue, or return -1 if there are none left. 150060894Smsmith * 150160894Smsmith * We are more or less interrupt-safe, so don't block interrupts. 150260894Smsmith */ 1503123103Spsstatic u_int16_t 150460894Smsmithtwe_dequeue_aen(struct twe_softc *sc) 150560894Smsmith{ 1506123103Sps u_int16_t result; 150760894Smsmith 150860894Smsmith debug_called(4); 150960894Smsmith 1510239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 151160894Smsmith if (sc->twe_aen_tail == sc->twe_aen_head) { 1512118508Sps result = TWE_AEN_QUEUE_EMPTY; 151360894Smsmith } else { 151460894Smsmith result = sc->twe_aen_queue[sc->twe_aen_tail]; 151560894Smsmith sc->twe_aen_tail = ((sc->twe_aen_tail + 1) % TWE_Q_LENGTH); 151660894Smsmith } 151760894Smsmith return(result); 151860894Smsmith} 151960894Smsmith 152060894Smsmith/******************************************************************************** 152160894Smsmith * Check to see if the requested AEN is in the queue. 152260894Smsmith * 152360894Smsmith * XXX we could probably avoid masking interrupts here 152460894Smsmith */ 152560894Smsmithstatic int 152660894Smsmithtwe_find_aen(struct twe_softc *sc, u_int16_t aen) 152760894Smsmith{ 1528239244Sjhb int i, missing; 152960894Smsmith 153060894Smsmith missing = 1; 153160894Smsmith for (i = sc->twe_aen_tail; (i != sc->twe_aen_head) && missing; i = (i + 1) % TWE_Q_LENGTH) { 153260894Smsmith if (sc->twe_aen_queue[i] == aen) 153360894Smsmith missing = 0; 153460894Smsmith } 153560894Smsmith return(missing); 153660894Smsmith} 153760894Smsmith 153860894Smsmith 153960894Smsmith#if 0 /* currently unused */ 154060894Smsmith/******************************************************************************** 154160894Smsmith * Sleep waiting for at least (timeout) seconds until we see (aen) as 154260894Smsmith * requested. Returns nonzero on timeout or failure. 154360894Smsmith * 154460894Smsmith * XXX: this should not be used in cases where there may be more than one sleeper 154560894Smsmith * without a mechanism for registering multiple sleepers. 154660894Smsmith */ 154760894Smsmithstatic int 154860894Smsmithtwe_wait_aen(struct twe_softc *sc, int aen, int timeout) 154960894Smsmith{ 155060894Smsmith time_t expiry; 1551239244Sjhb int found; 155260894Smsmith 155360894Smsmith debug_called(4); 155460894Smsmith 155560894Smsmith expiry = time_second + timeout; 155660894Smsmith found = 0; 155760894Smsmith 155860894Smsmith sc->twe_wait_aen = aen; 155960894Smsmith do { 156060894Smsmith twe_fetch_aen(sc); 1561239244Sjhb mtx_sleep(&sc->twe_wait_aen, &sc->twe_io_lock, PZERO, "twewaen", hz); 156260894Smsmith if (sc->twe_wait_aen == -1) 156360894Smsmith found = 1; 156460894Smsmith } while ((time_second <= expiry) && !found); 156560894Smsmith return(!found); 156660894Smsmith} 156760894Smsmith#endif 156860894Smsmith 156960894Smsmith/******************************************************************************** 157060894Smsmith ******************************************************************************** 157160894Smsmith Command Buffer Management 157260894Smsmith ******************************************************************************** 157360894Smsmith ********************************************************************************/ 157460894Smsmith 157560894Smsmith/******************************************************************************** 157660894Smsmith * Get a new command buffer. 157760894Smsmith * 157867555Smsmith * This will return NULL if all command buffers are in use. 157960894Smsmith */ 158067555Smsmithstatic int 158167555Smsmithtwe_get_request(struct twe_softc *sc, struct twe_request **tr) 158260894Smsmith{ 1583118816Sps TWE_Command *cmd; 158460894Smsmith debug_called(4); 158560894Smsmith 1586239244Sjhb if (!dumping) 1587239244Sjhb TWE_IO_ASSERT_LOCKED(sc); 1588239244Sjhb 158960894Smsmith /* try to reuse an old buffer */ 159067555Smsmith *tr = twe_dequeue_free(sc); 159160894Smsmith 159267555Smsmith /* initialise some fields to their defaults */ 159367555Smsmith if (*tr != NULL) { 1594118816Sps cmd = TWE_FIND_COMMAND(*tr); 159567555Smsmith (*tr)->tr_data = NULL; 159669543Smsmith (*tr)->tr_private = NULL; 159767555Smsmith (*tr)->tr_status = TWE_CMD_SETUP; /* command is in setup phase */ 159867555Smsmith (*tr)->tr_flags = 0; 159967555Smsmith (*tr)->tr_complete = NULL; 1600118816Sps cmd->generic.status = 0; /* before submission to controller */ 1601118816Sps cmd->generic.flags = 0; /* not used */ 160260894Smsmith } 160367555Smsmith return(*tr == NULL); 160460894Smsmith} 160560894Smsmith 160660894Smsmith/******************************************************************************** 160767555Smsmith * Release a command buffer for reuse. 160860894Smsmith * 160960894Smsmith */ 161060894Smsmithstatic void 161160894Smsmithtwe_release_request(struct twe_request *tr) 161260894Smsmith{ 161360894Smsmith debug_called(4); 161460894Smsmith 1615239244Sjhb if (!dumping) 1616239244Sjhb TWE_IO_ASSERT_LOCKED(tr->tr_sc); 161769543Smsmith if (tr->tr_private != NULL) 161869543Smsmith twe_panic(tr->tr_sc, "tr_private != NULL"); 161967555Smsmith twe_enqueue_free(tr); 162060894Smsmith} 162160894Smsmith 162260894Smsmith/******************************************************************************** 162367555Smsmith ******************************************************************************** 162467555Smsmith Debugging 162567555Smsmith ******************************************************************************** 162667555Smsmith ********************************************************************************/ 162760894Smsmith 162860894Smsmith/******************************************************************************** 162967555Smsmith * Print some information about the controller 163060894Smsmith */ 163167555Smsmithvoid 163267555Smsmithtwe_describe_controller(struct twe_softc *sc) 163360894Smsmith{ 163467555Smsmith TWE_Param *p[6]; 163567555Smsmith u_int8_t ports; 163667555Smsmith u_int32_t size; 163760894Smsmith int i; 163860894Smsmith 163967555Smsmith debug_called(2); 164060894Smsmith 1641239244Sjhb TWE_IO_LOCK(sc); 1642239244Sjhb 164367555Smsmith /* get the port count */ 164467555Smsmith twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports); 164560894Smsmith 164667555Smsmith /* get version strings */ 1647123103Sps p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW, 16, NULL); 1648123103Sps p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL); 1649123103Sps if (p[0] && p[1]) 1650123103Sps twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[0]->data, p[1]->data); 165160894Smsmith 1652123103Sps if (bootverbose) { 1653123103Sps p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon, 16, NULL); 1654123103Sps p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB, 8, NULL); 1655123103Sps p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA, 8, NULL); 1656123103Sps p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI, 8, NULL); 165760894Smsmith 1658123103Sps if (p[2] && p[3] && p[4] && p[5]) 1659123103Sps twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[2]->data, p[3]->data, 1660123103Sps p[4]->data, p[5]->data); 1661123103Sps if (p[2]) 1662123103Sps free(p[2], M_DEVBUF); 1663123103Sps if (p[3]) 1664123103Sps free(p[3], M_DEVBUF); 1665123103Sps if (p[4]) 1666123103Sps free(p[4], M_DEVBUF); 1667123103Sps if (p[5]) 1668123103Sps free(p[5], M_DEVBUF); 1669123103Sps } 1670123103Sps if (p[0]) 1671123103Sps free(p[0], M_DEVBUF); 1672123103Sps if (p[1]) 1673123103Sps free(p[1], M_DEVBUF); 1674123103Sps 167567555Smsmith /* print attached drives */ 167667555Smsmith if (bootverbose) { 167767555Smsmith p[0] = twe_get_param(sc, TWE_PARAM_DRIVESUMMARY, TWE_PARAM_DRIVESUMMARY_Status, 16, NULL); 167867555Smsmith for (i = 0; i < ports; i++) { 167967555Smsmith if (p[0]->data[i] != TWE_PARAM_DRIVESTATUS_Present) 168067555Smsmith continue; 168167555Smsmith twe_get_param_4(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Size, &size); 168267555Smsmith p[1] = twe_get_param(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Model, 40, NULL); 168367555Smsmith if (p[1] != NULL) { 168467555Smsmith twe_printf(sc, "port %d: %.40s %dMB\n", i, p[1]->data, size / 2048); 168567555Smsmith free(p[1], M_DEVBUF); 168667555Smsmith } else { 168767555Smsmith twe_printf(sc, "port %d, drive status unavailable\n", i); 168867555Smsmith } 168960894Smsmith } 1690123103Sps if (p[0]) 1691123103Sps free(p[0], M_DEVBUF); 169260894Smsmith } 1693239244Sjhb TWE_IO_UNLOCK(sc); 169460894Smsmith} 169560894Smsmith 169660894Smsmith/******************************************************************************** 1697123103Sps * Look up a text description of a numeric code and return a pointer to same. 1698123103Sps */ 1699123103Spschar * 1700123103Spstwe_describe_code(struct twe_code_lookup *table, u_int32_t code) 1701123103Sps{ 1702123103Sps int i; 1703123103Sps 1704123103Sps for (i = 0; table[i].string != NULL; i++) 1705123103Sps if (table[i].code == code) 1706123103Sps return(table[i].string); 1707123103Sps return(table[i+1].string); 1708123103Sps} 1709123103Sps 1710123103Sps/******************************************************************************** 171160894Smsmith * Complain if the status bits aren't what we're expecting. 171267555Smsmith * 171367555Smsmith * Rate-limit the complaints to at most one of each every five seconds, but 171467555Smsmith * always return the correct status. 171560894Smsmith */ 171660894Smsmithstatic int 171760894Smsmithtwe_check_bits(struct twe_softc *sc, u_int32_t status_reg) 171860894Smsmith{ 171967555Smsmith int result; 172067555Smsmith static time_t lastwarn[2] = {0, 0}; 172160894Smsmith 172267555Smsmith /* 172367555Smsmith * This can be a little problematic, as twe_panic may call twe_reset if 172467555Smsmith * TWE_DEBUG is not set, which will call us again as part of the soft reset. 172567555Smsmith */ 172667555Smsmith if ((status_reg & TWE_STATUS_PANIC_BITS) != 0) { 172767555Smsmith twe_printf(sc, "FATAL STATUS BIT(S) %b\n", status_reg & TWE_STATUS_PANIC_BITS, 172867555Smsmith TWE_STATUS_BITS_DESCRIPTION); 172967555Smsmith twe_panic(sc, "fatal status bits"); 173067555Smsmith } 173167555Smsmith 173260894Smsmith result = 0; 173360894Smsmith if ((status_reg & TWE_STATUS_EXPECTED_BITS) != TWE_STATUS_EXPECTED_BITS) { 173467555Smsmith if (time_second > (lastwarn[0] + 5)) { 173567555Smsmith twe_printf(sc, "missing expected status bit(s) %b\n", ~status_reg & TWE_STATUS_EXPECTED_BITS, 173667555Smsmith TWE_STATUS_BITS_DESCRIPTION); 173767555Smsmith lastwarn[0] = time_second; 173867555Smsmith } 173960894Smsmith result = 1; 174060894Smsmith } 174160894Smsmith 174260894Smsmith if ((status_reg & TWE_STATUS_UNEXPECTED_BITS) != 0) { 174367555Smsmith if (time_second > (lastwarn[1] + 5)) { 174467555Smsmith twe_printf(sc, "unexpected status bit(s) %b\n", status_reg & TWE_STATUS_UNEXPECTED_BITS, 174567555Smsmith TWE_STATUS_BITS_DESCRIPTION); 174667555Smsmith lastwarn[1] = time_second; 174767555Smsmith } 174860894Smsmith result = 1; 174991790Smsmith if (status_reg & TWE_STATUS_PCI_PARITY_ERROR) { 1750176200Sbrueffer twe_printf(sc, "PCI parity error: Reseat card, move card or buggy device present.\n"); 175191790Smsmith twe_clear_pci_parity_error(sc); 175291790Smsmith } 175391790Smsmith if (status_reg & TWE_STATUS_PCI_ABORT) { 1754118816Sps twe_printf(sc, "PCI abort, clearing.\n"); 175591790Smsmith twe_clear_pci_abort(sc); 175691790Smsmith } 175760894Smsmith } 175867555Smsmith 175960894Smsmith return(result); 176060894Smsmith} 176160894Smsmith 176260894Smsmith/******************************************************************************** 176367555Smsmith * Return a string describing (aen). 176467555Smsmith * 176567555Smsmith * The low 8 bits of the aen are the code, the high 8 bits give the unit number 176667555Smsmith * where an AEN is specific to a unit. 176767555Smsmith * 176867555Smsmith * Note that we could expand this routine to handle eg. up/downgrading the status 176967555Smsmith * of a drive if we had some idea of what the drive's initial status was. 177060894Smsmith */ 177160894Smsmith 177260894Smsmithstatic char * 177367555Smsmithtwe_format_aen(struct twe_softc *sc, u_int16_t aen) 177460894Smsmith{ 177567555Smsmith device_t child; 177667555Smsmith char *code, *msg; 177760894Smsmith 177867555Smsmith code = twe_describe_code(twe_table_aen, TWE_AEN_CODE(aen)); 177967555Smsmith msg = code + 2; 178060894Smsmith 178167555Smsmith switch (*code) { 178267555Smsmith case 'q': 178367555Smsmith if (!bootverbose) 178467555Smsmith return(NULL); 178567555Smsmith /* FALLTHROUGH */ 178691790Smsmith case 'a': 178767555Smsmith return(msg); 178867555Smsmith 178967555Smsmith case 'c': 179067555Smsmith if ((child = sc->twe_drive[TWE_AEN_UNIT(aen)].td_disk) != NULL) { 1791240137Sjhb snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "twed%d: %s", 1792240137Sjhb device_get_unit(child), msg); 179367555Smsmith } else { 1794240137Sjhb snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), 1795240137Sjhb "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev), 1796240137Sjhb msg, TWE_AEN_UNIT(aen)); 179767555Smsmith } 1798240137Sjhb return(sc->twe_aen_buf); 179991790Smsmith 180091790Smsmith case 'p': 1801240137Sjhb snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), 1802240137Sjhb "twe%d: port %d: %s", device_get_unit(sc->twe_dev), 1803240137Sjhb TWE_AEN_UNIT(aen), msg); 1804240137Sjhb return(sc->twe_aen_buf); 180591790Smsmith 180667555Smsmith 180767555Smsmith case 'x': 180867555Smsmith default: 180967555Smsmith break; 181067555Smsmith } 1811240137Sjhb snprintf(sc->twe_aen_buf, sizeof(sc->twe_aen_buf), "unknown AEN 0x%x", aen); 1812240137Sjhb return(sc->twe_aen_buf); 181360894Smsmith} 181460894Smsmith 181569543Smsmith/******************************************************************************** 181669543Smsmith * Print a diagnostic if the status of the command warrants it, and return 181769543Smsmith * either zero (command was ok) or nonzero (command failed). 181869543Smsmith */ 181967555Smsmithstatic int 182069543Smsmithtwe_report_request(struct twe_request *tr) 182167555Smsmith{ 182269543Smsmith struct twe_softc *sc = tr->tr_sc; 1823118816Sps TWE_Command *cmd = TWE_FIND_COMMAND(tr); 182476340Smsmith int result = 0; 182560894Smsmith 182676340Smsmith /* 182776340Smsmith * Check the command status value and handle accordingly. 182876340Smsmith */ 182976340Smsmith if (cmd->generic.status == TWE_STATUS_RESET) { 183076340Smsmith /* 183176340Smsmith * The status code 0xff requests a controller reset. 183276340Smsmith */ 1833123103Sps twe_printf(sc, "command returned with controller reset request\n"); 183476340Smsmith twe_reset(sc); 183569543Smsmith result = 1; 183676340Smsmith } else if (cmd->generic.status > TWE_STATUS_FATAL) { 183769543Smsmith /* 183876340Smsmith * Fatal errors that don't require controller reset. 183991790Smsmith * 184091790Smsmith * We know a few special flags values. 184169543Smsmith */ 184291790Smsmith switch (cmd->generic.flags) { 184391790Smsmith case 0x1b: 184491790Smsmith device_printf(sc->twe_drive[cmd->generic.unit].td_disk, 184591790Smsmith "drive timeout"); 184691790Smsmith break; 184791790Smsmith case 0x51: 184891790Smsmith device_printf(sc->twe_drive[cmd->generic.unit].td_disk, 184991790Smsmith "unrecoverable drive error"); 185091790Smsmith break; 185191790Smsmith default: 185291790Smsmith device_printf(sc->twe_drive[cmd->generic.unit].td_disk, 185391790Smsmith "controller error - %s (flags = 0x%x)\n", 185491790Smsmith twe_describe_code(twe_table_status, cmd->generic.status), 185591790Smsmith cmd->generic.flags); 185691790Smsmith result = 1; 185791790Smsmith } 185876340Smsmith } else if (cmd->generic.status > TWE_STATUS_WARNING) { 185976340Smsmith /* 186076340Smsmith * Warning level status. 186176340Smsmith */ 186291790Smsmith device_printf(sc->twe_drive[cmd->generic.unit].td_disk, 186391790Smsmith "warning - %s (flags = 0x%x)\n", 186491790Smsmith twe_describe_code(twe_table_status, cmd->generic.status), 186591790Smsmith cmd->generic.flags); 186676340Smsmith } else if (cmd->generic.status > 0x40) { 186776340Smsmith /* 186876340Smsmith * Info level status. 186976340Smsmith */ 187091790Smsmith device_printf(sc->twe_drive[cmd->generic.unit].td_disk, 187191790Smsmith "attention - %s (flags = 0x%x)\n", 187291790Smsmith twe_describe_code(twe_table_status, cmd->generic.status), 187391790Smsmith cmd->generic.flags); 187467555Smsmith } 187576340Smsmith 187669543Smsmith return(result); 187767555Smsmith} 187867555Smsmith 187969543Smsmith/******************************************************************************** 188069543Smsmith * Print some controller state to aid in debugging error/panic conditions 188169543Smsmith */ 188267555Smsmithvoid 188367555Smsmithtwe_print_controller(struct twe_softc *sc) 188460894Smsmith{ 188567555Smsmith u_int32_t status_reg; 188660894Smsmith 188767555Smsmith status_reg = TWE_STATUS(sc); 188867555Smsmith twe_printf(sc, "status %b\n", status_reg, TWE_STATUS_BITS_DESCRIPTION); 1889123103Sps twe_printf(sc, " current max min\n"); 1890123103Sps twe_printf(sc, "free %04d %04d %04d\n", 1891123103Sps sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max, sc->twe_qstat[TWEQ_FREE].q_min); 1892123103Sps 1893123103Sps twe_printf(sc, "ready %04d %04d %04d\n", 1894123103Sps sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max, sc->twe_qstat[TWEQ_READY].q_min); 1895123103Sps 1896123103Sps twe_printf(sc, "busy %04d %04d %04d\n", 1897123103Sps sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max, sc->twe_qstat[TWEQ_BUSY].q_min); 1898123103Sps 1899123103Sps twe_printf(sc, "complete %04d %04d %04d\n", 1900123103Sps sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max, sc->twe_qstat[TWEQ_COMPLETE].q_min); 1901123103Sps 1902123103Sps twe_printf(sc, "bioq %04d %04d %04d\n", 1903123103Sps sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max, sc->twe_qstat[TWEQ_BIO].q_min); 1904123103Sps 190567555Smsmith twe_printf(sc, "AEN queue head %d tail %d\n", sc->twe_aen_head, sc->twe_aen_tail); 190667555Smsmith} 190760894Smsmith 190867555Smsmithstatic void 190967555Smsmithtwe_panic(struct twe_softc *sc, char *reason) 191067555Smsmith{ 191167555Smsmith twe_print_controller(sc); 191267555Smsmith#ifdef TWE_DEBUG 191367555Smsmith panic(reason); 191467555Smsmith#else 191567555Smsmith twe_reset(sc); 191667555Smsmith#endif 191760894Smsmith} 191860894Smsmith 1919127415Svkashyap#if 0 192060894Smsmith/******************************************************************************** 192160894Smsmith * Print a request/command in human-readable format. 192260894Smsmith */ 192360894Smsmithstatic void 192460894Smsmithtwe_print_request(struct twe_request *tr) 192560894Smsmith{ 192667555Smsmith struct twe_softc *sc = tr->tr_sc; 1927118816Sps TWE_Command *cmd = TWE_FIND_COMMAND(tr); 192860894Smsmith int i; 192960894Smsmith 193067555Smsmith twe_printf(sc, "CMD: request_id %d opcode <%s> size %d unit %d host_id %d\n", 193167555Smsmith cmd->generic.request_id, twe_describe_code(twe_table_opcode, cmd->generic.opcode), cmd->generic.size, 193267555Smsmith cmd->generic.unit, cmd->generic.host_id); 193367555Smsmith twe_printf(sc, " status %d flags 0x%x count %d sgl_offset %d\n", 193467555Smsmith cmd->generic.status, cmd->generic.flags, cmd->generic.count, cmd->generic.sgl_offset); 193567555Smsmith 193667555Smsmith switch(cmd->generic.opcode) { /* XXX add more opcodes? */ 193767555Smsmith case TWE_OP_READ: 193867555Smsmith case TWE_OP_WRITE: 193967555Smsmith twe_printf(sc, " lba %d\n", cmd->io.lba); 194067555Smsmith for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->io.sgl[i].length != 0); i++) 194167555Smsmith twe_printf(sc, " %d: 0x%x/%d\n", 194267555Smsmith i, cmd->io.sgl[i].address, cmd->io.sgl[i].length); 194360894Smsmith break; 194460894Smsmith 194567555Smsmith case TWE_OP_GET_PARAM: 194667555Smsmith case TWE_OP_SET_PARAM: 194767555Smsmith for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->param.sgl[i].length != 0); i++) 194867555Smsmith twe_printf(sc, " %d: 0x%x/%d\n", 194967555Smsmith i, cmd->param.sgl[i].address, cmd->param.sgl[i].length); 195060894Smsmith break; 195160894Smsmith 195267555Smsmith case TWE_OP_INIT_CONNECTION: 195367555Smsmith twe_printf(sc, " response queue pointer 0x%x\n", 195467555Smsmith cmd->initconnection.response_queue_pointer); 195567555Smsmith break; 195667555Smsmith 195760894Smsmith default: 195867555Smsmith break; 195960894Smsmith } 196067555Smsmith twe_printf(sc, " tr_command %p/0x%x tr_data %p/0x%x,%d\n", 1961118816Sps tr, TWE_FIND_COMMANDPHYS(tr), tr->tr_data, tr->tr_dataphys, tr->tr_length); 196267555Smsmith twe_printf(sc, " tr_status %d tr_flags 0x%x tr_complete %p tr_private %p\n", 196367555Smsmith tr->tr_status, tr->tr_flags, tr->tr_complete, tr->tr_private); 196460894Smsmith} 196560894Smsmith 196660894Smsmith#endif 1967