twe.c revision 197409
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: head/sys/dev/twe/twe.c 197409 2009-09-22 16:28:07Z rdivacky $
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 */
7167555Smsmithstatic void	twe_done(struct twe_softc *sc);
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	 */
15467555Smsmith	twe_release_request(tr);
15560894Smsmith    }
15660894Smsmith
15760894Smsmith    /*
15891790Smsmith     * Check status register for errors, clear them.
15991790Smsmith     */
16091790Smsmith    status_reg = TWE_STATUS(sc);
16191790Smsmith    twe_check_bits(sc, status_reg);
16291790Smsmith
16391790Smsmith    /*
16467555Smsmith     * Wait for the controller to come ready.
16560894Smsmith     */
16667555Smsmith    if (twe_wait_status(sc, TWE_STATUS_MICROCONTROLLER_READY, 60)) {
16767555Smsmith	twe_printf(sc, "microcontroller not ready\n");
16860894Smsmith	return(ENXIO);
16960894Smsmith    }
17060894Smsmith
17160894Smsmith    /*
17267555Smsmith     * Disable interrupts from the card.
17360894Smsmith     */
17467555Smsmith    twe_disable_interrupts(sc);
17560894Smsmith
17660894Smsmith    /*
17767555Smsmith     * Soft reset the controller, look for the AEN acknowledging the reset,
17867555Smsmith     * check for errors, drain the response queue.
17960894Smsmith     */
18067555Smsmith    for (i = 0; i < TWE_MAX_RESET_TRIES; i++) {
18160894Smsmith
18267555Smsmith	if (i > 0)
18367555Smsmith	    twe_printf(sc, "reset %d failed, trying again\n", i);
18467555Smsmith
18567555Smsmith	if (!twe_soft_reset(sc))
18667555Smsmith	    break;			/* reset process complete */
18767555Smsmith    }
18867555Smsmith    /* did we give up? */
18967555Smsmith    if (i >= TWE_MAX_RESET_TRIES) {
19067555Smsmith	twe_printf(sc, "can't initialise controller, giving up\n");
19160894Smsmith	return(ENXIO);
19260894Smsmith    }
19360894Smsmith
19460894Smsmith    return(0);
19560894Smsmith}
19660894Smsmith
197123103Spsstatic int
198118508Spstwe_add_unit(struct twe_softc *sc, int unit)
19960894Smsmith{
20060894Smsmith    struct twe_drive		*dr;
201123103Sps    int				table, error = 0;
20267555Smsmith    u_int16_t			dsize;
203118508Sps    TWE_Param			*drives = NULL, *param = NULL;
20467555Smsmith    TWE_Unit_Descriptor		*ud;
20560894Smsmith
206118508Sps    if (unit < 0 || unit > TWE_MAX_UNITS)
207123103Sps	return (EINVAL);
20860894Smsmith
20960894Smsmith    /*
21067555Smsmith     * The controller is in a safe state, so try to find drives attached to it.
21160894Smsmith     */
21267555Smsmith    if ((drives = twe_get_param(sc, TWE_PARAM_UNITSUMMARY, TWE_PARAM_UNITSUMMARY_Status,
21367555Smsmith				TWE_MAX_UNITS, NULL)) == NULL) {
21467555Smsmith	twe_printf(sc, "can't detect attached units\n");
215123103Sps	return (EIO);
21660894Smsmith    }
21760894Smsmith
218118508Sps    dr = &sc->twe_drive[unit];
219118508Sps    /* check that the drive is online */
220123103Sps    if (!(drives->data[unit] & TWE_PARAM_UNITSTATUS_Online)) {
221123103Sps	error = ENXIO;
222118508Sps	goto out;
223123103Sps    }
22460894Smsmith
225118508Sps    table = TWE_PARAM_UNITINFO + unit;
22660894Smsmith
227118508Sps    if (twe_get_param_4(sc, table, TWE_PARAM_UNITINFO_Capacity, &dr->td_size)) {
228118508Sps	twe_printf(sc, "error fetching capacity for unit %d\n", unit);
229123103Sps	error = EIO;
230118508Sps	goto out;
231118508Sps    }
232118508Sps    if (twe_get_param_1(sc, table, TWE_PARAM_UNITINFO_Status, &dr->td_state)) {
233118508Sps	twe_printf(sc, "error fetching state for unit %d\n", unit);
234123103Sps	error = EIO;
235118508Sps	goto out;
236118508Sps    }
237118508Sps    if (twe_get_param_2(sc, table, TWE_PARAM_UNITINFO_DescriptorSize, &dsize)) {
238118508Sps	twe_printf(sc, "error fetching descriptor size for unit %d\n", unit);
239123103Sps	error = EIO;
240118508Sps	goto out;
241118508Sps    }
242118508Sps    if ((param = twe_get_param(sc, table, TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL)) == NULL) {
243118508Sps	twe_printf(sc, "error fetching descriptor for unit %d\n", unit);
244123103Sps	error = EIO;
245118508Sps	goto out;
246118508Sps    }
247118508Sps    ud = (TWE_Unit_Descriptor *)param->data;
248118508Sps    dr->td_type = ud->configuration;
249118508Sps
250118508Sps    /* build synthetic geometry as per controller internal rules */
251118508Sps    if (dr->td_size > 0x200000) {
252118508Sps	dr->td_heads = 255;
253118508Sps	dr->td_sectors = 63;
254118508Sps    } else {
255118508Sps	dr->td_heads = 64;
256118508Sps	dr->td_sectors = 32;
257118508Sps    }
258118508Sps    dr->td_cylinders = dr->td_size / (dr->td_heads * dr->td_sectors);
259123103Sps    dr->td_twe_unit = unit;
260118508Sps
261123103Sps    error = twe_attach_drive(sc, dr);
262118508Sps
263118508Spsout:
264118508Sps    if (param != NULL)
26567555Smsmith	free(param, M_DEVBUF);
266118508Sps    if (drives != NULL)
267118508Sps	free(drives, M_DEVBUF);
268123103Sps    return (error);
269118508Sps}
27060894Smsmith
271123103Spsstatic int
272118508Spstwe_del_unit(struct twe_softc *sc, int unit)
273118508Sps{
274123103Sps    int error;
27560894Smsmith
276126099Scperciva    if (unit < 0 || unit >= TWE_MAX_UNITS)
277123103Sps	return (ENXIO);
27860894Smsmith
279123103Sps    if (sc->twe_drive[unit].td_disk == NULL)
280123103Sps	return (ENXIO);
281123103Sps
282123103Sps    error = twe_detach_drive(sc, unit);
283123103Sps    return (error);
284118508Sps}
285118508Sps
286118508Sps/********************************************************************************
287118508Sps * Locate disk devices and attach children to them.
288118508Sps */
289118508Spsvoid
290118508Spstwe_init(struct twe_softc *sc)
291118508Sps{
292118508Sps    int 		i;
293118508Sps
29460894Smsmith    /*
295118508Sps     * Scan for drives
296118508Sps     */
297118508Sps    for (i = 0; i < TWE_MAX_UNITS; i++)
298118508Sps	twe_add_unit(sc, i);
299118508Sps
300118508Sps    /*
30160894Smsmith     * Initialise connection with controller.
30260894Smsmith     */
30367555Smsmith    twe_init_connection(sc, TWE_INIT_MESSAGE_CREDITS);
30460894Smsmith
30567555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION
30667555Smsmith    /*
30767555Smsmith     * Tell the controller we support shutdown notification.
30867555Smsmith     */
30967555Smsmith    twe_set_param_1(sc, TWE_PARAM_FEATURES, TWE_PARAM_FEATURES_DriverShutdown, 1);
31067555Smsmith#endif
31167555Smsmith
31260894Smsmith    /*
31360894Smsmith     * Mark controller up and ready to run.
31460894Smsmith     */
31560894Smsmith    sc->twe_state &= ~TWE_STATE_SHUTDOWN;
31660894Smsmith
31760894Smsmith    /*
31867555Smsmith     * Finally enable interrupts.
31960894Smsmith     */
32060894Smsmith    twe_enable_interrupts(sc);
32160894Smsmith}
32260894Smsmith
32360894Smsmith/********************************************************************************
32467555Smsmith * Stop the controller
32560894Smsmith */
32667555Smsmithvoid
32767555Smsmithtwe_deinit(struct twe_softc *sc)
32860894Smsmith{
32960894Smsmith    /*
33060894Smsmith     * Mark the controller as shutting down, and disable any further interrupts.
33160894Smsmith     */
33260894Smsmith    sc->twe_state |= TWE_STATE_SHUTDOWN;
33360894Smsmith    twe_disable_interrupts(sc);
33460894Smsmith
33567555Smsmith#ifdef TWE_SHUTDOWN_NOTIFICATION
33667555Smsmith    /*
33767555Smsmith     * Disconnect from the controller
33860894Smsmith     */
33967555Smsmith    twe_init_connection(sc, TWE_SHUTDOWN_MESSAGE_CREDITS);
34067555Smsmith#endif
34160894Smsmith}
34260894Smsmith
34360894Smsmith/*******************************************************************************
34460894Smsmith * Take an interrupt, or be poked by other code to look for interrupt-worthy
34560894Smsmith * status.
34660894Smsmith */
34767555Smsmithvoid
34867555Smsmithtwe_intr(struct twe_softc *sc)
34960894Smsmith{
35060894Smsmith    u_int32_t		status_reg;
35160894Smsmith
35260894Smsmith    debug_called(4);
35360894Smsmith
35460894Smsmith    /*
35560894Smsmith     * Collect current interrupt status.
35660894Smsmith     */
35760894Smsmith    status_reg = TWE_STATUS(sc);
35860894Smsmith    twe_check_bits(sc, status_reg);
35960894Smsmith
36060894Smsmith    /*
36160894Smsmith     * Dispatch based on interrupt status
36260894Smsmith     */
36360894Smsmith    if (status_reg & TWE_STATUS_HOST_INTERRUPT)
36460894Smsmith	twe_host_intr(sc);
36560894Smsmith    if (status_reg & TWE_STATUS_ATTENTION_INTERRUPT)
36660894Smsmith	twe_attention_intr(sc);
36760894Smsmith    if (status_reg & TWE_STATUS_COMMAND_INTERRUPT)
36860894Smsmith	twe_command_intr(sc);
36973104Smsmith    if (status_reg & TWE_STATUS_RESPONSE_INTERRUPT)
37060894Smsmith	twe_done(sc);
37160894Smsmith};
37260894Smsmith
37369543Smsmith/********************************************************************************
37469543Smsmith * Pull as much work off the softc's work queue as possible and give it to the
37569543Smsmith * controller.
37660894Smsmith */
37769543Smsmithvoid
37869543Smsmithtwe_startio(struct twe_softc *sc)
37960894Smsmith{
38069543Smsmith    struct twe_request	*tr;
38169543Smsmith    TWE_Command		*cmd;
38269543Smsmith    twe_bio		*bp;
38369543Smsmith    int			error;
38469543Smsmith
38567555Smsmith    debug_called(4);
38660894Smsmith
387130358Svkashyap    if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN))
388118816Sps	return;
389118816Sps
39069543Smsmith    /* spin until something prevents us from doing any work */
39169543Smsmith    for (;;) {
39267555Smsmith
39369543Smsmith	/* try to get a command that's already ready to go */
39469543Smsmith	tr = twe_dequeue_ready(sc);
39569543Smsmith
39669543Smsmith	/* build a command from an outstanding bio */
39769543Smsmith	if (tr == NULL) {
39869543Smsmith
399129144Svkashyap	    /* get a command to handle the bio with */
400129144Svkashyap	    if (twe_get_request(sc, &tr))
40169543Smsmith		break;
40269543Smsmith
403129144Svkashyap	    /* see if there's work to be done */
404129144Svkashyap	    if ((bp = twe_dequeue_bio(sc)) == NULL) {
405129144Svkashyap		twe_release_request(tr);
40669543Smsmith		break;
40769543Smsmith	    }
40869543Smsmith
40969543Smsmith	    /* connect the bio to the command */
41069543Smsmith	    tr->tr_complete = twe_completeio;
41169543Smsmith	    tr->tr_private = bp;
41269543Smsmith	    tr->tr_data = TWE_BIO_DATA(bp);
41369543Smsmith	    tr->tr_length = TWE_BIO_LENGTH(bp);
414118816Sps	    cmd = TWE_FIND_COMMAND(tr);
41569543Smsmith	    if (TWE_BIO_IS_READ(bp)) {
41669543Smsmith		tr->tr_flags |= TWE_CMD_DATAIN;
41769543Smsmith		cmd->io.opcode = TWE_OP_READ;
41869543Smsmith	    } else {
41969543Smsmith		tr->tr_flags |= TWE_CMD_DATAOUT;
42069543Smsmith		cmd->io.opcode = TWE_OP_WRITE;
42169543Smsmith	    }
42269543Smsmith
42369543Smsmith	    /* build a suitable I/O command (assumes 512-byte rounded transfers) */
42469543Smsmith	    cmd->io.size = 3;
42569543Smsmith	    cmd->io.unit = TWE_BIO_UNIT(bp);
42669543Smsmith	    cmd->io.block_count = (tr->tr_length + TWE_BLOCK_SIZE - 1) / TWE_BLOCK_SIZE;
42769543Smsmith	    cmd->io.lba = TWE_BIO_LBA(bp);
42869543Smsmith	}
42969543Smsmith
43069543Smsmith	/* did we find something to do? */
43169543Smsmith	if (tr == NULL)
43269543Smsmith	    break;
43369543Smsmith
434127415Svkashyap	/* try to map and submit the command to controller */
435118816Sps	error = twe_map_request(tr);
436127415Svkashyap
43769543Smsmith	if (error != 0) {
438130358Svkashyap	    if (error == EBUSY)
439130358Svkashyap		break;
440127415Svkashyap	    tr->tr_status = TWE_CMD_ERROR;
441127415Svkashyap	    if (tr->tr_private != NULL) {
442127415Svkashyap		bp = (twe_bio *)(tr->tr_private);
443127415Svkashyap		TWE_BIO_SET_ERROR(bp, error);
444127415Svkashyap		tr->tr_private = NULL;
445127415Svkashyap		twed_intr(bp);
446127415Svkashyap	        twe_release_request(tr);
447127415Svkashyap	    } else if (tr->tr_flags & TWE_CMD_SLEEPER)
448127415Svkashyap		wakeup_one(tr); /* wakeup the sleeping owner */
44969543Smsmith	}
45069543Smsmith    }
45160894Smsmith}
45260894Smsmith
45360894Smsmith/********************************************************************************
45469543Smsmith * Write blocks from memory to disk, for system crash dumps.
45569543Smsmith */
45669543Smsmithint
45769543Smsmithtwe_dump_blocks(struct twe_softc *sc, int unit,	u_int32_t lba, void *data, int nblks)
45869543Smsmith{
45969543Smsmith    struct twe_request	*tr;
46069543Smsmith    TWE_Command		*cmd;
46169543Smsmith    int			error;
46269543Smsmith
46369543Smsmith    if (twe_get_request(sc, &tr))
46469543Smsmith	return(ENOMEM);
46569543Smsmith
46669543Smsmith    tr->tr_data = data;
46769543Smsmith    tr->tr_status = TWE_CMD_SETUP;
46869543Smsmith    tr->tr_length = nblks * TWE_BLOCK_SIZE;
46969543Smsmith    tr->tr_flags = TWE_CMD_DATAOUT;
47069543Smsmith
471118816Sps    cmd = TWE_FIND_COMMAND(tr);
47269543Smsmith    cmd->io.opcode = TWE_OP_WRITE;
47369543Smsmith    cmd->io.size = 3;
47469543Smsmith    cmd->io.unit = unit;
47569543Smsmith    cmd->io.block_count = nblks;
47669543Smsmith    cmd->io.lba = lba;
47769543Smsmith
478141492Sscottl    error = twe_immediate_request(tr, 0);
47969543Smsmith    if (error == 0)
48069543Smsmith	if (twe_report_request(tr))
48169543Smsmith	    error = EIO;
48269543Smsmith    twe_release_request(tr);
48369543Smsmith    return(error);
48469543Smsmith}
48569543Smsmith
48669543Smsmith/********************************************************************************
48767555Smsmith * Handle controller-specific control operations.
48860894Smsmith */
48967555Smsmithint
490197409Srdivackytwe_ioctl(struct twe_softc *sc, u_long ioctlcmd, void *addr)
49160894Smsmith{
49267555Smsmith    struct twe_usercommand	*tu = (struct twe_usercommand *)addr;
49367555Smsmith    struct twe_paramcommand	*tp = (struct twe_paramcommand *)addr;
494118508Sps    struct twe_drivecommand	*td = (struct twe_drivecommand *)addr;
49567555Smsmith    union twe_statrequest	*ts = (union twe_statrequest *)addr;
49667555Smsmith    TWE_Param			*param;
497118816Sps    TWE_Command			*cmd;
49867555Smsmith    void			*data;
499123103Sps    u_int16_t			*aen_code = (u_int16_t *)addr;
50067555Smsmith    struct twe_request		*tr;
50169543Smsmith    u_int8_t			srid;
50267555Smsmith    int				s, error;
50360894Smsmith
50467555Smsmith    error = 0;
505118816Sps    switch(ioctlcmd) {
50667555Smsmith	/* handle a command from userspace */
50767555Smsmith    case TWEIO_COMMAND:
50867555Smsmith	/* get a request */
509118508Sps	while (twe_get_request(sc, &tr))
510119124Sps	    tsleep(sc, PPAUSE, "twioctl", hz);
51167555Smsmith
51269543Smsmith	/*
51369543Smsmith	 * Save the command's request ID, copy the user-supplied command in,
51469543Smsmith	 * restore the request ID.
51569543Smsmith	 */
516118816Sps	cmd = TWE_FIND_COMMAND(tr);
517118816Sps	srid = cmd->generic.request_id;
518118816Sps	bcopy(&tu->tu_command, cmd, sizeof(TWE_Command));
519118816Sps	cmd->generic.request_id = srid;
52067555Smsmith
521118508Sps	/*
522118508Sps	 * if there's a data buffer, allocate and copy it in.
523118508Sps	 * Must be in multipled of 512 bytes.
524118508Sps	 */
525118508Sps	tr->tr_length = (tu->tu_size + 511) & ~511;
52667555Smsmith	if (tr->tr_length > 0) {
527111119Simp	    if ((tr->tr_data = malloc(tr->tr_length, M_DEVBUF, M_WAITOK)) == NULL) {
52867555Smsmith		error = ENOMEM;
52967555Smsmith		goto cmd_done;
53067555Smsmith	    }
531118508Sps	    if ((error = copyin(tu->tu_data, tr->tr_data, tu->tu_size)) != 0)
53267555Smsmith		goto cmd_done;
53367555Smsmith	    tr->tr_flags |= TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
53467555Smsmith	}
53567555Smsmith
53667555Smsmith	/* run the command */
537127415Svkashyap	error = twe_wait_request(tr);
538127415Svkashyap	if (error)
539127415Svkashyap	    goto cmd_done;
54067555Smsmith
54167555Smsmith	/* copy the command out again */
542118816Sps	bcopy(cmd, &tu->tu_command, sizeof(TWE_Command));
54367555Smsmith
54467555Smsmith	/* if there was a data buffer, copy it out */
54567555Smsmith	if (tr->tr_length > 0)
546118508Sps	    error = copyout(tr->tr_data, tu->tu_data, tu->tu_size);
54767555Smsmith
54867555Smsmith    cmd_done:
54967555Smsmith	/* free resources */
55067555Smsmith	if (tr->tr_data != NULL)
55167555Smsmith	    free(tr->tr_data, M_DEVBUF);
55267555Smsmith	if (tr != NULL)
55367555Smsmith	    twe_release_request(tr);
55467555Smsmith
55567555Smsmith	break;
55667555Smsmith
55767555Smsmith	/* fetch statistics counter */
55867555Smsmith    case TWEIO_STATS:
55967555Smsmith	switch (ts->ts_item) {
56067555Smsmith#ifdef TWE_PERFORMANCE_MONITOR
56167555Smsmith	case TWEQ_FREE:
56267555Smsmith	case TWEQ_BIO:
56367555Smsmith	case TWEQ_READY:
56467555Smsmith	case TWEQ_BUSY:
56567555Smsmith	case TWEQ_COMPLETE:
56667555Smsmith	    bcopy(&sc->twe_qstat[ts->ts_item], &ts->ts_qstat, sizeof(struct twe_qstat));
56767555Smsmith	    break;
56867555Smsmith#endif
56967555Smsmith	default:
57067555Smsmith	    error = ENOENT;
57167555Smsmith	    break;
57267555Smsmith	}
57367555Smsmith	break;
57467555Smsmith
57567555Smsmith	/* poll for an AEN */
57667555Smsmith    case TWEIO_AEN_POLL:
577123103Sps	*aen_code = twe_dequeue_aen(sc);
57867555Smsmith	break;
57967555Smsmith
58067555Smsmith	/* wait for another AEN to show up */
58167555Smsmith    case TWEIO_AEN_WAIT:
58267555Smsmith	s = splbio();
583123103Sps	while ((*aen_code = twe_dequeue_aen(sc)) == TWE_AEN_QUEUE_EMPTY) {
58467555Smsmith	    error = tsleep(&sc->twe_aen_queue, PRIBIO | PCATCH, "tweaen", 0);
58567555Smsmith	    if (error == EINTR)
58667555Smsmith		break;
58767555Smsmith	}
58867555Smsmith	splx(s);
58967555Smsmith	break;
59067555Smsmith
59167555Smsmith    case TWEIO_GET_PARAM:
59267555Smsmith	if ((param = twe_get_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, NULL)) == NULL) {
59367555Smsmith	    twe_printf(sc, "TWEIO_GET_PARAM failed for 0x%x/0x%x/%d\n",
59467555Smsmith		       tp->tp_table_id, tp->tp_param_id, tp->tp_size);
59567555Smsmith	    error = EINVAL;
59667555Smsmith	} else {
59767555Smsmith	    if (param->parameter_size_bytes > tp->tp_size) {
59867555Smsmith		twe_printf(sc, "TWEIO_GET_PARAM parameter too large (%d > %d)\n",
59967555Smsmith			   param->parameter_size_bytes, tp->tp_size);
60067555Smsmith		error = EFAULT;
60167555Smsmith	    } else {
60267555Smsmith		error = copyout(param->data, tp->tp_data, param->parameter_size_bytes);
60367555Smsmith	    }
60467555Smsmith	    free(param, M_DEVBUF);
60567555Smsmith	}
60667555Smsmith	break;
60767555Smsmith
60867555Smsmith    case TWEIO_SET_PARAM:
609111119Simp	if ((data = malloc(tp->tp_size, M_DEVBUF, M_WAITOK)) == NULL) {
61067555Smsmith	    error = ENOMEM;
61167555Smsmith	} else {
61267555Smsmith	    error = copyin(tp->tp_data, data, tp->tp_size);
61367555Smsmith	    if (error == 0)
61467555Smsmith		error = twe_set_param(sc, tp->tp_table_id, tp->tp_param_id, tp->tp_size, data);
61567555Smsmith	    free(data, M_DEVBUF);
61667555Smsmith	}
61767555Smsmith	break;
61867555Smsmith
61967555Smsmith    case TWEIO_RESET:
62067555Smsmith	twe_reset(sc);
62167555Smsmith	break;
62267555Smsmith
623118508Sps    case TWEIO_ADD_UNIT:
624123103Sps	error = twe_add_unit(sc, td->td_unit);
625118508Sps	break;
626118508Sps
627118508Sps    case TWEIO_DEL_UNIT:
628123103Sps	error = twe_del_unit(sc, td->td_unit);
629118508Sps	break;
630118508Sps
63191790Smsmith	/* XXX implement ATA PASSTHROUGH */
63291790Smsmith
63367555Smsmith	/* nothing we understand */
63467555Smsmith    default:
63567555Smsmith	error = ENOTTY;
63667555Smsmith    }
63767555Smsmith
63867555Smsmith    return(error);
63960894Smsmith}
64060894Smsmith
64160894Smsmith/********************************************************************************
64267555Smsmith * Enable the useful interrupts from the controller.
64360894Smsmith */
64467555Smsmithvoid
64567555Smsmithtwe_enable_interrupts(struct twe_softc *sc)
64660894Smsmith{
64767555Smsmith    sc->twe_state |= TWE_STATE_INTEN;
64867555Smsmith    TWE_CONTROL(sc,
64967555Smsmith	       TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT |
65067555Smsmith	       TWE_CONTROL_UNMASK_RESPONSE_INTERRUPT |
65167555Smsmith	       TWE_CONTROL_ENABLE_INTERRUPTS);
65260894Smsmith}
65360894Smsmith
65460894Smsmith/********************************************************************************
65567555Smsmith * Disable interrupts from the controller.
65667555Smsmith */
65767555Smsmithvoid
65867555Smsmithtwe_disable_interrupts(struct twe_softc *sc)
65967555Smsmith{
66067555Smsmith    TWE_CONTROL(sc, TWE_CONTROL_DISABLE_INTERRUPTS);
66167555Smsmith    sc->twe_state &= ~TWE_STATE_INTEN;
66267555Smsmith}
66367555Smsmith
66467555Smsmith/********************************************************************************
66560894Smsmith ********************************************************************************
66660894Smsmith                                                               Command Submission
66760894Smsmith ********************************************************************************
66860894Smsmith ********************************************************************************/
66960894Smsmith
67067555Smsmith/********************************************************************************
67167555Smsmith * Read integer parameter table entries.
67260894Smsmith */
67367555Smsmithstatic int
67467555Smsmithtwe_get_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t *result)
67560894Smsmith{
67667555Smsmith    TWE_Param	*param;
67760894Smsmith
67867555Smsmith    if ((param = twe_get_param(sc, table_id, param_id, 1, NULL)) == NULL)
67967555Smsmith	return(ENOENT);
68067555Smsmith    *result = *(u_int8_t *)param->data;
68167555Smsmith    free(param, M_DEVBUF);
68267555Smsmith    return(0);
68367555Smsmith}
68460894Smsmith
68567555Smsmithstatic int
68667555Smsmithtwe_get_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t *result)
68767555Smsmith{
68867555Smsmith    TWE_Param	*param;
68967555Smsmith
69067555Smsmith    if ((param = twe_get_param(sc, table_id, param_id, 2, NULL)) == NULL)
69167555Smsmith	return(ENOENT);
69267555Smsmith    *result = *(u_int16_t *)param->data;
69367555Smsmith    free(param, M_DEVBUF);
69460894Smsmith    return(0);
69560894Smsmith}
69660894Smsmith
69767555Smsmithstatic int
69867555Smsmithtwe_get_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t *result)
69967555Smsmith{
70067555Smsmith    TWE_Param	*param;
70167555Smsmith
70267555Smsmith    if ((param = twe_get_param(sc, table_id, param_id, 4, NULL)) == NULL)
70367555Smsmith	return(ENOENT);
70467555Smsmith    *result = *(u_int32_t *)param->data;
70567555Smsmith    free(param, M_DEVBUF);
70667555Smsmith    return(0);
70767555Smsmith}
70867555Smsmith
70960894Smsmith/********************************************************************************
71060894Smsmith * Perform a TWE_OP_GET_PARAM command.  If a callback function is provided, it
71160894Smsmith * will be called with the command when it's completed.  If no callback is
71260894Smsmith * provided, we will wait for the command to complete and then return just the data.
71360894Smsmith * The caller is responsible for freeing the data when done with it.
71460894Smsmith */
71560894Smsmithstatic void *
71667555Smsmithtwe_get_param(struct twe_softc *sc, int table_id, int param_id, size_t param_size,
71767555Smsmith	      void (* func)(struct twe_request *tr))
71860894Smsmith{
71960894Smsmith    struct twe_request	*tr;
72060894Smsmith    TWE_Command		*cmd;
72160894Smsmith    TWE_Param		*param;
72260894Smsmith    int			error;
72360894Smsmith
72460894Smsmith    debug_called(4);
72560894Smsmith
72660894Smsmith    tr = NULL;
72760894Smsmith    param = NULL;
72860894Smsmith
72960894Smsmith    /* get a command */
73067555Smsmith    if (twe_get_request(sc, &tr))
73160894Smsmith	goto err;
73260894Smsmith
73360894Smsmith    /* get a buffer */
73460894Smsmith    if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL)
73560894Smsmith	goto err;
73660894Smsmith    tr->tr_data = param;
73760894Smsmith    tr->tr_length = TWE_SECTOR_SIZE;
73860894Smsmith    tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
73960894Smsmith
74060894Smsmith    /* build the command for the controller */
741118816Sps    cmd = TWE_FIND_COMMAND(tr);
74267555Smsmith    cmd->param.opcode = TWE_OP_GET_PARAM;
74367555Smsmith    cmd->param.size = 2;
74467555Smsmith    cmd->param.unit = 0;
74567555Smsmith    cmd->param.param_count = 1;
74660894Smsmith
74760894Smsmith    /* fill in the outbound parameter data */
74860894Smsmith    param->table_id = table_id;
74967555Smsmith    param->parameter_id = param_id;
75067555Smsmith    param->parameter_size_bytes = param_size;
75160894Smsmith
75260894Smsmith    /* submit the command and either wait or let the callback handle it */
75360894Smsmith    if (func == NULL) {
75460894Smsmith	/* XXX could use twe_wait_request here if interrupts were enabled? */
755141492Sscottl	error = twe_immediate_request(tr, 1 /* usetmp */);
75660894Smsmith	if (error == 0) {
75769543Smsmith	    if (twe_report_request(tr))
75860894Smsmith		goto err;
759123103Sps	} else {
760123103Sps	    goto err;
76160894Smsmith	}
76267555Smsmith	twe_release_request(tr);
76367555Smsmith	return(param);
76460894Smsmith    } else {
76560894Smsmith	tr->tr_complete = func;
766118816Sps	error = twe_map_request(tr);
767130358Svkashyap	if ((error == 0) || (error == EBUSY))
76860894Smsmith	    return(func);
76960894Smsmith    }
77060894Smsmith
77160894Smsmith    /* something failed */
77260894Smsmitherr:
77360894Smsmith    debug(1, "failed");
77460894Smsmith    if (tr != NULL)
77560894Smsmith	twe_release_request(tr);
77660894Smsmith    if (param != NULL)
77760894Smsmith	free(param, M_DEVBUF);
77860894Smsmith    return(NULL);
77960894Smsmith}
78060894Smsmith
78160894Smsmith/********************************************************************************
78267555Smsmith * Set integer parameter table entries.
78367555Smsmith */
78491449Speter#ifdef TWE_SHUTDOWN_NOTIFICATION
78567555Smsmithstatic int
78667555Smsmithtwe_set_param_1(struct twe_softc *sc, int table_id, int param_id, u_int8_t value)
78767555Smsmith{
78867555Smsmith    return(twe_set_param(sc, table_id, param_id, sizeof(value), &value));
78967555Smsmith}
79091449Speter#endif
79167555Smsmith
79291449Speter#if 0
79367555Smsmithstatic int
79467555Smsmithtwe_set_param_2(struct twe_softc *sc, int table_id, int param_id, u_int16_t value)
79567555Smsmith{
79667555Smsmith    return(twe_set_param(sc, table_id, param_id, sizeof(value), &value));
79767555Smsmith}
79867555Smsmith
79967555Smsmithstatic int
80067555Smsmithtwe_set_param_4(struct twe_softc *sc, int table_id, int param_id, u_int32_t value)
80167555Smsmith{
80267555Smsmith    return(twe_set_param(sc, table_id, param_id, sizeof(value), &value));
80367555Smsmith}
80491449Speter#endif
80567555Smsmith
80667555Smsmith/********************************************************************************
80767555Smsmith * Perform a TWE_OP_SET_PARAM command, returns nonzero on error.
80867555Smsmith */
80967555Smsmithstatic int
81067555Smsmithtwe_set_param(struct twe_softc *sc, int table_id, int param_id, int param_size, void *data)
81167555Smsmith{
81267555Smsmith    struct twe_request	*tr;
81367555Smsmith    TWE_Command		*cmd;
81467555Smsmith    TWE_Param		*param;
81567555Smsmith    int			error;
81667555Smsmith
81767555Smsmith    debug_called(4);
81867555Smsmith
81967555Smsmith    tr = NULL;
82067555Smsmith    param = NULL;
82167555Smsmith    error = ENOMEM;
82267555Smsmith
82367555Smsmith    /* get a command */
82467555Smsmith    if (twe_get_request(sc, &tr))
82567555Smsmith	goto out;
82667555Smsmith
82767555Smsmith    /* get a buffer */
82867555Smsmith    if ((param = (TWE_Param *)malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT)) == NULL)
82967555Smsmith	goto out;
83067555Smsmith    tr->tr_data = param;
83167555Smsmith    tr->tr_length = TWE_SECTOR_SIZE;
83267555Smsmith    tr->tr_flags = TWE_CMD_DATAIN | TWE_CMD_DATAOUT;
83367555Smsmith
83467555Smsmith    /* build the command for the controller */
835118816Sps    cmd = TWE_FIND_COMMAND(tr);
83667555Smsmith    cmd->param.opcode = TWE_OP_SET_PARAM;
83767555Smsmith    cmd->param.size = 2;
83867555Smsmith    cmd->param.unit = 0;
83967555Smsmith    cmd->param.param_count = 1;
84067555Smsmith
84167555Smsmith    /* fill in the outbound parameter data */
84267555Smsmith    param->table_id = table_id;
84367555Smsmith    param->parameter_id = param_id;
84467555Smsmith    param->parameter_size_bytes = param_size;
84567555Smsmith    bcopy(data, param->data, param_size);
84667555Smsmith
84767555Smsmith    /* XXX could use twe_wait_request here if interrupts were enabled? */
848141492Sscottl    error = twe_immediate_request(tr, 1 /* usetmp */);
84967555Smsmith    if (error == 0) {
85069543Smsmith	if (twe_report_request(tr))
85167555Smsmith	    error = EIO;
85267555Smsmith    }
85367555Smsmith
85467555Smsmithout:
85567555Smsmith    if (tr != NULL)
85667555Smsmith	twe_release_request(tr);
85767555Smsmith    if (param != NULL)
85867555Smsmith	free(param, M_DEVBUF);
85967555Smsmith    return(error);
86067555Smsmith}
86167555Smsmith
86267555Smsmith/********************************************************************************
86360894Smsmith * Perform a TWE_OP_INIT_CONNECTION command, returns nonzero on error.
86460894Smsmith *
86560894Smsmith * Typically called with interrupts disabled.
86660894Smsmith */
86760894Smsmithstatic int
86867555Smsmithtwe_init_connection(struct twe_softc *sc, int mode)
86960894Smsmith{
87060894Smsmith    struct twe_request	*tr;
87160894Smsmith    TWE_Command		*cmd;
87260894Smsmith    int			error;
87360894Smsmith
87460894Smsmith    debug_called(4);
87560894Smsmith
87660894Smsmith    /* get a command */
87767555Smsmith    if (twe_get_request(sc, &tr))
878102291Sarchie	return(0);
87960894Smsmith
88060894Smsmith    /* build the command */
881118816Sps    cmd = TWE_FIND_COMMAND(tr);
88267555Smsmith    cmd->initconnection.opcode = TWE_OP_INIT_CONNECTION;
88367555Smsmith    cmd->initconnection.size = 3;
88467555Smsmith    cmd->initconnection.host_id = 0;
88567555Smsmith    cmd->initconnection.message_credits = mode;
88667555Smsmith    cmd->initconnection.response_queue_pointer = 0;
88760894Smsmith
88860894Smsmith    /* submit the command */
889141492Sscottl    error = twe_immediate_request(tr, 0 /* usetmp */);
89060894Smsmith    twe_release_request(tr);
89160894Smsmith
89267555Smsmith    if (mode == TWE_INIT_MESSAGE_CREDITS)
89367555Smsmith	sc->twe_host_id = cmd->initconnection.host_id;
89460894Smsmith    return(error);
89560894Smsmith}
89660894Smsmith
89760894Smsmith/********************************************************************************
89860894Smsmith * Start the command (tr) and sleep waiting for it to complete.
89960894Smsmith *
90060894Smsmith * Successfully completed commands are dequeued.
90160894Smsmith */
90260894Smsmithstatic int
90360894Smsmithtwe_wait_request(struct twe_request *tr)
90460894Smsmith{
90567555Smsmith    int		s;
90660894Smsmith
90760894Smsmith    debug_called(4);
90860894Smsmith
90967555Smsmith    tr->tr_flags |= TWE_CMD_SLEEPER;
91067555Smsmith    tr->tr_status = TWE_CMD_BUSY;
91167555Smsmith    twe_enqueue_ready(tr);
91267555Smsmith    twe_startio(tr->tr_sc);
91360894Smsmith    s = splbio();
91467555Smsmith    while (tr->tr_status == TWE_CMD_BUSY)
91567555Smsmith	tsleep(tr, PRIBIO, "twewait", 0);
91660894Smsmith    splx(s);
91767555Smsmith
918127415Svkashyap    return(tr->tr_status != TWE_CMD_COMPLETE);
91960894Smsmith}
92060894Smsmith
92160894Smsmith/********************************************************************************
92260894Smsmith * Start the command (tr) and busy-wait for it to complete.
92360894Smsmith * This should only be used when interrupts are actually disabled (although it
92460894Smsmith * will work if they are not).
92560894Smsmith */
92660894Smsmithstatic int
927141492Sscottltwe_immediate_request(struct twe_request *tr, int usetmp)
92860894Smsmith{
929141492Sscottl    struct twe_softc *sc;
930127415Svkashyap    int		error;
931141492Sscottl    int		count = 0;
93260894Smsmith
93360894Smsmith    debug_called(4);
93460894Smsmith
935141492Sscottl    sc = tr->tr_sc;
936141492Sscottl
937141492Sscottl    if (usetmp && (tr->tr_data != NULL)) {
938141492Sscottl	tr->tr_flags |= TWE_CMD_IMMEDIATE;
939141492Sscottl	if (tr->tr_length > MAXBSIZE)
940141492Sscottl	    return (EINVAL);
941141492Sscottl	bcopy(tr->tr_data, sc->twe_immediate, tr->tr_length);
942141492Sscottl    }
943118816Sps    tr->tr_status = TWE_CMD_BUSY;
944127415Svkashyap    if ((error = twe_map_request(tr)) != 0)
945130358Svkashyap	if (error != EBUSY)
946130358Svkashyap	    return(error);
947141492Sscottl
948141492Sscottl    /* Wait up to 5 seconds for the command to complete */
949141492Sscottl    while ((count++ < 5000) && (tr->tr_status == TWE_CMD_BUSY)){
950141492Sscottl	DELAY(1000);
951141492Sscottl	twe_done(sc);
95260894Smsmith    }
953141492Sscottl    if (usetmp && (tr->tr_data != NULL))
954141492Sscottl	bcopy(sc->twe_immediate, tr->tr_data, tr->tr_length);
955141492Sscottl
95660894Smsmith    return(tr->tr_status != TWE_CMD_COMPLETE);
95760894Smsmith}
95860894Smsmith
95960894Smsmith/********************************************************************************
96060894Smsmith * Handle completion of an I/O command.
96160894Smsmith */
96260894Smsmithstatic void
96360894Smsmithtwe_completeio(struct twe_request *tr)
96460894Smsmith{
965123103Sps    TWE_Command		*cmd = TWE_FIND_COMMAND(tr);
96660894Smsmith    struct twe_softc	*sc = tr->tr_sc;
96767555Smsmith    twe_bio		*bp = (twe_bio *)tr->tr_private;
96860894Smsmith
96960894Smsmith    debug_called(4);
97060894Smsmith
97160894Smsmith    if (tr->tr_status == TWE_CMD_COMPLETE) {
97267555Smsmith
973123103Sps	if (cmd->generic.status)
974123103Sps	    if (twe_report_request(tr))
975123103Sps		TWE_BIO_SET_ERROR(bp, EIO);
97667555Smsmith
97769543Smsmith    } else {
97869543Smsmith	twe_panic(sc, "twe_completeio on incomplete command");
97960894Smsmith    }
98069543Smsmith    tr->tr_private = NULL;
98169543Smsmith    twed_intr(bp);
98260894Smsmith    twe_release_request(tr);
98360894Smsmith}
98460894Smsmith
98560894Smsmith/********************************************************************************
98667555Smsmith * Reset the controller and pull all the active commands back onto the ready
98767555Smsmith * queue.  Used to restart a controller that's exhibiting bad behaviour.
98867555Smsmith */
98967555Smsmithstatic void
99067555Smsmithtwe_reset(struct twe_softc *sc)
99167555Smsmith{
99267555Smsmith    struct twe_request	*tr;
99367555Smsmith    int			i, s;
99467555Smsmith
99591790Smsmith    /*
99691790Smsmith     * Sleep for a short period to allow AENs to be signalled.
99791790Smsmith     */
998119124Sps    tsleep(sc, PRIBIO, "twereset", hz);
99967555Smsmith
100067555Smsmith    /*
100167555Smsmith     * Disable interrupts from the controller, and mask any accidental entry
100267555Smsmith     * into our interrupt handler.
100367555Smsmith     */
100491790Smsmith    twe_printf(sc, "controller reset in progress...\n");
100567555Smsmith    twe_disable_interrupts(sc);
100667555Smsmith    s = splbio();
100767555Smsmith
100867555Smsmith    /*
100967555Smsmith     * Try to soft-reset the controller.
101067555Smsmith     */
101167555Smsmith    for (i = 0; i < TWE_MAX_RESET_TRIES; i++) {
101267555Smsmith
101367555Smsmith	if (i > 0)
101467555Smsmith	    twe_printf(sc, "reset %d failed, trying again\n", i);
101567555Smsmith
101667555Smsmith	if (!twe_soft_reset(sc))
101767555Smsmith	    break;			/* reset process complete */
101867555Smsmith    }
101967555Smsmith    /* did we give up? */
102067555Smsmith    if (i >= TWE_MAX_RESET_TRIES) {
102167555Smsmith	twe_printf(sc, "can't reset controller, giving up\n");
102267555Smsmith	goto out;
102367555Smsmith    }
102467555Smsmith
102567555Smsmith    /*
102667555Smsmith     * Move all of the commands that were busy back to the ready queue.
102767555Smsmith     */
102867555Smsmith    i = 0;
102967555Smsmith    while ((tr = twe_dequeue_busy(sc)) != NULL) {
103067555Smsmith	twe_enqueue_ready(tr);
103167555Smsmith	i++;
103267555Smsmith    }
103367555Smsmith
103467555Smsmith    /*
103567555Smsmith     * Kick the controller to start things going again, then re-enable interrupts.
103667555Smsmith     */
103767555Smsmith    twe_startio(sc);
103867555Smsmith    twe_enable_interrupts(sc);
103967555Smsmith    twe_printf(sc, "controller reset done, %d commands restarted\n", i);
104067555Smsmith
104167555Smsmithout:
104267555Smsmith    splx(s);
104367555Smsmith    twe_enable_interrupts(sc);
104467555Smsmith}
104567555Smsmith
104667555Smsmith/********************************************************************************
104760894Smsmith ********************************************************************************
104860894Smsmith                                                        Command I/O to Controller
104960894Smsmith ********************************************************************************
105060894Smsmith ********************************************************************************/
105160894Smsmith
105260894Smsmith/********************************************************************************
105360894Smsmith * Try to deliver (tr) to the controller.
105460894Smsmith *
105560894Smsmith * Can be called at any interrupt level, with or without interrupts enabled.
105660894Smsmith */
1057118816Spsint
105860894Smsmithtwe_start(struct twe_request *tr)
105960894Smsmith{
106060894Smsmith    struct twe_softc	*sc = tr->tr_sc;
1061118816Sps    TWE_Command		*cmd;
106260894Smsmith    int			i, s, done;
106360894Smsmith    u_int32_t		status_reg;
106460894Smsmith
106560894Smsmith    debug_called(4);
106660894Smsmith
106760894Smsmith    /* mark the command as currently being processed */
106860894Smsmith    tr->tr_status = TWE_CMD_BUSY;
1069118816Sps    cmd = TWE_FIND_COMMAND(tr);
107060894Smsmith
107167555Smsmith    /*
107267555Smsmith     * Spin briefly waiting for the controller to come ready
107367555Smsmith     *
107467555Smsmith     * XXX it might be more efficient to return EBUSY immediately
107567555Smsmith     *     and let the command be rescheduled.
107667555Smsmith     */
107760894Smsmith    for (i = 100000, done = 0; (i > 0) && !done; i--) {
107860894Smsmith	s = splbio();
107960894Smsmith
108060894Smsmith	/* check to see if we can post a command */
108160894Smsmith	status_reg = TWE_STATUS(sc);
108260894Smsmith	twe_check_bits(sc, status_reg);
108360894Smsmith
108460894Smsmith	if (!(status_reg & TWE_STATUS_COMMAND_QUEUE_FULL)) {
1085118816Sps	    twe_enqueue_busy(tr);
1086118816Sps
1087118816Sps	    TWE_COMMAND_QUEUE(sc, TWE_FIND_COMMANDPHYS(tr));
108860894Smsmith	    done = 1;
108960894Smsmith	    /* move command to work queue */
109067555Smsmith#ifdef TWE_DEBUG
109160894Smsmith	    if (tr->tr_complete != NULL) {
1092118816Sps		debug(3, "queued request %d with callback %p", cmd->generic.request_id, tr->tr_complete);
109367555Smsmith	    } else if (tr->tr_flags & TWE_CMD_SLEEPER) {
1094118816Sps		debug(3, "queued request %d with wait channel %p", cmd->generic.request_id, tr);
109560894Smsmith	    } else {
1096118816Sps		debug(3, "queued request %d for polling caller", cmd->generic.request_id);
109760894Smsmith	    }
109867555Smsmith#endif
109960894Smsmith	}
110060894Smsmith	splx(s);	/* drop spl to allow completion interrupts */
110160894Smsmith    }
110260894Smsmith
110360894Smsmith    /* command is enqueued */
110460894Smsmith    if (done)
110560894Smsmith	return(0);
110660894Smsmith
110760894Smsmith    /*
110860894Smsmith     * We couldn't get the controller to take the command; try submitting it again later.
110960894Smsmith     * This should only happen if something is wrong with the controller, or if we have
111060894Smsmith     * overestimated the number of commands it can accept.  (Should we actually reject
111160894Smsmith     * the command at this point?)
111260894Smsmith     */
111360894Smsmith    return(EBUSY);
111460894Smsmith}
111560894Smsmith
111660894Smsmith/********************************************************************************
111760894Smsmith * Poll the controller (sc) for completed commands.
111860894Smsmith *
111960894Smsmith * Can be called at any interrupt level, with or without interrupts enabled.
112060894Smsmith */
112160894Smsmithstatic void
112260894Smsmithtwe_done(struct twe_softc *sc)
112360894Smsmith{
112460894Smsmith    TWE_Response_Queue	rq;
1125118816Sps    TWE_Command		*cmd;
112660894Smsmith    struct twe_request	*tr;
112760894Smsmith    int			s, found;
112860894Smsmith    u_int32_t		status_reg;
112960894Smsmith
113060894Smsmith    debug_called(5);
113160894Smsmith
113260894Smsmith    /* loop collecting completed commands */
113360894Smsmith    found = 0;
113460894Smsmith    s = splbio();
113560894Smsmith    for (;;) {
113660894Smsmith	status_reg = TWE_STATUS(sc);
113760894Smsmith	twe_check_bits(sc, status_reg);		/* XXX should this fail? */
113860894Smsmith
113960894Smsmith	if (!(status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)) {
114060894Smsmith	    found = 1;
114160894Smsmith	    rq = TWE_RESPONSE_QUEUE(sc);
114267555Smsmith	    tr = sc->twe_lookup[rq.u.response_id];	/* find command */
1143118816Sps	    cmd = TWE_FIND_COMMAND(tr);
114469543Smsmith	    if (tr->tr_status != TWE_CMD_BUSY)
114569543Smsmith		twe_printf(sc, "completion event for nonbusy command\n");
114669543Smsmith	    tr->tr_status = TWE_CMD_COMPLETE;
114769543Smsmith	    debug(3, "completed request id %d with status %d",
1148118816Sps		  cmd->generic.request_id, cmd->generic.status);
114969543Smsmith	    /* move to completed queue */
115069543Smsmith	    twe_remove_busy(tr);
115169543Smsmith	    twe_enqueue_complete(tr);
1152130358Svkashyap	    sc->twe_state &= ~TWE_STATE_CTLR_BUSY;
115360894Smsmith	} else {
115460894Smsmith	    break;					/* no response ready */
115560894Smsmith	}
115660894Smsmith    }
115760894Smsmith    splx(s);
115860894Smsmith
115960894Smsmith    /* if we've completed any commands, try posting some more */
116060894Smsmith    if (found)
116160894Smsmith	twe_startio(sc);
116260894Smsmith
116360894Smsmith    /* handle completion and timeouts */
116467555Smsmith    twe_complete(sc);		/* XXX use deferred completion? */
116560894Smsmith}
116660894Smsmith
116760894Smsmith/********************************************************************************
116860894Smsmith * Perform post-completion processing for commands on (sc).
116960894Smsmith *
117060894Smsmith * This is split from twe_done as it can be safely deferred and run at a lower
117160894Smsmith * priority level should facilities for such a thing become available.
117260894Smsmith */
117360894Smsmithstatic void
117460894Smsmithtwe_complete(struct twe_softc *sc)
117560894Smsmith{
117667555Smsmith    struct twe_request	*tr;
117760894Smsmith
117860894Smsmith    debug_called(5);
117960894Smsmith
118060894Smsmith    /*
118167555Smsmith     * Pull commands off the completed list, dispatch them appropriately
118260894Smsmith     */
118367555Smsmith    while ((tr = twe_dequeue_complete(sc)) != NULL) {
118467555Smsmith	/* unmap the command's data buffer */
118567555Smsmith	twe_unmap_request(tr);
118660894Smsmith
118767555Smsmith	/* dispatch to suit command originator */
118867555Smsmith	if (tr->tr_complete != NULL) {		/* completion callback */
118967555Smsmith	    debug(2, "call completion handler %p", tr->tr_complete);
119067555Smsmith	    tr->tr_complete(tr);
119160894Smsmith
119267555Smsmith	} else if (tr->tr_flags & TWE_CMD_SLEEPER) {	/* caller is asleep waiting */
119367555Smsmith	    debug(2, "wake up command owner on %p", tr);
119467555Smsmith	    wakeup_one(tr);
119560894Smsmith
119667555Smsmith	} else {					/* caller is polling command */
119767555Smsmith	    debug(2, "command left for owner");
119860894Smsmith	}
119967555Smsmith    }
120060894Smsmith}
120160894Smsmith
120260894Smsmith/********************************************************************************
120360894Smsmith * Wait for (status) to be set in the controller status register for up to
120460894Smsmith * (timeout) seconds.  Returns 0 if found, nonzero if we time out.
120560894Smsmith *
120660894Smsmith * Note: this busy-waits, rather than sleeping, since we may be called with
120760894Smsmith * eg. clock interrupts masked.
120860894Smsmith */
120960894Smsmithstatic int
121060894Smsmithtwe_wait_status(struct twe_softc *sc, u_int32_t status, int timeout)
121160894Smsmith{
121260894Smsmith    time_t	expiry;
121360894Smsmith    u_int32_t	status_reg;
121460894Smsmith
121560894Smsmith    debug_called(4);
121660894Smsmith
121760894Smsmith    expiry = time_second + timeout;
121860894Smsmith
121960894Smsmith    do {
122060894Smsmith	status_reg = TWE_STATUS(sc);
122160894Smsmith	if (status_reg & status)	/* got the required bit(s)? */
122260894Smsmith	    return(0);
122360894Smsmith	DELAY(100000);
122460894Smsmith    } while (time_second <= expiry);
122560894Smsmith
122660894Smsmith    return(1);
122760894Smsmith}
122860894Smsmith
122960894Smsmith/********************************************************************************
123060894Smsmith * Drain the response queue, which may contain responses to commands we know
123160894Smsmith * nothing about.
123260894Smsmith */
123360894Smsmithstatic int
123460894Smsmithtwe_drain_response_queue(struct twe_softc *sc)
123560894Smsmith{
123660894Smsmith    TWE_Response_Queue	rq;
123760894Smsmith    u_int32_t		status_reg;
123860894Smsmith
123960894Smsmith    debug_called(4);
124060894Smsmith
124160894Smsmith    for (;;) {				/* XXX give up eventually? */
124260894Smsmith	status_reg = TWE_STATUS(sc);
124360894Smsmith	if (twe_check_bits(sc, status_reg))
124460894Smsmith	    return(1);
124560894Smsmith	if (status_reg & TWE_STATUS_RESPONSE_QUEUE_EMPTY)
124660894Smsmith	    return(0);
124760894Smsmith	rq = TWE_RESPONSE_QUEUE(sc);
124860894Smsmith    }
124960894Smsmith}
125060894Smsmith
125160894Smsmith/********************************************************************************
125267555Smsmith * Soft-reset the controller
125367555Smsmith */
125467555Smsmithstatic int
125567555Smsmithtwe_soft_reset(struct twe_softc *sc)
125667555Smsmith{
125767555Smsmith    u_int32_t		status_reg;
125867555Smsmith
125967555Smsmith    debug_called(2);
126067555Smsmith
126167555Smsmith    TWE_SOFT_RESET(sc);
126267555Smsmith
126391790Smsmith    if (twe_wait_status(sc, TWE_STATUS_ATTENTION_INTERRUPT, 30)) {
126467683Smsmith	twe_printf(sc, "no attention interrupt\n");
126567555Smsmith	return(1);
126667555Smsmith    }
126791790Smsmith    TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT);
126867555Smsmith    if (twe_drain_aen_queue(sc)) {
126967555Smsmith	twe_printf(sc, "can't drain AEN queue\n");
127067555Smsmith	return(1);
127167555Smsmith    }
127267555Smsmith    if (twe_find_aen(sc, TWE_AEN_SOFT_RESET)) {
127367555Smsmith	twe_printf(sc, "reset not reported\n");
127467555Smsmith	return(1);
127567555Smsmith    }
127667555Smsmith    status_reg = TWE_STATUS(sc);
127767555Smsmith    if (TWE_STATUS_ERRORS(status_reg) || twe_check_bits(sc, status_reg)) {
127867555Smsmith	twe_printf(sc, "controller errors detected\n");
127967555Smsmith	return(1);
128067555Smsmith    }
128167555Smsmith    if (twe_drain_response_queue(sc)) {
128267555Smsmith	twe_printf(sc, "can't drain response queue\n");
128367555Smsmith	return(1);
128467555Smsmith    }
128567555Smsmith    return(0);
128667555Smsmith}
128767555Smsmith
128867555Smsmith/********************************************************************************
128960894Smsmith ********************************************************************************
129060894Smsmith                                                               Interrupt Handling
129160894Smsmith ********************************************************************************
129260894Smsmith ********************************************************************************/
129360894Smsmith
129460894Smsmith/********************************************************************************
129560894Smsmith * Host interrupt.
129660894Smsmith *
129760894Smsmith * XXX what does this mean?
129860894Smsmith */
129960894Smsmithstatic void
130060894Smsmithtwe_host_intr(struct twe_softc *sc)
130160894Smsmith{
130260894Smsmith    debug_called(4);
130360894Smsmith
130467555Smsmith    twe_printf(sc, "host interrupt\n");
130560894Smsmith    TWE_CONTROL(sc, TWE_CONTROL_CLEAR_HOST_INTERRUPT);
130660894Smsmith}
130760894Smsmith
130860894Smsmith/********************************************************************************
130960894Smsmith * Attention interrupt.
131060894Smsmith *
131160894Smsmith * Signalled when the controller has one or more AENs for us.
131260894Smsmith */
131360894Smsmithstatic void
131460894Smsmithtwe_attention_intr(struct twe_softc *sc)
131560894Smsmith{
131660894Smsmith    debug_called(4);
131760894Smsmith
131860894Smsmith    /* instigate a poll for AENs */
131960894Smsmith    if (twe_fetch_aen(sc)) {
132067555Smsmith	twe_printf(sc, "error polling for signalled AEN\n");
132160894Smsmith    } else {
132260894Smsmith	TWE_CONTROL(sc, TWE_CONTROL_CLEAR_ATTENTION_INTERRUPT);
132360894Smsmith    }
132460894Smsmith}
132560894Smsmith
132660894Smsmith/********************************************************************************
132760894Smsmith * Command interrupt.
132860894Smsmith *
132960894Smsmith * Signalled when the controller can handle more commands.
133060894Smsmith */
133160894Smsmithstatic void
133260894Smsmithtwe_command_intr(struct twe_softc *sc)
133360894Smsmith{
133460894Smsmith    debug_called(4);
133560894Smsmith
133660894Smsmith    /*
133760894Smsmith     * We don't use this, rather we try to submit commands when we receive
133860894Smsmith     * them, and when other commands have completed.  Mask it so we don't get
133960894Smsmith     * another one.
134060894Smsmith     */
134160894Smsmith    TWE_CONTROL(sc, TWE_CONTROL_MASK_COMMAND_INTERRUPT);
134260894Smsmith}
134360894Smsmith
134460894Smsmith/********************************************************************************
134560894Smsmith ********************************************************************************
134660894Smsmith                                                      Asynchronous Event Handling
134760894Smsmith ********************************************************************************
134860894Smsmith ********************************************************************************/
134960894Smsmith
135060894Smsmith/********************************************************************************
135160894Smsmith * Request an AEN from the controller.
135260894Smsmith */
135360894Smsmithstatic int
135460894Smsmithtwe_fetch_aen(struct twe_softc *sc)
135560894Smsmith{
135660894Smsmith
135760894Smsmith    debug_called(4);
135860894Smsmith
135967555Smsmith    if ((twe_get_param(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, 2, twe_handle_aen)) == NULL)
136060894Smsmith	return(EIO);
136160894Smsmith    return(0);
136260894Smsmith}
136360894Smsmith
136460894Smsmith/********************************************************************************
136560894Smsmith * Handle an AEN returned by the controller.
136660894Smsmith */
136760894Smsmithstatic void
136860894Smsmithtwe_handle_aen(struct twe_request *tr)
136960894Smsmith{
137060894Smsmith    struct twe_softc	*sc = tr->tr_sc;
137160894Smsmith    TWE_Param		*param;
137260894Smsmith    u_int16_t		aen;
137360894Smsmith
137460894Smsmith    debug_called(4);
137560894Smsmith
137660894Smsmith    /* XXX check for command success somehow? */
137760894Smsmith
137860894Smsmith    param = (TWE_Param *)tr->tr_data;
137960894Smsmith    aen = *(u_int16_t *)(param->data);
138060894Smsmith
138160894Smsmith    free(tr->tr_data, M_DEVBUF);
138260894Smsmith    twe_release_request(tr);
138360894Smsmith    twe_enqueue_aen(sc, aen);
138460894Smsmith
138560894Smsmith    /* XXX poll for more AENs? */
138660894Smsmith}
138760894Smsmith
138860894Smsmith/********************************************************************************
138960894Smsmith * Pull AENs out of the controller and park them in the queue, in a context where
139060894Smsmith * interrupts aren't active.  Return nonzero if we encounter any errors in the
139160894Smsmith * process of obtaining all the available AENs.
139260894Smsmith */
139360894Smsmithstatic int
139460894Smsmithtwe_drain_aen_queue(struct twe_softc *sc)
139560894Smsmith{
139660894Smsmith    u_int16_t	aen;
139760894Smsmith
139860894Smsmith    for (;;) {
139967555Smsmith	if (twe_get_param_2(sc, TWE_PARAM_AEN, TWE_PARAM_AEN_UnitCode, &aen))
140060894Smsmith	    return(1);
140160894Smsmith	if (aen == TWE_AEN_QUEUE_EMPTY)
140260894Smsmith	    return(0);
140360894Smsmith	twe_enqueue_aen(sc, aen);
140460894Smsmith    }
140560894Smsmith}
140660894Smsmith
140760894Smsmith/********************************************************************************
140860894Smsmith * Push an AEN that we've received onto the queue.
140960894Smsmith *
141060894Smsmith * Note that we have to lock this against reentrance, since it may be called
141160894Smsmith * from both interrupt and non-interrupt context.
141260894Smsmith *
141360894Smsmith * If someone is waiting for the AEN we have, wake them up.
141460894Smsmith */
141560894Smsmithstatic void
141660894Smsmithtwe_enqueue_aen(struct twe_softc *sc, u_int16_t aen)
141760894Smsmith{
141867555Smsmith    char	*msg;
141967555Smsmith    int		s, next, nextnext;
142060894Smsmith
142160894Smsmith    debug_called(4);
142260894Smsmith
142367555Smsmith    if ((msg = twe_format_aen(sc, aen)) != NULL)
142467555Smsmith	twe_printf(sc, "AEN: <%s>\n", msg);
142560894Smsmith
142660894Smsmith    s = splbio();
142760894Smsmith    /* enqueue the AEN */
142860894Smsmith    next = ((sc->twe_aen_head + 1) % TWE_Q_LENGTH);
142967555Smsmith    nextnext = ((sc->twe_aen_head + 2) % TWE_Q_LENGTH);
143067555Smsmith
143167555Smsmith    /* check to see if this is the last free slot, and subvert the AEN if it is */
143267555Smsmith    if (nextnext == sc->twe_aen_tail)
143367555Smsmith	aen = TWE_AEN_QUEUE_FULL;
143467555Smsmith
143567555Smsmith    /* look to see if there's room for this AEN */
143660894Smsmith    if (next != sc->twe_aen_tail) {
143760894Smsmith	sc->twe_aen_queue[sc->twe_aen_head] = aen;
143860894Smsmith	sc->twe_aen_head = next;
143960894Smsmith    }
144060894Smsmith
144167555Smsmith    /* wake up anyone asleep on the queue */
144267555Smsmith    wakeup(&sc->twe_aen_queue);
144367555Smsmith
144460894Smsmith    /* anyone looking for this AEN? */
144560894Smsmith    if (sc->twe_wait_aen == aen) {
144660894Smsmith	sc->twe_wait_aen = -1;
144760894Smsmith	wakeup(&sc->twe_wait_aen);
144860894Smsmith    }
144960894Smsmith    splx(s);
145060894Smsmith}
145160894Smsmith
145260894Smsmith/********************************************************************************
145360894Smsmith * Pop an AEN off the queue, or return -1 if there are none left.
145460894Smsmith *
145560894Smsmith * We are more or less interrupt-safe, so don't block interrupts.
145660894Smsmith */
1457123103Spsstatic u_int16_t
145860894Smsmithtwe_dequeue_aen(struct twe_softc *sc)
145960894Smsmith{
1460123103Sps    u_int16_t	result;
146160894Smsmith
146260894Smsmith    debug_called(4);
146360894Smsmith
146460894Smsmith    if (sc->twe_aen_tail == sc->twe_aen_head) {
1465118508Sps	result = TWE_AEN_QUEUE_EMPTY;
146660894Smsmith    } else {
146760894Smsmith	result = sc->twe_aen_queue[sc->twe_aen_tail];
146860894Smsmith	sc->twe_aen_tail = ((sc->twe_aen_tail + 1) % TWE_Q_LENGTH);
146960894Smsmith    }
147060894Smsmith    return(result);
147160894Smsmith}
147260894Smsmith
147360894Smsmith/********************************************************************************
147460894Smsmith * Check to see if the requested AEN is in the queue.
147560894Smsmith *
147660894Smsmith * XXX we could probably avoid masking interrupts here
147760894Smsmith */
147860894Smsmithstatic int
147960894Smsmithtwe_find_aen(struct twe_softc *sc, u_int16_t aen)
148060894Smsmith{
148160894Smsmith    int		i, s, missing;
148260894Smsmith
148360894Smsmith    missing = 1;
148460894Smsmith    s = splbio();
148560894Smsmith    for (i = sc->twe_aen_tail; (i != sc->twe_aen_head) && missing; i = (i + 1) % TWE_Q_LENGTH) {
148660894Smsmith	if (sc->twe_aen_queue[i] == aen)
148760894Smsmith	    missing = 0;
148860894Smsmith    }
148967555Smsmith    splx(s);
149060894Smsmith    return(missing);
149160894Smsmith}
149260894Smsmith
149360894Smsmith
149460894Smsmith#if 0	/* currently unused */
149560894Smsmith/********************************************************************************
149660894Smsmith * Sleep waiting for at least (timeout) seconds until we see (aen) as
149760894Smsmith * requested.  Returns nonzero on timeout or failure.
149860894Smsmith *
149960894Smsmith * XXX: this should not be used in cases where there may be more than one sleeper
150060894Smsmith *      without a mechanism for registering multiple sleepers.
150160894Smsmith */
150260894Smsmithstatic int
150360894Smsmithtwe_wait_aen(struct twe_softc *sc, int aen, int timeout)
150460894Smsmith{
150560894Smsmith    time_t	expiry;
150660894Smsmith    int		found, s;
150760894Smsmith
150860894Smsmith    debug_called(4);
150960894Smsmith
151060894Smsmith    expiry = time_second + timeout;
151160894Smsmith    found = 0;
151260894Smsmith
151360894Smsmith    s = splbio();
151460894Smsmith    sc->twe_wait_aen = aen;
151560894Smsmith    do {
151660894Smsmith	twe_fetch_aen(sc);
151760894Smsmith	tsleep(&sc->twe_wait_aen, PZERO, "twewaen", hz);
151860894Smsmith	if (sc->twe_wait_aen == -1)
151960894Smsmith	    found = 1;
152060894Smsmith    } while ((time_second <= expiry) && !found);
152160894Smsmith    splx(s);
152260894Smsmith    return(!found);
152360894Smsmith}
152460894Smsmith#endif
152560894Smsmith
152660894Smsmith/********************************************************************************
152760894Smsmith ********************************************************************************
152860894Smsmith                                                        Command Buffer Management
152960894Smsmith ********************************************************************************
153060894Smsmith ********************************************************************************/
153160894Smsmith
153260894Smsmith/********************************************************************************
153360894Smsmith * Get a new command buffer.
153460894Smsmith *
153567555Smsmith * This will return NULL if all command buffers are in use.
153660894Smsmith */
153767555Smsmithstatic int
153867555Smsmithtwe_get_request(struct twe_softc *sc, struct twe_request **tr)
153960894Smsmith{
1540118816Sps    TWE_Command		*cmd;
154160894Smsmith    debug_called(4);
154260894Smsmith
154360894Smsmith    /* try to reuse an old buffer */
154467555Smsmith    *tr = twe_dequeue_free(sc);
154560894Smsmith
154667555Smsmith    /* initialise some fields to their defaults */
154767555Smsmith    if (*tr != NULL) {
1548118816Sps	cmd = TWE_FIND_COMMAND(*tr);
154967555Smsmith	(*tr)->tr_data = NULL;
155069543Smsmith	(*tr)->tr_private = NULL;
155167555Smsmith	(*tr)->tr_status = TWE_CMD_SETUP;		/* command is in setup phase */
155267555Smsmith	(*tr)->tr_flags = 0;
155367555Smsmith	(*tr)->tr_complete = NULL;
1554118816Sps	cmd->generic.status = 0;			/* before submission to controller */
1555118816Sps	cmd->generic.flags = 0;				/* not used */
155660894Smsmith    }
155767555Smsmith    return(*tr == NULL);
155860894Smsmith}
155960894Smsmith
156060894Smsmith/********************************************************************************
156167555Smsmith * Release a command buffer for reuse.
156260894Smsmith *
156360894Smsmith */
156460894Smsmithstatic void
156560894Smsmithtwe_release_request(struct twe_request *tr)
156660894Smsmith{
156760894Smsmith    debug_called(4);
156860894Smsmith
156969543Smsmith    if (tr->tr_private != NULL)
157069543Smsmith	twe_panic(tr->tr_sc, "tr_private != NULL");
157167555Smsmith    twe_enqueue_free(tr);
157260894Smsmith}
157360894Smsmith
157460894Smsmith/********************************************************************************
157567555Smsmith ********************************************************************************
157667555Smsmith                                                                        Debugging
157767555Smsmith ********************************************************************************
157867555Smsmith ********************************************************************************/
157960894Smsmith
158060894Smsmith/********************************************************************************
158167555Smsmith * Print some information about the controller
158260894Smsmith */
158367555Smsmithvoid
158467555Smsmithtwe_describe_controller(struct twe_softc *sc)
158560894Smsmith{
158667555Smsmith    TWE_Param		*p[6];
158767555Smsmith    u_int8_t		ports;
158867555Smsmith    u_int32_t		size;
158960894Smsmith    int			i;
159060894Smsmith
159167555Smsmith    debug_called(2);
159260894Smsmith
159367555Smsmith    /* get the port count */
159467555Smsmith    twe_get_param_1(sc, TWE_PARAM_CONTROLLER, TWE_PARAM_CONTROLLER_PortCount, &ports);
159560894Smsmith
159667555Smsmith    /* get version strings */
1597123103Sps    p[0] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW,   16, NULL);
1598123103Sps    p[1] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS, 16, NULL);
1599123103Sps    if (p[0] && p[1])
1600123103Sps	 twe_printf(sc, "%d ports, Firmware %.16s, BIOS %.16s\n", ports, p[0]->data, p[1]->data);
160160894Smsmith
1602123103Sps    if (bootverbose) {
1603123103Sps	p[2] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon,  16, NULL);
1604123103Sps	p[3] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB,  8, NULL);
1605123103Sps	p[4] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA,  8, NULL);
1606123103Sps	p[5] = twe_get_param(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI,  8, NULL);
160760894Smsmith
1608123103Sps	if (p[2] && p[3] && p[4] && p[5])
1609123103Sps	    twe_printf(sc, "Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n", p[2]->data, p[3]->data,
1610123103Sps		p[4]->data, p[5]->data);
1611123103Sps	if (p[2])
1612123103Sps	    free(p[2], M_DEVBUF);
1613123103Sps	if (p[3])
1614123103Sps	    free(p[3], M_DEVBUF);
1615123103Sps	if (p[4])
1616123103Sps	    free(p[4], M_DEVBUF);
1617123103Sps	if (p[5])
1618123103Sps	    free(p[5], M_DEVBUF);
1619123103Sps    }
1620123103Sps    if (p[0])
1621123103Sps	free(p[0], M_DEVBUF);
1622123103Sps    if (p[1])
1623123103Sps	free(p[1], M_DEVBUF);
1624123103Sps
162567555Smsmith    /* print attached drives */
162667555Smsmith    if (bootverbose) {
162767555Smsmith	p[0] = twe_get_param(sc, TWE_PARAM_DRIVESUMMARY, TWE_PARAM_DRIVESUMMARY_Status, 16, NULL);
162867555Smsmith	for (i = 0; i < ports; i++) {
162967555Smsmith	    if (p[0]->data[i] != TWE_PARAM_DRIVESTATUS_Present)
163067555Smsmith		continue;
163167555Smsmith	    twe_get_param_4(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Size, &size);
163267555Smsmith	    p[1] = twe_get_param(sc, TWE_PARAM_DRIVEINFO + i, TWE_PARAM_DRIVEINFO_Model, 40, NULL);
163367555Smsmith	    if (p[1] != NULL) {
163467555Smsmith		twe_printf(sc, "port %d: %.40s %dMB\n", i, p[1]->data, size / 2048);
163567555Smsmith		free(p[1], M_DEVBUF);
163667555Smsmith	    } else {
163767555Smsmith		twe_printf(sc, "port %d, drive status unavailable\n", i);
163867555Smsmith	    }
163960894Smsmith	}
1640123103Sps	if (p[0])
1641123103Sps	    free(p[0], M_DEVBUF);
164260894Smsmith    }
164360894Smsmith}
164460894Smsmith
164560894Smsmith/********************************************************************************
1646123103Sps * Look up a text description of a numeric code and return a pointer to same.
1647123103Sps */
1648123103Spschar *
1649123103Spstwe_describe_code(struct twe_code_lookup *table, u_int32_t code)
1650123103Sps{
1651123103Sps    int         i;
1652123103Sps
1653123103Sps    for (i = 0; table[i].string != NULL; i++)
1654123103Sps	if (table[i].code == code)
1655123103Sps	    return(table[i].string);
1656123103Sps    return(table[i+1].string);
1657123103Sps}
1658123103Sps
1659123103Sps/********************************************************************************
166060894Smsmith * Complain if the status bits aren't what we're expecting.
166167555Smsmith *
166267555Smsmith * Rate-limit the complaints to at most one of each every five seconds, but
166367555Smsmith * always return the correct status.
166460894Smsmith */
166560894Smsmithstatic int
166660894Smsmithtwe_check_bits(struct twe_softc *sc, u_int32_t status_reg)
166760894Smsmith{
166867555Smsmith    int			result;
166967555Smsmith    static time_t	lastwarn[2] = {0, 0};
167060894Smsmith
167167555Smsmith    /*
167267555Smsmith     * This can be a little problematic, as twe_panic may call twe_reset if
167367555Smsmith     * TWE_DEBUG is not set, which will call us again as part of the soft reset.
167467555Smsmith     */
167567555Smsmith    if ((status_reg & TWE_STATUS_PANIC_BITS) != 0) {
167667555Smsmith	twe_printf(sc, "FATAL STATUS BIT(S) %b\n", status_reg & TWE_STATUS_PANIC_BITS,
167767555Smsmith		   TWE_STATUS_BITS_DESCRIPTION);
167867555Smsmith	twe_panic(sc, "fatal status bits");
167967555Smsmith    }
168067555Smsmith
168160894Smsmith    result = 0;
168260894Smsmith    if ((status_reg & TWE_STATUS_EXPECTED_BITS) != TWE_STATUS_EXPECTED_BITS) {
168367555Smsmith	if (time_second > (lastwarn[0] + 5)) {
168467555Smsmith	    twe_printf(sc, "missing expected status bit(s) %b\n", ~status_reg & TWE_STATUS_EXPECTED_BITS,
168567555Smsmith		       TWE_STATUS_BITS_DESCRIPTION);
168667555Smsmith	    lastwarn[0] = time_second;
168767555Smsmith	}
168860894Smsmith	result = 1;
168960894Smsmith    }
169060894Smsmith
169160894Smsmith    if ((status_reg & TWE_STATUS_UNEXPECTED_BITS) != 0) {
169267555Smsmith	if (time_second > (lastwarn[1] + 5)) {
169367555Smsmith	    twe_printf(sc, "unexpected status bit(s) %b\n", status_reg & TWE_STATUS_UNEXPECTED_BITS,
169467555Smsmith		       TWE_STATUS_BITS_DESCRIPTION);
169567555Smsmith	    lastwarn[1] = time_second;
169667555Smsmith	}
169760894Smsmith	result = 1;
169891790Smsmith	if (status_reg & TWE_STATUS_PCI_PARITY_ERROR) {
1699176200Sbrueffer	    twe_printf(sc, "PCI parity error: Reseat card, move card or buggy device present.\n");
170091790Smsmith	    twe_clear_pci_parity_error(sc);
170191790Smsmith	}
170291790Smsmith	if (status_reg & TWE_STATUS_PCI_ABORT) {
1703118816Sps	    twe_printf(sc, "PCI abort, clearing.\n");
170491790Smsmith	    twe_clear_pci_abort(sc);
170591790Smsmith	}
170660894Smsmith    }
170767555Smsmith
170860894Smsmith    return(result);
170960894Smsmith}
171060894Smsmith
171160894Smsmith/********************************************************************************
171267555Smsmith * Return a string describing (aen).
171367555Smsmith *
171467555Smsmith * The low 8 bits of the aen are the code, the high 8 bits give the unit number
171567555Smsmith * where an AEN is specific to a unit.
171667555Smsmith *
171767555Smsmith * Note that we could expand this routine to handle eg. up/downgrading the status
171867555Smsmith * of a drive if we had some idea of what the drive's initial status was.
171960894Smsmith */
172060894Smsmith
172160894Smsmithstatic char *
172267555Smsmithtwe_format_aen(struct twe_softc *sc, u_int16_t aen)
172360894Smsmith{
172467555Smsmith    static char	buf[80];
172567555Smsmith    device_t	child;
172667555Smsmith    char	*code, *msg;
172760894Smsmith
172867555Smsmith    code = twe_describe_code(twe_table_aen, TWE_AEN_CODE(aen));
172967555Smsmith    msg = code + 2;
173060894Smsmith
173167555Smsmith    switch (*code) {
173267555Smsmith    case 'q':
173367555Smsmith	if (!bootverbose)
173467555Smsmith	    return(NULL);
173567555Smsmith	/* FALLTHROUGH */
173691790Smsmith    case 'a':
173767555Smsmith	return(msg);
173867555Smsmith
173967555Smsmith    case 'c':
174067555Smsmith	if ((child = sc->twe_drive[TWE_AEN_UNIT(aen)].td_disk) != NULL) {
174167555Smsmith	    sprintf(buf, "twed%d: %s", device_get_unit(child), msg);
174267555Smsmith	} else {
174367555Smsmith	    sprintf(buf, "twe%d: %s for unknown unit %d", device_get_unit(sc->twe_dev),
174467555Smsmith		    msg, TWE_AEN_UNIT(aen));
174567555Smsmith	}
174667555Smsmith	return(buf);
174791790Smsmith
174891790Smsmith    case 'p':
174991790Smsmith	sprintf(buf, "twe%d: port %d: %s", device_get_unit(sc->twe_dev), TWE_AEN_UNIT(aen),
175091790Smsmith		msg);
175191790Smsmith	return(buf);
175291790Smsmith
175367555Smsmith
175467555Smsmith    case 'x':
175567555Smsmith    default:
175667555Smsmith	break;
175767555Smsmith    }
175867555Smsmith    sprintf(buf, "unknown AEN 0x%x", aen);
175960894Smsmith    return(buf);
176060894Smsmith}
176160894Smsmith
176269543Smsmith/********************************************************************************
176369543Smsmith * Print a diagnostic if the status of the command warrants it, and return
176469543Smsmith * either zero (command was ok) or nonzero (command failed).
176569543Smsmith */
176667555Smsmithstatic int
176769543Smsmithtwe_report_request(struct twe_request *tr)
176867555Smsmith{
176969543Smsmith    struct twe_softc	*sc = tr->tr_sc;
1770118816Sps    TWE_Command		*cmd = TWE_FIND_COMMAND(tr);
177176340Smsmith    int			result = 0;
177260894Smsmith
177376340Smsmith    /*
177476340Smsmith     * Check the command status value and handle accordingly.
177576340Smsmith     */
177676340Smsmith    if (cmd->generic.status == TWE_STATUS_RESET) {
177776340Smsmith	/*
177876340Smsmith	 * The status code 0xff requests a controller reset.
177976340Smsmith	 */
1780123103Sps	twe_printf(sc, "command returned with controller reset request\n");
178176340Smsmith	twe_reset(sc);
178269543Smsmith	result = 1;
178376340Smsmith    } else if (cmd->generic.status > TWE_STATUS_FATAL) {
178469543Smsmith	/*
178576340Smsmith	 * Fatal errors that don't require controller reset.
178691790Smsmith	 *
178791790Smsmith	 * We know a few special flags values.
178869543Smsmith	 */
178991790Smsmith	switch (cmd->generic.flags) {
179091790Smsmith	case 0x1b:
179191790Smsmith	    device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
179291790Smsmith			  "drive timeout");
179391790Smsmith	    break;
179491790Smsmith	case 0x51:
179591790Smsmith	    device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
179691790Smsmith			  "unrecoverable drive error");
179791790Smsmith	    break;
179891790Smsmith	default:
179991790Smsmith	    device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
180091790Smsmith			  "controller error - %s (flags = 0x%x)\n",
180191790Smsmith			  twe_describe_code(twe_table_status, cmd->generic.status),
180291790Smsmith			  cmd->generic.flags);
180391790Smsmith	    result = 1;
180491790Smsmith	}
180576340Smsmith    } else if (cmd->generic.status > TWE_STATUS_WARNING) {
180676340Smsmith	/*
180776340Smsmith	 * Warning level status.
180876340Smsmith	 */
180991790Smsmith	device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
181091790Smsmith		      "warning - %s (flags = 0x%x)\n",
181191790Smsmith		      twe_describe_code(twe_table_status, cmd->generic.status),
181291790Smsmith		      cmd->generic.flags);
181376340Smsmith    } else if (cmd->generic.status > 0x40) {
181476340Smsmith	/*
181576340Smsmith	 * Info level status.
181676340Smsmith	 */
181791790Smsmith	device_printf(sc->twe_drive[cmd->generic.unit].td_disk,
181891790Smsmith		      "attention - %s (flags = 0x%x)\n",
181991790Smsmith		      twe_describe_code(twe_table_status, cmd->generic.status),
182091790Smsmith		      cmd->generic.flags);
182167555Smsmith    }
182276340Smsmith
182369543Smsmith    return(result);
182467555Smsmith}
182567555Smsmith
182669543Smsmith/********************************************************************************
182769543Smsmith * Print some controller state to aid in debugging error/panic conditions
182869543Smsmith */
182967555Smsmithvoid
183067555Smsmithtwe_print_controller(struct twe_softc *sc)
183160894Smsmith{
183267555Smsmith    u_int32_t		status_reg;
183360894Smsmith
183467555Smsmith    status_reg = TWE_STATUS(sc);
183567555Smsmith    twe_printf(sc, "status   %b\n", status_reg, TWE_STATUS_BITS_DESCRIPTION);
1836123103Sps    twe_printf(sc, "          current  max    min\n");
1837123103Sps    twe_printf(sc, "free      %04d     %04d   %04d\n",
1838123103Sps	sc->twe_qstat[TWEQ_FREE].q_length, sc->twe_qstat[TWEQ_FREE].q_max, sc->twe_qstat[TWEQ_FREE].q_min);
1839123103Sps
1840123103Sps    twe_printf(sc, "ready     %04d     %04d   %04d\n",
1841123103Sps	sc->twe_qstat[TWEQ_READY].q_length, sc->twe_qstat[TWEQ_READY].q_max, sc->twe_qstat[TWEQ_READY].q_min);
1842123103Sps
1843123103Sps    twe_printf(sc, "busy      %04d     %04d   %04d\n",
1844123103Sps	sc->twe_qstat[TWEQ_BUSY].q_length, sc->twe_qstat[TWEQ_BUSY].q_max, sc->twe_qstat[TWEQ_BUSY].q_min);
1845123103Sps
1846123103Sps    twe_printf(sc, "complete  %04d     %04d   %04d\n",
1847123103Sps	sc->twe_qstat[TWEQ_COMPLETE].q_length, sc->twe_qstat[TWEQ_COMPLETE].q_max, sc->twe_qstat[TWEQ_COMPLETE].q_min);
1848123103Sps
1849123103Sps    twe_printf(sc, "bioq      %04d     %04d   %04d\n",
1850123103Sps	sc->twe_qstat[TWEQ_BIO].q_length, sc->twe_qstat[TWEQ_BIO].q_max, sc->twe_qstat[TWEQ_BIO].q_min);
1851123103Sps
185267555Smsmith    twe_printf(sc, "AEN queue head %d  tail %d\n", sc->twe_aen_head, sc->twe_aen_tail);
185367555Smsmith}
185460894Smsmith
185567555Smsmithstatic void
185667555Smsmithtwe_panic(struct twe_softc *sc, char *reason)
185767555Smsmith{
185867555Smsmith    twe_print_controller(sc);
185967555Smsmith#ifdef TWE_DEBUG
186067555Smsmith    panic(reason);
186167555Smsmith#else
186267555Smsmith    twe_reset(sc);
186367555Smsmith#endif
186460894Smsmith}
186560894Smsmith
1866127415Svkashyap#if 0
186760894Smsmith/********************************************************************************
186860894Smsmith * Print a request/command in human-readable format.
186960894Smsmith */
187060894Smsmithstatic void
187160894Smsmithtwe_print_request(struct twe_request *tr)
187260894Smsmith{
187367555Smsmith    struct twe_softc	*sc = tr->tr_sc;
1874118816Sps    TWE_Command	*cmd = TWE_FIND_COMMAND(tr);
187560894Smsmith    int		i;
187660894Smsmith
187767555Smsmith    twe_printf(sc, "CMD: request_id %d  opcode <%s>  size %d  unit %d  host_id %d\n",
187867555Smsmith	       cmd->generic.request_id, twe_describe_code(twe_table_opcode, cmd->generic.opcode), cmd->generic.size,
187967555Smsmith	       cmd->generic.unit, cmd->generic.host_id);
188067555Smsmith    twe_printf(sc, " status %d  flags 0x%x  count %d  sgl_offset %d\n",
188167555Smsmith	       cmd->generic.status, cmd->generic.flags, cmd->generic.count, cmd->generic.sgl_offset);
188267555Smsmith
188367555Smsmith    switch(cmd->generic.opcode) {	/* XXX add more opcodes? */
188467555Smsmith    case TWE_OP_READ:
188567555Smsmith    case TWE_OP_WRITE:
188667555Smsmith	twe_printf(sc, " lba %d\n", cmd->io.lba);
188767555Smsmith	for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->io.sgl[i].length != 0); i++)
188867555Smsmith	    twe_printf(sc, "  %d: 0x%x/%d\n",
188967555Smsmith		       i, cmd->io.sgl[i].address, cmd->io.sgl[i].length);
189060894Smsmith	break;
189160894Smsmith
189267555Smsmith    case TWE_OP_GET_PARAM:
189367555Smsmith    case TWE_OP_SET_PARAM:
189467555Smsmith	for (i = 0; (i < TWE_MAX_SGL_LENGTH) && (cmd->param.sgl[i].length != 0); i++)
189567555Smsmith	    twe_printf(sc, "  %d: 0x%x/%d\n",
189667555Smsmith		       i, cmd->param.sgl[i].address, cmd->param.sgl[i].length);
189760894Smsmith	break;
189860894Smsmith
189967555Smsmith    case TWE_OP_INIT_CONNECTION:
190067555Smsmith	twe_printf(sc, " response queue pointer 0x%x\n",
190167555Smsmith		   cmd->initconnection.response_queue_pointer);
190267555Smsmith	break;
190367555Smsmith
190460894Smsmith    default:
190567555Smsmith	break;
190660894Smsmith    }
190767555Smsmith    twe_printf(sc, " tr_command %p/0x%x  tr_data %p/0x%x,%d\n",
1908118816Sps	       tr, TWE_FIND_COMMANDPHYS(tr), tr->tr_data, tr->tr_dataphys, tr->tr_length);
190967555Smsmith    twe_printf(sc, " tr_status %d  tr_flags 0x%x  tr_complete %p  tr_private %p\n",
191067555Smsmith	       tr->tr_status, tr->tr_flags, tr->tr_complete, tr->tr_private);
191160894Smsmith}
191260894Smsmith
191360894Smsmith#endif
1914