isci_io_request.c revision 234106
1/*-
2 * BSD LICENSE
3 *
4 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *   * Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 *   * Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in
15 *     the documentation and/or other materials provided with the
16 *     distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/isci/isci_io_request.c 234106 2012-04-10 16:33:19Z jimharris $");
33
34#include <dev/isci/isci.h>
35
36#include <cam/scsi/scsi_all.h>
37#include <cam/scsi/scsi_message.h>
38
39#include <dev/isci/scil/intel_sas.h>
40
41#include <dev/isci/scil/sci_util.h>
42
43#include <dev/isci/scil/scif_io_request.h>
44#include <dev/isci/scil/scif_controller.h>
45#include <dev/isci/scil/scif_remote_device.h>
46#include <dev/isci/scil/scif_user_callback.h>
47
48#include <dev/isci/scil/scic_io_request.h>
49#include <dev/isci/scil/scic_user_callback.h>
50
51/**
52 * @brief This user callback will inform the user that an IO request has
53 *        completed.
54 *
55 * @param[in]  controller This parameter specifies the controller on
56 *             which the IO request is completing.
57 * @param[in]  remote_device This parameter specifies the remote device on
58 *             which this request is completing.
59 * @param[in]  io_request This parameter specifies the IO request that has
60 *             completed.
61 * @param[in]  completion_status This parameter specifies the results of
62 *             the IO request operation.  SCI_IO_SUCCESS indicates
63 *             successful completion.
64 *
65 * @return none
66 */
67void
68scif_cb_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
69    SCI_REMOTE_DEVICE_HANDLE_T remote_device,
70    SCI_IO_REQUEST_HANDLE_T io_request, SCI_IO_STATUS completion_status)
71{
72	struct ISCI_IO_REQUEST *isci_request =
73	    (struct ISCI_IO_REQUEST *)sci_object_get_association(io_request);
74
75	scif_controller_complete_io(scif_controller, remote_device, io_request);
76	isci_io_request_complete(scif_controller, remote_device, isci_request,
77	    completion_status);
78}
79
80void
81isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
82    SCI_REMOTE_DEVICE_HANDLE_T remote_device,
83    struct ISCI_IO_REQUEST *isci_request, SCI_IO_STATUS completion_status)
84{
85	struct ISCI_CONTROLLER *isci_controller;
86	struct ISCI_REMOTE_DEVICE *isci_remote_device;
87	union ccb *ccb;
88	BOOL complete_ccb;
89
90	complete_ccb = TRUE;
91	isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller);
92	isci_remote_device =
93		(struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device);
94
95	ccb = isci_request->ccb;
96
97	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
98
99	switch (completion_status) {
100	case SCI_IO_SUCCESS:
101	case SCI_IO_SUCCESS_COMPLETE_BEFORE_START:
102#if __FreeBSD_version >= 900026
103		if (ccb->ccb_h.func_code == XPT_SMP_IO) {
104			void *smp_response =
105			    scif_io_request_get_response_iu_address(
106			        isci_request->sci_object);
107
108			memcpy(ccb->smpio.smp_response, smp_response,
109			    ccb->smpio.smp_response_len);
110		}
111#endif
112		ccb->ccb_h.status |= CAM_REQ_CMP;
113		break;
114
115	case SCI_IO_SUCCESS_IO_DONE_EARLY:
116		ccb->ccb_h.status |= CAM_REQ_CMP;
117		ccb->csio.resid = ccb->csio.dxfer_len -
118		    scif_io_request_get_number_of_bytes_transferred(
119		        isci_request->sci_object);
120		break;
121
122	case SCI_IO_FAILURE_RESPONSE_VALID:
123	{
124		SCI_SSP_RESPONSE_IU_T * response_buffer;
125		uint32_t sense_length;
126		int error_code, sense_key, asc, ascq;
127		struct ccb_scsiio *csio = &ccb->csio;
128
129		response_buffer = (SCI_SSP_RESPONSE_IU_T *)
130		    scif_io_request_get_response_iu_address(
131		        isci_request->sci_object);
132
133		sense_length = sci_ssp_get_sense_data_length(
134		    response_buffer->sense_data_length);
135
136		sense_length = MIN(csio->sense_len, sense_length);
137
138		memcpy(&csio->sense_data, response_buffer->data, sense_length);
139
140		csio->sense_resid = csio->sense_len - sense_length;
141		csio->scsi_status = response_buffer->status;
142		ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
143		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
144		scsi_extract_sense( &csio->sense_data, &error_code, &sense_key,
145		    &asc, &ascq );
146		isci_log_message(1, "ISCI",
147		    "isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n",
148		    ccb->ccb_h.path_id, ccb->ccb_h.target_id,
149		    ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0],
150		    csio->scsi_status, sense_key, asc, ascq);
151		break;
152	}
153
154	case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
155		isci_remote_device_reset(isci_remote_device, NULL);
156
157		/* drop through */
158	case SCI_IO_FAILURE_TERMINATED:
159		ccb->ccb_h.status |= CAM_REQ_TERMIO;
160		isci_log_message(1, "ISCI",
161		    "isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n",
162		    ccb->ccb_h.path_id, ccb->ccb_h.target_id,
163		    ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
164		break;
165
166	case SCI_IO_FAILURE_INVALID_STATE:
167	case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES:
168		complete_ccb = FALSE;
169		break;
170
171	case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE:
172		ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
173		break;
174
175	case SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE:
176		{
177			struct ccb_relsim ccb_relsim;
178			struct cam_path *path;
179
180			xpt_create_path(&path, NULL,
181			    cam_sim_path(isci_controller->sim),
182			    isci_remote_device->index, 0);
183
184			xpt_setup_ccb(&ccb_relsim.ccb_h, path, 5);
185			ccb_relsim.ccb_h.func_code = XPT_REL_SIMQ;
186			ccb_relsim.ccb_h.flags = CAM_DEV_QFREEZE;
187			ccb_relsim.release_flags = RELSIM_ADJUST_OPENINGS;
188			ccb_relsim.openings =
189			    scif_remote_device_get_max_queue_depth(remote_device);
190			xpt_action((union ccb *)&ccb_relsim);
191			xpt_free_path(path);
192			complete_ccb = FALSE;
193		}
194		break;
195
196	case SCI_IO_FAILURE:
197	case SCI_IO_FAILURE_REQUIRES_SCSI_ABORT:
198	case SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL:
199	case SCI_IO_FAILURE_PROTOCOL_VIOLATION:
200	case SCI_IO_FAILURE_INVALID_PARAMETER_VALUE:
201	case SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR:
202	default:
203		isci_log_message(1, "ISCI",
204		    "isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n",
205		    ccb->ccb_h.path_id, ccb->ccb_h.target_id,
206		    ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0],
207		    completion_status);
208		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
209		break;
210	}
211
212	callout_stop(&isci_request->parent.timer);
213	bus_dmamap_sync(isci_request->parent.dma_tag,
214	    isci_request->parent.dma_map,
215	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
216
217	bus_dmamap_unload(isci_request->parent.dma_tag,
218	    isci_request->parent.dma_map);
219
220	isci_request->ccb = NULL;
221
222	sci_pool_put(isci_controller->request_pool,
223	    (struct ISCI_REQUEST *)isci_request);
224
225	if (complete_ccb) {
226		if (ccb->ccb_h.status != CAM_REQ_CMP) {
227			/* ccb will be completed with some type of non-success
228			 *  status.  So temporarily freeze the queue until the
229			 *  upper layers can act on the status.  The
230			 *  CAM_DEV_QFRZN flag will then release the queue
231			 *  after the status is acted upon.
232			 */
233			ccb->ccb_h.status |= CAM_DEV_QFRZN;
234			xpt_freeze_devq(ccb->ccb_h.path, 1);
235		}
236
237		if (isci_remote_device->frozen_lun_mask != 0) {
238			isci_remote_device_release_device_queue(isci_remote_device);
239		}
240
241		xpt_done(ccb);
242
243		if (isci_controller->is_frozen == TRUE) {
244			isci_controller->is_frozen = FALSE;
245			xpt_release_simq(isci_controller->sim, TRUE);
246		}
247	} else {
248		isci_remote_device_freeze_lun_queue(isci_remote_device,
249		    ccb->ccb_h.target_lun);
250
251		isci_log_message(1, "ISCI", "queue %p %x\n", ccb,
252		    ccb->csio.cdb_io.cdb_bytes[0]);
253		ccb->ccb_h.status |= CAM_SIM_QUEUED;
254		TAILQ_INSERT_TAIL(&isci_remote_device->queued_ccbs,
255		    &ccb->ccb_h, sim_links.tqe);
256	}
257}
258
259/**
260 * @brief This callback method asks the user to provide the physical
261 *        address for the supplied virtual address when building an
262 *        io request object.
263 *
264 * @param[in] controller This parameter is the core controller object
265 *            handle.
266 * @param[in] io_request This parameter is the io request object handle
267 *            for which the physical address is being requested.
268 * @param[in] virtual_address This paramter is the virtual address which
269 *            is to be returned as a physical address.
270 * @param[out] physical_address The physical address for the supplied virtual
271 *             address.
272 *
273 * @return None.
274 */
275void
276scic_cb_io_request_get_physical_address(SCI_CONTROLLER_HANDLE_T	controller,
277    SCI_IO_REQUEST_HANDLE_T io_request, void *virtual_address,
278    SCI_PHYSICAL_ADDRESS *physical_address)
279{
280	SCI_IO_REQUEST_HANDLE_T scif_request =
281	    sci_object_get_association(io_request);
282	struct ISCI_REQUEST *isci_request =
283	    sci_object_get_association(scif_request);
284
285	if(isci_request != NULL) {
286		/* isci_request is not NULL, meaning this is a request initiated
287		 *  by CAM or the isci layer (i.e. device reset for I/O
288		 *  timeout).  Therefore we can calculate the physical address
289		 *  based on the address we stored in the struct ISCI_REQUEST
290		 *  object.
291		 */
292		*physical_address = isci_request->physical_address +
293		    (uintptr_t)virtual_address -
294		    (uintptr_t)isci_request;
295	} else {
296		/* isci_request is NULL, meaning this is a request generated
297		 *  internally by SCIL (i.e. for SMP requests or NCQ error
298		 *  recovery).  Therefore we calculate the physical address
299		 *  based on the controller's uncached controller memory buffer,
300		 *  since we know that this is what SCIL uses for internal
301		 *  framework requests.
302		 */
303		SCI_CONTROLLER_HANDLE_T scif_controller =
304		    (SCI_CONTROLLER_HANDLE_T) sci_object_get_association(controller);
305		struct ISCI_CONTROLLER *isci_controller =
306		    (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
307		U64 virt_addr_offset = (uintptr_t)virtual_address -
308		    (U64)isci_controller->uncached_controller_memory.virtual_address;
309
310		*physical_address =
311		    isci_controller->uncached_controller_memory.physical_address
312		    + virt_addr_offset;
313	}
314}
315
316/**
317 * @brief This callback method asks the user to provide the address for
318 *        the command descriptor block (CDB) associated with this IO request.
319 *
320 * @param[in] scif_user_io_request This parameter points to the user's
321 *            IO request object.  It is a cookie that allows the user to
322 *            provide the necessary information for this callback.
323 *
324 * @return This method returns the virtual address of the CDB.
325 */
326void *
327scif_cb_io_request_get_cdb_address(void * scif_user_io_request)
328{
329	struct ISCI_IO_REQUEST *isci_request =
330	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
331
332	return (isci_request->ccb->csio.cdb_io.cdb_bytes);
333}
334
335/**
336 * @brief This callback method asks the user to provide the length of
337 *        the command descriptor block (CDB) associated with this IO request.
338 *
339 * @param[in] scif_user_io_request This parameter points to the user's
340 *            IO request object.  It is a cookie that allows the user to
341 *            provide the necessary information for this callback.
342 *
343 * @return This method returns the length of the CDB.
344 */
345uint32_t
346scif_cb_io_request_get_cdb_length(void * scif_user_io_request)
347{
348	struct ISCI_IO_REQUEST *isci_request =
349	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
350
351	return (isci_request->ccb->csio.cdb_len);
352}
353
354/**
355 * @brief This callback method asks the user to provide the Logical Unit (LUN)
356 *        associated with this IO request.
357 *
358 * @note The contents of the value returned from this callback are defined
359 *       by the protocol standard (e.g. T10 SAS specification).  Please
360 *       refer to the transport command information unit description
361 *       in the associated standard.
362 *
363 * @param[in] scif_user_io_request This parameter points to the user's
364 *            IO request object.  It is a cookie that allows the user to
365 *            provide the necessary information for this callback.
366 *
367 * @return This method returns the LUN associated with this request.
368 */
369uint32_t
370scif_cb_io_request_get_lun(void * scif_user_io_request)
371{
372	struct ISCI_IO_REQUEST *isci_request =
373	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
374
375	return (isci_request->ccb->ccb_h.target_lun);
376}
377
378/**
379 * @brief This callback method asks the user to provide the task attribute
380 *        associated with this IO request.
381 *
382 * @note The contents of the value returned from this callback are defined
383 *       by the protocol standard (e.g. T10 SAS specification).  Please
384 *       refer to the transport command information unit description
385 *       in the associated standard.
386 *
387 * @param[in] scif_user_io_request This parameter points to the user's
388 *            IO request object.  It is a cookie that allows the user to
389 *            provide the necessary information for this callback.
390 *
391 * @return This method returns the task attribute associated with this
392 *         IO request.
393 */
394uint32_t
395scif_cb_io_request_get_task_attribute(void * scif_user_io_request)
396{
397	struct ISCI_IO_REQUEST *isci_request =
398	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
399	uint32_t task_attribute;
400
401	if((isci_request->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
402		switch(isci_request->ccb->csio.tag_action) {
403		case MSG_HEAD_OF_Q_TAG:
404			task_attribute = SCI_SAS_HEAD_OF_QUEUE_ATTRIBUTE;
405			break;
406
407		case MSG_ORDERED_Q_TAG:
408			task_attribute = SCI_SAS_ORDERED_ATTRIBUTE;
409			break;
410
411		case MSG_ACA_TASK:
412			task_attribute = SCI_SAS_ACA_ATTRIBUTE;
413			break;
414
415		default:
416			task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE;
417			break;
418		}
419	else
420		task_attribute = SCI_SAS_SIMPLE_ATTRIBUTE;
421
422	return (task_attribute);
423}
424
425/**
426 * @brief This callback method asks the user to provide the command priority
427 *        associated with this IO request.
428 *
429 * @note The contents of the value returned from this callback are defined
430 *       by the protocol standard (e.g. T10 SAS specification).  Please
431 *       refer to the transport command information unit description
432 *       in the associated standard.
433 *
434 * @param[in] scif_user_io_request This parameter points to the user's
435 *            IO request object.  It is a cookie that allows the user to
436 *            provide the necessary information for this callback.
437 *
438 * @return This method returns the command priority associated with this
439 *         IO request.
440 */
441uint32_t
442scif_cb_io_request_get_command_priority(void * scif_user_io_request)
443{
444	return (0);
445}
446
447/**
448 * @brief This method simply returns the virtual address associated
449 *        with the scsi_io and byte_offset supplied parameters.
450 *
451 * @note This callback is not utilized in the fast path.  The expectation
452 *       is that this method is utilized for items such as SCSI to ATA
453 *       translation for commands like INQUIRY, READ CAPACITY, etc.
454 *
455 * @param[in] scif_user_io_request This parameter points to the user's
456 *            IO request object.  It is a cookie that allows the user to
457 *            provide the necessary information for this callback.
458 * @param[in] byte_offset This parameter specifies the offset into the data
459 *            buffers pointed to by the SGL.  The byte offset starts at 0
460 *            and continues until the last byte pointed to be the last SGL
461 *            element.
462 *
463 * @return A virtual address pointer to the location specified by the
464 *         parameters.
465 */
466uint8_t *
467scif_cb_io_request_get_virtual_address_from_sgl(void * scif_user_io_request,
468    uint32_t byte_offset)
469{
470	struct ISCI_IO_REQUEST *isci_request =
471	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
472
473	return (isci_request->ccb->csio.data_ptr + byte_offset);
474}
475
476/**
477 * @brief This callback method asks the user to provide the number of
478 *        bytes to be transfered as part of this request.
479 *
480 * @param[in] scif_user_io_request This parameter points to the user's
481 *            IO request object.  It is a cookie that allows the user to
482 *            provide the necessary information for this callback.
483 *
484 * @return This method returns the number of payload data bytes to be
485 *         transfered for this IO request.
486 */
487uint32_t
488scif_cb_io_request_get_transfer_length(void * scif_user_io_request)
489{
490	struct ISCI_IO_REQUEST *isci_request =
491	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
492
493	return (isci_request->ccb->csio.dxfer_len);
494
495}
496
497/**
498 * @brief This callback method asks the user to provide the data direction
499 *        for this request.
500 *
501 * @param[in] scif_user_io_request This parameter points to the user's
502 *            IO request object.  It is a cookie that allows the user to
503 *            provide the necessary information for this callback.
504 *
505 * @return This method returns the value of SCI_IO_REQUEST_DATA_OUT,
506 *         SCI_IO_REQUEST_DATA_IN, or SCI_IO_REQUEST_NO_DATA.
507 */
508SCI_IO_REQUEST_DATA_DIRECTION
509scif_cb_io_request_get_data_direction(void * scif_user_io_request)
510{
511	struct ISCI_IO_REQUEST *isci_request =
512	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
513
514	switch (isci_request->ccb->ccb_h.flags & CAM_DIR_MASK) {
515	case CAM_DIR_IN:
516		return (SCI_IO_REQUEST_DATA_IN);
517	case CAM_DIR_OUT:
518		return (SCI_IO_REQUEST_DATA_OUT);
519	default:
520		return (SCI_IO_REQUEST_NO_DATA);
521	}
522}
523
524/**
525 * @brief This callback method asks the user to provide the address
526 *        to where the next Scatter-Gather Element is located.
527 *
528 * Details regarding usage:
529 *   - Regarding the first SGE: the user should initialize an index,
530 *     or a pointer, prior to construction of the request that will
531 *     reference the very first scatter-gather element.  This is
532 *     important since this method is called for every scatter-gather
533 *     element, including the first element.
534 *   - Regarding the last SGE: the user should return NULL from this
535 *     method when this method is called and the SGL has exhausted
536 *     all elements.
537 *
538 * @param[in] scif_user_io_request This parameter points to the user's
539 *            IO request object.  It is a cookie that allows the user to
540 *            provide the necessary information for this callback.
541 * @param[in] current_sge_address This parameter specifies the address for
542 *            the current SGE (i.e. the one that has just processed).
543 * @param[out] next_sge An address specifying the location for the next scatter
544 *             gather element to be processed.
545 *
546 * @return None.
547 */
548void
549scif_cb_io_request_get_next_sge(void * scif_user_io_request,
550    void * current_sge_address, void ** next_sge)
551{
552	struct ISCI_IO_REQUEST *isci_request =
553	    (struct ISCI_IO_REQUEST *)scif_user_io_request;
554
555	if (isci_request->current_sge_index == isci_request->num_segments)
556		*next_sge = NULL;
557	else {
558		bus_dma_segment_t *sge =
559		    &isci_request->sge[isci_request->current_sge_index];
560
561		isci_request->current_sge_index++;
562		*next_sge = sge;
563	}
564}
565
566/**
567 * @brief This callback method asks the user to provide the contents of the
568 *        "address" field in the Scatter-Gather Element.
569 *
570 * @param[in] scif_user_io_request This parameter points to the user's
571 *            IO request object.  It is a cookie that allows the user to
572 *            provide the necessary information for this callback.
573 * @param[in] sge_address This parameter specifies the address for the
574 *            SGE from which to retrieve the address field.
575 *
576 * @return A physical address specifying the contents of the SGE's address
577 *         field.
578 */
579SCI_PHYSICAL_ADDRESS
580scif_cb_sge_get_address_field(void *scif_user_io_request, void *sge_address)
581{
582	bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address;
583
584	return ((SCI_PHYSICAL_ADDRESS)sge->ds_addr);
585}
586
587/**
588 * @brief This callback method asks the user to provide the contents of the
589 *        "length" field in the Scatter-Gather Element.
590 *
591 * @param[in] scif_user_io_request This parameter points to the user's
592 *            IO request object.  It is a cookie that allows the user to
593 *            provide the necessary information for this callback.
594 * @param[in] sge_address This parameter specifies the address for the
595 *            SGE from which to retrieve the address field.
596 *
597 * @return This method returns the length field specified inside the SGE
598 *         referenced by the sge_address parameter.
599 */
600uint32_t
601scif_cb_sge_get_length_field(void *scif_user_io_request, void *sge_address)
602{
603	bus_dma_segment_t *sge = (bus_dma_segment_t *)sge_address;
604
605	return ((uint32_t)sge->ds_len);
606}
607
608void
609isci_request_construct(struct ISCI_REQUEST *request,
610    SCI_CONTROLLER_HANDLE_T scif_controller_handle,
611    bus_dma_tag_t io_buffer_dma_tag, bus_addr_t physical_address)
612{
613
614	request->controller_handle = scif_controller_handle;
615	request->dma_tag = io_buffer_dma_tag;
616	request->physical_address = physical_address;
617	bus_dmamap_create(request->dma_tag, 0, &request->dma_map);
618	callout_init(&request->timer, CALLOUT_MPSAFE);
619}
620
621static void
622isci_io_request_construct(void *arg, bus_dma_segment_t *seg, int nseg,
623    int error)
624{
625	union ccb *ccb;
626	struct ISCI_IO_REQUEST *io_request = (struct ISCI_IO_REQUEST *)arg;
627	SCI_REMOTE_DEVICE_HANDLE_T *device = io_request->parent.remote_device_handle;
628	SCI_STATUS status;
629
630	io_request->num_segments = nseg;
631	io_request->sge = seg;
632	ccb = io_request->ccb;
633
634	/* XXX More cleanup is needed here */
635	if ((nseg == 0) || (error != 0)) {
636		ccb->ccb_h.status = CAM_REQ_INVALID;
637		xpt_done(ccb);
638		return;
639	}
640
641	status = scif_io_request_construct(
642	    io_request->parent.controller_handle,
643	    io_request->parent.remote_device_handle,
644	    SCI_CONTROLLER_INVALID_IO_TAG, (void *)io_request,
645	    (void *)((char*)io_request + sizeof(struct ISCI_IO_REQUEST)),
646	    &io_request->sci_object);
647
648	if (status != SCI_SUCCESS) {
649		isci_io_request_complete(io_request->parent.controller_handle,
650		    device, io_request, (SCI_IO_STATUS)status);
651		return;
652	}
653
654	sci_object_set_association(io_request->sci_object, io_request);
655
656	bus_dmamap_sync(io_request->parent.dma_tag, io_request->parent.dma_map,
657	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
658
659	status = (SCI_STATUS)scif_controller_start_io(
660	    io_request->parent.controller_handle, device,
661	    io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
662
663	if (status != SCI_SUCCESS) {
664		isci_io_request_complete(io_request->parent.controller_handle,
665		    device, io_request, (SCI_IO_STATUS)status);
666		return;
667	}
668
669	if (ccb->ccb_h.timeout != CAM_TIME_INFINITY)
670		callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout,
671		    isci_io_request_timeout, io_request);
672}
673
674void
675isci_io_request_execute_scsi_io(union ccb *ccb,
676    struct ISCI_CONTROLLER *controller)
677{
678	struct ccb_scsiio *csio = &ccb->csio;
679	target_id_t target_id = ccb->ccb_h.target_id;
680	struct ISCI_REQUEST *request;
681	struct ISCI_IO_REQUEST *io_request;
682	struct ISCI_REMOTE_DEVICE *device =
683	    controller->remote_device[target_id];
684	int error;
685
686	if (device == NULL) {
687		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
688		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
689		ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
690		xpt_done(ccb);
691		return;
692	}
693
694	if (sci_pool_empty(controller->request_pool)) {
695		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
696		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
697		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
698		xpt_freeze_simq(controller->sim, 1);
699		controller->is_frozen = TRUE;
700		xpt_done(ccb);
701		return;
702	}
703
704	ASSERT(device->is_resetting == FALSE);
705
706	sci_pool_get(controller->request_pool, request);
707	io_request = (struct ISCI_IO_REQUEST *)request;
708
709	io_request->ccb = ccb;
710	io_request->current_sge_index = 0;
711	io_request->parent.remote_device_handle = device->sci_object;
712
713	if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) != 0)
714		panic("Unexpected CAM_SCATTER_VALID flag!  flags = 0x%x\n",
715		    ccb->ccb_h.flags);
716
717	if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
718		panic("Unexpected CAM_DATA_PHYS flag!  flags = 0x%x\n",
719		    ccb->ccb_h.flags);
720
721	error = bus_dmamap_load(io_request->parent.dma_tag,
722	    io_request->parent.dma_map, csio->data_ptr, csio->dxfer_len,
723	    isci_io_request_construct, io_request, 0x0);
724
725	/* A resource shortage from BUSDMA will be automatically
726	 * continued at a later point, pushing the CCB processing
727	 * forward, which will in turn unfreeze the simq.
728	 */
729	if (error == EINPROGRESS) {
730		xpt_freeze_simq(controller->sim, 1);
731		ccb->ccb_h.flags |= CAM_RELEASE_SIMQ;
732	}
733}
734
735void
736isci_io_request_timeout(void *arg)
737{
738	struct ISCI_IO_REQUEST *request = (struct ISCI_IO_REQUEST *)arg;
739	struct ISCI_REMOTE_DEVICE *remote_device = (struct ISCI_REMOTE_DEVICE *)
740		sci_object_get_association(request->parent.remote_device_handle);
741	struct ISCI_CONTROLLER *controller = remote_device->domain->controller;
742
743	mtx_lock(&controller->lock);
744	isci_remote_device_reset(remote_device, NULL);
745	mtx_unlock(&controller->lock);
746}
747
748#if __FreeBSD_version >= 900026
749/**
750 * @brief This callback method gets the size of and pointer to the buffer
751 *         (if any) containing the request buffer for an SMP request.
752 *
753 * @param[in]  core_request This parameter specifies the SCI core's request
754 *             object associated with the SMP request.
755 * @param[out] smp_request_buffer This parameter returns a pointer to the
756 *             payload portion of the SMP request - i.e. everything after
757 *             the SMP request header.
758 *
759 * @return Size of the request buffer in bytes.  This does *not* include
760 *          the size of the SMP request header.
761 */
762static uint32_t
763smp_io_request_cb_get_request_buffer(SCI_IO_REQUEST_HANDLE_T core_request,
764    uint8_t ** smp_request_buffer)
765{
766	struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
767	    sci_object_get_association(sci_object_get_association(core_request));
768
769	*smp_request_buffer = isci_request->ccb->smpio.smp_request +
770	    sizeof(SMP_REQUEST_HEADER_T);
771
772	return (isci_request->ccb->smpio.smp_request_len -
773	    sizeof(SMP_REQUEST_HEADER_T));
774}
775
776/**
777 * @brief This callback method gets the SMP function for an SMP request.
778 *
779 * @param[in]  core_request This parameter specifies the SCI core's request
780 *             object associated with the SMP request.
781 *
782 * @return SMP function for the SMP request.
783 */
784static uint8_t
785smp_io_request_cb_get_function(SCI_IO_REQUEST_HANDLE_T core_request)
786{
787	struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
788	    sci_object_get_association(sci_object_get_association(core_request));
789	SMP_REQUEST_HEADER_T *header =
790	    (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
791
792	return (header->function);
793}
794
795/**
796 * @brief This callback method gets the SMP frame type for an SMP request.
797 *
798 * @param[in]  core_request This parameter specifies the SCI core's request
799 *             object associated with the SMP request.
800 *
801 * @return SMP frame type for the SMP request.
802 */
803static uint8_t
804smp_io_request_cb_get_frame_type(SCI_IO_REQUEST_HANDLE_T core_request)
805{
806	struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
807	    sci_object_get_association(sci_object_get_association(core_request));
808	SMP_REQUEST_HEADER_T *header =
809	    (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
810
811	return (header->smp_frame_type);
812}
813
814/**
815 * @brief This callback method gets the allocated response length for an SMP request.
816 *
817 * @param[in]  core_request This parameter specifies the SCI core's request
818 *             object associated with the SMP request.
819 *
820 * @return Allocated response length for the SMP request.
821 */
822static uint8_t
823smp_io_request_cb_get_allocated_response_length(
824    SCI_IO_REQUEST_HANDLE_T core_request)
825{
826	struct ISCI_IO_REQUEST *isci_request = (struct ISCI_IO_REQUEST *)
827	    sci_object_get_association(sci_object_get_association(core_request));
828	SMP_REQUEST_HEADER_T *header =
829	    (SMP_REQUEST_HEADER_T *)isci_request->ccb->smpio.smp_request;
830
831	return (header->allocated_response_length);
832}
833
834static SCI_STATUS
835isci_smp_request_construct(struct ISCI_IO_REQUEST *request)
836{
837	SCI_STATUS status;
838	SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T callbacks;
839
840	status = scif_request_construct(request->parent.controller_handle,
841	    request->parent.remote_device_handle, SCI_CONTROLLER_INVALID_IO_TAG,
842	    (void *)request,
843	    (void *)((char*)request + sizeof(struct ISCI_IO_REQUEST)),
844	    &request->sci_object);
845
846	if (status == SCI_SUCCESS) {
847		callbacks.scic_cb_smp_passthru_get_request =
848		    &smp_io_request_cb_get_request_buffer;
849		callbacks.scic_cb_smp_passthru_get_function =
850		    &smp_io_request_cb_get_function;
851		callbacks.scic_cb_smp_passthru_get_frame_type =
852		    &smp_io_request_cb_get_frame_type;
853		callbacks.scic_cb_smp_passthru_get_allocated_response_length =
854		    &smp_io_request_cb_get_allocated_response_length;
855
856		/* create the smp passthrough part of the io request */
857		status = scic_io_request_construct_smp_pass_through(
858		    scif_io_request_get_scic_handle(request->sci_object),
859		    &callbacks);
860	}
861
862	return (status);
863}
864
865void
866isci_io_request_execute_smp_io(union ccb *ccb,
867    struct ISCI_CONTROLLER *controller)
868{
869	SCI_STATUS status;
870	target_id_t target_id = ccb->ccb_h.target_id;
871	struct ISCI_REQUEST *request;
872	struct ISCI_IO_REQUEST *io_request;
873	SCI_REMOTE_DEVICE_HANDLE_T smp_device_handle;
874	struct ISCI_REMOTE_DEVICE *end_device = controller->remote_device[target_id];
875
876	/* SMP commands are sent to an end device, because SMP devices are not
877	 *  exposed to the kernel.  It is our responsibility to use this method
878	 *  to get the SMP device that contains the specified end device.  If
879	 *  the device is direct-attached, the handle will come back NULL, and
880	 *  we'll just fail the SMP_IO with DEV_NOT_THERE.
881	 */
882	scif_remote_device_get_containing_device(end_device->sci_object,
883	    &smp_device_handle);
884
885	if (smp_device_handle == NULL) {
886		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
887		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
888		ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
889		xpt_done(ccb);
890		return;
891	}
892
893	if (sci_pool_empty(controller->request_pool)) {
894		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
895		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
896		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
897		xpt_freeze_simq(controller->sim, 1);
898		controller->is_frozen = TRUE;
899		xpt_done(ccb);
900		return;
901	}
902
903	ASSERT(device->is_resetting == FALSE);
904
905	sci_pool_get(controller->request_pool, request);
906	io_request = (struct ISCI_IO_REQUEST *)request;
907
908	io_request->ccb = ccb;
909	io_request->parent.remote_device_handle = smp_device_handle;
910
911	status = isci_smp_request_construct(io_request);
912
913	if (status != SCI_SUCCESS) {
914		isci_io_request_complete(controller->scif_controller_handle,
915		    smp_device_handle, io_request, (SCI_IO_STATUS)status);
916		return;
917	}
918
919	sci_object_set_association(io_request->sci_object, io_request);
920
921	status = (SCI_STATUS) scif_controller_start_io(
922	    controller->scif_controller_handle, smp_device_handle,
923	    io_request->sci_object, SCI_CONTROLLER_INVALID_IO_TAG);
924
925	if (status != SCI_SUCCESS) {
926		isci_io_request_complete(controller->scif_controller_handle,
927		    smp_device_handle, io_request, (SCI_IO_STATUS)status);
928		return;
929	}
930
931	if (ccb->ccb_h.timeout != CAM_TIME_INFINITY)
932		callout_reset(&io_request->parent.timer, ccb->ccb_h.timeout,
933		    isci_io_request_timeout, request);
934}
935#endif
936