xref: /freebsd/sys/dev/ocs_fc/ocs_cam.c (revision a9504d76)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  */
31ef270ab1SKenneth D. Merry 
32ef270ab1SKenneth D. Merry /**
33ef270ab1SKenneth D. Merry  * @defgroup scsi_api_target SCSI Target API
34ef270ab1SKenneth D. Merry  * @defgroup scsi_api_initiator SCSI Initiator API
35ef270ab1SKenneth D. Merry  * @defgroup cam_api Common Access Method (CAM) API
36ef270ab1SKenneth D. Merry  * @defgroup cam_io CAM IO
37ef270ab1SKenneth D. Merry  */
38ef270ab1SKenneth D. Merry 
39ef270ab1SKenneth D. Merry /**
40ef270ab1SKenneth D. Merry  * @file
41ef270ab1SKenneth D. Merry  * Provides CAM functionality.
42ef270ab1SKenneth D. Merry  */
43ef270ab1SKenneth D. Merry 
44ef270ab1SKenneth D. Merry #include "ocs.h"
45ef270ab1SKenneth D. Merry #include "ocs_scsi.h"
46ef270ab1SKenneth D. Merry #include "ocs_device.h"
4770547544SRam Kishore Vegesna #include <sys/sbuf.h>
48ef270ab1SKenneth D. Merry 
49ef270ab1SKenneth D. Merry /* Default IO timeout value for initiators is 30 seconds */
50ef270ab1SKenneth D. Merry #define OCS_CAM_IO_TIMEOUT	30
51ef270ab1SKenneth D. Merry 
52ef270ab1SKenneth D. Merry typedef struct {
53ef270ab1SKenneth D. Merry 	ocs_scsi_sgl_t *sgl;
54ef270ab1SKenneth D. Merry 	uint32_t sgl_max;
55ef270ab1SKenneth D. Merry 	uint32_t sgl_count;
56ef270ab1SKenneth D. Merry 	int32_t rc;
57ef270ab1SKenneth D. Merry } ocs_dmamap_load_arg_t;
58ef270ab1SKenneth D. Merry 
5970547544SRam Kishore Vegesna struct ocs_scsi_status_desc {
6070547544SRam Kishore Vegesna 	ocs_scsi_io_status_e status;
6170547544SRam Kishore Vegesna 	const char *desc;
6270547544SRam Kishore Vegesna } ocs_status_desc[] = {
6370547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_GOOD, "Good" },
6470547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_ABORTED, "Aborted" },
6570547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_ERROR, "Error" },
6670547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_DIF_GUARD_ERROR, "DIF Guard Error" },
6770547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_DIF_REF_TAG_ERROR, "DIF REF Tag Error" },
6870547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_DIF_APP_TAG_ERROR, "DIF App Tag Error" },
6970547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR, "DIF Unknown Error" },
7070547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_PROTOCOL_CRC_ERROR, "Proto CRC Error" },
7170547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_NO_IO, "No IO" },
7270547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_ABORT_IN_PROGRESS, "Abort in Progress" },
7370547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_CHECK_RESPONSE, "Check Response" },
7470547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_COMMAND_TIMEOUT, "Command Timeout" },
7570547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED, "Timed out and Aborted" },
7670547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_SHUTDOWN, "Shutdown" },
7770547544SRam Kishore Vegesna 	{ OCS_SCSI_STATUS_NEXUS_LOST, "Nexus Lost" }
7870547544SRam Kishore Vegesna };
7970547544SRam Kishore Vegesna 
80ef270ab1SKenneth D. Merry static void ocs_action(struct cam_sim *, union ccb *);
81ef270ab1SKenneth D. Merry static void ocs_poll(struct cam_sim *);
82ef270ab1SKenneth D. Merry 
83ef270ab1SKenneth D. Merry static ocs_tgt_resource_t *ocs_tgt_resource_get(ocs_fcport *,
84ef270ab1SKenneth D. Merry 					struct ccb_hdr *, uint32_t *);
85ef270ab1SKenneth D. Merry static int32_t ocs_tgt_resource_abort(struct ocs_softc *, ocs_tgt_resource_t *);
86ef270ab1SKenneth D. Merry static uint32_t ocs_abort_initiator_io(struct ocs_softc *ocs, union ccb *accb);
87ef270ab1SKenneth D. Merry static void ocs_abort_inot(struct ocs_softc *ocs, union ccb *ccb);
88ef270ab1SKenneth D. Merry static void ocs_abort_atio(struct ocs_softc *ocs, union ccb *ccb);
89ef270ab1SKenneth D. Merry static int32_t ocs_target_tmf_cb(ocs_io_t *, ocs_scsi_io_status_e, uint32_t, void *);
90ef270ab1SKenneth D. Merry static int32_t ocs_io_abort_cb(ocs_io_t *, ocs_scsi_io_status_e, uint32_t, void *);
91ef270ab1SKenneth D. Merry static int32_t ocs_task_set_full_or_busy(ocs_io_t *io);
92ef270ab1SKenneth D. Merry static int32_t ocs_initiator_tmf_cb(ocs_io_t *, ocs_scsi_io_status_e,
93ef270ab1SKenneth D. Merry 		ocs_scsi_cmd_resp_t *, uint32_t, void *);
94ef270ab1SKenneth D. Merry static uint32_t
95ef270ab1SKenneth D. Merry ocs_fcp_change_role(struct ocs_softc *ocs, ocs_fcport *fcp, uint32_t new_role);
96ef270ab1SKenneth D. Merry 
976affb8ebSRam Kishore Vegesna static void ocs_ldt(void *arg);
986affb8ebSRam Kishore Vegesna static void ocs_ldt_task(void *arg, int pending);
996affb8ebSRam Kishore Vegesna static void ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt);
1006affb8ebSRam Kishore Vegesna uint32_t ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp);
1016affb8ebSRam Kishore Vegesna uint32_t ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id);
1026affb8ebSRam Kishore Vegesna 
1036affb8ebSRam Kishore Vegesna int32_t ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node);
1046affb8ebSRam Kishore Vegesna 
ocs_scsi_find_io(struct ocs_softc * ocs,uint32_t tag)105ef270ab1SKenneth D. Merry static inline ocs_io_t *ocs_scsi_find_io(struct ocs_softc *ocs, uint32_t tag)
106ef270ab1SKenneth D. Merry {
107ef270ab1SKenneth D. Merry 
108ef270ab1SKenneth D. Merry 	return ocs_io_get_instance(ocs, tag);
109ef270ab1SKenneth D. Merry }
110ef270ab1SKenneth D. Merry 
ocs_target_io_free(ocs_io_t * io)111ef270ab1SKenneth D. Merry static inline void ocs_target_io_free(ocs_io_t *io)
112ef270ab1SKenneth D. Merry {
113ef270ab1SKenneth D. Merry 	io->tgt_io.state = OCS_CAM_IO_FREE;
114ef270ab1SKenneth D. Merry 	io->tgt_io.flags = 0;
115ef270ab1SKenneth D. Merry 	io->tgt_io.app = NULL;
116ef270ab1SKenneth D. Merry 	ocs_scsi_io_complete(io);
117ef270ab1SKenneth D. Merry 	if(io->ocs->io_in_use != 0)
118ef270ab1SKenneth D. Merry 		atomic_subtract_acq_32(&io->ocs->io_in_use, 1);
119ef270ab1SKenneth D. Merry }
120ef270ab1SKenneth D. Merry 
121ef270ab1SKenneth D. Merry static int32_t
ocs_attach_port(ocs_t * ocs,int chan)122ef270ab1SKenneth D. Merry ocs_attach_port(ocs_t *ocs, int chan)
123ef270ab1SKenneth D. Merry {
124ef270ab1SKenneth D. Merry 
125ef270ab1SKenneth D. Merry 	struct cam_sim	*sim = NULL;
126ef270ab1SKenneth D. Merry 	struct cam_path	*path = NULL;
127ef270ab1SKenneth D. Merry 	uint32_t	max_io = ocs_scsi_get_property(ocs, OCS_SCSI_MAX_IOS);
128ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = FCPORT(ocs, chan);
129ef270ab1SKenneth D. Merry 
130ef270ab1SKenneth D. Merry 	if (NULL == (sim = cam_sim_alloc(ocs_action, ocs_poll,
131ef270ab1SKenneth D. Merry 				device_get_name(ocs->dev), ocs,
132ef270ab1SKenneth D. Merry 				device_get_unit(ocs->dev), &ocs->sim_lock,
133ef270ab1SKenneth D. Merry 				max_io, max_io, ocs->devq))) {
134ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Can't allocate SIM\n");
135ef270ab1SKenneth D. Merry 		return 1;
136ef270ab1SKenneth D. Merry 	}
137ef270ab1SKenneth D. Merry 
138ef270ab1SKenneth D. Merry 	mtx_lock(&ocs->sim_lock);
139ef270ab1SKenneth D. Merry 	if (CAM_SUCCESS != xpt_bus_register(sim, ocs->dev, chan)) {
140ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Can't register bus %d\n", 0);
141ef270ab1SKenneth D. Merry 		mtx_unlock(&ocs->sim_lock);
142ef270ab1SKenneth D. Merry 		cam_sim_free(sim, FALSE);
143ef270ab1SKenneth D. Merry 		return 1;
144ef270ab1SKenneth D. Merry 	}
145ef270ab1SKenneth D. Merry 	mtx_unlock(&ocs->sim_lock);
146ef270ab1SKenneth D. Merry 
147ef270ab1SKenneth D. Merry 	if (CAM_REQ_CMP != xpt_create_path(&path, NULL, cam_sim_path(sim),
148ef270ab1SKenneth D. Merry 				CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)) {
149ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Can't create path\n");
150ef270ab1SKenneth D. Merry 		xpt_bus_deregister(cam_sim_path(sim));
151ef270ab1SKenneth D. Merry 		mtx_unlock(&ocs->sim_lock);
152ef270ab1SKenneth D. Merry 		cam_sim_free(sim, FALSE);
153ef270ab1SKenneth D. Merry 		return 1;
154ef270ab1SKenneth D. Merry 	}
155ef270ab1SKenneth D. Merry 
1566affb8ebSRam Kishore Vegesna 	fcp->ocs = ocs;
157ef270ab1SKenneth D. Merry 	fcp->sim  = sim;
158ef270ab1SKenneth D. Merry 	fcp->path = path;
159ef270ab1SKenneth D. Merry 
1606affb8ebSRam Kishore Vegesna 	callout_init_mtx(&fcp->ldt, &ocs->sim_lock, 0);
1616affb8ebSRam Kishore Vegesna 	TASK_INIT(&fcp->ltask, 1, ocs_ldt_task, fcp);
162ef270ab1SKenneth D. Merry 
1636affb8ebSRam Kishore Vegesna 	return 0;
164ef270ab1SKenneth D. Merry }
165ef270ab1SKenneth D. Merry 
166ef270ab1SKenneth D. Merry static int32_t
ocs_detach_port(ocs_t * ocs,int32_t chan)167ef270ab1SKenneth D. Merry ocs_detach_port(ocs_t *ocs, int32_t chan)
168ef270ab1SKenneth D. Merry {
169ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = NULL;
170ef270ab1SKenneth D. Merry 	struct cam_sim	*sim = NULL;
171ef270ab1SKenneth D. Merry 	struct cam_path	*path = NULL;
172ef270ab1SKenneth D. Merry 	fcp = FCPORT(ocs, chan);
173ef270ab1SKenneth D. Merry 
174ef270ab1SKenneth D. Merry 	sim = fcp->sim;
175ef270ab1SKenneth D. Merry 	path = fcp->path;
176ef270ab1SKenneth D. Merry 
1776affb8ebSRam Kishore Vegesna 	callout_drain(&fcp->ldt);
1786affb8ebSRam Kishore Vegesna 	ocs_ldt_task(fcp, 0);
1796affb8ebSRam Kishore Vegesna 
180ef270ab1SKenneth D. Merry 	if (fcp->sim) {
181ef270ab1SKenneth D. Merry 		mtx_lock(&ocs->sim_lock);
182ef270ab1SKenneth D. Merry 			ocs_tgt_resource_abort(ocs, &fcp->targ_rsrc_wildcard);
183ef270ab1SKenneth D. Merry 			if (path) {
184ef270ab1SKenneth D. Merry 				xpt_async(AC_LOST_DEVICE, path, NULL);
185ef270ab1SKenneth D. Merry 				xpt_free_path(path);
186ef270ab1SKenneth D. Merry 				fcp->path = NULL;
187ef270ab1SKenneth D. Merry 			}
188ef270ab1SKenneth D. Merry 			xpt_bus_deregister(cam_sim_path(sim));
189ef270ab1SKenneth D. Merry 
190ef270ab1SKenneth D. Merry 			cam_sim_free(sim, FALSE);
191ef270ab1SKenneth D. Merry 			fcp->sim = NULL;
192ef270ab1SKenneth D. Merry 		mtx_unlock(&ocs->sim_lock);
193ef270ab1SKenneth D. Merry 	}
194ef270ab1SKenneth D. Merry 
195ef270ab1SKenneth D. Merry 	return 0;
196ef270ab1SKenneth D. Merry }
197ef270ab1SKenneth D. Merry 
198ef270ab1SKenneth D. Merry int32_t
ocs_cam_attach(ocs_t * ocs)199ef270ab1SKenneth D. Merry ocs_cam_attach(ocs_t *ocs)
200ef270ab1SKenneth D. Merry {
201ef270ab1SKenneth D. Merry 	struct cam_devq	*devq = NULL;
202ef270ab1SKenneth D. Merry 	int	i = 0;
203ef270ab1SKenneth D. Merry 	uint32_t	max_io = ocs_scsi_get_property(ocs, OCS_SCSI_MAX_IOS);
204ef270ab1SKenneth D. Merry 
205ef270ab1SKenneth D. Merry 	if (NULL == (devq = cam_simq_alloc(max_io))) {
206ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "Can't allocate SIMQ\n");
207ef270ab1SKenneth D. Merry 		return -1;
208ef270ab1SKenneth D. Merry 	}
209ef270ab1SKenneth D. Merry 
210ef270ab1SKenneth D. Merry 	ocs->devq = devq;
211ef270ab1SKenneth D. Merry 
212ef270ab1SKenneth D. Merry 	if (mtx_initialized(&ocs->sim_lock) == 0) {
213ef270ab1SKenneth D. Merry 		mtx_init(&ocs->sim_lock, "ocs_sim_lock", NULL, MTX_DEF);
214ef270ab1SKenneth D. Merry 	}
215ef270ab1SKenneth D. Merry 
216ef270ab1SKenneth D. Merry 	for (i = 0; i < (ocs->num_vports + 1); i++) {
217ef270ab1SKenneth D. Merry 		if (ocs_attach_port(ocs, i)) {
218ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "Attach port failed for chan: %d\n", i);
219ef270ab1SKenneth D. Merry 			goto detach_port;
220ef270ab1SKenneth D. Merry 		}
221ef270ab1SKenneth D. Merry 	}
222ef270ab1SKenneth D. Merry 
223ef270ab1SKenneth D. Merry 	ocs->io_high_watermark = max_io;
224ef270ab1SKenneth D. Merry 	ocs->io_in_use = 0;
225ef270ab1SKenneth D. Merry 	return 0;
226ef270ab1SKenneth D. Merry 
227ef270ab1SKenneth D. Merry detach_port:
228ef270ab1SKenneth D. Merry 	while (--i >= 0) {
229ef270ab1SKenneth D. Merry 		ocs_detach_port(ocs, i);
230ef270ab1SKenneth D. Merry 	}
231ef270ab1SKenneth D. Merry 
232ef270ab1SKenneth D. Merry 	cam_simq_free(ocs->devq);
233ef270ab1SKenneth D. Merry 
234ef270ab1SKenneth D. Merry 	if (mtx_initialized(&ocs->sim_lock))
235ef270ab1SKenneth D. Merry 		mtx_destroy(&ocs->sim_lock);
236ef270ab1SKenneth D. Merry 
237ef270ab1SKenneth D. Merry 	return 1;
238ef270ab1SKenneth D. Merry }
239ef270ab1SKenneth D. Merry 
240ef270ab1SKenneth D. Merry int32_t
ocs_cam_detach(ocs_t * ocs)241ef270ab1SKenneth D. Merry ocs_cam_detach(ocs_t *ocs)
242ef270ab1SKenneth D. Merry {
243ef270ab1SKenneth D. Merry 	int i = 0;
244ef270ab1SKenneth D. Merry 
245ef270ab1SKenneth D. Merry 	for (i = (ocs->num_vports); i >= 0; i--) {
246ef270ab1SKenneth D. Merry 		ocs_detach_port(ocs, i);
247ef270ab1SKenneth D. Merry 	}
248ef270ab1SKenneth D. Merry 
249ef270ab1SKenneth D. Merry 	cam_simq_free(ocs->devq);
250ef270ab1SKenneth D. Merry 
251ef270ab1SKenneth D. Merry 	if (mtx_initialized(&ocs->sim_lock))
252ef270ab1SKenneth D. Merry 		mtx_destroy(&ocs->sim_lock);
253ef270ab1SKenneth D. Merry 
254ef270ab1SKenneth D. Merry 	return 0;
255ef270ab1SKenneth D. Merry }
256ef270ab1SKenneth D. Merry 
257ef270ab1SKenneth D. Merry /***************************************************************************
258ef270ab1SKenneth D. Merry  * Functions required by SCSI base driver API
259ef270ab1SKenneth D. Merry  */
260ef270ab1SKenneth D. Merry 
261ef270ab1SKenneth D. Merry /**
262ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
263ef270ab1SKenneth D. Merry  * @brief Attach driver to the BSD SCSI layer (a.k.a CAM)
264ef270ab1SKenneth D. Merry  *
265ef270ab1SKenneth D. Merry  * Allocates + initializes CAM related resources and attaches to the CAM
266ef270ab1SKenneth D. Merry  *
267ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
268ef270ab1SKenneth D. Merry  *
269ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
270ef270ab1SKenneth D. Merry  */
271ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_new_device(ocs_t * ocs)272ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_device(ocs_t *ocs)
273ef270ab1SKenneth D. Merry {
274ef270ab1SKenneth D. Merry 	ocs->enable_task_set_full = ocs_scsi_get_property(ocs,
275ef270ab1SKenneth D. Merry 					OCS_SCSI_ENABLE_TASK_SET_FULL);
276ef270ab1SKenneth D. Merry 	ocs_log_debug(ocs, "task set full processing is %s\n",
277ef270ab1SKenneth D. Merry 		ocs->enable_task_set_full ? "enabled" : "disabled");
278ef270ab1SKenneth D. Merry 
279ef270ab1SKenneth D. Merry 	return 0;
280ef270ab1SKenneth D. Merry }
281ef270ab1SKenneth D. Merry 
282ef270ab1SKenneth D. Merry /**
283ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
284ef270ab1SKenneth D. Merry  * @brief Tears down target members of ocs structure.
285ef270ab1SKenneth D. Merry  *
286ef270ab1SKenneth D. Merry  * Called by OS code when device is removed.
287ef270ab1SKenneth D. Merry  *
288ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs
289ef270ab1SKenneth D. Merry  *
290ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
291ef270ab1SKenneth D. Merry  */
292ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_del_device(ocs_t * ocs)293ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_device(ocs_t *ocs)
294ef270ab1SKenneth D. Merry {
295ef270ab1SKenneth D. Merry 
296ef270ab1SKenneth D. Merry 	return 0;
297ef270ab1SKenneth D. Merry }
298ef270ab1SKenneth D. Merry 
299ef270ab1SKenneth D. Merry /**
300ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
301ef270ab1SKenneth D. Merry  * @brief accept new domain notification
302ef270ab1SKenneth D. Merry  *
303ef270ab1SKenneth D. Merry  * Called by base drive when new domain is discovered.  A target-server
304ef270ab1SKenneth D. Merry  * will use this call to prepare for new remote node notifications
305ef270ab1SKenneth D. Merry  * arising from ocs_scsi_new_initiator().
306ef270ab1SKenneth D. Merry  *
307ef270ab1SKenneth D. Merry  * The domain context has an element <b>ocs_scsi_tgt_domain_t tgt_domain</b>
308ef270ab1SKenneth D. Merry  * which is declared by the target-server code and is used for target-server
309ef270ab1SKenneth D. Merry  * private data.
310ef270ab1SKenneth D. Merry  *
311ef270ab1SKenneth D. Merry  * This function will only be called if the base-driver has been enabled for
312ef270ab1SKenneth D. Merry  * target capability.
313ef270ab1SKenneth D. Merry  *
314ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
315ef270ab1SKenneth D. Merry  * the ocs_scsi_ini_new_domain() function is called to initiator-client backends.
316ef270ab1SKenneth D. Merry  *
317ef270ab1SKenneth D. Merry  * @param domain pointer to domain
318ef270ab1SKenneth D. Merry  *
319ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
320ef270ab1SKenneth D. Merry  */
321ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_new_domain(ocs_domain_t * domain)322ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_domain(ocs_domain_t *domain)
323ef270ab1SKenneth D. Merry {
324ef270ab1SKenneth D. Merry 	return 0;
325ef270ab1SKenneth D. Merry }
326ef270ab1SKenneth D. Merry 
327ef270ab1SKenneth D. Merry /**
328ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
329ef270ab1SKenneth D. Merry  * @brief accept domain lost notification
330ef270ab1SKenneth D. Merry  *
331ef270ab1SKenneth D. Merry  * Called by base-driver when a domain goes away.  A target-server will
332ef270ab1SKenneth D. Merry  * use this call to clean up all domain scoped resources.
333ef270ab1SKenneth D. Merry  *
334ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
335ef270ab1SKenneth D. Merry  * the ocs_scsi_ini_del_domain() function is called to initiator-client backends.
336ef270ab1SKenneth D. Merry  *
337ef270ab1SKenneth D. Merry  * @param domain pointer to domain
338ef270ab1SKenneth D. Merry  *
339ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
340ef270ab1SKenneth D. Merry  */
341ef270ab1SKenneth D. Merry void
ocs_scsi_tgt_del_domain(ocs_domain_t * domain)342ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_domain(ocs_domain_t *domain)
343ef270ab1SKenneth D. Merry {
344ef270ab1SKenneth D. Merry }
345ef270ab1SKenneth D. Merry 
346ef270ab1SKenneth D. Merry /**
347ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
348ef270ab1SKenneth D. Merry  * @brief accept new sli port (sport) notification
349ef270ab1SKenneth D. Merry  *
350ef270ab1SKenneth D. Merry  * Called by base drive when new sport is discovered.  A target-server
351ef270ab1SKenneth D. Merry  * will use this call to prepare for new remote node notifications
352ef270ab1SKenneth D. Merry  * arising from ocs_scsi_new_initiator().
353ef270ab1SKenneth D. Merry  *
354ef270ab1SKenneth D. Merry  * The domain context has an element <b>ocs_scsi_tgt_sport_t tgt_sport</b>
355ef270ab1SKenneth D. Merry  * which is declared by the target-server code and is used for
356ef270ab1SKenneth D. Merry  * target-server private data.
357ef270ab1SKenneth D. Merry  *
358ef270ab1SKenneth D. Merry  * This function will only be called if the base-driver has been enabled for
359ef270ab1SKenneth D. Merry  * target capability.
360ef270ab1SKenneth D. Merry  *
361ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
362ef270ab1SKenneth D. Merry  * the ocs_scsi_tgt_new_domain() is called to initiator-client backends.
363ef270ab1SKenneth D. Merry  *
364ef270ab1SKenneth D. Merry  * @param sport pointer to SLI port
365ef270ab1SKenneth D. Merry  *
366ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
367ef270ab1SKenneth D. Merry  */
368ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_new_sport(ocs_sport_t * sport)369ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_sport(ocs_sport_t *sport)
370ef270ab1SKenneth D. Merry {
371ef270ab1SKenneth D. Merry 	ocs_t *ocs = sport->ocs;
372ef270ab1SKenneth D. Merry 
373ef270ab1SKenneth D. Merry 	if(!sport->is_vport) {
374ef270ab1SKenneth D. Merry 		sport->tgt_data = FCPORT(ocs, 0);
375ef270ab1SKenneth D. Merry 	}
376ef270ab1SKenneth D. Merry 
377ef270ab1SKenneth D. Merry 	return 0;
378ef270ab1SKenneth D. Merry }
379ef270ab1SKenneth D. Merry 
380ef270ab1SKenneth D. Merry /**
381ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
382ef270ab1SKenneth D. Merry  * @brief accept SLI port gone notification
383ef270ab1SKenneth D. Merry  *
384ef270ab1SKenneth D. Merry  * Called by base-driver when a sport goes away.  A target-server will
385ef270ab1SKenneth D. Merry  * use this call to clean up all sport scoped resources.
386ef270ab1SKenneth D. Merry  *
387ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
388ef270ab1SKenneth D. Merry  * the ocs_scsi_ini_del_sport() is called to initiator-client backends.
389ef270ab1SKenneth D. Merry  *
390ef270ab1SKenneth D. Merry  * @param sport pointer to SLI port
391ef270ab1SKenneth D. Merry  *
392ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
393ef270ab1SKenneth D. Merry  */
394ef270ab1SKenneth D. Merry void
ocs_scsi_tgt_del_sport(ocs_sport_t * sport)395ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_sport(ocs_sport_t *sport)
396ef270ab1SKenneth D. Merry {
397ef270ab1SKenneth D. Merry 	return;
398ef270ab1SKenneth D. Merry }
399ef270ab1SKenneth D. Merry 
400ef270ab1SKenneth D. Merry /**
401ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
402ef270ab1SKenneth D. Merry  * @brief receive notification of a new SCSI initiator node
403ef270ab1SKenneth D. Merry  *
404ef270ab1SKenneth D. Merry  * Sent by base driver to notify a target-server of the presense of a new
405ef270ab1SKenneth D. Merry  * remote initiator.   The target-server may use this call to prepare for
406ef270ab1SKenneth D. Merry  * inbound IO from this node.
407ef270ab1SKenneth D. Merry  *
408ef270ab1SKenneth D. Merry  * The ocs_node_t structure has and elment of type ocs_scsi_tgt_node_t named
409ef270ab1SKenneth D. Merry  * tgt_node that is declared and used by a target-server for private
410ef270ab1SKenneth D. Merry  * information.
411ef270ab1SKenneth D. Merry  *
412ef270ab1SKenneth D. Merry  * This function is only called if the target capability is enabled in driver.
413ef270ab1SKenneth D. Merry  *
414ef270ab1SKenneth D. Merry  * @param node pointer to new remote initiator node
415ef270ab1SKenneth D. Merry  *
416ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
417ef270ab1SKenneth D. Merry  *
418ef270ab1SKenneth D. Merry  * @note
419ef270ab1SKenneth D. Merry  */
420ef270ab1SKenneth D. Merry int32_t
ocs_scsi_new_initiator(ocs_node_t * node)421ef270ab1SKenneth D. Merry ocs_scsi_new_initiator(ocs_node_t *node)
422ef270ab1SKenneth D. Merry {
423ef270ab1SKenneth D. Merry 	ocs_t	*ocs = node->ocs;
424ef270ab1SKenneth D. Merry 	struct ac_contract ac;
425ef270ab1SKenneth D. Merry 	struct ac_device_changed *adc;
426ef270ab1SKenneth D. Merry 
427ef270ab1SKenneth D. Merry 	ocs_fcport	*fcp = NULL;
428ef270ab1SKenneth D. Merry 
429ef270ab1SKenneth D. Merry 	fcp = node->sport->tgt_data;
430ef270ab1SKenneth D. Merry 	if (fcp == NULL) {
431ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "FCP is NULL \n");
432ef270ab1SKenneth D. Merry 		return 1;
433ef270ab1SKenneth D. Merry 	}
434ef270ab1SKenneth D. Merry 
435ef270ab1SKenneth D. Merry 	/*
436ef270ab1SKenneth D. Merry 	 * Update the IO watermark by decrementing it by the
437ef270ab1SKenneth D. Merry 	 * number of IOs reserved for each initiator.
438ef270ab1SKenneth D. Merry 	 */
439ef270ab1SKenneth D. Merry 	atomic_subtract_acq_32(&ocs->io_high_watermark, OCS_RSVD_INI_IO);
440ef270ab1SKenneth D. Merry 
441ef270ab1SKenneth D. Merry 	ac.contract_number = AC_CONTRACT_DEV_CHG;
442ef270ab1SKenneth D. Merry 	adc = (struct ac_device_changed *) ac.contract_data;
443ef270ab1SKenneth D. Merry 	adc->wwpn = ocs_node_get_wwpn(node);
444ef270ab1SKenneth D. Merry 	adc->port = node->rnode.fc_id;
445ef270ab1SKenneth D. Merry 	adc->target = node->instance_index;
446ef270ab1SKenneth D. Merry 	adc->arrived = 1;
447ef270ab1SKenneth D. Merry 	xpt_async(AC_CONTRACT, fcp->path, &ac);
448ef270ab1SKenneth D. Merry 
449ef270ab1SKenneth D. Merry 	return 0;
450ef270ab1SKenneth D. Merry }
451ef270ab1SKenneth D. Merry 
452ef270ab1SKenneth D. Merry /**
453ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
454ef270ab1SKenneth D. Merry  * @brief validate new initiator
455ef270ab1SKenneth D. Merry  *
456ef270ab1SKenneth D. Merry  * Sent by base driver to validate a remote initiatiator.   The target-server
457ef270ab1SKenneth D. Merry  * returns TRUE if this initiator should be accepted.
458ef270ab1SKenneth D. Merry  *
459ef270ab1SKenneth D. Merry  * This function is only called if the target capability is enabled in driver.
460ef270ab1SKenneth D. Merry  *
461ef270ab1SKenneth D. Merry  * @param node pointer to remote initiator node to validate
462ef270ab1SKenneth D. Merry  *
463ef270ab1SKenneth D. Merry  * @return TRUE if initiator should be accepted, FALSE if it should be rejected
464ef270ab1SKenneth D. Merry  *
465ef270ab1SKenneth D. Merry  * @note
466ef270ab1SKenneth D. Merry  */
467ef270ab1SKenneth D. Merry 
468ef270ab1SKenneth D. Merry int32_t
ocs_scsi_validate_initiator(ocs_node_t * node)469ef270ab1SKenneth D. Merry ocs_scsi_validate_initiator(ocs_node_t *node)
470ef270ab1SKenneth D. Merry {
471ef270ab1SKenneth D. Merry 	return 1;
472ef270ab1SKenneth D. Merry }
473ef270ab1SKenneth D. Merry 
474ef270ab1SKenneth D. Merry /**
475ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
476ef270ab1SKenneth D. Merry  * @brief Delete a SCSI initiator node
477ef270ab1SKenneth D. Merry  *
478ef270ab1SKenneth D. Merry  * Sent by base driver to notify a target-server that a remote initiator
479ef270ab1SKenneth D. Merry  * is now gone. The base driver will have terminated all outstanding IOs
480ef270ab1SKenneth D. Merry  * and the target-server will receive appropriate completions.
481ef270ab1SKenneth D. Merry  *
482ef270ab1SKenneth D. Merry  * This function is only called if the base driver is enabled for
483ef270ab1SKenneth D. Merry  * target capability.
484ef270ab1SKenneth D. Merry  *
485ef270ab1SKenneth D. Merry  * @param node pointer node being deleted
486ef270ab1SKenneth D. Merry  * @param reason Reason why initiator is gone.
487ef270ab1SKenneth D. Merry  *
488ef270ab1SKenneth D. Merry  * @return OCS_SCSI_CALL_COMPLETE to indicate that all work was completed
489ef270ab1SKenneth D. Merry  *
490ef270ab1SKenneth D. Merry  * @note
491ef270ab1SKenneth D. Merry  */
492ef270ab1SKenneth D. Merry int32_t
ocs_scsi_del_initiator(ocs_node_t * node,ocs_scsi_del_initiator_reason_e reason)493ef270ab1SKenneth D. Merry ocs_scsi_del_initiator(ocs_node_t *node, ocs_scsi_del_initiator_reason_e reason)
494ef270ab1SKenneth D. Merry {
495ef270ab1SKenneth D. Merry 	ocs_t	*ocs = node->ocs;
496ef270ab1SKenneth D. Merry 
497ef270ab1SKenneth D. Merry 	struct ac_contract ac;
498ef270ab1SKenneth D. Merry 	struct ac_device_changed *adc;
499ef270ab1SKenneth D. Merry 	ocs_fcport	*fcp = NULL;
500ef270ab1SKenneth D. Merry 
501ef270ab1SKenneth D. Merry 	fcp = node->sport->tgt_data;
502ef270ab1SKenneth D. Merry 	if (fcp == NULL) {
503ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "FCP is NULL \n");
504ef270ab1SKenneth D. Merry 		return 1;
505ef270ab1SKenneth D. Merry 	}
506ef270ab1SKenneth D. Merry 
507ef270ab1SKenneth D. Merry 	ac.contract_number = AC_CONTRACT_DEV_CHG;
508ef270ab1SKenneth D. Merry 	adc = (struct ac_device_changed *) ac.contract_data;
509ef270ab1SKenneth D. Merry 	adc->wwpn = ocs_node_get_wwpn(node);
510ef270ab1SKenneth D. Merry 	adc->port = node->rnode.fc_id;
511ef270ab1SKenneth D. Merry 	adc->target = node->instance_index;
512ef270ab1SKenneth D. Merry 	adc->arrived = 0;
513ef270ab1SKenneth D. Merry 	xpt_async(AC_CONTRACT, fcp->path, &ac);
514ef270ab1SKenneth D. Merry 
515ef270ab1SKenneth D. Merry 	if (reason == OCS_SCSI_INITIATOR_MISSING) {
516ef270ab1SKenneth D. Merry 		return OCS_SCSI_CALL_COMPLETE;
517ef270ab1SKenneth D. Merry 	}
518ef270ab1SKenneth D. Merry 
519ef270ab1SKenneth D. Merry 	/*
520ef270ab1SKenneth D. Merry 	 * Update the IO watermark by incrementing it by the
521ef270ab1SKenneth D. Merry 	 * number of IOs reserved for each initiator.
522ef270ab1SKenneth D. Merry 	 */
523ef270ab1SKenneth D. Merry 	atomic_add_acq_32(&ocs->io_high_watermark, OCS_RSVD_INI_IO);
524ef270ab1SKenneth D. Merry 
525ef270ab1SKenneth D. Merry 	return OCS_SCSI_CALL_COMPLETE;
526ef270ab1SKenneth D. Merry }
527ef270ab1SKenneth D. Merry 
528ef270ab1SKenneth D. Merry /**
529ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
530ef270ab1SKenneth D. Merry  * @brief receive FCP SCSI Command
531ef270ab1SKenneth D. Merry  *
532ef270ab1SKenneth D. Merry  * Called by the base driver when a new SCSI command has been received.   The
533ef270ab1SKenneth D. Merry  * target-server will process the command, and issue data and/or response phase
534ef270ab1SKenneth D. Merry  * requests to the base driver.
535ef270ab1SKenneth D. Merry  *
536ef270ab1SKenneth D. Merry  * The IO context (ocs_io_t) structure has and element of type
537ef270ab1SKenneth D. Merry  * ocs_scsi_tgt_io_t named tgt_io that is declared and used by
538ef270ab1SKenneth D. Merry  * a target-server for private information.
539ef270ab1SKenneth D. Merry  *
540ef270ab1SKenneth D. Merry  * @param io pointer to IO context
541ef270ab1SKenneth D. Merry  * @param lun LUN for this IO
542ef270ab1SKenneth D. Merry  * @param cdb pointer to SCSI CDB
543ef270ab1SKenneth D. Merry  * @param cdb_len length of CDB in bytes
544ef270ab1SKenneth D. Merry  * @param flags command flags
545ef270ab1SKenneth D. Merry  *
546ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
547ef270ab1SKenneth D. Merry  */
ocs_scsi_recv_cmd(ocs_io_t * io,uint64_t lun,uint8_t * cdb,uint32_t cdb_len,uint32_t flags)548ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint64_t lun, uint8_t *cdb,
549ef270ab1SKenneth D. Merry 				uint32_t cdb_len, uint32_t flags)
550ef270ab1SKenneth D. Merry {
551ef270ab1SKenneth D. Merry 	ocs_t *ocs = io->ocs;
552ef270ab1SKenneth D. Merry 	struct ccb_accept_tio *atio = NULL;
553ef270ab1SKenneth D. Merry 	ocs_node_t	*node = io->node;
554ef270ab1SKenneth D. Merry 	ocs_tgt_resource_t *trsrc = NULL;
555ef270ab1SKenneth D. Merry 	int32_t		rc = -1;
556ef270ab1SKenneth D. Merry 	ocs_fcport	*fcp = NULL;
557ef270ab1SKenneth D. Merry 
558ef270ab1SKenneth D. Merry 	fcp = node->sport->tgt_data;
559ef270ab1SKenneth D. Merry 	if (fcp == NULL) {
560ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "FCP is NULL \n");
561ef270ab1SKenneth D. Merry 		return 1;
562ef270ab1SKenneth D. Merry 	}
563ef270ab1SKenneth D. Merry 
564ef270ab1SKenneth D. Merry 	atomic_add_acq_32(&ocs->io_in_use, 1);
565ef270ab1SKenneth D. Merry 
566ef270ab1SKenneth D. Merry 	/* set target io timeout */
567ef270ab1SKenneth D. Merry 	io->timeout = ocs->target_io_timer_sec;
568ef270ab1SKenneth D. Merry 
569ef270ab1SKenneth D. Merry 	if (ocs->enable_task_set_full &&
570ef270ab1SKenneth D. Merry 		(ocs->io_in_use >= ocs->io_high_watermark)) {
571ef270ab1SKenneth D. Merry 		return ocs_task_set_full_or_busy(io);
572ef270ab1SKenneth D. Merry 	} else {
573ef270ab1SKenneth D. Merry 		atomic_store_rel_32(&io->node->tgt_node.busy_sent, FALSE);
574ef270ab1SKenneth D. Merry 	}
575ef270ab1SKenneth D. Merry 
576ef270ab1SKenneth D. Merry 	if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) {
577ef270ab1SKenneth D. Merry 		trsrc = &fcp->targ_rsrc[lun];
578ef270ab1SKenneth D. Merry 	} else if (fcp->targ_rsrc_wildcard.enabled) {
579ef270ab1SKenneth D. Merry 		trsrc = &fcp->targ_rsrc_wildcard;
580ef270ab1SKenneth D. Merry 	}
581ef270ab1SKenneth D. Merry 
582ef270ab1SKenneth D. Merry 	if (trsrc) {
583ef270ab1SKenneth D. Merry 		atio = (struct ccb_accept_tio *)STAILQ_FIRST(&trsrc->atio);
584ef270ab1SKenneth D. Merry 	}
585ef270ab1SKenneth D. Merry 
586ef270ab1SKenneth D. Merry 	if (atio) {
587ef270ab1SKenneth D. Merry 		STAILQ_REMOVE_HEAD(&trsrc->atio, sim_links.stqe);
588ef270ab1SKenneth D. Merry 
589ef270ab1SKenneth D. Merry 		atio->ccb_h.status = CAM_CDB_RECVD;
590ef270ab1SKenneth D. Merry 		atio->ccb_h.target_lun = lun;
591ef270ab1SKenneth D. Merry 		atio->sense_len = 0;
592ef270ab1SKenneth D. Merry 
593ef270ab1SKenneth D. Merry 		atio->init_id = node->instance_index;
594ef270ab1SKenneth D. Merry 		atio->tag_id = io->tag;
595ef270ab1SKenneth D. Merry 		atio->ccb_h.ccb_io_ptr = io;
596ef270ab1SKenneth D. Merry 
597ef270ab1SKenneth D. Merry 		if (flags & OCS_SCSI_CMD_SIMPLE)
598ef270ab1SKenneth D. Merry 			atio->tag_action = MSG_SIMPLE_Q_TAG;
599eb5a54f8SAlexander Motin 		else if (flags & OCS_SCSI_CMD_HEAD_OF_QUEUE)
600ef270ab1SKenneth D. Merry 			atio->tag_action = MSG_HEAD_OF_Q_TAG;
601eb5a54f8SAlexander Motin 		else if (flags & OCS_SCSI_CMD_ORDERED)
602ef270ab1SKenneth D. Merry 			atio->tag_action = MSG_ORDERED_Q_TAG;
60388364968SAlexander Motin 		else if (flags & OCS_SCSI_CMD_ACA)
60488364968SAlexander Motin 			atio->tag_action = MSG_ACA_TASK;
605ef270ab1SKenneth D. Merry 		else
60688364968SAlexander Motin 			atio->tag_action = CAM_TAG_ACTION_NONE;
60788364968SAlexander Motin 		atio->priority = (flags & OCS_SCSI_PRIORITY_MASK) >>
60888364968SAlexander Motin 		    OCS_SCSI_PRIORITY_SHIFT;
609ef270ab1SKenneth D. Merry 
610ef270ab1SKenneth D. Merry 		atio->cdb_len = cdb_len;
611ef270ab1SKenneth D. Merry 		ocs_memcpy(atio->cdb_io.cdb_bytes, cdb, cdb_len);
612ef270ab1SKenneth D. Merry 
613ef270ab1SKenneth D. Merry 		io->tgt_io.flags = 0;
614ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_COMMAND;
615ef270ab1SKenneth D. Merry 		io->tgt_io.lun = lun;
616ef270ab1SKenneth D. Merry 
617ef270ab1SKenneth D. Merry 		xpt_done((union ccb *)atio);
618ef270ab1SKenneth D. Merry 
619ef270ab1SKenneth D. Merry 		rc = 0;
620ef270ab1SKenneth D. Merry 	} else {
621ef270ab1SKenneth D. Merry 		device_printf(
622ef270ab1SKenneth D. Merry 			ocs->dev, "%s: no ATIO for LUN %lx (en=%s) OX_ID %#x\n",
623ef270ab1SKenneth D. Merry 			__func__, (unsigned long)lun,
624ef270ab1SKenneth D. Merry 			trsrc ? (trsrc->enabled ? "T" : "F") : "X",
625ef270ab1SKenneth D. Merry 			be16toh(io->init_task_tag));
626ef270ab1SKenneth D. Merry 
627ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_MAX;
628ef270ab1SKenneth D. Merry 		ocs_target_io_free(io);
629ef270ab1SKenneth D. Merry 	}
630ef270ab1SKenneth D. Merry 
631ef270ab1SKenneth D. Merry 	return rc;
632ef270ab1SKenneth D. Merry }
633ef270ab1SKenneth D. Merry 
634ef270ab1SKenneth D. Merry /**
635ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
636ef270ab1SKenneth D. Merry  * @brief receive FCP SCSI Command with first burst data.
637ef270ab1SKenneth D. Merry  *
638ef270ab1SKenneth D. Merry  * Receive a new FCP SCSI command from the base driver with first burst data.
639ef270ab1SKenneth D. Merry  *
640ef270ab1SKenneth D. Merry  * @param io pointer to IO context
641ef270ab1SKenneth D. Merry  * @param lun LUN for this IO
642ef270ab1SKenneth D. Merry  * @param cdb pointer to SCSI CDB
643ef270ab1SKenneth D. Merry  * @param cdb_len length of CDB in bytes
644ef270ab1SKenneth D. Merry  * @param flags command flags
645ef270ab1SKenneth D. Merry  * @param first_burst_buffers first burst buffers
646ef270ab1SKenneth D. Merry  * @param first_burst_buffer_count The number of bytes received in the first burst
647ef270ab1SKenneth D. Merry  *
648ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
649ef270ab1SKenneth D. Merry  */
ocs_scsi_recv_cmd_first_burst(ocs_io_t * io,uint64_t lun,uint8_t * cdb,uint32_t cdb_len,uint32_t flags,ocs_dma_t first_burst_buffers[],uint32_t first_burst_buffer_count)650ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint64_t lun, uint8_t *cdb,
651ef270ab1SKenneth D. Merry 		 			uint32_t cdb_len, uint32_t flags,
652ef270ab1SKenneth D. Merry 					ocs_dma_t first_burst_buffers[],
653ef270ab1SKenneth D. Merry 					uint32_t first_burst_buffer_count)
654ef270ab1SKenneth D. Merry {
655ef270ab1SKenneth D. Merry 	return -1;
656ef270ab1SKenneth D. Merry }
657ef270ab1SKenneth D. Merry 
658ef270ab1SKenneth D. Merry /**
659ef270ab1SKenneth D. Merry  * @ingroup scsi_api_target
660ef270ab1SKenneth D. Merry  * @brief receive a TMF command IO
661ef270ab1SKenneth D. Merry  *
662ef270ab1SKenneth D. Merry  * Called by the base driver when a SCSI TMF command has been received.   The
663ef270ab1SKenneth D. Merry  * target-server will process the command, aborting commands as needed, and post
664ef270ab1SKenneth D. Merry  * a response using ocs_scsi_send_resp()
665ef270ab1SKenneth D. Merry  *
666ef270ab1SKenneth D. Merry  * The IO context (ocs_io_t) structure has and element of type ocs_scsi_tgt_io_t named
667ef270ab1SKenneth D. Merry  * tgt_io that is declared and used by a target-server for private information.
668ef270ab1SKenneth D. Merry  *
669ef270ab1SKenneth D. Merry  * If the target-server walks the nodes active_ios linked list, and starts IO
670ef270ab1SKenneth D. Merry  * abort processing, the code <b>must</b> be sure not to abort the IO passed into the
671ef270ab1SKenneth D. Merry  * ocs_scsi_recv_tmf() command.
672ef270ab1SKenneth D. Merry  *
673ef270ab1SKenneth D. Merry  * @param tmfio pointer to IO context
674ef270ab1SKenneth D. Merry  * @param lun logical unit value
675ef270ab1SKenneth D. Merry  * @param cmd command request
676ef270ab1SKenneth D. Merry  * @param abortio pointer to IO object to abort for TASK_ABORT (NULL for all other TMF)
677ef270ab1SKenneth D. Merry  * @param flags flags
678ef270ab1SKenneth D. Merry  *
679ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
680ef270ab1SKenneth D. Merry  */
ocs_scsi_recv_tmf(ocs_io_t * tmfio,uint64_t lun,ocs_scsi_tmf_cmd_e cmd,ocs_io_t * abortio,uint32_t flags)681ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint64_t lun, ocs_scsi_tmf_cmd_e cmd,
682ef270ab1SKenneth D. Merry 				ocs_io_t *abortio, uint32_t flags)
683ef270ab1SKenneth D. Merry {
684ef270ab1SKenneth D. Merry 	ocs_t *ocs = tmfio->ocs;
685ef270ab1SKenneth D. Merry 	ocs_node_t *node = tmfio->node;
686ef270ab1SKenneth D. Merry 	ocs_tgt_resource_t *trsrc = NULL;
687ef270ab1SKenneth D. Merry 	struct ccb_immediate_notify *inot = NULL;
688ef270ab1SKenneth D. Merry 	int32_t		rc = -1;
689ef270ab1SKenneth D. Merry 	ocs_fcport	*fcp = NULL;
690ef270ab1SKenneth D. Merry 
691ef270ab1SKenneth D. Merry 	fcp = node->sport->tgt_data;
692ef270ab1SKenneth D. Merry 	if (fcp == NULL) {
693ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "FCP is NULL \n");
694ef270ab1SKenneth D. Merry 		return 1;
695ef270ab1SKenneth D. Merry 	}
696ef270ab1SKenneth D. Merry 
697ef270ab1SKenneth D. Merry 	if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) {
698ef270ab1SKenneth D. Merry 		trsrc = &fcp->targ_rsrc[lun];
699ef270ab1SKenneth D. Merry 	} else if (fcp->targ_rsrc_wildcard.enabled) {
700ef270ab1SKenneth D. Merry 		trsrc = &fcp->targ_rsrc_wildcard;
701ef270ab1SKenneth D. Merry 	}
702ef270ab1SKenneth D. Merry 
703ef270ab1SKenneth D. Merry 	device_printf(tmfio->ocs->dev, "%s: io=%p cmd=%#x LU=%lx en=%s\n",
704ef270ab1SKenneth D. Merry 			__func__, tmfio, cmd, (unsigned long)lun,
705ef270ab1SKenneth D. Merry 			trsrc ? (trsrc->enabled ? "T" : "F") : "X");
706ef270ab1SKenneth D. Merry 	if (trsrc) {
707ef270ab1SKenneth D. Merry 		inot = (struct ccb_immediate_notify *)STAILQ_FIRST(&trsrc->inot);
708ef270ab1SKenneth D. Merry 	}
709ef270ab1SKenneth D. Merry 
710ef270ab1SKenneth D. Merry 	if (!inot) {
711ef270ab1SKenneth D. Merry 		device_printf(
712ef270ab1SKenneth D. Merry 			ocs->dev, "%s: no INOT for LUN %llx (en=%s) OX_ID %#x\n",
713ef270ab1SKenneth D. Merry 			__func__, (unsigned long long)lun, trsrc ? (trsrc->enabled ? "T" : "F") : "X",
714ef270ab1SKenneth D. Merry 			be16toh(tmfio->init_task_tag));
715ef270ab1SKenneth D. Merry 
716ef270ab1SKenneth D. Merry 		if (abortio) {
717ef270ab1SKenneth D. Merry 			ocs_scsi_io_complete(abortio);
718ef270ab1SKenneth D. Merry 		}
719ef270ab1SKenneth D. Merry 		ocs_scsi_io_complete(tmfio);
720ef270ab1SKenneth D. Merry 		goto ocs_scsi_recv_tmf_out;
721ef270ab1SKenneth D. Merry 	}
722ef270ab1SKenneth D. Merry 
723ef270ab1SKenneth D. Merry 	tmfio->tgt_io.app = abortio;
724ef270ab1SKenneth D. Merry 
725ef270ab1SKenneth D. Merry 	STAILQ_REMOVE_HEAD(&trsrc->inot, sim_links.stqe);
726ef270ab1SKenneth D. Merry 
727ef270ab1SKenneth D. Merry 	inot->tag_id = tmfio->tag;
728ef270ab1SKenneth D. Merry 	inot->seq_id = tmfio->tag;
729ef270ab1SKenneth D. Merry 
730ef270ab1SKenneth D. Merry 	if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) {
731ef270ab1SKenneth D. Merry 		inot->initiator_id = node->instance_index;
732ef270ab1SKenneth D. Merry 	} else {
733ef270ab1SKenneth D. Merry 		inot->initiator_id = CAM_TARGET_WILDCARD;
734ef270ab1SKenneth D. Merry 	}
735ef270ab1SKenneth D. Merry 
736ef270ab1SKenneth D. Merry 	inot->ccb_h.status = CAM_MESSAGE_RECV;
737ef270ab1SKenneth D. Merry 	inot->ccb_h.target_lun = lun;
738ef270ab1SKenneth D. Merry 
739ef270ab1SKenneth D. Merry 	switch (cmd) {
740ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_ABORT_TASK:
741ef270ab1SKenneth D. Merry 		inot->arg = MSG_ABORT_TASK;
742ef270ab1SKenneth D. Merry 		inot->seq_id = abortio->tag;
743ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: ABTS IO.%#x st=%#x\n",
744ef270ab1SKenneth D. Merry 			__func__, abortio->tag,	abortio->tgt_io.state);
745ef270ab1SKenneth D. Merry 		abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_RECV;
746ef270ab1SKenneth D. Merry 		abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_NOTIFY;
747ef270ab1SKenneth D. Merry 		break;
748ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_QUERY_TASK_SET:
749ef270ab1SKenneth D. Merry 		device_printf(ocs->dev,
750ef270ab1SKenneth D. Merry 			"%s: OCS_SCSI_TMF_QUERY_TASK_SET not supported\n",
751ef270ab1SKenneth D. Merry 				__func__);
752ef270ab1SKenneth D. Merry 		STAILQ_INSERT_TAIL(&trsrc->inot, &inot->ccb_h, sim_links.stqe);
753ef270ab1SKenneth D. Merry 		ocs_scsi_io_complete(tmfio);
754ef270ab1SKenneth D. Merry 		goto ocs_scsi_recv_tmf_out;
755ef270ab1SKenneth D. Merry 		break;
756ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_ABORT_TASK_SET:
757ef270ab1SKenneth D. Merry 		inot->arg = MSG_ABORT_TASK_SET;
758ef270ab1SKenneth D. Merry 		break;
759ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_CLEAR_TASK_SET:
760ef270ab1SKenneth D. Merry 		inot->arg = MSG_CLEAR_TASK_SET;
761ef270ab1SKenneth D. Merry 		break;
762ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
763ef270ab1SKenneth D. Merry 		inot->arg = MSG_QUERY_ASYNC_EVENT;
764ef270ab1SKenneth D. Merry 		break;
765ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_LOGICAL_UNIT_RESET:
766ef270ab1SKenneth D. Merry 		inot->arg = MSG_LOGICAL_UNIT_RESET;
767ef270ab1SKenneth D. Merry 		break;
768ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_CLEAR_ACA:
769ef270ab1SKenneth D. Merry 		inot->arg = MSG_CLEAR_ACA;
770ef270ab1SKenneth D. Merry 		break;
771ef270ab1SKenneth D. Merry 	case OCS_SCSI_TMF_TARGET_RESET:
772ef270ab1SKenneth D. Merry 		inot->arg = MSG_TARGET_RESET;
773ef270ab1SKenneth D. Merry 		break;
774ef270ab1SKenneth D. Merry 	default:
775ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: unsupported TMF %#x\n",
776ef270ab1SKenneth D. Merry 							 __func__, cmd);
777ef270ab1SKenneth D. Merry 		STAILQ_INSERT_TAIL(&trsrc->inot, &inot->ccb_h, sim_links.stqe);
778ef270ab1SKenneth D. Merry 		goto ocs_scsi_recv_tmf_out;
779ef270ab1SKenneth D. Merry 	}
780ef270ab1SKenneth D. Merry 
781ef270ab1SKenneth D. Merry 	rc = 0;
782ef270ab1SKenneth D. Merry 
783ef270ab1SKenneth D. Merry 	xpt_print(inot->ccb_h.path, "%s: func=%#x stat=%#x id=%#x lun=%#x"
784ef270ab1SKenneth D. Merry 			" flags=%#x tag=%#x seq=%#x ini=%#x arg=%#x\n",
785ef270ab1SKenneth D. Merry 			__func__, inot->ccb_h.func_code, inot->ccb_h.status,
786ef270ab1SKenneth D. Merry 			inot->ccb_h.target_id,
787ef270ab1SKenneth D. Merry 			(unsigned int)inot->ccb_h.target_lun, inot->ccb_h.flags,
788ef270ab1SKenneth D. Merry 			inot->tag_id, inot->seq_id, inot->initiator_id,
789ef270ab1SKenneth D. Merry 			inot->arg);
790ef270ab1SKenneth D. Merry 	xpt_done((union ccb *)inot);
791ef270ab1SKenneth D. Merry 
792ef270ab1SKenneth D. Merry 	if (abortio) {
793ef270ab1SKenneth D. Merry 		abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_DEV;
794ef270ab1SKenneth D. Merry 		rc = ocs_scsi_tgt_abort_io(abortio, ocs_io_abort_cb, tmfio);
795ef270ab1SKenneth D. Merry 	}
796ef270ab1SKenneth D. Merry 
797ef270ab1SKenneth D. Merry ocs_scsi_recv_tmf_out:
798ef270ab1SKenneth D. Merry 	return rc;
799ef270ab1SKenneth D. Merry }
800ef270ab1SKenneth D. Merry 
801ef270ab1SKenneth D. Merry /**
802ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
803ef270ab1SKenneth D. Merry  * @brief Initializes any initiator fields on the ocs structure.
804ef270ab1SKenneth D. Merry  *
805ef270ab1SKenneth D. Merry  * Called by OS initialization code when a new device is discovered.
806ef270ab1SKenneth D. Merry  *
807ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs
808ef270ab1SKenneth D. Merry  *
809ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
810ef270ab1SKenneth D. Merry  */
811ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_new_device(ocs_t * ocs)812ef270ab1SKenneth D. Merry ocs_scsi_ini_new_device(ocs_t *ocs)
813ef270ab1SKenneth D. Merry {
814ef270ab1SKenneth D. Merry 
815ef270ab1SKenneth D. Merry 	return 0;
816ef270ab1SKenneth D. Merry }
817ef270ab1SKenneth D. Merry 
818ef270ab1SKenneth D. Merry /**
819ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
820ef270ab1SKenneth D. Merry  * @brief Tears down initiator members of ocs structure.
821ef270ab1SKenneth D. Merry  *
822ef270ab1SKenneth D. Merry  * Called by OS code when device is removed.
823ef270ab1SKenneth D. Merry  *
824ef270ab1SKenneth D. Merry  * @param ocs pointer to ocs
825ef270ab1SKenneth D. Merry  *
826ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
827ef270ab1SKenneth D. Merry  */
828ef270ab1SKenneth D. Merry 
829ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_del_device(ocs_t * ocs)830ef270ab1SKenneth D. Merry ocs_scsi_ini_del_device(ocs_t *ocs)
831ef270ab1SKenneth D. Merry {
832ef270ab1SKenneth D. Merry 
833ef270ab1SKenneth D. Merry 	return 0;
834ef270ab1SKenneth D. Merry }
835ef270ab1SKenneth D. Merry 
836ef270ab1SKenneth D. Merry /**
837ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
838ef270ab1SKenneth D. Merry  * @brief accept new domain notification
839ef270ab1SKenneth D. Merry  *
840ef270ab1SKenneth D. Merry  * Called by base drive when new domain is discovered.  An initiator-client
841ef270ab1SKenneth D. Merry  * will accept this call to prepare for new remote node notifications
842ef270ab1SKenneth D. Merry  * arising from ocs_scsi_new_target().
843ef270ab1SKenneth D. Merry  *
844ef270ab1SKenneth D. Merry  * The domain context has the element <b>ocs_scsi_ini_domain_t ini_domain</b>
845ef270ab1SKenneth D. Merry  * which is declared by the initiator-client code and is used for
846ef270ab1SKenneth D. Merry  * initiator-client private data.
847ef270ab1SKenneth D. Merry  *
848ef270ab1SKenneth D. Merry  * This function will only be called if the base-driver has been enabled for
849ef270ab1SKenneth D. Merry  * initiator capability.
850ef270ab1SKenneth D. Merry  *
851ef270ab1SKenneth D. Merry  * Note that this call is made to initiator-client backends,
852ef270ab1SKenneth D. Merry  * the ocs_scsi_tgt_new_domain() function is called to target-server backends.
853ef270ab1SKenneth D. Merry  *
854ef270ab1SKenneth D. Merry  * @param domain pointer to domain
855ef270ab1SKenneth D. Merry  *
856ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
857ef270ab1SKenneth D. Merry  */
858ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_new_domain(ocs_domain_t * domain)859ef270ab1SKenneth D. Merry ocs_scsi_ini_new_domain(ocs_domain_t *domain)
860ef270ab1SKenneth D. Merry {
861ef270ab1SKenneth D. Merry 	return 0;
862ef270ab1SKenneth D. Merry }
863ef270ab1SKenneth D. Merry 
864ef270ab1SKenneth D. Merry /**
865ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
866ef270ab1SKenneth D. Merry  * @brief accept domain lost notification
867ef270ab1SKenneth D. Merry  *
868ef270ab1SKenneth D. Merry  * Called by base-driver when a domain goes away.  An initiator-client will
869ef270ab1SKenneth D. Merry  * use this call to clean up all domain scoped resources.
870ef270ab1SKenneth D. Merry  *
871ef270ab1SKenneth D. Merry  * This function will only be called if the base-driver has been enabled for
872ef270ab1SKenneth D. Merry  * initiator capability.
873ef270ab1SKenneth D. Merry  *
874ef270ab1SKenneth D. Merry  * Note that this call is made to initiator-client backends,
875ef270ab1SKenneth D. Merry  * the ocs_scsi_tgt_del_domain() function is called to target-server backends.
876ef270ab1SKenneth D. Merry  *
877ef270ab1SKenneth D. Merry  * @param domain pointer to domain
878ef270ab1SKenneth D. Merry  *
879ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
880ef270ab1SKenneth D. Merry  */
881ef270ab1SKenneth D. Merry void
ocs_scsi_ini_del_domain(ocs_domain_t * domain)882ef270ab1SKenneth D. Merry ocs_scsi_ini_del_domain(ocs_domain_t *domain)
883ef270ab1SKenneth D. Merry {
884ef270ab1SKenneth D. Merry }
885ef270ab1SKenneth D. Merry 
886ef270ab1SKenneth D. Merry /**
887ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
888ef270ab1SKenneth D. Merry  * @brief accept new sli port notification
889ef270ab1SKenneth D. Merry  *
890ef270ab1SKenneth D. Merry  * Called by base drive when new sli port (sport) is discovered.
891ef270ab1SKenneth D. Merry  * A target-server will use this call to prepare for new remote node
892ef270ab1SKenneth D. Merry  * notifications arising from ocs_scsi_new_initiator().
893ef270ab1SKenneth D. Merry  *
894ef270ab1SKenneth D. Merry  * This function will only be called if the base-driver has been enabled for
895ef270ab1SKenneth D. Merry  * target capability.
896ef270ab1SKenneth D. Merry  *
897ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
898ef270ab1SKenneth D. Merry  * the ocs_scsi_ini_new_sport() function is called to initiator-client backends.
899ef270ab1SKenneth D. Merry  *
900ef270ab1SKenneth D. Merry  * @param sport pointer to sport
901ef270ab1SKenneth D. Merry  *
902ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
903ef270ab1SKenneth D. Merry  */
904ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_new_sport(ocs_sport_t * sport)905ef270ab1SKenneth D. Merry ocs_scsi_ini_new_sport(ocs_sport_t *sport)
906ef270ab1SKenneth D. Merry {
907ef270ab1SKenneth D. Merry 	ocs_t *ocs = sport->ocs;
908b9732f78SRam Kishore Vegesna 	ocs_fcport *fcp = FCPORT(ocs, 0);
909ef270ab1SKenneth D. Merry 
910ef270ab1SKenneth D. Merry 	if (!sport->is_vport) {
911b9732f78SRam Kishore Vegesna 		sport->tgt_data = fcp;
912b9732f78SRam Kishore Vegesna 		fcp->fc_id = sport->fc_id;
913ef270ab1SKenneth D. Merry 	}
914ef270ab1SKenneth D. Merry 
915ef270ab1SKenneth D. Merry 	return 0;
916ef270ab1SKenneth D. Merry }
917ef270ab1SKenneth D. Merry 
918ef270ab1SKenneth D. Merry /**
919ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
920ef270ab1SKenneth D. Merry  * @brief accept sli port gone notification
921ef270ab1SKenneth D. Merry  *
922ef270ab1SKenneth D. Merry  * Called by base-driver when a sport goes away.  A target-server will
923ef270ab1SKenneth D. Merry  * use this call to clean up all sport scoped resources.
924ef270ab1SKenneth D. Merry  *
925ef270ab1SKenneth D. Merry  * Note that this call is made to target-server backends,
926ef270ab1SKenneth D. Merry  * the ocs_scsi_ini_del_sport() function is called to initiator-client backends.
927ef270ab1SKenneth D. Merry  *
928ef270ab1SKenneth D. Merry  * @param sport pointer to SLI port
929ef270ab1SKenneth D. Merry  *
930ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
931ef270ab1SKenneth D. Merry  */
932ef270ab1SKenneth D. Merry void
ocs_scsi_ini_del_sport(ocs_sport_t * sport)933ef270ab1SKenneth D. Merry ocs_scsi_ini_del_sport(ocs_sport_t *sport)
934ef270ab1SKenneth D. Merry {
935b9732f78SRam Kishore Vegesna 	ocs_t *ocs = sport->ocs;
936b9732f78SRam Kishore Vegesna 	ocs_fcport *fcp = FCPORT(ocs, 0);
937b9732f78SRam Kishore Vegesna 
938b9732f78SRam Kishore Vegesna 	if (!sport->is_vport) {
939b9732f78SRam Kishore Vegesna 		fcp->fc_id = 0;
940b9732f78SRam Kishore Vegesna 	}
941ef270ab1SKenneth D. Merry }
942ef270ab1SKenneth D. Merry 
943ef270ab1SKenneth D. Merry void
ocs_scsi_sport_deleted(ocs_sport_t * sport)944ef270ab1SKenneth D. Merry ocs_scsi_sport_deleted(ocs_sport_t *sport)
945ef270ab1SKenneth D. Merry {
946ef270ab1SKenneth D. Merry 	ocs_t *ocs = sport->ocs;
947ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = NULL;
948ef270ab1SKenneth D. Merry 
949ef270ab1SKenneth D. Merry 	ocs_xport_stats_t value;
950ef270ab1SKenneth D. Merry 
951ef270ab1SKenneth D. Merry 	if (!sport->is_vport) {
952ef270ab1SKenneth D. Merry 		return;
953ef270ab1SKenneth D. Merry 	}
954ef270ab1SKenneth D. Merry 
955ef270ab1SKenneth D. Merry 	fcp = sport->tgt_data;
956ef270ab1SKenneth D. Merry 
957ef270ab1SKenneth D. Merry 	ocs_xport_status(ocs->xport, OCS_XPORT_PORT_STATUS, &value);
958ef270ab1SKenneth D. Merry 
959ef270ab1SKenneth D. Merry 	if (value.value == 0) {
960ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "PORT offline,.. skipping\n");
961ef270ab1SKenneth D. Merry 		return;
962ef270ab1SKenneth D. Merry 	}
963ef270ab1SKenneth D. Merry 
964ef270ab1SKenneth D. Merry 	if ((fcp->role != KNOB_ROLE_NONE)) {
965ef270ab1SKenneth D. Merry 		if(fcp->vport->sport != NULL) {
966ef270ab1SKenneth D. Merry 			ocs_log_debug(ocs,"sport is not NULL, skipping\n");
967ef270ab1SKenneth D. Merry 			return;
968ef270ab1SKenneth D. Merry 		}
969ef270ab1SKenneth D. Merry 
970ef270ab1SKenneth D. Merry 		ocs_sport_vport_alloc(ocs->domain, fcp->vport);
971ef270ab1SKenneth D. Merry 		return;
972ef270ab1SKenneth D. Merry 	}
973ef270ab1SKenneth D. Merry 
974ef270ab1SKenneth D. Merry }
975ef270ab1SKenneth D. Merry 
9766affb8ebSRam Kishore Vegesna int32_t
ocs_tgt_find(ocs_fcport * fcp,ocs_node_t * node)9776affb8ebSRam Kishore Vegesna ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node)
9786affb8ebSRam Kishore Vegesna {
9796affb8ebSRam Kishore Vegesna 	ocs_fc_target_t *tgt = NULL;
9806affb8ebSRam Kishore Vegesna 	uint32_t i;
9816affb8ebSRam Kishore Vegesna 
9826affb8ebSRam Kishore Vegesna 	for (i = 0; i < OCS_MAX_TARGETS; i++) {
9836affb8ebSRam Kishore Vegesna 		tgt = &fcp->tgt[i];
9846affb8ebSRam Kishore Vegesna 
9856affb8ebSRam Kishore Vegesna 		if (tgt->state == OCS_TGT_STATE_NONE)
9866affb8ebSRam Kishore Vegesna 			continue;
9876affb8ebSRam Kishore Vegesna 
9886affb8ebSRam Kishore Vegesna 		if (ocs_node_get_wwpn(node) == tgt->wwpn) {
9896affb8ebSRam Kishore Vegesna 			return i;
9906affb8ebSRam Kishore Vegesna 		}
9916affb8ebSRam Kishore Vegesna 	}
9926affb8ebSRam Kishore Vegesna 
9936affb8ebSRam Kishore Vegesna 	return -1;
9946affb8ebSRam Kishore Vegesna }
9956affb8ebSRam Kishore Vegesna 
996ef270ab1SKenneth D. Merry /**
997ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
998ef270ab1SKenneth D. Merry  * @brief receive notification of a new SCSI target node
999ef270ab1SKenneth D. Merry  *
1000ef270ab1SKenneth D. Merry  * Sent by base driver to notify an initiator-client of the presense of a new
1001ef270ab1SKenneth D. Merry  * remote target.   The initiator-server may use this call to prepare for
1002ef270ab1SKenneth D. Merry  * inbound IO from this node.
1003ef270ab1SKenneth D. Merry  *
1004ef270ab1SKenneth D. Merry  * This function is only called if the base driver is enabled for
1005ef270ab1SKenneth D. Merry  * initiator capability.
1006ef270ab1SKenneth D. Merry  *
1007ef270ab1SKenneth D. Merry  * @param node pointer to new remote initiator node
1008ef270ab1SKenneth D. Merry  *
1009ef270ab1SKenneth D. Merry  * @return none
1010ef270ab1SKenneth D. Merry  *
1011ef270ab1SKenneth D. Merry  * @note
1012ef270ab1SKenneth D. Merry  */
10136affb8ebSRam Kishore Vegesna 
10146affb8ebSRam Kishore Vegesna uint32_t
ocs_update_tgt(ocs_node_t * node,ocs_fcport * fcp,uint32_t tgt_id)10156affb8ebSRam Kishore Vegesna ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id)
1016ef270ab1SKenneth D. Merry {
10176affb8ebSRam Kishore Vegesna 	ocs_fc_target_t *tgt = NULL;
10186affb8ebSRam Kishore Vegesna 
10196affb8ebSRam Kishore Vegesna 	tgt = &fcp->tgt[tgt_id];
10206affb8ebSRam Kishore Vegesna 
10216affb8ebSRam Kishore Vegesna 	tgt->node_id = node->instance_index;
10226affb8ebSRam Kishore Vegesna 	tgt->state = OCS_TGT_STATE_VALID;
10236affb8ebSRam Kishore Vegesna 
10246affb8ebSRam Kishore Vegesna 	tgt->port_id = node->rnode.fc_id;
10256affb8ebSRam Kishore Vegesna 	tgt->wwpn = ocs_node_get_wwpn(node);
10266affb8ebSRam Kishore Vegesna 	tgt->wwnn = ocs_node_get_wwnn(node);
10276affb8ebSRam Kishore Vegesna 	return 0;
10286affb8ebSRam Kishore Vegesna }
10296affb8ebSRam Kishore Vegesna 
10306affb8ebSRam Kishore Vegesna uint32_t
ocs_add_new_tgt(ocs_node_t * node,ocs_fcport * fcp)10316affb8ebSRam Kishore Vegesna ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp)
10326affb8ebSRam Kishore Vegesna {
10336affb8ebSRam Kishore Vegesna 	uint32_t i;
10346affb8ebSRam Kishore Vegesna 
1035ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = node->ocs;
1036ef270ab1SKenneth D. Merry 	union ccb *ccb = NULL;
10376affb8ebSRam Kishore Vegesna 	for (i = 0; i < OCS_MAX_TARGETS; i++) {
10386affb8ebSRam Kishore Vegesna 		if (fcp->tgt[i].state == OCS_TGT_STATE_NONE)
10396affb8ebSRam Kishore Vegesna 			break;
1040ef270ab1SKenneth D. Merry 	}
1041ef270ab1SKenneth D. Merry 
1042ef270ab1SKenneth D. Merry 	if (NULL == (ccb = xpt_alloc_ccb_nowait())) {
1043ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: ccb allocation failed\n", __func__);
1044ef270ab1SKenneth D. Merry 		return -1;
1045ef270ab1SKenneth D. Merry 	}
1046ef270ab1SKenneth D. Merry 
1047ef270ab1SKenneth D. Merry 	if (CAM_REQ_CMP != xpt_create_path(&ccb->ccb_h.path, xpt_periph,
1048ef270ab1SKenneth D. Merry 				cam_sim_path(fcp->sim),
10496affb8ebSRam Kishore Vegesna 				i, CAM_LUN_WILDCARD)) {
1050ef270ab1SKenneth D. Merry 		device_printf(
1051ef270ab1SKenneth D. Merry 			ocs->dev, "%s: target path creation failed\n", __func__);
1052ef270ab1SKenneth D. Merry 		xpt_free_ccb(ccb);
1053ef270ab1SKenneth D. Merry 		return -1;
1054ef270ab1SKenneth D. Merry 	}
1055ef270ab1SKenneth D. Merry 
10566affb8ebSRam Kishore Vegesna 	ocs_update_tgt(node, fcp, i);
1057ef270ab1SKenneth D. Merry 	xpt_rescan(ccb);
1058ef270ab1SKenneth D. Merry 	return 0;
1059ef270ab1SKenneth D. Merry }
1060ef270ab1SKenneth D. Merry 
10616affb8ebSRam Kishore Vegesna int32_t
ocs_scsi_new_target(ocs_node_t * node)10626affb8ebSRam Kishore Vegesna ocs_scsi_new_target(ocs_node_t *node)
10636affb8ebSRam Kishore Vegesna {
10646affb8ebSRam Kishore Vegesna 	ocs_fcport	*fcp = NULL;
10656affb8ebSRam Kishore Vegesna 	int32_t i;
10666affb8ebSRam Kishore Vegesna 
10676affb8ebSRam Kishore Vegesna 	fcp = node->sport->tgt_data;
10686affb8ebSRam Kishore Vegesna 	if (fcp == NULL) {
10696affb8ebSRam Kishore Vegesna 		printf("%s:FCP is NULL \n", __func__);
10706affb8ebSRam Kishore Vegesna 		return 0;
10716affb8ebSRam Kishore Vegesna 	}
10726affb8ebSRam Kishore Vegesna 
10736affb8ebSRam Kishore Vegesna 	i = ocs_tgt_find(fcp, node);
10746affb8ebSRam Kishore Vegesna 
10756affb8ebSRam Kishore Vegesna 	if (i < 0) {
10766affb8ebSRam Kishore Vegesna 		ocs_add_new_tgt(node, fcp);
10776affb8ebSRam Kishore Vegesna 		return 0;
10786affb8ebSRam Kishore Vegesna 	}
10796affb8ebSRam Kishore Vegesna 
10806affb8ebSRam Kishore Vegesna 	ocs_update_tgt(node, fcp, i);
10816affb8ebSRam Kishore Vegesna 	return 0;
10826affb8ebSRam Kishore Vegesna }
10836affb8ebSRam Kishore Vegesna 
10846affb8ebSRam Kishore Vegesna static void
ocs_delete_target(ocs_t * ocs,ocs_fcport * fcp,int tgt)10856affb8ebSRam Kishore Vegesna ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt)
10866affb8ebSRam Kishore Vegesna {
10876affb8ebSRam Kishore Vegesna 	struct cam_path *cpath = NULL;
10886affb8ebSRam Kishore Vegesna 
10896affb8ebSRam Kishore Vegesna 	if (!fcp->sim) {
10906affb8ebSRam Kishore Vegesna 		device_printf(ocs->dev, "%s: calling with NULL sim\n", __func__);
10916affb8ebSRam Kishore Vegesna 		return;
10926affb8ebSRam Kishore Vegesna 	}
10936affb8ebSRam Kishore Vegesna 
10946affb8ebSRam Kishore Vegesna 	if (CAM_REQ_CMP == xpt_create_path(&cpath, NULL, cam_sim_path(fcp->sim),
10956affb8ebSRam Kishore Vegesna 				tgt, CAM_LUN_WILDCARD)) {
10966affb8ebSRam Kishore Vegesna 		xpt_async(AC_LOST_DEVICE, cpath, NULL);
10976affb8ebSRam Kishore Vegesna 
10986affb8ebSRam Kishore Vegesna 		xpt_free_path(cpath);
10996affb8ebSRam Kishore Vegesna 	}
11006affb8ebSRam Kishore Vegesna }
11016affb8ebSRam Kishore Vegesna 
11026affb8ebSRam Kishore Vegesna /*
11036affb8ebSRam Kishore Vegesna  * Device Lost Timer Function- when we have decided that a device was lost,
11046affb8ebSRam Kishore Vegesna  * we wait a specific period of time prior to telling the OS about lost device.
11056affb8ebSRam Kishore Vegesna  *
11066affb8ebSRam Kishore Vegesna  * This timer function gets activated when the device was lost.
11076affb8ebSRam Kishore Vegesna  * This function fires once a second and then scans the port database
11086affb8ebSRam Kishore Vegesna  * for devices that are marked dead but still have a virtual target assigned.
11096affb8ebSRam Kishore Vegesna  * We decrement a counter for that port database entry, and when it hits zero,
11106affb8ebSRam Kishore Vegesna  * we tell the OS the device was lost. Timer will be stopped when the device
11116affb8ebSRam Kishore Vegesna  * comes back active or removed from the OS.
11126affb8ebSRam Kishore Vegesna  */
11136affb8ebSRam Kishore Vegesna static void
ocs_ldt(void * arg)11146affb8ebSRam Kishore Vegesna ocs_ldt(void *arg)
11156affb8ebSRam Kishore Vegesna {
11166affb8ebSRam Kishore Vegesna 	ocs_fcport *fcp = arg;
11176affb8ebSRam Kishore Vegesna 	taskqueue_enqueue(taskqueue_thread, &fcp->ltask);
11186affb8ebSRam Kishore Vegesna }
11196affb8ebSRam Kishore Vegesna 
11206affb8ebSRam Kishore Vegesna static void
ocs_ldt_task(void * arg,int pending)11216affb8ebSRam Kishore Vegesna ocs_ldt_task(void *arg, int pending)
11226affb8ebSRam Kishore Vegesna {
11236affb8ebSRam Kishore Vegesna 	ocs_fcport *fcp = arg;
11246affb8ebSRam Kishore Vegesna 	ocs_t	*ocs = fcp->ocs;
11256affb8ebSRam Kishore Vegesna 	int i, more_to_do = 0;
11266affb8ebSRam Kishore Vegesna 	ocs_fc_target_t *tgt = NULL;
11276affb8ebSRam Kishore Vegesna 
11286affb8ebSRam Kishore Vegesna 	for (i = 0; i < OCS_MAX_TARGETS; i++) {
11296affb8ebSRam Kishore Vegesna 		tgt = &fcp->tgt[i];
11306affb8ebSRam Kishore Vegesna 
11316affb8ebSRam Kishore Vegesna 		if (tgt->state != OCS_TGT_STATE_LOST) {
11326affb8ebSRam Kishore Vegesna 			continue;
11336affb8ebSRam Kishore Vegesna 		}
11346affb8ebSRam Kishore Vegesna 
11356affb8ebSRam Kishore Vegesna 		if ((tgt->gone_timer != 0) && (ocs->attached)){
11366affb8ebSRam Kishore Vegesna 			tgt->gone_timer -= 1;
11376affb8ebSRam Kishore Vegesna 			more_to_do++;
11386affb8ebSRam Kishore Vegesna 			continue;
11396affb8ebSRam Kishore Vegesna 		}
11406affb8ebSRam Kishore Vegesna 
11416affb8ebSRam Kishore Vegesna 		ocs_delete_target(ocs, fcp, i);
11426affb8ebSRam Kishore Vegesna 
11436affb8ebSRam Kishore Vegesna 		tgt->state = OCS_TGT_STATE_NONE;
11446affb8ebSRam Kishore Vegesna 	}
11456affb8ebSRam Kishore Vegesna 
11466affb8ebSRam Kishore Vegesna 	if (more_to_do) {
11476affb8ebSRam Kishore Vegesna 		callout_reset(&fcp->ldt, hz, ocs_ldt, fcp);
11486affb8ebSRam Kishore Vegesna 	} else {
11496affb8ebSRam Kishore Vegesna 		callout_deactivate(&fcp->ldt);
11506affb8ebSRam Kishore Vegesna 	}
11516affb8ebSRam Kishore Vegesna 
11526affb8ebSRam Kishore Vegesna }
11536affb8ebSRam Kishore Vegesna 
1154ef270ab1SKenneth D. Merry /**
1155ef270ab1SKenneth D. Merry  * @ingroup scsi_api_initiator
1156ef270ab1SKenneth D. Merry  * @brief Delete a SCSI target node
1157ef270ab1SKenneth D. Merry  *
1158ef270ab1SKenneth D. Merry  * Sent by base driver to notify a initiator-client that a remote target
1159ef270ab1SKenneth D. Merry  * is now gone. The base driver will have terminated all  outstanding IOs
1160ef270ab1SKenneth D. Merry  * and the initiator-client will receive appropriate completions.
1161ef270ab1SKenneth D. Merry  *
1162ef270ab1SKenneth D. Merry  * The ocs_node_t structure has and elment of type ocs_scsi_ini_node_t named
1163ef270ab1SKenneth D. Merry  * ini_node that is declared and used by a target-server for private
1164ef270ab1SKenneth D. Merry  * information.
1165ef270ab1SKenneth D. Merry  *
1166ef270ab1SKenneth D. Merry  * This function is only called if the base driver is enabled for
1167ef270ab1SKenneth D. Merry  * initiator capability.
1168ef270ab1SKenneth D. Merry  *
1169ef270ab1SKenneth D. Merry  * @param node pointer node being deleted
1170ef270ab1SKenneth D. Merry  * @param reason reason for deleting the target
1171ef270ab1SKenneth D. Merry  *
1172ef270ab1SKenneth D. Merry  * @return Returns OCS_SCSI_CALL_ASYNC if target delete is queued for async
1173ef270ab1SKenneth D. Merry  * completion and OCS_SCSI_CALL_COMPLETE if call completed or error.
1174ef270ab1SKenneth D. Merry  *
1175ef270ab1SKenneth D. Merry  * @note
1176ef270ab1SKenneth D. Merry  */
1177ef270ab1SKenneth D. Merry int32_t
ocs_scsi_del_target(ocs_node_t * node,ocs_scsi_del_target_reason_e reason)1178ef270ab1SKenneth D. Merry ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason)
1179ef270ab1SKenneth D. Merry {
1180ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = node->ocs;
1181ef270ab1SKenneth D. Merry 	ocs_fcport	*fcp = NULL;
11826affb8ebSRam Kishore Vegesna 	ocs_fc_target_t *tgt = NULL;
11834915e5c7SRam Kishore Vegesna 	int32_t	tgt_id;
11844915e5c7SRam Kishore Vegesna 
11854915e5c7SRam Kishore Vegesna 	if (ocs == NULL) {
11864915e5c7SRam Kishore Vegesna 		ocs_log_err(ocs,"OCS is NULL \n");
11874915e5c7SRam Kishore Vegesna 		return -1;
11884915e5c7SRam Kishore Vegesna 	}
1189ef270ab1SKenneth D. Merry 
1190ef270ab1SKenneth D. Merry 	fcp = node->sport->tgt_data;
1191ef270ab1SKenneth D. Merry 	if (fcp == NULL) {
1192ef270ab1SKenneth D. Merry 		ocs_log_err(ocs,"FCP is NULL \n");
11934915e5c7SRam Kishore Vegesna 		return -1;
1194ef270ab1SKenneth D. Merry 	}
1195ef270ab1SKenneth D. Merry 
11966affb8ebSRam Kishore Vegesna 	tgt_id = ocs_tgt_find(fcp, node);
11974915e5c7SRam Kishore Vegesna 	if (tgt_id == -1) {
11984915e5c7SRam Kishore Vegesna 		ocs_log_err(ocs,"target is invalid\n");
11994915e5c7SRam Kishore Vegesna 		return -1;
12004915e5c7SRam Kishore Vegesna 	}
12016affb8ebSRam Kishore Vegesna 
12026affb8ebSRam Kishore Vegesna 	tgt = &fcp->tgt[tgt_id];
12036affb8ebSRam Kishore Vegesna 
12046affb8ebSRam Kishore Vegesna 	// IF in shutdown delete target.
12056affb8ebSRam Kishore Vegesna 	if(!ocs->attached) {
12066affb8ebSRam Kishore Vegesna 		ocs_delete_target(ocs, fcp, tgt_id);
12076affb8ebSRam Kishore Vegesna 	} else {
12086affb8ebSRam Kishore Vegesna 		tgt->state = OCS_TGT_STATE_LOST;
12096affb8ebSRam Kishore Vegesna 		tgt->gone_timer = 30;
12106affb8ebSRam Kishore Vegesna 		if (!callout_active(&fcp->ldt)) {
12116affb8ebSRam Kishore Vegesna 			callout_reset(&fcp->ldt, hz, ocs_ldt, fcp);
12126affb8ebSRam Kishore Vegesna 		}
1213ef270ab1SKenneth D. Merry 	}
1214ef270ab1SKenneth D. Merry 
12156affb8ebSRam Kishore Vegesna 	return 0;
1216ef270ab1SKenneth D. Merry }
1217ef270ab1SKenneth D. Merry 
1218ef270ab1SKenneth D. Merry /**
1219ef270ab1SKenneth D. Merry  * @brief Initialize SCSI IO
1220ef270ab1SKenneth D. Merry  *
1221ef270ab1SKenneth D. Merry  * Initialize SCSI IO, this function is called once per IO during IO pool
1222ef270ab1SKenneth D. Merry  * allocation so that the target server may initialize any of its own private
1223ef270ab1SKenneth D. Merry  * data.
1224ef270ab1SKenneth D. Merry  *
1225ef270ab1SKenneth D. Merry  * @param io pointer to SCSI IO object
1226ef270ab1SKenneth D. Merry  *
1227ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1228ef270ab1SKenneth D. Merry  */
1229ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_io_init(ocs_io_t * io)1230ef270ab1SKenneth D. Merry ocs_scsi_tgt_io_init(ocs_io_t *io)
1231ef270ab1SKenneth D. Merry {
1232ef270ab1SKenneth D. Merry 	return 0;
1233ef270ab1SKenneth D. Merry }
1234ef270ab1SKenneth D. Merry 
1235ef270ab1SKenneth D. Merry /**
1236ef270ab1SKenneth D. Merry  * @brief Uninitialize SCSI IO
1237ef270ab1SKenneth D. Merry  *
1238ef270ab1SKenneth D. Merry  * Uninitialize target server private data in a SCSI io object
1239ef270ab1SKenneth D. Merry  *
1240ef270ab1SKenneth D. Merry  * @param io pointer to SCSI IO object
1241ef270ab1SKenneth D. Merry  *
1242ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1243ef270ab1SKenneth D. Merry  */
1244ef270ab1SKenneth D. Merry int32_t
ocs_scsi_tgt_io_exit(ocs_io_t * io)1245ef270ab1SKenneth D. Merry ocs_scsi_tgt_io_exit(ocs_io_t *io)
1246ef270ab1SKenneth D. Merry {
1247ef270ab1SKenneth D. Merry 	return 0;
1248ef270ab1SKenneth D. Merry }
1249ef270ab1SKenneth D. Merry 
1250ef270ab1SKenneth D. Merry /**
1251ef270ab1SKenneth D. Merry  * @brief Initialize SCSI IO
1252ef270ab1SKenneth D. Merry  *
1253ef270ab1SKenneth D. Merry  * Initialize SCSI IO, this function is called once per IO during IO pool
1254ef270ab1SKenneth D. Merry  * allocation so that the initiator client may initialize any of its own private
1255ef270ab1SKenneth D. Merry  * data.
1256ef270ab1SKenneth D. Merry  *
1257ef270ab1SKenneth D. Merry  * @param io pointer to SCSI IO object
1258ef270ab1SKenneth D. Merry  *
1259ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1260ef270ab1SKenneth D. Merry  */
1261ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_io_init(ocs_io_t * io)1262ef270ab1SKenneth D. Merry ocs_scsi_ini_io_init(ocs_io_t *io)
1263ef270ab1SKenneth D. Merry {
1264ef270ab1SKenneth D. Merry 	return 0;
1265ef270ab1SKenneth D. Merry }
1266ef270ab1SKenneth D. Merry 
1267ef270ab1SKenneth D. Merry /**
1268ef270ab1SKenneth D. Merry  * @brief Uninitialize SCSI IO
1269ef270ab1SKenneth D. Merry  *
1270ef270ab1SKenneth D. Merry  * Uninitialize initiator client private data in a SCSI io object
1271ef270ab1SKenneth D. Merry  *
1272ef270ab1SKenneth D. Merry  * @param io pointer to SCSI IO object
1273ef270ab1SKenneth D. Merry  *
1274ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1275ef270ab1SKenneth D. Merry  */
1276ef270ab1SKenneth D. Merry int32_t
ocs_scsi_ini_io_exit(ocs_io_t * io)1277ef270ab1SKenneth D. Merry ocs_scsi_ini_io_exit(ocs_io_t *io)
1278ef270ab1SKenneth D. Merry {
1279ef270ab1SKenneth D. Merry 	return 0;
1280ef270ab1SKenneth D. Merry }
1281ef270ab1SKenneth D. Merry /*
1282ef270ab1SKenneth D. Merry  * End of functions required by SCSI base driver API
1283ef270ab1SKenneth D. Merry  ***************************************************************************/
1284ef270ab1SKenneth D. Merry 
1285ef270ab1SKenneth D. Merry static __inline void
ocs_set_ccb_status(union ccb * ccb,cam_status status)1286ef270ab1SKenneth D. Merry ocs_set_ccb_status(union ccb *ccb, cam_status status)
1287ef270ab1SKenneth D. Merry {
1288ef270ab1SKenneth D. Merry 	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
1289ef270ab1SKenneth D. Merry 	ccb->ccb_h.status |= status;
1290ef270ab1SKenneth D. Merry }
1291ef270ab1SKenneth D. Merry 
1292ef270ab1SKenneth D. Merry static int32_t
ocs_task_set_full_or_busy_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,uint32_t flags,void * arg)1293ef270ab1SKenneth D. Merry ocs_task_set_full_or_busy_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status,
1294ef270ab1SKenneth D. Merry 						uint32_t flags, void *arg)
1295ef270ab1SKenneth D. Merry {
1296ef270ab1SKenneth D. Merry 
1297ef270ab1SKenneth D. Merry 	ocs_target_io_free(io);
1298ef270ab1SKenneth D. Merry 
1299ef270ab1SKenneth D. Merry 	return 0;
1300ef270ab1SKenneth D. Merry }
1301ef270ab1SKenneth D. Merry 
1302ef270ab1SKenneth D. Merry /**
1303ef270ab1SKenneth D. Merry  * @brief send SCSI task set full or busy status
1304ef270ab1SKenneth D. Merry  *
1305ef270ab1SKenneth D. Merry  * A SCSI task set full or busy response is sent depending on whether
1306ef270ab1SKenneth D. Merry  * another IO is already active on the LUN.
1307ef270ab1SKenneth D. Merry  *
1308ef270ab1SKenneth D. Merry  * @param io pointer to IO context
1309ef270ab1SKenneth D. Merry  *
1310ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1311ef270ab1SKenneth D. Merry  */
1312ef270ab1SKenneth D. Merry 
1313ef270ab1SKenneth D. Merry static int32_t
ocs_task_set_full_or_busy(ocs_io_t * io)1314ef270ab1SKenneth D. Merry ocs_task_set_full_or_busy(ocs_io_t *io)
1315ef270ab1SKenneth D. Merry {
1316ef270ab1SKenneth D. Merry 	ocs_scsi_cmd_resp_t rsp = { 0 };
1317ef270ab1SKenneth D. Merry 	ocs_t *ocs = io->ocs;
1318ef270ab1SKenneth D. Merry 
1319ef270ab1SKenneth D. Merry 	/*
1320ef270ab1SKenneth D. Merry 	 * If there is another command for the LUN, then send task set full,
1321ef270ab1SKenneth D. Merry 	 * if this is the first one, then send the busy status.
1322ef270ab1SKenneth D. Merry 	 *
1323ef270ab1SKenneth D. Merry 	 * if 'busy sent' is FALSE, set it to TRUE and send BUSY
1324ef270ab1SKenneth D. Merry 	 * otherwise send FULL
1325ef270ab1SKenneth D. Merry 	 */
1326ef270ab1SKenneth D. Merry 	if (atomic_cmpset_acq_32(&io->node->tgt_node.busy_sent, FALSE, TRUE)) {
1327ef270ab1SKenneth D. Merry 		rsp.scsi_status = SCSI_STATUS_BUSY; /* Busy */
1328ef270ab1SKenneth D. Merry 		printf("%s: busy [%s] tag=%x iiu=%d ihw=%d\n", __func__,
1329ef270ab1SKenneth D. Merry 				io->node->display_name, io->tag,
1330ef270ab1SKenneth D. Merry 				io->ocs->io_in_use, io->ocs->io_high_watermark);
1331ef270ab1SKenneth D. Merry 	} else {
1332ef270ab1SKenneth D. Merry 		rsp.scsi_status = SCSI_STATUS_TASK_SET_FULL; /* Task set full */
1333ef270ab1SKenneth D. Merry 		printf("%s: full tag=%x iiu=%d\n", __func__, io->tag,
1334ef270ab1SKenneth D. Merry 			io->ocs->io_in_use);
1335ef270ab1SKenneth D. Merry 	}
1336ef270ab1SKenneth D. Merry 
1337ef270ab1SKenneth D. Merry 	/* Log a message here indicating a busy or task set full state */
1338ef270ab1SKenneth D. Merry 	if (OCS_LOG_ENABLE_Q_FULL_BUSY_MSG(ocs)) {
1339ef270ab1SKenneth D. Merry 		/* Log Task Set Full */
1340ef270ab1SKenneth D. Merry 		if (rsp.scsi_status == SCSI_STATUS_TASK_SET_FULL) {
1341ef270ab1SKenneth D. Merry 			/* Task Set Full Message */
1342ef270ab1SKenneth D. Merry 			ocs_log_info(ocs, "OCS CAM TASK SET FULL. Tasks >= %d\n",
1343ef270ab1SKenneth D. Merry 			 		ocs->io_high_watermark);
1344ef270ab1SKenneth D. Merry 		}
1345ef270ab1SKenneth D. Merry 		else if (rsp.scsi_status == SCSI_STATUS_BUSY) {
1346ef270ab1SKenneth D. Merry 			/* Log Busy Message */
1347ef270ab1SKenneth D. Merry 			ocs_log_info(ocs, "OCS CAM SCSI BUSY\n");
1348ef270ab1SKenneth D. Merry 		}
1349ef270ab1SKenneth D. Merry 	}
1350ef270ab1SKenneth D. Merry 
1351ef270ab1SKenneth D. Merry 	/* Send the response */
1352ef270ab1SKenneth D. Merry 	return
1353ef270ab1SKenneth D. Merry 	ocs_scsi_send_resp(io, 0, &rsp, ocs_task_set_full_or_busy_cb, NULL);
1354ef270ab1SKenneth D. Merry }
1355ef270ab1SKenneth D. Merry 
1356ef270ab1SKenneth D. Merry /**
1357ef270ab1SKenneth D. Merry  * @ingroup cam_io
1358ef270ab1SKenneth D. Merry  * @brief Process target IO completions
1359ef270ab1SKenneth D. Merry  *
1360ef270ab1SKenneth D. Merry  * @param io
1361ef270ab1SKenneth D. Merry  * @param scsi_status did the IO complete successfully
1362ef270ab1SKenneth D. Merry  * @param flags
1363ef270ab1SKenneth D. Merry  * @param arg application specific pointer provided in the call to ocs_target_io()
1364ef270ab1SKenneth D. Merry  *
1365ef270ab1SKenneth D. Merry  * @todo
1366ef270ab1SKenneth D. Merry  */
ocs_scsi_target_io_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,uint32_t flags,void * arg)1367ef270ab1SKenneth D. Merry static int32_t ocs_scsi_target_io_cb(ocs_io_t *io,
1368ef270ab1SKenneth D. Merry 				ocs_scsi_io_status_e scsi_status,
1369ef270ab1SKenneth D. Merry 				uint32_t flags, void *arg)
1370ef270ab1SKenneth D. Merry {
1371ef270ab1SKenneth D. Merry 	union ccb *ccb = arg;
1372ef270ab1SKenneth D. Merry 	struct ccb_scsiio *csio = &ccb->csio;
1373ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = csio->ccb_h.ccb_ocs_ptr;
1374ef270ab1SKenneth D. Merry 	uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1375ef270ab1SKenneth D. Merry 	uint32_t io_is_done =
1376ef270ab1SKenneth D. Merry 		(ccb->ccb_h.flags & CAM_SEND_STATUS) == CAM_SEND_STATUS;
1377ef270ab1SKenneth D. Merry 
1378ef270ab1SKenneth D. Merry 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1379ef270ab1SKenneth D. Merry 
1380ef270ab1SKenneth D. Merry 	if (CAM_DIR_NONE != cam_dir) {
1381ef270ab1SKenneth D. Merry 		bus_dmasync_op_t op;
1382ef270ab1SKenneth D. Merry 
1383ef270ab1SKenneth D. Merry 		if (CAM_DIR_IN == cam_dir) {
1384ef270ab1SKenneth D. Merry 			op = BUS_DMASYNC_POSTREAD;
1385ef270ab1SKenneth D. Merry 		} else {
1386ef270ab1SKenneth D. Merry 			op = BUS_DMASYNC_POSTWRITE;
1387ef270ab1SKenneth D. Merry 		}
1388ef270ab1SKenneth D. Merry 		/* Synchronize the DMA memory with the CPU and free the mapping */
1389ef270ab1SKenneth D. Merry 		bus_dmamap_sync(ocs->buf_dmat, io->tgt_io.dmap, op);
1390ef270ab1SKenneth D. Merry 		if (io->tgt_io.flags & OCS_CAM_IO_F_DMAPPED) {
1391ef270ab1SKenneth D. Merry 			bus_dmamap_unload(ocs->buf_dmat, io->tgt_io.dmap);
1392ef270ab1SKenneth D. Merry 		}
1393ef270ab1SKenneth D. Merry 	}
1394ef270ab1SKenneth D. Merry 
1395ef270ab1SKenneth D. Merry 	if (io->tgt_io.sendresp) {
1396ef270ab1SKenneth D. Merry 		io->tgt_io.sendresp = 0;
1397ef270ab1SKenneth D. Merry 		ocs_scsi_cmd_resp_t  resp = { 0 };
1398ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_RESP;
1399ef270ab1SKenneth D. Merry 		resp.scsi_status = scsi_status;
1400ef270ab1SKenneth D. Merry 		if (ccb->ccb_h.flags & CAM_SEND_SENSE) {
1401ef270ab1SKenneth D. Merry 			resp.sense_data = (uint8_t *)&csio->sense_data;
1402ef270ab1SKenneth D. Merry 			resp.sense_data_length = csio->sense_len;
1403ef270ab1SKenneth D. Merry 		}
1404ef270ab1SKenneth D. Merry 		resp.residual = io->exp_xfer_len - io->transferred;
1405ef270ab1SKenneth D. Merry 
1406ef270ab1SKenneth D. Merry 		return ocs_scsi_send_resp(io, 0, &resp, ocs_scsi_target_io_cb, ccb);
1407ef270ab1SKenneth D. Merry 	}
1408ef270ab1SKenneth D. Merry 
1409ef270ab1SKenneth D. Merry 	switch (scsi_status) {
1410ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_GOOD:
1411ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
1412ef270ab1SKenneth D. Merry 		break;
1413ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_ABORTED:
1414ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_ABORTED);
1415ef270ab1SKenneth D. Merry 		break;
1416ef270ab1SKenneth D. Merry 	default:
1417ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
1418ef270ab1SKenneth D. Merry 	}
1419ef270ab1SKenneth D. Merry 
1420ef270ab1SKenneth D. Merry 	if (io_is_done) {
1421ef270ab1SKenneth D. Merry 		if ((io->tgt_io.flags & OCS_CAM_IO_F_ABORT_NOTIFY) == 0) {
1422ef270ab1SKenneth D. Merry 			ocs_target_io_free(io);
1423ef270ab1SKenneth D. Merry 		}
1424ef270ab1SKenneth D. Merry 	} else {
1425ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_DATA_DONE;
1426ef270ab1SKenneth D. Merry 		/*device_printf(ocs->dev, "%s: CTIO state=%d tag=%#x\n",
1427ef270ab1SKenneth D. Merry 				__func__, io->tgt_io.state, io->tag);*/
1428ef270ab1SKenneth D. Merry 	}
1429ef270ab1SKenneth D. Merry 
1430ef270ab1SKenneth D. Merry 	xpt_done(ccb);
1431ef270ab1SKenneth D. Merry 
1432ef270ab1SKenneth D. Merry 	return 0;
1433ef270ab1SKenneth D. Merry }
1434ef270ab1SKenneth D. Merry 
1435ef270ab1SKenneth D. Merry /**
1436ef270ab1SKenneth D. Merry  * @note	1. Since the CCB is assigned to the ocs_io_t on an XPT_CONT_TARGET_IO
1437ef270ab1SKenneth D. Merry  * 		   action, if an initiator aborts a command prior to the SIM receiving
1438ef270ab1SKenneth D. Merry  * 		   a CTIO, the IO's CCB will be NULL.
1439ef270ab1SKenneth D. Merry  */
1440ef270ab1SKenneth D. Merry static int32_t
ocs_io_abort_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,uint32_t flags,void * arg)1441ef270ab1SKenneth D. Merry ocs_io_abort_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
1442ef270ab1SKenneth D. Merry {
1443ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = NULL;
1444ef270ab1SKenneth D. Merry 	ocs_io_t	*tmfio = arg;
1445ef270ab1SKenneth D. Merry 	ocs_scsi_tmf_resp_e tmf_resp = OCS_SCSI_TMF_FUNCTION_COMPLETE;
1446ef270ab1SKenneth D. Merry 	int32_t	rc = 0;
1447ef270ab1SKenneth D. Merry 
1448ef270ab1SKenneth D. Merry 	ocs = io->ocs;
1449ef270ab1SKenneth D. Merry 
1450ef270ab1SKenneth D. Merry 	io->tgt_io.flags &= ~OCS_CAM_IO_F_ABORT_DEV;
1451ef270ab1SKenneth D. Merry 
1452ef270ab1SKenneth D. Merry 	/* A good status indicates the IO was aborted and will be completed in
1453ef270ab1SKenneth D. Merry 	 * the IO's completion handler. Handle the other cases here. */
1454ef270ab1SKenneth D. Merry 	switch (scsi_status) {
1455ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_GOOD:
1456ef270ab1SKenneth D. Merry 		break;
1457ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_NO_IO:
1458ef270ab1SKenneth D. Merry 		break;
1459ef270ab1SKenneth D. Merry 	default:
1460ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: unhandled status %d\n",
1461ef270ab1SKenneth D. Merry 				__func__, scsi_status);
1462ef270ab1SKenneth D. Merry 		tmf_resp = OCS_SCSI_TMF_FUNCTION_REJECTED;
1463ef270ab1SKenneth D. Merry 		rc = -1;
1464ef270ab1SKenneth D. Merry 	}
1465ef270ab1SKenneth D. Merry 
1466ef270ab1SKenneth D. Merry 	ocs_scsi_send_tmf_resp(tmfio, tmf_resp, NULL, ocs_target_tmf_cb, NULL);
1467ef270ab1SKenneth D. Merry 
1468ef270ab1SKenneth D. Merry 	return rc;
1469ef270ab1SKenneth D. Merry }
1470ef270ab1SKenneth D. Merry 
1471ef270ab1SKenneth D. Merry /**
1472ef270ab1SKenneth D. Merry  * @ingroup cam_io
1473ef270ab1SKenneth D. Merry  * @brief Process initiator IO completions
1474ef270ab1SKenneth D. Merry  *
1475ef270ab1SKenneth D. Merry  * @param io
1476ef270ab1SKenneth D. Merry  * @param scsi_status did the IO complete successfully
1477ef270ab1SKenneth D. Merry  * @param rsp pointer to response buffer
1478ef270ab1SKenneth D. Merry  * @param flags
1479ef270ab1SKenneth D. Merry  * @param arg application specific pointer provided in the call to ocs_target_io()
1480ef270ab1SKenneth D. Merry  *
1481ef270ab1SKenneth D. Merry  * @todo
1482ef270ab1SKenneth D. Merry  */
ocs_scsi_initiator_io_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,ocs_scsi_cmd_resp_t * rsp,uint32_t flags,void * arg)1483ef270ab1SKenneth D. Merry static int32_t ocs_scsi_initiator_io_cb(ocs_io_t *io,
1484ef270ab1SKenneth D. Merry 					ocs_scsi_io_status_e scsi_status,
1485ef270ab1SKenneth D. Merry 					ocs_scsi_cmd_resp_t *rsp,
1486ef270ab1SKenneth D. Merry 					uint32_t flags, void *arg)
1487ef270ab1SKenneth D. Merry {
1488ef270ab1SKenneth D. Merry 	union ccb *ccb = arg;
1489ef270ab1SKenneth D. Merry 	struct ccb_scsiio *csio = &ccb->csio;
1490ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = csio->ccb_h.ccb_ocs_ptr;
1491ef270ab1SKenneth D. Merry 	uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1492ef270ab1SKenneth D. Merry 	cam_status ccb_status= CAM_REQ_CMP_ERR;
1493ef270ab1SKenneth D. Merry 
1494ef270ab1SKenneth D. Merry 	if (CAM_DIR_NONE != cam_dir) {
1495ef270ab1SKenneth D. Merry 		bus_dmasync_op_t op;
1496ef270ab1SKenneth D. Merry 
1497ef270ab1SKenneth D. Merry 		if (CAM_DIR_IN == cam_dir) {
1498ef270ab1SKenneth D. Merry 			op = BUS_DMASYNC_POSTREAD;
1499ef270ab1SKenneth D. Merry 		} else {
1500ef270ab1SKenneth D. Merry 			op = BUS_DMASYNC_POSTWRITE;
1501ef270ab1SKenneth D. Merry 		}
1502ef270ab1SKenneth D. Merry 		/* Synchronize the DMA memory with the CPU and free the mapping */
1503ef270ab1SKenneth D. Merry 		bus_dmamap_sync(ocs->buf_dmat, io->tgt_io.dmap, op);
1504ef270ab1SKenneth D. Merry 		if (io->tgt_io.flags & OCS_CAM_IO_F_DMAPPED) {
1505ef270ab1SKenneth D. Merry 			bus_dmamap_unload(ocs->buf_dmat, io->tgt_io.dmap);
1506ef270ab1SKenneth D. Merry 		}
1507ef270ab1SKenneth D. Merry 	}
1508ef270ab1SKenneth D. Merry 
1509ef270ab1SKenneth D. Merry 	if (scsi_status == OCS_SCSI_STATUS_CHECK_RESPONSE) {
1510ef270ab1SKenneth D. Merry 		csio->scsi_status = rsp->scsi_status;
15111af49c2eSRam Kishore Vegesna 		if (SCSI_STATUS_OK != rsp->scsi_status)
1512ef270ab1SKenneth D. Merry 			ccb_status = CAM_SCSI_STATUS_ERROR;
15131af49c2eSRam Kishore Vegesna 		else
15141af49c2eSRam Kishore Vegesna 			ccb_status = CAM_REQ_CMP;
1515ef270ab1SKenneth D. Merry 
1516ef270ab1SKenneth D. Merry 		csio->resid = rsp->residual;
15171af49c2eSRam Kishore Vegesna 
15181af49c2eSRam Kishore Vegesna 		/*
15191af49c2eSRam Kishore Vegesna 		 * If we've already got a SCSI error, prefer that because it
15201af49c2eSRam Kishore Vegesna 		 * will have more detail.
15211af49c2eSRam Kishore Vegesna 		 */
15221af49c2eSRam Kishore Vegesna 		if ((rsp->residual < 0) && (ccb_status == CAM_REQ_CMP)) {
1523ef270ab1SKenneth D. Merry 			ccb_status = CAM_DATA_RUN_ERR;
1524ef270ab1SKenneth D. Merry 		}
1525ef270ab1SKenneth D. Merry 
1526ef270ab1SKenneth D. Merry 		if ((rsp->sense_data_length) &&
1527ef270ab1SKenneth D. Merry 			!(ccb->ccb_h.flags & (CAM_SENSE_PHYS | CAM_SENSE_PTR))) {
1528ef270ab1SKenneth D. Merry 			uint32_t	sense_len = 0;
1529ef270ab1SKenneth D. Merry 
1530ef270ab1SKenneth D. Merry 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1531ef270ab1SKenneth D. Merry 			if (rsp->sense_data_length < csio->sense_len) {
1532ef270ab1SKenneth D. Merry 				csio->sense_resid =
1533ef270ab1SKenneth D. Merry 					csio->sense_len - rsp->sense_data_length;
1534ef270ab1SKenneth D. Merry 				sense_len = rsp->sense_data_length;
1535ef270ab1SKenneth D. Merry 			} else {
1536ef270ab1SKenneth D. Merry 				csio->sense_resid = 0;
1537ef270ab1SKenneth D. Merry 				sense_len = csio->sense_len;
1538ef270ab1SKenneth D. Merry 			}
1539ef270ab1SKenneth D. Merry 			ocs_memcpy(&csio->sense_data, rsp->sense_data, sense_len);
1540ef270ab1SKenneth D. Merry 		}
1541ef270ab1SKenneth D. Merry 	} else if (scsi_status != OCS_SCSI_STATUS_GOOD) {
154270547544SRam Kishore Vegesna 		const char *err_desc = NULL;
154370547544SRam Kishore Vegesna 		char err_str[224];
154470547544SRam Kishore Vegesna 		struct sbuf sb;
154570547544SRam Kishore Vegesna 		size_t i;
154670547544SRam Kishore Vegesna 
154770547544SRam Kishore Vegesna 		sbuf_new(&sb, err_str, sizeof(err_str), 0);
154870547544SRam Kishore Vegesna 
1549a9504d76SRam Kishore Vegesna 		xpt_path_sbuf(ccb->ccb_h.path, &sb);
155070547544SRam Kishore Vegesna 
155170547544SRam Kishore Vegesna 		for (i = 0; i < (sizeof(ocs_status_desc) /
155270547544SRam Kishore Vegesna 		     sizeof(ocs_status_desc[0])); i++) {
155370547544SRam Kishore Vegesna 			if (scsi_status == ocs_status_desc[i].status) {
155470547544SRam Kishore Vegesna 				err_desc = ocs_status_desc[i].desc;
155570547544SRam Kishore Vegesna 				break;
155670547544SRam Kishore Vegesna 			}
155770547544SRam Kishore Vegesna 		}
155870547544SRam Kishore Vegesna 		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
155970547544SRam Kishore Vegesna 			scsi_command_string(&ccb->csio, &sb);
156070547544SRam Kishore Vegesna 			sbuf_printf(&sb, "length %d ", ccb->csio.dxfer_len);
156170547544SRam Kishore Vegesna 		}
156270547544SRam Kishore Vegesna 		sbuf_printf(&sb, "error status %d (%s)\n", scsi_status,
156370547544SRam Kishore Vegesna 		    (err_desc != NULL) ? err_desc : "Unknown");
156470547544SRam Kishore Vegesna 		sbuf_finish(&sb);
156570547544SRam Kishore Vegesna 		printf("%s", sbuf_data(&sb));
156670547544SRam Kishore Vegesna 
156770547544SRam Kishore Vegesna 		switch (scsi_status) {
156870547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_ABORTED:
156970547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_ABORT_IN_PROGRESS:
157070547544SRam Kishore Vegesna 			ccb_status = CAM_REQ_ABORTED;
157170547544SRam Kishore Vegesna 			break;
157270547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_DIF_GUARD_ERROR:
157370547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_DIF_REF_TAG_ERROR:
157470547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_DIF_APP_TAG_ERROR:
157570547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR:
157670547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_PROTOCOL_CRC_ERROR:
157770547544SRam Kishore Vegesna 			ccb_status = CAM_IDE;
157870547544SRam Kishore Vegesna 			break;
157970547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_ERROR:
158070547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_NO_IO:
1581ef270ab1SKenneth D. Merry 			ccb_status = CAM_REQ_CMP_ERR;
158270547544SRam Kishore Vegesna 			break;
158370547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_COMMAND_TIMEOUT:
158470547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED:
158570547544SRam Kishore Vegesna 			ccb_status = CAM_CMD_TIMEOUT;
158670547544SRam Kishore Vegesna 			break;
158770547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_SHUTDOWN:
158870547544SRam Kishore Vegesna 		case OCS_SCSI_STATUS_NEXUS_LOST:
158970547544SRam Kishore Vegesna 			ccb_status = CAM_SCSI_IT_NEXUS_LOST;
159070547544SRam Kishore Vegesna 			break;
159170547544SRam Kishore Vegesna 		default:
159270547544SRam Kishore Vegesna 			ccb_status = CAM_REQ_CMP_ERR;
159370547544SRam Kishore Vegesna 			break;
159470547544SRam Kishore Vegesna 		}
159570547544SRam Kishore Vegesna 
1596ef270ab1SKenneth D. Merry 	} else {
1597ef270ab1SKenneth D. Merry 		ccb_status = CAM_REQ_CMP;
1598ef270ab1SKenneth D. Merry 	}
1599ef270ab1SKenneth D. Merry 
1600ef270ab1SKenneth D. Merry 	ocs_set_ccb_status(ccb, ccb_status);
1601ef270ab1SKenneth D. Merry 
1602ef270ab1SKenneth D. Merry 	ocs_scsi_io_free(io);
1603ef270ab1SKenneth D. Merry 
1604ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_io_ptr = NULL;
1605ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_ocs_ptr = NULL;
1606d063d1bcSRam Kishore Vegesna 
1607ef270ab1SKenneth D. Merry 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1608ef270ab1SKenneth D. Merry 
1609d063d1bcSRam Kishore Vegesna 	if ((ccb_status != CAM_REQ_CMP) &&
1610d063d1bcSRam Kishore Vegesna 	    ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0)) {
1611d063d1bcSRam Kishore Vegesna 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
1612d063d1bcSRam Kishore Vegesna 		xpt_freeze_devq(ccb->ccb_h.path, 1);
1613d063d1bcSRam Kishore Vegesna 	}
1614d063d1bcSRam Kishore Vegesna 
1615ef270ab1SKenneth D. Merry 	xpt_done(ccb);
1616ef270ab1SKenneth D. Merry 
1617ef270ab1SKenneth D. Merry 	return 0;
1618ef270ab1SKenneth D. Merry }
1619ef270ab1SKenneth D. Merry 
1620ef270ab1SKenneth D. Merry /**
1621ef270ab1SKenneth D. Merry  * @brief Load scatter-gather list entries into an IO
1622ef270ab1SKenneth D. Merry  *
1623ef270ab1SKenneth D. Merry  * This routine relies on the driver instance's software context pointer and
1624ef270ab1SKenneth D. Merry  * the IO object pointer having been already assigned to hooks in the CCB.
1625ef270ab1SKenneth D. Merry  * Although the routine does not return success/fail, callers can look at the
1626ef270ab1SKenneth D. Merry  * n_sge member to determine if the mapping failed (0 on failure).
1627ef270ab1SKenneth D. Merry  *
1628ef270ab1SKenneth D. Merry  * @param arg pointer to the CAM ccb for this IO
1629ef270ab1SKenneth D. Merry  * @param seg DMA address/length pairs
1630ef270ab1SKenneth D. Merry  * @param nseg number of DMA address/length pairs
1631ef270ab1SKenneth D. Merry  * @param error any errors while mapping the IO
1632ef270ab1SKenneth D. Merry  */
1633ef270ab1SKenneth D. Merry static void
ocs_scsi_dmamap_load(void * arg,bus_dma_segment_t * seg,int nseg,int error)1634ef270ab1SKenneth D. Merry ocs_scsi_dmamap_load(void *arg, bus_dma_segment_t *seg, int nseg, int error)
1635ef270ab1SKenneth D. Merry {
1636ef270ab1SKenneth D. Merry 	ocs_dmamap_load_arg_t *sglarg = (ocs_dmamap_load_arg_t*) arg;
1637ef270ab1SKenneth D. Merry 
1638ef270ab1SKenneth D. Merry 	if (error) {
1639ef270ab1SKenneth D. Merry 		printf("%s: seg=%p nseg=%d error=%d\n",
1640ef270ab1SKenneth D. Merry 				__func__, seg, nseg, error);
1641ef270ab1SKenneth D. Merry 		sglarg->rc = -1;
1642ef270ab1SKenneth D. Merry 	} else {
1643ef270ab1SKenneth D. Merry 		uint32_t i = 0;
1644ef270ab1SKenneth D. Merry 		uint32_t c = 0;
1645ef270ab1SKenneth D. Merry 
1646ef270ab1SKenneth D. Merry 		if ((sglarg->sgl_count + nseg) > sglarg->sgl_max) {
1647ef270ab1SKenneth D. Merry 			printf("%s: sgl_count=%d nseg=%d max=%d\n", __func__,
1648ef270ab1SKenneth D. Merry 				sglarg->sgl_count, nseg, sglarg->sgl_max);
1649ef270ab1SKenneth D. Merry 			sglarg->rc = -2;
1650ef270ab1SKenneth D. Merry 			return;
1651ef270ab1SKenneth D. Merry 		}
1652ef270ab1SKenneth D. Merry 
1653ef270ab1SKenneth D. Merry 		for (i = 0, c = sglarg->sgl_count; i < nseg; i++, c++) {
1654ef270ab1SKenneth D. Merry 			sglarg->sgl[c].addr = seg[i].ds_addr;
1655ef270ab1SKenneth D. Merry 			sglarg->sgl[c].len  = seg[i].ds_len;
1656ef270ab1SKenneth D. Merry 		}
1657ef270ab1SKenneth D. Merry 
1658ef270ab1SKenneth D. Merry 		sglarg->sgl_count = c;
1659ef270ab1SKenneth D. Merry 
1660ef270ab1SKenneth D. Merry 		sglarg->rc = 0;
1661ef270ab1SKenneth D. Merry 	}
1662ef270ab1SKenneth D. Merry }
1663ef270ab1SKenneth D. Merry 
1664ef270ab1SKenneth D. Merry /**
1665ef270ab1SKenneth D. Merry  * @brief Build a scatter-gather list from a CAM CCB
1666ef270ab1SKenneth D. Merry  *
1667ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
1668ef270ab1SKenneth D. Merry  * @param ccb pointer to the CCB
1669ef270ab1SKenneth D. Merry  * @param io pointer to the previously allocated IO object
1670ef270ab1SKenneth D. Merry  * @param sgl pointer to SGL
1671ef270ab1SKenneth D. Merry  * @param sgl_max number of entries in sgl
1672ef270ab1SKenneth D. Merry  *
1673ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
1674ef270ab1SKenneth D. Merry  */
1675ef270ab1SKenneth D. Merry static int32_t
ocs_build_scsi_sgl(struct ocs_softc * ocs,union ccb * ccb,ocs_io_t * io,ocs_scsi_sgl_t * sgl,uint32_t sgl_max)1676ef270ab1SKenneth D. Merry ocs_build_scsi_sgl(struct ocs_softc *ocs, union ccb *ccb, ocs_io_t *io,
1677ef270ab1SKenneth D. Merry 		ocs_scsi_sgl_t *sgl, uint32_t sgl_max)
1678ef270ab1SKenneth D. Merry {
1679ef270ab1SKenneth D. Merry 	ocs_dmamap_load_arg_t dmaarg;
1680ef270ab1SKenneth D. Merry 	int32_t	err = 0;
1681ef270ab1SKenneth D. Merry 
1682ef270ab1SKenneth D. Merry 	if (!ocs || !ccb || !io || !sgl) {
1683ef270ab1SKenneth D. Merry 		printf("%s: bad param o=%p c=%p i=%p s=%p\n", __func__,
1684ef270ab1SKenneth D. Merry 				ocs, ccb, io, sgl);
1685ef270ab1SKenneth D. Merry 		return -1;
1686ef270ab1SKenneth D. Merry 	}
1687ef270ab1SKenneth D. Merry 
1688ef270ab1SKenneth D. Merry 	io->tgt_io.flags &= ~OCS_CAM_IO_F_DMAPPED;
1689ef270ab1SKenneth D. Merry 
1690ef270ab1SKenneth D. Merry 	dmaarg.sgl = sgl;
1691ef270ab1SKenneth D. Merry 	dmaarg.sgl_count = 0;
1692ef270ab1SKenneth D. Merry 	dmaarg.sgl_max = sgl_max;
1693ef270ab1SKenneth D. Merry 	dmaarg.rc = 0;
1694ef270ab1SKenneth D. Merry 
1695ef270ab1SKenneth D. Merry 	err = bus_dmamap_load_ccb(ocs->buf_dmat, io->tgt_io.dmap, ccb,
1696ef270ab1SKenneth D. Merry 			ocs_scsi_dmamap_load, &dmaarg, 0);
1697ef270ab1SKenneth D. Merry 
1698ef270ab1SKenneth D. Merry 	if (err || dmaarg.rc) {
1699ef270ab1SKenneth D. Merry 		device_printf(
1700ef270ab1SKenneth D. Merry 			ocs->dev, "%s: bus_dmamap_load_ccb error (%d %d)\n",
1701ef270ab1SKenneth D. Merry 				__func__, err, dmaarg.rc);
1702ef270ab1SKenneth D. Merry 		return -1;
1703ef270ab1SKenneth D. Merry 	}
1704ef270ab1SKenneth D. Merry 
1705ef270ab1SKenneth D. Merry 	io->tgt_io.flags |= OCS_CAM_IO_F_DMAPPED;
1706ef270ab1SKenneth D. Merry 	return dmaarg.sgl_count;
1707ef270ab1SKenneth D. Merry }
1708ef270ab1SKenneth D. Merry 
1709ef270ab1SKenneth D. Merry /**
1710ef270ab1SKenneth D. Merry  * @ingroup cam_io
1711ef270ab1SKenneth D. Merry  * @brief Send a target IO
1712ef270ab1SKenneth D. Merry  *
1713ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
1714ef270ab1SKenneth D. Merry  * @param ccb pointer to the CCB
1715ef270ab1SKenneth D. Merry  *
1716ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
1717ef270ab1SKenneth D. Merry  */
1718ef270ab1SKenneth D. Merry static int32_t
ocs_target_io(struct ocs_softc * ocs,union ccb * ccb)1719ef270ab1SKenneth D. Merry ocs_target_io(struct ocs_softc *ocs, union ccb *ccb)
1720ef270ab1SKenneth D. Merry {
1721ef270ab1SKenneth D. Merry 	struct ccb_scsiio *csio = &ccb->csio;
1722ef270ab1SKenneth D. Merry 	ocs_io_t *io = NULL;
1723ef270ab1SKenneth D. Merry 	uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK;
1724ef270ab1SKenneth D. Merry 	bool sendstatus = ccb->ccb_h.flags & CAM_SEND_STATUS;
1725ef270ab1SKenneth D. Merry 	uint32_t xferlen = csio->dxfer_len;
1726ef270ab1SKenneth D. Merry 	int32_t rc = 0;
1727ef270ab1SKenneth D. Merry 
1728ef270ab1SKenneth D. Merry 	io = ocs_scsi_find_io(ocs, csio->tag_id);
1729ef270ab1SKenneth D. Merry 	if (io == NULL) {
1730ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
1731ef270ab1SKenneth D. Merry 		panic("bad tag value");
1732ef270ab1SKenneth D. Merry 		return 1;
1733ef270ab1SKenneth D. Merry 	}
1734ef270ab1SKenneth D. Merry 
1735ef270ab1SKenneth D. Merry 	/* Received an ABORT TASK for this IO */
1736ef270ab1SKenneth D. Merry 	if (io->tgt_io.flags & OCS_CAM_IO_F_ABORT_RECV) {
1737ef270ab1SKenneth D. Merry 		/*device_printf(ocs->dev,
1738ef270ab1SKenneth D. Merry 			"%s: XPT_CONT_TARGET_IO state=%d tag=%#x xid=%#x flags=%#x\n",
1739ef270ab1SKenneth D. Merry 			__func__, io->tgt_io.state, io->tag, io->init_task_tag,
1740ef270ab1SKenneth D. Merry 			io->tgt_io.flags);*/
1741ef270ab1SKenneth D. Merry 		io->tgt_io.flags |= OCS_CAM_IO_F_ABORT_CAM;
1742ef270ab1SKenneth D. Merry 
1743ef270ab1SKenneth D. Merry 		if (ccb->ccb_h.flags & CAM_SEND_STATUS) {
1744ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP);
1745ef270ab1SKenneth D. Merry 			ocs_target_io_free(io);
1746ef270ab1SKenneth D. Merry 			return 1;
1747ef270ab1SKenneth D. Merry 		}
1748ef270ab1SKenneth D. Merry 
1749ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_ABORTED);
1750ef270ab1SKenneth D. Merry 
1751ef270ab1SKenneth D. Merry 		return 1;
1752ef270ab1SKenneth D. Merry 	}
1753ef270ab1SKenneth D. Merry 
1754ef270ab1SKenneth D. Merry 	io->tgt_io.app = ccb;
1755ef270ab1SKenneth D. Merry 
1756ef270ab1SKenneth D. Merry 	ocs_set_ccb_status(ccb, CAM_REQ_INPROG);
1757ef270ab1SKenneth D. Merry 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1758ef270ab1SKenneth D. Merry 
1759ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_ocs_ptr = ocs;
1760ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_io_ptr  = io;
1761ef270ab1SKenneth D. Merry 
1762ef270ab1SKenneth D. Merry 	if ((sendstatus && (xferlen == 0))) {
1763ef270ab1SKenneth D. Merry 		ocs_scsi_cmd_resp_t	resp = { 0 };
1764ef270ab1SKenneth D. Merry 
1765ef270ab1SKenneth D. Merry 		ocs_assert(ccb->ccb_h.flags & CAM_SEND_STATUS, -1);
1766ef270ab1SKenneth D. Merry 
1767ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_RESP;
1768ef270ab1SKenneth D. Merry 
1769ef270ab1SKenneth D. Merry 		resp.scsi_status = csio->scsi_status;
1770ef270ab1SKenneth D. Merry 
1771ef270ab1SKenneth D. Merry 		if (ccb->ccb_h.flags & CAM_SEND_SENSE) {
1772ef270ab1SKenneth D. Merry 			resp.sense_data = (uint8_t *)&csio->sense_data;
1773ef270ab1SKenneth D. Merry 			resp.sense_data_length = csio->sense_len;
1774ef270ab1SKenneth D. Merry 		}
1775ef270ab1SKenneth D. Merry 
1776ef270ab1SKenneth D. Merry 		resp.residual = io->exp_xfer_len - io->transferred;
1777ef270ab1SKenneth D. Merry 		rc = ocs_scsi_send_resp(io, 0, &resp, ocs_scsi_target_io_cb, ccb);
1778ef270ab1SKenneth D. Merry 
1779ef270ab1SKenneth D. Merry 	} else if (xferlen != 0) {
1780322dbb8cSRam Kishore Vegesna 		ocs_scsi_sgl_t *sgl;
1781ef270ab1SKenneth D. Merry 		int32_t sgl_count = 0;
1782ef270ab1SKenneth D. Merry 
1783ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_DATA;
1784ef270ab1SKenneth D. Merry 
1785ef270ab1SKenneth D. Merry 		if (sendstatus)
1786ef270ab1SKenneth D. Merry 			io->tgt_io.sendresp = 1;
1787ef270ab1SKenneth D. Merry 
1788322dbb8cSRam Kishore Vegesna 		sgl = io->sgl;
1789322dbb8cSRam Kishore Vegesna 
1790322dbb8cSRam Kishore Vegesna 		sgl_count = ocs_build_scsi_sgl(ocs, ccb, io, sgl, io->sgl_allocated);
1791ef270ab1SKenneth D. Merry 		if (sgl_count > 0) {
1792ef270ab1SKenneth D. Merry 			if (cam_dir == CAM_DIR_IN) {
1793ef270ab1SKenneth D. Merry 				rc = ocs_scsi_send_rd_data(io, 0, NULL, sgl,
1794ef270ab1SKenneth D. Merry 						sgl_count, csio->dxfer_len,
1795ef270ab1SKenneth D. Merry 						ocs_scsi_target_io_cb, ccb);
1796ef270ab1SKenneth D. Merry 			} else if (cam_dir == CAM_DIR_OUT) {
1797ef270ab1SKenneth D. Merry 				rc = ocs_scsi_recv_wr_data(io, 0, NULL, sgl,
1798ef270ab1SKenneth D. Merry 						sgl_count, csio->dxfer_len,
1799ef270ab1SKenneth D. Merry 						ocs_scsi_target_io_cb, ccb);
1800ef270ab1SKenneth D. Merry 			} else {
1801ef270ab1SKenneth D. Merry 				device_printf(ocs->dev, "%s:"
1802ef270ab1SKenneth D. Merry 						" unknown CAM direction %#x\n",
1803ef270ab1SKenneth D. Merry 						__func__, cam_dir);
1804ef270ab1SKenneth D. Merry 				ocs_set_ccb_status(ccb, CAM_REQ_INVALID);
1805ef270ab1SKenneth D. Merry 				rc = 1;
1806ef270ab1SKenneth D. Merry 			}
1807ef270ab1SKenneth D. Merry 		} else {
1808ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: building SGL failed\n",
1809ef270ab1SKenneth D. Merry 						__func__);
1810ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
1811ef270ab1SKenneth D. Merry 			rc = 1;
1812ef270ab1SKenneth D. Merry 		}
1813ef270ab1SKenneth D. Merry 	} else {
1814ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: Wrong value xfer and sendstatus"
1815ef270ab1SKenneth D. Merry 					" are 0 \n", __func__);
1816ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_INVALID);
1817ef270ab1SKenneth D. Merry 		rc = 1;
1818ef270ab1SKenneth D. Merry 	}
1819ef270ab1SKenneth D. Merry 
1820ef270ab1SKenneth D. Merry 	if (rc) {
1821ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
1822ef270ab1SKenneth D. Merry 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1823ef270ab1SKenneth D. Merry 		io->tgt_io.state = OCS_CAM_IO_DATA_DONE;
1824ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: CTIO state=%d tag=%#x\n",
1825ef270ab1SKenneth D. Merry 				__func__, io->tgt_io.state, io->tag);
1826ef270ab1SKenneth D. Merry 	if ((sendstatus && (xferlen == 0))) {
1827ef270ab1SKenneth D. Merry 			ocs_target_io_free(io);
1828ef270ab1SKenneth D. Merry 		}
1829ef270ab1SKenneth D. Merry 	}
1830ef270ab1SKenneth D. Merry 
1831ef270ab1SKenneth D. Merry 	return rc;
1832ef270ab1SKenneth D. Merry }
1833ef270ab1SKenneth D. Merry 
1834ef270ab1SKenneth D. Merry static int32_t
ocs_target_tmf_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,uint32_t flags,void * arg)1835ef270ab1SKenneth D. Merry ocs_target_tmf_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags,
1836ef270ab1SKenneth D. Merry 		void *arg)
1837ef270ab1SKenneth D. Merry {
1838ef270ab1SKenneth D. Merry 
1839ef270ab1SKenneth D. Merry 	/*device_printf(io->ocs->dev, "%s: tag=%x io=%p s=%#x\n",
1840ef270ab1SKenneth D. Merry 			 __func__, io->tag, io, scsi_status);*/
1841ef270ab1SKenneth D. Merry 	ocs_scsi_io_complete(io);
1842ef270ab1SKenneth D. Merry 
1843ef270ab1SKenneth D. Merry 	return 0;
1844ef270ab1SKenneth D. Merry }
1845ef270ab1SKenneth D. Merry 
1846ef270ab1SKenneth D. Merry /**
1847ef270ab1SKenneth D. Merry  * @ingroup cam_io
1848ef270ab1SKenneth D. Merry  * @brief Send an initiator IO
1849ef270ab1SKenneth D. Merry  *
1850ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
1851ef270ab1SKenneth D. Merry  * @param ccb pointer to the CCB
1852ef270ab1SKenneth D. Merry  *
1853ef270ab1SKenneth D. Merry  * @return 0 on success, non-zero otherwise
1854ef270ab1SKenneth D. Merry  */
1855ef270ab1SKenneth D. Merry static int32_t
ocs_initiator_io(struct ocs_softc * ocs,union ccb * ccb)1856ef270ab1SKenneth D. Merry ocs_initiator_io(struct ocs_softc *ocs, union ccb *ccb)
1857ef270ab1SKenneth D. Merry {
1858ef270ab1SKenneth D. Merry 	int32_t rc;
1859ef270ab1SKenneth D. Merry 	struct ccb_scsiio *csio = &ccb->csio;
1860ef270ab1SKenneth D. Merry 	struct ccb_hdr *ccb_h = &csio->ccb_h;
1861ef270ab1SKenneth D. Merry 	ocs_node_t *node = NULL;
1862ef270ab1SKenneth D. Merry 	ocs_io_t *io = NULL;
1863322dbb8cSRam Kishore Vegesna 	ocs_scsi_sgl_t *sgl;
186488364968SAlexander Motin 	int32_t flags, sgl_count;
18654915e5c7SRam Kishore Vegesna 	ocs_fcport	*fcp;
1866ef270ab1SKenneth D. Merry 
18676affb8ebSRam Kishore Vegesna 	fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path)));
18686affb8ebSRam Kishore Vegesna 
18696affb8ebSRam Kishore Vegesna 	if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_LOST) {
18706affb8ebSRam Kishore Vegesna 		device_printf(ocs->dev, "%s: device LOST %d\n", __func__,
18716affb8ebSRam Kishore Vegesna 							ccb_h->target_id);
18726affb8ebSRam Kishore Vegesna 		return CAM_REQUEUE_REQ;
18736affb8ebSRam Kishore Vegesna 	}
18746affb8ebSRam Kishore Vegesna 
18756affb8ebSRam Kishore Vegesna 	if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_NONE) {
18766affb8ebSRam Kishore Vegesna 		device_printf(ocs->dev, "%s: device not ready %d\n", __func__,
18776affb8ebSRam Kishore Vegesna 							ccb_h->target_id);
18786affb8ebSRam Kishore Vegesna 		return CAM_SEL_TIMEOUT;
18796affb8ebSRam Kishore Vegesna 	}
18806affb8ebSRam Kishore Vegesna 
18816affb8ebSRam Kishore Vegesna 	node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id);
1882ef270ab1SKenneth D. Merry 	if (node == NULL) {
1883ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: no device %d\n", __func__,
1884ef270ab1SKenneth D. Merry 							ccb_h->target_id);
18856affb8ebSRam Kishore Vegesna 		return CAM_SEL_TIMEOUT;
1886ef270ab1SKenneth D. Merry 	}
1887ef270ab1SKenneth D. Merry 
1888ef270ab1SKenneth D. Merry 	if (!node->targ) {
1889ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: not target device %d\n", __func__,
1890ef270ab1SKenneth D. Merry 							ccb_h->target_id);
18916affb8ebSRam Kishore Vegesna 		return CAM_SEL_TIMEOUT;
1892ef270ab1SKenneth D. Merry 	}
1893ef270ab1SKenneth D. Merry 
1894ef270ab1SKenneth D. Merry 	io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR);
1895ef270ab1SKenneth D. Merry 	if (io == NULL) {
1896ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: unable to alloc IO\n", __func__);
1897ef270ab1SKenneth D. Merry 		return -1;
1898ef270ab1SKenneth D. Merry 	}
1899ef270ab1SKenneth D. Merry 
1900ef270ab1SKenneth D. Merry 	/* eventhough this is INI, use target structure as ocs_build_scsi_sgl
1901ef270ab1SKenneth D. Merry 	 * only references the tgt_io part of an ocs_io_t */
1902ef270ab1SKenneth D. Merry 	io->tgt_io.app = ccb;
1903ef270ab1SKenneth D. Merry 
1904ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_ocs_ptr = ocs;
1905ef270ab1SKenneth D. Merry 	csio->ccb_h.ccb_io_ptr  = io;
1906322dbb8cSRam Kishore Vegesna 	sgl = io->sgl;
1907ef270ab1SKenneth D. Merry 
1908322dbb8cSRam Kishore Vegesna 	sgl_count = ocs_build_scsi_sgl(ocs, ccb, io, sgl, io->sgl_allocated);
1909ef270ab1SKenneth D. Merry 	if (sgl_count < 0) {
1910ef270ab1SKenneth D. Merry 		ocs_scsi_io_free(io);
1911ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: building SGL failed\n", __func__);
1912ef270ab1SKenneth D. Merry 		return -1;
1913ef270ab1SKenneth D. Merry 	}
1914ef270ab1SKenneth D. Merry 
1915ef270ab1SKenneth D. Merry 	if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) {
1916ef270ab1SKenneth D. Merry 		io->timeout = 0;
1917ef270ab1SKenneth D. Merry 	} else if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) {
1918ef270ab1SKenneth D. Merry 		io->timeout = OCS_CAM_IO_TIMEOUT;
1919ef270ab1SKenneth D. Merry 	} else {
192070547544SRam Kishore Vegesna 		if (ccb->ccb_h.timeout < 1000)
192170547544SRam Kishore Vegesna 			io->timeout = 1;
192270547544SRam Kishore Vegesna 		else {
192370547544SRam Kishore Vegesna 			io->timeout = ccb->ccb_h.timeout / 1000;
192470547544SRam Kishore Vegesna 		}
1925ef270ab1SKenneth D. Merry 	}
1926ef270ab1SKenneth D. Merry 
192788364968SAlexander Motin 	switch (csio->tag_action) {
192888364968SAlexander Motin 	case MSG_HEAD_OF_Q_TAG:
192988364968SAlexander Motin 		flags = OCS_SCSI_CMD_HEAD_OF_QUEUE;
193088364968SAlexander Motin 		break;
193188364968SAlexander Motin 	case MSG_ORDERED_Q_TAG:
193288364968SAlexander Motin 		flags = OCS_SCSI_CMD_ORDERED;
193388364968SAlexander Motin 		break;
193488364968SAlexander Motin 	case MSG_ACA_TASK:
193588364968SAlexander Motin 		flags = OCS_SCSI_CMD_ACA;
193688364968SAlexander Motin 		break;
193788364968SAlexander Motin 	case CAM_TAG_ACTION_NONE:
193888364968SAlexander Motin 	case MSG_SIMPLE_Q_TAG:
193988364968SAlexander Motin 	default:
194088364968SAlexander Motin 		flags = OCS_SCSI_CMD_SIMPLE;
194188364968SAlexander Motin 		break;
194288364968SAlexander Motin 	}
194388364968SAlexander Motin 	flags |= (csio->priority << OCS_SCSI_PRIORITY_SHIFT) &
194488364968SAlexander Motin 	    OCS_SCSI_PRIORITY_MASK;
194588364968SAlexander Motin 
1946ef270ab1SKenneth D. Merry 	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
1947ef270ab1SKenneth D. Merry 	case CAM_DIR_NONE:
1948ef270ab1SKenneth D. Merry 		rc = ocs_scsi_send_nodata_io(node, io, ccb_h->target_lun,
1949ef270ab1SKenneth D. Merry 				ccb->ccb_h.flags & CAM_CDB_POINTER ?
1950ef270ab1SKenneth D. Merry 				csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes,
1951ef270ab1SKenneth D. Merry 				csio->cdb_len,
195288364968SAlexander Motin 				ocs_scsi_initiator_io_cb, ccb, flags);
1953ef270ab1SKenneth D. Merry 		break;
1954ef270ab1SKenneth D. Merry 	case CAM_DIR_IN:
1955ef270ab1SKenneth D. Merry 		rc = ocs_scsi_send_rd_io(node, io, ccb_h->target_lun,
1956ef270ab1SKenneth D. Merry 				ccb->ccb_h.flags & CAM_CDB_POINTER ?
1957ef270ab1SKenneth D. Merry 				csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes,
1958ef270ab1SKenneth D. Merry 				csio->cdb_len,
1959ef270ab1SKenneth D. Merry 				NULL,
1960ef270ab1SKenneth D. Merry 				sgl, sgl_count, csio->dxfer_len,
196188364968SAlexander Motin 				ocs_scsi_initiator_io_cb, ccb, flags);
1962ef270ab1SKenneth D. Merry 		break;
1963ef270ab1SKenneth D. Merry 	case CAM_DIR_OUT:
1964ef270ab1SKenneth D. Merry 		rc = ocs_scsi_send_wr_io(node, io, ccb_h->target_lun,
1965ef270ab1SKenneth D. Merry 				ccb->ccb_h.flags & CAM_CDB_POINTER ?
1966ef270ab1SKenneth D. Merry 				csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes,
1967ef270ab1SKenneth D. Merry 				csio->cdb_len,
1968ef270ab1SKenneth D. Merry 				NULL,
1969ef270ab1SKenneth D. Merry 				sgl, sgl_count, csio->dxfer_len,
197088364968SAlexander Motin 				ocs_scsi_initiator_io_cb, ccb, flags);
1971ef270ab1SKenneth D. Merry 		break;
1972ef270ab1SKenneth D. Merry 	default:
1973ef270ab1SKenneth D. Merry 		panic("%s invalid data direction %08x\n", __func__,
1974ef270ab1SKenneth D. Merry 							ccb->ccb_h.flags);
1975ef270ab1SKenneth D. Merry 		break;
1976ef270ab1SKenneth D. Merry 	}
1977ef270ab1SKenneth D. Merry 
1978ef270ab1SKenneth D. Merry 	return rc;
1979ef270ab1SKenneth D. Merry }
1980ef270ab1SKenneth D. Merry 
1981ef270ab1SKenneth D. Merry static uint32_t
ocs_fcp_change_role(struct ocs_softc * ocs,ocs_fcport * fcp,uint32_t new_role)1982ef270ab1SKenneth D. Merry ocs_fcp_change_role(struct ocs_softc *ocs, ocs_fcport *fcp, uint32_t new_role)
1983ef270ab1SKenneth D. Merry {
1984ef270ab1SKenneth D. Merry 
1985ef270ab1SKenneth D. Merry 	uint32_t rc = 0, was = 0, i = 0;
1986ef270ab1SKenneth D. Merry 	ocs_vport_spec_t *vport = fcp->vport;
1987ef270ab1SKenneth D. Merry 
1988ef270ab1SKenneth D. Merry 	for (was = 0, i = 0; i < (ocs->num_vports + 1); i++) {
1989ef270ab1SKenneth D. Merry 		if (FCPORT(ocs, i)->role != KNOB_ROLE_NONE)
1990ef270ab1SKenneth D. Merry 		was++;
1991ef270ab1SKenneth D. Merry 	}
1992ef270ab1SKenneth D. Merry 
1993ef270ab1SKenneth D. Merry 	// Physical port
1994ef270ab1SKenneth D. Merry 	if ((was == 0) || (vport == NULL)) {
1995ef270ab1SKenneth D. Merry 		fcp->role = new_role;
1996ef270ab1SKenneth D. Merry 		if (vport == NULL) {
1997ef270ab1SKenneth D. Merry 			ocs->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0;
1998ef270ab1SKenneth D. Merry 			ocs->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0;
1999ef270ab1SKenneth D. Merry 		} else {
2000ef270ab1SKenneth D. Merry 			vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0;
2001ef270ab1SKenneth D. Merry 			vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0;
2002ef270ab1SKenneth D. Merry 		}
2003ef270ab1SKenneth D. Merry 
2004ef270ab1SKenneth D. Merry 		rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
2005ef270ab1SKenneth D. Merry 		if (rc) {
2006ef270ab1SKenneth D. Merry 			ocs_log_debug(ocs, "port offline failed : %d\n", rc);
2007ef270ab1SKenneth D. Merry 		}
2008ef270ab1SKenneth D. Merry 
2009ef270ab1SKenneth D. Merry 		rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
2010ef270ab1SKenneth D. Merry 		if (rc) {
2011ef270ab1SKenneth D. Merry 			ocs_log_debug(ocs, "port online failed : %d\n", rc);
2012ef270ab1SKenneth D. Merry 		}
2013ef270ab1SKenneth D. Merry 
2014ef270ab1SKenneth D. Merry 		return 0;
2015ef270ab1SKenneth D. Merry 	}
2016ef270ab1SKenneth D. Merry 
2017ef270ab1SKenneth D. Merry 	if ((fcp->role != KNOB_ROLE_NONE)){
2018ef270ab1SKenneth D. Merry 		fcp->role = new_role;
2019ef270ab1SKenneth D. Merry 		vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0;
2020ef270ab1SKenneth D. Merry 		vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0;
2021ef270ab1SKenneth D. Merry 		/* New Sport will be created in sport deleted cb */
2022ef270ab1SKenneth D. Merry 		return ocs_sport_vport_del(ocs, ocs->domain, vport->wwpn, vport->wwnn);
2023ef270ab1SKenneth D. Merry 	}
2024ef270ab1SKenneth D. Merry 
2025ef270ab1SKenneth D. Merry 	fcp->role = new_role;
2026ef270ab1SKenneth D. Merry 
2027ef270ab1SKenneth D. Merry 	vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0;
2028ef270ab1SKenneth D. Merry 	vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0;
2029ef270ab1SKenneth D. Merry 
2030ef270ab1SKenneth D. Merry 	if (fcp->role != KNOB_ROLE_NONE) {
2031ef270ab1SKenneth D. Merry 		return ocs_sport_vport_alloc(ocs->domain, vport);
2032ef270ab1SKenneth D. Merry 	}
2033ef270ab1SKenneth D. Merry 
2034ef270ab1SKenneth D. Merry 	return (0);
2035ef270ab1SKenneth D. Merry }
2036ef270ab1SKenneth D. Merry 
2037ef270ab1SKenneth D. Merry /**
2038ef270ab1SKenneth D. Merry  * @ingroup cam_api
2039ef270ab1SKenneth D. Merry  * @brief Process CAM actions
2040ef270ab1SKenneth D. Merry  *
2041ef270ab1SKenneth D. Merry  * The driver supplies this routine to the CAM during intialization and
2042ef270ab1SKenneth D. Merry  * is the main entry point for processing CAM Control Blocks (CCB)
2043ef270ab1SKenneth D. Merry  *
2044ef270ab1SKenneth D. Merry  * @param sim pointer to the SCSI Interface Module
2045ef270ab1SKenneth D. Merry  * @param ccb CAM control block
2046ef270ab1SKenneth D. Merry  *
2047ef270ab1SKenneth D. Merry  * @todo
2048ef270ab1SKenneth D. Merry  *  - populate path inquiry data via info retrieved from SLI port
2049ef270ab1SKenneth D. Merry  */
2050ef270ab1SKenneth D. Merry static void
ocs_action(struct cam_sim * sim,union ccb * ccb)2051ef270ab1SKenneth D. Merry ocs_action(struct cam_sim *sim, union ccb *ccb)
2052ef270ab1SKenneth D. Merry {
2053ef270ab1SKenneth D. Merry 	struct ocs_softc *ocs = (struct ocs_softc *)cam_sim_softc(sim);
2054ef270ab1SKenneth D. Merry 	struct ccb_hdr	*ccb_h = &ccb->ccb_h;
2055ef270ab1SKenneth D. Merry 
2056ef270ab1SKenneth D. Merry 	int32_t	rc, bus;
2057ef270ab1SKenneth D. Merry 	bus = cam_sim_bus(sim);
2058ef270ab1SKenneth D. Merry 
2059ef270ab1SKenneth D. Merry 	switch (ccb_h->func_code) {
2060ef270ab1SKenneth D. Merry 	case XPT_SCSI_IO:
2061ef270ab1SKenneth D. Merry 
2062ef270ab1SKenneth D. Merry 		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
2063ef270ab1SKenneth D. Merry 			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
2064ef270ab1SKenneth D. Merry 				ccb->ccb_h.status = CAM_REQ_INVALID;
2065ef270ab1SKenneth D. Merry 				xpt_done(ccb);
2066ef270ab1SKenneth D. Merry 				break;
2067ef270ab1SKenneth D. Merry 			}
2068ef270ab1SKenneth D. Merry 		}
2069ef270ab1SKenneth D. Merry 
2070ef270ab1SKenneth D. Merry 		rc = ocs_initiator_io(ocs, ccb);
2071ef270ab1SKenneth D. Merry 		if (0 == rc) {
2072ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_INPROG | CAM_SIM_QUEUED);
2073ef270ab1SKenneth D. Merry 			break;
2074ef270ab1SKenneth D. Merry 		} else {
20756affb8ebSRam Kishore Vegesna 		  	if (rc == CAM_REQUEUE_REQ) {
20766affb8ebSRam Kishore Vegesna 				cam_freeze_devq(ccb->ccb_h.path);
20776affb8ebSRam Kishore Vegesna 				cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0);
20786affb8ebSRam Kishore Vegesna 				ccb->ccb_h.status = CAM_REQUEUE_REQ;
20796affb8ebSRam Kishore Vegesna 				xpt_done(ccb);
20806affb8ebSRam Kishore Vegesna 				break;
20816affb8ebSRam Kishore Vegesna 			}
20826affb8ebSRam Kishore Vegesna 
2083ef270ab1SKenneth D. Merry 			ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
2084ef270ab1SKenneth D. Merry 			if (rc > 0) {
2085ef270ab1SKenneth D. Merry 				ocs_set_ccb_status(ccb, rc);
2086ef270ab1SKenneth D. Merry 			} else {
2087ef270ab1SKenneth D. Merry 				ocs_set_ccb_status(ccb, CAM_SEL_TIMEOUT);
2088ef270ab1SKenneth D. Merry 			}
2089ef270ab1SKenneth D. Merry 		}
2090ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2091ef270ab1SKenneth D. Merry 		break;
2092ef270ab1SKenneth D. Merry 	case XPT_PATH_INQ:
2093ef270ab1SKenneth D. Merry 	{
2094ef270ab1SKenneth D. Merry 		struct ccb_pathinq *cpi = &ccb->cpi;
2095ef270ab1SKenneth D. Merry 		struct ccb_pathinq_settings_fc *fc = &cpi->xport_specific.fc;
2096b9732f78SRam Kishore Vegesna 		ocs_fcport *fcp = FCPORT(ocs, bus);
2097ef270ab1SKenneth D. Merry 
2098ef270ab1SKenneth D. Merry 		uint64_t wwn = 0;
2099ef270ab1SKenneth D. Merry 		ocs_xport_stats_t value;
2100ef270ab1SKenneth D. Merry 
2101ef270ab1SKenneth D. Merry 		cpi->version_num = 1;
2102ef270ab1SKenneth D. Merry 
2103ef270ab1SKenneth D. Merry 		cpi->protocol = PROTO_SCSI;
2104ef270ab1SKenneth D. Merry 		cpi->protocol_version = SCSI_REV_SPC;
2105ef270ab1SKenneth D. Merry 
2106ef270ab1SKenneth D. Merry 		if (ocs->ocs_xport == OCS_XPORT_FC) {
2107ef270ab1SKenneth D. Merry 			cpi->transport = XPORT_FC;
2108ef270ab1SKenneth D. Merry 		} else {
2109ef270ab1SKenneth D. Merry 			cpi->transport = XPORT_UNKNOWN;
2110ef270ab1SKenneth D. Merry 		}
2111ef270ab1SKenneth D. Merry 
2112ef270ab1SKenneth D. Merry 		cpi->transport_version = 0;
2113ef270ab1SKenneth D. Merry 
2114ef270ab1SKenneth D. Merry 		/* Set the transport parameters of the SIM */
2115ef270ab1SKenneth D. Merry 		ocs_xport_status(ocs->xport, OCS_XPORT_LINK_SPEED, &value);
2116ef270ab1SKenneth D. Merry 		fc->bitrate = value.value * 1000;	/* speed in Mbps */
2117ef270ab1SKenneth D. Merry 
2118ef270ab1SKenneth D. Merry 		wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, OCS_SCSI_WWPN));
2119ef270ab1SKenneth D. Merry 		fc->wwpn = be64toh(wwn);
2120ef270ab1SKenneth D. Merry 
2121ef270ab1SKenneth D. Merry 		wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, OCS_SCSI_WWNN));
2122ef270ab1SKenneth D. Merry 		fc->wwnn = be64toh(wwn);
2123ef270ab1SKenneth D. Merry 
2124b9732f78SRam Kishore Vegesna 		fc->port = fcp->fc_id;
2125ef270ab1SKenneth D. Merry 
2126ef270ab1SKenneth D. Merry 		if (ocs->config_tgt) {
2127ef270ab1SKenneth D. Merry 			cpi->target_sprt =
2128ef270ab1SKenneth D. Merry 				PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
2129ef270ab1SKenneth D. Merry 		}
2130ef270ab1SKenneth D. Merry 
2131ef270ab1SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
2132ef270ab1SKenneth D. Merry 		cpi->hba_misc |= PIM_EXTLUNS | PIM_NOSCAN;
2133ef270ab1SKenneth D. Merry 
2134ef270ab1SKenneth D. Merry 		cpi->hba_inquiry = PI_TAG_ABLE;
2135ef270ab1SKenneth D. Merry 		cpi->max_target = OCS_MAX_TARGETS;
2136ef270ab1SKenneth D. Merry 		cpi->initiator_id = ocs->max_remote_nodes + 1;
2137ef270ab1SKenneth D. Merry 
2138ef270ab1SKenneth D. Merry 		if (!ocs->enable_ini) {
2139ef270ab1SKenneth D. Merry 			cpi->hba_misc |= PIM_NOINITIATOR;
2140ef270ab1SKenneth D. Merry 		}
2141ef270ab1SKenneth D. Merry 
2142ef270ab1SKenneth D. Merry 		cpi->max_lun = OCS_MAX_LUN;
2143ef270ab1SKenneth D. Merry 		cpi->bus_id = cam_sim_bus(sim);
2144ef270ab1SKenneth D. Merry 
2145ef270ab1SKenneth D. Merry 		/* Need to supply a base transfer speed prior to linking up
2146ef270ab1SKenneth D. Merry 		 * Worst case, this would be FC 1Gbps */
2147ef270ab1SKenneth D. Merry 		cpi->base_transfer_speed = 1 * 1000 * 1000;
2148ef270ab1SKenneth D. Merry 
2149ef270ab1SKenneth D. Merry 		/* Calculate the max IO supported
2150ef270ab1SKenneth D. Merry 		 * Worst case would be an OS page per SGL entry */
2151322dbb8cSRam Kishore Vegesna 
2152ef270ab1SKenneth D. Merry 		cpi->maxio = PAGE_SIZE *
2153ef270ab1SKenneth D. Merry 			(ocs_scsi_get_property(ocs, OCS_SCSI_MAX_SGL) - 1);
2154ef270ab1SKenneth D. Merry 
2155ef270ab1SKenneth D. Merry 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2156ef270ab1SKenneth D. Merry 		strncpy(cpi->hba_vid, "Emulex", HBA_IDLEN);
2157ef270ab1SKenneth D. Merry 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2158ef270ab1SKenneth D. Merry 		cpi->unit_number = cam_sim_unit(sim);
2159ef270ab1SKenneth D. Merry 
2160ef270ab1SKenneth D. Merry 		cpi->ccb_h.status = CAM_REQ_CMP;
2161ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2162ef270ab1SKenneth D. Merry 		break;
2163ef270ab1SKenneth D. Merry 	}
2164ef270ab1SKenneth D. Merry 	case XPT_GET_TRAN_SETTINGS:
2165ef270ab1SKenneth D. Merry 	{
2166ef270ab1SKenneth D. Merry 		struct ccb_trans_settings *cts = &ccb->cts;
2167ef270ab1SKenneth D. Merry 		struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
2168ef270ab1SKenneth D. Merry 		struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc;
2169ef270ab1SKenneth D. Merry 		ocs_xport_stats_t value;
21706affb8ebSRam Kishore Vegesna 		ocs_fcport *fcp = FCPORT(ocs, bus);
2171b9732f78SRam Kishore Vegesna 		ocs_fc_target_t *tgt = NULL;
2172ef270ab1SKenneth D. Merry 
2173ef270ab1SKenneth D. Merry 		if (ocs->ocs_xport != OCS_XPORT_FC) {
2174ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_INVALID);
2175ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2176ef270ab1SKenneth D. Merry 			break;
2177ef270ab1SKenneth D. Merry 		}
2178ef270ab1SKenneth D. Merry 
2179b9732f78SRam Kishore Vegesna 		if (cts->ccb_h.target_id > OCS_MAX_TARGETS) {
2180b9732f78SRam Kishore Vegesna 			ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE);
2181b9732f78SRam Kishore Vegesna 			xpt_done(ccb);
2182b9732f78SRam Kishore Vegesna 			break;
2183b9732f78SRam Kishore Vegesna 		}
2184b9732f78SRam Kishore Vegesna 
2185b9732f78SRam Kishore Vegesna 		tgt = &fcp->tgt[cts->ccb_h.target_id];
2186b9732f78SRam Kishore Vegesna 		if (tgt->state == OCS_TGT_STATE_NONE) {
2187ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE);
2188ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2189ef270ab1SKenneth D. Merry 			break;
2190ef270ab1SKenneth D. Merry 		}
2191ef270ab1SKenneth D. Merry 
2192ef270ab1SKenneth D. Merry 		cts->protocol = PROTO_SCSI;
2193ef270ab1SKenneth D. Merry 		cts->protocol_version = SCSI_REV_SPC2;
2194ef270ab1SKenneth D. Merry 		cts->transport = XPORT_FC;
2195ef270ab1SKenneth D. Merry 		cts->transport_version = 2;
2196ef270ab1SKenneth D. Merry 
2197ef270ab1SKenneth D. Merry 		scsi->valid = CTS_SCSI_VALID_TQ;
2198ef270ab1SKenneth D. Merry 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
2199ef270ab1SKenneth D. Merry 
2200ef270ab1SKenneth D. Merry 		/* speed in Mbps */
2201ef270ab1SKenneth D. Merry 		ocs_xport_status(ocs->xport, OCS_XPORT_LINK_SPEED, &value);
2202ef270ab1SKenneth D. Merry 		fc->bitrate = value.value * 100;
2203ef270ab1SKenneth D. Merry 
2204b9732f78SRam Kishore Vegesna 		fc->wwpn = tgt->wwpn;
2205ef270ab1SKenneth D. Merry 
2206b9732f78SRam Kishore Vegesna 		fc->wwnn = tgt->wwnn;
2207ef270ab1SKenneth D. Merry 
2208b9732f78SRam Kishore Vegesna 		fc->port = tgt->port_id;
2209ef270ab1SKenneth D. Merry 
2210ef270ab1SKenneth D. Merry 		fc->valid = CTS_FC_VALID_SPEED |
2211ef270ab1SKenneth D. Merry 			CTS_FC_VALID_WWPN |
2212ef270ab1SKenneth D. Merry 			CTS_FC_VALID_WWNN |
2213ef270ab1SKenneth D. Merry 			CTS_FC_VALID_PORT;
2214ef270ab1SKenneth D. Merry 
2215ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2216ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2217ef270ab1SKenneth D. Merry 		break;
2218ef270ab1SKenneth D. Merry 	}
2219ef270ab1SKenneth D. Merry 	case XPT_SET_TRAN_SETTINGS:
2220ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2221ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2222ef270ab1SKenneth D. Merry 		break;
2223ef270ab1SKenneth D. Merry 
2224ef270ab1SKenneth D. Merry 	case XPT_CALC_GEOMETRY:
2225ef270ab1SKenneth D. Merry 		cam_calc_geometry(&ccb->ccg, TRUE);
2226ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2227ef270ab1SKenneth D. Merry 		break;
2228ef270ab1SKenneth D. Merry 
2229ef270ab1SKenneth D. Merry 	case XPT_GET_SIM_KNOB:
2230ef270ab1SKenneth D. Merry 	{
2231ef270ab1SKenneth D. Merry 		struct ccb_sim_knob *knob = &ccb->knob;
2232ef270ab1SKenneth D. Merry 		uint64_t wwn = 0;
2233ef270ab1SKenneth D. Merry 		ocs_fcport *fcp = FCPORT(ocs, bus);
2234ef270ab1SKenneth D. Merry 
2235ef270ab1SKenneth D. Merry 		if (ocs->ocs_xport != OCS_XPORT_FC) {
2236ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_INVALID);
2237ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2238ef270ab1SKenneth D. Merry 			break;
2239ef270ab1SKenneth D. Merry 		}
2240ef270ab1SKenneth D. Merry 
2241ef270ab1SKenneth D. Merry 		if (bus == 0) {
2242ef270ab1SKenneth D. Merry 			wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs,
2243ef270ab1SKenneth D. Merry 						OCS_SCSI_WWNN));
2244ef270ab1SKenneth D. Merry 			knob->xport_specific.fc.wwnn = be64toh(wwn);
2245ef270ab1SKenneth D. Merry 
2246ef270ab1SKenneth D. Merry 			wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs,
2247ef270ab1SKenneth D. Merry 						OCS_SCSI_WWPN));
2248ef270ab1SKenneth D. Merry 			knob->xport_specific.fc.wwpn = be64toh(wwn);
2249ef270ab1SKenneth D. Merry 		} else {
2250ef270ab1SKenneth D. Merry 			knob->xport_specific.fc.wwnn = fcp->vport->wwnn;
2251ef270ab1SKenneth D. Merry 			knob->xport_specific.fc.wwpn = fcp->vport->wwpn;
2252ef270ab1SKenneth D. Merry 		}
2253ef270ab1SKenneth D. Merry 
2254ef270ab1SKenneth D. Merry 		knob->xport_specific.fc.role = fcp->role;
2255ef270ab1SKenneth D. Merry 		knob->xport_specific.fc.valid = KNOB_VALID_ADDRESS |
2256ef270ab1SKenneth D. Merry 						KNOB_VALID_ROLE;
2257ef270ab1SKenneth D. Merry 
2258ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2259ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2260ef270ab1SKenneth D. Merry 		break;
2261ef270ab1SKenneth D. Merry 	}
2262ef270ab1SKenneth D. Merry 	case XPT_SET_SIM_KNOB:
2263ef270ab1SKenneth D. Merry 	{
2264ef270ab1SKenneth D. Merry 		struct ccb_sim_knob *knob = &ccb->knob;
2265ef270ab1SKenneth D. Merry 		bool role_changed = FALSE;
2266ef270ab1SKenneth D. Merry 		ocs_fcport *fcp = FCPORT(ocs, bus);
2267ef270ab1SKenneth D. Merry 
2268ef270ab1SKenneth D. Merry 		if (ocs->ocs_xport != OCS_XPORT_FC) {
2269ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_INVALID);
2270ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2271ef270ab1SKenneth D. Merry 			break;
2272ef270ab1SKenneth D. Merry 		}
2273ef270ab1SKenneth D. Merry 
2274ef270ab1SKenneth D. Merry 		if (knob->xport_specific.fc.valid & KNOB_VALID_ADDRESS) {
2275ef270ab1SKenneth D. Merry 			device_printf(ocs->dev,
2276ef270ab1SKenneth D. Merry 				"%s: XPT_SET_SIM_KNOB wwnn=%llx wwpn=%llx\n",
2277ef270ab1SKenneth D. Merry 					__func__,
2278ef270ab1SKenneth D. Merry 					(unsigned long long)knob->xport_specific.fc.wwnn,
2279ef270ab1SKenneth D. Merry 					(unsigned long long)knob->xport_specific.fc.wwpn);
2280ef270ab1SKenneth D. Merry 		}
2281ef270ab1SKenneth D. Merry 
2282ef270ab1SKenneth D. Merry 		if (knob->xport_specific.fc.valid & KNOB_VALID_ROLE) {
2283ef270ab1SKenneth D. Merry 			switch (knob->xport_specific.fc.role) {
2284ef270ab1SKenneth D. Merry 			case KNOB_ROLE_NONE:
2285ef270ab1SKenneth D. Merry 				if (fcp->role != KNOB_ROLE_NONE) {
2286ef270ab1SKenneth D. Merry 					role_changed = TRUE;
2287ef270ab1SKenneth D. Merry 				}
2288ef270ab1SKenneth D. Merry 				break;
2289ef270ab1SKenneth D. Merry 			case KNOB_ROLE_TARGET:
2290ef270ab1SKenneth D. Merry 				if (fcp->role != KNOB_ROLE_TARGET) {
2291ef270ab1SKenneth D. Merry 					role_changed = TRUE;
2292ef270ab1SKenneth D. Merry 				}
2293ef270ab1SKenneth D. Merry 				break;
2294ef270ab1SKenneth D. Merry 			case KNOB_ROLE_INITIATOR:
2295ef270ab1SKenneth D. Merry 				if (fcp->role != KNOB_ROLE_INITIATOR) {
2296ef270ab1SKenneth D. Merry 					role_changed = TRUE;
2297ef270ab1SKenneth D. Merry 				}
2298ef270ab1SKenneth D. Merry 				break;
2299ef270ab1SKenneth D. Merry 			case KNOB_ROLE_BOTH:
2300ef270ab1SKenneth D. Merry 				if (fcp->role != KNOB_ROLE_BOTH) {
2301ef270ab1SKenneth D. Merry 					role_changed = TRUE;
2302ef270ab1SKenneth D. Merry 				}
2303ef270ab1SKenneth D. Merry 				break;
2304ef270ab1SKenneth D. Merry 			default:
2305ef270ab1SKenneth D. Merry 				device_printf(ocs->dev,
2306ef270ab1SKenneth D. Merry 					"%s: XPT_SET_SIM_KNOB unsupported role: %d\n",
2307ef270ab1SKenneth D. Merry 					__func__, knob->xport_specific.fc.role);
2308ef270ab1SKenneth D. Merry 			}
2309ef270ab1SKenneth D. Merry 
2310ef270ab1SKenneth D. Merry 			if (role_changed) {
2311ef270ab1SKenneth D. Merry 				device_printf(ocs->dev,
2312ef270ab1SKenneth D. Merry 						"BUS:%d XPT_SET_SIM_KNOB old_role: %d new_role: %d\n",
2313ef270ab1SKenneth D. Merry 						bus, fcp->role, knob->xport_specific.fc.role);
2314ef270ab1SKenneth D. Merry 
2315ef270ab1SKenneth D. Merry 				ocs_fcp_change_role(ocs, fcp, knob->xport_specific.fc.role);
2316ef270ab1SKenneth D. Merry 			}
2317ef270ab1SKenneth D. Merry 		}
2318ef270ab1SKenneth D. Merry 
2319ef270ab1SKenneth D. Merry 
2320ef270ab1SKenneth D. Merry 
2321ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2322ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2323ef270ab1SKenneth D. Merry 		break;
2324ef270ab1SKenneth D. Merry 	}
2325ef270ab1SKenneth D. Merry 	case XPT_ABORT:
2326ef270ab1SKenneth D. Merry 	{
2327ef270ab1SKenneth D. Merry 		union ccb *accb = ccb->cab.abort_ccb;
2328ef270ab1SKenneth D. Merry 
2329ef270ab1SKenneth D. Merry 		switch (accb->ccb_h.func_code) {
2330ef270ab1SKenneth D. Merry 		case XPT_ACCEPT_TARGET_IO:
2331ef270ab1SKenneth D. Merry 			ocs_abort_atio(ocs, ccb);
2332ef270ab1SKenneth D. Merry 			break;
2333ef270ab1SKenneth D. Merry 		case XPT_IMMEDIATE_NOTIFY:
2334ef270ab1SKenneth D. Merry 			ocs_abort_inot(ocs, ccb);
2335ef270ab1SKenneth D. Merry 			break;
2336ef270ab1SKenneth D. Merry 		case XPT_SCSI_IO:
2337ef270ab1SKenneth D. Merry 			rc = ocs_abort_initiator_io(ocs, accb);
2338ef270ab1SKenneth D. Merry 			if (rc) {
2339ef270ab1SKenneth D. Merry 				ccb->ccb_h.status = CAM_UA_ABORT;
2340ef270ab1SKenneth D. Merry 			} else {
2341ef270ab1SKenneth D. Merry 				ccb->ccb_h.status = CAM_REQ_CMP;
2342ef270ab1SKenneth D. Merry 			}
2343ef270ab1SKenneth D. Merry 
2344ef270ab1SKenneth D. Merry 			break;
2345ef270ab1SKenneth D. Merry 		default:
2346ef270ab1SKenneth D. Merry 			printf("abort of unknown func %#x\n",
2347ef270ab1SKenneth D. Merry 					accb->ccb_h.func_code);
2348ef270ab1SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_INVALID;
2349ef270ab1SKenneth D. Merry 			break;
2350ef270ab1SKenneth D. Merry 		}
2351ef270ab1SKenneth D. Merry 		break;
2352ef270ab1SKenneth D. Merry 	}
2353ef270ab1SKenneth D. Merry 	case XPT_RESET_BUS:
2354ef270ab1SKenneth D. Merry 		if (ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE) == 0) {
23554915e5c7SRam Kishore Vegesna 			rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
23564915e5c7SRam Kishore Vegesna 			if (rc) {
23574915e5c7SRam Kishore Vegesna 				ocs_log_debug(ocs, "Failed to bring port online"
23584915e5c7SRam Kishore Vegesna 								" : %d\n", rc);
23594915e5c7SRam Kishore Vegesna 			}
2360ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2361ef270ab1SKenneth D. Merry 		} else {
2362ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
2363ef270ab1SKenneth D. Merry 		}
2364ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2365ef270ab1SKenneth D. Merry 		break;
2366ef270ab1SKenneth D. Merry 	case XPT_RESET_DEV:
2367ef270ab1SKenneth D. Merry 	{
2368ef270ab1SKenneth D. Merry 		ocs_node_t	*node = NULL;
2369ef270ab1SKenneth D. Merry 		ocs_io_t	*io = NULL;
2370ef270ab1SKenneth D. Merry 		int32_t		rc = 0;
23716affb8ebSRam Kishore Vegesna 		ocs_fcport *fcp = FCPORT(ocs, bus);
2372ef270ab1SKenneth D. Merry 
23736affb8ebSRam Kishore Vegesna 		node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id);
2374ef270ab1SKenneth D. Merry 		if (node == NULL) {
2375ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: no device %d\n",
2376ef270ab1SKenneth D. Merry 						__func__, ccb_h->target_id);
2377ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE);
2378ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2379ef270ab1SKenneth D. Merry 			break;
2380ef270ab1SKenneth D. Merry 		}
2381ef270ab1SKenneth D. Merry 
2382ef270ab1SKenneth D. Merry 		io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR);
2383ef270ab1SKenneth D. Merry 		if (io == NULL) {
2384ef270ab1SKenneth D. Merry 			device_printf(ocs->dev, "%s: unable to alloc IO\n",
2385ef270ab1SKenneth D. Merry 								 __func__);
2386ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
2387ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2388ef270ab1SKenneth D. Merry 			break;
2389ef270ab1SKenneth D. Merry 		}
2390ef270ab1SKenneth D. Merry 
2391ef270ab1SKenneth D. Merry 		rc = ocs_scsi_send_tmf(node, io, NULL, ccb_h->target_lun,
2392ef270ab1SKenneth D. Merry 				OCS_SCSI_TMF_LOGICAL_UNIT_RESET,
2393ef270ab1SKenneth D. Merry 				NULL, 0, 0,	/* sgl, sgl_count, length */
2394ef270ab1SKenneth D. Merry 				ocs_initiator_tmf_cb, NULL/*arg*/);
2395ef270ab1SKenneth D. Merry 
2396ef270ab1SKenneth D. Merry 		if (rc) {
2397ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
2398ef270ab1SKenneth D. Merry 		} else {
2399ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2400ef270ab1SKenneth D. Merry 		}
2401ef270ab1SKenneth D. Merry 
2402ef270ab1SKenneth D. Merry 		if (node->fcp2device) {
2403ef270ab1SKenneth D. Merry 			ocs_reset_crn(node, ccb_h->target_lun);
2404ef270ab1SKenneth D. Merry 		}
2405ef270ab1SKenneth D. Merry 
2406ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2407ef270ab1SKenneth D. Merry 		break;
2408ef270ab1SKenneth D. Merry 	}
2409ef270ab1SKenneth D. Merry 	case XPT_EN_LUN:	/* target support */
2410ef270ab1SKenneth D. Merry 	{
2411ef270ab1SKenneth D. Merry 		ocs_tgt_resource_t *trsrc = NULL;
2412ef270ab1SKenneth D. Merry 		uint32_t	status = 0;
2413ef270ab1SKenneth D. Merry 		ocs_fcport *fcp = FCPORT(ocs, bus);
2414ef270ab1SKenneth D. Merry 
2415ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "XPT_EN_LUN %sable %d:%d\n",
2416ef270ab1SKenneth D. Merry 				ccb->cel.enable ? "en" : "dis",
2417ef270ab1SKenneth D. Merry 				ccb->ccb_h.target_id,
2418ef270ab1SKenneth D. Merry 				(unsigned int)ccb->ccb_h.target_lun);
2419ef270ab1SKenneth D. Merry 
2420ef270ab1SKenneth D. Merry 		trsrc = ocs_tgt_resource_get(fcp, &ccb->ccb_h, &status);
2421ef270ab1SKenneth D. Merry 		if (trsrc) {
2422ef270ab1SKenneth D. Merry 			trsrc->enabled = ccb->cel.enable;
2423ef270ab1SKenneth D. Merry 
2424ef270ab1SKenneth D. Merry 			/* Abort all ATIO/INOT on LUN disable */
2425ef270ab1SKenneth D. Merry 			if (trsrc->enabled == FALSE) {
2426ef270ab1SKenneth D. Merry 				ocs_tgt_resource_abort(ocs, trsrc);
2427ef270ab1SKenneth D. Merry 			} else {
2428ef270ab1SKenneth D. Merry 				STAILQ_INIT(&trsrc->atio);
2429ef270ab1SKenneth D. Merry 				STAILQ_INIT(&trsrc->inot);
2430ef270ab1SKenneth D. Merry 			}
2431ef270ab1SKenneth D. Merry 			status = CAM_REQ_CMP;
2432ef270ab1SKenneth D. Merry 		}
2433ef270ab1SKenneth D. Merry 
2434ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, status);
2435ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2436ef270ab1SKenneth D. Merry 		break;
2437ef270ab1SKenneth D. Merry 	}
2438ef270ab1SKenneth D. Merry 	/*
2439ef270ab1SKenneth D. Merry 	 * The flow of target IOs in CAM is:
2440ef270ab1SKenneth D. Merry 	 *  - CAM supplies a number of CCBs to the driver used for received
2441ef270ab1SKenneth D. Merry 	 *    commands.
2442ef270ab1SKenneth D. Merry 	 *  - when the driver receives a command, it copies the relevant
2443ef270ab1SKenneth D. Merry 	 *    information to the CCB and returns it to the CAM using xpt_done()
2444ef270ab1SKenneth D. Merry 	 *  - after the target server processes the request, it creates
2445ef270ab1SKenneth D. Merry 	 *    a new CCB containing information on how to continue the IO and
2446ef270ab1SKenneth D. Merry 	 *    passes that to the driver
2447ef270ab1SKenneth D. Merry 	 *  - the driver processes the "continue IO" (a.k.a CTIO) CCB
2448ef270ab1SKenneth D. Merry 	 *  - once the IO completes, the driver returns the CTIO to the CAM
2449ef270ab1SKenneth D. Merry 	 *    using xpt_done()
2450ef270ab1SKenneth D. Merry 	 */
2451ef270ab1SKenneth D. Merry 	case XPT_ACCEPT_TARGET_IO:	/* used to inform upper layer of
2452ef270ab1SKenneth D. Merry 						received CDB (a.k.a. ATIO) */
2453ef270ab1SKenneth D. Merry 	case XPT_IMMEDIATE_NOTIFY:	/* used to inform upper layer of other
2454ef270ab1SKenneth D. Merry 							 event (a.k.a. INOT) */
2455ef270ab1SKenneth D. Merry 	{
2456ef270ab1SKenneth D. Merry 		ocs_tgt_resource_t *trsrc = NULL;
2457ef270ab1SKenneth D. Merry 		uint32_t	status = 0;
2458ef270ab1SKenneth D. Merry 		ocs_fcport *fcp = FCPORT(ocs, bus);
2459ef270ab1SKenneth D. Merry 
2460ef270ab1SKenneth D. Merry 		/*printf("XPT_%s %p\n", ccb_h->func_code == XPT_ACCEPT_TARGET_IO ?
2461ef270ab1SKenneth D. Merry 				"ACCEPT_TARGET_IO" : "IMMEDIATE_NOTIFY", ccb);*/
2462ef270ab1SKenneth D. Merry 		trsrc = ocs_tgt_resource_get(fcp, &ccb->ccb_h, &status);
2463ef270ab1SKenneth D. Merry 		if (trsrc == NULL) {
2464ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE);
2465ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2466ef270ab1SKenneth D. Merry 			break;
2467ef270ab1SKenneth D. Merry 		}
2468ef270ab1SKenneth D. Merry 
2469ef270ab1SKenneth D. Merry 		if (XPT_ACCEPT_TARGET_IO == ccb->ccb_h.func_code) {
2470ef270ab1SKenneth D. Merry 			struct ccb_accept_tio *atio = NULL;
2471ef270ab1SKenneth D. Merry 
2472ef270ab1SKenneth D. Merry 			atio = (struct ccb_accept_tio *)ccb;
2473ef270ab1SKenneth D. Merry 			atio->init_id = 0x0badbeef;
2474ef270ab1SKenneth D. Merry 			atio->tag_id  = 0xdeadc0de;
2475ef270ab1SKenneth D. Merry 
2476ef270ab1SKenneth D. Merry 			STAILQ_INSERT_TAIL(&trsrc->atio, &ccb->ccb_h,
2477ef270ab1SKenneth D. Merry 					sim_links.stqe);
2478ef270ab1SKenneth D. Merry 		} else {
2479ef270ab1SKenneth D. Merry 			STAILQ_INSERT_TAIL(&trsrc->inot, &ccb->ccb_h,
2480ef270ab1SKenneth D. Merry 					sim_links.stqe);
2481ef270ab1SKenneth D. Merry 		}
2482ef270ab1SKenneth D. Merry 		ccb->ccb_h.ccb_io_ptr  = NULL;
2483ef270ab1SKenneth D. Merry 		ccb->ccb_h.ccb_ocs_ptr = ocs;
2484ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_INPROG);
2485ef270ab1SKenneth D. Merry 		/*
2486ef270ab1SKenneth D. Merry 		 * These actions give resources to the target driver.
2487ef270ab1SKenneth D. Merry 		 * If we didn't return here, this function would call
2488ef270ab1SKenneth D. Merry 		 * xpt_done(), signaling to the upper layers that an
2489ef270ab1SKenneth D. Merry 		 * IO or other event had arrived.
2490ef270ab1SKenneth D. Merry 		 */
2491ef270ab1SKenneth D. Merry 		break;
2492ef270ab1SKenneth D. Merry 	}
2493ef270ab1SKenneth D. Merry 	case XPT_NOTIFY_ACKNOWLEDGE:
2494ef270ab1SKenneth D. Merry 	{
2495ef270ab1SKenneth D. Merry 		ocs_io_t *io = NULL;
2496ef270ab1SKenneth D. Merry 		ocs_io_t *abortio = NULL;
2497ef270ab1SKenneth D. Merry 
2498ef270ab1SKenneth D. Merry 		/* Get the IO reference for this tag */
2499ef270ab1SKenneth D. Merry 		io = ocs_scsi_find_io(ocs, ccb->cna2.tag_id);
2500ef270ab1SKenneth D. Merry 		if (io == NULL) {
2501ef270ab1SKenneth D. Merry 			device_printf(ocs->dev,
2502ef270ab1SKenneth D. Merry 				"%s: XPT_NOTIFY_ACKNOWLEDGE no IO with tag %#x\n",
2503ef270ab1SKenneth D. Merry 					__func__, ccb->cna2.tag_id);
2504ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR);
2505ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2506ef270ab1SKenneth D. Merry 			break;
2507ef270ab1SKenneth D. Merry 		}
2508ef270ab1SKenneth D. Merry 
2509ef270ab1SKenneth D. Merry 		abortio = io->tgt_io.app;
2510ef270ab1SKenneth D. Merry 		if (abortio) {
2511ef270ab1SKenneth D. Merry 			abortio->tgt_io.flags &= ~OCS_CAM_IO_F_ABORT_NOTIFY;
2512ef270ab1SKenneth D. Merry 			device_printf(ocs->dev,
2513ef270ab1SKenneth D. Merry 				"%s: XPT_NOTIFY_ACK state=%d tag=%#x xid=%#x"
2514ef270ab1SKenneth D. Merry 				" flags=%#x\n",	__func__, abortio->tgt_io.state,
2515ef270ab1SKenneth D. Merry 				abortio->tag, abortio->init_task_tag,
2516ef270ab1SKenneth D. Merry 					abortio->tgt_io.flags);
2517ef270ab1SKenneth D. Merry 			/* TMF response was sent in abort callback */
2518ef270ab1SKenneth D. Merry 		} else {
2519ef270ab1SKenneth D. Merry 			ocs_scsi_send_tmf_resp(io,
2520ef270ab1SKenneth D. Merry 					OCS_SCSI_TMF_FUNCTION_COMPLETE,
2521ef270ab1SKenneth D. Merry 					NULL, ocs_target_tmf_cb, NULL);
2522ef270ab1SKenneth D. Merry 		}
2523ef270ab1SKenneth D. Merry 
2524ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2525ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2526ef270ab1SKenneth D. Merry 		break;
2527ef270ab1SKenneth D. Merry 	}
2528ef270ab1SKenneth D. Merry 	case XPT_CONT_TARGET_IO:	/* continue target IO, sending data/response (a.k.a. CTIO) */
2529ef270ab1SKenneth D. Merry 		if (ocs_target_io(ocs, ccb)) {
2530ef270ab1SKenneth D. Merry 			device_printf(ocs->dev,
2531ef270ab1SKenneth D. Merry 				"XPT_CONT_TARGET_IO failed flags=%x tag=%#x\n",
2532ef270ab1SKenneth D. Merry 				ccb->ccb_h.flags, ccb->csio.tag_id);
2533ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2534ef270ab1SKenneth D. Merry 		}
2535ef270ab1SKenneth D. Merry 		break;
2536ef270ab1SKenneth D. Merry 	default:
2537ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "unhandled func_code = %#x\n",
2538ef270ab1SKenneth D. Merry 				ccb_h->func_code);
2539ef270ab1SKenneth D. Merry 		ccb_h->status = CAM_REQ_INVALID;
2540ef270ab1SKenneth D. Merry 		xpt_done(ccb);
2541ef270ab1SKenneth D. Merry 		break;
2542ef270ab1SKenneth D. Merry 	}
2543ef270ab1SKenneth D. Merry }
2544ef270ab1SKenneth D. Merry 
2545ef270ab1SKenneth D. Merry /**
2546ef270ab1SKenneth D. Merry  * @ingroup cam_api
2547ef270ab1SKenneth D. Merry  * @brief Process events
2548ef270ab1SKenneth D. Merry  *
2549ef270ab1SKenneth D. Merry  * @param sim pointer to the SCSI Interface Module
2550ef270ab1SKenneth D. Merry  *
2551ef270ab1SKenneth D. Merry  */
2552ef270ab1SKenneth D. Merry static void
ocs_poll(struct cam_sim * sim)2553ef270ab1SKenneth D. Merry ocs_poll(struct cam_sim *sim)
2554ef270ab1SKenneth D. Merry {
2555ef270ab1SKenneth D. Merry 	printf("%s\n", __func__);
2556ef270ab1SKenneth D. Merry }
2557ef270ab1SKenneth D. Merry 
2558ef270ab1SKenneth D. Merry static int32_t
ocs_initiator_tmf_cb(ocs_io_t * io,ocs_scsi_io_status_e scsi_status,ocs_scsi_cmd_resp_t * rsp,uint32_t flags,void * arg)2559ef270ab1SKenneth D. Merry ocs_initiator_tmf_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status,
2560ef270ab1SKenneth D. Merry 		ocs_scsi_cmd_resp_t *rsp, uint32_t flags, void *arg)
2561ef270ab1SKenneth D. Merry {
2562ef270ab1SKenneth D. Merry 	int32_t	rc = 0;
2563ef270ab1SKenneth D. Merry 
2564ef270ab1SKenneth D. Merry 	switch (scsi_status) {
2565ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_GOOD:
2566ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_NO_IO:
2567ef270ab1SKenneth D. Merry 		break;
2568ef270ab1SKenneth D. Merry 	case OCS_SCSI_STATUS_CHECK_RESPONSE:
2569ef270ab1SKenneth D. Merry 		if (rsp->response_data_length == 0) {
2570ef270ab1SKenneth D. Merry 			ocs_log_test(io->ocs, "check response without data?!?\n");
2571ef270ab1SKenneth D. Merry 			rc = -1;
2572ef270ab1SKenneth D. Merry 			break;
2573ef270ab1SKenneth D. Merry 		}
2574ef270ab1SKenneth D. Merry 
2575ef270ab1SKenneth D. Merry 		if (rsp->response_data[3] != 0) {
2576ef270ab1SKenneth D. Merry 			ocs_log_test(io->ocs, "TMF status %08x\n",
2577ef270ab1SKenneth D. Merry 				be32toh(*((uint32_t *)rsp->response_data)));
2578ef270ab1SKenneth D. Merry 			rc = -1;
2579ef270ab1SKenneth D. Merry 			break;
2580ef270ab1SKenneth D. Merry 		}
2581ef270ab1SKenneth D. Merry 		break;
2582ef270ab1SKenneth D. Merry 	default:
2583ef270ab1SKenneth D. Merry 		ocs_log_test(io->ocs, "status=%#x\n", scsi_status);
2584ef270ab1SKenneth D. Merry 		rc = -1;
2585ef270ab1SKenneth D. Merry 	}
2586ef270ab1SKenneth D. Merry 
2587ef270ab1SKenneth D. Merry 	ocs_scsi_io_free(io);
2588ef270ab1SKenneth D. Merry 
2589ef270ab1SKenneth D. Merry 	return rc;
2590ef270ab1SKenneth D. Merry }
2591ef270ab1SKenneth D. Merry 
2592ef270ab1SKenneth D. Merry /**
2593ef270ab1SKenneth D. Merry  * @brief lookup target resource structure
2594ef270ab1SKenneth D. Merry  *
2595ef270ab1SKenneth D. Merry  * Arbitrarily support
2596ef270ab1SKenneth D. Merry  *  - wildcard target ID + LU
2597ef270ab1SKenneth D. Merry  *  - 0 target ID + non-wildcard LU
2598ef270ab1SKenneth D. Merry  *
2599ef270ab1SKenneth D. Merry  * @param ocs the driver instance's software context
2600ef270ab1SKenneth D. Merry  * @param ccb_h pointer to the CCB header
2601ef270ab1SKenneth D. Merry  * @param status returned status value
2602ef270ab1SKenneth D. Merry  *
2603ef270ab1SKenneth D. Merry  * @return pointer to the target resource, NULL if none available (e.g. if LU
2604ef270ab1SKenneth D. Merry  * 	   is not enabled)
2605ef270ab1SKenneth D. Merry  */
ocs_tgt_resource_get(ocs_fcport * fcp,struct ccb_hdr * ccb_h,uint32_t * status)2606ef270ab1SKenneth D. Merry static ocs_tgt_resource_t *ocs_tgt_resource_get(ocs_fcport *fcp,
2607ef270ab1SKenneth D. Merry 				struct ccb_hdr *ccb_h, uint32_t *status)
2608ef270ab1SKenneth D. Merry {
2609ef270ab1SKenneth D. Merry 	target_id_t	tid = ccb_h->target_id;
2610ef270ab1SKenneth D. Merry 	lun_id_t	lun = ccb_h->target_lun;
2611ef270ab1SKenneth D. Merry 
2612ef270ab1SKenneth D. Merry 	if (CAM_TARGET_WILDCARD == tid) {
2613ef270ab1SKenneth D. Merry 		if (CAM_LUN_WILDCARD != lun) {
2614ef270ab1SKenneth D. Merry 			*status = CAM_LUN_INVALID;
2615ef270ab1SKenneth D. Merry 			return NULL;
2616ef270ab1SKenneth D. Merry 		}
2617ef270ab1SKenneth D. Merry 		return &fcp->targ_rsrc_wildcard;
2618ef270ab1SKenneth D. Merry 	} else {
2619ef270ab1SKenneth D. Merry 		if (lun < OCS_MAX_LUN) {
2620ef270ab1SKenneth D. Merry 			return &fcp->targ_rsrc[lun];
2621ef270ab1SKenneth D. Merry 		} else {
2622ef270ab1SKenneth D. Merry 			*status = CAM_LUN_INVALID;
2623ef270ab1SKenneth D. Merry 			return NULL;
2624ef270ab1SKenneth D. Merry 		}
2625ef270ab1SKenneth D. Merry 	}
2626ef270ab1SKenneth D. Merry 
2627ef270ab1SKenneth D. Merry }
2628ef270ab1SKenneth D. Merry 
2629ef270ab1SKenneth D. Merry static int32_t
ocs_tgt_resource_abort(struct ocs_softc * ocs,ocs_tgt_resource_t * trsrc)2630ef270ab1SKenneth D. Merry ocs_tgt_resource_abort(struct ocs_softc *ocs, ocs_tgt_resource_t *trsrc)
2631ef270ab1SKenneth D. Merry {
2632ef270ab1SKenneth D. Merry 	union ccb *ccb = NULL;
2633ef270ab1SKenneth D. Merry 
2634ef270ab1SKenneth D. Merry 	do {
2635ef270ab1SKenneth D. Merry 		ccb = (union ccb *)STAILQ_FIRST(&trsrc->atio);
2636ef270ab1SKenneth D. Merry 		if (ccb) {
2637ef270ab1SKenneth D. Merry 			STAILQ_REMOVE_HEAD(&trsrc->atio, sim_links.stqe);
2638ef270ab1SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2639ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2640ef270ab1SKenneth D. Merry 		}
2641ef270ab1SKenneth D. Merry 	} while (ccb);
2642ef270ab1SKenneth D. Merry 
2643ef270ab1SKenneth D. Merry 	do {
2644ef270ab1SKenneth D. Merry 		ccb = (union ccb *)STAILQ_FIRST(&trsrc->inot);
2645ef270ab1SKenneth D. Merry 		if (ccb) {
2646ef270ab1SKenneth D. Merry 			STAILQ_REMOVE_HEAD(&trsrc->inot, sim_links.stqe);
2647ef270ab1SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2648ef270ab1SKenneth D. Merry 			xpt_done(ccb);
2649ef270ab1SKenneth D. Merry 		}
2650ef270ab1SKenneth D. Merry 	} while (ccb);
2651ef270ab1SKenneth D. Merry 
2652ef270ab1SKenneth D. Merry 	return 0;
2653ef270ab1SKenneth D. Merry }
2654ef270ab1SKenneth D. Merry 
2655ef270ab1SKenneth D. Merry static void
ocs_abort_atio(struct ocs_softc * ocs,union ccb * ccb)2656ef270ab1SKenneth D. Merry ocs_abort_atio(struct ocs_softc *ocs, union ccb *ccb)
2657ef270ab1SKenneth D. Merry {
2658ef270ab1SKenneth D. Merry 
2659ef270ab1SKenneth D. Merry 	ocs_io_t	*aio = NULL;
2660ef270ab1SKenneth D. Merry 	ocs_tgt_resource_t *trsrc = NULL;
2661ef270ab1SKenneth D. Merry 	uint32_t	status = CAM_REQ_INVALID;
2662ef270ab1SKenneth D. Merry 	struct ccb_hdr *cur = NULL;
2663ef270ab1SKenneth D. Merry 	union ccb *accb = ccb->cab.abort_ccb;
2664ef270ab1SKenneth D. Merry 
2665ef270ab1SKenneth D. Merry 	int bus = cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path));
2666ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = FCPORT(ocs, bus);
2667ef270ab1SKenneth D. Merry 
2668ef270ab1SKenneth D. Merry 	trsrc = ocs_tgt_resource_get(fcp, &accb->ccb_h, &status);
2669ef270ab1SKenneth D. Merry 	if (trsrc != NULL) {
2670ef270ab1SKenneth D. Merry 		STAILQ_FOREACH(cur, &trsrc->atio, sim_links.stqe) {
2671ef270ab1SKenneth D. Merry 			if (cur != &accb->ccb_h)
2672ef270ab1SKenneth D. Merry 				continue;
2673ef270ab1SKenneth D. Merry 
2674ef270ab1SKenneth D. Merry 			STAILQ_REMOVE(&trsrc->atio, cur, ccb_hdr,
2675ef270ab1SKenneth D. Merry 							sim_links.stqe);
2676ef270ab1SKenneth D. Merry 			accb->ccb_h.status = CAM_REQ_ABORTED;
2677ef270ab1SKenneth D. Merry 			xpt_done(accb);
2678ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2679ef270ab1SKenneth D. Merry 			return;
2680ef270ab1SKenneth D. Merry 		}
2681ef270ab1SKenneth D. Merry 	}
2682ef270ab1SKenneth D. Merry 
2683ef270ab1SKenneth D. Merry 	/* if the ATIO has a valid IO pointer, CAM is telling
2684ef270ab1SKenneth D. Merry 	 * the driver that the ATIO (which represents the entire
2685ef270ab1SKenneth D. Merry 	 * exchange) has been aborted. */
2686ef270ab1SKenneth D. Merry 
2687ef270ab1SKenneth D. Merry 	aio = accb->ccb_h.ccb_io_ptr;
2688ef270ab1SKenneth D. Merry 	if (aio == NULL) {
2689ef270ab1SKenneth D. Merry 		ccb->ccb_h.status = CAM_UA_ABORT;
2690ef270ab1SKenneth D. Merry 		return;
2691ef270ab1SKenneth D. Merry 	}
2692ef270ab1SKenneth D. Merry 
2693ef270ab1SKenneth D. Merry 	device_printf(ocs->dev,
2694ef270ab1SKenneth D. Merry 			"%s: XPT_ABORT ATIO state=%d tag=%#x"
2695ef270ab1SKenneth D. Merry 			" xid=%#x flags=%#x\n",	__func__,
2696ef270ab1SKenneth D. Merry 			aio->tgt_io.state, aio->tag,
2697ef270ab1SKenneth D. Merry 			aio->init_task_tag, aio->tgt_io.flags);
2698ef270ab1SKenneth D. Merry 	/* Expectations are:
2699ef270ab1SKenneth D. Merry 	 *  - abort task was received
2700ef270ab1SKenneth D. Merry 	 *  - already aborted IO in the DEVICE
2701ef270ab1SKenneth D. Merry 	 *  - already received NOTIFY ACKNOWLEDGE */
2702ef270ab1SKenneth D. Merry 
2703ef270ab1SKenneth D. Merry 	if ((aio->tgt_io.flags & OCS_CAM_IO_F_ABORT_RECV) == 0) {
2704ef270ab1SKenneth D. Merry 		device_printf(ocs->dev,	"%s: abort not received or io completed \n", __func__);
2705ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2706ef270ab1SKenneth D. Merry 		return;
2707ef270ab1SKenneth D. Merry 	}
2708ef270ab1SKenneth D. Merry 
2709ef270ab1SKenneth D. Merry 	aio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_CAM;
2710ef270ab1SKenneth D. Merry 	ocs_target_io_free(aio);
2711ef270ab1SKenneth D. Merry 	ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2712ef270ab1SKenneth D. Merry 
2713ef270ab1SKenneth D. Merry 	return;
2714ef270ab1SKenneth D. Merry }
2715ef270ab1SKenneth D. Merry 
2716ef270ab1SKenneth D. Merry static void
ocs_abort_inot(struct ocs_softc * ocs,union ccb * ccb)2717ef270ab1SKenneth D. Merry ocs_abort_inot(struct ocs_softc *ocs, union ccb *ccb)
2718ef270ab1SKenneth D. Merry {
2719ef270ab1SKenneth D. Merry 	ocs_tgt_resource_t *trsrc = NULL;
2720ef270ab1SKenneth D. Merry 	uint32_t	status = CAM_REQ_INVALID;
2721ef270ab1SKenneth D. Merry 	struct ccb_hdr *cur = NULL;
2722ef270ab1SKenneth D. Merry 	union ccb *accb = ccb->cab.abort_ccb;
2723ef270ab1SKenneth D. Merry 
2724ef270ab1SKenneth D. Merry 	int bus = cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path));
2725ef270ab1SKenneth D. Merry 	ocs_fcport *fcp = FCPORT(ocs, bus);
2726ef270ab1SKenneth D. Merry 
2727ef270ab1SKenneth D. Merry 	trsrc = ocs_tgt_resource_get(fcp, &accb->ccb_h, &status);
2728ef270ab1SKenneth D. Merry 	if (trsrc) {
2729ef270ab1SKenneth D. Merry 		STAILQ_FOREACH(cur, &trsrc->inot, sim_links.stqe) {
2730ef270ab1SKenneth D. Merry 			if (cur != &accb->ccb_h)
2731ef270ab1SKenneth D. Merry 				continue;
2732ef270ab1SKenneth D. Merry 
2733ef270ab1SKenneth D. Merry 			STAILQ_REMOVE(&trsrc->inot, cur, ccb_hdr,
2734ef270ab1SKenneth D. Merry 							sim_links.stqe);
2735ef270ab1SKenneth D. Merry 			accb->ccb_h.status = CAM_REQ_ABORTED;
2736ef270ab1SKenneth D. Merry 			xpt_done(accb);
2737ef270ab1SKenneth D. Merry 			ocs_set_ccb_status(ccb, CAM_REQ_CMP);
2738ef270ab1SKenneth D. Merry 			return;
2739ef270ab1SKenneth D. Merry 		}
2740ef270ab1SKenneth D. Merry 	}
2741ef270ab1SKenneth D. Merry 
2742ef270ab1SKenneth D. Merry 	ocs_set_ccb_status(ccb, CAM_UA_ABORT);
2743ef270ab1SKenneth D. Merry 	return;
2744ef270ab1SKenneth D. Merry }
2745ef270ab1SKenneth D. Merry 
2746ef270ab1SKenneth D. Merry static uint32_t
ocs_abort_initiator_io(struct ocs_softc * ocs,union ccb * accb)2747ef270ab1SKenneth D. Merry ocs_abort_initiator_io(struct ocs_softc *ocs, union ccb *accb)
2748ef270ab1SKenneth D. Merry {
2749ef270ab1SKenneth D. Merry 
2750ef270ab1SKenneth D. Merry 	ocs_node_t	*node = NULL;
2751ef270ab1SKenneth D. Merry 	ocs_io_t	*io = NULL;
2752ef270ab1SKenneth D. Merry 	int32_t		rc = 0;
2753ef270ab1SKenneth D. Merry 	struct ccb_scsiio *csio = &accb->csio;
2754ef270ab1SKenneth D. Merry 
27556affb8ebSRam Kishore Vegesna 	ocs_fcport *fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((accb)->ccb_h.path)));
27566affb8ebSRam Kishore Vegesna 	node = ocs_node_get_instance(ocs, fcp->tgt[accb->ccb_h.target_id].node_id);
2757ef270ab1SKenneth D. Merry 	if (node == NULL) {
2758ef270ab1SKenneth D. Merry 		device_printf(ocs->dev, "%s: no device %d\n",
2759ef270ab1SKenneth D. Merry 				__func__, accb->ccb_h.target_id);
2760ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(accb, CAM_DEV_NOT_THERE);
2761ef270ab1SKenneth D. Merry 		xpt_done(accb);
2762ef270ab1SKenneth D. Merry 		return (-1);
2763ef270ab1SKenneth D. Merry 	}
2764ef270ab1SKenneth D. Merry 
2765ef270ab1SKenneth D. Merry 	io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR);
2766ef270ab1SKenneth D. Merry 	if (io == NULL) {
2767ef270ab1SKenneth D. Merry 		device_printf(ocs->dev,
2768ef270ab1SKenneth D. Merry 				"%s: unable to alloc IO\n", __func__);
2769ef270ab1SKenneth D. Merry 		ocs_set_ccb_status(accb, CAM_REQ_CMP_ERR);
2770ef270ab1SKenneth D. Merry 		xpt_done(accb);
2771ef270ab1SKenneth D. Merry 		return (-1);
2772ef270ab1SKenneth D. Merry 	}
2773ef270ab1SKenneth D. Merry 
2774ef270ab1SKenneth D. Merry 	rc = ocs_scsi_send_tmf(node, io,
2775ef270ab1SKenneth D. Merry 			(ocs_io_t *)csio->ccb_h.ccb_io_ptr,
2776ef270ab1SKenneth D. Merry 			accb->ccb_h.target_lun,
2777ef270ab1SKenneth D. Merry 			OCS_SCSI_TMF_ABORT_TASK,
2778ef270ab1SKenneth D. Merry 			NULL, 0, 0,
2779ef270ab1SKenneth D. Merry 			ocs_initiator_tmf_cb, NULL/*arg*/);
2780ef270ab1SKenneth D. Merry 
2781ef270ab1SKenneth D. Merry 	return rc;
2782ef270ab1SKenneth D. Merry }
2783ef270ab1SKenneth D. Merry 
2784ef270ab1SKenneth D. Merry void
ocs_scsi_ini_ddump(ocs_textbuf_t * textbuf,ocs_scsi_ddump_type_e type,void * obj)2785ef270ab1SKenneth D. Merry ocs_scsi_ini_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
2786ef270ab1SKenneth D. Merry {
2787ef270ab1SKenneth D. Merry 	switch(type) {
2788ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_DEVICE: {
2789ef270ab1SKenneth D. Merry 		//ocs_t *ocs = obj;
2790ef270ab1SKenneth D. Merry 		break;
2791ef270ab1SKenneth D. Merry 	}
2792ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_DOMAIN: {
2793ef270ab1SKenneth D. Merry 		//ocs_domain_t *domain = obj;
2794ef270ab1SKenneth D. Merry 		break;
2795ef270ab1SKenneth D. Merry 	}
2796ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_SPORT: {
2797ef270ab1SKenneth D. Merry 		//ocs_sport_t *sport = obj;
2798ef270ab1SKenneth D. Merry 		break;
2799ef270ab1SKenneth D. Merry 	}
2800ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_NODE: {
2801ef270ab1SKenneth D. Merry 		//ocs_node_t *node = obj;
2802ef270ab1SKenneth D. Merry 		break;
2803ef270ab1SKenneth D. Merry 	}
2804ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_IO: {
2805ef270ab1SKenneth D. Merry 		//ocs_io_t *io = obj;
2806ef270ab1SKenneth D. Merry 		break;
2807ef270ab1SKenneth D. Merry 	}
2808ef270ab1SKenneth D. Merry 	default: {
2809ef270ab1SKenneth D. Merry 		break;
2810ef270ab1SKenneth D. Merry 	}
2811ef270ab1SKenneth D. Merry 	}
2812ef270ab1SKenneth D. Merry }
2813ef270ab1SKenneth D. Merry 
2814ef270ab1SKenneth D. Merry void
ocs_scsi_tgt_ddump(ocs_textbuf_t * textbuf,ocs_scsi_ddump_type_e type,void * obj)2815ef270ab1SKenneth D. Merry ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
2816ef270ab1SKenneth D. Merry {
2817ef270ab1SKenneth D. Merry 	switch(type) {
2818ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_DEVICE: {
2819ef270ab1SKenneth D. Merry 		//ocs_t *ocs = obj;
2820ef270ab1SKenneth D. Merry 		break;
2821ef270ab1SKenneth D. Merry 	}
2822ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_DOMAIN: {
2823ef270ab1SKenneth D. Merry 		//ocs_domain_t *domain = obj;
2824ef270ab1SKenneth D. Merry 		break;
2825ef270ab1SKenneth D. Merry 	}
2826ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_SPORT: {
2827ef270ab1SKenneth D. Merry 		//ocs_sport_t *sport = obj;
2828ef270ab1SKenneth D. Merry 		break;
2829ef270ab1SKenneth D. Merry 	}
2830ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_NODE: {
2831ef270ab1SKenneth D. Merry 		//ocs_node_t *node = obj;
2832ef270ab1SKenneth D. Merry 		break;
2833ef270ab1SKenneth D. Merry 	}
2834ef270ab1SKenneth D. Merry 	case OCS_SCSI_DDUMP_IO: {
2835ef270ab1SKenneth D. Merry 		ocs_io_t *io = obj;
2836ef270ab1SKenneth D. Merry 		char *state_str = NULL;
2837ef270ab1SKenneth D. Merry 
2838ef270ab1SKenneth D. Merry 		switch (io->tgt_io.state) {
2839ef270ab1SKenneth D. Merry 		case OCS_CAM_IO_FREE:
2840ef270ab1SKenneth D. Merry 			state_str = "FREE";
2841ef270ab1SKenneth D. Merry 			break;
2842ef270ab1SKenneth D. Merry 		case OCS_CAM_IO_COMMAND:
2843ef270ab1SKenneth D. Merry 			state_str = "COMMAND";
2844ef270ab1SKenneth D. Merry 			break;
2845ef270ab1SKenneth D. Merry 		case OCS_CAM_IO_DATA:
2846ef270ab1SKenneth D. Merry 			state_str = "DATA";
2847ef270ab1SKenneth D. Merry 			break;
2848ef270ab1SKenneth D. Merry 		case OCS_CAM_IO_DATA_DONE:
2849ef270ab1SKenneth D. Merry 			state_str = "DATA_DONE";
2850ef270ab1SKenneth D. Merry 			break;
2851ef270ab1SKenneth D. Merry 		case OCS_CAM_IO_RESP:
2852ef270ab1SKenneth D. Merry 			state_str = "RESP";
2853ef270ab1SKenneth D. Merry 			break;
2854ef270ab1SKenneth D. Merry 		default:
2855ef270ab1SKenneth D. Merry 			state_str = "xxx BAD xxx";
2856ef270ab1SKenneth D. Merry 		}
2857ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "cam_st", "%s", state_str);
2858ef270ab1SKenneth D. Merry 		if (io->tgt_io.app) {
2859ef270ab1SKenneth D. Merry 			ocs_ddump_value(textbuf, "cam_flags", "%#x",
2860ef270ab1SKenneth D. Merry 				((union ccb *)(io->tgt_io.app))->ccb_h.flags);
2861ef270ab1SKenneth D. Merry 			ocs_ddump_value(textbuf, "cam_status", "%#x",
2862ef270ab1SKenneth D. Merry 				((union ccb *)(io->tgt_io.app))->ccb_h.status);
2863ef270ab1SKenneth D. Merry 		}
2864ef270ab1SKenneth D. Merry 
2865ef270ab1SKenneth D. Merry 		break;
2866ef270ab1SKenneth D. Merry 	}
2867ef270ab1SKenneth D. Merry 	default: {
2868ef270ab1SKenneth D. Merry 		break;
2869ef270ab1SKenneth D. Merry 	}
2870ef270ab1SKenneth D. Merry 	}
2871ef270ab1SKenneth D. Merry }
2872ef270ab1SKenneth D. Merry 
ocs_scsi_get_block_vaddr(ocs_io_t * io,uint64_t blocknumber,ocs_scsi_vaddr_len_t addrlen[],uint32_t max_addrlen,void ** dif_vaddr)2873ef270ab1SKenneth D. Merry int32_t ocs_scsi_get_block_vaddr(ocs_io_t *io, uint64_t blocknumber,
2874ef270ab1SKenneth D. Merry 				ocs_scsi_vaddr_len_t addrlen[],
2875ef270ab1SKenneth D. Merry 				uint32_t max_addrlen, void **dif_vaddr)
2876ef270ab1SKenneth D. Merry {
2877ef270ab1SKenneth D. Merry 	return -1;
2878ef270ab1SKenneth D. Merry }
2879ef270ab1SKenneth D. Merry 
2880ef270ab1SKenneth D. Merry uint32_t
ocs_get_crn(ocs_node_t * node,uint8_t * crn,uint64_t lun)2881ef270ab1SKenneth D. Merry ocs_get_crn(ocs_node_t *node, uint8_t *crn, uint64_t lun)
2882ef270ab1SKenneth D. Merry {
2883ef270ab1SKenneth D. Merry 	uint32_t idx;
2884ef270ab1SKenneth D. Merry 	struct ocs_lun_crn *lcrn = NULL;
2885ef270ab1SKenneth D. Merry 	idx = lun % OCS_MAX_LUN;
2886ef270ab1SKenneth D. Merry 
2887ef270ab1SKenneth D. Merry 	lcrn = node->ini_node.lun_crn[idx];
2888ef270ab1SKenneth D. Merry 
2889ef270ab1SKenneth D. Merry 	if (lcrn == NULL) {
2890ef270ab1SKenneth D. Merry 		lcrn = ocs_malloc(node->ocs, sizeof(struct ocs_lun_crn),
2891ef270ab1SKenneth D. Merry 					M_ZERO|M_NOWAIT);
2892ef270ab1SKenneth D. Merry 		if (lcrn == NULL) {
2893ef270ab1SKenneth D. Merry 			return (1);
2894ef270ab1SKenneth D. Merry 		}
2895ef270ab1SKenneth D. Merry 
2896ef270ab1SKenneth D. Merry 		lcrn->lun = lun;
2897ef270ab1SKenneth D. Merry 		node->ini_node.lun_crn[idx] = lcrn;
2898ef270ab1SKenneth D. Merry 	}
2899ef270ab1SKenneth D. Merry 
2900ef270ab1SKenneth D. Merry 	if (lcrn->lun != lun) {
2901ef270ab1SKenneth D. Merry 		return (1);
2902ef270ab1SKenneth D. Merry 	}
2903ef270ab1SKenneth D. Merry 
2904ef270ab1SKenneth D. Merry 	if (lcrn->crnseed == 0)
2905ef270ab1SKenneth D. Merry 		lcrn->crnseed = 1;
2906ef270ab1SKenneth D. Merry 
2907ef270ab1SKenneth D. Merry 	*crn = lcrn->crnseed++;
2908ef270ab1SKenneth D. Merry 	return (0);
2909ef270ab1SKenneth D. Merry }
2910ef270ab1SKenneth D. Merry 
2911ef270ab1SKenneth D. Merry void
ocs_del_crn(ocs_node_t * node)2912ef270ab1SKenneth D. Merry ocs_del_crn(ocs_node_t *node)
2913ef270ab1SKenneth D. Merry {
2914ef270ab1SKenneth D. Merry 	uint32_t i;
2915ef270ab1SKenneth D. Merry 	struct ocs_lun_crn *lcrn = NULL;
2916ef270ab1SKenneth D. Merry 
2917ef270ab1SKenneth D. Merry 	for(i = 0; i < OCS_MAX_LUN; i++) {
2918ef270ab1SKenneth D. Merry 		lcrn = node->ini_node.lun_crn[i];
2919ef270ab1SKenneth D. Merry 		if (lcrn) {
2920ef270ab1SKenneth D. Merry 			ocs_free(node->ocs, lcrn, sizeof(*lcrn));
2921ef270ab1SKenneth D. Merry 		}
2922ef270ab1SKenneth D. Merry 	}
2923ef270ab1SKenneth D. Merry 
2924ef270ab1SKenneth D. Merry 	return;
2925ef270ab1SKenneth D. Merry }
2926ef270ab1SKenneth D. Merry 
2927ef270ab1SKenneth D. Merry void
ocs_reset_crn(ocs_node_t * node,uint64_t lun)2928ef270ab1SKenneth D. Merry ocs_reset_crn(ocs_node_t *node, uint64_t lun)
2929ef270ab1SKenneth D. Merry {
2930ef270ab1SKenneth D. Merry 	uint32_t idx;
2931ef270ab1SKenneth D. Merry 	struct ocs_lun_crn *lcrn = NULL;
2932ef270ab1SKenneth D. Merry 	idx = lun % OCS_MAX_LUN;
2933ef270ab1SKenneth D. Merry 
2934ef270ab1SKenneth D. Merry 	lcrn = node->ini_node.lun_crn[idx];
2935ef270ab1SKenneth D. Merry 	if (lcrn)
2936ef270ab1SKenneth D. Merry 		lcrn->crnseed = 0;
2937ef270ab1SKenneth D. Merry 
2938ef270ab1SKenneth D. Merry 	return;
2939ef270ab1SKenneth D. Merry }
2940