aic79xx_osm.c revision 239104
1139749Simp/*-
2123579Sgibbs * Bus independent FreeBSD shim for the aic79xx based Adaptec SCSI controllers
397883Sgibbs *
4133122Sgibbs * Copyright (c) 1994-2002, 2004 Justin T. Gibbs.
5102684Sgibbs * Copyright (c) 2001-2002 Adaptec Inc.
697883Sgibbs * All rights reserved.
797883Sgibbs *
897883Sgibbs * Redistribution and use in source and binary forms, with or without
997883Sgibbs * modification, are permitted provided that the following conditions
1097883Sgibbs * are met:
1197883Sgibbs * 1. Redistributions of source code must retain the above copyright
1297883Sgibbs *    notice, this list of conditions, and the following disclaimer,
1397883Sgibbs *    without modification.
1497883Sgibbs * 2. The name of the author may not be used to endorse or promote products
1597883Sgibbs *    derived from this software without specific prior written permission.
1697883Sgibbs *
1797883Sgibbs * Alternatively, this software may be distributed under the terms of the
1897883Sgibbs * GNU Public License ("GPL").
1997883Sgibbs *
2097883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2197883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2297883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2397883Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2497883Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2597883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2697883Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2797883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2897883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2997883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3097883Sgibbs * SUCH DAMAGE.
3197883Sgibbs *
32123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#35 $
3397883Sgibbs */
3497883Sgibbs
35119418Sobrien#include <sys/cdefs.h>
36119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/aic79xx_osm.c 239104 2012-08-06 20:01:32Z dim $");
37119418Sobrien
3897883Sgibbs#include <dev/aic7xxx/aic79xx_osm.h>
3997883Sgibbs#include <dev/aic7xxx/aic79xx_inline.h>
4097883Sgibbs
41123579Sgibbs#include <sys/kthread.h>
42123579Sgibbs
4397883Sgibbs#include "opt_ddb.h"
4497883Sgibbs#ifdef DDB
4597883Sgibbs#include <ddb/ddb.h>
4697883Sgibbs#endif
4797883Sgibbs
4897883Sgibbs#ifndef AHD_TMODE_ENABLE
4997883Sgibbs#define AHD_TMODE_ENABLE 0
5097883Sgibbs#endif
5197883Sgibbs
52123579Sgibbs#include <dev/aic7xxx/aic_osm_lib.c>
53123579Sgibbs
5497883Sgibbs#define ccb_scb_ptr spriv_ptr0
5597883Sgibbs
56153072Sru#if 0
5797883Sgibbsstatic void	ahd_dump_targcmd(struct target_cmd *cmd);
5897883Sgibbs#endif
5997883Sgibbsstatic int	ahd_modevent(module_t mod, int type, void *data);
6097883Sgibbsstatic void	ahd_action(struct cam_sim *sim, union ccb *ccb);
6197883Sgibbsstatic void	ahd_set_tran_settings(struct ahd_softc *ahd,
6297883Sgibbs				      int our_id, char channel,
6397883Sgibbs				      struct ccb_trans_settings *cts);
6497883Sgibbsstatic void	ahd_get_tran_settings(struct ahd_softc *ahd,
6597883Sgibbs				      int our_id, char channel,
6697883Sgibbs				      struct ccb_trans_settings *cts);
6797883Sgibbsstatic void	ahd_async(void *callback_arg, uint32_t code,
6897883Sgibbs			  struct cam_path *path, void *arg);
6997883Sgibbsstatic void	ahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
7097883Sgibbs				int nsegments, int error);
7197883Sgibbsstatic void	ahd_poll(struct cam_sim *sim);
7297883Sgibbsstatic void	ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
7397883Sgibbs			       struct ccb_scsiio *csio, struct scb *scb);
7497883Sgibbsstatic void	ahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim,
7597883Sgibbs			      union ccb *ccb);
7697883Sgibbsstatic int	ahd_create_path(struct ahd_softc *ahd,
7797883Sgibbs				char channel, u_int target, u_int lun,
7897883Sgibbs				struct cam_path **path);
7997883Sgibbs
80199260Sattiliostatic const char *ahd_sysctl_node_elements[] = {
81199260Sattilio	"root",
82199260Sattilio	"summary",
83199260Sattilio	"debug"
84199260Sattilio};
85199260Sattilio
86203685Sbrucec#ifndef NO_SYSCTL_DESCR
87199260Sattiliostatic const char *ahd_sysctl_node_descriptions[] = {
88199260Sattilio	"root error collection for aic79xx controllers",
89199260Sattilio	"summary collection for aic79xx controllers",
90199260Sattilio	"debug collection for aic79xx controllers"
91199260Sattilio};
92203685Sbrucec#endif
93199260Sattilio
94199260Sattiliostatic const char *ahd_sysctl_errors_elements[] = {
95199260Sattilio	"Cerrors",
96199260Sattilio	"Uerrors",
97199260Sattilio	"Ferrors"
98199260Sattilio};
99199260Sattilio
100203685Sbrucec#ifndef NO_SYSCTL_DESCR
101199260Sattiliostatic const char *ahd_sysctl_errors_descriptions[] = {
102199260Sattilio	"Correctable errors",
103199260Sattilio	"Uncorrectable errors",
104199260Sattilio	"Fatal errors"
105199260Sattilio};
106203685Sbrucec#endif
107199260Sattilio
10897883Sgibbsstatic int
109199260Sattilioahd_set_debugcounters(SYSCTL_HANDLER_ARGS)
110199260Sattilio{
111199260Sattilio	struct ahd_softc *sc;
112199260Sattilio	int error, tmpv;
113199260Sattilio
114199260Sattilio	tmpv = 0;
115199260Sattilio	sc = arg1;
116199260Sattilio	error = sysctl_handle_int(oidp, &tmpv, 0, req);
117199260Sattilio	if (error != 0 || req->newptr == NULL)
118199260Sattilio		return (error);
119199260Sattilio	if (tmpv < 0 || tmpv >= AHD_ERRORS_NUMBER)
120199260Sattilio		return (EINVAL);
121199260Sattilio	sc->summerr[arg2] = tmpv;
122199260Sattilio	return (0);
123199260Sattilio}
124199260Sattilio
125199260Sattiliostatic int
126199260Sattilioahd_clear_allcounters(SYSCTL_HANDLER_ARGS)
127199260Sattilio{
128199260Sattilio	struct ahd_softc *sc;
129199260Sattilio	int error, tmpv;
130199260Sattilio
131199260Sattilio	tmpv = 0;
132199260Sattilio	sc = arg1;
133199260Sattilio	error = sysctl_handle_int(oidp, &tmpv, 0, req);
134199260Sattilio	if (error != 0 || req->newptr == NULL)
135199260Sattilio		return (error);
136199260Sattilio	if (tmpv != 0)
137199260Sattilio		bzero(sc->summerr, sizeof(sc->summerr));
138199260Sattilio	return (0);
139199260Sattilio}
140199260Sattilio
141199260Sattiliostatic int
14297883Sgibbsahd_create_path(struct ahd_softc *ahd, char channel, u_int target,
14397883Sgibbs	        u_int lun, struct cam_path **path)
14497883Sgibbs{
14597883Sgibbs	path_id_t path_id;
14697883Sgibbs
147123579Sgibbs	path_id = cam_sim_path(ahd->platform_data->sim);
14897883Sgibbs	return (xpt_create_path(path, /*periph*/NULL,
14997883Sgibbs				path_id, target, lun));
15097883Sgibbs}
15197883Sgibbs
152199260Sattiliovoid
153199260Sattilioahd_sysctl(struct ahd_softc *ahd)
154199260Sattilio{
155199260Sattilio	u_int i;
156199260Sattilio
157199260Sattilio	for (i = 0; i < AHD_SYSCTL_NUMBER; i++)
158199260Sattilio		sysctl_ctx_init(&ahd->sysctl_ctx[i]);
159199260Sattilio
160199260Sattilio	ahd->sysctl_tree[AHD_SYSCTL_ROOT] =
161199260Sattilio	    SYSCTL_ADD_NODE(&ahd->sysctl_ctx[AHD_SYSCTL_ROOT],
162199260Sattilio			    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
163199260Sattilio			    device_get_nameunit(ahd->dev_softc), CTLFLAG_RD, 0,
164199260Sattilio			    ahd_sysctl_node_descriptions[AHD_SYSCTL_ROOT]);
165199260Sattilio	    SYSCTL_ADD_PROC(&ahd->sysctl_ctx[AHD_SYSCTL_ROOT],
166199260Sattilio			    SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_ROOT]),
167199260Sattilio			    OID_AUTO, "clear", CTLTYPE_UINT | CTLFLAG_RW, ahd,
168199260Sattilio			    0, ahd_clear_allcounters, "IU",
169199260Sattilio			    "Clear all counters");
170199260Sattilio
171199260Sattilio	for (i = AHD_SYSCTL_SUMMARY; i < AHD_SYSCTL_NUMBER; i++)
172199260Sattilio		ahd->sysctl_tree[i] =
173199260Sattilio		    SYSCTL_ADD_NODE(&ahd->sysctl_ctx[i],
174199260Sattilio				    SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_ROOT]),
175199260Sattilio				    OID_AUTO, ahd_sysctl_node_elements[i],
176199260Sattilio				    CTLFLAG_RD, 0,
177199260Sattilio				    ahd_sysctl_node_descriptions[i]);
178199260Sattilio
179199260Sattilio	for (i = AHD_ERRORS_CORRECTABLE; i < AHD_ERRORS_NUMBER; i++) {
180199260Sattilio		SYSCTL_ADD_UINT(&ahd->sysctl_ctx[AHD_SYSCTL_SUMMARY],
181199260Sattilio				SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_SUMMARY]),
182199260Sattilio				OID_AUTO, ahd_sysctl_errors_elements[i],
183199260Sattilio				CTLFLAG_RD, &ahd->summerr[i], i,
184199260Sattilio				ahd_sysctl_errors_descriptions[i]);
185199260Sattilio		SYSCTL_ADD_PROC(&ahd->sysctl_ctx[AHD_SYSCTL_DEBUG],
186199260Sattilio				SYSCTL_CHILDREN(ahd->sysctl_tree[AHD_SYSCTL_DEBUG]),
187199260Sattilio				OID_AUTO, ahd_sysctl_errors_elements[i],
188199260Sattilio				CTLFLAG_RW | CTLTYPE_UINT, ahd, i,
189199260Sattilio				ahd_set_debugcounters, "IU",
190199260Sattilio				ahd_sysctl_errors_descriptions[i]);
191199260Sattilio	}
192199260Sattilio}
193199260Sattilio
19497883Sgibbsint
19597883Sgibbsahd_map_int(struct ahd_softc *ahd)
19697883Sgibbs{
19797883Sgibbs	int error;
19897883Sgibbs
19997883Sgibbs	/* Hook up our interrupt handler */
20097883Sgibbs	error = bus_setup_intr(ahd->dev_softc, ahd->platform_data->irq,
201168807Sscottl			       INTR_TYPE_CAM|INTR_MPSAFE, NULL,
202168807Sscottl			       ahd_platform_intr, ahd, &ahd->platform_data->ih);
20397883Sgibbs	if (error != 0)
20497883Sgibbs		device_printf(ahd->dev_softc, "bus_setup_intr() failed: %d\n",
20597883Sgibbs			      error);
20697883Sgibbs	return (error);
20797883Sgibbs}
20897883Sgibbs
20997883Sgibbs/*
21097883Sgibbs * Attach all the sub-devices we can find
21197883Sgibbs */
21297883Sgibbsint
21397883Sgibbsahd_attach(struct ahd_softc *ahd)
21497883Sgibbs{
21597883Sgibbs	char   ahd_info[256];
21697883Sgibbs	struct ccb_setasync csa;
21797883Sgibbs	struct cam_devq *devq;
21897883Sgibbs	struct cam_sim *sim;
21997883Sgibbs	struct cam_path *path;
22097883Sgibbs	int count;
22197883Sgibbs
22297883Sgibbs	count = 0;
223123579Sgibbs	devq = NULL;
22497883Sgibbs	sim = NULL;
225239104Sdim	path = NULL;
22697883Sgibbs
227123579Sgibbs	/*
228123579Sgibbs	 * Create a thread to perform all recovery.
229123579Sgibbs	 */
230123579Sgibbs	if (ahd_spawn_recovery_thread(ahd) != 0)
231123579Sgibbs		goto fail;
232123579Sgibbs
23397883Sgibbs	ahd_controller_info(ahd, ahd_info);
23497883Sgibbs	printf("%s\n", ahd_info);
235168807Sscottl	ahd_lock(ahd);
23697883Sgibbs
23797883Sgibbs	/*
23897883Sgibbs	 * Create the device queue for our SIM(s).
23997883Sgibbs	 */
24097883Sgibbs	devq = cam_simq_alloc(AHD_MAX_QUEUE);
24197883Sgibbs	if (devq == NULL)
24297883Sgibbs		goto fail;
24397883Sgibbs
24497883Sgibbs	/*
24597883Sgibbs	 * Construct our SIM entry
24697883Sgibbs	 */
24797883Sgibbs	sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd,
24897883Sgibbs			    device_get_unit(ahd->dev_softc),
249168807Sscottl			    &ahd->platform_data->mtx, 1, /*XXX*/256, devq);
25097883Sgibbs	if (sim == NULL) {
25197883Sgibbs		cam_simq_free(devq);
25297883Sgibbs		goto fail;
25397883Sgibbs	}
25497883Sgibbs
255170872Sscottl	if (xpt_bus_register(sim, ahd->dev_softc, /*bus_id*/0) != CAM_SUCCESS) {
25697883Sgibbs		cam_sim_free(sim, /*free_devq*/TRUE);
25797883Sgibbs		sim = NULL;
25897883Sgibbs		goto fail;
25997883Sgibbs	}
26097883Sgibbs
26197883Sgibbs	if (xpt_create_path(&path, /*periph*/NULL,
26297883Sgibbs			    cam_sim_path(sim), CAM_TARGET_WILDCARD,
26397883Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
26497883Sgibbs		xpt_bus_deregister(cam_sim_path(sim));
26597883Sgibbs		cam_sim_free(sim, /*free_devq*/TRUE);
26697883Sgibbs		sim = NULL;
26797883Sgibbs		goto fail;
26897883Sgibbs	}
26997883Sgibbs
27097883Sgibbs	xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
27197883Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
27297883Sgibbs	csa.event_enable = AC_LOST_DEVICE;
27397883Sgibbs	csa.callback = ahd_async;
27497883Sgibbs	csa.callback_arg = sim;
27597883Sgibbs	xpt_action((union ccb *)&csa);
27697883Sgibbs	count++;
27797883Sgibbs
27897883Sgibbsfail:
27997883Sgibbs	ahd->platform_data->sim = sim;
28097883Sgibbs	ahd->platform_data->path = path;
281168807Sscottl	ahd_unlock(ahd);
282102684Sgibbs	if (count != 0) {
28397883Sgibbs		/* We have to wait until after any system dumps... */
28497883Sgibbs		ahd->platform_data->eh =
28597883Sgibbs		    EVENTHANDLER_REGISTER(shutdown_final, ahd_shutdown,
28697883Sgibbs					  ahd, SHUTDOWN_PRI_DEFAULT);
287102684Sgibbs		ahd_intr_enable(ahd, TRUE);
288102684Sgibbs	}
28997883Sgibbs
290102684Sgibbs
29197883Sgibbs	return (count);
29297883Sgibbs}
29397883Sgibbs
29497883Sgibbs/*
29597883Sgibbs * Catch an interrupt from the adapter
29697883Sgibbs */
29797883Sgibbsvoid
29897883Sgibbsahd_platform_intr(void *arg)
29997883Sgibbs{
30097883Sgibbs	struct	ahd_softc *ahd;
30197883Sgibbs
30297883Sgibbs	ahd = (struct ahd_softc *)arg;
303168807Sscottl	ahd_lock(ahd);
30497883Sgibbs	ahd_intr(ahd);
305168807Sscottl	ahd_unlock(ahd);
30697883Sgibbs}
30797883Sgibbs
30897883Sgibbs/*
30997883Sgibbs * We have an scb which has been processed by the
31097883Sgibbs * adaptor, now we look to see how the operation
31197883Sgibbs * went.
31297883Sgibbs */
31397883Sgibbsvoid
31497883Sgibbsahd_done(struct ahd_softc *ahd, struct scb *scb)
31597883Sgibbs{
31697883Sgibbs	union ccb *ccb;
31797883Sgibbs
31897883Sgibbs	CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE,
31997883Sgibbs		  ("ahd_done - scb %d\n", SCB_GET_TAG(scb)));
32097883Sgibbs
32197883Sgibbs	ccb = scb->io_ctx;
32297883Sgibbs	LIST_REMOVE(scb, pending_links);
323123579Sgibbs	if ((scb->flags & SCB_TIMEDOUT) != 0)
324123579Sgibbs		LIST_REMOVE(scb, timedout_links);
32597883Sgibbs
326168807Sscottl	callout_stop(&scb->io_timer);
32797883Sgibbs
32897883Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
329115343Sscottl		bus_dmasync_op_t op;
33097883Sgibbs
33197883Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
33297883Sgibbs			op = BUS_DMASYNC_POSTREAD;
33397883Sgibbs		else
33497883Sgibbs			op = BUS_DMASYNC_POSTWRITE;
33597883Sgibbs		bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op);
33697883Sgibbs		bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap);
33797883Sgibbs	}
33897883Sgibbs
33997883Sgibbs#ifdef AHD_TARGET_MODE
34097883Sgibbs	if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
34197883Sgibbs		struct cam_path *ccb_path;
34297883Sgibbs
34397883Sgibbs		/*
34497883Sgibbs		 * If we have finally disconnected, clean up our
34597883Sgibbs		 * pending device state.
34697883Sgibbs		 * XXX - There may be error states that cause where
34797883Sgibbs		 *       we will remain connected.
34897883Sgibbs		 */
34997883Sgibbs		ccb_path = ccb->ccb_h.path;
35097883Sgibbs		if (ahd->pending_device != NULL
35197883Sgibbs		 && xpt_path_comp(ahd->pending_device->path, ccb_path) == 0) {
35297883Sgibbs
35397883Sgibbs			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
35497883Sgibbs				ahd->pending_device = NULL;
35597883Sgibbs			} else {
35697883Sgibbs				xpt_print_path(ccb->ccb_h.path);
35797883Sgibbs				printf("Still disconnected\n");
35897883Sgibbs				ahd_freeze_ccb(ccb);
35997883Sgibbs			}
36097883Sgibbs		}
36197883Sgibbs
362123579Sgibbs		if (aic_get_transaction_status(scb) == CAM_REQ_INPROG)
36397883Sgibbs			ccb->ccb_h.status |= CAM_REQ_CMP;
36497883Sgibbs		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
36597883Sgibbs		ahd_free_scb(ahd, scb);
36697883Sgibbs		xpt_done(ccb);
36797883Sgibbs		return;
36897883Sgibbs	}
36997883Sgibbs#endif
37097883Sgibbs
37197883Sgibbs	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
37297883Sgibbs		struct	scb *list_scb;
37397883Sgibbs
374133911Sgibbs		ahd->scb_data.recovery_scbs--;
37597883Sgibbs
376123579Sgibbs		if (aic_get_transaction_status(scb) == CAM_BDR_SENT
377123579Sgibbs		 || aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
378123579Sgibbs			aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
379123579Sgibbs
380133911Sgibbs		if (ahd->scb_data.recovery_scbs == 0) {
381133911Sgibbs			/*
382133911Sgibbs			 * All recovery actions have completed successfully,
383133911Sgibbs			 * so reinstate the timeouts for all other pending
384133911Sgibbs			 * commands.
385133911Sgibbs			 */
386133911Sgibbs			LIST_FOREACH(list_scb,
387133911Sgibbs				     &ahd->pending_scbs, pending_links) {
388133911Sgibbs
389150450Sgibbs				aic_scb_timer_reset(list_scb,
390150450Sgibbs						    aic_get_timeout(scb));
391133911Sgibbs			}
392133911Sgibbs
393133911Sgibbs			ahd_print_path(ahd, scb);
394133911Sgibbs			printf("no longer in timeout, status = %x\n",
395133911Sgibbs			       ccb->ccb_h.status);
396133911Sgibbs		}
39797883Sgibbs	}
39897883Sgibbs
39997883Sgibbs	/* Don't clobber any existing error state */
400123579Sgibbs	if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) {
40197883Sgibbs		ccb->ccb_h.status |= CAM_REQ_CMP;
40297883Sgibbs	} else if ((scb->flags & SCB_SENSE) != 0) {
40397883Sgibbs		/*
40497883Sgibbs		 * We performed autosense retrieval.
40597883Sgibbs		 *
40697883Sgibbs		 * Zero any sense not transferred by the
40797883Sgibbs		 * device.  The SCSI spec mandates that any
40897883Sgibbs		 * untransfered data should be assumed to be
40997883Sgibbs		 * zero.  Complete the 'bounce' of sense information
41097883Sgibbs		 * through buffers accessible via bus-space by
41197883Sgibbs		 * copying it into the clients csio.
41297883Sgibbs		 */
41397883Sgibbs		memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
41497883Sgibbs		memcpy(&ccb->csio.sense_data,
41597883Sgibbs		       ahd_get_sense_buf(ahd, scb),
41697883Sgibbs/* XXX What size do we want to use??? */
41797883Sgibbs			sizeof(ccb->csio.sense_data)
41897883Sgibbs		       - ccb->csio.sense_resid);
41997883Sgibbs		scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID;
42097883Sgibbs	} else if ((scb->flags & SCB_PKT_SENSE) != 0) {
42197883Sgibbs		struct scsi_status_iu_header *siu;
42297883Sgibbs		u_int sense_len;
42397883Sgibbs
42497883Sgibbs		/*
42597883Sgibbs		 * Copy only the sense data into the provided buffer.
42697883Sgibbs		 */
42797883Sgibbs		siu = (struct scsi_status_iu_header *)scb->sense_data;
42897883Sgibbs		sense_len = MIN(scsi_4btoul(siu->sense_length),
42997883Sgibbs				sizeof(ccb->csio.sense_data));
43097883Sgibbs		memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
43197883Sgibbs		memcpy(&ccb->csio.sense_data,
43297883Sgibbs		       ahd_get_sense_buf(ahd, scb) + SIU_SENSE_OFFSET(siu),
43397883Sgibbs		       sense_len);
434176366Sgibbs#ifdef AHD_DEBUG
435176366Sgibbs		if ((ahd_debug & AHD_SHOW_SENSE) != 0) {
436176366Sgibbs			uint8_t *sense_data = (uint8_t *)&ccb->csio.sense_data;
437176366Sgibbs			u_int i;
438176366Sgibbs
439176366Sgibbs			printf("Copied %d bytes of sense data offset %d:",
440176366Sgibbs			       sense_len, SIU_SENSE_OFFSET(siu));
441176366Sgibbs			for (i = 0; i < sense_len; i++)
442176366Sgibbs				printf(" 0x%x", *sense_data++);
443176366Sgibbs			printf("\n");
444176366Sgibbs		}
445176366Sgibbs#endif
44697883Sgibbs		scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID;
44797883Sgibbs	}
44897883Sgibbs	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
44997883Sgibbs	ahd_free_scb(ahd, scb);
45097883Sgibbs	xpt_done(ccb);
45197883Sgibbs}
45297883Sgibbs
45397883Sgibbsstatic void
45497883Sgibbsahd_action(struct cam_sim *sim, union ccb *ccb)
45597883Sgibbs{
45697883Sgibbs	struct	ahd_softc *ahd;
45797883Sgibbs#ifdef AHD_TARGET_MODE
45897883Sgibbs	struct	ahd_tmode_lstate *lstate;
45997883Sgibbs#endif
46097883Sgibbs	u_int	target_id;
46197883Sgibbs	u_int	our_id;
46297883Sgibbs
46397883Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahd_action\n"));
46497883Sgibbs
46597883Sgibbs	ahd = (struct ahd_softc *)cam_sim_softc(sim);
46697883Sgibbs
46797883Sgibbs	target_id = ccb->ccb_h.target_id;
46897883Sgibbs	our_id = SIM_SCSI_ID(ahd, sim);
46997883Sgibbs
47097883Sgibbs	switch (ccb->ccb_h.func_code) {
47197883Sgibbs	/* Common cases first */
47297883Sgibbs#ifdef AHD_TARGET_MODE
47397883Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
47497883Sgibbs	case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/
47597883Sgibbs	{
47697883Sgibbs		struct	   ahd_tmode_tstate *tstate;
47797883Sgibbs		cam_status status;
47897883Sgibbs
47997883Sgibbs		status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate,
48097883Sgibbs					     &lstate, TRUE);
48197883Sgibbs
48297883Sgibbs		if (status != CAM_REQ_CMP) {
48397883Sgibbs			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
48497883Sgibbs				/* Response from the black hole device */
48597883Sgibbs				tstate = NULL;
48697883Sgibbs				lstate = ahd->black_hole;
48797883Sgibbs			} else {
48897883Sgibbs				ccb->ccb_h.status = status;
48997883Sgibbs				xpt_done(ccb);
49097883Sgibbs				break;
49197883Sgibbs			}
49297883Sgibbs		}
49397883Sgibbs		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
49497883Sgibbs
49597883Sgibbs			SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
49697883Sgibbs					  sim_links.sle);
49797883Sgibbs			ccb->ccb_h.status = CAM_REQ_INPROG;
49897883Sgibbs			if ((ahd->flags & AHD_TQINFIFO_BLOCKED) != 0)
49997883Sgibbs				ahd_run_tqinfifo(ahd, /*paused*/FALSE);
50097883Sgibbs			break;
50197883Sgibbs		}
50297883Sgibbs
50397883Sgibbs		/*
50497883Sgibbs		 * The target_id represents the target we attempt to
50597883Sgibbs		 * select.  In target mode, this is the initiator of
50697883Sgibbs		 * the original command.
50797883Sgibbs		 */
50897883Sgibbs		our_id = target_id;
50997883Sgibbs		target_id = ccb->csio.init_id;
51097883Sgibbs		/* FALLTHROUGH */
51197883Sgibbs	}
51297883Sgibbs#endif
51397883Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
51497883Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
51597883Sgibbs	{
51697883Sgibbs		struct	scb *scb;
51797883Sgibbs		struct	hardware_scb *hscb;
518102684Sgibbs		struct	ahd_initiator_tinfo *tinfo;
519102684Sgibbs		struct	ahd_tmode_tstate *tstate;
520102684Sgibbs		u_int	col_idx;
52197883Sgibbs
52297883Sgibbs		if ((ahd->flags & AHD_INITIATORROLE) == 0
52397883Sgibbs		 && (ccb->ccb_h.func_code == XPT_SCSI_IO
52497883Sgibbs		  || ccb->ccb_h.func_code == XPT_RESET_DEV)) {
52597883Sgibbs			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
52697883Sgibbs			xpt_done(ccb);
52797883Sgibbs			return;
52897883Sgibbs		}
52997883Sgibbs
53097883Sgibbs		/*
53197883Sgibbs		 * get an scb to use.
53297883Sgibbs		 */
533102684Sgibbs		tinfo = ahd_fetch_transinfo(ahd, 'A', our_id,
534102684Sgibbs					    target_id, &tstate);
535102684Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0
536102684Sgibbs		 || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0
537102684Sgibbs		 || ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
538102684Sgibbs			col_idx = AHD_NEVER_COL_IDX;
539102684Sgibbs		} else {
540102684Sgibbs			col_idx = AHD_BUILD_COL_IDX(target_id,
541102684Sgibbs						    ccb->ccb_h.target_lun);
542102684Sgibbs		}
543102684Sgibbs		if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
54497883Sgibbs
54597883Sgibbs			xpt_freeze_simq(sim, /*count*/1);
54697883Sgibbs			ahd->flags |= AHD_RESOURCE_SHORTAGE;
54797883Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
54897883Sgibbs			xpt_done(ccb);
54997883Sgibbs			return;
55097883Sgibbs		}
55197883Sgibbs
55297883Sgibbs		hscb = scb->hscb;
55397883Sgibbs
55497883Sgibbs		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE,
55597883Sgibbs			  ("start scb(%p)\n", scb));
55697883Sgibbs		scb->io_ctx = ccb;
55797883Sgibbs		/*
55897883Sgibbs		 * So we can find the SCB when an abort is requested
55997883Sgibbs		 */
56097883Sgibbs		ccb->ccb_h.ccb_scb_ptr = scb;
56197883Sgibbs
56297883Sgibbs		/*
56397883Sgibbs		 * Put all the arguments for the xfer in the scb
56497883Sgibbs		 */
56597883Sgibbs		hscb->control = 0;
56697883Sgibbs		hscb->scsiid = BUILD_SCSIID(ahd, sim, target_id, our_id);
56797883Sgibbs		hscb->lun = ccb->ccb_h.target_lun;
56897883Sgibbs		if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
56997883Sgibbs			hscb->cdb_len = 0;
57097883Sgibbs			scb->flags |= SCB_DEVICE_RESET;
57197883Sgibbs			hscb->control |= MK_MESSAGE;
572109588Sgibbs			hscb->task_management = SIU_TASKMGMT_LUN_RESET;
57397883Sgibbs			ahd_execute_scb(scb, NULL, 0, 0);
57497883Sgibbs		} else {
57597883Sgibbs#ifdef AHD_TARGET_MODE
57697883Sgibbs			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
57797883Sgibbs				struct target_data *tdata;
57897883Sgibbs
57997883Sgibbs				tdata = &hscb->shared_data.tdata;
58097883Sgibbs				if (ahd->pending_device == lstate)
58197883Sgibbs					scb->flags |= SCB_TARGET_IMMEDIATE;
58297883Sgibbs				hscb->control |= TARGET_SCB;
58397883Sgibbs				tdata->target_phases = 0;
58497883Sgibbs				if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
58597883Sgibbs					tdata->target_phases |= SPHASE_PENDING;
58697883Sgibbs					tdata->scsi_status =
58797883Sgibbs					    ccb->csio.scsi_status;
58897883Sgibbs				}
58997883Sgibbs	 			if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT)
59097883Sgibbs					tdata->target_phases |= NO_DISCONNECT;
59197883Sgibbs
59297883Sgibbs				tdata->initiator_tag =
59397883Sgibbs				    ahd_htole16(ccb->csio.tag_id);
59497883Sgibbs			}
59597883Sgibbs#endif
596109588Sgibbs			hscb->task_management = 0;
59797883Sgibbs			if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID)
59897883Sgibbs				hscb->control |= ccb->csio.tag_action;
59997883Sgibbs
60097883Sgibbs			ahd_setup_data(ahd, sim, &ccb->csio, scb);
60197883Sgibbs		}
60297883Sgibbs		break;
60397883Sgibbs	}
60497883Sgibbs#ifdef AHD_TARGET_MODE
605237601Sken	case XPT_NOTIFY_ACKNOWLEDGE:
606237601Sken	case XPT_IMMEDIATE_NOTIFY:
60797883Sgibbs	{
60897883Sgibbs		struct	   ahd_tmode_tstate *tstate;
60997883Sgibbs		struct	   ahd_tmode_lstate *lstate;
61097883Sgibbs		cam_status status;
61197883Sgibbs
61297883Sgibbs		status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate,
61397883Sgibbs					     &lstate, TRUE);
61497883Sgibbs
61597883Sgibbs		if (status != CAM_REQ_CMP) {
61697883Sgibbs			ccb->ccb_h.status = status;
61797883Sgibbs			xpt_done(ccb);
61897883Sgibbs			break;
61997883Sgibbs		}
62097883Sgibbs		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
62197883Sgibbs				  sim_links.sle);
62297883Sgibbs		ccb->ccb_h.status = CAM_REQ_INPROG;
62397883Sgibbs		ahd_send_lstate_events(ahd, lstate);
62497883Sgibbs		break;
62597883Sgibbs	}
62697883Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
62797883Sgibbs		ahd_handle_en_lun(ahd, sim, ccb);
62897883Sgibbs		xpt_done(ccb);
62997883Sgibbs		break;
63097883Sgibbs#endif
63197883Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
63297883Sgibbs	{
63397883Sgibbs		ahd_abort_ccb(ahd, sim, ccb);
63497883Sgibbs		break;
63597883Sgibbs	}
63697883Sgibbs	case XPT_SET_TRAN_SETTINGS:
63797883Sgibbs	{
63897883Sgibbs		ahd_set_tran_settings(ahd, SIM_SCSI_ID(ahd, sim),
63997883Sgibbs				      SIM_CHANNEL(ahd, sim), &ccb->cts);
64097883Sgibbs		xpt_done(ccb);
64197883Sgibbs		break;
64297883Sgibbs	}
64397883Sgibbs	case XPT_GET_TRAN_SETTINGS:
64497883Sgibbs	/* Get default/user set transfer settings for the target */
64597883Sgibbs	{
64697883Sgibbs		ahd_get_tran_settings(ahd, SIM_SCSI_ID(ahd, sim),
64797883Sgibbs				      SIM_CHANNEL(ahd, sim), &ccb->cts);
64897883Sgibbs		xpt_done(ccb);
64997883Sgibbs		break;
65097883Sgibbs	}
65197883Sgibbs	case XPT_CALC_GEOMETRY:
65297883Sgibbs	{
653123579Sgibbs		aic_calc_geometry(&ccb->ccg, ahd->flags & AHD_EXTENDED_TRANS_A);
65497883Sgibbs		xpt_done(ccb);
65597883Sgibbs		break;
65697883Sgibbs	}
65797883Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
65897883Sgibbs	{
65997883Sgibbs		int  found;
66097883Sgibbs
66197883Sgibbs		found = ahd_reset_channel(ahd, SIM_CHANNEL(ahd, sim),
66297883Sgibbs					  /*initiate reset*/TRUE);
66397883Sgibbs		if (bootverbose) {
66497883Sgibbs			xpt_print_path(SIM_PATH(ahd, sim));
66597883Sgibbs			printf("SCSI bus reset delivered. "
66697883Sgibbs			       "%d SCBs aborted.\n", found);
66797883Sgibbs		}
66897883Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
66997883Sgibbs		xpt_done(ccb);
67097883Sgibbs		break;
67197883Sgibbs	}
67297883Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
67397883Sgibbs		/* XXX Implement */
67497883Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
67597883Sgibbs		xpt_done(ccb);
67697883Sgibbs		break;
67797883Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
67897883Sgibbs	{
67997883Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
68097883Sgibbs
68197883Sgibbs		cpi->version_num = 1; /* XXX??? */
68297883Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
68397883Sgibbs		if ((ahd->features & AHD_WIDE) != 0)
68497883Sgibbs			cpi->hba_inquiry |= PI_WIDE_16;
68597883Sgibbs		if ((ahd->features & AHD_TARGETMODE) != 0) {
68697883Sgibbs			cpi->target_sprt = PIT_PROCESSOR
68797883Sgibbs					 | PIT_DISCONNECT
68897883Sgibbs					 | PIT_TERM_IO;
68997883Sgibbs		} else {
69097883Sgibbs			cpi->target_sprt = 0;
69197883Sgibbs		}
69297883Sgibbs		cpi->hba_misc = 0;
69397883Sgibbs		cpi->hba_eng_cnt = 0;
69497883Sgibbs		cpi->max_target = (ahd->features & AHD_WIDE) ? 15 : 7;
695141978Sgibbs		cpi->max_lun = AHD_NUM_LUNS_NONPKT - 1;
69697883Sgibbs		cpi->initiator_id = ahd->our_id;
69797883Sgibbs		if ((ahd->flags & AHD_RESET_BUS_A) == 0) {
69897883Sgibbs			cpi->hba_misc |= PIM_NOBUSRESET;
69997883Sgibbs		}
70097883Sgibbs		cpi->bus_id = cam_sim_bus(sim);
70197883Sgibbs		cpi->base_transfer_speed = 3300;
70297883Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
70397883Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
70497883Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
70597883Sgibbs		cpi->unit_number = cam_sim_unit(sim);
70697883Sgibbs		cpi->protocol = PROTO_SCSI;
70797883Sgibbs		cpi->protocol_version = SCSI_REV_2;
70897883Sgibbs		cpi->transport = XPORT_SPI;
70997883Sgibbs		cpi->transport_version = 4;
710176355Sgibbs		cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_DT_ST
711176355Sgibbs						    | SID_SPI_IUS
712176355Sgibbs						    | SID_SPI_QAS;
71397883Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
71497883Sgibbs		xpt_done(ccb);
71597883Sgibbs		break;
71697883Sgibbs	}
71797883Sgibbs	default:
71897883Sgibbs		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
71997883Sgibbs		xpt_done(ccb);
72097883Sgibbs		break;
72197883Sgibbs	}
72297883Sgibbs}
72397883Sgibbs
72497883Sgibbs
72597883Sgibbsstatic void
72697883Sgibbsahd_set_tran_settings(struct ahd_softc *ahd, int our_id, char channel,
72797883Sgibbs		      struct ccb_trans_settings *cts)
72897883Sgibbs{
72997883Sgibbs	struct	  ahd_devinfo devinfo;
73097883Sgibbs	struct	  ccb_trans_settings_scsi *scsi;
73197883Sgibbs	struct	  ccb_trans_settings_spi *spi;
73297883Sgibbs	struct	  ahd_initiator_tinfo *tinfo;
73397883Sgibbs	struct	  ahd_tmode_tstate *tstate;
73497883Sgibbs	uint16_t *discenable;
73597883Sgibbs	uint16_t *tagenable;
73697883Sgibbs	u_int	  update_type;
73797883Sgibbs
73897883Sgibbs	scsi = &cts->proto_specific.scsi;
73997883Sgibbs	spi = &cts->xport_specific.spi;
74097883Sgibbs	ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim),
74197883Sgibbs			    cts->ccb_h.target_id,
74297883Sgibbs			    cts->ccb_h.target_lun,
74397883Sgibbs			    SIM_CHANNEL(ahd, sim),
74497883Sgibbs			    ROLE_UNKNOWN);
74597883Sgibbs	tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
74697883Sgibbs				    devinfo.our_scsiid,
74797883Sgibbs				    devinfo.target, &tstate);
74897883Sgibbs	update_type = 0;
74997883Sgibbs	if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
75097883Sgibbs		update_type |= AHD_TRANS_GOAL;
75197883Sgibbs		discenable = &tstate->discenable;
75297883Sgibbs		tagenable = &tstate->tagenable;
75397883Sgibbs		tinfo->curr.protocol_version = cts->protocol_version;
75497883Sgibbs		tinfo->curr.transport_version = cts->transport_version;
75597883Sgibbs		tinfo->goal.protocol_version = cts->protocol_version;
75697883Sgibbs		tinfo->goal.transport_version = cts->transport_version;
75797883Sgibbs	} else if (cts->type == CTS_TYPE_USER_SETTINGS) {
75897883Sgibbs		update_type |= AHD_TRANS_USER;
75997883Sgibbs		discenable = &ahd->user_discenable;
76097883Sgibbs		tagenable = &ahd->user_tagenable;
76197883Sgibbs		tinfo->user.protocol_version = cts->protocol_version;
76297883Sgibbs		tinfo->user.transport_version = cts->transport_version;
76397883Sgibbs	} else {
76497883Sgibbs		cts->ccb_h.status = CAM_REQ_INVALID;
76597883Sgibbs		return;
76697883Sgibbs	}
76797883Sgibbs
76897883Sgibbs	if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
76997883Sgibbs		if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
77097883Sgibbs			*discenable |= devinfo.target_mask;
77197883Sgibbs		else
77297883Sgibbs			*discenable &= ~devinfo.target_mask;
77397883Sgibbs	}
77497883Sgibbs
77597883Sgibbs	if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
77697883Sgibbs		if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
77797883Sgibbs			*tagenable |= devinfo.target_mask;
77897883Sgibbs		else
77997883Sgibbs			*tagenable &= ~devinfo.target_mask;
78097883Sgibbs	}
78197883Sgibbs
78297883Sgibbs	if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
78397883Sgibbs		ahd_validate_width(ahd, /*tinfo limit*/NULL,
78497883Sgibbs				   &spi->bus_width, ROLE_UNKNOWN);
78597883Sgibbs		ahd_set_width(ahd, &devinfo, spi->bus_width,
78697883Sgibbs			      update_type, /*paused*/FALSE);
78797883Sgibbs	}
78897883Sgibbs
78997883Sgibbs	if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) {
79097883Sgibbs		if (update_type == AHD_TRANS_USER)
79197883Sgibbs			spi->ppr_options = tinfo->user.ppr_options;
79297883Sgibbs		else
79397883Sgibbs			spi->ppr_options = tinfo->goal.ppr_options;
79497883Sgibbs	}
79597883Sgibbs
79697883Sgibbs	if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) {
79797883Sgibbs		if (update_type == AHD_TRANS_USER)
79897883Sgibbs			spi->sync_offset = tinfo->user.offset;
79997883Sgibbs		else
80097883Sgibbs			spi->sync_offset = tinfo->goal.offset;
80197883Sgibbs	}
80297883Sgibbs
80397883Sgibbs	if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
80497883Sgibbs		if (update_type == AHD_TRANS_USER)
80597883Sgibbs			spi->sync_period = tinfo->user.period;
80697883Sgibbs		else
80797883Sgibbs			spi->sync_period = tinfo->goal.period;
80897883Sgibbs	}
80997883Sgibbs
81097883Sgibbs	if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
81197883Sgibbs	 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
81297883Sgibbs		u_int	maxsync;
81397883Sgibbs
81497883Sgibbs		maxsync = AHD_SYNCRATE_MAX;
81597883Sgibbs
81697883Sgibbs		if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT)
81797883Sgibbs			spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
81897883Sgibbs
81997883Sgibbs		if ((*discenable & devinfo.target_mask) == 0)
82097883Sgibbs			spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ;
82197883Sgibbs
82297883Sgibbs		ahd_find_syncrate(ahd, &spi->sync_period,
82397883Sgibbs				  &spi->ppr_options, maxsync);
82497883Sgibbs		ahd_validate_offset(ahd, /*tinfo limit*/NULL,
82597883Sgibbs				    spi->sync_period, &spi->sync_offset,
82697883Sgibbs				    spi->bus_width, ROLE_UNKNOWN);
82797883Sgibbs
82897883Sgibbs		/* We use a period of 0 to represent async */
82997883Sgibbs		if (spi->sync_offset == 0) {
83097883Sgibbs			spi->sync_period = 0;
83197883Sgibbs			spi->ppr_options = 0;
83297883Sgibbs		}
83397883Sgibbs
83497883Sgibbs		ahd_set_syncrate(ahd, &devinfo, spi->sync_period,
83597883Sgibbs				 spi->sync_offset, spi->ppr_options,
83697883Sgibbs				 update_type, /*paused*/FALSE);
83797883Sgibbs	}
83897883Sgibbs	cts->ccb_h.status = CAM_REQ_CMP;
83997883Sgibbs}
84097883Sgibbs
84197883Sgibbsstatic void
84297883Sgibbsahd_get_tran_settings(struct ahd_softc *ahd, int our_id, char channel,
84397883Sgibbs		      struct ccb_trans_settings *cts)
84497883Sgibbs{
84597883Sgibbs	struct	ahd_devinfo devinfo;
84697883Sgibbs	struct	ccb_trans_settings_scsi *scsi;
84797883Sgibbs	struct	ccb_trans_settings_spi *spi;
84897883Sgibbs	struct	ahd_initiator_tinfo *targ_info;
84997883Sgibbs	struct	ahd_tmode_tstate *tstate;
85097883Sgibbs	struct	ahd_transinfo *tinfo;
85197883Sgibbs
85297883Sgibbs	scsi = &cts->proto_specific.scsi;
85397883Sgibbs	spi = &cts->xport_specific.spi;
85497883Sgibbs	ahd_compile_devinfo(&devinfo, our_id,
85597883Sgibbs			    cts->ccb_h.target_id,
85697883Sgibbs			    cts->ccb_h.target_lun,
85797883Sgibbs			    channel, ROLE_UNKNOWN);
85897883Sgibbs	targ_info = ahd_fetch_transinfo(ahd, devinfo.channel,
85997883Sgibbs					devinfo.our_scsiid,
86097883Sgibbs					devinfo.target, &tstate);
86197883Sgibbs
86297883Sgibbs	if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
86397883Sgibbs		tinfo = &targ_info->curr;
86497883Sgibbs	else
86597883Sgibbs		tinfo = &targ_info->user;
86697883Sgibbs
86797883Sgibbs	scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
86897883Sgibbs	spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
86997883Sgibbs	if (cts->type == CTS_TYPE_USER_SETTINGS) {
87097883Sgibbs		if ((ahd->user_discenable & devinfo.target_mask) != 0)
87197883Sgibbs			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
87297883Sgibbs
87397883Sgibbs		if ((ahd->user_tagenable & devinfo.target_mask) != 0)
87497883Sgibbs			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
87597883Sgibbs	} else {
87697883Sgibbs		if ((tstate->discenable & devinfo.target_mask) != 0)
87797883Sgibbs			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
87897883Sgibbs
87997883Sgibbs		if ((tstate->tagenable & devinfo.target_mask) != 0)
88097883Sgibbs			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
88197883Sgibbs	}
88297883Sgibbs	cts->protocol_version = tinfo->protocol_version;
88397883Sgibbs	cts->transport_version = tinfo->transport_version;
88497883Sgibbs
88597883Sgibbs	spi->sync_period = tinfo->period;
88697883Sgibbs	spi->sync_offset = tinfo->offset;
88797883Sgibbs	spi->bus_width = tinfo->width;
88897883Sgibbs	spi->ppr_options = tinfo->ppr_options;
88997883Sgibbs
89097883Sgibbs	cts->protocol = PROTO_SCSI;
89197883Sgibbs	cts->transport = XPORT_SPI;
89297883Sgibbs	spi->valid = CTS_SPI_VALID_SYNC_RATE
89397883Sgibbs		   | CTS_SPI_VALID_SYNC_OFFSET
89497883Sgibbs		   | CTS_SPI_VALID_BUS_WIDTH
89597883Sgibbs		   | CTS_SPI_VALID_PPR_OPTIONS;
89697883Sgibbs
89797883Sgibbs	if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
89897883Sgibbs		scsi->valid = CTS_SCSI_VALID_TQ;
89997883Sgibbs		spi->valid |= CTS_SPI_VALID_DISC;
90097883Sgibbs	} else {
90197883Sgibbs		scsi->valid = 0;
90297883Sgibbs	}
90397883Sgibbs
90497883Sgibbs	cts->ccb_h.status = CAM_REQ_CMP;
90597883Sgibbs}
90697883Sgibbs
90797883Sgibbsstatic void
90897883Sgibbsahd_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
90997883Sgibbs{
91097883Sgibbs	struct ahd_softc *ahd;
91197883Sgibbs	struct cam_sim *sim;
91297883Sgibbs
91397883Sgibbs	sim = (struct cam_sim *)callback_arg;
91497883Sgibbs	ahd = (struct ahd_softc *)cam_sim_softc(sim);
91597883Sgibbs	switch (code) {
91697883Sgibbs	case AC_LOST_DEVICE:
91797883Sgibbs	{
91897883Sgibbs		struct	ahd_devinfo devinfo;
91997883Sgibbs
92097883Sgibbs		ahd_compile_devinfo(&devinfo, SIM_SCSI_ID(ahd, sim),
92197883Sgibbs				    xpt_path_target_id(path),
92297883Sgibbs				    xpt_path_lun_id(path),
92397883Sgibbs				    SIM_CHANNEL(ahd, sim),
92497883Sgibbs				    ROLE_UNKNOWN);
92597883Sgibbs
92697883Sgibbs		/*
92797883Sgibbs		 * Revert to async/narrow transfers
92897883Sgibbs		 * for the next device.
92997883Sgibbs		 */
93097883Sgibbs		ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
93197883Sgibbs			      AHD_TRANS_GOAL|AHD_TRANS_CUR, /*paused*/FALSE);
93297883Sgibbs		ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
93397883Sgibbs				 /*ppr_options*/0, AHD_TRANS_GOAL|AHD_TRANS_CUR,
93497883Sgibbs				 /*paused*/FALSE);
93597883Sgibbs		break;
93697883Sgibbs	}
93797883Sgibbs	default:
93897883Sgibbs		break;
93997883Sgibbs	}
94097883Sgibbs}
94197883Sgibbs
94297883Sgibbsstatic void
94397883Sgibbsahd_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
94497883Sgibbs		int error)
94597883Sgibbs{
94697883Sgibbs	struct	scb *scb;
94797883Sgibbs	union	ccb *ccb;
94897883Sgibbs	struct	ahd_softc *ahd;
94997883Sgibbs	struct	ahd_initiator_tinfo *tinfo;
95097883Sgibbs	struct	ahd_tmode_tstate *tstate;
95197883Sgibbs	u_int	mask;
95297883Sgibbs
95397883Sgibbs	scb = (struct scb *)arg;
95497883Sgibbs	ccb = scb->io_ctx;
95597883Sgibbs	ahd = scb->ahd_softc;
95697883Sgibbs
95797883Sgibbs	if (error != 0) {
95897883Sgibbs		if (error == EFBIG)
959123579Sgibbs			aic_set_transaction_status(scb, CAM_REQ_TOO_BIG);
96097883Sgibbs		else
961123579Sgibbs			aic_set_transaction_status(scb, CAM_REQ_CMP_ERR);
96297883Sgibbs		if (nsegments != 0)
96397883Sgibbs			bus_dmamap_unload(ahd->buffer_dmat, scb->dmamap);
96497883Sgibbs		ahd_free_scb(ahd, scb);
96597883Sgibbs		xpt_done(ccb);
96697883Sgibbs		return;
96797883Sgibbs	}
96897883Sgibbs	scb->sg_count = 0;
96997883Sgibbs	if (nsegments != 0) {
97097883Sgibbs		void *sg;
971115343Sscottl		bus_dmasync_op_t op;
97297883Sgibbs		u_int i;
97397883Sgibbs
97497883Sgibbs		/* Copy the segments into our SG list */
97597883Sgibbs		for (i = nsegments, sg = scb->sg_list; i > 0; i--) {
97697883Sgibbs
97797883Sgibbs			sg = ahd_sg_setup(ahd, scb, sg, dm_segs->ds_addr,
97897883Sgibbs					  dm_segs->ds_len,
97997883Sgibbs					  /*last*/i == 1);
98097883Sgibbs			dm_segs++;
98197883Sgibbs		}
98297883Sgibbs
98397883Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
98497883Sgibbs			op = BUS_DMASYNC_PREREAD;
98597883Sgibbs		else
98697883Sgibbs			op = BUS_DMASYNC_PREWRITE;
98797883Sgibbs
98897883Sgibbs		bus_dmamap_sync(ahd->buffer_dmat, scb->dmamap, op);
98997883Sgibbs
99097883Sgibbs		if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
99197883Sgibbs			struct target_data *tdata;
99297883Sgibbs
99397883Sgibbs			tdata = &scb->hscb->shared_data.tdata;
99497883Sgibbs			tdata->target_phases |= DPHASE_PENDING;
99597883Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
99697883Sgibbs				tdata->data_phase = P_DATAOUT;
99797883Sgibbs			else
99897883Sgibbs				tdata->data_phase = P_DATAIN;
99997883Sgibbs		}
100097883Sgibbs	}
100197883Sgibbs
100297883Sgibbs	/*
100397883Sgibbs	 * Last time we need to check if this SCB needs to
100497883Sgibbs	 * be aborted.
100597883Sgibbs	 */
1006123579Sgibbs	if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) {
100797883Sgibbs		if (nsegments != 0)
100897883Sgibbs			bus_dmamap_unload(ahd->buffer_dmat,
100997883Sgibbs					  scb->dmamap);
101097883Sgibbs		ahd_free_scb(ahd, scb);
101197883Sgibbs		xpt_done(ccb);
101297883Sgibbs		return;
101397883Sgibbs	}
101497883Sgibbs
101597883Sgibbs	tinfo = ahd_fetch_transinfo(ahd, SCSIID_CHANNEL(ahd, scb->hscb->scsiid),
101697883Sgibbs				    SCSIID_OUR_ID(scb->hscb->scsiid),
101797883Sgibbs				    SCSIID_TARGET(ahd, scb->hscb->scsiid),
101897883Sgibbs				    &tstate);
101997883Sgibbs
102097883Sgibbs	mask = SCB_GET_TARGET_MASK(ahd, scb);
102197883Sgibbs
102297883Sgibbs	if ((tstate->discenable & mask) != 0
102397883Sgibbs	 && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0)
102497883Sgibbs		scb->hscb->control |= DISCENB;
102597883Sgibbs
1026109588Sgibbs	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
102797883Sgibbs		scb->flags |= SCB_PACKETIZED;
1028109588Sgibbs		if (scb->hscb->task_management != 0)
1029109588Sgibbs			scb->hscb->control &= ~MK_MESSAGE;
1030109588Sgibbs	}
103197883Sgibbs
103297883Sgibbs	if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
103397883Sgibbs	 && (tinfo->goal.width != 0
103497883Sgibbs	  || tinfo->goal.period != 0
103597883Sgibbs	  || tinfo->goal.ppr_options != 0)) {
103697883Sgibbs		scb->flags |= SCB_NEGOTIATE;
103797883Sgibbs		scb->hscb->control |= MK_MESSAGE;
103897883Sgibbs	} else if ((tstate->auto_negotiate & mask) != 0) {
103997883Sgibbs		scb->flags |= SCB_AUTO_NEGOTIATE;
104097883Sgibbs		scb->hscb->control |= MK_MESSAGE;
104197883Sgibbs	}
104297883Sgibbs
104397883Sgibbs	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
104497883Sgibbs
104597883Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
104697883Sgibbs
1047133911Sgibbs	aic_scb_timer_start(scb);
104897883Sgibbs
104997883Sgibbs	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
105097883Sgibbs		/* Define a mapping from our tag to the SCB. */
105197883Sgibbs		ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
105297883Sgibbs		ahd_pause(ahd);
105397883Sgibbs		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
105497883Sgibbs		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
105597883Sgibbs		ahd_unpause(ahd);
105697883Sgibbs	} else {
105797883Sgibbs		ahd_queue_scb(ahd, scb);
105897883Sgibbs	}
105997883Sgibbs
106097883Sgibbs}
106197883Sgibbs
106297883Sgibbsstatic void
106397883Sgibbsahd_poll(struct cam_sim *sim)
106497883Sgibbs{
106597883Sgibbs	ahd_intr(cam_sim_softc(sim));
106697883Sgibbs}
106797883Sgibbs
106897883Sgibbsstatic void
106997883Sgibbsahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim,
107097883Sgibbs	       struct ccb_scsiio *csio, struct scb *scb)
107197883Sgibbs{
107297883Sgibbs	struct hardware_scb *hscb;
107397883Sgibbs	struct ccb_hdr *ccb_h;
107497883Sgibbs
107597883Sgibbs	hscb = scb->hscb;
107697883Sgibbs	ccb_h = &csio->ccb_h;
107797883Sgibbs
107897883Sgibbs	csio->resid = 0;
107997883Sgibbs	csio->sense_resid = 0;
108097883Sgibbs	if (ccb_h->func_code == XPT_SCSI_IO) {
108197883Sgibbs		hscb->cdb_len = csio->cdb_len;
108297883Sgibbs		if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
108397883Sgibbs
108497883Sgibbs			if (hscb->cdb_len > MAX_CDB_LEN
108597883Sgibbs			 && (ccb_h->flags & CAM_CDB_PHYS) == 0) {
108697883Sgibbs
1087111653Sgibbs				/*
1088111653Sgibbs				 * Should CAM start to support CDB sizes
1089111653Sgibbs				 * greater than 16 bytes, we could use
1090111653Sgibbs				 * the sense buffer to store the CDB.
1091111653Sgibbs				 */
1092123579Sgibbs				aic_set_transaction_status(scb,
109397883Sgibbs							   CAM_REQ_INVALID);
109497883Sgibbs				ahd_free_scb(ahd, scb);
109597883Sgibbs				xpt_done((union ccb *)csio);
109697883Sgibbs				return;
109797883Sgibbs			}
109897883Sgibbs			if ((ccb_h->flags & CAM_CDB_PHYS) != 0) {
1099111653Sgibbs				hscb->shared_data.idata.cdb_from_host.cdbptr =
1100123579Sgibbs				   aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr);
1101111653Sgibbs				hscb->shared_data.idata.cdb_from_host.cdblen =
1102111653Sgibbs				   csio->cdb_len;
1103111653Sgibbs				hscb->cdb_len |= SCB_CDB_LEN_PTR;
110497883Sgibbs			} else {
110597883Sgibbs				memcpy(hscb->shared_data.idata.cdb,
110697883Sgibbs				       csio->cdb_io.cdb_ptr,
110797883Sgibbs				       hscb->cdb_len);
110897883Sgibbs			}
110997883Sgibbs		} else {
111097883Sgibbs			if (hscb->cdb_len > MAX_CDB_LEN) {
111197883Sgibbs
1112123579Sgibbs				aic_set_transaction_status(scb,
111397883Sgibbs							   CAM_REQ_INVALID);
111497883Sgibbs				ahd_free_scb(ahd, scb);
111597883Sgibbs				xpt_done((union ccb *)csio);
111697883Sgibbs				return;
111797883Sgibbs			}
111897883Sgibbs			memcpy(hscb->shared_data.idata.cdb,
111997883Sgibbs			       csio->cdb_io.cdb_bytes, hscb->cdb_len);
112097883Sgibbs		}
112197883Sgibbs	}
112297883Sgibbs
112397883Sgibbs	/* Only use S/G if there is a transfer */
112497883Sgibbs	if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
112597883Sgibbs		if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
112697883Sgibbs			/* We've been given a pointer to a single buffer */
112797883Sgibbs			if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
112897883Sgibbs				int s;
112997883Sgibbs				int error;
113097883Sgibbs
113197883Sgibbs				s = splsoftvm();
113297883Sgibbs				error = bus_dmamap_load(ahd->buffer_dmat,
113397883Sgibbs							scb->dmamap,
113497883Sgibbs							csio->data_ptr,
113597883Sgibbs							csio->dxfer_len,
113697883Sgibbs							ahd_execute_scb,
113797883Sgibbs							scb, /*flags*/0);
113897883Sgibbs				if (error == EINPROGRESS) {
113997883Sgibbs					/*
114097883Sgibbs					 * So as to maintain ordering,
114197883Sgibbs					 * freeze the controller queue
114297883Sgibbs					 * until our mapping is
114397883Sgibbs					 * returned.
114497883Sgibbs					 */
114597883Sgibbs					xpt_freeze_simq(sim,
114697883Sgibbs							/*count*/1);
114797883Sgibbs					scb->io_ctx->ccb_h.status |=
114897883Sgibbs					    CAM_RELEASE_SIMQ;
114997883Sgibbs				}
115097883Sgibbs				splx(s);
115197883Sgibbs			} else {
115297883Sgibbs				struct bus_dma_segment seg;
115397883Sgibbs
115497883Sgibbs				/* Pointer to physical buffer */
115597883Sgibbs				if (csio->dxfer_len > AHD_MAXTRANSFER_SIZE)
115697883Sgibbs					panic("ahd_setup_data - Transfer size "
115797883Sgibbs					      "larger than can device max");
115897883Sgibbs
1159113296Sjake				seg.ds_addr =
1160113296Sjake				    (bus_addr_t)(vm_offset_t)csio->data_ptr;
116197883Sgibbs				seg.ds_len = csio->dxfer_len;
116297883Sgibbs				ahd_execute_scb(scb, &seg, 1, 0);
116397883Sgibbs			}
116497883Sgibbs		} else {
116597883Sgibbs			struct bus_dma_segment *segs;
116697883Sgibbs
116797883Sgibbs			if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
116897883Sgibbs				panic("ahd_setup_data - Physical segment "
116997883Sgibbs				      "pointers unsupported");
117097883Sgibbs
117197883Sgibbs			if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
117297883Sgibbs				panic("ahd_setup_data - Virtual segment "
117397883Sgibbs				      "addresses unsupported");
117497883Sgibbs
117597883Sgibbs			/* Just use the segments provided */
117697883Sgibbs			segs = (struct bus_dma_segment *)csio->data_ptr;
117797883Sgibbs			ahd_execute_scb(scb, segs, csio->sglist_cnt, 0);
117897883Sgibbs		}
117997883Sgibbs	} else {
118097883Sgibbs		ahd_execute_scb(scb, NULL, 0, 0);
118197883Sgibbs	}
118297883Sgibbs}
118397883Sgibbs
118497883Sgibbsstatic void
118597883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
118697883Sgibbs{
118797883Sgibbs	union ccb *abort_ccb;
118897883Sgibbs
118997883Sgibbs	abort_ccb = ccb->cab.abort_ccb;
119097883Sgibbs	switch (abort_ccb->ccb_h.func_code) {
119197883Sgibbs#ifdef AHD_TARGET_MODE
119297883Sgibbs	case XPT_ACCEPT_TARGET_IO:
1193237601Sken	case XPT_IMMEDIATE_NOTIFY:
119497883Sgibbs	case XPT_CONT_TARGET_IO:
119597883Sgibbs	{
119697883Sgibbs		struct ahd_tmode_tstate *tstate;
119797883Sgibbs		struct ahd_tmode_lstate *lstate;
119897883Sgibbs		struct ccb_hdr_slist *list;
119997883Sgibbs		cam_status status;
120097883Sgibbs
120197883Sgibbs		status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate,
120297883Sgibbs					     &lstate, TRUE);
120397883Sgibbs
120497883Sgibbs		if (status != CAM_REQ_CMP) {
120597883Sgibbs			ccb->ccb_h.status = status;
120697883Sgibbs			break;
120797883Sgibbs		}
120897883Sgibbs
120997883Sgibbs		if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
121097883Sgibbs			list = &lstate->accept_tios;
1211237601Sken		else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
121297883Sgibbs			list = &lstate->immed_notifies;
121397883Sgibbs		else
121497883Sgibbs			list = NULL;
121597883Sgibbs
121697883Sgibbs		if (list != NULL) {
121797883Sgibbs			struct ccb_hdr *curelm;
121897883Sgibbs			int found;
121997883Sgibbs
122097883Sgibbs			curelm = SLIST_FIRST(list);
122197883Sgibbs			found = 0;
122297883Sgibbs			if (curelm == &abort_ccb->ccb_h) {
122397883Sgibbs				found = 1;
122497883Sgibbs				SLIST_REMOVE_HEAD(list, sim_links.sle);
122597883Sgibbs			} else {
122697883Sgibbs				while(curelm != NULL) {
122797883Sgibbs					struct ccb_hdr *nextelm;
122897883Sgibbs
122997883Sgibbs					nextelm =
123097883Sgibbs					    SLIST_NEXT(curelm, sim_links.sle);
123197883Sgibbs
123297883Sgibbs					if (nextelm == &abort_ccb->ccb_h) {
123397883Sgibbs						found = 1;
123497883Sgibbs						SLIST_NEXT(curelm,
123597883Sgibbs							   sim_links.sle) =
123697883Sgibbs						    SLIST_NEXT(nextelm,
123797883Sgibbs							       sim_links.sle);
123897883Sgibbs						break;
123997883Sgibbs					}
124097883Sgibbs					curelm = nextelm;
124197883Sgibbs				}
124297883Sgibbs			}
124397883Sgibbs
124497883Sgibbs			if (found) {
124597883Sgibbs				abort_ccb->ccb_h.status = CAM_REQ_ABORTED;
124697883Sgibbs				xpt_done(abort_ccb);
124797883Sgibbs				ccb->ccb_h.status = CAM_REQ_CMP;
124897883Sgibbs			} else {
124997883Sgibbs				xpt_print_path(abort_ccb->ccb_h.path);
125097883Sgibbs				printf("Not found\n");
125197883Sgibbs				ccb->ccb_h.status = CAM_PATH_INVALID;
125297883Sgibbs			}
125397883Sgibbs			break;
125497883Sgibbs		}
125597883Sgibbs		/* FALLTHROUGH */
125697883Sgibbs	}
125797883Sgibbs#endif
125897883Sgibbs	case XPT_SCSI_IO:
125997883Sgibbs		/* XXX Fully implement the hard ones */
126097883Sgibbs		ccb->ccb_h.status = CAM_UA_ABORT;
126197883Sgibbs		break;
126297883Sgibbs	default:
126397883Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
126497883Sgibbs		break;
126597883Sgibbs	}
126697883Sgibbs	xpt_done(ccb);
126797883Sgibbs}
126897883Sgibbs
126997883Sgibbsvoid
127097883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target,
127197883Sgibbs		u_int lun, ac_code code, void *opt_arg)
127297883Sgibbs{
127397883Sgibbs	struct	ccb_trans_settings cts;
127497883Sgibbs	struct cam_path *path;
127597883Sgibbs	void *arg;
127697883Sgibbs	int error;
127797883Sgibbs
127897883Sgibbs	arg = NULL;
127997883Sgibbs	error = ahd_create_path(ahd, channel, target, lun, &path);
128097883Sgibbs
128197883Sgibbs	if (error != CAM_REQ_CMP)
128297883Sgibbs		return;
128397883Sgibbs
128497883Sgibbs	switch (code) {
128597883Sgibbs	case AC_TRANSFER_NEG:
128697883Sgibbs	{
128797883Sgibbs		struct	ccb_trans_settings_scsi *scsi;
128897883Sgibbs
128997883Sgibbs		cts.type = CTS_TYPE_CURRENT_SETTINGS;
129097883Sgibbs		scsi = &cts.proto_specific.scsi;
129197883Sgibbs		cts.ccb_h.path = path;
129297883Sgibbs		cts.ccb_h.target_id = target;
129397883Sgibbs		cts.ccb_h.target_lun = lun;
129497883Sgibbs		ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts);
129597883Sgibbs		arg = &cts;
129697883Sgibbs		scsi->valid &= ~CTS_SCSI_VALID_TQ;
129797883Sgibbs		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
129897883Sgibbs		if (opt_arg == NULL)
129997883Sgibbs			break;
130097883Sgibbs		if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED)
130197883Sgibbs			scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
130297883Sgibbs		scsi->valid |= CTS_SCSI_VALID_TQ;
130397883Sgibbs		break;
130497883Sgibbs	}
130597883Sgibbs	case AC_SENT_BDR:
130697883Sgibbs	case AC_BUS_RESET:
130797883Sgibbs		break;
130897883Sgibbs	default:
130997883Sgibbs		panic("ahd_send_async: Unexpected async event");
131097883Sgibbs	}
131197883Sgibbs	xpt_async(code, path, arg);
131297883Sgibbs	xpt_free_path(path);
131397883Sgibbs}
131497883Sgibbs
131597883Sgibbsvoid
131697883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd,
131797883Sgibbs		      struct ahd_devinfo *devinfo, int enable)
131897883Sgibbs{
131997883Sgibbs}
132097883Sgibbs
132197883Sgibbsint
132297883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
132397883Sgibbs{
132497883Sgibbs	ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF,
132597883Sgibbs	    M_NOWAIT | M_ZERO);
132697883Sgibbs	if (ahd->platform_data == NULL)
132797883Sgibbs		return (ENOMEM);
132897883Sgibbs	return (0);
132997883Sgibbs}
133097883Sgibbs
133197883Sgibbsvoid
133297883Sgibbsahd_platform_free(struct ahd_softc *ahd)
133397883Sgibbs{
133497883Sgibbs	struct ahd_platform_data *pdata;
133597883Sgibbs
133697883Sgibbs	pdata = ahd->platform_data;
133797883Sgibbs	if (pdata != NULL) {
133897883Sgibbs		if (pdata->regs[0] != NULL)
133997883Sgibbs			bus_release_resource(ahd->dev_softc,
134097883Sgibbs					     pdata->regs_res_type[0],
134197883Sgibbs					     pdata->regs_res_id[0],
134297883Sgibbs					     pdata->regs[0]);
134397883Sgibbs
134497883Sgibbs		if (pdata->regs[1] != NULL)
134597883Sgibbs			bus_release_resource(ahd->dev_softc,
134697883Sgibbs					     pdata->regs_res_type[1],
134797883Sgibbs					     pdata->regs_res_id[1],
134897883Sgibbs					     pdata->regs[1]);
134997883Sgibbs
135097883Sgibbs		if (pdata->irq != NULL)
135197883Sgibbs			bus_release_resource(ahd->dev_softc,
135297883Sgibbs					     pdata->irq_res_type,
135397883Sgibbs					     0, pdata->irq);
135497883Sgibbs
135597883Sgibbs		if (pdata->sim != NULL) {
135697883Sgibbs			xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
135797883Sgibbs			xpt_free_path(pdata->path);
135897883Sgibbs			xpt_bus_deregister(cam_sim_path(pdata->sim));
135997883Sgibbs			cam_sim_free(pdata->sim, /*free_devq*/TRUE);
136097883Sgibbs		}
136197883Sgibbs		if (pdata->eh != NULL)
136297883Sgibbs			EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
136397883Sgibbs		free(ahd->platform_data, M_DEVBUF);
136497883Sgibbs	}
136597883Sgibbs}
136697883Sgibbs
136797883Sgibbsint
136897883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
136997883Sgibbs{
137097883Sgibbs	/* We don't sort softcs under FreeBSD so report equal always */
137197883Sgibbs	return (0);
137297883Sgibbs}
137397883Sgibbs
137497883Sgibbsint
137597883Sgibbsahd_detach(device_t dev)
137697883Sgibbs{
137797883Sgibbs	struct ahd_softc *ahd;
137897883Sgibbs
137997883Sgibbs	device_printf(dev, "detaching device\n");
138097883Sgibbs	ahd = device_get_softc(dev);
1381168807Sscottl	ahd_lock(ahd);
1382123579Sgibbs	TAILQ_REMOVE(&ahd_tailq, ahd, links);
138397883Sgibbs	ahd_intr_enable(ahd, FALSE);
138497883Sgibbs	bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih);
1385168807Sscottl	ahd_unlock(ahd);
138697883Sgibbs	ahd_free(ahd);
138797883Sgibbs	return (0);
138897883Sgibbs}
138997883Sgibbs
1390153072Sru#if 0
139197883Sgibbsstatic void
139297883Sgibbsahd_dump_targcmd(struct target_cmd *cmd)
139397883Sgibbs{
139497883Sgibbs	uint8_t *byte;
139597883Sgibbs	uint8_t *last_byte;
139697883Sgibbs	int i;
139797883Sgibbs
139897883Sgibbs	byte = &cmd->initiator_channel;
139997883Sgibbs	/* Debugging info for received commands */
140097883Sgibbs	last_byte = &cmd[1].initiator_channel;
140197883Sgibbs
140297883Sgibbs	i = 0;
140397883Sgibbs	while (byte < last_byte) {
140497883Sgibbs		if (i == 0)
140597883Sgibbs			printf("\t");
140697883Sgibbs		printf("%#x", *byte++);
140797883Sgibbs		i++;
140897883Sgibbs		if (i == 8) {
140997883Sgibbs			printf("\n");
141097883Sgibbs			i = 0;
141197883Sgibbs		} else {
141297883Sgibbs			printf(", ");
141397883Sgibbs		}
141497883Sgibbs	}
141597883Sgibbs}
141697883Sgibbs#endif
141797883Sgibbs
141897883Sgibbsstatic int
141997883Sgibbsahd_modevent(module_t mod, int type, void *data)
142097883Sgibbs{
142197883Sgibbs	/* XXX Deal with busy status on unload. */
1422132199Sphk	/* XXX Deal with unknown events */
142397883Sgibbs	return 0;
142497883Sgibbs}
142597883Sgibbs
142697883Sgibbsstatic moduledata_t ahd_mod = {
142797883Sgibbs	"ahd",
142897883Sgibbs	ahd_modevent,
142997883Sgibbs	NULL
143097883Sgibbs};
143197883Sgibbs
143297883Sgibbs/********************************** DDB Hooks *********************************/
143397883Sgibbs#ifdef DDB
143497883Sgibbsstatic struct ahd_softc *ahd_ddb_softc;
143597883Sgibbsstatic int ahd_ddb_paused;
143697883Sgibbsstatic int ahd_ddb_paused_on_entry;
1437133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit)
143897883Sgibbs{
143997883Sgibbs	struct ahd_softc *list_ahd;
144097883Sgibbs
144197883Sgibbs	ahd_ddb_softc = NULL;
144297883Sgibbs	TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
144397883Sgibbs		if (list_ahd->unit == addr)
144497883Sgibbs			ahd_ddb_softc = list_ahd;
144597883Sgibbs	}
144697883Sgibbs	if (ahd_ddb_softc == NULL)
144797883Sgibbs		db_error("No matching softc found!\n");
144897883Sgibbs}
144997883Sgibbs
145097883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause)
145197883Sgibbs{
145297883Sgibbs	if (ahd_ddb_softc == NULL) {
1453133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
145497883Sgibbs		return;
145597883Sgibbs	}
145697883Sgibbs	if (ahd_ddb_paused == 0) {
145797883Sgibbs		ahd_ddb_paused++;
145897883Sgibbs		if (ahd_is_paused(ahd_ddb_softc)) {
145997883Sgibbs			ahd_ddb_paused_on_entry++;
146097883Sgibbs			return;
146197883Sgibbs		}
146297883Sgibbs		ahd_pause(ahd_ddb_softc);
146397883Sgibbs	}
146497883Sgibbs}
146597883Sgibbs
146697883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause)
146797883Sgibbs{
146897883Sgibbs	if (ahd_ddb_softc == NULL) {
1469133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
147097883Sgibbs		return;
147197883Sgibbs	}
147297883Sgibbs	if (ahd_ddb_paused != 0) {
147397883Sgibbs		ahd_ddb_paused = 0;
147497883Sgibbs		if (ahd_ddb_paused_on_entry)
147597883Sgibbs			return;
147697883Sgibbs		ahd_unpause(ahd_ddb_softc);
147797883Sgibbs	} else if (ahd_ddb_paused_on_entry != 0) {
147897883Sgibbs		/* Two unpauses to clear a paused on entry. */
147997883Sgibbs		ahd_ddb_paused_on_entry = 0;
148097883Sgibbs		ahd_unpause(ahd_ddb_softc);
148197883Sgibbs	}
148297883Sgibbs}
148397883Sgibbs
148497883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in)
148597883Sgibbs{
148697883Sgibbs	int c;
148797883Sgibbs	int size;
148897883Sgibbs
148997883Sgibbs	if (ahd_ddb_softc == NULL) {
1490133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
149197883Sgibbs		return;
149297883Sgibbs	}
149397883Sgibbs	if (have_addr == 0)
149497883Sgibbs		return;
149597883Sgibbs
149697883Sgibbs	size = 1;
149797883Sgibbs	while ((c = *modif++) != '\0') {
149897883Sgibbs		switch (c) {
149997883Sgibbs		case 'b':
150097883Sgibbs			size = 1;
150197883Sgibbs			break;
150297883Sgibbs		case 'w':
150397883Sgibbs			size = 2;
150497883Sgibbs			break;
150597883Sgibbs		case 'l':
150697883Sgibbs			size = 4;
150797883Sgibbs		break;
150897883Sgibbs		}
150997883Sgibbs	}
151097883Sgibbs
151197883Sgibbs	if (count <= 0)
151297883Sgibbs		count = 1;
151397883Sgibbs	while (--count >= 0) {
1514107368Sscottl		db_printf("%04lx (M)%x: \t", (u_long)addr,
151597883Sgibbs			  ahd_inb(ahd_ddb_softc, MODE_PTR));
151697883Sgibbs		switch (size) {
151797883Sgibbs		case 1:
151897883Sgibbs			db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr));
151997883Sgibbs			break;
152097883Sgibbs		case 2:
152197883Sgibbs			db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr));
152297883Sgibbs			break;
152397883Sgibbs		case 4:
152497883Sgibbs			db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr));
152597883Sgibbs			break;
152697883Sgibbs		}
152797883Sgibbs	}
152897883Sgibbs}
152997883Sgibbs
1530183054SsamDB_FUNC(ahd_out, ahd_ddb_out, db_cmd_table, CS_MORE, NULL)
153197883Sgibbs{
153297883Sgibbs	db_expr_t old_value;
153397883Sgibbs	db_expr_t new_value;
153497883Sgibbs	int	  size;
153597883Sgibbs
153697883Sgibbs	if (ahd_ddb_softc == NULL) {
1537133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
153897883Sgibbs		return;
153997883Sgibbs	}
154097883Sgibbs
154197883Sgibbs	switch (modif[0]) {
154297883Sgibbs	case '\0':
154397883Sgibbs	case 'b':
154497883Sgibbs		size = 1;
154597883Sgibbs		break;
154697883Sgibbs	case 'h':
154797883Sgibbs		size = 2;
154897883Sgibbs		break;
154997883Sgibbs	case 'l':
155097883Sgibbs		size = 4;
155197883Sgibbs		break;
155297883Sgibbs	default:
155397883Sgibbs		db_error("Unknown size\n");
155497883Sgibbs		return;
155597883Sgibbs	}
155697883Sgibbs
155797883Sgibbs	while (db_expression(&new_value)) {
155897883Sgibbs		switch (size) {
155997883Sgibbs		default:
156097883Sgibbs		case 1:
156197883Sgibbs			old_value = ahd_inb(ahd_ddb_softc, addr);
156297883Sgibbs			ahd_outb(ahd_ddb_softc, addr, new_value);
156397883Sgibbs			break;
156497883Sgibbs		case 2:
156597883Sgibbs			old_value = ahd_inw(ahd_ddb_softc, addr);
156697883Sgibbs			ahd_outw(ahd_ddb_softc, addr, new_value);
156797883Sgibbs			break;
156897883Sgibbs		case 4:
156997883Sgibbs			old_value = ahd_inl(ahd_ddb_softc, addr);
157097883Sgibbs			ahd_outl(ahd_ddb_softc, addr, new_value);
157197883Sgibbs			break;
157297883Sgibbs		}
1573107368Sscottl		db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx",
1574107368Sscottl			  (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR),
1575107368Sscottl			  (u_long)old_value, (u_long)new_value);
157697883Sgibbs		addr += size;
157797883Sgibbs	}
157897883Sgibbs	db_skip_to_eol();
157997883Sgibbs}
158097883Sgibbs
1581133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump)
1582133122Sgibbs{
1583133122Sgibbs	if (ahd_ddb_softc == NULL) {
1584133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
1585133122Sgibbs		return;
1586133122Sgibbs	}
1587133122Sgibbs	ahd_dump_card_state(ahd_ddb_softc);
1588133122Sgibbs}
1589133122Sgibbs
159097883Sgibbs#endif
159197883Sgibbs
159297883Sgibbs
159397883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
159497883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1);
159597883SgibbsMODULE_VERSION(ahd, 1);
1596