twe.c revision 73104
160894Smsmith/*- 260894Smsmith * Copyright (c) 2000 Michael Smith 360894Smsmith * Copyright (c) 2000 BSDi 460894Smsmith * All rights reserved. 560894Smsmith * 660894Smsmith * Redistribution and use in source and binary forms, with or without 760894Smsmith * modification, are permitted provided that the following conditions 860894Smsmith * are met: 960894Smsmith * 1. Redistributions of source code must retain the above copyright 1060894Smsmith * notice, this list of conditions and the following disclaimer. 1160894Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1260894Smsmith * notice, this list of conditions and the following disclaimer in the 1360894Smsmith * documentation and/or other materials provided with the distribution. 1460894Smsmith * 1560894Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1660894Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1760894Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1860894Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1960894Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2060894Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2160894Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2260894Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2360894Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2460894Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2560894Smsmith * SUCH DAMAGE. 2660894Smsmith * 2760894Smsmith * $FreeBSD: head/sys/dev/twe/twe.c 73104 2001-02-26 20:13:19Z msmith $ 2860894Smsmith */ 2960894Smsmith 3060894Smsmith/* 3160894Smsmith * Driver for the 3ware Escalade family of IDE RAID controllers. 3260894Smsmith */ 3360894Smsmith 3467555Smsmith#include <dev/twe/twe_compat.h> 3560894Smsmith#include <dev/twe/twereg.h> 3667555Smsmith#include <dev/twe/tweio.h> 3760894Smsmith#include <dev/twe/twevar.h> 3867555Smsmith#define TWE_DEFINE_TABLES 3967555Smsmith#include <dev/twe/twe_tables.h> 4060894Smsmith 4160894Smsmith/* 4260894Smsmith * Command submission. 4360894Smsmith */ 4467555Smsmithstatic int twe_get_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t *result); 4567555Smsmithstatic int twe_get_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t *result); 4667555Smsmithstatic int twe_get_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t *result); 4767555Smsmithstatic void *twe_get_param(struct twe_softc *sc, int table_id, int parameter_id, size_t size, 4860894Smsmith void (* func)(struct twe_request *tr)); 4967555Smsmithstatic int twe_set_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t value); 5067555Smsmithstatic int twe_set_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t value); 5167555Smsmithstatic int twe_set_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t value); 5267555Smsmithstatic int twe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, 5367555Smsmith void *data); 5467555Smsmithstatic int twe_init_connection(struct twe_softc *sc, int mode); 5567555Smsmithstatic int twe_wait_request(struct twe_request *tr); 5667555Smsmithstatic int twe_immediate_request(struct twe_request *tr); 5767555Smsmithstatic void twe_completeio(struct twe_request *tr); 5867555Smsmithstatic void twe_reset(struct twe_softc *sc); 5960894Smsmith 6060894Smsmith/* 6160894Smsmith * Command I/O to controller. 6260894Smsmith */ 6367555Smsmithstatic int twe_start(struct twe_request *tr); 6467555Smsmithstatic void twe_done(struct twe_softc *sc); 6567555Smsmithstatic void twe_complete(struct twe_softc *sc); 6667555Smsmithstatic int twe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout); 6767555Smsmithstatic int twe_drain_response_queue(struct twe_softc *sc); 6867555Smsmithstatic int twe_check_bits(struct twe_softc *sc, u_int32_t status_reg); 6967555Smsmithstatic int twe_soft_reset(struct twe_softc *sc); 7060894Smsmith 7160894Smsmith/* 7260894Smsmith * Interrupt handling. 7360894Smsmith */ 7467555Smsmithstatic void twe_host_intr(struct twe_softc *sc); 7567555Smsmithstatic void twe_attention_intr(struct twe_softc *sc); 7667555Smsmithstatic void twe_command_intr(struct twe_softc *sc); 7760894Smsmith 7860894Smsmith/* 7960894Smsmith * Asynchronous event handling. 8060894Smsmith */ 8167555Smsmithstatic int twe_fetch_aen(struct twe_softc *sc); 8267555Smsmithstatic void twe_handle_aen(struct twe_request *tr); 8367555Smsmithstatic void twe_enqueue_aen(struct twe_softc *sc, u_int16_t aen); 8467555Smsmithstatic int twe_dequeue_aen(struct twe_softc *sc); 8567555Smsmithstatic int twe_drain_aen_queue(struct twe_softc *sc); 8667555Smsmithstatic int twe_find_aen(struct twe_softc *sc, u_int16_t aen); 8760894Smsmith 8860894Smsmith/* 8960894Smsmith * Command buffer management. 9060894Smsmith */ 9167555Smsmithstatic int twe_get_request(struct twe_softc *sc, struct twe_request **tr); 9267555Smsmithstatic void twe_release_request(struct twe_request *tr); 9360894Smsmith 9460894Smsmith/* 9560894Smsmith * Debugging. 9660894Smsmith */ 9767555Smsmithstatic char *twe_format_aen(struct twe_softc *sc, u_int16_t aen); 9869543Smsmithstatic int twe_report_request(struct twe_request *tr); 9967555Smsmithstatic void twe_panic(struct twe_softc *sc, char *reason); 10060894Smsmith 10160894Smsmith/******************************************************************************** 10260894Smsmith ******************************************************************************** 10360894Smsmith Public Interfaces 10460894Smsmith ******************************************************************************** 10560894Smsmith ********************************************************************************/ 10660894Smsmith 10760894Smsmith/******************************************************************************** 10867555Smsmith * Initialise the controller, set up driver data structures. 10960894Smsmith */ 11067555Smsmithint 11167555Smsmithtwe_setup(struct twe_softc *sc) 11260894Smsmith{ 11360894Smsmith struct twe_request *tr; 11467555Smsmith int i; 11560894Smsmith 11660894Smsmith debug_called(4); 11760894Smsmith 11860894Smsmith /* 11967555Smsmith * Initialise request queues. 12060894Smsmith */ 12167555Smsmith twe_initq_free(sc); 12267555Smsmith twe_initq_bio(sc); 12367555Smsmith twe_initq_ready(sc); 12467555Smsmith twe_initq_busy(sc); 12567555Smsmith twe_initq_complete(sc); 12667555Smsmith sc->twe_wait_aen = -1; 12760894Smsmith 12860894Smsmith /* 12967555Smsmith * Allocate request structures up front. 13060894Smsmith */ 13167555Smsmith for (i = 0; i < TWE_Q_LENGTH; i++) { 13267555Smsmith if ((tr = twe_allocate_request(sc)) == NULL) 13367555Smsmith return(ENOMEM); 13467555Smsmith /* 13567555Smsmith * Set global defaults that won't change. 13667555Smsmith */ 13767555Smsmith tr->tr_command.generic.host_id = sc->twe_host_id; /* controller-assigned host ID */ 13867555Smsmith tr->tr_command.generic.request_id = i; /* our index number */ 13967555Smsmith sc->twe_lookup[i] = tr; 14060894Smsmith 14167555Smsmith /* 14267555Smsmith * Put command onto the freelist. 14367555Smsmith */ 14467555Smsmith twe_release_request(tr); 14560894Smsmith } 14660894Smsmith 14760894Smsmith /* 14867555Smsmith * Wait for the controller to come ready. 14960894Smsmith */ 15067555Smsmith if (twe_wait_status(sc, TWE_STATUS_MICROCONTROLLER_READY, 60)) { 15167555Smsmith twe_printf(sc, "microcontroller not ready\n"); 15260894Smsmith return(ENXIO); 15360894Smsmith } 15460894Smsmith 15560894Smsmith /* 15667555Smsmith * Disable interrupts from the card. 15760894Smsmith */ 15867555Smsmith twe_disable_interrupts(sc); 15960894Smsmith 16060894Smsmith /* 16167555Smsmith * Soft reset the controller, look for the AEN acknowledging the reset, 16267555Smsmith * check for errors, drain the response queue. 16360894Smsmith */ 16467555Smsmith for (i = 0; i < TWE_MAX_RESET_TRIES; i++) { 16560894Smsmith 16667555Smsmith if (i > 0) 16767555Smsmith twe_printf(sc, "reset %d failed, trying again\n", i); 16867555Smsmith 16967555Smsmith if (!twe_soft_reset(sc)) 17067555Smsmith break; /* reset process complete */ 17167555Smsmith } 17267555Smsmith /* did we give up? */ 17367555Smsmith if (i >= TWE_MAX_RESET_TRIES) { 17467555Smsmith twe_printf(sc, "can't initialise controller, giving up\n"); 17560894Smsmith return(ENXIO); 17660894Smsmith } 17760894Smsmith 17860894Smsmith return(0); 17960894Smsmith} 18060894Smsmith 18160894Smsmith/******************************************************************************** 18267555Smsmith * Locate disk devices and attach children to them. 18360894Smsmith */ 18467555Smsmithvoid 18567555Smsmithtwe_init(struct twe_softc *sc) 18660894Smsmith{ 18760894Smsmith struct twe_drive *dr; 18867555Smsmith int i, table; 18967555Smsmith u_int16_t dsize; 19067555Smsmith TWE_Param *drives, *param; 19167555Smsmith TWE_Unit_Descriptor *ud; 19260894Smsmith 19360894Smsmith 19460894Smsmith /* 19567555Smsmith * The controller is in a safe state, so try to find drives attached to it. 19660894Smsmith */ 19767555Smsmith if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status, 19867555Smsmith TWE_MAX_UNITS, NULL)) == NULL) { 19967555Smsmith twe_printf(sc, "can't detect attached units\n"); 20060894Smsmith return; 20160894Smsmith } 20267555Smsmith 20360894Smsmith /* 20467555Smsmith * For each detected unit, create a child device. 20560894Smsmith */ 20667555Smsmith for (i = 0, dr = &sc->twe_drive[0]; i < TWE_MAX_UNITS; i++, dr++) { 20760894Smsmith 20867555Smsmith /* check that the drive is online */ 20967555Smsmith if (!(drives->data[i] & TWE_PARAM_UNITSTATUS_Online)) 21067555Smsmith continue; 21160894Smsmith 21267555Smsmith table = TWE_PARAM_UNITINFO + i; 21360894Smsmith 21467555Smsmith if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) { 21567555Smsmith twe_printf(sc, "error fetching capacity for unit %d\n", i); 21660894Smsmith continue; 21760894Smsmith } 21867555Smsmith if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) { 21967555Smsmith twe_printf(sc, "error fetching state for unit %d\n", i); 22060894Smsmith continue; 22160894Smsmith } 22267555Smsmith if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) { 22367555Smsmith twe_printf(sc, "error fetching descriptor size for unit %d\n", i); 22460894Smsmith continue; 22560894Smsmith } 22667555Smsmith if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) { 22767555Smsmith twe_printf(sc, "error fetching descriptor for unit %d\n", i); 22860894Smsmith continue; 22960894Smsmith } 23067555Smsmith ud = (TWE_Unit_Descriptor *)param->data; 23167555Smsmith dr->td_type = ud->configuration; 23267555Smsmith free(param, M_DEVBUF); 23360894Smsmith 23460894Smsmith /* build synthetic geometry as per controller internal rules */ 23560894Smsmith if (dr->td_size > 0x200000) { 23660894Smsmith dr->td_heads = 255; 23760894Smsmith dr->td_sectors = 63; 23860894Smsmith } else { 23960894Smsmith dr->td_heads = 64; 24060894Smsmith dr->td_sectors = 32; 24160894Smsmith } 24260894Smsmith dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors); 24360894Smsmith dr->td_unit = i; 24460894Smsmith 24567555Smsmith twe_attach_drive(sc, dr); 24660894Smsmith } 24760894Smsmith free(drives, M_DEVBUF); 24860894Smsmith 24960894Smsmith /* 25060894Smsmith * Initialise connection with controller. 25160894Smsmith */ 25267555Smsmith twe_init_connection(sc, TWE_INIT_MESSAGE_CREDITS); 25360894Smsmith 25467555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION 25567555Smsmith /* 25667555Smsmith * Tell the controller we support shutdown notification. 25767555Smsmith */ 25867555Smsmith twe_set_param_1(sc, TWE_PARAM_FEATURES, TWE_PARAM_FEATURES_DriverShutdown, 1); 25967555Smsmith#endif 26067555Smsmith 26160894Smsmith /* 26260894Smsmith * Mark controller up and ready to run. 26360894Smsmith */ 26460894Smsmith sc->twe_state &= ~TWE_STATE_SHUTDOWN; 26560894Smsmith 26660894Smsmith /* 26767555Smsmith * Finally enable interrupts. 26860894Smsmith */ 26960894Smsmith twe_enable_interrupts(sc); 27060894Smsmith} 27160894Smsmith 27260894Smsmith/******************************************************************************** 27367555Smsmith * Stop the controller 27460894Smsmith */ 27567555Smsmithvoid 27667555Smsmithtwe_deinit(struct twe_softc *sc) 27760894Smsmith{ 27860894Smsmith /* 27960894Smsmith * Mark the controller as shutting down, and disable any further interrupts. 28060894Smsmith */ 28160894Smsmith sc->twe_state |= TWE_STATE_SHUTDOWN; 28260894Smsmith twe_disable_interrupts(sc); 28360894Smsmith 28467555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION 28567555Smsmith /* 28667555Smsmith * Disconnect from the controller 28760894Smsmith */ 28867555Smsmith twe_init_connection(sc, TWE_SHUTDOWN_MESSAGE_CREDITS); 28967555Smsmith#endif 29060894Smsmith} 29160894Smsmith 29260894Smsmith/******************************************************************************* 29360894Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy 29460894Smsmith * status. 29560894Smsmith */ 29667555Smsmithvoid 29767555Smsmithtwe_intr(struct twe_softc *sc) 29860894Smsmith{ 29960894Smsmith u_int32_t status_reg; 30060894Smsmith 30160894Smsmith debug_called(4); 30260894Smsmith 30360894Smsmith /* 30460894Smsmith * Collect current interrupt status. 30560894Smsmith */ 30660894Smsmith status_reg = TWE_STATUS(sc); 30760894Smsmith twe_check_bits(sc, status_reg); 30860894Smsmith 30960894Smsmith /* 31060894Smsmith * Dispatch based on interrupt status 31160894Smsmith */ 31260894Smsmith if (status_reg & TWE_STATUS_HOST_INTERRUPT) 31360894Smsmith twe_host_intr(sc); 31460894Smsmith if (status_reg & TWE_STATUS_ATTENTION_INTERRUPT) 31560894Smsmith twe_attention_intr(sc); 31660894Smsmith if (status_reg & TWE_STATUS_COMMAND_INTERRUPT) 31760894Smsmith twe_command_intr(sc); 31873104Smsmith if (status_reg & TWE_STATUS_RESPONSE_INTERRUPT) 31960894Smsmith twe_done(sc); 32060894Smsmith}; 32160894Smsmith 32269543Smsmith/******************************************************************************** 32369543Smsmith * Pull as much work off the softc's work queue as possible and give it to the 32469543Smsmith * controller. 32560894Smsmith */ 32669543Smsmithvoid 32769543Smsmithtwe_startio(struct twe_softc *sc) 32860894Smsmith{ 32969543Smsmith struct twe_request *tr; 33069543Smsmith TWE_Command *cmd; 33169543Smsmith twe_bio *bp; 33269543Smsmith int error; 33369543Smsmith 33467555Smsmith debug_called(4); 33560894Smsmith 33669543Smsmith /* spin until something prevents us from doing any work */ 33769543Smsmith for (;;) { 33867555Smsmith 33969543Smsmith /* try to get a command that's already ready to go */ 34069543Smsmith tr = twe_dequeue_ready(sc); 34169543Smsmith 34269543Smsmith /* build a command from an outstanding bio */ 34369543Smsmith if (tr == NULL) { 34469543Smsmith 34569543Smsmith /* see if there's work to be done */ 34669543Smsmith if ((bp = twe_dequeue_bio(sc)) == NULL) 34769543Smsmith break; 34869543Smsmith 34969543Smsmith /* get a command to handle the bio with */ 35069543Smsmith if (twe_get_request(sc, &tr)) { 35169543Smsmith twe_enqueue_bio(sc, bp); /* failed, put the bio back */ 35269543Smsmith break; 35369543Smsmith } 35469543Smsmith 35569543Smsmith /* connect the bio to the command */ 35669543Smsmith tr->tr_complete = twe_completeio; 35769543Smsmith tr->tr_private = bp; 35869543Smsmith tr->tr_data = TWE_BIO_DATA(bp); 35969543Smsmith tr->tr_length = TWE_BIO_LENGTH(bp); 36069543Smsmith cmd = &tr->tr_command; 36169543Smsmith if (TWE_BIO_IS_READ(bp)) { 36269543Smsmith tr->tr_flags |= TWE_CMD_DATAIN; 36369543Smsmith cmd->io.opcode = TWE_OP_READ; 36469543Smsmith } else { 36569543Smsmith tr->tr_flags |= TWE_CMD_DATAOUT; 36669543Smsmith cmd->io.opcode = TWE_OP_WRITE; 36769543Smsmith } 36869543Smsmith 36969543Smsmith /* build a suitable I/O command (assumes 512-byte rounded transfers) */ 37069543Smsmith cmd->io.size = 3; 37169543Smsmith cmd->io.unit = TWE_BIO_UNIT(bp); 37269543Smsmith cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE; 37369543Smsmith cmd->io.lba = TWE_BIO_LBA(bp); 37469543Smsmith 37569543Smsmith /* map the command so the controller can work with it */ 37669543Smsmith twe_map_request(tr); 37769543Smsmith } 37869543Smsmith 37969543Smsmith /* did we find something to do? */ 38069543Smsmith if (tr == NULL) 38169543Smsmith break; 38269543Smsmith 38369543Smsmith /* try to give command to controller */ 38469543Smsmith error = twe_start(tr); 38569543Smsmith 38669543Smsmith if (error != 0) { 38769543Smsmith if (error == EBUSY) { 38869543Smsmith twe_requeue_ready(tr); /* try it again later */ 38969543Smsmith break; /* don't try anything more for now */ 39069543Smsmith } 39169543Smsmith /* we don't support any other return from twe_start */ 39269543Smsmith twe_panic(sc, "twe_start returned nonsense"); 39369543Smsmith } 39469543Smsmith } 39560894Smsmith} 39660894Smsmith 39760894Smsmith/******************************************************************************** 39869543Smsmith * Write blocks from memory to disk, for system crash dumps. 39969543Smsmith */ 40069543Smsmithint 40169543Smsmithtwe_dump_blocks(struct twe_softc *sc, int unit, u_int32_t lba, void *data, int nblks) 40269543Smsmith{ 40369543Smsmith struct twe_request *tr; 40469543Smsmith TWE_Command *cmd; 40569543Smsmith int error; 40669543Smsmith 40769543Smsmith if (twe_get_request(sc, &tr)) 40869543Smsmith return(ENOMEM); 40969543Smsmith 41069543Smsmith tr->tr_data = data; 41169543Smsmith tr->tr_status = TWE_CMD_SETUP; 41269543Smsmith tr->tr_length = nblks * TWE_BLOCK_SIZE; 41369543Smsmith tr->tr_flags = TWE_CMD_DATAOUT; 41469543Smsmith 41569543Smsmith cmd = &tr->tr_command; 41669543Smsmith cmd->io.opcode = TWE_OP_WRITE; 41769543Smsmith cmd->io.size = 3; 41869543Smsmith cmd->io.unit = unit; 41969543Smsmith cmd->io.block_count = nblks; 42069543Smsmith cmd->io.lba = lba; 42169543Smsmith 42269543Smsmith twe_map_request(tr); 42369543Smsmith error = twe_immediate_request(tr); 42469543Smsmith if (error == 0) 42569543Smsmith if (twe_report_request(tr)) 42669543Smsmith error = EIO; 42769543Smsmith twe_release_request(tr); 42869543Smsmith return(error); 42969543Smsmith} 43069543Smsmith 43169543Smsmith/******************************************************************************** 43267555Smsmith * Handle controller-specific control operations. 43360894Smsmith */ 43467555Smsmithint 43567555Smsmithtwe_ioctl(struct twe_softc *sc, int cmd, void *addr) 43660894Smsmith{ 43767555Smsmith struct twe_usercommand *tu = (struct twe_usercommand *)addr; 43867555Smsmith struct twe_paramcommand *tp = (struct twe_paramcommand *)addr; 43967555Smsmith union twe_statrequest *ts = (union twe_statrequest *)addr; 44067555Smsmith TWE_Param *param; 44167555Smsmith void *data; 44267555Smsmith int *arg = (int *)addr; 44367555Smsmith struct twe_request *tr; 44469543Smsmith u_int8_t srid; 44567555Smsmith int s, error; 44660894Smsmith 44767555Smsmith error = 0; 44867555Smsmith switch(cmd) { 44967555Smsmith /* handle a command from userspace */ 45067555Smsmith case TWEIO_COMMAND: 45167555Smsmith /* get a request */ 45267555Smsmith if (twe_get_request(sc, &tr)) { 45367555Smsmith error = EBUSY; 45467555Smsmith goto cmd_done; 45567555Smsmith } 45667555Smsmith 45769543Smsmith /* 45869543Smsmith * Save the command's request ID, copy the user-supplied command in, 45969543Smsmith * restore the request ID. 46069543Smsmith */ 46169543Smsmith srid = tr->tr_command.generic.request_id; 46267555Smsmith bcopy(&tu->tu_command, &tr->tr_command, sizeof(TWE_Command)); 46369543Smsmith tr->tr_command.generic.request_id = srid; 46467555Smsmith 46567555Smsmith /* if there's a data buffer, allocate and copy it in */ 46667555Smsmith tr->tr_length = tu->tu_size; 46767555Smsmith if (tr->tr_length > 0) { 46867555Smsmith if ((tr->tr_data = malloc(tr->tr_length, M_DEVBUF, M_WAITOK)) == NULL) { 46967555Smsmith error = ENOMEM; 47067555Smsmith goto cmd_done; 47167555Smsmith } 47267555Smsmith if ((error = copyin(tu->tu_data, tr->tr_data, tr->tr_length)) != 0) 47367555Smsmith goto cmd_done; 47467555Smsmith tr->tr_flags |= TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 47567555Smsmith } 47667555Smsmith 47767555Smsmith /* run the command */ 47869543Smsmith twe_map_request(tr); 47967555Smsmith twe_wait_request(tr); 48067555Smsmith 48167555Smsmith /* copy the command out again */ 48267555Smsmith bcopy(&tr->tr_command, &tu->tu_command, sizeof(TWE_Command)); 48367555Smsmith 48467555Smsmith /* if there was a data buffer, copy it out */ 48567555Smsmith if (tr->tr_length > 0) 48667555Smsmith error = copyout(tr->tr_data, tu->tu_data, tr->tr_length); 48767555Smsmith 48867555Smsmith cmd_done: 48967555Smsmith /* free resources */ 49067555Smsmith if (tr->tr_data != NULL) 49167555Smsmith free(tr->tr_data, M_DEVBUF); 49267555Smsmith if (tr != NULL) 49367555Smsmith twe_release_request(tr); 49467555Smsmith 49567555Smsmith break; 49667555Smsmith 49767555Smsmith /* fetch statistics counter */ 49867555Smsmith case TWEIO_STATS: 49967555Smsmith switch (ts->ts_item) { 50067555Smsmith#ifdef TWE_PERFORMANCE_MONITOR 50167555Smsmith case TWEQ_FREE: 50267555Smsmith case TWEQ_BIO: 50367555Smsmith case TWEQ_READY: 50467555Smsmith case TWEQ_BUSY: 50567555Smsmith case TWEQ_COMPLETE: 50667555Smsmith bcopy(&sc->twe_qstat[ts->ts_item], &ts->ts_qstat, sizeof(struct twe_qstat)); 50767555Smsmith break; 50867555Smsmith#endif 50967555Smsmith default: 51067555Smsmith error = ENOENT; 51167555Smsmith break; 51267555Smsmith } 51367555Smsmith break; 51467555Smsmith 51567555Smsmith /* poll for an AEN */ 51667555Smsmith case TWEIO_AEN_POLL: 51767555Smsmith *arg = twe_dequeue_aen(sc); 51867555Smsmith if (*arg == -1) 51967555Smsmith error = ENOENT; 52067555Smsmith break; 52167555Smsmith 52267555Smsmith /* wait for another AEN to show up */ 52367555Smsmith case TWEIO_AEN_WAIT: 52467555Smsmith s = splbio(); 52567555Smsmith while ((*arg = twe_dequeue_aen(sc)) == -1) { 52667555Smsmith error = tsleep(&sc->twe_aen_queue, PRIBIO | PCATCH, "tweaen", 0); 52767555Smsmith if (error == EINTR) 52867555Smsmith break; 52967555Smsmith } 53067555Smsmith splx(s); 53167555Smsmith break; 53267555Smsmith 53367555Smsmith case TWEIO_GET_PARAM: 53467555Smsmith if ((param = twe_get_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, NULL)) == NULL) { 53567555Smsmith twe_printf(sc, "TWEIO_GET_PARAM failed for 0x%x/0x%x/%d\n", 53667555Smsmith tp->tp_table_id, tp->tp_param_id, tp->tp_size); 53767555Smsmith error = EINVAL; 53867555Smsmith } else { 53967555Smsmith if (param->parameter_size_bytes > tp->tp_size) { 54067555Smsmith twe_printf(sc, "TWEIO_GET_PARAM parameter too large (%d > %d)\n", 54167555Smsmith param->parameter_size_bytes, tp->tp_size); 54267555Smsmith error = EFAULT; 54367555Smsmith } else { 54467555Smsmith error = copyout(param->data, tp->tp_data, param->parameter_size_bytes); 54567555Smsmith } 54667555Smsmith free(param, M_DEVBUF); 54767555Smsmith } 54867555Smsmith break; 54967555Smsmith 55067555Smsmith case TWEIO_SET_PARAM: 55167555Smsmith if ((data = malloc(tp->tp_size, M_DEVBUF, M_WAITOK)) == NULL) { 55267555Smsmith error = ENOMEM; 55367555Smsmith } else { 55467555Smsmith error = copyin(tp->tp_data, data, tp->tp_size); 55567555Smsmith if (error == 0) 55667555Smsmith error = twe_set_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, data); 55767555Smsmith free(data, M_DEVBUF); 55867555Smsmith } 55967555Smsmith break; 56067555Smsmith 56167555Smsmith case TWEIO_RESET: 56267555Smsmith twe_reset(sc); 56367555Smsmith break; 56467555Smsmith 56567555Smsmith /* nothing we understand */ 56667555Smsmith default: 56767555Smsmith error = ENOTTY; 56867555Smsmith } 56967555Smsmith 57067555Smsmith return(error); 57160894Smsmith} 57260894Smsmith 57360894Smsmith/******************************************************************************** 57467555Smsmith * Enable the useful interrupts from the controller. 57560894Smsmith */ 57667555Smsmithvoid 57767555Smsmithtwe_enable_interrupts(struct twe_softc *sc) 57860894Smsmith{ 57967555Smsmith sc->twe_state |= TWE_STATE_INTEN; 58067555Smsmith TWE_CONTROL(sc, 58167555Smsmith TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT | 58267555Smsmith TWE_CONTROL_UNMASK_RESPONSE_INTERRUPT | 58367555Smsmith TWE_CONTROL_ENABLE_INTERRUPTS); 58460894Smsmith} 58560894Smsmith 58660894Smsmith/******************************************************************************** 58767555Smsmith * Disable interrupts from the controller. 58867555Smsmith */ 58967555Smsmithvoid 59067555Smsmithtwe_disable_interrupts(struct twe_softc *sc) 59167555Smsmith{ 59267555Smsmith TWE_CONTROL(sc, TWE_CONTROL_DISABLE_INTERRUPTS); 59367555Smsmith sc->twe_state &= ~TWE_STATE_INTEN; 59467555Smsmith} 59567555Smsmith 59667555Smsmith/******************************************************************************** 59760894Smsmith ******************************************************************************** 59860894Smsmith Command Submission 59960894Smsmith ******************************************************************************** 60060894Smsmith ********************************************************************************/ 60160894Smsmith 60267555Smsmith/******************************************************************************** 60367555Smsmith * Read integer parameter table entries. 60460894Smsmith */ 60567555Smsmithstatic int 60667555Smsmithtwe_get_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t *result) 60760894Smsmith{ 60867555Smsmith TWE_Param *param; 60960894Smsmith 61067555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 1, NULL)) == NULL) 61167555Smsmith return(ENOENT); 61267555Smsmith *result = *(u_int8_t *)param->data; 61367555Smsmith free(param, M_DEVBUF); 61467555Smsmith return(0); 61567555Smsmith} 61660894Smsmith 61767555Smsmithstatic int 61867555Smsmithtwe_get_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t *result) 61967555Smsmith{ 62067555Smsmith TWE_Param *param; 62167555Smsmith 62267555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 2, NULL)) == NULL) 62367555Smsmith return(ENOENT); 62467555Smsmith *result = *(u_int16_t *)param->data; 62567555Smsmith free(param, M_DEVBUF); 62660894Smsmith return(0); 62760894Smsmith} 62860894Smsmith 62967555Smsmithstatic int 63067555Smsmithtwe_get_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t *result) 63167555Smsmith{ 63267555Smsmith TWE_Param *param; 63367555Smsmith 63467555Smsmith if ((param = twe_get_param(sc, table_id, param_id, 4, NULL)) == NULL) 63567555Smsmith return(ENOENT); 63667555Smsmith *result = *(u_int32_t *)param->data; 63767555Smsmith free(param, M_DEVBUF); 63867555Smsmith return(0); 63967555Smsmith} 64067555Smsmith 64160894Smsmith/******************************************************************************** 64260894Smsmith * Perform a TWE_OP_GET_PARAM command. If a callback function is provided, it 64360894Smsmith * will be called with the command when it's completed. If no callback is 64460894Smsmith * provided, we will wait for the command to complete and then return just the data. 64560894Smsmith * The caller is responsible for freeing the data when done with it. 64660894Smsmith */ 64760894Smsmithstatic void * 64867555Smsmithtwe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_size, 64967555Smsmith void (* func)(struct twe_request *tr)) 65060894Smsmith{ 65160894Smsmith struct twe_request *tr; 65260894Smsmith TWE_Command *cmd; 65360894Smsmith TWE_Param *param; 65460894Smsmith int error; 65560894Smsmith 65660894Smsmith debug_called(4); 65760894Smsmith 65860894Smsmith tr = NULL; 65960894Smsmith param = NULL; 66060894Smsmith 66160894Smsmith /* get a command */ 66267555Smsmith if (twe_get_request(sc, &tr)) 66360894Smsmith goto err; 66460894Smsmith 66560894Smsmith /* get a buffer */ 66660894Smsmith if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 66760894Smsmith goto err; 66860894Smsmith tr->tr_data = param; 66960894Smsmith tr->tr_length = TWE_SECTOR_SIZE; 67060894Smsmith tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 67160894Smsmith 67260894Smsmith /* build the command for the controller */ 67360894Smsmith cmd = &tr->tr_command; 67467555Smsmith cmd->param.opcode = TWE_OP_GET_PARAM; 67567555Smsmith cmd->param.size = 2; 67667555Smsmith cmd->param.unit = 0; 67767555Smsmith cmd->param.param_count = 1; 67860894Smsmith 67960894Smsmith /* map the command/data into controller-visible space */ 68060894Smsmith twe_map_request(tr); 68160894Smsmith 68260894Smsmith /* fill in the outbound parameter data */ 68360894Smsmith param->table_id = table_id; 68467555Smsmith param->parameter_id = param_id; 68567555Smsmith param->parameter_size_bytes = param_size; 68660894Smsmith 68760894Smsmith /* submit the command and either wait or let the callback handle it */ 68860894Smsmith if (func == NULL) { 68960894Smsmith /* XXX could use twe_wait_request here if interrupts were enabled? */ 69060894Smsmith error = twe_immediate_request(tr); 69160894Smsmith if (error == 0) { 69269543Smsmith if (twe_report_request(tr)) 69360894Smsmith goto err; 69460894Smsmith } 69567555Smsmith twe_release_request(tr); 69667555Smsmith return(param); 69760894Smsmith } else { 69860894Smsmith tr->tr_complete = func; 69960894Smsmith error = twe_start(tr); 70060894Smsmith if (error == 0) 70160894Smsmith return(func); 70260894Smsmith } 70360894Smsmith 70460894Smsmith /* something failed */ 70560894Smsmitherr: 70660894Smsmith debug(1, "failed"); 70760894Smsmith if (tr != NULL) 70860894Smsmith twe_release_request(tr); 70960894Smsmith if (param != NULL) 71060894Smsmith free(param, M_DEVBUF); 71160894Smsmith return(NULL); 71260894Smsmith} 71360894Smsmith 71460894Smsmith/******************************************************************************** 71567555Smsmith * Set integer parameter table entries. 71667555Smsmith */ 71767555Smsmithstatic int 71867555Smsmithtwe_set_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t value) 71967555Smsmith{ 72067555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 72167555Smsmith} 72267555Smsmith 72367555Smsmithstatic int 72467555Smsmithtwe_set_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t value) 72567555Smsmith{ 72667555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 72767555Smsmith} 72867555Smsmith 72967555Smsmithstatic int 73067555Smsmithtwe_set_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t value) 73167555Smsmith{ 73267555Smsmith return(twe_set_param(sc, table_id, param_id, sizeof(value), &value)); 73367555Smsmith} 73467555Smsmith 73567555Smsmith/******************************************************************************** 73667555Smsmith * Perform a TWE_OP_SET_PARAM command, returns nonzero on error. 73767555Smsmith */ 73867555Smsmithstatic int 73967555Smsmithtwe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, void *data) 74067555Smsmith{ 74167555Smsmith struct twe_request *tr; 74267555Smsmith TWE_Command *cmd; 74367555Smsmith TWE_Param *param; 74467555Smsmith int error; 74567555Smsmith 74667555Smsmith debug_called(4); 74767555Smsmith 74867555Smsmith tr = NULL; 74967555Smsmith param = NULL; 75067555Smsmith error = ENOMEM; 75167555Smsmith 75267555Smsmith /* get a command */ 75367555Smsmith if (twe_get_request(sc, &tr)) 75467555Smsmith goto out; 75567555Smsmith 75667555Smsmith /* get a buffer */ 75767555Smsmith if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL) 75867555Smsmith goto out; 75967555Smsmith tr->tr_data = param; 76067555Smsmith tr->tr_length = TWE_SECTOR_SIZE; 76167555Smsmith tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT; 76267555Smsmith 76367555Smsmith /* build the command for the controller */ 76467555Smsmith cmd = &tr->tr_command; 76567555Smsmith cmd->param.opcode = TWE_OP_SET_PARAM; 76667555Smsmith cmd->param.size = 2; 76767555Smsmith cmd->param.unit = 0; 76867555Smsmith cmd->param.param_count = 1; 76967555Smsmith 77067555Smsmith /* map the command/data into controller-visible space */ 77167555Smsmith twe_map_request(tr); 77267555Smsmith 77367555Smsmith /* fill in the outbound parameter data */ 77467555Smsmith param->table_id = table_id; 77567555Smsmith param->parameter_id = param_id; 77667555Smsmith param->parameter_size_bytes = param_size; 77767555Smsmith bcopy(data, param->data, param_size); 77867555Smsmith 77967555Smsmith /* XXX could use twe_wait_request here if interrupts were enabled? */ 78067555Smsmith error = twe_immediate_request(tr); 78167555Smsmith if (error == 0) { 78269543Smsmith if (twe_report_request(tr)) 78367555Smsmith error = EIO; 78467555Smsmith } 78567555Smsmith 78667555Smsmithout: 78767555Smsmith if (tr != NULL) 78867555Smsmith twe_release_request(tr); 78967555Smsmith if (param != NULL) 79067555Smsmith free(param, M_DEVBUF); 79167555Smsmith return(error); 79267555Smsmith} 79367555Smsmith 79467555Smsmith/******************************************************************************** 79560894Smsmith * Perform a TWE_OP_INIT_CONNECTION command, returns nonzero on error. 79660894Smsmith * 79760894Smsmith * Typically called with interrupts disabled. 79860894Smsmith */ 79960894Smsmithstatic int 80067555Smsmithtwe_init_connection(struct twe_softc *sc, int mode) 80160894Smsmith{ 80260894Smsmith struct twe_request *tr; 80360894Smsmith TWE_Command *cmd; 80460894Smsmith int error; 80560894Smsmith 80660894Smsmith debug_called(4); 80760894Smsmith 80860894Smsmith /* get a command */ 80967555Smsmith if (twe_get_request(sc, &tr)) 81060894Smsmith return(NULL); 81160894Smsmith 81260894Smsmith /* build the command */ 81360894Smsmith cmd = &tr->tr_command; 81467555Smsmith cmd->initconnection.opcode = TWE_OP_INIT_CONNECTION; 81567555Smsmith cmd->initconnection.size = 3; 81667555Smsmith cmd->initconnection.host_id = 0; 81767555Smsmith cmd->initconnection.message_credits = mode; 81867555Smsmith cmd->initconnection.response_queue_pointer = 0; 81960894Smsmith 82060894Smsmith /* map the command into controller-visible space */ 82160894Smsmith twe_map_request(tr); 82260894Smsmith 82360894Smsmith /* submit the command */ 82460894Smsmith error = twe_immediate_request(tr); 82560894Smsmith /* XXX check command result? */ 82660894Smsmith twe_unmap_request(tr); 82760894Smsmith twe_release_request(tr); 82860894Smsmith 82967555Smsmith if (mode == TWE_INIT_MESSAGE_CREDITS) 83067555Smsmith sc->twe_host_id = cmd->initconnection.host_id; 83160894Smsmith return(error); 83260894Smsmith} 83360894Smsmith 83460894Smsmith/******************************************************************************** 83560894Smsmith * Start the command (tr) and sleep waiting for it to complete. 83660894Smsmith * 83760894Smsmith * Successfully completed commands are dequeued. 83860894Smsmith */ 83960894Smsmithstatic int 84060894Smsmithtwe_wait_request(struct twe_request *tr) 84160894Smsmith{ 84267555Smsmith int s; 84360894Smsmith 84460894Smsmith debug_called(4); 84560894Smsmith 84667555Smsmith tr->tr_flags |= TWE_CMD_SLEEPER; 84767555Smsmith tr->tr_status = TWE_CMD_BUSY; 84867555Smsmith twe_enqueue_ready(tr); 84967555Smsmith twe_startio(tr->tr_sc); 85060894Smsmith s = splbio(); 85167555Smsmith while (tr->tr_status == TWE_CMD_BUSY) 85267555Smsmith tsleep(tr, PRIBIO, "twewait", 0); 85360894Smsmith splx(s); 85467555Smsmith 85567555Smsmith return(0); 85660894Smsmith} 85760894Smsmith 85860894Smsmith/******************************************************************************** 85960894Smsmith * Start the command (tr) and busy-wait for it to complete. 86060894Smsmith * This should only be used when interrupts are actually disabled (although it 86160894Smsmith * will work if they are not). 86260894Smsmith */ 86360894Smsmithstatic int 86460894Smsmithtwe_immediate_request(struct twe_request *tr) 86560894Smsmith{ 86660894Smsmith int error; 86760894Smsmith 86860894Smsmith debug_called(4); 86960894Smsmith 87060894Smsmith error = 0; 87160894Smsmith 87260894Smsmith if ((error = twe_start(tr)) != 0) 87360894Smsmith return(error); 87460894Smsmith while (tr->tr_status == TWE_CMD_BUSY){ 87560894Smsmith twe_done(tr->tr_sc); 87660894Smsmith } 87760894Smsmith return(tr->tr_status != TWE_CMD_COMPLETE); 87860894Smsmith} 87960894Smsmith 88060894Smsmith/******************************************************************************** 88160894Smsmith * Handle completion of an I/O command. 88260894Smsmith */ 88360894Smsmithstatic void 88460894Smsmithtwe_completeio(struct twe_request *tr) 88560894Smsmith{ 88660894Smsmith struct twe_softc *sc = tr->tr_sc; 88767555Smsmith twe_bio *bp = (twe_bio *)tr->tr_private; 88860894Smsmith 88960894Smsmith debug_called(4); 89060894Smsmith 89160894Smsmith if (tr->tr_status == TWE_CMD_COMPLETE) { 89267555Smsmith 89369543Smsmith if (twe_report_request(tr)) 89467555Smsmith TWE_BIO_SET_ERROR(bp, EIO); 89567555Smsmith 89669543Smsmith } else { 89769543Smsmith twe_panic(sc, "twe_completeio on incomplete command"); 89860894Smsmith } 89969543Smsmith tr->tr_private = NULL; 90069543Smsmith twed_intr(bp); 90160894Smsmith twe_release_request(tr); 90260894Smsmith} 90360894Smsmith 90460894Smsmith/******************************************************************************** 90567555Smsmith * Reset the controller and pull all the active commands back onto the ready 90667555Smsmith * queue. Used to restart a controller that's exhibiting bad behaviour. 90767555Smsmith */ 90867555Smsmithstatic void 90967555Smsmithtwe_reset(struct twe_softc *sc) 91067555Smsmith{ 91167555Smsmith struct twe_request *tr; 91267555Smsmith int i, s; 91367555Smsmith 91469543Smsmith twe_printf(sc, "controller reset in progress...\n"); 91567555Smsmith 91667555Smsmith /* 91767555Smsmith * Disable interrupts from the controller, and mask any accidental entry 91867555Smsmith * into our interrupt handler. 91967555Smsmith */ 92067555Smsmith twe_disable_interrupts(sc); 92167555Smsmith s = splbio(); 92267555Smsmith 92367555Smsmith /* 92467555Smsmith * Try to soft-reset the controller. 92567555Smsmith */ 92667555Smsmith for (i = 0; i < TWE_MAX_RESET_TRIES; i++) { 92767555Smsmith 92867555Smsmith if (i > 0) 92967555Smsmith twe_printf(sc, "reset %d failed, trying again\n", i); 93067555Smsmith 93167555Smsmith if (!twe_soft_reset(sc)) 93267555Smsmith break; /* reset process complete */ 93367555Smsmith } 93467555Smsmith /* did we give up? */ 93567555Smsmith if (i >= TWE_MAX_RESET_TRIES) { 93667555Smsmith twe_printf(sc, "can't reset controller, giving up\n"); 93767555Smsmith goto out; 93867555Smsmith } 93967555Smsmith 94067555Smsmith /* 94167555Smsmith * Move all of the commands that were busy back to the ready queue. 94267555Smsmith */ 94367555Smsmith i = 0; 94467555Smsmith while ((tr = twe_dequeue_busy(sc)) != NULL) { 94567555Smsmith twe_enqueue_ready(tr); 94667555Smsmith i++; 94767555Smsmith } 94867555Smsmith 94967555Smsmith /* 95067555Smsmith * Kick the controller to start things going again, then re-enable interrupts. 95167555Smsmith */ 95267555Smsmith twe_startio(sc); 95367555Smsmith twe_enable_interrupts(sc); 95467555Smsmith twe_printf(sc, "controller reset done, %d commands restarted\n", i); 95567555Smsmith 95667555Smsmithout: 95767555Smsmith splx(s); 95867555Smsmith twe_enable_interrupts(sc); 95967555Smsmith} 96067555Smsmith 96167555Smsmith/******************************************************************************** 96260894Smsmith ******************************************************************************** 96360894Smsmith Command I/O to Controller 96460894Smsmith ******************************************************************************** 96560894Smsmith ********************************************************************************/ 96660894Smsmith 96760894Smsmith/******************************************************************************** 96860894Smsmith * Try to deliver (tr) to the controller. 96960894Smsmith * 97060894Smsmith * Can be called at any interrupt level, with or without interrupts enabled. 97160894Smsmith */ 97260894Smsmithstatic int 97360894Smsmithtwe_start(struct twe_request *tr) 97460894Smsmith{ 97560894Smsmith struct twe_softc *sc = tr->tr_sc; 97660894Smsmith int i, s, done; 97760894Smsmith u_int32_t status_reg; 97860894Smsmith 97960894Smsmith debug_called(4); 98060894Smsmith 98160894Smsmith /* mark the command as currently being processed */ 98260894Smsmith tr->tr_status = TWE_CMD_BUSY; 98360894Smsmith 98467555Smsmith /* 98567555Smsmith * Spin briefly waiting for the controller to come ready 98667555Smsmith * 98767555Smsmith * XXX it might be more efficient to return EBUSY immediately 98867555Smsmith * and let the command be rescheduled. 98967555Smsmith */ 99060894Smsmith for (i = 100000, done = 0; (i > 0) && !done; i--) { 99160894Smsmith s = splbio(); 99260894Smsmith 99360894Smsmith /* check to see if we can post a command */ 99460894Smsmith status_reg = TWE_STATUS(sc); 99560894Smsmith twe_check_bits(sc, status_reg); 99660894Smsmith 99760894Smsmith if (!(status_reg & TWE_STATUS_COMMAND_QUEUE_FULL)) { 99860894Smsmith TWE_COMMAND_QUEUE(sc, tr->tr_cmdphys); 99960894Smsmith done = 1; 100060894Smsmith /* move command to work queue */ 100167555Smsmith twe_enqueue_busy(tr); 100267555Smsmith#ifdef TWE_DEBUG 100360894Smsmith if (tr->tr_complete != NULL) { 100467555Smsmith debug(3, "queued request %d with callback %p", tr->tr_command.generic.request_id, tr->tr_complete); 100567555Smsmith } else if (tr->tr_flags & TWE_CMD_SLEEPER) { 100667555Smsmith debug(3, "queued request %d with wait channel %p", tr->tr_command.generic.request_id, tr); 100760894Smsmith } else { 100867555Smsmith debug(3, "queued request %d for polling caller", tr->tr_command.generic.request_id); 100960894Smsmith } 101067555Smsmith#endif 101160894Smsmith } 101260894Smsmith splx(s); /* drop spl to allow completion interrupts */ 101360894Smsmith } 101460894Smsmith 101560894Smsmith /* command is enqueued */ 101660894Smsmith if (done) 101760894Smsmith return(0); 101860894Smsmith 101960894Smsmith /* 102060894Smsmith * We couldn't get the controller to take the command; try submitting it again later. 102160894Smsmith * This should only happen if something is wrong with the controller, or if we have 102260894Smsmith * overestimated the number of commands it can accept. (Should we actually reject 102360894Smsmith * the command at this point?) 102460894Smsmith */ 102560894Smsmith return(EBUSY); 102660894Smsmith} 102760894Smsmith 102860894Smsmith/******************************************************************************** 102960894Smsmith * Poll the controller (sc) for completed commands. 103060894Smsmith * 103160894Smsmith * Can be called at any interrupt level, with or without interrupts enabled. 103260894Smsmith */ 103360894Smsmithstatic void 103460894Smsmithtwe_done(struct twe_softc *sc) 103560894Smsmith{ 103660894Smsmith TWE_Response_Queue rq; 103760894Smsmith struct twe_request *tr; 103860894Smsmith int s, found; 103960894Smsmith u_int32_t status_reg; 104060894Smsmith 104160894Smsmith debug_called(5); 104260894Smsmith 104360894Smsmith /* loop collecting completed commands */ 104460894Smsmith found = 0; 104560894Smsmith s = splbio(); 104660894Smsmith for (;;) { 104760894Smsmith status_reg = TWE_STATUS(sc); 104860894Smsmith twe_check_bits(sc, status_reg); /* XXX should this fail? */ 104960894Smsmith 105060894Smsmith if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) { 105160894Smsmith found = 1; 105260894Smsmith rq = TWE_RESPONSE_QUEUE(sc); 105367555Smsmith tr = sc->twe_lookup[rq.u.response_id]; /* find command */ 105469543Smsmith if (tr->tr_status != TWE_CMD_BUSY) 105569543Smsmith twe_printf(sc, "completion event for nonbusy command\n"); 105669543Smsmith tr->tr_status = TWE_CMD_COMPLETE; 105769543Smsmith debug(3, "completed request id %d with status %d", 105869543Smsmith tr->tr_command.generic.request_id, tr->tr_command.generic.status); 105969543Smsmith /* move to completed queue */ 106069543Smsmith twe_remove_busy(tr); 106169543Smsmith twe_enqueue_complete(tr); 106260894Smsmith } else { 106360894Smsmith break; /* no response ready */ 106460894Smsmith } 106560894Smsmith } 106660894Smsmith splx(s); 106760894Smsmith 106860894Smsmith /* if we've completed any commands, try posting some more */ 106960894Smsmith if (found) 107060894Smsmith twe_startio(sc); 107160894Smsmith 107260894Smsmith /* handle completion and timeouts */ 107367555Smsmith twe_complete(sc); /* XXX use deferred completion? */ 107460894Smsmith} 107560894Smsmith 107660894Smsmith/******************************************************************************** 107760894Smsmith * Perform post-completion processing for commands on (sc). 107860894Smsmith * 107960894Smsmith * This is split from twe_done as it can be safely deferred and run at a lower 108060894Smsmith * priority level should facilities for such a thing become available. 108160894Smsmith */ 108260894Smsmithstatic void 108360894Smsmithtwe_complete(struct twe_softc *sc) 108460894Smsmith{ 108567555Smsmith struct twe_request *tr; 108660894Smsmith 108760894Smsmith debug_called(5); 108860894Smsmith 108960894Smsmith /* 109067555Smsmith * Pull commands off the completed list, dispatch them appropriately 109160894Smsmith */ 109267555Smsmith while ((tr = twe_dequeue_complete(sc)) != NULL) { 109360894Smsmith 109467555Smsmith /* unmap the command's data buffer */ 109567555Smsmith twe_unmap_request(tr); 109660894Smsmith 109767555Smsmith /* dispatch to suit command originator */ 109867555Smsmith if (tr->tr_complete != NULL) { /* completion callback */ 109967555Smsmith debug(2, "call completion handler %p", tr->tr_complete); 110067555Smsmith tr->tr_complete(tr); 110160894Smsmith 110267555Smsmith } else if (tr->tr_flags & TWE_CMD_SLEEPER) { /* caller is asleep waiting */ 110367555Smsmith debug(2, "wake up command owner on %p", tr); 110467555Smsmith wakeup_one(tr); 110560894Smsmith 110667555Smsmith } else { /* caller is polling command */ 110767555Smsmith debug(2, "command left for owner"); 110860894Smsmith } 110967555Smsmith } 111060894Smsmith} 111160894Smsmith 111260894Smsmith/******************************************************************************** 111360894Smsmith * Wait for (status) to be set in the controller status register for up to 111460894Smsmith * (timeout) seconds. Returns 0 if found, nonzero if we time out. 111560894Smsmith * 111660894Smsmith * Note: this busy-waits, rather than sleeping, since we may be called with 111760894Smsmith * eg. clock interrupts masked. 111860894Smsmith */ 111960894Smsmithstatic int 112060894Smsmithtwe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout) 112160894Smsmith{ 112260894Smsmith time_t expiry; 112360894Smsmith u_int32_t status_reg; 112460894Smsmith 112560894Smsmith debug_called(4); 112660894Smsmith 112760894Smsmith expiry = time_second + timeout; 112860894Smsmith 112960894Smsmith do { 113060894Smsmith status_reg = TWE_STATUS(sc); 113160894Smsmith if (status_reg & status) /* got the required bit(s)? */ 113260894Smsmith return(0); 113360894Smsmith DELAY(100000); 113460894Smsmith } while (time_second <= expiry); 113560894Smsmith 113660894Smsmith return(1); 113760894Smsmith} 113860894Smsmith 113960894Smsmith/******************************************************************************** 114060894Smsmith * Drain the response queue, which may contain responses to commands we know 114160894Smsmith * nothing about. 114260894Smsmith */ 114360894Smsmithstatic int 114460894Smsmithtwe_drain_response_queue(struct twe_softc *sc) 114560894Smsmith{ 114660894Smsmith TWE_Response_Queue rq; 114760894Smsmith u_int32_t status_reg; 114860894Smsmith 114960894Smsmith debug_called(4); 115060894Smsmith 115160894Smsmith for (;;) { /* XXX give up eventually? */ 115260894Smsmith status_reg = TWE_STATUS(sc); 115360894Smsmith if (twe_check_bits(sc, status_reg)) 115460894Smsmith return(1); 115560894Smsmith if (status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY) 115660894Smsmith return(0); 115760894Smsmith rq = TWE_RESPONSE_QUEUE(sc); 115860894Smsmith } 115960894Smsmith} 116060894Smsmith 116160894Smsmith/******************************************************************************** 116267555Smsmith * Soft-reset the controller 116367555Smsmith */ 116467555Smsmithstatic int 116567555Smsmithtwe_soft_reset(struct twe_softc *sc) 116667555Smsmith{ 116767555Smsmith u_int32_t status_reg; 116867555Smsmith 116967555Smsmith debug_called(2); 117067555Smsmith 117167555Smsmith TWE_SOFT_RESET(sc); 117267555Smsmith 117367555Smsmith if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 15)) { 117467683Smsmith twe_printf(sc, "no attention interrupt\n"); 117567555Smsmith return(1); 117667555Smsmith } 117767555Smsmith if (twe_drain_aen_queue(sc)) { 117867555Smsmith twe_printf(sc, "can't drain AEN queue\n"); 117967555Smsmith return(1); 118067555Smsmith } 118167555Smsmith if (twe_find_aen(sc, TWE_AEN_SOFT_RESET)) { 118267555Smsmith twe_printf(sc, "reset not reported\n"); 118367555Smsmith return(1); 118467555Smsmith } 118567555Smsmith status_reg = TWE_STATUS(sc); 118667555Smsmith if (TWE_STATUS_ERRORS(status_reg) || twe_check_bits(sc, status_reg)) { 118767555Smsmith twe_printf(sc, "controller errors detected\n"); 118867555Smsmith return(1); 118967555Smsmith } 119067555Smsmith if (twe_drain_response_queue(sc)) { 119167555Smsmith twe_printf(sc, "can't drain response queue\n"); 119267555Smsmith return(1); 119367555Smsmith } 119467555Smsmith return(0); 119567555Smsmith} 119667555Smsmith 119767555Smsmith/******************************************************************************** 119860894Smsmith ******************************************************************************** 119960894Smsmith Interrupt Handling 120060894Smsmith ******************************************************************************** 120160894Smsmith ********************************************************************************/ 120260894Smsmith 120360894Smsmith/******************************************************************************** 120460894Smsmith * Host interrupt. 120560894Smsmith * 120660894Smsmith * XXX what does this mean? 120760894Smsmith */ 120860894Smsmithstatic void 120960894Smsmithtwe_host_intr(struct twe_softc *sc) 121060894Smsmith{ 121160894Smsmith debug_called(4); 121260894Smsmith 121367555Smsmith twe_printf(sc, "host interrupt\n"); 121460894Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_HOST_INTERRUPT); 121560894Smsmith} 121660894Smsmith 121760894Smsmith/******************************************************************************** 121860894Smsmith * Attention interrupt. 121960894Smsmith * 122060894Smsmith * Signalled when the controller has one or more AENs for us. 122160894Smsmith */ 122260894Smsmithstatic void 122360894Smsmithtwe_attention_intr(struct twe_softc *sc) 122460894Smsmith{ 122560894Smsmith debug_called(4); 122660894Smsmith 122760894Smsmith /* instigate a poll for AENs */ 122860894Smsmith if (twe_fetch_aen(sc)) { 122967555Smsmith twe_printf(sc, "error polling for signalled AEN\n"); 123060894Smsmith } else { 123160894Smsmith TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT); 123260894Smsmith } 123360894Smsmith} 123460894Smsmith 123560894Smsmith/******************************************************************************** 123660894Smsmith * Command interrupt. 123760894Smsmith * 123860894Smsmith * Signalled when the controller can handle more commands. 123960894Smsmith */ 124060894Smsmithstatic void 124160894Smsmithtwe_command_intr(struct twe_softc *sc) 124260894Smsmith{ 124360894Smsmith debug_called(4); 124460894Smsmith 124560894Smsmith /* 124660894Smsmith * We don't use this, rather we try to submit commands when we receive 124760894Smsmith * them, and when other commands have completed. Mask it so we don't get 124860894Smsmith * another one. 124960894Smsmith */ 125067555Smsmith twe_printf(sc, "command interrupt\n"); 125160894Smsmith TWE_CONTROL(sc, TWE_CONTROL_MASK_COMMAND_INTERRUPT); 125260894Smsmith} 125360894Smsmith 125460894Smsmith/******************************************************************************** 125560894Smsmith ******************************************************************************** 125660894Smsmith Asynchronous Event Handling 125760894Smsmith ******************************************************************************** 125860894Smsmith ********************************************************************************/ 125960894Smsmith 126060894Smsmith/******************************************************************************** 126160894Smsmith * Request an AEN from the controller. 126260894Smsmith */ 126360894Smsmithstatic int 126460894Smsmithtwe_fetch_aen(struct twe_softc *sc) 126560894Smsmith{ 126660894Smsmith 126760894Smsmith debug_called(4); 126860894Smsmith 126967555Smsmith if ((twe_get_param(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 2, twe_handle_aen)) == NULL) 127060894Smsmith return(EIO); 127160894Smsmith return(0); 127260894Smsmith} 127360894Smsmith 127460894Smsmith/******************************************************************************** 127560894Smsmith * Handle an AEN returned by the controller. 127660894Smsmith */ 127760894Smsmithstatic void 127860894Smsmithtwe_handle_aen(struct twe_request *tr) 127960894Smsmith{ 128060894Smsmith struct twe_softc *sc = tr->tr_sc; 128160894Smsmith TWE_Param *param; 128260894Smsmith u_int16_t aen; 128360894Smsmith 128460894Smsmith debug_called(4); 128560894Smsmith 128660894Smsmith /* XXX check for command success somehow? */ 128760894Smsmith 128860894Smsmith param = (TWE_Param *)tr->tr_data; 128960894Smsmith aen = *(u_int16_t *)(param->data); 129060894Smsmith 129160894Smsmith free(tr->tr_data, M_DEVBUF); 129260894Smsmith twe_release_request(tr); 129360894Smsmith twe_enqueue_aen(sc, aen); 129460894Smsmith 129560894Smsmith /* XXX poll for more AENs? */ 129660894Smsmith} 129760894Smsmith 129860894Smsmith/******************************************************************************** 129960894Smsmith * Pull AENs out of the controller and park them in the queue, in a context where 130060894Smsmith * interrupts aren't active. Return nonzero if we encounter any errors in the 130160894Smsmith * process of obtaining all the available AENs. 130260894Smsmith */ 130360894Smsmithstatic int 130460894Smsmithtwe_drain_aen_queue(struct twe_softc *sc) 130560894Smsmith{ 130660894Smsmith u_int16_t aen; 130760894Smsmith 130860894Smsmith for (;;) { 130967555Smsmith if (twe_get_param_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, &aen)) 131060894Smsmith return(1); 131160894Smsmith if (aen == TWE_AEN_QUEUE_EMPTY) 131260894Smsmith return(0); 131360894Smsmith twe_enqueue_aen(sc, aen); 131460894Smsmith } 131560894Smsmith} 131660894Smsmith 131760894Smsmith/******************************************************************************** 131860894Smsmith * Push an AEN that we've received onto the queue. 131960894Smsmith * 132060894Smsmith * Note that we have to lock this against reentrance, since it may be called 132160894Smsmith * from both interrupt and non-interrupt context. 132260894Smsmith * 132360894Smsmith * If someone is waiting for the AEN we have, wake them up. 132460894Smsmith */ 132560894Smsmithstatic void 132660894Smsmithtwe_enqueue_aen(struct twe_softc *sc, u_int16_t aen) 132760894Smsmith{ 132867555Smsmith char *msg; 132967555Smsmith int s, next, nextnext; 133060894Smsmith 133160894Smsmith debug_called(4); 133260894Smsmith 133367555Smsmith if ((msg = twe_format_aen(sc, aen)) != NULL) 133467555Smsmith twe_printf(sc, "AEN: <%s>\n", msg); 133560894Smsmith 133660894Smsmith s = splbio(); 133760894Smsmith /* enqueue the AEN */ 133860894Smsmith next = ((sc->twe_aen_head + 1) % TWE_Q_LENGTH); 133967555Smsmith nextnext = ((sc->twe_aen_head + 2) % TWE_Q_LENGTH); 134067555Smsmith 134167555Smsmith /* check to see if this is the last free slot, and subvert the AEN if it is */ 134267555Smsmith if (nextnext == sc->twe_aen_tail) 134367555Smsmith aen = TWE_AEN_QUEUE_FULL; 134467555Smsmith 134567555Smsmith /* look to see if there's room for this AEN */ 134660894Smsmith if (next != sc->twe_aen_tail) { 134760894Smsmith sc->twe_aen_queue[sc->twe_aen_head] = aen; 134860894Smsmith sc->twe_aen_head = next; 134960894Smsmith } 135060894Smsmith 135167555Smsmith /* wake up anyone asleep on the queue */ 135267555Smsmith wakeup(&sc->twe_aen_queue); 135367555Smsmith 135460894Smsmith /* anyone looking for this AEN? */ 135560894Smsmith if (sc->twe_wait_aen == aen) { 135660894Smsmith sc->twe_wait_aen = -1; 135760894Smsmith wakeup(&sc->twe_wait_aen); 135860894Smsmith } 135960894Smsmith splx(s); 136060894Smsmith} 136160894Smsmith 136260894Smsmith/******************************************************************************** 136360894Smsmith * Pop an AEN off the queue, or return -1 if there are none left. 136460894Smsmith * 136560894Smsmith * We are more or less interrupt-safe, so don't block interrupts. 136660894Smsmith */ 136760894Smsmithstatic int 136860894Smsmithtwe_dequeue_aen(struct twe_softc *sc) 136960894Smsmith{ 137060894Smsmith int result; 137160894Smsmith 137260894Smsmith debug_called(4); 137360894Smsmith 137460894Smsmith if (sc->twe_aen_tail == sc->twe_aen_head) { 137560894Smsmith result = -1; 137660894Smsmith } else { 137760894Smsmith result = sc->twe_aen_queue[sc->twe_aen_tail]; 137860894Smsmith sc->twe_aen_tail = ((sc->twe_aen_tail + 1) % TWE_Q_LENGTH); 137960894Smsmith } 138060894Smsmith return(result); 138160894Smsmith} 138260894Smsmith 138360894Smsmith/******************************************************************************** 138460894Smsmith * Check to see if the requested AEN is in the queue. 138560894Smsmith * 138660894Smsmith * XXX we could probably avoid masking interrupts here 138760894Smsmith */ 138860894Smsmithstatic int 138960894Smsmithtwe_find_aen(struct twe_softc *sc, u_int16_t aen) 139060894Smsmith{ 139160894Smsmith int i, s, missing; 139260894Smsmith 139360894Smsmith missing = 1; 139460894Smsmith s = splbio(); 139560894Smsmith for (i = sc->twe_aen_tail; (i != sc->twe_aen_head) && missing; i = (i + 1) % TWE_Q_LENGTH) { 139660894Smsmith if (sc->twe_aen_queue[i] == aen) 139760894Smsmith missing = 0; 139860894Smsmith } 139967555Smsmith splx(s); 140060894Smsmith return(missing); 140160894Smsmith} 140260894Smsmith 140360894Smsmith 140460894Smsmith#if 0 /* currently unused */ 140560894Smsmith/******************************************************************************** 140660894Smsmith * Sleep waiting for at least (timeout) seconds until we see (aen) as 140760894Smsmith * requested. Returns nonzero on timeout or failure. 140860894Smsmith * 140960894Smsmith * XXX: this should not be used in cases where there may be more than one sleeper 141060894Smsmith * without a mechanism for registering multiple sleepers. 141160894Smsmith */ 141260894Smsmithstatic int 141360894Smsmithtwe_wait_aen(struct twe_softc *sc, int aen, int timeout) 141460894Smsmith{ 141560894Smsmith time_t expiry; 141660894Smsmith int found, s; 141760894Smsmith 141860894Smsmith debug_called(4); 141960894Smsmith 142060894Smsmith expiry = time_second + timeout; 142160894Smsmith found = 0; 142260894Smsmith 142360894Smsmith s = splbio(); 142460894Smsmith sc->twe_wait_aen = aen; 142560894Smsmith do { 142660894Smsmith twe_fetch_aen(sc); 142760894Smsmith tsleep(&sc->twe_wait_aen, PZERO, "twewaen", hz); 142860894Smsmith if (sc->twe_wait_aen == -1) 142960894Smsmith found = 1; 143060894Smsmith } while ((time_second <= expiry) && !found); 143160894Smsmith splx(s); 143260894Smsmith return(!found); 143360894Smsmith} 143460894Smsmith#endif 143560894Smsmith 143660894Smsmith/******************************************************************************** 143760894Smsmith ******************************************************************************** 143860894Smsmith Command Buffer Management 143960894Smsmith ******************************************************************************** 144060894Smsmith ********************************************************************************/ 144160894Smsmith 144260894Smsmith/******************************************************************************** 144360894Smsmith * Get a new command buffer. 144460894Smsmith * 144567555Smsmith * This will return NULL if all command buffers are in use. 144660894Smsmith */ 144767555Smsmithstatic int 144867555Smsmithtwe_get_request(struct twe_softc *sc, struct twe_request **tr) 144960894Smsmith{ 145060894Smsmith debug_called(4); 145160894Smsmith 145260894Smsmith /* try to reuse an old buffer */ 145367555Smsmith *tr = twe_dequeue_free(sc); 145460894Smsmith 145567555Smsmith /* initialise some fields to their defaults */ 145667555Smsmith if (*tr != NULL) { 145767555Smsmith (*tr)->tr_data = NULL; 145869543Smsmith (*tr)->tr_private = NULL; 145967555Smsmith (*tr)->tr_status = TWE_CMD_SETUP; /* command is in setup phase */ 146067555Smsmith (*tr)->tr_flags = 0; 146167555Smsmith (*tr)->tr_complete = NULL; 146267555Smsmith (*tr)->tr_command.generic.status = 0; /* before submission to controller */ 146367555Smsmith (*tr)->tr_command.generic.flags = 0; /* not used */ 146460894Smsmith } 146567555Smsmith return(*tr == NULL); 146660894Smsmith} 146760894Smsmith 146860894Smsmith/******************************************************************************** 146967555Smsmith * Release a command buffer for reuse. 147060894Smsmith * 147160894Smsmith */ 147260894Smsmithstatic void 147360894Smsmithtwe_release_request(struct twe_request *tr) 147460894Smsmith{ 147560894Smsmith debug_called(4); 147660894Smsmith 147769543Smsmith if (tr->tr_private != NULL) 147869543Smsmith twe_panic(tr->tr_sc, "tr_private != NULL"); 147967555Smsmith twe_enqueue_free(tr); 148060894Smsmith} 148160894Smsmith 148260894Smsmith/******************************************************************************** 148367555Smsmith ******************************************************************************** 148467555Smsmith Debugging 148567555Smsmith ******************************************************************************** 148667555Smsmith ********************************************************************************/ 148760894Smsmith 148860894Smsmith/******************************************************************************** 148967555Smsmith * Print some information about the controller 149060894Smsmith */ 149167555Smsmithvoid 149267555Smsmithtwe_describe_controller(struct twe_softc *sc) 149360894Smsmith{ 149467555Smsmith TWE_Param *p[6]; 149567555Smsmith u_int8_t ports; 149667555Smsmith u_int32_t size; 149760894Smsmith int i; 149860894Smsmith 149967555Smsmith debug_called(2); 150060894Smsmith 150167555Smsmith /* get the port count */ 150267555Smsmith twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports); 150360894Smsmith 150467555Smsmith /* get version strings */ 150567555Smsmith p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon, 16, NULL); 150667555Smsmith p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW, 16, NULL); 150767555Smsmith p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL); 150867555Smsmith p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB, 8, NULL); 150967555Smsmith p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA, 8, NULL); 151067555Smsmith p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI, 8, NULL); 151160894Smsmith 151267555Smsmith twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[1]->data, p[2]->data); 151367555Smsmith if (bootverbose) 151467555Smsmith twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[0]->data, p[3]->data, 151567555Smsmith p[4]->data, p[5]->data); 151667555Smsmith free(p[0], M_DEVBUF); 151767555Smsmith free(p[1], M_DEVBUF); 151867555Smsmith free(p[2], M_DEVBUF); 151967555Smsmith free(p[3], M_DEVBUF); 152067555Smsmith free(p[4], M_DEVBUF); 152167555Smsmith free(p[5], M_DEVBUF); 152260894Smsmith 152367555Smsmith /* print attached drives */ 152467555Smsmith if (bootverbose) { 152567555Smsmith p[0] = twe_get_param(sc, TWE_PARAM_DRIVESUMMARY, TWE_PARAM_DRIVESUMMARY_Status, 16, NULL); 152667555Smsmith for (i = 0; i < ports; i++) { 152767555Smsmith if (p[0]->data[i] != TWE_PARAM_DRIVESTATUS_Present) 152867555Smsmith continue; 152967555Smsmith twe_get_param_4(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Size, &size); 153067555Smsmith p[1] = twe_get_param(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Model, 40, NULL); 153167555Smsmith if (p[1] != NULL) { 153267555Smsmith twe_printf(sc, "port %d: %.40s %dMB\n", i, p[1]->data, size / 2048); 153367555Smsmith free(p[1], M_DEVBUF); 153467555Smsmith } else { 153567555Smsmith twe_printf(sc, "port %d, drive status unavailable\n", i); 153667555Smsmith } 153760894Smsmith } 153867555Smsmith free(p[0], M_DEVBUF); 153960894Smsmith } 154060894Smsmith} 154160894Smsmith 154260894Smsmith/******************************************************************************** 154360894Smsmith * Complain if the status bits aren't what we're expecting. 154467555Smsmith * 154567555Smsmith * Rate-limit the complaints to at most one of each every five seconds, but 154667555Smsmith * always return the correct status. 154760894Smsmith */ 154860894Smsmithstatic int 154960894Smsmithtwe_check_bits(struct twe_softc *sc, u_int32_t status_reg) 155060894Smsmith{ 155167555Smsmith int result; 155267555Smsmith static time_t lastwarn[2] = {0, 0}; 155360894Smsmith 155467555Smsmith /* 155567555Smsmith * This can be a little problematic, as twe_panic may call twe_reset if 155667555Smsmith * TWE_DEBUG is not set, which will call us again as part of the soft reset. 155767555Smsmith */ 155867555Smsmith if ((status_reg & TWE_STATUS_PANIC_BITS) != 0) { 155967555Smsmith twe_printf(sc, "FATAL STATUS BIT(S) %b\n", status_reg & TWE_STATUS_PANIC_BITS, 156067555Smsmith TWE_STATUS_BITS_DESCRIPTION); 156167555Smsmith twe_panic(sc, "fatal status bits"); 156267555Smsmith } 156367555Smsmith 156460894Smsmith result = 0; 156560894Smsmith if ((status_reg & TWE_STATUS_EXPECTED_BITS) != TWE_STATUS_EXPECTED_BITS) { 156667555Smsmith if (time_second > (lastwarn[0] + 5)) { 156767555Smsmith twe_printf(sc, "missing expected status bit(s) %b\n", ~status_reg & TWE_STATUS_EXPECTED_BITS, 156867555Smsmith TWE_STATUS_BITS_DESCRIPTION); 156967555Smsmith lastwarn[0] = time_second; 157067555Smsmith } 157160894Smsmith result = 1; 157260894Smsmith } 157360894Smsmith 157460894Smsmith if ((status_reg & TWE_STATUS_UNEXPECTED_BITS) != 0) { 157567555Smsmith if (time_second > (lastwarn[1] + 5)) { 157667555Smsmith twe_printf(sc, "unexpected status bit(s) %b\n", status_reg & TWE_STATUS_UNEXPECTED_BITS, 157767555Smsmith TWE_STATUS_BITS_DESCRIPTION); 157867555Smsmith lastwarn[1] = time_second; 157967555Smsmith } 158060894Smsmith result = 1; 158160894Smsmith } 158267555Smsmith 158360894Smsmith return(result); 158460894Smsmith} 158560894Smsmith 158660894Smsmith/******************************************************************************** 158767555Smsmith * Return a string describing (aen). 158867555Smsmith * 158967555Smsmith * The low 8 bits of the aen are the code, the high 8 bits give the unit number 159067555Smsmith * where an AEN is specific to a unit. 159167555Smsmith * 159267555Smsmith * Note that we could expand this routine to handle eg. up/downgrading the status 159367555Smsmith * of a drive if we had some idea of what the drive's initial status was. 159460894Smsmith */ 159560894Smsmith 159660894Smsmithstatic char * 159767555Smsmithtwe_format_aen(struct twe_softc *sc, u_int16_t aen) 159860894Smsmith{ 159967555Smsmith static char buf[80]; 160067555Smsmith device_t child; 160167555Smsmith char *code, *msg; 160260894Smsmith 160367555Smsmith code = twe_describe_code(twe_table_aen, TWE_AEN_CODE(aen)); 160467555Smsmith msg = code + 2; 160560894Smsmith 160667555Smsmith switch (*code) { 160767555Smsmith case 'q': 160867555Smsmith if (!bootverbose) 160967555Smsmith return(NULL); 161067555Smsmith /* FALLTHROUGH */ 161167555Smsmith case 'p': 161267555Smsmith return(msg); 161367555Smsmith 161467555Smsmith case 'c': 161567555Smsmith if ((child = sc->twe_drive[TWE_AEN_UNIT(aen)].td_disk) != NULL) { 161667555Smsmith sprintf(buf, "twed%d: %s", device_get_unit(child), msg); 161767555Smsmith } else { 161867555Smsmith sprintf(buf, "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev), 161967555Smsmith msg, TWE_AEN_UNIT(aen)); 162067555Smsmith } 162167555Smsmith return(buf); 162267555Smsmith 162367555Smsmith case 'x': 162467555Smsmith default: 162567555Smsmith break; 162667555Smsmith } 162767555Smsmith sprintf(buf, "unknown AEN 0x%x", aen); 162860894Smsmith return(buf); 162960894Smsmith} 163060894Smsmith 163169543Smsmith/******************************************************************************** 163269543Smsmith * Print a diagnostic if the status of the command warrants it, and return 163369543Smsmith * either zero (command was ok) or nonzero (command failed). 163469543Smsmith */ 163567555Smsmithstatic int 163669543Smsmithtwe_report_request(struct twe_request *tr) 163767555Smsmith{ 163869543Smsmith struct twe_softc *sc = tr->tr_sc; 163969543Smsmith TWE_Command *cmd = &tr->tr_command; 164069543Smsmith int result; 164160894Smsmith 164269543Smsmith switch (cmd->generic.flags) { 164369543Smsmith case TWE_FLAGS_SUCCESS: 164469543Smsmith result = 0; 164569543Smsmith break; 164669543Smsmith case TWE_FLAGS_INFORMATIONAL: 164769543Smsmith case TWE_FLAGS_WARNING: 164869543Smsmith twe_printf(sc, "command completed - %s\n", 164969543Smsmith twe_describe_code(twe_table_status, cmd->generic.status)); 165069543Smsmith result = 0; 165169543Smsmith break; 165269543Smsmith 165369543Smsmith case TWE_FLAGS_FATAL: 165469543Smsmith default: 165569543Smsmith twe_printf(sc, "command failed - %s\n", 165669543Smsmith twe_describe_code(twe_table_status, cmd->generic.status)); 165769543Smsmith result = 1; 165869543Smsmith 165969543Smsmith /* 166069543Smsmith * The status code 0xff requests a controller reset 166169543Smsmith */ 166269543Smsmith if (cmd->generic.status == 0xff) 166369543Smsmith twe_reset(sc); 166469543Smsmith break; 166567555Smsmith } 166669543Smsmith return(result); 166767555Smsmith} 166867555Smsmith 166969543Smsmith/******************************************************************************** 167069543Smsmith * Print some controller state to aid in debugging error/panic conditions 167169543Smsmith */ 167267555Smsmithvoid 167367555Smsmithtwe_print_controller(struct twe_softc *sc) 167460894Smsmith{ 167567555Smsmith u_int32_t status_reg; 167660894Smsmith 167767555Smsmith status_reg = TWE_STATUS(sc); 167867555Smsmith twe_printf(sc, "status %b\n", status_reg, TWE_STATUS_BITS_DESCRIPTION); 167969543Smsmith twe_printf(sc, " current max\n"); 168069543Smsmith twe_printf(sc, "free %04d %04d\n", sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max); 168169543Smsmith twe_printf(sc, "ready %04d %04d\n", sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max); 168269543Smsmith twe_printf(sc, "busy %04d %04d\n", sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max); 168369543Smsmith twe_printf(sc, "complete %04d %04d\n", sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max); 168469543Smsmith twe_printf(sc, "bioq %04d %04d\n", sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max); 168567555Smsmith twe_printf(sc, "AEN queue head %d tail %d\n", sc->twe_aen_head, sc->twe_aen_tail); 168667555Smsmith} 168760894Smsmith 168867555Smsmithstatic void 168967555Smsmithtwe_panic(struct twe_softc *sc, char *reason) 169067555Smsmith{ 169167555Smsmith twe_print_controller(sc); 169267555Smsmith#ifdef TWE_DEBUG 169367555Smsmith panic(reason); 169467555Smsmith#else 169567555Smsmith twe_reset(sc); 169667555Smsmith#endif 169760894Smsmith} 169860894Smsmith 169967555Smsmith#if 0 170060894Smsmith/******************************************************************************** 170160894Smsmith * Print a request/command in human-readable format. 170260894Smsmith */ 170360894Smsmithstatic void 170460894Smsmithtwe_print_request(struct twe_request *tr) 170560894Smsmith{ 170667555Smsmith struct twe_softc *sc = tr->tr_sc; 170760894Smsmith TWE_Command *cmd = &tr->tr_command; 170860894Smsmith int i; 170960894Smsmith 171067555Smsmith twe_printf(sc, "CMD: request_id %d opcode <%s> size %d unit %d host_id %d\n", 171167555Smsmith cmd->generic.request_id, twe_describe_code(twe_table_opcode, cmd->generic.opcode), cmd->generic.size, 171267555Smsmith cmd->generic.unit, cmd->generic.host_id); 171367555Smsmith twe_printf(sc, " status %d flags 0x%x count %d sgl_offset %d\n", 171467555Smsmith cmd->generic.status, cmd->generic.flags, cmd->generic.count, cmd->generic.sgl_offset); 171567555Smsmith 171667555Smsmith switch(cmd->generic.opcode) { /* XXX add more opcodes? */ 171767555Smsmith case TWE_OP_READ: 171867555Smsmith case TWE_OP_WRITE: 171967555Smsmith twe_printf(sc, " lba %d\n", cmd->io.lba); 172067555Smsmith for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->io.sgl[i].length != 0); i++) 172167555Smsmith twe_printf(sc, " %d: 0x%x/%d\n", 172267555Smsmith i, cmd->io.sgl[i].address, cmd->io.sgl[i].length); 172360894Smsmith break; 172460894Smsmith 172567555Smsmith case TWE_OP_GET_PARAM: 172667555Smsmith case TWE_OP_SET_PARAM: 172767555Smsmith for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->param.sgl[i].length != 0); i++) 172867555Smsmith twe_printf(sc, " %d: 0x%x/%d\n", 172967555Smsmith i, cmd->param.sgl[i].address, cmd->param.sgl[i].length); 173060894Smsmith break; 173160894Smsmith 173267555Smsmith case TWE_OP_INIT_CONNECTION: 173367555Smsmith twe_printf(sc, " response queue pointer 0x%x\n", 173467555Smsmith cmd->initconnection.response_queue_pointer); 173567555Smsmith break; 173667555Smsmith 173760894Smsmith default: 173867555Smsmith break; 173960894Smsmith } 174067555Smsmith twe_printf(sc, " tr_command %p/0x%x tr_data %p/0x%x,%d\n", 174167555Smsmith tr, tr->tr_cmdphys, tr->tr_data, tr->tr_dataphys, tr->tr_length); 174267555Smsmith twe_printf(sc, " tr_status %d tr_flags 0x%x tr_complete %p tr_private %p\n", 174367555Smsmith tr->tr_status, tr->tr_flags, tr->tr_complete, tr->tr_private); 174460894Smsmith} 174560894Smsmith 174660894Smsmith#endif 1747