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