xref: /freebsd/sys/dev/aic7xxx/aic7xxx_osm.c (revision 65971073d935e8314bff8bca26d1445e9e336fce)
1098ca2bdSWarner Losh /*-
2b3b25f2cSJustin T. Gibbs  * Bus independent FreeBSD shim for the aic7xxx based Adaptec SCSI controllers
3717d4247SJustin T. Gibbs  *
464a3876fSJustin T. Gibbs  * Copyright (c) 1994-2001 Justin T. Gibbs.
5717d4247SJustin T. Gibbs  * All rights reserved.
6717d4247SJustin T. Gibbs  *
7717d4247SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
8717d4247SJustin T. Gibbs  * modification, are permitted provided that the following conditions
9717d4247SJustin T. Gibbs  * are met:
10717d4247SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
11717d4247SJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
12717d4247SJustin T. Gibbs  *    without modification.
13717d4247SJustin T. Gibbs  * 2. The name of the author may not be used to endorse or promote products
14717d4247SJustin T. Gibbs  *    derived from this software without specific prior written permission.
15717d4247SJustin T. Gibbs  *
16717d4247SJustin T. Gibbs  * Alternatively, this software may be distributed under the terms of the
17717d4247SJustin T. Gibbs  * GNU Public License ("GPL").
18717d4247SJustin T. Gibbs  *
19717d4247SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20717d4247SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21717d4247SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22717d4247SJustin T. Gibbs  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23717d4247SJustin T. Gibbs  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24717d4247SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25717d4247SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26717d4247SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27717d4247SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28717d4247SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29717d4247SJustin T. Gibbs  * SUCH DAMAGE.
30717d4247SJustin T. Gibbs  *
31b3b25f2cSJustin T. Gibbs  * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#20 $
32717d4247SJustin T. Gibbs  */
33717d4247SJustin T. Gibbs 
348f214efcSJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_osm.h>
35717d4247SJustin T. Gibbs #include <dev/aic7xxx/aic7xxx_inline.h>
36717d4247SJustin T. Gibbs 
37b3b25f2cSJustin T. Gibbs #include <sys/kthread.h>
38b3b25f2cSJustin T. Gibbs 
39717d4247SJustin T. Gibbs #ifndef AHC_TMODE_ENABLE
40717d4247SJustin T. Gibbs #define AHC_TMODE_ENABLE 0
41717d4247SJustin T. Gibbs #endif
42717d4247SJustin T. Gibbs 
43b3b25f2cSJustin T. Gibbs #include <dev/aic7xxx/aic_osm_lib.c>
44b3b25f2cSJustin T. Gibbs 
45717d4247SJustin T. Gibbs #define ccb_scb_ptr spriv_ptr0
46717d4247SJustin T. Gibbs 
47f4e98881SRuslan Ermilov #if 0
48717d4247SJustin T. Gibbs static void	ahc_dump_targcmd(struct target_cmd *cmd);
49717d4247SJustin T. Gibbs #endif
5058fb7d8eSJustin T. Gibbs static int	ahc_modevent(module_t mod, int type, void *data);
51717d4247SJustin T. Gibbs static void	ahc_action(struct cam_sim *sim, union ccb *ccb);
52717d4247SJustin T. Gibbs static void	ahc_get_tran_settings(struct ahc_softc *ahc,
53717d4247SJustin T. Gibbs 				      int our_id, char channel,
54717d4247SJustin T. Gibbs 				      struct ccb_trans_settings *cts);
55717d4247SJustin T. Gibbs static void	ahc_async(void *callback_arg, uint32_t code,
56717d4247SJustin T. Gibbs 			  struct cam_path *path, void *arg);
57717d4247SJustin T. Gibbs static void	ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
58717d4247SJustin T. Gibbs 				int nsegments, int error);
59717d4247SJustin T. Gibbs static void	ahc_poll(struct cam_sim *sim);
60717d4247SJustin T. Gibbs static void	ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
61717d4247SJustin T. Gibbs 			       struct ccb_scsiio *csio, struct scb *scb);
62717d4247SJustin T. Gibbs static void	ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim,
63717d4247SJustin T. Gibbs 			      union ccb *ccb);
64717d4247SJustin T. Gibbs static int	ahc_create_path(struct ahc_softc *ahc,
65c498406dSJustin T. Gibbs 				char channel, u_int target, u_int lun,
66717d4247SJustin T. Gibbs 				struct cam_path **path);
67717d4247SJustin T. Gibbs 
68717d4247SJustin T. Gibbs static int
69c498406dSJustin T. Gibbs ahc_create_path(struct ahc_softc *ahc, char channel, u_int target,
70c498406dSJustin T. Gibbs 	        u_int lun, struct cam_path **path)
71717d4247SJustin T. Gibbs {
72717d4247SJustin T. Gibbs 	path_id_t path_id;
73717d4247SJustin T. Gibbs 
74c498406dSJustin T. Gibbs 	if (channel == 'B')
75717d4247SJustin T. Gibbs 		path_id = cam_sim_path(ahc->platform_data->sim_b);
76717d4247SJustin T. Gibbs 	else
77717d4247SJustin T. Gibbs 		path_id = cam_sim_path(ahc->platform_data->sim);
78717d4247SJustin T. Gibbs 
79717d4247SJustin T. Gibbs 	return (xpt_create_path(path, /*periph*/NULL,
80c498406dSJustin T. Gibbs 				path_id, target, lun));
81717d4247SJustin T. Gibbs }
82717d4247SJustin T. Gibbs 
838f214efcSJustin T. Gibbs int
848f214efcSJustin T. Gibbs ahc_map_int(struct ahc_softc *ahc)
858f214efcSJustin T. Gibbs {
868f214efcSJustin T. Gibbs 	int error;
877afc0218SJustin T. Gibbs 	int zero;
887afc0218SJustin T. Gibbs 	int shareable;
897afc0218SJustin T. Gibbs 
907afc0218SJustin T. Gibbs 	zero = 0;
917afc0218SJustin T. Gibbs 	shareable = (ahc->flags & AHC_EDGE_INTERRUPT) ? 0: RF_SHAREABLE;
927afc0218SJustin T. Gibbs 	ahc->platform_data->irq =
937afc0218SJustin T. Gibbs 	    bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero,
947afc0218SJustin T. Gibbs 				   RF_ACTIVE | shareable);
957afc0218SJustin T. Gibbs 	if (ahc->platform_data->irq == NULL) {
967afc0218SJustin T. Gibbs 		device_printf(ahc->dev_softc,
977afc0218SJustin T. Gibbs 			      "bus_alloc_resource() failed to allocate IRQ\n");
987afc0218SJustin T. Gibbs 		return (ENOMEM);
997afc0218SJustin T. Gibbs 	}
1007afc0218SJustin T. Gibbs 	ahc->platform_data->irq_res_type = SYS_RES_IRQ;
1018f214efcSJustin T. Gibbs 
1028f214efcSJustin T. Gibbs 	/* Hook up our interrupt handler */
1038f214efcSJustin T. Gibbs 	error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
104032b0a17SScott Long 			       INTR_TYPE_CAM|INTR_MPSAFE, NULL,
105032b0a17SScott Long 			       ahc_platform_intr, ahc, &ahc->platform_data->ih);
1068f214efcSJustin T. Gibbs 
1078f214efcSJustin T. Gibbs 	if (error != 0)
1088f214efcSJustin T. Gibbs 		device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n",
1098f214efcSJustin T. Gibbs 			      error);
1108f214efcSJustin T. Gibbs 	return (error);
1118f214efcSJustin T. Gibbs }
1128f214efcSJustin T. Gibbs 
1137afc0218SJustin T. Gibbs int
1147afc0218SJustin T. Gibbs aic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg)
1157afc0218SJustin T. Gibbs {
1167afc0218SJustin T. Gibbs 	struct	resource *regs;
1177afc0218SJustin T. Gibbs 	int	rid;
1187afc0218SJustin T. Gibbs 
1197afc0218SJustin T. Gibbs 	rid = 0;
1207afc0218SJustin T. Gibbs 	regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid,
1217afc0218SJustin T. Gibbs 				      RF_ACTIVE);
1227afc0218SJustin T. Gibbs 	if (regs == NULL) {
1237afc0218SJustin T. Gibbs 		device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
1247afc0218SJustin T. Gibbs 		return ENOMEM;
1257afc0218SJustin T. Gibbs 	}
1267afc0218SJustin T. Gibbs 	ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
127f0be707dSPedro F. Giffuni 	ahc->platform_data->regs_res_id = rid;
1287afc0218SJustin T. Gibbs 	ahc->platform_data->regs = regs;
1297afc0218SJustin T. Gibbs 	ahc->tag = rman_get_bustag(regs);
1307afc0218SJustin T. Gibbs 	ahc->bsh = rman_get_bushandle(regs);
1317afc0218SJustin T. Gibbs 	return (0);
1327afc0218SJustin T. Gibbs }
1337afc0218SJustin T. Gibbs 
134717d4247SJustin T. Gibbs /*
135717d4247SJustin T. Gibbs  * Attach all the sub-devices we can find
136717d4247SJustin T. Gibbs  */
137717d4247SJustin T. Gibbs int
138717d4247SJustin T. Gibbs ahc_attach(struct ahc_softc *ahc)
139717d4247SJustin T. Gibbs {
140717d4247SJustin T. Gibbs 	char   ahc_info[256];
141717d4247SJustin T. Gibbs 	struct ccb_setasync csa;
142717d4247SJustin T. Gibbs 	struct cam_devq *devq;
143717d4247SJustin T. Gibbs 	int bus_id;
144717d4247SJustin T. Gibbs 	int bus_id2;
145717d4247SJustin T. Gibbs 	struct cam_sim *sim;
146717d4247SJustin T. Gibbs 	struct cam_sim *sim2;
147717d4247SJustin T. Gibbs 	struct cam_path *path;
148717d4247SJustin T. Gibbs 	struct cam_path *path2;
149717d4247SJustin T. Gibbs 	int count;
150717d4247SJustin T. Gibbs 
151717d4247SJustin T. Gibbs 	count = 0;
152717d4247SJustin T. Gibbs 	sim = NULL;
153717d4247SJustin T. Gibbs 	sim2 = NULL;
1549af877a1SMatt Jacob 	path = NULL;
1559af877a1SMatt Jacob 	path2 = NULL;
156717d4247SJustin T. Gibbs 
157b3b25f2cSJustin T. Gibbs 	/*
158b3b25f2cSJustin T. Gibbs 	 * Create a thread to perform all recovery.
159b3b25f2cSJustin T. Gibbs 	 */
160b3b25f2cSJustin T. Gibbs 	if (ahc_spawn_recovery_thread(ahc) != 0)
161b3b25f2cSJustin T. Gibbs 		goto fail;
162b3b25f2cSJustin T. Gibbs 
163717d4247SJustin T. Gibbs 	ahc_controller_info(ahc, ahc_info);
164717d4247SJustin T. Gibbs 	printf("%s\n", ahc_info);
165032b0a17SScott Long 	ahc_lock(ahc);
166b3b25f2cSJustin T. Gibbs 
167717d4247SJustin T. Gibbs 	/*
168717d4247SJustin T. Gibbs 	 * Attach secondary channel first if the user has
169717d4247SJustin T. Gibbs 	 * declared it the primary channel.
170717d4247SJustin T. Gibbs 	 */
171077c1baeSJustin T. Gibbs 	if ((ahc->features & AHC_TWIN) != 0
1726fb77fefSJustin T. Gibbs 	 && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
173717d4247SJustin T. Gibbs 		bus_id = 1;
174717d4247SJustin T. Gibbs 		bus_id2 = 0;
175717d4247SJustin T. Gibbs 	} else {
176717d4247SJustin T. Gibbs 		bus_id = 0;
177717d4247SJustin T. Gibbs 		bus_id2 = 1;
178717d4247SJustin T. Gibbs 	}
179717d4247SJustin T. Gibbs 
180717d4247SJustin T. Gibbs 	/*
181717d4247SJustin T. Gibbs 	 * Create the device queue for our SIM(s).
182717d4247SJustin T. Gibbs 	 */
183a5847d5cSJustin T. Gibbs 	devq = cam_simq_alloc(AHC_MAX_QUEUE);
184717d4247SJustin T. Gibbs 	if (devq == NULL)
185717d4247SJustin T. Gibbs 		goto fail;
186717d4247SJustin T. Gibbs 
187717d4247SJustin T. Gibbs 	/*
188717d4247SJustin T. Gibbs 	 * Construct our first channel SIM entry
189717d4247SJustin T. Gibbs 	 */
190dfd86f14SJustin T. Gibbs 	sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc,
191dfd86f14SJustin T. Gibbs 			    device_get_unit(ahc->dev_softc),
192032b0a17SScott Long 			    &ahc->platform_data->mtx, 1, AHC_MAX_QUEUE, devq);
193717d4247SJustin T. Gibbs 	if (sim == NULL) {
194717d4247SJustin T. Gibbs 		cam_simq_free(devq);
195717d4247SJustin T. Gibbs 		goto fail;
196717d4247SJustin T. Gibbs 	}
197717d4247SJustin T. Gibbs 
198b50569b7SScott Long 	if (xpt_bus_register(sim, ahc->dev_softc, bus_id) != CAM_SUCCESS) {
199717d4247SJustin T. Gibbs 		cam_sim_free(sim, /*free_devq*/TRUE);
200717d4247SJustin T. Gibbs 		sim = NULL;
201717d4247SJustin T. Gibbs 		goto fail;
202717d4247SJustin T. Gibbs 	}
203717d4247SJustin T. Gibbs 
204717d4247SJustin T. Gibbs 	if (xpt_create_path(&path, /*periph*/NULL,
205717d4247SJustin T. Gibbs 			    cam_sim_path(sim), CAM_TARGET_WILDCARD,
206717d4247SJustin T. Gibbs 			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
207717d4247SJustin T. Gibbs 		xpt_bus_deregister(cam_sim_path(sim));
208717d4247SJustin T. Gibbs 		cam_sim_free(sim, /*free_devq*/TRUE);
209717d4247SJustin T. Gibbs 		sim = NULL;
210717d4247SJustin T. Gibbs 		goto fail;
211717d4247SJustin T. Gibbs 	}
212717d4247SJustin T. Gibbs 
2138dc96b74SEdward Tomasz Napierala 	memset(&csa, 0, sizeof(csa));
214717d4247SJustin T. Gibbs 	xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
215717d4247SJustin T. Gibbs 	csa.ccb_h.func_code = XPT_SASYNC_CB;
216717d4247SJustin T. Gibbs 	csa.event_enable = AC_LOST_DEVICE;
217717d4247SJustin T. Gibbs 	csa.callback = ahc_async;
218717d4247SJustin T. Gibbs 	csa.callback_arg = sim;
219717d4247SJustin T. Gibbs 	xpt_action((union ccb *)&csa);
220717d4247SJustin T. Gibbs 	count++;
221717d4247SJustin T. Gibbs 
222717d4247SJustin T. Gibbs 	if (ahc->features & AHC_TWIN) {
223717d4247SJustin T. Gibbs 		sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc",
2242b83592fSScott Long 				    ahc, device_get_unit(ahc->dev_softc),
225032b0a17SScott Long 				    &ahc->platform_data->mtx, 1,
226a5847d5cSJustin T. Gibbs 				    AHC_MAX_QUEUE, devq);
227717d4247SJustin T. Gibbs 
228717d4247SJustin T. Gibbs 		if (sim2 == NULL) {
229717d4247SJustin T. Gibbs 			printf("ahc_attach: Unable to attach second "
230717d4247SJustin T. Gibbs 			       "bus due to resource shortage");
231717d4247SJustin T. Gibbs 			goto fail;
232717d4247SJustin T. Gibbs 		}
233717d4247SJustin T. Gibbs 
234b50569b7SScott Long 		if (xpt_bus_register(sim2, ahc->dev_softc, bus_id2) !=
235b50569b7SScott Long 		    CAM_SUCCESS) {
236717d4247SJustin T. Gibbs 			printf("ahc_attach: Unable to attach second "
237717d4247SJustin T. Gibbs 			       "bus due to resource shortage");
238717d4247SJustin T. Gibbs 			/*
239717d4247SJustin T. Gibbs 			 * We do not want to destroy the device queue
240717d4247SJustin T. Gibbs 			 * because the first bus is using it.
241717d4247SJustin T. Gibbs 			 */
242717d4247SJustin T. Gibbs 			cam_sim_free(sim2, /*free_devq*/FALSE);
243717d4247SJustin T. Gibbs 			goto fail;
244717d4247SJustin T. Gibbs 		}
245717d4247SJustin T. Gibbs 
246717d4247SJustin T. Gibbs 		if (xpt_create_path(&path2, /*periph*/NULL,
247717d4247SJustin T. Gibbs 				    cam_sim_path(sim2),
248717d4247SJustin T. Gibbs 				    CAM_TARGET_WILDCARD,
249717d4247SJustin T. Gibbs 				    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
250717d4247SJustin T. Gibbs 			xpt_bus_deregister(cam_sim_path(sim2));
251717d4247SJustin T. Gibbs 			cam_sim_free(sim2, /*free_devq*/FALSE);
252717d4247SJustin T. Gibbs 			sim2 = NULL;
253717d4247SJustin T. Gibbs 			goto fail;
254717d4247SJustin T. Gibbs 		}
255717d4247SJustin T. Gibbs 		xpt_setup_ccb(&csa.ccb_h, path2, /*priority*/5);
256717d4247SJustin T. Gibbs 		csa.ccb_h.func_code = XPT_SASYNC_CB;
257717d4247SJustin T. Gibbs 		csa.event_enable = AC_LOST_DEVICE;
258717d4247SJustin T. Gibbs 		csa.callback = ahc_async;
259717d4247SJustin T. Gibbs 		csa.callback_arg = sim2;
260717d4247SJustin T. Gibbs 		xpt_action((union ccb *)&csa);
261717d4247SJustin T. Gibbs 		count++;
262717d4247SJustin T. Gibbs 	}
263717d4247SJustin T. Gibbs 
264717d4247SJustin T. Gibbs fail:
265077c1baeSJustin T. Gibbs 	if ((ahc->features & AHC_TWIN) != 0
2666fb77fefSJustin T. Gibbs 	 && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
267717d4247SJustin T. Gibbs 		ahc->platform_data->sim_b = sim;
268717d4247SJustin T. Gibbs 		ahc->platform_data->path_b = path;
269717d4247SJustin T. Gibbs 		ahc->platform_data->sim = sim2;
270717d4247SJustin T. Gibbs 		ahc->platform_data->path = path2;
271717d4247SJustin T. Gibbs 	} else {
272717d4247SJustin T. Gibbs 		ahc->platform_data->sim = sim;
273717d4247SJustin T. Gibbs 		ahc->platform_data->path = path;
274717d4247SJustin T. Gibbs 		ahc->platform_data->sim_b = sim2;
275717d4247SJustin T. Gibbs 		ahc->platform_data->path_b = path2;
276717d4247SJustin T. Gibbs 	}
277032b0a17SScott Long 	ahc_unlock(ahc);
278717d4247SJustin T. Gibbs 
279226aa6eaSJustin T. Gibbs 	if (count != 0) {
280717d4247SJustin T. Gibbs 		/* We have to wait until after any system dumps... */
28156a7c4a8SJustin T. Gibbs 		ahc->platform_data->eh =
282717d4247SJustin T. Gibbs 		    EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
283717d4247SJustin T. Gibbs 					  ahc, SHUTDOWN_PRI_DEFAULT);
284226aa6eaSJustin T. Gibbs 		ahc_intr_enable(ahc, TRUE);
285226aa6eaSJustin T. Gibbs 	}
286717d4247SJustin T. Gibbs 
287717d4247SJustin T. Gibbs 	return (count);
288717d4247SJustin T. Gibbs }
289717d4247SJustin T. Gibbs 
290717d4247SJustin T. Gibbs /*
291717d4247SJustin T. Gibbs  * Catch an interrupt from the adapter
292717d4247SJustin T. Gibbs  */
293717d4247SJustin T. Gibbs void
29456a7c4a8SJustin T. Gibbs ahc_platform_intr(void *arg)
295717d4247SJustin T. Gibbs {
296717d4247SJustin T. Gibbs 	struct	ahc_softc *ahc;
297717d4247SJustin T. Gibbs 
298717d4247SJustin T. Gibbs 	ahc = (struct ahc_softc *)arg;
299032b0a17SScott Long 	ahc_lock(ahc);
300717d4247SJustin T. Gibbs 	ahc_intr(ahc);
301032b0a17SScott Long 	ahc_unlock(ahc);
302717d4247SJustin T. Gibbs }
303717d4247SJustin T. Gibbs 
304*9dcf3957SKyle Evans static void
305*9dcf3957SKyle Evans ahc_sync_ccb(struct ahc_softc *ahc, struct scb *scb, union ccb *ccb, bool post)
306*9dcf3957SKyle Evans {
307*9dcf3957SKyle Evans 	bus_dmasync_op_t op;
308*9dcf3957SKyle Evans 	uint32_t rdmask;
309*9dcf3957SKyle Evans 
310*9dcf3957SKyle Evans 	if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO)
311*9dcf3957SKyle Evans 		rdmask = CAM_DIR_OUT;
312*9dcf3957SKyle Evans 	else
313*9dcf3957SKyle Evans 		rdmask = CAM_DIR_IN;
314*9dcf3957SKyle Evans 
315*9dcf3957SKyle Evans 	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == rdmask)
316*9dcf3957SKyle Evans 		op = post ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_PREREAD;
317*9dcf3957SKyle Evans 	else
318*9dcf3957SKyle Evans 		op = post ? BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_PREWRITE;
319*9dcf3957SKyle Evans 
320*9dcf3957SKyle Evans 	bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op);
321*9dcf3957SKyle Evans }
322*9dcf3957SKyle Evans 
323717d4247SJustin T. Gibbs /*
324717d4247SJustin T. Gibbs  * We have an scb which has been processed by the
325717d4247SJustin T. Gibbs  * adaptor, now we look to see how the operation
326717d4247SJustin T. Gibbs  * went.
327717d4247SJustin T. Gibbs  */
328717d4247SJustin T. Gibbs void
329717d4247SJustin T. Gibbs ahc_done(struct ahc_softc *ahc, struct scb *scb)
330717d4247SJustin T. Gibbs {
331717d4247SJustin T. Gibbs 	union ccb *ccb;
332717d4247SJustin T. Gibbs 
333717d4247SJustin T. Gibbs 	CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE,
334717d4247SJustin T. Gibbs 		  ("ahc_done - scb %d\n", scb->hscb->tag));
335717d4247SJustin T. Gibbs 
336717d4247SJustin T. Gibbs 	ccb = scb->io_ctx;
337717d4247SJustin T. Gibbs 	LIST_REMOVE(scb, pending_links);
338b3b25f2cSJustin T. Gibbs 	if ((scb->flags & SCB_TIMEDOUT) != 0)
339b3b25f2cSJustin T. Gibbs 		LIST_REMOVE(scb, timedout_links);
34070351c9aSJustin T. Gibbs 	if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
341717d4247SJustin T. Gibbs 		struct scb_tailq *untagged_q;
3421478c711SJustin T. Gibbs 		int target_offset;
343717d4247SJustin T. Gibbs 
3441478c711SJustin T. Gibbs 		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
3451478c711SJustin T. Gibbs 		untagged_q = &ahc->untagged_queues[target_offset];
346717d4247SJustin T. Gibbs 		TAILQ_REMOVE(untagged_q, scb, links.tqe);
34770351c9aSJustin T. Gibbs 		scb->flags &= ~SCB_UNTAGGEDQ;
348717d4247SJustin T. Gibbs 		ahc_run_untagged_queue(ahc, untagged_q);
349717d4247SJustin T. Gibbs 	}
350717d4247SJustin T. Gibbs 
351032b0a17SScott Long 	callout_stop(&scb->io_timer);
352717d4247SJustin T. Gibbs 
353717d4247SJustin T. Gibbs 	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
354*9dcf3957SKyle Evans 		ahc_sync_ccb(ahc, scb, ccb, true);
355717d4247SJustin T. Gibbs 		bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
356717d4247SJustin T. Gibbs 	}
357717d4247SJustin T. Gibbs 
358717d4247SJustin T. Gibbs 	if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
359b95de6daSJustin T. Gibbs 		struct cam_path *ccb_path;
360b95de6daSJustin T. Gibbs 
361b95de6daSJustin T. Gibbs 		/*
362b95de6daSJustin T. Gibbs 		 * If we have finally disconnected, clean up our
363b95de6daSJustin T. Gibbs 		 * pending device state.
364b95de6daSJustin T. Gibbs 		 * XXX - There may be error states that cause where
365b95de6daSJustin T. Gibbs 		 *       we will remain connected.
366b95de6daSJustin T. Gibbs 		 */
367b95de6daSJustin T. Gibbs 		ccb_path = ccb->ccb_h.path;
368b95de6daSJustin T. Gibbs 		if (ahc->pending_device != NULL
369b95de6daSJustin T. Gibbs 		 && xpt_path_comp(ahc->pending_device->path, ccb_path) == 0) {
370b95de6daSJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
371b95de6daSJustin T. Gibbs 				ahc->pending_device = NULL;
372b95de6daSJustin T. Gibbs 			} else {
3738f214efcSJustin T. Gibbs 				if (bootverbose) {
374b95de6daSJustin T. Gibbs 					xpt_print_path(ccb->ccb_h.path);
3758f214efcSJustin T. Gibbs 					printf("Still connected\n");
3768f214efcSJustin T. Gibbs 				}
377b3b25f2cSJustin T. Gibbs 				aic_freeze_ccb(ccb);
378b95de6daSJustin T. Gibbs 			}
379b95de6daSJustin T. Gibbs 		}
380b95de6daSJustin T. Gibbs 
381b3b25f2cSJustin T. Gibbs 		if (aic_get_transaction_status(scb) == CAM_REQ_INPROG)
382717d4247SJustin T. Gibbs 			ccb->ccb_h.status |= CAM_REQ_CMP;
383717d4247SJustin T. Gibbs 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
384717d4247SJustin T. Gibbs 		ahc_free_scb(ahc, scb);
385717d4247SJustin T. Gibbs 		xpt_done(ccb);
386717d4247SJustin T. Gibbs 		return;
387717d4247SJustin T. Gibbs 	}
388717d4247SJustin T. Gibbs 
389717d4247SJustin T. Gibbs 	/*
390717d4247SJustin T. Gibbs 	 * If the recovery SCB completes, we have to be
391717d4247SJustin T. Gibbs 	 * out of our timeout.
392717d4247SJustin T. Gibbs 	 */
393717d4247SJustin T. Gibbs 	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
394717d4247SJustin T. Gibbs 		struct	scb *list_scb;
395717d4247SJustin T. Gibbs 
3967afc0218SJustin T. Gibbs 		ahc->scb_data->recovery_scbs--;
397717d4247SJustin T. Gibbs 
398b3b25f2cSJustin T. Gibbs 		if (aic_get_transaction_status(scb) == CAM_BDR_SENT
399b3b25f2cSJustin T. Gibbs 		 || aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
400b3b25f2cSJustin T. Gibbs 			aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
4017afc0218SJustin T. Gibbs 
4027afc0218SJustin T. Gibbs 		if (ahc->scb_data->recovery_scbs == 0) {
4037afc0218SJustin T. Gibbs 			/*
4047afc0218SJustin T. Gibbs 			 * All recovery actions have completed successfully,
4057afc0218SJustin T. Gibbs 			 * so reinstate the timeouts for all other pending
4067afc0218SJustin T. Gibbs 			 * commands.
4077afc0218SJustin T. Gibbs 			 */
4087afc0218SJustin T. Gibbs 			LIST_FOREACH(list_scb, &ahc->pending_scbs,
4097afc0218SJustin T. Gibbs 				     pending_links) {
41016346ae5SJustin T. Gibbs 				aic_scb_timer_reset(list_scb,
41116346ae5SJustin T. Gibbs 						    aic_get_timeout(scb));
4127afc0218SJustin T. Gibbs 			}
4137afc0218SJustin T. Gibbs 
414717d4247SJustin T. Gibbs 			ahc_print_path(ahc, scb);
415717d4247SJustin T. Gibbs 			printf("no longer in timeout, status = %x\n",
416717d4247SJustin T. Gibbs 			       ccb->ccb_h.status);
417717d4247SJustin T. Gibbs 		}
4187afc0218SJustin T. Gibbs 	}
419717d4247SJustin T. Gibbs 
420717d4247SJustin T. Gibbs 	/* Don't clobber any existing error state */
421b3b25f2cSJustin T. Gibbs 	if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) {
422717d4247SJustin T. Gibbs 		ccb->ccb_h.status |= CAM_REQ_CMP;
423717d4247SJustin T. Gibbs 	} else if ((scb->flags & SCB_SENSE) != 0) {
424717d4247SJustin T. Gibbs 		/*
425717d4247SJustin T. Gibbs 		 * We performed autosense retrieval.
426717d4247SJustin T. Gibbs 		 *
427717d4247SJustin T. Gibbs 		 * Zero any sense not transferred by the
428717d4247SJustin T. Gibbs 		 * device.  The SCSI spec mandates that any
429717d4247SJustin T. Gibbs 		 * untransfered data should be assumed to be
430717d4247SJustin T. Gibbs 		 * zero.  Complete the 'bounce' of sense information
431717d4247SJustin T. Gibbs 		 * through buffers accessible via bus-space by
432717d4247SJustin T. Gibbs 		 * copying it into the clients csio.
433717d4247SJustin T. Gibbs 		 */
434717d4247SJustin T. Gibbs 		memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
435717d4247SJustin T. Gibbs 		memcpy(&ccb->csio.sense_data,
43676150586SJustin T. Gibbs 		       ahc_get_sense_buf(ahc, scb),
437b3b25f2cSJustin T. Gibbs 		       (aic_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK)
438717d4247SJustin T. Gibbs 		       - ccb->csio.sense_resid);
439717d4247SJustin T. Gibbs 		scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID;
440717d4247SJustin T. Gibbs 	}
441717d4247SJustin T. Gibbs 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
442717d4247SJustin T. Gibbs 	ahc_free_scb(ahc, scb);
443717d4247SJustin T. Gibbs 	xpt_done(ccb);
444717d4247SJustin T. Gibbs }
445717d4247SJustin T. Gibbs 
446717d4247SJustin T. Gibbs static void
447717d4247SJustin T. Gibbs ahc_action(struct cam_sim *sim, union ccb *ccb)
448717d4247SJustin T. Gibbs {
449717d4247SJustin T. Gibbs 	struct	ahc_softc *ahc;
450b95de6daSJustin T. Gibbs 	struct	ahc_tmode_lstate *lstate;
451717d4247SJustin T. Gibbs 	u_int	target_id;
452717d4247SJustin T. Gibbs 	u_int	our_id;
453717d4247SJustin T. Gibbs 
454717d4247SJustin T. Gibbs 	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahc_action\n"));
455717d4247SJustin T. Gibbs 
456717d4247SJustin T. Gibbs 	ahc = (struct ahc_softc *)cam_sim_softc(sim);
457717d4247SJustin T. Gibbs 
458717d4247SJustin T. Gibbs 	target_id = ccb->ccb_h.target_id;
459717d4247SJustin T. Gibbs 	our_id = SIM_SCSI_ID(ahc, sim);
460717d4247SJustin T. Gibbs 
461717d4247SJustin T. Gibbs 	switch (ccb->ccb_h.func_code) {
462717d4247SJustin T. Gibbs 	/* Common cases first */
463717d4247SJustin T. Gibbs 	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
464717d4247SJustin T. Gibbs 	case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/
465717d4247SJustin T. Gibbs 	{
466b95de6daSJustin T. Gibbs 		struct	   ahc_tmode_tstate *tstate;
467717d4247SJustin T. Gibbs 		cam_status status;
468717d4247SJustin T. Gibbs 
469717d4247SJustin T. Gibbs 		status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate,
470717d4247SJustin T. Gibbs 					     &lstate, TRUE);
471717d4247SJustin T. Gibbs 
472717d4247SJustin T. Gibbs 		if (status != CAM_REQ_CMP) {
473717d4247SJustin T. Gibbs 			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
474717d4247SJustin T. Gibbs 				/* Response from the black hole device */
475717d4247SJustin T. Gibbs 				tstate = NULL;
476717d4247SJustin T. Gibbs 				lstate = ahc->black_hole;
477717d4247SJustin T. Gibbs 			} else {
478717d4247SJustin T. Gibbs 				ccb->ccb_h.status = status;
479717d4247SJustin T. Gibbs 				xpt_done(ccb);
480717d4247SJustin T. Gibbs 				break;
481717d4247SJustin T. Gibbs 			}
482717d4247SJustin T. Gibbs 		}
483717d4247SJustin T. Gibbs 		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
484717d4247SJustin T. Gibbs 			SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
485717d4247SJustin T. Gibbs 					  sim_links.sle);
486717d4247SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INPROG;
487717d4247SJustin T. Gibbs 			if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0)
488717d4247SJustin T. Gibbs 				ahc_run_tqinfifo(ahc, /*paused*/FALSE);
489717d4247SJustin T. Gibbs 			break;
490717d4247SJustin T. Gibbs 		}
491717d4247SJustin T. Gibbs 
492717d4247SJustin T. Gibbs 		/*
493717d4247SJustin T. Gibbs 		 * The target_id represents the target we attempt to
494717d4247SJustin T. Gibbs 		 * select.  In target mode, this is the initiator of
495717d4247SJustin T. Gibbs 		 * the original command.
496717d4247SJustin T. Gibbs 		 */
497717d4247SJustin T. Gibbs 		our_id = target_id;
498717d4247SJustin T. Gibbs 		target_id = ccb->csio.init_id;
499717d4247SJustin T. Gibbs 		/* FALLTHROUGH */
500717d4247SJustin T. Gibbs 	}
501717d4247SJustin T. Gibbs 	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
502717d4247SJustin T. Gibbs 	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
503717d4247SJustin T. Gibbs 	{
504717d4247SJustin T. Gibbs 		struct	scb *scb;
505717d4247SJustin T. Gibbs 		struct	hardware_scb *hscb;
506717d4247SJustin T. Gibbs 
507dd1290f0SJustin T. Gibbs 		if ((ahc->flags & AHC_INITIATORROLE) == 0
508dd1290f0SJustin T. Gibbs 		 && (ccb->ccb_h.func_code == XPT_SCSI_IO
509dd1290f0SJustin T. Gibbs 		  || ccb->ccb_h.func_code == XPT_RESET_DEV)) {
510dd1290f0SJustin T. Gibbs 			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
511dd1290f0SJustin T. Gibbs 			xpt_done(ccb);
512b95de6daSJustin T. Gibbs 			return;
513dd1290f0SJustin T. Gibbs 		}
514dd1290f0SJustin T. Gibbs 
515717d4247SJustin T. Gibbs 		/*
516717d4247SJustin T. Gibbs 		 * get an scb to use.
517717d4247SJustin T. Gibbs 		 */
518717d4247SJustin T. Gibbs 		if ((scb = ahc_get_scb(ahc)) == NULL) {
519b00aeda6SJustin T. Gibbs 			xpt_freeze_simq(sim, /*count*/1);
520717d4247SJustin T. Gibbs 			ahc->flags |= AHC_RESOURCE_SHORTAGE;
521155c0683SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQUEUE_REQ;
522717d4247SJustin T. Gibbs 			xpt_done(ccb);
523717d4247SJustin T. Gibbs 			return;
524717d4247SJustin T. Gibbs 		}
525717d4247SJustin T. Gibbs 
526717d4247SJustin T. Gibbs 		hscb = scb->hscb;
527717d4247SJustin T. Gibbs 
528717d4247SJustin T. Gibbs 		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE,
529717d4247SJustin T. Gibbs 			  ("start scb(%p)\n", scb));
530717d4247SJustin T. Gibbs 		scb->io_ctx = ccb;
531717d4247SJustin T. Gibbs 		/*
532717d4247SJustin T. Gibbs 		 * So we can find the SCB when an abort is requested
533717d4247SJustin T. Gibbs 		 */
534717d4247SJustin T. Gibbs 		ccb->ccb_h.ccb_scb_ptr = scb;
535717d4247SJustin T. Gibbs 
536717d4247SJustin T. Gibbs 		/*
537717d4247SJustin T. Gibbs 		 * Put all the arguments for the xfer in the scb
538717d4247SJustin T. Gibbs 		 */
539717d4247SJustin T. Gibbs 		hscb->control = 0;
540717d4247SJustin T. Gibbs 		hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id);
541717d4247SJustin T. Gibbs 		hscb->lun = ccb->ccb_h.target_lun;
542717d4247SJustin T. Gibbs 		if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
543717d4247SJustin T. Gibbs 			hscb->cdb_len = 0;
544717d4247SJustin T. Gibbs 			scb->flags |= SCB_DEVICE_RESET;
545717d4247SJustin T. Gibbs 			hscb->control |= MK_MESSAGE;
546717d4247SJustin T. Gibbs 			ahc_execute_scb(scb, NULL, 0, 0);
547717d4247SJustin T. Gibbs 		} else {
548717d4247SJustin T. Gibbs 			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
549717d4247SJustin T. Gibbs 				struct target_data *tdata;
550717d4247SJustin T. Gibbs 
551717d4247SJustin T. Gibbs 				tdata = &hscb->shared_data.tdata;
552b95de6daSJustin T. Gibbs 				if (ahc->pending_device == lstate)
553717d4247SJustin T. Gibbs 					scb->flags |= SCB_TARGET_IMMEDIATE;
554717d4247SJustin T. Gibbs 				hscb->control |= TARGET_SCB;
555a3a33a2bSScott Long 				scb->flags |= SCB_TARGET_SCB;
556a3a33a2bSScott Long 				tdata->target_phases = 0;
557717d4247SJustin T. Gibbs 				if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
558717d4247SJustin T. Gibbs 					tdata->target_phases |= SPHASE_PENDING;
559717d4247SJustin T. Gibbs 					tdata->scsi_status =
560717d4247SJustin T. Gibbs 					    ccb->csio.scsi_status;
561717d4247SJustin T. Gibbs 				}
562b95de6daSJustin T. Gibbs 	 			if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT)
563b95de6daSJustin T. Gibbs 					tdata->target_phases |= NO_DISCONNECT;
564b95de6daSJustin T. Gibbs 
565717d4247SJustin T. Gibbs 				tdata->initiator_tag = ccb->csio.tag_id;
566717d4247SJustin T. Gibbs 			}
567717d4247SJustin T. Gibbs 			if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID)
568717d4247SJustin T. Gibbs 				hscb->control |= ccb->csio.tag_action;
569717d4247SJustin T. Gibbs 
570717d4247SJustin T. Gibbs 			ahc_setup_data(ahc, sim, &ccb->csio, scb);
571717d4247SJustin T. Gibbs 		}
572717d4247SJustin T. Gibbs 		break;
573717d4247SJustin T. Gibbs 	}
574b79dc8a8SKenneth D. Merry 	case XPT_NOTIFY_ACKNOWLEDGE:
575b79dc8a8SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY:
576717d4247SJustin T. Gibbs 	{
577b95de6daSJustin T. Gibbs 		struct	   ahc_tmode_tstate *tstate;
578b95de6daSJustin T. Gibbs 		struct	   ahc_tmode_lstate *lstate;
579717d4247SJustin T. Gibbs 		cam_status status;
580717d4247SJustin T. Gibbs 
581717d4247SJustin T. Gibbs 		status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate,
582717d4247SJustin T. Gibbs 					     &lstate, TRUE);
583717d4247SJustin T. Gibbs 
584717d4247SJustin T. Gibbs 		if (status != CAM_REQ_CMP) {
585717d4247SJustin T. Gibbs 			ccb->ccb_h.status = status;
586717d4247SJustin T. Gibbs 			xpt_done(ccb);
587717d4247SJustin T. Gibbs 			break;
588717d4247SJustin T. Gibbs 		}
589717d4247SJustin T. Gibbs 		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
590717d4247SJustin T. Gibbs 				  sim_links.sle);
591717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INPROG;
592717d4247SJustin T. Gibbs 		ahc_send_lstate_events(ahc, lstate);
593717d4247SJustin T. Gibbs 		break;
594717d4247SJustin T. Gibbs 	}
595717d4247SJustin T. Gibbs 	case XPT_EN_LUN:		/* Enable LUN as a target */
596717d4247SJustin T. Gibbs 		ahc_handle_en_lun(ahc, sim, ccb);
597717d4247SJustin T. Gibbs 		xpt_done(ccb);
598717d4247SJustin T. Gibbs 		break;
599717d4247SJustin T. Gibbs 	case XPT_ABORT:			/* Abort the specified CCB */
600717d4247SJustin T. Gibbs 	{
601717d4247SJustin T. Gibbs 		ahc_abort_ccb(ahc, sim, ccb);
602717d4247SJustin T. Gibbs 		break;
603717d4247SJustin T. Gibbs 	}
604717d4247SJustin T. Gibbs 	case XPT_SET_TRAN_SETTINGS:
605717d4247SJustin T. Gibbs 	{
606717d4247SJustin T. Gibbs 		struct	ahc_devinfo devinfo;
607717d4247SJustin T. Gibbs 		struct	ccb_trans_settings *cts;
608717d4247SJustin T. Gibbs 		struct	ccb_trans_settings_scsi *scsi;
609717d4247SJustin T. Gibbs 		struct	ccb_trans_settings_spi *spi;
610717d4247SJustin T. Gibbs 		struct	ahc_initiator_tinfo *tinfo;
611b95de6daSJustin T. Gibbs 		struct	ahc_tmode_tstate *tstate;
612717d4247SJustin T. Gibbs 		uint16_t *discenable;
613717d4247SJustin T. Gibbs 		uint16_t *tagenable;
614717d4247SJustin T. Gibbs 		u_int	update_type;
615717d4247SJustin T. Gibbs 
616717d4247SJustin T. Gibbs 		cts = &ccb->cts;
617717d4247SJustin T. Gibbs 		scsi = &cts->proto_specific.scsi;
618717d4247SJustin T. Gibbs 		spi = &cts->xport_specific.spi;
619717d4247SJustin T. Gibbs 		ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
620717d4247SJustin T. Gibbs 				    cts->ccb_h.target_id,
621717d4247SJustin T. Gibbs 				    cts->ccb_h.target_lun,
622717d4247SJustin T. Gibbs 				    SIM_CHANNEL(ahc, sim),
623717d4247SJustin T. Gibbs 				    ROLE_UNKNOWN);
624717d4247SJustin T. Gibbs 		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
625717d4247SJustin T. Gibbs 					    devinfo.our_scsiid,
626717d4247SJustin T. Gibbs 					    devinfo.target, &tstate);
627717d4247SJustin T. Gibbs 		update_type = 0;
628717d4247SJustin T. Gibbs 		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
629717d4247SJustin T. Gibbs 			update_type |= AHC_TRANS_GOAL;
630717d4247SJustin T. Gibbs 			discenable = &tstate->discenable;
631717d4247SJustin T. Gibbs 			tagenable = &tstate->tagenable;
63258fb7d8eSJustin T. Gibbs 			tinfo->curr.protocol_version =
633717d4247SJustin T. Gibbs 			    cts->protocol_version;
63458fb7d8eSJustin T. Gibbs 			tinfo->curr.transport_version =
635717d4247SJustin T. Gibbs 			    cts->transport_version;
636717d4247SJustin T. Gibbs 			tinfo->goal.protocol_version =
637717d4247SJustin T. Gibbs 			    cts->protocol_version;
638717d4247SJustin T. Gibbs 			tinfo->goal.transport_version =
639717d4247SJustin T. Gibbs 			    cts->transport_version;
640717d4247SJustin T. Gibbs 		} else if (cts->type == CTS_TYPE_USER_SETTINGS) {
641717d4247SJustin T. Gibbs 			update_type |= AHC_TRANS_USER;
642717d4247SJustin T. Gibbs 			discenable = &ahc->user_discenable;
643717d4247SJustin T. Gibbs 			tagenable = &ahc->user_tagenable;
644717d4247SJustin T. Gibbs 			tinfo->user.protocol_version =
645717d4247SJustin T. Gibbs 			    cts->protocol_version;
646717d4247SJustin T. Gibbs 			tinfo->user.transport_version =
647717d4247SJustin T. Gibbs 			    cts->transport_version;
648717d4247SJustin T. Gibbs 		} else {
649717d4247SJustin T. Gibbs 			ccb->ccb_h.status = CAM_REQ_INVALID;
650717d4247SJustin T. Gibbs 			xpt_done(ccb);
651717d4247SJustin T. Gibbs 			break;
652717d4247SJustin T. Gibbs 		}
653717d4247SJustin T. Gibbs 
654717d4247SJustin T. Gibbs 		if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
655717d4247SJustin T. Gibbs 			if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
656717d4247SJustin T. Gibbs 				*discenable |= devinfo.target_mask;
657717d4247SJustin T. Gibbs 			else
658717d4247SJustin T. Gibbs 				*discenable &= ~devinfo.target_mask;
659717d4247SJustin T. Gibbs 		}
660717d4247SJustin T. Gibbs 
661717d4247SJustin T. Gibbs 		if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
662717d4247SJustin T. Gibbs 			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
663717d4247SJustin T. Gibbs 				*tagenable |= devinfo.target_mask;
664717d4247SJustin T. Gibbs 			else
665717d4247SJustin T. Gibbs 				*tagenable &= ~devinfo.target_mask;
666717d4247SJustin T. Gibbs 		}
667717d4247SJustin T. Gibbs 
668717d4247SJustin T. Gibbs 		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
669dd1290f0SJustin T. Gibbs 			ahc_validate_width(ahc, /*tinfo limit*/NULL,
670dd1290f0SJustin T. Gibbs 					   &spi->bus_width, ROLE_UNKNOWN);
671717d4247SJustin T. Gibbs 			ahc_set_width(ahc, &devinfo, spi->bus_width,
672717d4247SJustin T. Gibbs 				      update_type, /*paused*/FALSE);
673717d4247SJustin T. Gibbs 		}
674717d4247SJustin T. Gibbs 
675717d4247SJustin T. Gibbs 		if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) {
676717d4247SJustin T. Gibbs 			if (update_type == AHC_TRANS_USER)
677717d4247SJustin T. Gibbs 				spi->ppr_options = tinfo->user.ppr_options;
678717d4247SJustin T. Gibbs 			else
679717d4247SJustin T. Gibbs 				spi->ppr_options = tinfo->goal.ppr_options;
680717d4247SJustin T. Gibbs 		}
681717d4247SJustin T. Gibbs 
682717d4247SJustin T. Gibbs 		if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) {
683717d4247SJustin T. Gibbs 			if (update_type == AHC_TRANS_USER)
684717d4247SJustin T. Gibbs 				spi->sync_offset = tinfo->user.offset;
685717d4247SJustin T. Gibbs 			else
686717d4247SJustin T. Gibbs 				spi->sync_offset = tinfo->goal.offset;
687717d4247SJustin T. Gibbs 		}
688717d4247SJustin T. Gibbs 
689717d4247SJustin T. Gibbs 		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
690717d4247SJustin T. Gibbs 			if (update_type == AHC_TRANS_USER)
691717d4247SJustin T. Gibbs 				spi->sync_period = tinfo->user.period;
692717d4247SJustin T. Gibbs 			else
693717d4247SJustin T. Gibbs 				spi->sync_period = tinfo->goal.period;
694717d4247SJustin T. Gibbs 		}
695717d4247SJustin T. Gibbs 
696717d4247SJustin T. Gibbs 		if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
697717d4247SJustin T. Gibbs 		 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
698717d4247SJustin T. Gibbs 			struct ahc_syncrate *syncrate;
699717d4247SJustin T. Gibbs 			u_int maxsync;
700717d4247SJustin T. Gibbs 
701717d4247SJustin T. Gibbs 			if ((ahc->features & AHC_ULTRA2) != 0)
702717d4247SJustin T. Gibbs 				maxsync = AHC_SYNCRATE_DT;
703717d4247SJustin T. Gibbs 			else if ((ahc->features & AHC_ULTRA) != 0)
704717d4247SJustin T. Gibbs 				maxsync = AHC_SYNCRATE_ULTRA;
705717d4247SJustin T. Gibbs 			else
706717d4247SJustin T. Gibbs 				maxsync = AHC_SYNCRATE_FAST;
707717d4247SJustin T. Gibbs 
7088f214efcSJustin T. Gibbs 			if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT)
7098f214efcSJustin T. Gibbs 				spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
7108f214efcSJustin T. Gibbs 
711717d4247SJustin T. Gibbs 			syncrate = ahc_find_syncrate(ahc, &spi->sync_period,
712717d4247SJustin T. Gibbs 						     &spi->ppr_options,
713717d4247SJustin T. Gibbs 						     maxsync);
714dd1290f0SJustin T. Gibbs 			ahc_validate_offset(ahc, /*tinfo limit*/NULL,
715dd1290f0SJustin T. Gibbs 					    syncrate, &spi->sync_offset,
716dd1290f0SJustin T. Gibbs 					    spi->bus_width, ROLE_UNKNOWN);
717717d4247SJustin T. Gibbs 
718717d4247SJustin T. Gibbs 			/* We use a period of 0 to represent async */
719717d4247SJustin T. Gibbs 			if (spi->sync_offset == 0) {
720717d4247SJustin T. Gibbs 				spi->sync_period = 0;
721717d4247SJustin T. Gibbs 				spi->ppr_options = 0;
722717d4247SJustin T. Gibbs 			}
723717d4247SJustin T. Gibbs 
724717d4247SJustin T. Gibbs 			ahc_set_syncrate(ahc, &devinfo, syncrate,
725717d4247SJustin T. Gibbs 					 spi->sync_period, spi->sync_offset,
726717d4247SJustin T. Gibbs 					 spi->ppr_options, update_type,
727717d4247SJustin T. Gibbs 					 /*paused*/FALSE);
728717d4247SJustin T. Gibbs 		}
729717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
730717d4247SJustin T. Gibbs 		xpt_done(ccb);
731717d4247SJustin T. Gibbs 		break;
732717d4247SJustin T. Gibbs 	}
733717d4247SJustin T. Gibbs 	case XPT_GET_TRAN_SETTINGS:
734717d4247SJustin T. Gibbs 	/* Get default/user set transfer settings for the target */
735717d4247SJustin T. Gibbs 	{
736717d4247SJustin T. Gibbs 		ahc_get_tran_settings(ahc, SIM_SCSI_ID(ahc, sim),
737717d4247SJustin T. Gibbs 				      SIM_CHANNEL(ahc, sim), &ccb->cts);
738717d4247SJustin T. Gibbs 		xpt_done(ccb);
739717d4247SJustin T. Gibbs 		break;
740717d4247SJustin T. Gibbs 	}
741717d4247SJustin T. Gibbs 	case XPT_CALC_GEOMETRY:
742717d4247SJustin T. Gibbs 	{
743717d4247SJustin T. Gibbs 		int extended;
744717d4247SJustin T. Gibbs 
745717d4247SJustin T. Gibbs 		extended = SIM_IS_SCSIBUS_B(ahc, sim)
746717d4247SJustin T. Gibbs 			 ? ahc->flags & AHC_EXTENDED_TRANS_B
747717d4247SJustin T. Gibbs 			 : ahc->flags & AHC_EXTENDED_TRANS_A;
748b3b25f2cSJustin T. Gibbs 		aic_calc_geometry(&ccb->ccg, extended);
749717d4247SJustin T. Gibbs 		xpt_done(ccb);
750717d4247SJustin T. Gibbs 		break;
751717d4247SJustin T. Gibbs 	}
752717d4247SJustin T. Gibbs 	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
753717d4247SJustin T. Gibbs 	{
754717d4247SJustin T. Gibbs 		int  found;
755717d4247SJustin T. Gibbs 
756717d4247SJustin T. Gibbs 		found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim),
757717d4247SJustin T. Gibbs 					  /*initiate reset*/TRUE);
758717d4247SJustin T. Gibbs 		if (bootverbose) {
759717d4247SJustin T. Gibbs 			xpt_print_path(SIM_PATH(ahc, sim));
760717d4247SJustin T. Gibbs 			printf("SCSI bus reset delivered. "
761717d4247SJustin T. Gibbs 			       "%d SCBs aborted.\n", found);
762717d4247SJustin T. Gibbs 		}
763717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_CMP;
764717d4247SJustin T. Gibbs 		xpt_done(ccb);
765717d4247SJustin T. Gibbs 		break;
766717d4247SJustin T. Gibbs 	}
767717d4247SJustin T. Gibbs 	case XPT_TERM_IO:		/* Terminate the I/O process */
768717d4247SJustin T. Gibbs 		/* XXX Implement */
769717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
770717d4247SJustin T. Gibbs 		xpt_done(ccb);
771717d4247SJustin T. Gibbs 		break;
772717d4247SJustin T. Gibbs 	case XPT_PATH_INQ:		/* Path routing inquiry */
773717d4247SJustin T. Gibbs 	{
774717d4247SJustin T. Gibbs 		struct ccb_pathinq *cpi = &ccb->cpi;
775717d4247SJustin T. Gibbs 
776717d4247SJustin T. Gibbs 		cpi->version_num = 1; /* XXX??? */
777717d4247SJustin T. Gibbs 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
778717d4247SJustin T. Gibbs 		if ((ahc->features & AHC_WIDE) != 0)
779717d4247SJustin T. Gibbs 			cpi->hba_inquiry |= PI_WIDE_16;
780dd1290f0SJustin T. Gibbs 		if ((ahc->features & AHC_TARGETMODE) != 0) {
781717d4247SJustin T. Gibbs 			cpi->target_sprt = PIT_PROCESSOR
782717d4247SJustin T. Gibbs 					 | PIT_DISCONNECT
783717d4247SJustin T. Gibbs 					 | PIT_TERM_IO;
784717d4247SJustin T. Gibbs 		} else {
785717d4247SJustin T. Gibbs 			cpi->target_sprt = 0;
786717d4247SJustin T. Gibbs 		}
787dd1290f0SJustin T. Gibbs 		cpi->hba_misc = 0;
788717d4247SJustin T. Gibbs 		cpi->hba_eng_cnt = 0;
789717d4247SJustin T. Gibbs 		cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7;
79056a7c4a8SJustin T. Gibbs 		cpi->max_lun = AHC_NUM_LUNS - 1;
791717d4247SJustin T. Gibbs 		if (SIM_IS_SCSIBUS_B(ahc, sim)) {
792717d4247SJustin T. Gibbs 			cpi->initiator_id = ahc->our_id_b;
793717d4247SJustin T. Gibbs 			if ((ahc->flags & AHC_RESET_BUS_B) == 0)
794717d4247SJustin T. Gibbs 				cpi->hba_misc |= PIM_NOBUSRESET;
795717d4247SJustin T. Gibbs 		} else {
796717d4247SJustin T. Gibbs 			cpi->initiator_id = ahc->our_id;
797717d4247SJustin T. Gibbs 			if ((ahc->flags & AHC_RESET_BUS_A) == 0)
798717d4247SJustin T. Gibbs 				cpi->hba_misc |= PIM_NOBUSRESET;
799717d4247SJustin T. Gibbs 		}
800717d4247SJustin T. Gibbs 		cpi->bus_id = cam_sim_bus(sim);
801717d4247SJustin T. Gibbs 		cpi->base_transfer_speed = 3300;
8024195c7deSAlan Somers 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
8034195c7deSAlan Somers 		strlcpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
8044195c7deSAlan Somers 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
805717d4247SJustin T. Gibbs 		cpi->unit_number = cam_sim_unit(sim);
806717d4247SJustin T. Gibbs 		cpi->protocol = PROTO_SCSI;
807717d4247SJustin T. Gibbs 		cpi->protocol_version = SCSI_REV_2;
808717d4247SJustin T. Gibbs 		cpi->transport = XPORT_SPI;
809717d4247SJustin T. Gibbs 		cpi->transport_version = 2;
810717d4247SJustin T. Gibbs 		cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST;
811717d4247SJustin T. Gibbs 		if ((ahc->features & AHC_DT) != 0) {
812717d4247SJustin T. Gibbs 			cpi->transport_version = 3;
813717d4247SJustin T. Gibbs 			cpi->xport_specific.spi.ppr_options =
814717d4247SJustin T. Gibbs 			    SID_SPI_CLOCK_DT_ST;
815717d4247SJustin T. Gibbs 		}
816717d4247SJustin T. Gibbs 		cpi->ccb_h.status = CAM_REQ_CMP;
817717d4247SJustin T. Gibbs 		xpt_done(ccb);
818717d4247SJustin T. Gibbs 		break;
819717d4247SJustin T. Gibbs 	}
820717d4247SJustin T. Gibbs 	default:
821dd1290f0SJustin T. Gibbs 		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
822717d4247SJustin T. Gibbs 		xpt_done(ccb);
823717d4247SJustin T. Gibbs 		break;
824717d4247SJustin T. Gibbs 	}
825717d4247SJustin T. Gibbs }
826717d4247SJustin T. Gibbs 
827717d4247SJustin T. Gibbs static void
828717d4247SJustin T. Gibbs ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
829717d4247SJustin T. Gibbs 		      struct ccb_trans_settings *cts)
830717d4247SJustin T. Gibbs {
831717d4247SJustin T. Gibbs 	struct	ahc_devinfo devinfo;
832717d4247SJustin T. Gibbs 	struct	ccb_trans_settings_scsi *scsi;
833717d4247SJustin T. Gibbs 	struct	ccb_trans_settings_spi *spi;
834717d4247SJustin T. Gibbs 	struct	ahc_initiator_tinfo *targ_info;
835b95de6daSJustin T. Gibbs 	struct	ahc_tmode_tstate *tstate;
836717d4247SJustin T. Gibbs 	struct	ahc_transinfo *tinfo;
837717d4247SJustin T. Gibbs 
838717d4247SJustin T. Gibbs 	scsi = &cts->proto_specific.scsi;
839717d4247SJustin T. Gibbs 	spi = &cts->xport_specific.spi;
840717d4247SJustin T. Gibbs 	ahc_compile_devinfo(&devinfo, our_id,
841717d4247SJustin T. Gibbs 			    cts->ccb_h.target_id,
842717d4247SJustin T. Gibbs 			    cts->ccb_h.target_lun,
843717d4247SJustin T. Gibbs 			    channel, ROLE_UNKNOWN);
844717d4247SJustin T. Gibbs 	targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,
845717d4247SJustin T. Gibbs 					devinfo.our_scsiid,
846717d4247SJustin T. Gibbs 					devinfo.target, &tstate);
847717d4247SJustin T. Gibbs 
848717d4247SJustin T. Gibbs 	if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
84958fb7d8eSJustin T. Gibbs 		tinfo = &targ_info->curr;
850717d4247SJustin T. Gibbs 	else
851717d4247SJustin T. Gibbs 		tinfo = &targ_info->user;
852717d4247SJustin T. Gibbs 
853717d4247SJustin T. Gibbs 	scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
854717d4247SJustin T. Gibbs 	spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
855717d4247SJustin T. Gibbs 	if (cts->type == CTS_TYPE_USER_SETTINGS) {
856717d4247SJustin T. Gibbs 		if ((ahc->user_discenable & devinfo.target_mask) != 0)
857717d4247SJustin T. Gibbs 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
858717d4247SJustin T. Gibbs 
859717d4247SJustin T. Gibbs 		if ((ahc->user_tagenable & devinfo.target_mask) != 0)
860717d4247SJustin T. Gibbs 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
861717d4247SJustin T. Gibbs 	} else {
862717d4247SJustin T. Gibbs 		if ((tstate->discenable & devinfo.target_mask) != 0)
863717d4247SJustin T. Gibbs 			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
864717d4247SJustin T. Gibbs 
865717d4247SJustin T. Gibbs 		if ((tstate->tagenable & devinfo.target_mask) != 0)
866717d4247SJustin T. Gibbs 			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
867717d4247SJustin T. Gibbs 	}
868717d4247SJustin T. Gibbs 	cts->protocol_version = tinfo->protocol_version;
869717d4247SJustin T. Gibbs 	cts->transport_version = tinfo->transport_version;
870717d4247SJustin T. Gibbs 
871717d4247SJustin T. Gibbs 	spi->sync_period = tinfo->period;
872717d4247SJustin T. Gibbs 	spi->sync_offset = tinfo->offset;
873717d4247SJustin T. Gibbs 	spi->bus_width = tinfo->width;
874717d4247SJustin T. Gibbs 	spi->ppr_options = tinfo->ppr_options;
875717d4247SJustin T. Gibbs 
876717d4247SJustin T. Gibbs 	cts->protocol = PROTO_SCSI;
877717d4247SJustin T. Gibbs 	cts->transport = XPORT_SPI;
878717d4247SJustin T. Gibbs 	spi->valid = CTS_SPI_VALID_SYNC_RATE
879717d4247SJustin T. Gibbs 		   | CTS_SPI_VALID_SYNC_OFFSET
880717d4247SJustin T. Gibbs 		   | CTS_SPI_VALID_BUS_WIDTH
881717d4247SJustin T. Gibbs 		   | CTS_SPI_VALID_PPR_OPTIONS;
882717d4247SJustin T. Gibbs 
883ff0c1dafSJustin T. Gibbs 	if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
884ff0c1dafSJustin T. Gibbs 		scsi->valid = CTS_SCSI_VALID_TQ;
885ff0c1dafSJustin T. Gibbs 		spi->valid |= CTS_SPI_VALID_DISC;
886ff0c1dafSJustin T. Gibbs 	} else {
887ff0c1dafSJustin T. Gibbs 		scsi->valid = 0;
888ff0c1dafSJustin T. Gibbs 	}
889ff0c1dafSJustin T. Gibbs 
890717d4247SJustin T. Gibbs 	cts->ccb_h.status = CAM_REQ_CMP;
891717d4247SJustin T. Gibbs }
892717d4247SJustin T. Gibbs 
893717d4247SJustin T. Gibbs static void
894717d4247SJustin T. Gibbs ahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
895717d4247SJustin T. Gibbs {
896717d4247SJustin T. Gibbs 	struct ahc_softc *ahc;
897717d4247SJustin T. Gibbs 	struct cam_sim *sim;
898717d4247SJustin T. Gibbs 
899717d4247SJustin T. Gibbs 	sim = (struct cam_sim *)callback_arg;
900717d4247SJustin T. Gibbs 	ahc = (struct ahc_softc *)cam_sim_softc(sim);
901717d4247SJustin T. Gibbs 	switch (code) {
902717d4247SJustin T. Gibbs 	case AC_LOST_DEVICE:
903717d4247SJustin T. Gibbs 	{
904717d4247SJustin T. Gibbs 		struct	ahc_devinfo devinfo;
905717d4247SJustin T. Gibbs 
906717d4247SJustin T. Gibbs 		ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
907717d4247SJustin T. Gibbs 				    xpt_path_target_id(path),
908717d4247SJustin T. Gibbs 				    xpt_path_lun_id(path),
909717d4247SJustin T. Gibbs 				    SIM_CHANNEL(ahc, sim),
910717d4247SJustin T. Gibbs 				    ROLE_UNKNOWN);
911717d4247SJustin T. Gibbs 
912717d4247SJustin T. Gibbs 		/*
913717d4247SJustin T. Gibbs 		 * Revert to async/narrow transfers
914717d4247SJustin T. Gibbs 		 * for the next device.
915717d4247SJustin T. Gibbs 		 */
916717d4247SJustin T. Gibbs 		ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
917717d4247SJustin T. Gibbs 			      AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE);
918717d4247SJustin T. Gibbs 		ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL,
919717d4247SJustin T. Gibbs 				 /*period*/0, /*offset*/0, /*ppr_options*/0,
920717d4247SJustin T. Gibbs 				 AHC_TRANS_GOAL|AHC_TRANS_CUR,
921717d4247SJustin T. Gibbs 				 /*paused*/FALSE);
922717d4247SJustin T. Gibbs 		break;
923717d4247SJustin T. Gibbs 	}
924717d4247SJustin T. Gibbs 	default:
925717d4247SJustin T. Gibbs 		break;
926717d4247SJustin T. Gibbs 	}
927717d4247SJustin T. Gibbs }
928717d4247SJustin T. Gibbs 
929717d4247SJustin T. Gibbs static void
930717d4247SJustin T. Gibbs ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
931717d4247SJustin T. Gibbs 		int error)
932717d4247SJustin T. Gibbs {
933717d4247SJustin T. Gibbs 	struct	scb *scb;
934717d4247SJustin T. Gibbs 	union	ccb *ccb;
935717d4247SJustin T. Gibbs 	struct	ahc_softc *ahc;
936ff0c1dafSJustin T. Gibbs 	struct	ahc_initiator_tinfo *tinfo;
937b95de6daSJustin T. Gibbs 	struct	ahc_tmode_tstate *tstate;
938ff0c1dafSJustin T. Gibbs 	u_int	mask;
939717d4247SJustin T. Gibbs 
940717d4247SJustin T. Gibbs 	scb = (struct scb *)arg;
941717d4247SJustin T. Gibbs 	ccb = scb->io_ctx;
94270351c9aSJustin T. Gibbs 	ahc = scb->ahc_softc;
943717d4247SJustin T. Gibbs 
944717d4247SJustin T. Gibbs 	if (error != 0) {
945717d4247SJustin T. Gibbs 		if (error == EFBIG)
946b3b25f2cSJustin T. Gibbs 			aic_set_transaction_status(scb, CAM_REQ_TOO_BIG);
947717d4247SJustin T. Gibbs 		else
948b3b25f2cSJustin T. Gibbs 			aic_set_transaction_status(scb, CAM_REQ_CMP_ERR);
949717d4247SJustin T. Gibbs 		if (nsegments != 0)
950717d4247SJustin T. Gibbs 			bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
951717d4247SJustin T. Gibbs 		ahc_free_scb(ahc, scb);
952717d4247SJustin T. Gibbs 		xpt_done(ccb);
953717d4247SJustin T. Gibbs 		return;
954717d4247SJustin T. Gibbs 	}
955717d4247SJustin T. Gibbs 	if (nsegments != 0) {
956717d4247SJustin T. Gibbs 		struct	  ahc_dma_seg *sg;
957717d4247SJustin T. Gibbs 		bus_dma_segment_t *end_seg;
958717d4247SJustin T. Gibbs 
959717d4247SJustin T. Gibbs 		end_seg = dm_segs + nsegments;
960717d4247SJustin T. Gibbs 
961717d4247SJustin T. Gibbs 		/* Copy the segments into our SG list */
962717d4247SJustin T. Gibbs 		sg = scb->sg_list;
963717d4247SJustin T. Gibbs 		while (dm_segs < end_seg) {
964cd036e89SJustin T. Gibbs 			uint32_t len;
965cd036e89SJustin T. Gibbs 
966b3b25f2cSJustin T. Gibbs 			sg->addr = aic_htole32(dm_segs->ds_addr);
967cd036e89SJustin T. Gibbs 			len = dm_segs->ds_len
968cd036e89SJustin T. Gibbs 			    | ((dm_segs->ds_addr >> 8) & 0x7F000000);
969b3b25f2cSJustin T. Gibbs 			sg->len = aic_htole32(len);
970717d4247SJustin T. Gibbs 			sg++;
971717d4247SJustin T. Gibbs 			dm_segs++;
972717d4247SJustin T. Gibbs 		}
973717d4247SJustin T. Gibbs 
974717d4247SJustin T. Gibbs 		/*
975717d4247SJustin T. Gibbs 		 * Note where to find the SG entries in bus space.
976717d4247SJustin T. Gibbs 		 * We also set the full residual flag which the
977717d4247SJustin T. Gibbs 		 * sequencer will clear as soon as a data transfer
978717d4247SJustin T. Gibbs 		 * occurs.
979717d4247SJustin T. Gibbs 		 */
980b3b25f2cSJustin T. Gibbs 		scb->hscb->sgptr = aic_htole32(scb->sg_list_phys|SG_FULL_RESID);
981717d4247SJustin T. Gibbs 
982*9dcf3957SKyle Evans 		ahc_sync_ccb(ahc, scb, ccb, false);
983717d4247SJustin T. Gibbs 
984717d4247SJustin T. Gibbs 		if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
985717d4247SJustin T. Gibbs 			struct target_data *tdata;
986717d4247SJustin T. Gibbs 
987717d4247SJustin T. Gibbs 			tdata = &scb->hscb->shared_data.tdata;
988717d4247SJustin T. Gibbs 			tdata->target_phases |= DPHASE_PENDING;
989b3b25f2cSJustin T. Gibbs 			/*
990b3b25f2cSJustin T. Gibbs 			 * CAM data direction is relative to the initiator.
991b3b25f2cSJustin T. Gibbs 			 */
992717d4247SJustin T. Gibbs 			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
993717d4247SJustin T. Gibbs 				tdata->data_phase = P_DATAOUT;
994717d4247SJustin T. Gibbs 			else
995717d4247SJustin T. Gibbs 				tdata->data_phase = P_DATAIN;
996717d4247SJustin T. Gibbs 
997717d4247SJustin T. Gibbs 			/*
998717d4247SJustin T. Gibbs 			 * If the transfer is of an odd length and in the
999717d4247SJustin T. Gibbs 			 * "in" direction (scsi->HostBus), then it may
1000717d4247SJustin T. Gibbs 			 * trigger a bug in the 'WideODD' feature of
1001717d4247SJustin T. Gibbs 			 * non-Ultra2 chips.  Force the total data-length
1002717d4247SJustin T. Gibbs 			 * to be even by adding an extra, 1 byte, SG,
1003717d4247SJustin T. Gibbs 			 * element.  We do this even if we are not currently
1004717d4247SJustin T. Gibbs 			 * negotiated wide as negotiation could occur before
1005717d4247SJustin T. Gibbs 			 * this command is executed.
1006717d4247SJustin T. Gibbs 			 */
1007717d4247SJustin T. Gibbs 			if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0
1008717d4247SJustin T. Gibbs 			 && (ccb->csio.dxfer_len & 0x1) != 0
1009b3b25f2cSJustin T. Gibbs 			 && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1010717d4247SJustin T. Gibbs 				nsegments++;
1011717d4247SJustin T. Gibbs 				if (nsegments > AHC_NSEG) {
1012b3b25f2cSJustin T. Gibbs 					aic_set_transaction_status(scb,
1013717d4247SJustin T. Gibbs 					    CAM_REQ_TOO_BIG);
1014717d4247SJustin T. Gibbs 					bus_dmamap_unload(ahc->buffer_dmat,
1015717d4247SJustin T. Gibbs 							  scb->dmamap);
1016717d4247SJustin T. Gibbs 					ahc_free_scb(ahc, scb);
1017717d4247SJustin T. Gibbs 					xpt_done(ccb);
1018717d4247SJustin T. Gibbs 					return;
1019717d4247SJustin T. Gibbs 				}
1020b3b25f2cSJustin T. Gibbs 				sg->addr = aic_htole32(ahc->dma_bug_buf);
1021b3b25f2cSJustin T. Gibbs 				sg->len = aic_htole32(1);
1022717d4247SJustin T. Gibbs 				sg++;
1023717d4247SJustin T. Gibbs 			}
1024717d4247SJustin T. Gibbs 		}
1025717d4247SJustin T. Gibbs 		sg--;
1026b3b25f2cSJustin T. Gibbs 		sg->len |= aic_htole32(AHC_DMA_LAST_SEG);
1027717d4247SJustin T. Gibbs 
1028717d4247SJustin T. Gibbs 		/* Copy the first SG into the "current" data pointer area */
1029717d4247SJustin T. Gibbs 		scb->hscb->dataptr = scb->sg_list->addr;
1030717d4247SJustin T. Gibbs 		scb->hscb->datacnt = scb->sg_list->len;
1031717d4247SJustin T. Gibbs 	} else {
1032b3b25f2cSJustin T. Gibbs 		scb->hscb->sgptr = aic_htole32(SG_LIST_NULL);
1033717d4247SJustin T. Gibbs 		scb->hscb->dataptr = 0;
1034717d4247SJustin T. Gibbs 		scb->hscb->datacnt = 0;
1035717d4247SJustin T. Gibbs 	}
1036717d4247SJustin T. Gibbs 
1037717d4247SJustin T. Gibbs 	scb->sg_count = nsegments;
1038717d4247SJustin T. Gibbs 
1039717d4247SJustin T. Gibbs 	/*
1040717d4247SJustin T. Gibbs 	 * Last time we need to check if this SCB needs to
1041717d4247SJustin T. Gibbs 	 * be aborted.
1042717d4247SJustin T. Gibbs 	 */
1043b3b25f2cSJustin T. Gibbs 	if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) {
1044717d4247SJustin T. Gibbs 		if (nsegments != 0)
10458f214efcSJustin T. Gibbs 			bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
1046717d4247SJustin T. Gibbs 		ahc_free_scb(ahc, scb);
1047a49630acSJustin T. Gibbs 		xpt_done(ccb);
1048717d4247SJustin T. Gibbs 		return;
1049717d4247SJustin T. Gibbs 	}
1050717d4247SJustin T. Gibbs 
1051ff0c1dafSJustin T. Gibbs 	tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid),
1052ff0c1dafSJustin T. Gibbs 				    SCSIID_OUR_ID(scb->hscb->scsiid),
1053dd1290f0SJustin T. Gibbs 				    SCSIID_TARGET(ahc, scb->hscb->scsiid),
1054dd1290f0SJustin T. Gibbs 				    &tstate);
1055ff0c1dafSJustin T. Gibbs 
1056ff0c1dafSJustin T. Gibbs 	mask = SCB_GET_TARGET_MASK(ahc, scb);
1057ff0c1dafSJustin T. Gibbs 	scb->hscb->scsirate = tinfo->scsirate;
105858fb7d8eSJustin T. Gibbs 	scb->hscb->scsioffset = tinfo->curr.offset;
1059ff0c1dafSJustin T. Gibbs 	if ((tstate->ultraenb & mask) != 0)
1060ff0c1dafSJustin T. Gibbs 		scb->hscb->control |= ULTRAENB;
1061ff0c1dafSJustin T. Gibbs 
1062ff0c1dafSJustin T. Gibbs 	if ((tstate->discenable & mask) != 0
1063ff0c1dafSJustin T. Gibbs 	 && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0)
1064ff0c1dafSJustin T. Gibbs 		scb->hscb->control |= DISCENB;
1065ff0c1dafSJustin T. Gibbs 
1066ff0c1dafSJustin T. Gibbs 	if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
106756a7c4a8SJustin T. Gibbs 	 && (tinfo->goal.width != 0
1068226aa6eaSJustin T. Gibbs 	  || tinfo->goal.offset != 0
106956a7c4a8SJustin T. Gibbs 	  || tinfo->goal.ppr_options != 0)) {
1070ff0c1dafSJustin T. Gibbs 		scb->flags |= SCB_NEGOTIATE;
1071ff0c1dafSJustin T. Gibbs 		scb->hscb->control |= MK_MESSAGE;
1072b95de6daSJustin T. Gibbs 	} else if ((tstate->auto_negotiate & mask) != 0) {
1073b95de6daSJustin T. Gibbs 		scb->flags |= SCB_AUTO_NEGOTIATE;
1074b95de6daSJustin T. Gibbs 		scb->hscb->control |= MK_MESSAGE;
1075ff0c1dafSJustin T. Gibbs 	}
1076ff0c1dafSJustin T. Gibbs 
1077717d4247SJustin T. Gibbs 	LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
1078717d4247SJustin T. Gibbs 
1079717d4247SJustin T. Gibbs 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1080717d4247SJustin T. Gibbs 
1081717d4247SJustin T. Gibbs 	/*
1082717d4247SJustin T. Gibbs 	 * We only allow one untagged transaction
1083717d4247SJustin T. Gibbs 	 * per target in the initiator role unless
1084717d4247SJustin T. Gibbs 	 * we are storing a full busy target *lun*
1085717d4247SJustin T. Gibbs 	 * table in SCB space.
1086717d4247SJustin T. Gibbs 	 */
1087717d4247SJustin T. Gibbs 	if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
1088a5847d5cSJustin T. Gibbs 	 && (ahc->flags & AHC_SCB_BTT) == 0) {
1089717d4247SJustin T. Gibbs 		struct scb_tailq *untagged_q;
10901478c711SJustin T. Gibbs 		int target_offset;
1091717d4247SJustin T. Gibbs 
10921478c711SJustin T. Gibbs 		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
10931478c711SJustin T. Gibbs 		untagged_q = &(ahc->untagged_queues[target_offset]);
1094717d4247SJustin T. Gibbs 		TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
109570351c9aSJustin T. Gibbs 		scb->flags |= SCB_UNTAGGEDQ;
1096717d4247SJustin T. Gibbs 		if (TAILQ_FIRST(untagged_q) != scb) {
1097717d4247SJustin T. Gibbs 			return;
1098717d4247SJustin T. Gibbs 		}
1099717d4247SJustin T. Gibbs 	}
1100717d4247SJustin T. Gibbs 	scb->flags |= SCB_ACTIVE;
1101717d4247SJustin T. Gibbs 
11027afc0218SJustin T. Gibbs 	/*
11037afc0218SJustin T. Gibbs 	 * Timers are disabled while recovery is in progress.
11047afc0218SJustin T. Gibbs 	 */
11057afc0218SJustin T. Gibbs 	aic_scb_timer_start(scb);
11067afc0218SJustin T. Gibbs 
1107717d4247SJustin T. Gibbs 	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
1108b95de6daSJustin T. Gibbs 		/* Define a mapping from our tag to the SCB. */
1109b95de6daSJustin T. Gibbs 		ahc->scb_data->scbindex[scb->hscb->tag] = scb;
11106fb77fefSJustin T. Gibbs 		ahc_pause(ahc);
1111717d4247SJustin T. Gibbs 		if ((ahc->flags & AHC_PAGESCBS) == 0)
1112717d4247SJustin T. Gibbs 			ahc_outb(ahc, SCBPTR, scb->hscb->tag);
1113226aa6eaSJustin T. Gibbs 		ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag);
11146fb77fefSJustin T. Gibbs 		ahc_unpause(ahc);
1115717d4247SJustin T. Gibbs 	} else {
1116717d4247SJustin T. Gibbs 		ahc_queue_scb(ahc, scb);
1117717d4247SJustin T. Gibbs 	}
1118717d4247SJustin T. Gibbs }
1119717d4247SJustin T. Gibbs 
1120717d4247SJustin T. Gibbs static void
1121717d4247SJustin T. Gibbs ahc_poll(struct cam_sim *sim)
1122717d4247SJustin T. Gibbs {
1123226aa6eaSJustin T. Gibbs 	struct ahc_softc *ahc;
1124226aa6eaSJustin T. Gibbs 
1125226aa6eaSJustin T. Gibbs 	ahc = (struct ahc_softc *)cam_sim_softc(sim);
1126226aa6eaSJustin T. Gibbs 	ahc_intr(ahc);
1127717d4247SJustin T. Gibbs }
1128717d4247SJustin T. Gibbs 
1129717d4247SJustin T. Gibbs static void
1130717d4247SJustin T. Gibbs ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
1131717d4247SJustin T. Gibbs 	       struct ccb_scsiio *csio, struct scb *scb)
1132717d4247SJustin T. Gibbs {
1133717d4247SJustin T. Gibbs 	struct hardware_scb *hscb;
1134717d4247SJustin T. Gibbs 	struct ccb_hdr *ccb_h;
1135dd0b4fb6SKonstantin Belousov 	int error;
1136717d4247SJustin T. Gibbs 
1137717d4247SJustin T. Gibbs 	hscb = scb->hscb;
1138717d4247SJustin T. Gibbs 	ccb_h = &csio->ccb_h;
1139717d4247SJustin T. Gibbs 
1140cd036e89SJustin T. Gibbs 	csio->resid = 0;
1141cd036e89SJustin T. Gibbs 	csio->sense_resid = 0;
1142717d4247SJustin T. Gibbs 	if (ccb_h->func_code == XPT_SCSI_IO) {
1143717d4247SJustin T. Gibbs 		hscb->cdb_len = csio->cdb_len;
1144717d4247SJustin T. Gibbs 		if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
1145717d4247SJustin T. Gibbs 			if (hscb->cdb_len > sizeof(hscb->cdb32)
1146717d4247SJustin T. Gibbs 			 || (ccb_h->flags & CAM_CDB_PHYS) != 0) {
1147b3b25f2cSJustin T. Gibbs 				aic_set_transaction_status(scb,
1148717d4247SJustin T. Gibbs 							   CAM_REQ_INVALID);
1149717d4247SJustin T. Gibbs 				ahc_free_scb(ahc, scb);
1150a49630acSJustin T. Gibbs 				xpt_done((union ccb *)csio);
1151717d4247SJustin T. Gibbs 				return;
1152717d4247SJustin T. Gibbs 			}
1153717d4247SJustin T. Gibbs 			if (hscb->cdb_len > 12) {
1154717d4247SJustin T. Gibbs 				memcpy(hscb->cdb32,
1155717d4247SJustin T. Gibbs 				       csio->cdb_io.cdb_ptr,
1156717d4247SJustin T. Gibbs 				       hscb->cdb_len);
1157dd1290f0SJustin T. Gibbs 				scb->flags |= SCB_CDB32_PTR;
1158717d4247SJustin T. Gibbs 			} else {
1159717d4247SJustin T. Gibbs 				memcpy(hscb->shared_data.cdb,
1160717d4247SJustin T. Gibbs 				       csio->cdb_io.cdb_ptr,
1161717d4247SJustin T. Gibbs 				       hscb->cdb_len);
1162717d4247SJustin T. Gibbs 			}
1163717d4247SJustin T. Gibbs 		} else {
1164717d4247SJustin T. Gibbs 			if (hscb->cdb_len > 12) {
1165717d4247SJustin T. Gibbs 				memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes,
1166717d4247SJustin T. Gibbs 				       hscb->cdb_len);
1167dd1290f0SJustin T. Gibbs 				scb->flags |= SCB_CDB32_PTR;
1168717d4247SJustin T. Gibbs 			} else {
1169717d4247SJustin T. Gibbs 				memcpy(hscb->shared_data.cdb,
1170717d4247SJustin T. Gibbs 				       csio->cdb_io.cdb_bytes,
1171717d4247SJustin T. Gibbs 				       hscb->cdb_len);
1172717d4247SJustin T. Gibbs 			}
1173717d4247SJustin T. Gibbs 		}
1174717d4247SJustin T. Gibbs 	}
1175717d4247SJustin T. Gibbs 
1176dd0b4fb6SKonstantin Belousov 	error = bus_dmamap_load_ccb(ahc->buffer_dmat,
1177717d4247SJustin T. Gibbs 				    scb->dmamap,
1178dd0b4fb6SKonstantin Belousov 				    (union ccb *)csio,
1179717d4247SJustin T. Gibbs 				    ahc_execute_scb,
1180dd0b4fb6SKonstantin Belousov 				    scb,
1181dd0b4fb6SKonstantin Belousov 				    0);
1182717d4247SJustin T. Gibbs 	if (error == EINPROGRESS) {
1183717d4247SJustin T. Gibbs 		/*
1184717d4247SJustin T. Gibbs 		 * So as to maintain ordering,
1185717d4247SJustin T. Gibbs 		 * freeze the controller queue
1186717d4247SJustin T. Gibbs 		 * until our mapping is
1187717d4247SJustin T. Gibbs 		 * returned.
1188717d4247SJustin T. Gibbs 		 */
1189dd0b4fb6SKonstantin Belousov 		xpt_freeze_simq(sim, /*count*/1);
1190dd0b4fb6SKonstantin Belousov 		scb->io_ctx->ccb_h.status |= CAM_RELEASE_SIMQ;
1191717d4247SJustin T. Gibbs 	}
1192717d4247SJustin T. Gibbs }
1193717d4247SJustin T. Gibbs 
1194717d4247SJustin T. Gibbs static void
1195717d4247SJustin T. Gibbs ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
1196717d4247SJustin T. Gibbs {
1197717d4247SJustin T. Gibbs 	union ccb *abort_ccb;
1198717d4247SJustin T. Gibbs 
1199717d4247SJustin T. Gibbs 	abort_ccb = ccb->cab.abort_ccb;
1200717d4247SJustin T. Gibbs 	switch (abort_ccb->ccb_h.func_code) {
1201717d4247SJustin T. Gibbs 	case XPT_ACCEPT_TARGET_IO:
1202b79dc8a8SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY:
1203717d4247SJustin T. Gibbs 	case XPT_CONT_TARGET_IO:
1204717d4247SJustin T. Gibbs 	{
1205b95de6daSJustin T. Gibbs 		struct ahc_tmode_tstate *tstate;
1206b95de6daSJustin T. Gibbs 		struct ahc_tmode_lstate *lstate;
1207717d4247SJustin T. Gibbs 		struct ccb_hdr_slist *list;
1208717d4247SJustin T. Gibbs 		cam_status status;
1209717d4247SJustin T. Gibbs 
1210717d4247SJustin T. Gibbs 		status = ahc_find_tmode_devs(ahc, sim, abort_ccb, &tstate,
1211717d4247SJustin T. Gibbs 					     &lstate, TRUE);
1212717d4247SJustin T. Gibbs 
1213717d4247SJustin T. Gibbs 		if (status != CAM_REQ_CMP) {
1214717d4247SJustin T. Gibbs 			ccb->ccb_h.status = status;
1215717d4247SJustin T. Gibbs 			break;
1216717d4247SJustin T. Gibbs 		}
1217717d4247SJustin T. Gibbs 
1218717d4247SJustin T. Gibbs 		if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
1219717d4247SJustin T. Gibbs 			list = &lstate->accept_tios;
1220b79dc8a8SKenneth D. Merry 		else if (abort_ccb->ccb_h.func_code == XPT_IMMEDIATE_NOTIFY)
1221717d4247SJustin T. Gibbs 			list = &lstate->immed_notifies;
1222717d4247SJustin T. Gibbs 		else
1223717d4247SJustin T. Gibbs 			list = NULL;
1224717d4247SJustin T. Gibbs 
1225717d4247SJustin T. Gibbs 		if (list != NULL) {
1226717d4247SJustin T. Gibbs 			struct ccb_hdr *curelm;
1227717d4247SJustin T. Gibbs 			int found;
1228717d4247SJustin T. Gibbs 
1229717d4247SJustin T. Gibbs 			curelm = SLIST_FIRST(list);
1230717d4247SJustin T. Gibbs 			found = 0;
1231717d4247SJustin T. Gibbs 			if (curelm == &abort_ccb->ccb_h) {
1232717d4247SJustin T. Gibbs 				found = 1;
1233717d4247SJustin T. Gibbs 				SLIST_REMOVE_HEAD(list, sim_links.sle);
1234717d4247SJustin T. Gibbs 			} else {
1235717d4247SJustin T. Gibbs 				while(curelm != NULL) {
1236717d4247SJustin T. Gibbs 					struct ccb_hdr *nextelm;
1237717d4247SJustin T. Gibbs 
1238717d4247SJustin T. Gibbs 					nextelm =
1239717d4247SJustin T. Gibbs 					    SLIST_NEXT(curelm, sim_links.sle);
1240717d4247SJustin T. Gibbs 
1241717d4247SJustin T. Gibbs 					if (nextelm == &abort_ccb->ccb_h) {
1242717d4247SJustin T. Gibbs 						found = 1;
1243717d4247SJustin T. Gibbs 						SLIST_NEXT(curelm,
1244717d4247SJustin T. Gibbs 							   sim_links.sle) =
1245717d4247SJustin T. Gibbs 						    SLIST_NEXT(nextelm,
1246717d4247SJustin T. Gibbs 							       sim_links.sle);
1247717d4247SJustin T. Gibbs 						break;
1248717d4247SJustin T. Gibbs 					}
1249717d4247SJustin T. Gibbs 					curelm = nextelm;
1250717d4247SJustin T. Gibbs 				}
1251717d4247SJustin T. Gibbs 			}
1252717d4247SJustin T. Gibbs 
1253717d4247SJustin T. Gibbs 			if (found) {
1254717d4247SJustin T. Gibbs 				abort_ccb->ccb_h.status = CAM_REQ_ABORTED;
1255717d4247SJustin T. Gibbs 				xpt_done(abort_ccb);
1256717d4247SJustin T. Gibbs 				ccb->ccb_h.status = CAM_REQ_CMP;
1257717d4247SJustin T. Gibbs 			} else {
1258dd1290f0SJustin T. Gibbs 				xpt_print_path(abort_ccb->ccb_h.path);
1259717d4247SJustin T. Gibbs 				printf("Not found\n");
1260717d4247SJustin T. Gibbs 				ccb->ccb_h.status = CAM_PATH_INVALID;
1261717d4247SJustin T. Gibbs 			}
1262717d4247SJustin T. Gibbs 			break;
1263717d4247SJustin T. Gibbs 		}
1264717d4247SJustin T. Gibbs 		/* FALLTHROUGH */
1265717d4247SJustin T. Gibbs 	}
1266717d4247SJustin T. Gibbs 	case XPT_SCSI_IO:
1267717d4247SJustin T. Gibbs 		/* XXX Fully implement the hard ones */
1268717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_UA_ABORT;
1269717d4247SJustin T. Gibbs 		break;
1270717d4247SJustin T. Gibbs 	default:
1271717d4247SJustin T. Gibbs 		ccb->ccb_h.status = CAM_REQ_INVALID;
1272717d4247SJustin T. Gibbs 		break;
1273717d4247SJustin T. Gibbs 	}
1274717d4247SJustin T. Gibbs 	xpt_done(ccb);
1275717d4247SJustin T. Gibbs }
1276717d4247SJustin T. Gibbs 
1277717d4247SJustin T. Gibbs void
1278c498406dSJustin T. Gibbs ahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
127958fb7d8eSJustin T. Gibbs 		u_int lun, ac_code code, void *opt_arg)
1280717d4247SJustin T. Gibbs {
1281717d4247SJustin T. Gibbs 	struct	ccb_trans_settings cts;
1282717d4247SJustin T. Gibbs 	struct cam_path *path;
1283717d4247SJustin T. Gibbs 	void *arg;
1284717d4247SJustin T. Gibbs 	int error;
1285717d4247SJustin T. Gibbs 
1286717d4247SJustin T. Gibbs 	arg = NULL;
1287c498406dSJustin T. Gibbs 	error = ahc_create_path(ahc, channel, target, lun, &path);
1288717d4247SJustin T. Gibbs 
1289717d4247SJustin T. Gibbs 	if (error != CAM_REQ_CMP)
1290717d4247SJustin T. Gibbs 		return;
1291717d4247SJustin T. Gibbs 
1292717d4247SJustin T. Gibbs 	switch (code) {
1293717d4247SJustin T. Gibbs 	case AC_TRANSFER_NEG:
129458fb7d8eSJustin T. Gibbs 	{
129558fb7d8eSJustin T. Gibbs 		struct	ccb_trans_settings_scsi *scsi;
129658fb7d8eSJustin T. Gibbs 
1297717d4247SJustin T. Gibbs 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
129858fb7d8eSJustin T. Gibbs 		scsi = &cts.proto_specific.scsi;
1299717d4247SJustin T. Gibbs 		cts.ccb_h.path = path;
1300c498406dSJustin T. Gibbs 		cts.ccb_h.target_id = target;
1301c498406dSJustin T. Gibbs 		cts.ccb_h.target_lun = lun;
1302c498406dSJustin T. Gibbs 		ahc_get_tran_settings(ahc, channel == 'A' ? ahc->our_id
1303c498406dSJustin T. Gibbs 							  : ahc->our_id_b,
1304c498406dSJustin T. Gibbs 				      channel, &cts);
1305717d4247SJustin T. Gibbs 		arg = &cts;
130658fb7d8eSJustin T. Gibbs 		scsi->valid &= ~CTS_SCSI_VALID_TQ;
130758fb7d8eSJustin T. Gibbs 		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
130858fb7d8eSJustin T. Gibbs 		if (opt_arg == NULL)
1309717d4247SJustin T. Gibbs 			break;
131058fb7d8eSJustin T. Gibbs 		if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED)
131158fb7d8eSJustin T. Gibbs 			scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
131258fb7d8eSJustin T. Gibbs 		scsi->valid |= CTS_SCSI_VALID_TQ;
131358fb7d8eSJustin T. Gibbs 		break;
131458fb7d8eSJustin T. Gibbs 	}
1315717d4247SJustin T. Gibbs 	case AC_SENT_BDR:
1316717d4247SJustin T. Gibbs 	case AC_BUS_RESET:
1317717d4247SJustin T. Gibbs 		break;
1318717d4247SJustin T. Gibbs 	default:
1319717d4247SJustin T. Gibbs 		panic("ahc_send_async: Unexpected async event");
1320717d4247SJustin T. Gibbs 	}
1321717d4247SJustin T. Gibbs 	xpt_async(code, path, arg);
132247c2d60fSJustin T. Gibbs 	xpt_free_path(path);
1323717d4247SJustin T. Gibbs }
1324717d4247SJustin T. Gibbs 
1325717d4247SJustin T. Gibbs void
1326717d4247SJustin T. Gibbs ahc_platform_set_tags(struct ahc_softc *ahc,
1327717d4247SJustin T. Gibbs 		      struct ahc_devinfo *devinfo, int enable)
1328717d4247SJustin T. Gibbs {
1329717d4247SJustin T. Gibbs }
1330717d4247SJustin T. Gibbs 
1331717d4247SJustin T. Gibbs int
1332717d4247SJustin T. Gibbs ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
1333717d4247SJustin T. Gibbs {
13345417ec4dSDavid Malone 	ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF,
13355417ec4dSDavid Malone 	    M_NOWAIT | M_ZERO);
1336717d4247SJustin T. Gibbs 	if (ahc->platform_data == NULL)
1337717d4247SJustin T. Gibbs 		return (ENOMEM);
1338717d4247SJustin T. Gibbs 	return (0);
1339717d4247SJustin T. Gibbs }
1340717d4247SJustin T. Gibbs 
1341717d4247SJustin T. Gibbs void
1342717d4247SJustin T. Gibbs ahc_platform_free(struct ahc_softc *ahc)
1343717d4247SJustin T. Gibbs {
134456a7c4a8SJustin T. Gibbs 	struct ahc_platform_data *pdata;
1345717d4247SJustin T. Gibbs 
134656a7c4a8SJustin T. Gibbs 	pdata = ahc->platform_data;
134756a7c4a8SJustin T. Gibbs 	if (pdata != NULL) {
134856a7c4a8SJustin T. Gibbs 		if (pdata->regs != NULL)
1349717d4247SJustin T. Gibbs 			bus_release_resource(ahc->dev_softc,
135056a7c4a8SJustin T. Gibbs 					     pdata->regs_res_type,
135156a7c4a8SJustin T. Gibbs 					     pdata->regs_res_id,
135256a7c4a8SJustin T. Gibbs 					     pdata->regs);
1353717d4247SJustin T. Gibbs 
135456a7c4a8SJustin T. Gibbs 		if (pdata->irq != NULL)
135556a7c4a8SJustin T. Gibbs 			bus_release_resource(ahc->dev_softc,
135656a7c4a8SJustin T. Gibbs 					     pdata->irq_res_type,
135756a7c4a8SJustin T. Gibbs 					     0, pdata->irq);
135856a7c4a8SJustin T. Gibbs 
135956a7c4a8SJustin T. Gibbs 		if (pdata->sim_b != NULL) {
136056a7c4a8SJustin T. Gibbs 			xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL);
136156a7c4a8SJustin T. Gibbs 			xpt_free_path(pdata->path_b);
136256a7c4a8SJustin T. Gibbs 			xpt_bus_deregister(cam_sim_path(pdata->sim_b));
136356a7c4a8SJustin T. Gibbs 			cam_sim_free(pdata->sim_b, /*free_devq*/TRUE);
136456a7c4a8SJustin T. Gibbs 		}
136556a7c4a8SJustin T. Gibbs 		if (pdata->sim != NULL) {
136656a7c4a8SJustin T. Gibbs 			xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
136756a7c4a8SJustin T. Gibbs 			xpt_free_path(pdata->path);
136856a7c4a8SJustin T. Gibbs 			xpt_bus_deregister(cam_sim_path(pdata->sim));
136956a7c4a8SJustin T. Gibbs 			cam_sim_free(pdata->sim, /*free_devq*/TRUE);
137056a7c4a8SJustin T. Gibbs 		}
137156a7c4a8SJustin T. Gibbs 		if (pdata->eh != NULL)
137256a7c4a8SJustin T. Gibbs 			EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
1373717d4247SJustin T. Gibbs 		free(ahc->platform_data, M_DEVBUF);
1374717d4247SJustin T. Gibbs 	}
1375717d4247SJustin T. Gibbs }
1376717d4247SJustin T. Gibbs 
1377717d4247SJustin T. Gibbs int
1378717d4247SJustin T. Gibbs ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
1379717d4247SJustin T. Gibbs {
1380717d4247SJustin T. Gibbs 	/* We don't sort softcs under FreeBSD so report equal always */
1381717d4247SJustin T. Gibbs 	return (0);
1382717d4247SJustin T. Gibbs }
1383717d4247SJustin T. Gibbs 
138456a7c4a8SJustin T. Gibbs int
138556a7c4a8SJustin T. Gibbs ahc_detach(device_t dev)
138656a7c4a8SJustin T. Gibbs {
138756a7c4a8SJustin T. Gibbs 	struct ahc_softc *ahc;
138856a7c4a8SJustin T. Gibbs 
138956a7c4a8SJustin T. Gibbs 	device_printf(dev, "detaching device\n");
139056a7c4a8SJustin T. Gibbs 	ahc = device_get_softc(dev);
1391032b0a17SScott Long 	ahc_lock(ahc);
1392b3b25f2cSJustin T. Gibbs 	TAILQ_REMOVE(&ahc_tailq, ahc, links);
1393226aa6eaSJustin T. Gibbs 	ahc_intr_enable(ahc, FALSE);
139456a7c4a8SJustin T. Gibbs 	bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih);
1395032b0a17SScott Long 	ahc_unlock(ahc);
139656a7c4a8SJustin T. Gibbs 	ahc_free(ahc);
139756a7c4a8SJustin T. Gibbs 	return (0);
139856a7c4a8SJustin T. Gibbs }
139956a7c4a8SJustin T. Gibbs 
1400f4e98881SRuslan Ermilov #if 0
1401717d4247SJustin T. Gibbs static void
1402717d4247SJustin T. Gibbs ahc_dump_targcmd(struct target_cmd *cmd)
1403717d4247SJustin T. Gibbs {
1404717d4247SJustin T. Gibbs 	uint8_t *byte;
1405717d4247SJustin T. Gibbs 	uint8_t *last_byte;
1406717d4247SJustin T. Gibbs 	int i;
1407717d4247SJustin T. Gibbs 
1408717d4247SJustin T. Gibbs 	byte = &cmd->initiator_channel;
1409717d4247SJustin T. Gibbs 	/* Debugging info for received commands */
1410717d4247SJustin T. Gibbs 	last_byte = &cmd[1].initiator_channel;
1411717d4247SJustin T. Gibbs 
1412717d4247SJustin T. Gibbs 	i = 0;
1413717d4247SJustin T. Gibbs 	while (byte < last_byte) {
1414717d4247SJustin T. Gibbs 		if (i == 0)
1415717d4247SJustin T. Gibbs 			printf("\t");
1416717d4247SJustin T. Gibbs 		printf("%#x", *byte++);
1417717d4247SJustin T. Gibbs 		i++;
1418717d4247SJustin T. Gibbs 		if (i == 8) {
1419717d4247SJustin T. Gibbs 			printf("\n");
1420717d4247SJustin T. Gibbs 			i = 0;
1421717d4247SJustin T. Gibbs 		} else {
1422717d4247SJustin T. Gibbs 			printf(", ");
1423717d4247SJustin T. Gibbs 		}
1424717d4247SJustin T. Gibbs 	}
1425717d4247SJustin T. Gibbs }
1426717d4247SJustin T. Gibbs #endif
142758fb7d8eSJustin T. Gibbs 
142858fb7d8eSJustin T. Gibbs static int
142958fb7d8eSJustin T. Gibbs ahc_modevent(module_t mod, int type, void *data)
143058fb7d8eSJustin T. Gibbs {
143158fb7d8eSJustin T. Gibbs 	/* XXX Deal with busy status on unload. */
14323e019deaSPoul-Henning Kamp 	/* XXX Deal with unknown events */
143358fb7d8eSJustin T. Gibbs 	return 0;
143458fb7d8eSJustin T. Gibbs }
143558fb7d8eSJustin T. Gibbs 
143658fb7d8eSJustin T. Gibbs static moduledata_t ahc_mod = {
143758fb7d8eSJustin T. Gibbs 	"ahc",
143858fb7d8eSJustin T. Gibbs 	ahc_modevent,
143958fb7d8eSJustin T. Gibbs 	NULL
144058fb7d8eSJustin T. Gibbs };
144158fb7d8eSJustin T. Gibbs 
144258fb7d8eSJustin T. Gibbs DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
144358fb7d8eSJustin T. Gibbs MODULE_DEPEND(ahc, cam, 1, 1, 1);
144458fb7d8eSJustin T. Gibbs MODULE_VERSION(ahc, 1);
1445