tw_osl_cam.c revision 203108
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 203108 2010-01-28 08:41:30Z 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);
58static TW_VOID	twa_timeout(TW_VOID *arg);
59
60static TW_INT32	tw_osli_execute_scsi(struct tw_osli_req_context *req,
61	union ccb *ccb);
62
63
64
65/*
66 * Function name:	tw_osli_cam_attach
67 * Description:		Attaches the driver to CAM.
68 *
69 * Input:		sc	-- ptr to OSL internal ctlr context
70 * Output:		None
71 * Return value:	0	-- success
72 *			non-zero-- failure
73 */
74TW_INT32
75tw_osli_cam_attach(struct twa_softc *sc)
76{
77	struct cam_devq		*devq;
78
79	tw_osli_dbg_dprintf(3, sc, "entered");
80
81	/*
82	 * Create the device queue for our SIM.
83	 */
84	if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
85		tw_osli_printf(sc, "error = %d",
86			TW_CL_SEVERITY_ERROR_STRING,
87			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
88			0x2100,
89			"Failed to create SIM device queue",
90			ENOMEM);
91		return(ENOMEM);
92	}
93
94	/*
95	 * Create a SIM entry.  Though we can support TW_OSLI_MAX_NUM_IOS
96	 * simultaneous requests, we claim to be able to handle only
97	 * (TW_OSLI_MAX_NUM_IOS - 1), so that we always have a request
98	 * packet available to service ioctls.
99	 */
100	tw_osli_dbg_dprintf(3, sc, "Calling cam_sim_alloc");
101	sc->sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
102			device_get_unit(sc->bus_dev), sc->sim_lock,
103			TW_OSLI_MAX_NUM_IOS - 1, 1, devq);
104	if (sc->sim == NULL) {
105		cam_simq_free(devq);
106		tw_osli_printf(sc, "error = %d",
107			TW_CL_SEVERITY_ERROR_STRING,
108			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
109			0x2101,
110			"Failed to create a SIM entry",
111			ENOMEM);
112		return(ENOMEM);
113	}
114
115	/*
116	 * Register the bus.
117	 */
118	tw_osli_dbg_dprintf(3, sc, "Calling xpt_bus_register");
119	mtx_lock(sc->sim_lock);
120	if (xpt_bus_register(sc->sim, sc->bus_dev, 0) != CAM_SUCCESS) {
121		cam_sim_free(sc->sim, TRUE);
122		sc->sim = NULL; /* so cam_detach will not try to free it */
123		tw_osli_printf(sc, "error = %d",
124			TW_CL_SEVERITY_ERROR_STRING,
125			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
126			0x2102,
127			"Failed to register the bus",
128			ENXIO);
129		mtx_unlock(sc->sim_lock);
130		return(ENXIO);
131	}
132
133	tw_osli_dbg_dprintf(3, sc, "Calling xpt_create_path");
134	if (xpt_create_path(&sc->path, NULL,
135				cam_sim_path(sc->sim),
136				CAM_TARGET_WILDCARD,
137				CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
138		xpt_bus_deregister(cam_sim_path (sc->sim));
139		/* Passing TRUE to cam_sim_free will free the devq as well. */
140		cam_sim_free(sc->sim, TRUE);
141		tw_osli_printf(sc, "error = %d",
142			TW_CL_SEVERITY_ERROR_STRING,
143			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
144			0x2103,
145			"Failed to create path",
146			ENXIO);
147		mtx_unlock(sc->sim_lock);
148		return(ENXIO);
149	}
150	mtx_unlock(sc->sim_lock);
151
152	tw_osli_dbg_dprintf(3, sc, "exiting");
153	return(0);
154}
155
156
157
158/*
159 * Function name:	tw_osli_cam_detach
160 * Description:		Detaches the driver from CAM.
161 *
162 * Input:		sc	-- ptr to OSL internal ctlr context
163 * Output:		None
164 * Return value:	None
165 */
166TW_VOID
167tw_osli_cam_detach(struct twa_softc *sc)
168{
169	tw_osli_dbg_dprintf(3, sc, "entered");
170
171#ifdef TW_OSLI_DEFERRED_INTR_USED
172	/*  - drain the taskqueue
173           Ctrl is already went down so, no more enqueuetask will
174           happen . Don't  hold any locks, that task might need.
175 	*/
176
177	taskqueue_drain(taskqueue_fast, &(sc->deferred_intr_callback));
178#endif
179	mtx_lock(sc->sim_lock);
180
181	if (sc->path)
182		xpt_free_path(sc->path);
183	if (sc->sim) {
184		xpt_bus_deregister(cam_sim_path(sc->sim));
185		/* Passing TRUE to cam_sim_free will free the devq as well. */
186		cam_sim_free(sc->sim, TRUE);
187	}
188	/* It's ok have 1 hold count while destroying the mutex */
189	mtx_destroy(sc->sim_lock);
190}
191
192
193
194/*
195 * Function name:	tw_osli_execute_scsi
196 * Description:		Build a fw cmd, based on a CAM style ccb, and
197 *			send it down.
198 *
199 * Input:		req	-- ptr to OSL internal request context
200 *			ccb	-- ptr to CAM style ccb
201 * Output:		None
202 * Return value:	0	-- success
203 *			non-zero-- failure
204 */
205TW_INT32
206tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb)
207{
208	struct twa_softc		*sc = req->ctlr;
209	struct tw_cl_req_packet		*req_pkt;
210	struct tw_cl_scsi_req_packet	*scsi_req;
211	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
212	struct ccb_scsiio		*csio = &(ccb->csio);
213	TW_INT32			error;
214
215	tw_osli_dbg_dprintf(10, sc, "SCSI I/O request 0x%x",
216		csio->cdb_io.cdb_bytes[0]);
217
218	if (ccb_h->target_id >= TW_CL_MAX_NUM_UNITS) {
219		tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %x",
220			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
221		ccb_h->status |= CAM_TID_INVALID;
222		xpt_done(ccb);
223		return(1);
224	}
225	if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
226		tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %x",
227			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
228		ccb_h->status |= CAM_LUN_INVALID;
229		xpt_done(ccb);
230		return(1);
231	}
232
233	if(ccb_h->flags & CAM_CDB_PHYS) {
234		tw_osli_printf(sc, "",
235			TW_CL_SEVERITY_ERROR_STRING,
236			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
237			0x2105,
238			"Physical CDB address!");
239		ccb_h->status = CAM_REQ_CMP_ERR;
240		xpt_done(ccb);
241		return(1);
242	}
243
244	/*
245	 * We are going to work on this request.  Mark it as enqueued (though
246	 * we don't actually queue it...)
247	 */
248	ccb_h->status |= CAM_SIM_QUEUED;
249
250	if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
251		if(ccb_h->flags & CAM_DIR_IN)
252			req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
253		else
254			req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
255	}
256
257	/* Build the CL understood request packet for SCSI cmds. */
258	req_pkt = &req->req_pkt;
259	req_pkt->status = 0;
260	req_pkt->tw_osl_callback = tw_osl_complete_io;
261	scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
262	scsi_req->unit = ccb_h->target_id;
263	scsi_req->lun = ccb_h->target_lun;
264	scsi_req->sense_len = 0;
265	scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
266	scsi_req->scsi_status = 0;
267	if(ccb_h->flags & CAM_CDB_POINTER)
268		scsi_req->cdb = csio->cdb_io.cdb_ptr;
269	else
270		scsi_req->cdb = csio->cdb_io.cdb_bytes;
271	scsi_req->cdb_len = csio->cdb_len;
272
273	if (!(ccb_h->flags & CAM_DATA_PHYS)) {
274		/* Virtual data addresses.  Need to convert them... */
275		tw_osli_dbg_dprintf(3, sc,
276			"XPT_SCSI_IO: Single virtual address!");
277		if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
278			if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
279				tw_osli_printf(sc, "size = %d",
280					TW_CL_SEVERITY_ERROR_STRING,
281					TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
282					0x2106,
283					"I/O size too big",
284					csio->dxfer_len);
285				ccb_h->status = CAM_REQ_TOO_BIG;
286				xpt_done(ccb);
287				return(1);
288			}
289
290			if ((req->length = csio->dxfer_len)) {
291				req->data = csio->data_ptr;
292				scsi_req->sgl_entries = 1;
293			}
294		} else {
295			tw_osli_printf(sc, "",
296				TW_CL_SEVERITY_ERROR_STRING,
297				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
298				0x2107,
299				"XPT_SCSI_IO: Got SGList");
300			ccb_h->status = CAM_REQ_CMP_ERR;
301			xpt_done(ccb);
302			return(1);
303		}
304	} else {
305		/* Data addresses are physical. */
306		tw_osli_printf(sc, "",
307			TW_CL_SEVERITY_ERROR_STRING,
308			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
309			0x2108,
310			"XPT_SCSI_IO: Physical data addresses");
311		ccb_h->status = CAM_REQ_CMP_ERR;
312		ccb_h->status |= CAM_RELEASE_SIMQ;
313		ccb_h->status &= ~CAM_SIM_QUEUED;
314		xpt_done(ccb);
315		return(1);
316	}
317
318	ccb_h->timeout_ch = timeout(twa_timeout, req,
319		(ccb_h->timeout * hz) / 1000);
320	/*
321	 * twa_map_load_data_callback will fill in the SGL,
322	 * and submit the I/O.
323	 */
324	error = tw_osli_map_request(req);
325	return(error);
326}
327
328
329
330/*
331 * Function name:	twa_action
332 * Description:		Driver entry point for CAM's use.
333 *
334 * Input:		sim	-- sim corresponding to the ctlr
335 *			ccb	-- ptr to CAM request
336 * Output:		None
337 * Return value:	None
338 */
339TW_VOID
340twa_action(struct cam_sim *sim, union ccb *ccb)
341{
342	struct twa_softc	*sc = (struct twa_softc *)cam_sim_softc(sim);
343	struct ccb_hdr		*ccb_h = &(ccb->ccb_h);
344
345	switch (ccb_h->func_code) {
346	case XPT_SCSI_IO:	/* SCSI I/O */
347	{
348		struct tw_osli_req_context	*req;
349
350		if ((sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN) ||
351				((req = tw_osli_get_request(sc)) == NULL)) {
352			tw_osli_dbg_dprintf(2, sc,
353				"simq frozen/Cannot get request pkt.");
354			/*
355			 * Freeze the simq to maintain ccb ordering.  The next
356			 * ccb that gets completed will unfreeze the simq.
357			 */
358			tw_osli_disallow_new_requests(sc);
359			ccb_h->status |= CAM_REQUEUE_REQ;
360			xpt_done(ccb);
361			break;
362		}
363		req->req_handle.osl_req_ctxt = req;
364		req->orig_req = ccb;
365		if (tw_osli_execute_scsi(req, ccb))
366			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
367		break;
368	}
369
370	case XPT_ABORT:
371		tw_osli_dbg_dprintf(2, sc, "Abort request.");
372		ccb_h->status = CAM_UA_ABORT;
373		xpt_done(ccb);
374		break;
375
376	case XPT_RESET_BUS:
377		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
378			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
379			0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
380			"Received Reset Bus request from CAM",
381			" ");
382
383		mtx_unlock(sc->sim_lock);
384		if (tw_cl_reset_ctlr(&sc->ctlr_handle)) {
385			tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
386				TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
387				0x2109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
388				"Failed to reset bus",
389				" ");
390			ccb_h->status = CAM_REQ_CMP_ERR;
391		}
392		else
393			ccb_h->status = CAM_REQ_CMP;
394
395		mtx_lock(sc->sim_lock);
396		xpt_done(ccb);
397		break;
398
399	case XPT_SET_TRAN_SETTINGS:
400		tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
401
402		/*
403		 * This command is not supported, since it's very specific
404		 * to SCSI, and we are doing ATA.
405		 */
406  		ccb_h->status = CAM_FUNC_NOTAVAIL;
407  		xpt_done(ccb);
408  		break;
409
410	case XPT_GET_TRAN_SETTINGS:
411	{
412		struct ccb_trans_settings	*cts = &ccb->cts;
413		struct ccb_trans_settings_scsi *scsi =
414		    &cts->proto_specific.scsi;
415		struct ccb_trans_settings_spi *spi =
416		    &cts->xport_specific.spi;
417
418		cts->protocol = PROTO_SCSI;
419		cts->protocol_version = SCSI_REV_2;
420		cts->transport = XPORT_SPI;
421		cts->transport_version = 2;
422
423		spi->valid = CTS_SPI_VALID_DISC;
424		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
425		scsi->valid = CTS_SCSI_VALID_TQ;
426		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
427		tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
428		ccb_h->status = CAM_REQ_CMP;
429		xpt_done(ccb);
430		break;
431	}
432
433	case XPT_CALC_GEOMETRY:
434		tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
435		cam_calc_geometry(&ccb->ccg, 1/* extended */);
436		xpt_done(ccb);
437		break;
438
439	case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
440	{
441		struct ccb_pathinq	*path_inq = &ccb->cpi;
442
443		tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
444
445		path_inq->version_num = 1;
446		path_inq->hba_inquiry = 0;
447		path_inq->target_sprt = 0;
448		path_inq->hba_misc = 0;
449		path_inq->hba_eng_cnt = 0;
450		path_inq->max_target = TW_CL_MAX_NUM_UNITS;
451		path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
452		path_inq->unit_number = cam_sim_unit(sim);
453		path_inq->bus_id = cam_sim_bus(sim);
454		path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
455		path_inq->base_transfer_speed = 100000;
456		strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
457		strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
458		strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
459                path_inq->transport = XPORT_SPI;
460                path_inq->transport_version = 2;
461                path_inq->protocol = PROTO_SCSI;
462                path_inq->protocol_version = SCSI_REV_2;
463		ccb_h->status = CAM_REQ_CMP;
464		xpt_done(ccb);
465		break;
466	}
467
468	default:
469		tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
470		ccb_h->status = CAM_REQ_INVALID;
471		xpt_done(ccb);
472		break;
473	}
474}
475
476
477
478/*
479 * Function name:	twa_poll
480 * Description:		Driver entry point called when interrupts are not
481 *			available.
482 *
483 * Input:		sim	-- sim corresponding to the controller
484 * Output:		None
485 * Return value:	None
486 */
487TW_VOID
488twa_poll(struct cam_sim *sim)
489{
490	struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
491
492	tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
493	/*
494	 * It's been observed that twa_poll can get called (from
495	 * dashutdown --> xpt_polled_action) even when interrupts are
496	 * active, in which case, the ISR might clear the interrupt,
497	 * leaving the call to tw_cl_interrupt below, no way of determining
498	 * that the response from firmware is ready, resulting in
499	 * tw_cl_deferred_interrupt never getting called.  To cover this case,
500	 * we will make the call to tw_cl_deferred_interrupt not dependent
501	 * on the return value from tw_cl_interrupt.
502	 */
503	tw_cl_interrupt(&(sc->ctlr_handle));
504	tw_cl_deferred_interrupt(&(sc->ctlr_handle));
505	tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
506}
507
508
509
510/*
511 * Function name:	twa_timeout
512 * Description:		Driver entry point for being alerted on a request
513 *			timing out.
514 *
515 * Input:		arg	-- ptr to timed out request
516 * Output:		None
517 * Return value:	None
518 */
519static TW_VOID
520twa_timeout(TW_VOID *arg)
521{
522	struct tw_osli_req_context	*req =
523		(struct tw_osli_req_context *)arg;
524
525	tw_cl_create_event(&(req->ctlr->ctlr_handle), TW_CL_TRUE,
526		TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
527		0x210B, 0x1, TW_CL_SEVERITY_ERROR_STRING,
528		"Request timed out!",
529		"request = %p", req);
530	tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
531}
532
533
534
535/*
536 * Function name:	tw_osli_request_bus_scan
537 * Description:		Requests CAM for a scan of the bus.
538 *
539 * Input:		sc	-- ptr to per ctlr structure
540 * Output:		None
541 * Return value:	0	-- success
542 *			non-zero-- failure
543 */
544TW_INT32
545tw_osli_request_bus_scan(struct twa_softc *sc)
546{
547	union ccb	*ccb;
548
549	tw_osli_dbg_dprintf(3, sc, "entering");
550
551	/* If we get here before sc->sim is initialized, return an error. */
552	if (!(sc->sim))
553		return(ENXIO);
554	if ((ccb = xpt_alloc_ccb()) == NULL)
555		return(ENOMEM);
556	mtx_lock(sc->sim_lock);
557	if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sc->sim),
558	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
559		xpt_free_ccb(ccb);
560		mtx_unlock(sc->sim_lock);
561		return(EIO);
562	}
563
564	/* Release simq at the end of a reset */
565	if (sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN) {
566		xpt_release_simq(sc->sim, 1);
567		sc->state &= ~TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
568	}
569
570	xpt_rescan(ccb);
571	mtx_unlock(sc->sim_lock);
572	return(0);
573}
574
575
576
577/*
578 * Function name:	tw_osli_allow_new_requests
579 * Description:		Sets the appropriate status bits in a ccb such that,
580 *			when the ccb is completed by a call to xpt_done,
581 *			CAM knows that it's ok to unfreeze the flow of new
582 *			requests to this controller, if the flow is frozen.
583 *
584 * Input:		sc	-- ptr to OSL internal ctlr context
585 *			ccb	-- ptr to CAM request
586 * Output:		None
587 * Return value:	None
588 */
589TW_VOID
590tw_osli_allow_new_requests(struct twa_softc *sc, TW_VOID *ccb)
591{
592	((union ccb *)(ccb))->ccb_h.status |= CAM_RELEASE_SIMQ;
593	sc->state &= ~TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
594}
595
596
597
598/*
599 * Function name:	tw_osli_disallow_new_requests
600 * Description:		Calls the appropriate CAM function, so as to freeze
601 *			the flow of new requests from CAM to this controller.
602 *
603 * Input:		sc	-- ptr to OSL internal ctlr context
604 * Output:		None
605 * Return value:	None
606 */
607TW_VOID
608tw_osli_disallow_new_requests(struct twa_softc *sc)
609{
610	/* Don't double freeze if already frozen */
611	if ((sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN) == 0) {
612		mtx_lock(sc->sim_lock);
613		xpt_freeze_simq(sc->sim, 1);
614		mtx_unlock(sc->sim_lock);
615		sc->state |= TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
616	}
617}
618
619
620
621/*
622 * Function name:	tw_osl_ctlr_busy
623 * Description:		CL calls this function on cmd queue full or otherwise,
624 *			when it is too busy to accept new requests.
625 *
626 * Input:		ctlr_handle	-- ptr to controller handle
627 *			req_handle	-- ptr to request handle sent by OSL.
628 * Output:		None
629 * Return value:	None
630 */
631TW_VOID
632tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle,
633	struct tw_cl_req_handle *req_handle)
634{
635	tw_osli_disallow_new_requests(ctlr_handle->osl_ctlr_ctxt);
636}
637
638
639
640/*
641 * Function name:	tw_osl_scan_bus
642 * Description:		CL calls this function to request for a bus scan.
643 *
644 * Input:		ctlr_handle	-- ptr to controller handle
645 * Output:		None
646 * Return value:	None
647 */
648TW_VOID
649tw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
650{
651	struct twa_softc	*sc = ctlr_handle->osl_ctlr_ctxt;
652	TW_INT32		error;
653
654	if ((error = tw_osli_request_bus_scan(sc)))
655		tw_osli_printf(sc, "error = %d",
656			TW_CL_SEVERITY_ERROR_STRING,
657			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
658			0x2109,
659			"Bus scan request to CAM failed",
660			error);
661}
662
663
664
665/*
666 * Function name:	tw_osl_complete_io
667 * Description:		Called to complete CAM scsi requests.
668 *
669 * Input:		req_handle	-- ptr to request handle
670 * Output:		None
671 * Return value:	None
672 */
673TW_VOID
674tw_osl_complete_io(struct tw_cl_req_handle *req_handle)
675{
676	struct tw_osli_req_context	*req = req_handle->osl_req_ctxt;
677	struct tw_cl_req_packet		*req_pkt =
678		(struct tw_cl_req_packet *)(&req->req_pkt);
679	struct tw_cl_scsi_req_packet	*scsi_req;
680	struct twa_softc		*sc = req->ctlr;
681	union ccb			*ccb = (union ccb *)(req->orig_req);
682
683	tw_osli_dbg_dprintf(10, sc, "entering");
684
685	if (req->state != TW_OSLI_REQ_STATE_BUSY)
686		tw_osli_printf(sc, "request = %p, status = %d",
687			TW_CL_SEVERITY_ERROR_STRING,
688			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
689			0x210A,
690			"Unposted command completed!!",
691			req, req->state);
692
693	/*
694	 * Remove request from the busy queue.  Just mark it complete.
695	 * There's no need to move it into the complete queue as we are
696	 * going to be done with it right now.
697	 */
698	req->state = TW_OSLI_REQ_STATE_COMPLETE;
699	tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
700
701	tw_osli_unmap_request(req);
702
703	untimeout(twa_timeout, req, ccb->ccb_h.timeout_ch);
704	if (req->error_code) {
705		/* This request never got submitted to the firmware. */
706		if (req->error_code == EBUSY) {
707			/*
708			 * Cmd queue is full, or the Common Layer is out of
709			 * resources.  The simq will already have been frozen
710			 * by CL's call to tw_osl_ctlr_busy, and this will
711			 * maintain ccb ordering.  The next ccb that gets
712			 * completed will unfreeze the simq.
713			 */
714			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
715		}
716		else if (req->error_code == EFBIG)
717			ccb->ccb_h.status = CAM_REQ_TOO_BIG;
718		else
719			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
720	} else {
721		scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
722		if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
723			ccb->ccb_h.status = CAM_REQ_CMP;
724		else {
725			if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
726				ccb->ccb_h.status |= CAM_TID_INVALID;
727			else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
728				ccb->ccb_h.status |= CAM_LUN_INVALID;
729			else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
730				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
731			else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
732				ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
733			/*
734			 * If none of the above errors occurred, simply
735			 * mark completion error.
736			 */
737			if (ccb->ccb_h.status == 0)
738				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
739
740			if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
741				ccb->csio.sense_len = scsi_req->sense_len;
742				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
743			}
744		}
745
746		ccb->csio.scsi_status = scsi_req->scsi_status;
747		/* If simq is frozen, unfreeze it. */
748		if (sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN)
749			tw_osli_allow_new_requests(sc, (TW_VOID *)ccb);
750	}
751
752	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
753	mtx_lock(sc->sim_lock);
754	xpt_done(ccb);
755	mtx_unlock(sc->sim_lock);
756	if (! req->error_code)
757		 /* twa_action will free the request otherwise */
758		tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
759}
760
761