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: stable/11/sys/dev/aic7xxx/aic79xx_osm.c 315812 2017-03-23 06:40:20Z mav $");
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;
702315812Smav		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
703315812Smav		strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
704315812Smav		strlcpy(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;
1074246713Skib	int error;
107597883Sgibbs
107697883Sgibbs	hscb = scb->hscb;
107797883Sgibbs	ccb_h = &csio->ccb_h;
107897883Sgibbs
107997883Sgibbs	csio->resid = 0;
108097883Sgibbs	csio->sense_resid = 0;
108197883Sgibbs	if (ccb_h->func_code == XPT_SCSI_IO) {
108297883Sgibbs		hscb->cdb_len = csio->cdb_len;
108397883Sgibbs		if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
108497883Sgibbs
108597883Sgibbs			if (hscb->cdb_len > MAX_CDB_LEN
108697883Sgibbs			 && (ccb_h->flags & CAM_CDB_PHYS) == 0) {
108797883Sgibbs
1088111653Sgibbs				/*
1089111653Sgibbs				 * Should CAM start to support CDB sizes
1090111653Sgibbs				 * greater than 16 bytes, we could use
1091111653Sgibbs				 * the sense buffer to store the CDB.
1092111653Sgibbs				 */
1093123579Sgibbs				aic_set_transaction_status(scb,
109497883Sgibbs							   CAM_REQ_INVALID);
109597883Sgibbs				ahd_free_scb(ahd, scb);
109697883Sgibbs				xpt_done((union ccb *)csio);
109797883Sgibbs				return;
109897883Sgibbs			}
109997883Sgibbs			if ((ccb_h->flags & CAM_CDB_PHYS) != 0) {
1100111653Sgibbs				hscb->shared_data.idata.cdb_from_host.cdbptr =
1101123579Sgibbs				   aic_htole64((uintptr_t)csio->cdb_io.cdb_ptr);
1102111653Sgibbs				hscb->shared_data.idata.cdb_from_host.cdblen =
1103111653Sgibbs				   csio->cdb_len;
1104111653Sgibbs				hscb->cdb_len |= SCB_CDB_LEN_PTR;
110597883Sgibbs			} else {
110697883Sgibbs				memcpy(hscb->shared_data.idata.cdb,
110797883Sgibbs				       csio->cdb_io.cdb_ptr,
110897883Sgibbs				       hscb->cdb_len);
110997883Sgibbs			}
111097883Sgibbs		} else {
111197883Sgibbs			if (hscb->cdb_len > MAX_CDB_LEN) {
111297883Sgibbs
1113123579Sgibbs				aic_set_transaction_status(scb,
111497883Sgibbs							   CAM_REQ_INVALID);
111597883Sgibbs				ahd_free_scb(ahd, scb);
111697883Sgibbs				xpt_done((union ccb *)csio);
111797883Sgibbs				return;
111897883Sgibbs			}
111997883Sgibbs			memcpy(hscb->shared_data.idata.cdb,
112097883Sgibbs			       csio->cdb_io.cdb_bytes, hscb->cdb_len);
112197883Sgibbs		}
112297883Sgibbs	}
112397883Sgibbs
1124246713Skib	error = bus_dmamap_load_ccb(ahd->buffer_dmat,
1125246713Skib				    scb->dmamap,
1126246713Skib				    (union ccb *)csio,
1127246713Skib				    ahd_execute_scb,
1128246713Skib				    scb, /*flags*/0);
1129246713Skib	if (error == EINPROGRESS) {
1130246713Skib		/*
1131246713Skib		 * So as to maintain ordering, freeze the controller queue
1132246713Skib		 * until our mapping is returned.
1133246713Skib		 */
1134246713Skib		xpt_freeze_simq(sim, /*count*/1);
1135246713Skib		scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ;
113697883Sgibbs	}
113797883Sgibbs}
113897883Sgibbs
113997883Sgibbsstatic void
114097883Sgibbsahd_abort_ccb(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
114197883Sgibbs{
114297883Sgibbs	union ccb *abort_ccb;
114397883Sgibbs
114497883Sgibbs	abort_ccb = ccb->cab.abort_ccb;
114597883Sgibbs	switch (abort_ccb->ccb_h.func_code) {
114697883Sgibbs#ifdef AHD_TARGET_MODE
114797883Sgibbs	case XPT_ACCEPT_TARGET_IO:
1148237601Sken	case XPT_IMMEDIATE_NOTIFY:
114997883Sgibbs	case XPT_CONT_TARGET_IO:
115097883Sgibbs	{
115197883Sgibbs		struct ahd_tmode_tstate *tstate;
115297883Sgibbs		struct ahd_tmode_lstate *lstate;
115397883Sgibbs		struct ccb_hdr_slist *list;
115497883Sgibbs		cam_status status;
115597883Sgibbs
115697883Sgibbs		status = ahd_find_tmode_devs(ahd, sim, abort_ccb, &tstate,
115797883Sgibbs					     &lstate, TRUE);
115897883Sgibbs
115997883Sgibbs		if (status != CAM_REQ_CMP) {
116097883Sgibbs			ccb->ccb_h.status = status;
116197883Sgibbs			break;
116297883Sgibbs		}
116397883Sgibbs
116497883Sgibbs		if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
116597883Sgibbs			list = &lstate->accept_tios;
1166237601Sken		else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
116797883Sgibbs			list = &lstate->immed_notifies;
116897883Sgibbs		else
116997883Sgibbs			list = NULL;
117097883Sgibbs
117197883Sgibbs		if (list != NULL) {
117297883Sgibbs			struct ccb_hdr *curelm;
117397883Sgibbs			int found;
117497883Sgibbs
117597883Sgibbs			curelm = SLIST_FIRST(list);
117697883Sgibbs			found = 0;
117797883Sgibbs			if (curelm == &abort_ccb->ccb_h) {
117897883Sgibbs				found = 1;
117997883Sgibbs				SLIST_REMOVE_HEAD(list, sim_links.sle);
118097883Sgibbs			} else {
118197883Sgibbs				while(curelm != NULL) {
118297883Sgibbs					struct ccb_hdr *nextelm;
118397883Sgibbs
118497883Sgibbs					nextelm =
118597883Sgibbs					    SLIST_NEXT(curelm, sim_links.sle);
118697883Sgibbs
118797883Sgibbs					if (nextelm == &abort_ccb->ccb_h) {
118897883Sgibbs						found = 1;
118997883Sgibbs						SLIST_NEXT(curelm,
119097883Sgibbs							   sim_links.sle) =
119197883Sgibbs						    SLIST_NEXT(nextelm,
119297883Sgibbs							       sim_links.sle);
119397883Sgibbs						break;
119497883Sgibbs					}
119597883Sgibbs					curelm = nextelm;
119697883Sgibbs				}
119797883Sgibbs			}
119897883Sgibbs
119997883Sgibbs			if (found) {
120097883Sgibbs				abort_ccb->ccb_h.status = CAM_REQ_ABORTED;
120197883Sgibbs				xpt_done(abort_ccb);
120297883Sgibbs				ccb->ccb_h.status = CAM_REQ_CMP;
120397883Sgibbs			} else {
120497883Sgibbs				xpt_print_path(abort_ccb->ccb_h.path);
120597883Sgibbs				printf("Not found\n");
120697883Sgibbs				ccb->ccb_h.status = CAM_PATH_INVALID;
120797883Sgibbs			}
120897883Sgibbs			break;
120997883Sgibbs		}
121097883Sgibbs		/* FALLTHROUGH */
121197883Sgibbs	}
121297883Sgibbs#endif
121397883Sgibbs	case XPT_SCSI_IO:
121497883Sgibbs		/* XXX Fully implement the hard ones */
121597883Sgibbs		ccb->ccb_h.status = CAM_UA_ABORT;
121697883Sgibbs		break;
121797883Sgibbs	default:
121897883Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
121997883Sgibbs		break;
122097883Sgibbs	}
122197883Sgibbs	xpt_done(ccb);
122297883Sgibbs}
122397883Sgibbs
122497883Sgibbsvoid
122597883Sgibbsahd_send_async(struct ahd_softc *ahd, char channel, u_int target,
122697883Sgibbs		u_int lun, ac_code code, void *opt_arg)
122797883Sgibbs{
122897883Sgibbs	struct	ccb_trans_settings cts;
122997883Sgibbs	struct cam_path *path;
123097883Sgibbs	void *arg;
123197883Sgibbs	int error;
123297883Sgibbs
123397883Sgibbs	arg = NULL;
123497883Sgibbs	error = ahd_create_path(ahd, channel, target, lun, &path);
123597883Sgibbs
123697883Sgibbs	if (error != CAM_REQ_CMP)
123797883Sgibbs		return;
123897883Sgibbs
123997883Sgibbs	switch (code) {
124097883Sgibbs	case AC_TRANSFER_NEG:
124197883Sgibbs	{
124297883Sgibbs		struct	ccb_trans_settings_scsi *scsi;
124397883Sgibbs
124497883Sgibbs		cts.type = CTS_TYPE_CURRENT_SETTINGS;
124597883Sgibbs		scsi = &cts.proto_specific.scsi;
124697883Sgibbs		cts.ccb_h.path = path;
124797883Sgibbs		cts.ccb_h.target_id = target;
124897883Sgibbs		cts.ccb_h.target_lun = lun;
124997883Sgibbs		ahd_get_tran_settings(ahd, ahd->our_id, channel, &cts);
125097883Sgibbs		arg = &cts;
125197883Sgibbs		scsi->valid &= ~CTS_SCSI_VALID_TQ;
125297883Sgibbs		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
125397883Sgibbs		if (opt_arg == NULL)
125497883Sgibbs			break;
125597883Sgibbs		if (*((ahd_queue_alg *)opt_arg) == AHD_QUEUE_TAGGED)
125697883Sgibbs			scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
125797883Sgibbs		scsi->valid |= CTS_SCSI_VALID_TQ;
125897883Sgibbs		break;
125997883Sgibbs	}
126097883Sgibbs	case AC_SENT_BDR:
126197883Sgibbs	case AC_BUS_RESET:
126297883Sgibbs		break;
126397883Sgibbs	default:
126497883Sgibbs		panic("ahd_send_async: Unexpected async event");
126597883Sgibbs	}
126697883Sgibbs	xpt_async(code, path, arg);
126797883Sgibbs	xpt_free_path(path);
126897883Sgibbs}
126997883Sgibbs
127097883Sgibbsvoid
127197883Sgibbsahd_platform_set_tags(struct ahd_softc *ahd,
127297883Sgibbs		      struct ahd_devinfo *devinfo, int enable)
127397883Sgibbs{
127497883Sgibbs}
127597883Sgibbs
127697883Sgibbsint
127797883Sgibbsahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
127897883Sgibbs{
127997883Sgibbs	ahd->platform_data = malloc(sizeof(struct ahd_platform_data), M_DEVBUF,
128097883Sgibbs	    M_NOWAIT | M_ZERO);
128197883Sgibbs	if (ahd->platform_data == NULL)
128297883Sgibbs		return (ENOMEM);
128397883Sgibbs	return (0);
128497883Sgibbs}
128597883Sgibbs
128697883Sgibbsvoid
128797883Sgibbsahd_platform_free(struct ahd_softc *ahd)
128897883Sgibbs{
128997883Sgibbs	struct ahd_platform_data *pdata;
129097883Sgibbs
129197883Sgibbs	pdata = ahd->platform_data;
129297883Sgibbs	if (pdata != NULL) {
129397883Sgibbs		if (pdata->regs[0] != NULL)
129497883Sgibbs			bus_release_resource(ahd->dev_softc,
129597883Sgibbs					     pdata->regs_res_type[0],
129697883Sgibbs					     pdata->regs_res_id[0],
129797883Sgibbs					     pdata->regs[0]);
129897883Sgibbs
129997883Sgibbs		if (pdata->regs[1] != NULL)
130097883Sgibbs			bus_release_resource(ahd->dev_softc,
130197883Sgibbs					     pdata->regs_res_type[1],
130297883Sgibbs					     pdata->regs_res_id[1],
130397883Sgibbs					     pdata->regs[1]);
130497883Sgibbs
130597883Sgibbs		if (pdata->irq != NULL)
130697883Sgibbs			bus_release_resource(ahd->dev_softc,
130797883Sgibbs					     pdata->irq_res_type,
130897883Sgibbs					     0, pdata->irq);
130997883Sgibbs
131097883Sgibbs		if (pdata->sim != NULL) {
131197883Sgibbs			xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
131297883Sgibbs			xpt_free_path(pdata->path);
131397883Sgibbs			xpt_bus_deregister(cam_sim_path(pdata->sim));
131497883Sgibbs			cam_sim_free(pdata->sim, /*free_devq*/TRUE);
131597883Sgibbs		}
131697883Sgibbs		if (pdata->eh != NULL)
131797883Sgibbs			EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
131897883Sgibbs		free(ahd->platform_data, M_DEVBUF);
131997883Sgibbs	}
132097883Sgibbs}
132197883Sgibbs
132297883Sgibbsint
132397883Sgibbsahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
132497883Sgibbs{
132597883Sgibbs	/* We don't sort softcs under FreeBSD so report equal always */
132697883Sgibbs	return (0);
132797883Sgibbs}
132897883Sgibbs
132997883Sgibbsint
133097883Sgibbsahd_detach(device_t dev)
133197883Sgibbs{
133297883Sgibbs	struct ahd_softc *ahd;
133397883Sgibbs
133497883Sgibbs	device_printf(dev, "detaching device\n");
133597883Sgibbs	ahd = device_get_softc(dev);
1336168807Sscottl	ahd_lock(ahd);
1337123579Sgibbs	TAILQ_REMOVE(&ahd_tailq, ahd, links);
133897883Sgibbs	ahd_intr_enable(ahd, FALSE);
133997883Sgibbs	bus_teardown_intr(dev, ahd->platform_data->irq, ahd->platform_data->ih);
1340168807Sscottl	ahd_unlock(ahd);
134197883Sgibbs	ahd_free(ahd);
134297883Sgibbs	return (0);
134397883Sgibbs}
134497883Sgibbs
1345153072Sru#if 0
134697883Sgibbsstatic void
134797883Sgibbsahd_dump_targcmd(struct target_cmd *cmd)
134897883Sgibbs{
134997883Sgibbs	uint8_t *byte;
135097883Sgibbs	uint8_t *last_byte;
135197883Sgibbs	int i;
135297883Sgibbs
135397883Sgibbs	byte = &cmd->initiator_channel;
135497883Sgibbs	/* Debugging info for received commands */
135597883Sgibbs	last_byte = &cmd[1].initiator_channel;
135697883Sgibbs
135797883Sgibbs	i = 0;
135897883Sgibbs	while (byte < last_byte) {
135997883Sgibbs		if (i == 0)
136097883Sgibbs			printf("\t");
136197883Sgibbs		printf("%#x", *byte++);
136297883Sgibbs		i++;
136397883Sgibbs		if (i == 8) {
136497883Sgibbs			printf("\n");
136597883Sgibbs			i = 0;
136697883Sgibbs		} else {
136797883Sgibbs			printf(", ");
136897883Sgibbs		}
136997883Sgibbs	}
137097883Sgibbs}
137197883Sgibbs#endif
137297883Sgibbs
137397883Sgibbsstatic int
137497883Sgibbsahd_modevent(module_t mod, int type, void *data)
137597883Sgibbs{
137697883Sgibbs	/* XXX Deal with busy status on unload. */
1377132199Sphk	/* XXX Deal with unknown events */
137897883Sgibbs	return 0;
137997883Sgibbs}
138097883Sgibbs
138197883Sgibbsstatic moduledata_t ahd_mod = {
138297883Sgibbs	"ahd",
138397883Sgibbs	ahd_modevent,
138497883Sgibbs	NULL
138597883Sgibbs};
138697883Sgibbs
138797883Sgibbs/********************************** DDB Hooks *********************************/
138897883Sgibbs#ifdef DDB
138997883Sgibbsstatic struct ahd_softc *ahd_ddb_softc;
139097883Sgibbsstatic int ahd_ddb_paused;
139197883Sgibbsstatic int ahd_ddb_paused_on_entry;
1392133122SgibbsDB_COMMAND(ahd_sunit, ahd_ddb_sunit)
139397883Sgibbs{
139497883Sgibbs	struct ahd_softc *list_ahd;
139597883Sgibbs
139697883Sgibbs	ahd_ddb_softc = NULL;
139797883Sgibbs	TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
139897883Sgibbs		if (list_ahd->unit == addr)
139997883Sgibbs			ahd_ddb_softc = list_ahd;
140097883Sgibbs	}
140197883Sgibbs	if (ahd_ddb_softc == NULL)
140297883Sgibbs		db_error("No matching softc found!\n");
140397883Sgibbs}
140497883Sgibbs
140597883SgibbsDB_COMMAND(ahd_pause, ahd_ddb_pause)
140697883Sgibbs{
140797883Sgibbs	if (ahd_ddb_softc == NULL) {
1408133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
140997883Sgibbs		return;
141097883Sgibbs	}
141197883Sgibbs	if (ahd_ddb_paused == 0) {
141297883Sgibbs		ahd_ddb_paused++;
141397883Sgibbs		if (ahd_is_paused(ahd_ddb_softc)) {
141497883Sgibbs			ahd_ddb_paused_on_entry++;
141597883Sgibbs			return;
141697883Sgibbs		}
141797883Sgibbs		ahd_pause(ahd_ddb_softc);
141897883Sgibbs	}
141997883Sgibbs}
142097883Sgibbs
142197883SgibbsDB_COMMAND(ahd_unpause, ahd_ddb_unpause)
142297883Sgibbs{
142397883Sgibbs	if (ahd_ddb_softc == NULL) {
1424133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
142597883Sgibbs		return;
142697883Sgibbs	}
142797883Sgibbs	if (ahd_ddb_paused != 0) {
142897883Sgibbs		ahd_ddb_paused = 0;
142997883Sgibbs		if (ahd_ddb_paused_on_entry)
143097883Sgibbs			return;
143197883Sgibbs		ahd_unpause(ahd_ddb_softc);
143297883Sgibbs	} else if (ahd_ddb_paused_on_entry != 0) {
143397883Sgibbs		/* Two unpauses to clear a paused on entry. */
143497883Sgibbs		ahd_ddb_paused_on_entry = 0;
143597883Sgibbs		ahd_unpause(ahd_ddb_softc);
143697883Sgibbs	}
143797883Sgibbs}
143897883Sgibbs
143997883SgibbsDB_COMMAND(ahd_in, ahd_ddb_in)
144097883Sgibbs{
144197883Sgibbs	int c;
144297883Sgibbs	int size;
144397883Sgibbs
144497883Sgibbs	if (ahd_ddb_softc == NULL) {
1445133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
144697883Sgibbs		return;
144797883Sgibbs	}
144897883Sgibbs	if (have_addr == 0)
144997883Sgibbs		return;
145097883Sgibbs
145197883Sgibbs	size = 1;
145297883Sgibbs	while ((c = *modif++) != '\0') {
145397883Sgibbs		switch (c) {
145497883Sgibbs		case 'b':
145597883Sgibbs			size = 1;
145697883Sgibbs			break;
145797883Sgibbs		case 'w':
145897883Sgibbs			size = 2;
145997883Sgibbs			break;
146097883Sgibbs		case 'l':
146197883Sgibbs			size = 4;
146297883Sgibbs		break;
146397883Sgibbs		}
146497883Sgibbs	}
146597883Sgibbs
146697883Sgibbs	if (count <= 0)
146797883Sgibbs		count = 1;
146897883Sgibbs	while (--count >= 0) {
1469107368Sscottl		db_printf("%04lx (M)%x: \t", (u_long)addr,
147097883Sgibbs			  ahd_inb(ahd_ddb_softc, MODE_PTR));
147197883Sgibbs		switch (size) {
147297883Sgibbs		case 1:
147397883Sgibbs			db_printf("%02x\n", ahd_inb(ahd_ddb_softc, addr));
147497883Sgibbs			break;
147597883Sgibbs		case 2:
147697883Sgibbs			db_printf("%04x\n", ahd_inw(ahd_ddb_softc, addr));
147797883Sgibbs			break;
147897883Sgibbs		case 4:
147997883Sgibbs			db_printf("%08x\n", ahd_inl(ahd_ddb_softc, addr));
148097883Sgibbs			break;
148197883Sgibbs		}
148297883Sgibbs	}
148397883Sgibbs}
148497883Sgibbs
1485183054SsamDB_FUNC(ahd_out, ahd_ddb_out, db_cmd_table, CS_MORE, NULL)
148697883Sgibbs{
148797883Sgibbs	db_expr_t old_value;
148897883Sgibbs	db_expr_t new_value;
148997883Sgibbs	int	  size;
149097883Sgibbs
149197883Sgibbs	if (ahd_ddb_softc == NULL) {
1492133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
149397883Sgibbs		return;
149497883Sgibbs	}
149597883Sgibbs
149697883Sgibbs	switch (modif[0]) {
149797883Sgibbs	case '\0':
149897883Sgibbs	case 'b':
149997883Sgibbs		size = 1;
150097883Sgibbs		break;
150197883Sgibbs	case 'h':
150297883Sgibbs		size = 2;
150397883Sgibbs		break;
150497883Sgibbs	case 'l':
150597883Sgibbs		size = 4;
150697883Sgibbs		break;
150797883Sgibbs	default:
150897883Sgibbs		db_error("Unknown size\n");
150997883Sgibbs		return;
151097883Sgibbs	}
151197883Sgibbs
151297883Sgibbs	while (db_expression(&new_value)) {
151397883Sgibbs		switch (size) {
151497883Sgibbs		default:
151597883Sgibbs		case 1:
151697883Sgibbs			old_value = ahd_inb(ahd_ddb_softc, addr);
151797883Sgibbs			ahd_outb(ahd_ddb_softc, addr, new_value);
151897883Sgibbs			break;
151997883Sgibbs		case 2:
152097883Sgibbs			old_value = ahd_inw(ahd_ddb_softc, addr);
152197883Sgibbs			ahd_outw(ahd_ddb_softc, addr, new_value);
152297883Sgibbs			break;
152397883Sgibbs		case 4:
152497883Sgibbs			old_value = ahd_inl(ahd_ddb_softc, addr);
152597883Sgibbs			ahd_outl(ahd_ddb_softc, addr, new_value);
152697883Sgibbs			break;
152797883Sgibbs		}
1528107368Sscottl		db_printf("%04lx (M)%x: \t0x%lx\t=\t0x%lx",
1529107368Sscottl			  (u_long)addr, ahd_inb(ahd_ddb_softc, MODE_PTR),
1530107368Sscottl			  (u_long)old_value, (u_long)new_value);
153197883Sgibbs		addr += size;
153297883Sgibbs	}
153397883Sgibbs	db_skip_to_eol();
153497883Sgibbs}
153597883Sgibbs
1536133122SgibbsDB_COMMAND(ahd_dump, ahd_ddb_dump)
1537133122Sgibbs{
1538133122Sgibbs	if (ahd_ddb_softc == NULL) {
1539133122Sgibbs		db_error("Must set unit with ahd_sunit first!\n");
1540133122Sgibbs		return;
1541133122Sgibbs	}
1542133122Sgibbs	ahd_dump_card_state(ahd_ddb_softc);
1543133122Sgibbs}
1544133122Sgibbs
154597883Sgibbs#endif
154697883Sgibbs
154797883Sgibbs
154897883SgibbsDECLARE_MODULE(ahd, ahd_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
154997883SgibbsMODULE_DEPEND(ahd, cam, 1, 1, 1);
155097883SgibbsMODULE_VERSION(ahd, 1);
1551