1df54c2f9SSascha Wildner /*
2df54c2f9SSascha Wildner * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3df54c2f9SSascha Wildner * Copyright (c) 2004-05 Vinod Kashyap.
4df54c2f9SSascha Wildner * All rights reserved.
5df54c2f9SSascha Wildner *
6df54c2f9SSascha Wildner * Redistribution and use in source and binary forms, with or without
7df54c2f9SSascha Wildner * modification, are permitted provided that the following conditions
8df54c2f9SSascha Wildner * are met:
9df54c2f9SSascha Wildner * 1. Redistributions of source code must retain the above copyright
10df54c2f9SSascha Wildner * notice, this list of conditions and the following disclaimer.
11df54c2f9SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
12df54c2f9SSascha Wildner * notice, this list of conditions and the following disclaimer in the
13df54c2f9SSascha Wildner * documentation and/or other materials provided with the distribution.
14df54c2f9SSascha Wildner *
15df54c2f9SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16df54c2f9SSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17df54c2f9SSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18df54c2f9SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19df54c2f9SSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20df54c2f9SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21df54c2f9SSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22df54c2f9SSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23df54c2f9SSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24df54c2f9SSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25df54c2f9SSascha Wildner * SUCH DAMAGE.
26df54c2f9SSascha Wildner *
271e0dd9ddSSascha Wildner * $FreeBSD: head/sys/dev/twa/tw_osl_cam.c 257381 2013-10-30 14:04:47Z nwhitehorn $
28df54c2f9SSascha Wildner */
29df54c2f9SSascha Wildner
30df54c2f9SSascha Wildner /*
31df54c2f9SSascha Wildner * AMCC'S 3ware driver for 9000 series storage controllers.
32df54c2f9SSascha Wildner *
33df54c2f9SSascha Wildner * Author: Vinod Kashyap
34df54c2f9SSascha Wildner * Modifications by: Adam Radford
35df54c2f9SSascha Wildner * Modifications by: Manjunath Ranganathaiah
36df54c2f9SSascha Wildner */
37df54c2f9SSascha Wildner
38df54c2f9SSascha Wildner
39df54c2f9SSascha Wildner /*
40df54c2f9SSascha Wildner * FreeBSD CAM related functions.
41df54c2f9SSascha Wildner */
42df54c2f9SSascha Wildner
43df54c2f9SSascha Wildner
44df54c2f9SSascha Wildner #include <dev/raid/twa/tw_osl_includes.h>
45df54c2f9SSascha Wildner
46df54c2f9SSascha Wildner #include <bus/cam/cam.h>
47df54c2f9SSascha Wildner #include <bus/cam/cam_ccb.h>
48df54c2f9SSascha Wildner #include <bus/cam/cam_sim.h>
49df54c2f9SSascha Wildner #include <bus/cam/cam_xpt_sim.h>
50df54c2f9SSascha Wildner #include <bus/cam/cam_debug.h>
51df54c2f9SSascha Wildner #include <bus/cam/cam_periph.h>
52df54c2f9SSascha Wildner #include <bus/cam/cam_xpt_periph.h>
53df54c2f9SSascha Wildner
54df54c2f9SSascha Wildner #include <bus/cam/scsi/scsi_all.h>
55df54c2f9SSascha Wildner #include <bus/cam/scsi/scsi_message.h>
56df54c2f9SSascha Wildner
57df54c2f9SSascha Wildner static TW_VOID twa_action(struct cam_sim *sim, union ccb *ccb);
58df54c2f9SSascha Wildner static TW_VOID twa_poll(struct cam_sim *sim);
59df54c2f9SSascha Wildner static TW_VOID twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
60df54c2f9SSascha Wildner
61df54c2f9SSascha Wildner static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req,
62df54c2f9SSascha Wildner union ccb *ccb);
63df54c2f9SSascha Wildner
64df54c2f9SSascha Wildner
65df54c2f9SSascha Wildner
66df54c2f9SSascha Wildner /*
67df54c2f9SSascha Wildner * Function name: tw_osli_cam_attach
68df54c2f9SSascha Wildner * Description: Attaches the driver to CAM.
69df54c2f9SSascha Wildner *
70df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
71df54c2f9SSascha Wildner * Output: None
72df54c2f9SSascha Wildner * Return value: 0 -- success
73df54c2f9SSascha Wildner * non-zero-- failure
74df54c2f9SSascha Wildner */
75df54c2f9SSascha Wildner TW_INT32
tw_osli_cam_attach(struct twa_softc * sc)76df54c2f9SSascha Wildner tw_osli_cam_attach(struct twa_softc *sc)
77df54c2f9SSascha Wildner {
78df54c2f9SSascha Wildner struct cam_devq *devq;
790ae4d753SSascha Wildner TW_INT32 error;
80df54c2f9SSascha Wildner
81df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
82df54c2f9SSascha Wildner
83df54c2f9SSascha Wildner /*
84df54c2f9SSascha Wildner * Create the device queue for our SIM.
85df54c2f9SSascha Wildner */
864fbf05f9SSascha Wildner if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
87df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
88df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
89df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
90df54c2f9SSascha Wildner 0x2100,
91df54c2f9SSascha Wildner "Failed to create SIM device queue",
92df54c2f9SSascha Wildner ENOMEM);
93df54c2f9SSascha Wildner return(ENOMEM);
94df54c2f9SSascha Wildner }
95df54c2f9SSascha Wildner
96df54c2f9SSascha Wildner /*
97df54c2f9SSascha Wildner * Create a SIM entry. Though we can support TW_OSLI_MAX_NUM_REQUESTS
98df54c2f9SSascha Wildner * simultaneous requests, we claim to be able to handle only
99df54c2f9SSascha Wildner * TW_OSLI_MAX_NUM_IOS (two less), so that we always have a request
100df54c2f9SSascha Wildner * packet available to service ioctls and AENs.
101df54c2f9SSascha Wildner */
102df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "Calling cam_sim_alloc");
103df54c2f9SSascha Wildner sc->sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
104df54c2f9SSascha Wildner device_get_unit(sc->bus_dev), sc->sim_lock,
105df54c2f9SSascha Wildner TW_OSLI_MAX_NUM_IOS, 1, devq);
1060ae4d753SSascha Wildner cam_simq_release(devq);
107a712521bSSascha Wildner if (sc->sim == NULL) {
108df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
109df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
110df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
111df54c2f9SSascha Wildner 0x2101,
112df54c2f9SSascha Wildner "Failed to create a SIM entry",
113df54c2f9SSascha Wildner ENOMEM);
114df54c2f9SSascha Wildner return(ENOMEM);
115df54c2f9SSascha Wildner }
116df54c2f9SSascha Wildner
117df54c2f9SSascha Wildner /*
118df54c2f9SSascha Wildner * Register the bus.
119df54c2f9SSascha Wildner */
120df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "Calling xpt_bus_register");
121df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_EXCLUSIVE);
122df54c2f9SSascha Wildner if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) {
123df54c2f9SSascha Wildner cam_sim_free(sc->sim);
124df54c2f9SSascha Wildner sc->sim = NULL; /* so cam_detach will not try to free it */
125df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
126df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
127df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
128df54c2f9SSascha Wildner 0x2102,
129df54c2f9SSascha Wildner "Failed to register the bus",
130df54c2f9SSascha Wildner ENXIO);
131df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
132df54c2f9SSascha Wildner return(ENXIO);
133df54c2f9SSascha Wildner }
134df54c2f9SSascha Wildner
135df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "Calling xpt_create_path");
136df54c2f9SSascha Wildner if (xpt_create_path(&sc->path, NULL,
137df54c2f9SSascha Wildner cam_sim_path(sc->sim),
138df54c2f9SSascha Wildner CAM_TARGET_WILDCARD,
139df54c2f9SSascha Wildner CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
140df54c2f9SSascha Wildner xpt_bus_deregister(cam_sim_path (sc->sim));
141df54c2f9SSascha Wildner cam_sim_free(sc->sim);
1420ae4d753SSascha Wildner sc->sim = NULL; /* so cam_detach will not try to free it */
143df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
144df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
145df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
146df54c2f9SSascha Wildner 0x2103,
147df54c2f9SSascha Wildner "Failed to create path",
148df54c2f9SSascha Wildner ENXIO);
149df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
150df54c2f9SSascha Wildner return(ENXIO);
151df54c2f9SSascha Wildner }
152df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
153df54c2f9SSascha Wildner
1540ae4d753SSascha Wildner tw_osli_dbg_dprintf(3, sc, "Calling tw_osli_request_bus_scan");
1550ae4d753SSascha Wildner /*
1560ae4d753SSascha Wildner * Request a bus scan, so that CAM gets to know of
1570ae4d753SSascha Wildner * the logical units that we control.
1580ae4d753SSascha Wildner */
1590ae4d753SSascha Wildner if ((error = tw_osli_request_bus_scan(sc)))
1600ae4d753SSascha Wildner tw_osli_printf(sc, "error = %d",
1610ae4d753SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
1620ae4d753SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
1630ae4d753SSascha Wildner 0x2104,
1640ae4d753SSascha Wildner "Bus scan request to CAM failed",
1650ae4d753SSascha Wildner error);
1660ae4d753SSascha Wildner
167df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "exiting");
168df54c2f9SSascha Wildner return(0);
169df54c2f9SSascha Wildner }
170df54c2f9SSascha Wildner
171df54c2f9SSascha Wildner
172df54c2f9SSascha Wildner
173df54c2f9SSascha Wildner /*
174df54c2f9SSascha Wildner * Function name: tw_osli_cam_detach
175df54c2f9SSascha Wildner * Description: Detaches the driver from CAM.
176df54c2f9SSascha Wildner *
177df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
178df54c2f9SSascha Wildner * Output: None
179df54c2f9SSascha Wildner * Return value: None
180df54c2f9SSascha Wildner */
181df54c2f9SSascha Wildner TW_VOID
tw_osli_cam_detach(struct twa_softc * sc)182df54c2f9SSascha Wildner tw_osli_cam_detach(struct twa_softc *sc)
183df54c2f9SSascha Wildner {
184df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entered");
185df54c2f9SSascha Wildner
186df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_EXCLUSIVE);
187df54c2f9SSascha Wildner
188df54c2f9SSascha Wildner if (sc->path)
189df54c2f9SSascha Wildner xpt_free_path(sc->path);
190df54c2f9SSascha Wildner if (sc->sim) {
191df54c2f9SSascha Wildner xpt_bus_deregister(cam_sim_path(sc->sim));
192df54c2f9SSascha Wildner /* Passing TRUE to cam_sim_free will free the devq as well. */
193df54c2f9SSascha Wildner cam_sim_free(sc->sim);
194df54c2f9SSascha Wildner }
195df54c2f9SSascha Wildner /* It's ok have 1 hold count while destroying the mutex */
196df54c2f9SSascha Wildner lockuninit(sc->sim_lock);
197df54c2f9SSascha Wildner }
198df54c2f9SSascha Wildner
199df54c2f9SSascha Wildner
200df54c2f9SSascha Wildner
201df54c2f9SSascha Wildner /*
202df54c2f9SSascha Wildner * Function name: tw_osli_execute_scsi
203df54c2f9SSascha Wildner * Description: Build a fw cmd, based on a CAM style ccb, and
204df54c2f9SSascha Wildner * send it down.
205df54c2f9SSascha Wildner *
206df54c2f9SSascha Wildner * Input: req -- ptr to OSL internal request context
207df54c2f9SSascha Wildner * ccb -- ptr to CAM style ccb
208df54c2f9SSascha Wildner * Output: None
209df54c2f9SSascha Wildner * Return value: 0 -- success
210df54c2f9SSascha Wildner * non-zero-- failure
211df54c2f9SSascha Wildner */
2128406cf70SSascha Wildner static TW_INT32
tw_osli_execute_scsi(struct tw_osli_req_context * req,union ccb * ccb)213df54c2f9SSascha Wildner tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb)
214df54c2f9SSascha Wildner {
215df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
216df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt;
217df54c2f9SSascha Wildner struct tw_cl_scsi_req_packet *scsi_req;
218df54c2f9SSascha Wildner struct ccb_hdr *ccb_h = &(ccb->ccb_h);
219df54c2f9SSascha Wildner struct ccb_scsiio *csio = &(ccb->csio);
220df54c2f9SSascha Wildner TW_INT32 error;
221df54c2f9SSascha Wildner
222df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "SCSI I/O request 0x%x",
223df54c2f9SSascha Wildner csio->cdb_io.cdb_bytes[0]);
224df54c2f9SSascha Wildner
225df54c2f9SSascha Wildner if (ccb_h->target_id >= TW_CL_MAX_NUM_UNITS) {
2261e0dd9ddSSascha Wildner tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %jx",
2271e0dd9ddSSascha Wildner ccb_h->path_id, ccb_h->target_id,
2281e0dd9ddSSascha Wildner (uintmax_t)ccb_h->target_lun);
229df54c2f9SSascha Wildner ccb_h->status |= CAM_TID_INVALID;
230df54c2f9SSascha Wildner xpt_done(ccb);
231df54c2f9SSascha Wildner return(1);
232df54c2f9SSascha Wildner }
233df54c2f9SSascha Wildner if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
2341e0dd9ddSSascha Wildner tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %jx",
2351e0dd9ddSSascha Wildner ccb_h->path_id, ccb_h->target_id,
2361e0dd9ddSSascha Wildner (uintmax_t)ccb_h->target_lun);
237df54c2f9SSascha Wildner ccb_h->status |= CAM_LUN_INVALID;
238df54c2f9SSascha Wildner xpt_done(ccb);
239df54c2f9SSascha Wildner return(1);
240df54c2f9SSascha Wildner }
241df54c2f9SSascha Wildner
242df54c2f9SSascha Wildner if(ccb_h->flags & CAM_CDB_PHYS) {
243df54c2f9SSascha Wildner tw_osli_printf(sc, "",
244df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
245df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
246df54c2f9SSascha Wildner 0x2105,
247df54c2f9SSascha Wildner "Physical CDB address!");
248df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
249df54c2f9SSascha Wildner xpt_done(ccb);
250df54c2f9SSascha Wildner return(1);
251df54c2f9SSascha Wildner }
252df54c2f9SSascha Wildner
253df54c2f9SSascha Wildner /*
254df54c2f9SSascha Wildner * We are going to work on this request. Mark it as enqueued (though
255df54c2f9SSascha Wildner * we don't actually queue it...)
256df54c2f9SSascha Wildner */
257df54c2f9SSascha Wildner ccb_h->status |= CAM_SIM_QUEUED;
258df54c2f9SSascha Wildner
259df54c2f9SSascha Wildner if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
260df54c2f9SSascha Wildner if(ccb_h->flags & CAM_DIR_IN)
261df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
262df54c2f9SSascha Wildner else
263df54c2f9SSascha Wildner req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
264df54c2f9SSascha Wildner }
265df54c2f9SSascha Wildner
266df54c2f9SSascha Wildner /* Build the CL understood request packet for SCSI cmds. */
267df54c2f9SSascha Wildner req_pkt = &req->req_pkt;
268df54c2f9SSascha Wildner req_pkt->status = 0;
269df54c2f9SSascha Wildner req_pkt->tw_osl_callback = tw_osl_complete_io;
270df54c2f9SSascha Wildner scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
271df54c2f9SSascha Wildner scsi_req->unit = ccb_h->target_id;
272df54c2f9SSascha Wildner scsi_req->lun = ccb_h->target_lun;
273df54c2f9SSascha Wildner scsi_req->sense_len = 0;
274df54c2f9SSascha Wildner scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
275df54c2f9SSascha Wildner scsi_req->scsi_status = 0;
276df54c2f9SSascha Wildner if(ccb_h->flags & CAM_CDB_POINTER)
277df54c2f9SSascha Wildner scsi_req->cdb = csio->cdb_io.cdb_ptr;
278df54c2f9SSascha Wildner else
279df54c2f9SSascha Wildner scsi_req->cdb = csio->cdb_io.cdb_bytes;
280df54c2f9SSascha Wildner scsi_req->cdb_len = csio->cdb_len;
281df54c2f9SSascha Wildner
282df54c2f9SSascha Wildner if (!(ccb_h->flags & CAM_DATA_PHYS)) {
283df54c2f9SSascha Wildner /* Virtual data addresses. Need to convert them... */
284df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc,
285df54c2f9SSascha Wildner "XPT_SCSI_IO: Single virtual address!");
286df54c2f9SSascha Wildner if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
287df54c2f9SSascha Wildner if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
288df54c2f9SSascha Wildner tw_osli_printf(sc, "size = %d",
289df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
290df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
291df54c2f9SSascha Wildner 0x2106,
292df54c2f9SSascha Wildner "I/O size too big",
293df54c2f9SSascha Wildner csio->dxfer_len);
294df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_TOO_BIG;
2954fbf05f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
296df54c2f9SSascha Wildner xpt_done(ccb);
297df54c2f9SSascha Wildner return(1);
298df54c2f9SSascha Wildner }
299df54c2f9SSascha Wildner
300df54c2f9SSascha Wildner if ((req->length = csio->dxfer_len)) {
301df54c2f9SSascha Wildner req->data = csio->data_ptr;
302df54c2f9SSascha Wildner scsi_req->sgl_entries = 1;
303df54c2f9SSascha Wildner }
304df54c2f9SSascha Wildner } else {
305df54c2f9SSascha Wildner tw_osli_printf(sc, "",
306df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
307df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
308df54c2f9SSascha Wildner 0x2107,
309df54c2f9SSascha Wildner "XPT_SCSI_IO: Got SGList");
310df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
3114fbf05f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
312df54c2f9SSascha Wildner xpt_done(ccb);
313df54c2f9SSascha Wildner return(1);
314df54c2f9SSascha Wildner }
315df54c2f9SSascha Wildner } else {
316df54c2f9SSascha Wildner /* Data addresses are physical. */
317df54c2f9SSascha Wildner tw_osli_printf(sc, "",
318df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
319df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
320df54c2f9SSascha Wildner 0x2108,
321df54c2f9SSascha Wildner "XPT_SCSI_IO: Physical data addresses");
322df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
323df54c2f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
324df54c2f9SSascha Wildner xpt_done(ccb);
325df54c2f9SSascha Wildner return(1);
326df54c2f9SSascha Wildner }
327df54c2f9SSascha Wildner
3284fbf05f9SSascha Wildner req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
3294fbf05f9SSascha Wildner
3304fbf05f9SSascha Wildner
331df54c2f9SSascha Wildner /*
332df54c2f9SSascha Wildner * twa_map_load_data_callback will fill in the SGL,
333df54c2f9SSascha Wildner * and submit the I/O.
334df54c2f9SSascha Wildner */
335df54c2f9SSascha Wildner error = tw_osli_map_request(req);
3364fbf05f9SSascha Wildner if ((error) && (req->flags & TW_OSLI_REQ_FLAGS_FAILED)) {
3374fbf05f9SSascha Wildner req->deadline = 0;
3384fbf05f9SSascha Wildner ccb_h->status = CAM_REQ_CMP_ERR;
3394fbf05f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
3404fbf05f9SSascha Wildner xpt_done(ccb);
3414fbf05f9SSascha Wildner }
342df54c2f9SSascha Wildner return(error);
343df54c2f9SSascha Wildner }
344df54c2f9SSascha Wildner
345df54c2f9SSascha Wildner
346df54c2f9SSascha Wildner
347df54c2f9SSascha Wildner /*
348df54c2f9SSascha Wildner * Function name: twa_action
349df54c2f9SSascha Wildner * Description: Driver entry point for CAM's use.
350df54c2f9SSascha Wildner *
351df54c2f9SSascha Wildner * Input: sim -- sim corresponding to the ctlr
352df54c2f9SSascha Wildner * ccb -- ptr to CAM request
353df54c2f9SSascha Wildner * Output: None
354df54c2f9SSascha Wildner * Return value: None
355df54c2f9SSascha Wildner */
3568406cf70SSascha Wildner static TW_VOID
twa_action(struct cam_sim * sim,union ccb * ccb)357df54c2f9SSascha Wildner twa_action(struct cam_sim *sim, union ccb *ccb)
358df54c2f9SSascha Wildner {
359df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)cam_sim_softc(sim);
360df54c2f9SSascha Wildner struct ccb_hdr *ccb_h = &(ccb->ccb_h);
361df54c2f9SSascha Wildner
362df54c2f9SSascha Wildner switch (ccb_h->func_code) {
363df54c2f9SSascha Wildner case XPT_SCSI_IO: /* SCSI I/O */
364df54c2f9SSascha Wildner {
365df54c2f9SSascha Wildner struct tw_osli_req_context *req;
366df54c2f9SSascha Wildner
367df54c2f9SSascha Wildner req = tw_osli_get_request(sc);
368df54c2f9SSascha Wildner if (req == NULL) {
369df54c2f9SSascha Wildner tw_osli_dbg_dprintf(2, sc, "Cannot get request pkt.");
370df54c2f9SSascha Wildner /*
371df54c2f9SSascha Wildner * Freeze the simq to maintain ccb ordering. The next
372df54c2f9SSascha Wildner * ccb that gets completed will unfreeze the simq.
373df54c2f9SSascha Wildner */
3744fbf05f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
375df54c2f9SSascha Wildner ccb_h->status |= CAM_REQUEUE_REQ;
376df54c2f9SSascha Wildner xpt_done(ccb);
377df54c2f9SSascha Wildner break;
378df54c2f9SSascha Wildner }
3794fbf05f9SSascha Wildner
3804fbf05f9SSascha Wildner if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
3814fbf05f9SSascha Wildner ccb_h->status &= ~CAM_SIM_QUEUED;
3824fbf05f9SSascha Wildner ccb_h->status |= CAM_REQUEUE_REQ;
3834fbf05f9SSascha Wildner xpt_done(ccb);
3844fbf05f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
3854fbf05f9SSascha Wildner break;
3864fbf05f9SSascha Wildner }
3874fbf05f9SSascha Wildner
388df54c2f9SSascha Wildner req->req_handle.osl_req_ctxt = req;
389df54c2f9SSascha Wildner req->req_handle.is_io = TW_CL_TRUE;
390df54c2f9SSascha Wildner req->orig_req = ccb;
391df54c2f9SSascha Wildner if (tw_osli_execute_scsi(req, ccb))
392df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
393df54c2f9SSascha Wildner break;
394df54c2f9SSascha Wildner }
395df54c2f9SSascha Wildner
396df54c2f9SSascha Wildner case XPT_ABORT:
397df54c2f9SSascha Wildner tw_osli_dbg_dprintf(2, sc, "Abort request.");
398df54c2f9SSascha Wildner ccb_h->status = CAM_UA_ABORT;
399df54c2f9SSascha Wildner xpt_done(ccb);
400df54c2f9SSascha Wildner break;
401df54c2f9SSascha Wildner
402df54c2f9SSascha Wildner case XPT_RESET_BUS:
4034fbf05f9SSascha Wildner tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE,
404df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
405df54c2f9SSascha Wildner 0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
406df54c2f9SSascha Wildner "Received Reset Bus request from CAM",
407df54c2f9SSascha Wildner " ");
408df54c2f9SSascha Wildner
4094fbf05f9SSascha Wildner tw_cl_set_reset_needed(&(sc->ctlr_handle));
410df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_CMP;
411df54c2f9SSascha Wildner xpt_done(ccb);
412df54c2f9SSascha Wildner break;
413df54c2f9SSascha Wildner
414df54c2f9SSascha Wildner case XPT_SET_TRAN_SETTINGS:
415df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
416df54c2f9SSascha Wildner
417df54c2f9SSascha Wildner /*
418df54c2f9SSascha Wildner * This command is not supported, since it's very specific
419df54c2f9SSascha Wildner * to SCSI, and we are doing ATA.
420df54c2f9SSascha Wildner */
421df54c2f9SSascha Wildner ccb_h->status = CAM_FUNC_NOTAVAIL;
422df54c2f9SSascha Wildner xpt_done(ccb);
423df54c2f9SSascha Wildner break;
424df54c2f9SSascha Wildner
425df54c2f9SSascha Wildner case XPT_GET_TRAN_SETTINGS:
426df54c2f9SSascha Wildner {
427df54c2f9SSascha Wildner struct ccb_trans_settings *cts = &ccb->cts;
428df54c2f9SSascha Wildner struct ccb_trans_settings_scsi *scsi =
429df54c2f9SSascha Wildner &cts->proto_specific.scsi;
430df54c2f9SSascha Wildner struct ccb_trans_settings_spi *spi =
431df54c2f9SSascha Wildner &cts->xport_specific.spi;
432df54c2f9SSascha Wildner
433df54c2f9SSascha Wildner cts->protocol = PROTO_SCSI;
434df54c2f9SSascha Wildner cts->protocol_version = SCSI_REV_2;
435df54c2f9SSascha Wildner cts->transport = XPORT_SPI;
436df54c2f9SSascha Wildner cts->transport_version = 2;
437df54c2f9SSascha Wildner
438df54c2f9SSascha Wildner spi->valid = CTS_SPI_VALID_DISC;
439df54c2f9SSascha Wildner spi->flags = CTS_SPI_FLAGS_DISC_ENB;
440df54c2f9SSascha Wildner scsi->valid = CTS_SCSI_VALID_TQ;
441df54c2f9SSascha Wildner scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
442df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
443df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_CMP;
444df54c2f9SSascha Wildner xpt_done(ccb);
445df54c2f9SSascha Wildner break;
446df54c2f9SSascha Wildner }
447df54c2f9SSascha Wildner
448df54c2f9SSascha Wildner case XPT_CALC_GEOMETRY:
449df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
450df54c2f9SSascha Wildner cam_calc_geometry(&ccb->ccg, 1/* extended */);
451df54c2f9SSascha Wildner xpt_done(ccb);
452df54c2f9SSascha Wildner break;
453df54c2f9SSascha Wildner
454df54c2f9SSascha Wildner case XPT_PATH_INQ: /* Path inquiry -- get twa properties */
455df54c2f9SSascha Wildner {
456df54c2f9SSascha Wildner struct ccb_pathinq *path_inq = &ccb->cpi;
457df54c2f9SSascha Wildner
458df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
459df54c2f9SSascha Wildner
460df54c2f9SSascha Wildner path_inq->version_num = 1;
461df54c2f9SSascha Wildner path_inq->hba_inquiry = 0;
462df54c2f9SSascha Wildner path_inq->target_sprt = 0;
463df54c2f9SSascha Wildner path_inq->hba_misc = 0;
464df54c2f9SSascha Wildner path_inq->hba_eng_cnt = 0;
465df54c2f9SSascha Wildner path_inq->max_target = TW_CL_MAX_NUM_UNITS;
466df54c2f9SSascha Wildner path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
467df54c2f9SSascha Wildner path_inq->unit_number = cam_sim_unit(sim);
468df54c2f9SSascha Wildner path_inq->bus_id = cam_sim_bus(sim);
469df54c2f9SSascha Wildner path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
470df54c2f9SSascha Wildner path_inq->base_transfer_speed = 100000;
471df54c2f9SSascha Wildner strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
472df54c2f9SSascha Wildner strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
473df54c2f9SSascha Wildner strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
474df54c2f9SSascha Wildner path_inq->transport = XPORT_SPI;
475df54c2f9SSascha Wildner path_inq->transport_version = 2;
476df54c2f9SSascha Wildner path_inq->protocol = PROTO_SCSI;
477df54c2f9SSascha Wildner path_inq->protocol_version = SCSI_REV_2;
4784fbf05f9SSascha Wildner #if 0 /* XXX swildner */
4794fbf05f9SSascha Wildner path_inq->maxio = TW_CL_MAX_IO_SIZE;
4804fbf05f9SSascha Wildner #endif
481df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_CMP;
482df54c2f9SSascha Wildner xpt_done(ccb);
483df54c2f9SSascha Wildner break;
484df54c2f9SSascha Wildner }
485df54c2f9SSascha Wildner
486df54c2f9SSascha Wildner default:
487df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
488df54c2f9SSascha Wildner ccb_h->status = CAM_REQ_INVALID;
489df54c2f9SSascha Wildner xpt_done(ccb);
490df54c2f9SSascha Wildner break;
491df54c2f9SSascha Wildner }
492df54c2f9SSascha Wildner }
493df54c2f9SSascha Wildner
494df54c2f9SSascha Wildner
495df54c2f9SSascha Wildner
496df54c2f9SSascha Wildner /*
497df54c2f9SSascha Wildner * Function name: twa_poll
498df54c2f9SSascha Wildner * Description: Driver entry point called when interrupts are not
499df54c2f9SSascha Wildner * available.
500df54c2f9SSascha Wildner *
501df54c2f9SSascha Wildner * Input: sim -- sim corresponding to the controller
502df54c2f9SSascha Wildner * Output: None
503df54c2f9SSascha Wildner * Return value: None
504df54c2f9SSascha Wildner */
5058406cf70SSascha Wildner static TW_VOID
twa_poll(struct cam_sim * sim)506df54c2f9SSascha Wildner twa_poll(struct cam_sim *sim)
507df54c2f9SSascha Wildner {
508df54c2f9SSascha Wildner struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
509df54c2f9SSascha Wildner
510df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
511df54c2f9SSascha Wildner tw_cl_interrupt(&(sc->ctlr_handle));
512df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
513df54c2f9SSascha Wildner }
514df54c2f9SSascha Wildner
515df54c2f9SSascha Wildner
516df54c2f9SSascha Wildner
517df54c2f9SSascha Wildner /*
518df54c2f9SSascha Wildner * Function name: tw_osli_request_bus_scan
519df54c2f9SSascha Wildner * Description: Requests CAM for a scan of the bus.
520df54c2f9SSascha Wildner *
521df54c2f9SSascha Wildner * Input: sc -- ptr to per ctlr structure
522df54c2f9SSascha Wildner * Output: None
523df54c2f9SSascha Wildner * Return value: 0 -- success
524df54c2f9SSascha Wildner * non-zero-- failure
525df54c2f9SSascha Wildner */
526df54c2f9SSascha Wildner TW_INT32
tw_osli_request_bus_scan(struct twa_softc * sc)527df54c2f9SSascha Wildner tw_osli_request_bus_scan(struct twa_softc *sc)
528df54c2f9SSascha Wildner {
529df54c2f9SSascha Wildner union ccb *ccb;
530df54c2f9SSascha Wildner
531df54c2f9SSascha Wildner tw_osli_dbg_dprintf(3, sc, "entering");
532df54c2f9SSascha Wildner
533df54c2f9SSascha Wildner /* If we get here before sc->sim is initialized, return an error. */
534df54c2f9SSascha Wildner if (!(sc->sim))
535df54c2f9SSascha Wildner return(ENXIO);
536df54c2f9SSascha Wildner if ((ccb = xpt_alloc_ccb()) == NULL)
537df54c2f9SSascha Wildner return(ENOMEM);
538df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_EXCLUSIVE);
539df54c2f9SSascha Wildner if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sc->sim),
540df54c2f9SSascha Wildner CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
541*cec957e9SMatthew Dillon xpt_free_ccb(&ccb->ccb_h);
542df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
543df54c2f9SSascha Wildner return(EIO);
544df54c2f9SSascha Wildner }
545df54c2f9SSascha Wildner
546df54c2f9SSascha Wildner xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5/*priority (low)*/);
547df54c2f9SSascha Wildner ccb->ccb_h.func_code = XPT_SCAN_BUS;
548df54c2f9SSascha Wildner ccb->ccb_h.cbfcnp = twa_bus_scan_cb;
549df54c2f9SSascha Wildner ccb->crcn.flags = CAM_FLAG_NONE;
550df54c2f9SSascha Wildner xpt_action(ccb);
551df54c2f9SSascha Wildner
552df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
553df54c2f9SSascha Wildner return(0);
554df54c2f9SSascha Wildner }
555df54c2f9SSascha Wildner
556df54c2f9SSascha Wildner
557df54c2f9SSascha Wildner
558df54c2f9SSascha Wildner /*
559df54c2f9SSascha Wildner * Function name: twa_bus_scan_cb
560df54c2f9SSascha Wildner * Description: Callback from CAM on a bus scan request.
561df54c2f9SSascha Wildner *
562df54c2f9SSascha Wildner * Input: periph -- we don't use this
563df54c2f9SSascha Wildner * ccb -- bus scan request ccb that we sent to CAM
564df54c2f9SSascha Wildner * Output: None
565df54c2f9SSascha Wildner * Return value: None
566df54c2f9SSascha Wildner */
567df54c2f9SSascha Wildner static TW_VOID
twa_bus_scan_cb(struct cam_periph * periph,union ccb * ccb)568df54c2f9SSascha Wildner twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
569df54c2f9SSascha Wildner {
570df54c2f9SSascha Wildner tw_osli_dbg_printf(3, "entering");
571df54c2f9SSascha Wildner
572df54c2f9SSascha Wildner if (ccb->ccb_h.status != CAM_REQ_CMP)
573df54c2f9SSascha Wildner kprintf("cam_scan_callback: failure status = %x\n",
574df54c2f9SSascha Wildner ccb->ccb_h.status);
575df54c2f9SSascha Wildner else
576df54c2f9SSascha Wildner tw_osli_dbg_printf(3, "success");
577df54c2f9SSascha Wildner
578df54c2f9SSascha Wildner xpt_free_path(ccb->ccb_h.path);
579df54c2f9SSascha Wildner kfree(ccb, M_TEMP);
580df54c2f9SSascha Wildner }
581df54c2f9SSascha Wildner
582df54c2f9SSascha Wildner
583df54c2f9SSascha Wildner
584df54c2f9SSascha Wildner /*
585df54c2f9SSascha Wildner * Function name: tw_osli_disallow_new_requests
586df54c2f9SSascha Wildner * Description: Calls the appropriate CAM function, so as to freeze
587df54c2f9SSascha Wildner * the flow of new requests from CAM to this controller.
588df54c2f9SSascha Wildner *
589df54c2f9SSascha Wildner * Input: sc -- ptr to OSL internal ctlr context
590df54c2f9SSascha Wildner * req_handle -- ptr to request handle sent by OSL.
591df54c2f9SSascha Wildner * Output: None
592df54c2f9SSascha Wildner * Return value: None
593df54c2f9SSascha Wildner */
594df54c2f9SSascha Wildner TW_VOID
tw_osli_disallow_new_requests(struct twa_softc * sc,struct tw_cl_req_handle * req_handle)595df54c2f9SSascha Wildner tw_osli_disallow_new_requests(struct twa_softc *sc,
596df54c2f9SSascha Wildner struct tw_cl_req_handle *req_handle)
597df54c2f9SSascha Wildner {
598df54c2f9SSascha Wildner /* Only freeze/release the simq for IOs */
599df54c2f9SSascha Wildner if (req_handle->is_io) {
600df54c2f9SSascha Wildner struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
601df54c2f9SSascha Wildner union ccb *ccb = (union ccb *)(req->orig_req);
602df54c2f9SSascha Wildner
603df54c2f9SSascha Wildner xpt_freeze_simq(sc->sim, 1);
604df54c2f9SSascha Wildner ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
605df54c2f9SSascha Wildner }
606df54c2f9SSascha Wildner }
607df54c2f9SSascha Wildner
608df54c2f9SSascha Wildner
609df54c2f9SSascha Wildner
610df54c2f9SSascha Wildner /*
6114fbf05f9SSascha Wildner * Function name: tw_osl_timeout
6124fbf05f9SSascha Wildner * Description: Call to timeout().
613df54c2f9SSascha Wildner *
6144fbf05f9SSascha Wildner * Input: req_handle -- ptr to request handle sent by OSL.
615df54c2f9SSascha Wildner * Output: None
616df54c2f9SSascha Wildner * Return value: None
617df54c2f9SSascha Wildner */
618df54c2f9SSascha Wildner TW_VOID
tw_osl_timeout(struct tw_cl_req_handle * req_handle)6194fbf05f9SSascha Wildner tw_osl_timeout(struct tw_cl_req_handle *req_handle)
620df54c2f9SSascha Wildner {
6214fbf05f9SSascha Wildner struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
6224fbf05f9SSascha Wildner union ccb *ccb = (union ccb *)(req->orig_req);
6234fbf05f9SSascha Wildner struct ccb_hdr *ccb_h = &(ccb->ccb_h);
6244fbf05f9SSascha Wildner
6254fbf05f9SSascha Wildner req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000);
6264fbf05f9SSascha Wildner }
6274fbf05f9SSascha Wildner
6284fbf05f9SSascha Wildner
6294fbf05f9SSascha Wildner
6304fbf05f9SSascha Wildner /*
6314fbf05f9SSascha Wildner * Function name: tw_osl_untimeout
6324fbf05f9SSascha Wildner * Description: Inverse of call to timeout().
6334fbf05f9SSascha Wildner *
6344fbf05f9SSascha Wildner * Input: req_handle -- ptr to request handle sent by OSL.
6354fbf05f9SSascha Wildner * Output: None
6364fbf05f9SSascha Wildner * Return value: None
6374fbf05f9SSascha Wildner */
6384fbf05f9SSascha Wildner TW_VOID
tw_osl_untimeout(struct tw_cl_req_handle * req_handle)6394fbf05f9SSascha Wildner tw_osl_untimeout(struct tw_cl_req_handle *req_handle)
6404fbf05f9SSascha Wildner {
6414fbf05f9SSascha Wildner struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
6424fbf05f9SSascha Wildner
6434fbf05f9SSascha Wildner req->deadline = 0;
644df54c2f9SSascha Wildner }
645df54c2f9SSascha Wildner
646df54c2f9SSascha Wildner
647df54c2f9SSascha Wildner
648df54c2f9SSascha Wildner /*
649df54c2f9SSascha Wildner * Function name: tw_osl_scan_bus
650df54c2f9SSascha Wildner * Description: CL calls this function to request for a bus scan.
651df54c2f9SSascha Wildner *
652df54c2f9SSascha Wildner * Input: ctlr_handle -- ptr to controller handle
653df54c2f9SSascha Wildner * Output: None
654df54c2f9SSascha Wildner * Return value: None
655df54c2f9SSascha Wildner */
656df54c2f9SSascha Wildner TW_VOID
tw_osl_scan_bus(struct tw_cl_ctlr_handle * ctlr_handle)657df54c2f9SSascha Wildner tw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
658df54c2f9SSascha Wildner {
659df54c2f9SSascha Wildner struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt;
660df54c2f9SSascha Wildner TW_INT32 error;
661df54c2f9SSascha Wildner
662df54c2f9SSascha Wildner if ((error = tw_osli_request_bus_scan(sc)))
663df54c2f9SSascha Wildner tw_osli_printf(sc, "error = %d",
664df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
665df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
666df54c2f9SSascha Wildner 0x2109,
667df54c2f9SSascha Wildner "Bus scan request to CAM failed",
668df54c2f9SSascha Wildner error);
669df54c2f9SSascha Wildner }
670df54c2f9SSascha Wildner
671df54c2f9SSascha Wildner
672df54c2f9SSascha Wildner
673df54c2f9SSascha Wildner /*
674df54c2f9SSascha Wildner * Function name: tw_osl_complete_io
675df54c2f9SSascha Wildner * Description: Called to complete CAM scsi requests.
676df54c2f9SSascha Wildner *
677df54c2f9SSascha Wildner * Input: req_handle -- ptr to request handle
678df54c2f9SSascha Wildner * Output: None
679df54c2f9SSascha Wildner * Return value: None
680df54c2f9SSascha Wildner */
681df54c2f9SSascha Wildner TW_VOID
tw_osl_complete_io(struct tw_cl_req_handle * req_handle)682df54c2f9SSascha Wildner tw_osl_complete_io(struct tw_cl_req_handle *req_handle)
683df54c2f9SSascha Wildner {
684df54c2f9SSascha Wildner struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
685df54c2f9SSascha Wildner struct tw_cl_req_packet *req_pkt =
686df54c2f9SSascha Wildner (struct tw_cl_req_packet *)(&req->req_pkt);
687df54c2f9SSascha Wildner struct tw_cl_scsi_req_packet *scsi_req;
688df54c2f9SSascha Wildner struct twa_softc *sc = req->ctlr;
689df54c2f9SSascha Wildner union ccb *ccb = (union ccb *)(req->orig_req);
690df54c2f9SSascha Wildner
691df54c2f9SSascha Wildner tw_osli_dbg_dprintf(10, sc, "entering");
692df54c2f9SSascha Wildner
693df54c2f9SSascha Wildner if (req->state != TW_OSLI_REQ_STATE_BUSY)
694df54c2f9SSascha Wildner tw_osli_printf(sc, "request = %p, status = %d",
695df54c2f9SSascha Wildner TW_CL_SEVERITY_ERROR_STRING,
696df54c2f9SSascha Wildner TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
697df54c2f9SSascha Wildner 0x210A,
698df54c2f9SSascha Wildner "Unposted command completed!!",
699df54c2f9SSascha Wildner req, req->state);
700df54c2f9SSascha Wildner
701df54c2f9SSascha Wildner /*
702df54c2f9SSascha Wildner * Remove request from the busy queue. Just mark it complete.
703df54c2f9SSascha Wildner * There's no need to move it into the complete queue as we are
704df54c2f9SSascha Wildner * going to be done with it right now.
705df54c2f9SSascha Wildner */
706df54c2f9SSascha Wildner req->state = TW_OSLI_REQ_STATE_COMPLETE;
707df54c2f9SSascha Wildner tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
708df54c2f9SSascha Wildner
709df54c2f9SSascha Wildner tw_osli_unmap_request(req);
710df54c2f9SSascha Wildner
7114fbf05f9SSascha Wildner req->deadline = 0;
712df54c2f9SSascha Wildner if (req->error_code) {
713df54c2f9SSascha Wildner /* This request never got submitted to the firmware. */
714df54c2f9SSascha Wildner if (req->error_code == EBUSY) {
715df54c2f9SSascha Wildner /*
716df54c2f9SSascha Wildner * Cmd queue is full, or the Common Layer is out of
717df54c2f9SSascha Wildner * resources. The simq will already have been frozen.
718df54c2f9SSascha Wildner * When this ccb gets completed will unfreeze the simq.
719df54c2f9SSascha Wildner */
720df54c2f9SSascha Wildner ccb->ccb_h.status |= CAM_REQUEUE_REQ;
721df54c2f9SSascha Wildner }
722df54c2f9SSascha Wildner else if (req->error_code == EFBIG)
723df54c2f9SSascha Wildner ccb->ccb_h.status = CAM_REQ_TOO_BIG;
724df54c2f9SSascha Wildner else
725df54c2f9SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR;
726df54c2f9SSascha Wildner } else {
727df54c2f9SSascha Wildner scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
728df54c2f9SSascha Wildner if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
729df54c2f9SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP;
730df54c2f9SSascha Wildner else {
731df54c2f9SSascha Wildner if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
73285b59853SSascha Wildner ccb->ccb_h.status |= CAM_SEL_TIMEOUT;
733df54c2f9SSascha Wildner else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
73485b59853SSascha Wildner ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
735df54c2f9SSascha Wildner else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
736df54c2f9SSascha Wildner ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
737df54c2f9SSascha Wildner else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
7384fbf05f9SSascha Wildner ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_SCSI_BUS_RESET);
739df54c2f9SSascha Wildner /*
740df54c2f9SSascha Wildner * If none of the above errors occurred, simply
741df54c2f9SSascha Wildner * mark completion error.
742df54c2f9SSascha Wildner */
743df54c2f9SSascha Wildner if (ccb->ccb_h.status == 0)
744df54c2f9SSascha Wildner ccb->ccb_h.status = CAM_REQ_CMP_ERR;
745df54c2f9SSascha Wildner
746df54c2f9SSascha Wildner if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
747df54c2f9SSascha Wildner ccb->csio.sense_len = scsi_req->sense_len;
748df54c2f9SSascha Wildner ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
749df54c2f9SSascha Wildner }
750df54c2f9SSascha Wildner }
751df54c2f9SSascha Wildner
752df54c2f9SSascha Wildner ccb->csio.scsi_status = scsi_req->scsi_status;
753df54c2f9SSascha Wildner }
754df54c2f9SSascha Wildner
755df54c2f9SSascha Wildner ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
756df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_EXCLUSIVE);
757df54c2f9SSascha Wildner xpt_done(ccb);
758df54c2f9SSascha Wildner lockmgr(sc->sim_lock, LK_RELEASE);
759df54c2f9SSascha Wildner if (! req->error_code)
760df54c2f9SSascha Wildner /* twa_action will free the request otherwise */
761df54c2f9SSascha Wildner tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
762df54c2f9SSascha Wildner }
763