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