xref: /freebsd/sys/dev/smartpqi/smartpqi_cam.c (revision 7000d321e8619f9a2962e4a011d2c3d86307e852)
11e66f787SSean Bruno /*-
21e66f787SSean Bruno  * Copyright (c) 2018 Microsemi Corporation.
31e66f787SSean Bruno  * All rights reserved.
41e66f787SSean Bruno  *
51e66f787SSean Bruno  * Redistribution and use in source and binary forms, with or without
61e66f787SSean Bruno  * modification, are permitted provided that the following conditions
71e66f787SSean Bruno  * are met:
81e66f787SSean Bruno  * 1. Redistributions of source code must retain the above copyright
91e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer.
101e66f787SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
111e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
121e66f787SSean Bruno  *    documentation and/or other materials provided with the distribution.
131e66f787SSean Bruno  *
141e66f787SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151e66f787SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161e66f787SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171e66f787SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181e66f787SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191e66f787SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201e66f787SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211e66f787SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221e66f787SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231e66f787SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241e66f787SSean Bruno  * SUCH DAMAGE.
251e66f787SSean Bruno  */
261e66f787SSean Bruno 
271e66f787SSean Bruno /* $FreeBSD$ */
281e66f787SSean Bruno /*
291e66f787SSean Bruno  * CAM interface for smartpqi driver
301e66f787SSean Bruno  */
311e66f787SSean Bruno 
321e66f787SSean Bruno #include "smartpqi_includes.h"
331e66f787SSean Bruno 
341e66f787SSean Bruno /*
351e66f787SSean Bruno  * Set cam sim properties of the smartpqi adapter.
361e66f787SSean Bruno  */
371e66f787SSean Bruno static void update_sim_properties(struct cam_sim *sim, struct ccb_pathinq *cpi)
381e66f787SSean Bruno {
391e66f787SSean Bruno 
401e66f787SSean Bruno 	pqisrc_softstate_t *softs = (struct pqisrc_softstate *)
411e66f787SSean Bruno 					cam_sim_softc(sim);
421e66f787SSean Bruno 	DBG_FUNC("IN\n");
431e66f787SSean Bruno 
441e66f787SSean Bruno 	cpi->version_num = 1;
451e66f787SSean Bruno 	cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
461e66f787SSean Bruno 	cpi->target_sprt = 0;
471e66f787SSean Bruno 	cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
481e66f787SSean Bruno 	cpi->hba_eng_cnt = 0;
491e66f787SSean Bruno 	cpi->max_lun = PQI_MAX_MULTILUN;
501e66f787SSean Bruno 	cpi->max_target = 1088;
511e66f787SSean Bruno 	cpi->maxio = (softs->pqi_cap.max_sg_elem - 1) * PAGE_SIZE;
521e66f787SSean Bruno 	cpi->initiator_id = 255;
531e66f787SSean Bruno 	strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
541e66f787SSean Bruno 	strncpy(cpi->hba_vid, "Microsemi", HBA_IDLEN);
551e66f787SSean Bruno 	strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
561e66f787SSean Bruno 	cpi->unit_number = cam_sim_unit(sim);
571e66f787SSean Bruno 	cpi->bus_id = cam_sim_bus(sim);
581e66f787SSean Bruno 	cpi->base_transfer_speed = 1200000; /* Base bus speed in KB/sec */
591e66f787SSean Bruno 	cpi->protocol = PROTO_SCSI;
601e66f787SSean Bruno 	cpi->protocol_version = SCSI_REV_SPC4;
611e66f787SSean Bruno 	cpi->transport = XPORT_SPI;
621e66f787SSean Bruno 	cpi->transport_version = 2;
631e66f787SSean Bruno 	cpi->ccb_h.status = CAM_REQ_CMP;
641e66f787SSean Bruno 
651e66f787SSean Bruno 	DBG_FUNC("OUT\n");
661e66f787SSean Bruno }
671e66f787SSean Bruno 
681e66f787SSean Bruno /*
691e66f787SSean Bruno  * Get transport settings of the smartpqi adapter
701e66f787SSean Bruno  */
711e66f787SSean Bruno static void get_transport_settings(struct pqisrc_softstate *softs,
721e66f787SSean Bruno 		struct ccb_trans_settings *cts)
731e66f787SSean Bruno {
741e66f787SSean Bruno 	struct ccb_trans_settings_scsi	*scsi = &cts->proto_specific.scsi;
751e66f787SSean Bruno 	struct ccb_trans_settings_sas	*sas = &cts->xport_specific.sas;
761e66f787SSean Bruno 	struct ccb_trans_settings_spi	*spi = &cts->xport_specific.spi;
771e66f787SSean Bruno 
781e66f787SSean Bruno 	DBG_FUNC("IN\n");
791e66f787SSean Bruno 
801e66f787SSean Bruno 	cts->protocol = PROTO_SCSI;
811e66f787SSean Bruno 	cts->protocol_version = SCSI_REV_SPC4;
821e66f787SSean Bruno 	cts->transport = XPORT_SPI;
831e66f787SSean Bruno 	cts->transport_version = 2;
841e66f787SSean Bruno 	spi->valid = CTS_SPI_VALID_DISC;
851e66f787SSean Bruno 	spi->flags = CTS_SPI_FLAGS_DISC_ENB;
861e66f787SSean Bruno 	scsi->valid = CTS_SCSI_VALID_TQ;
871e66f787SSean Bruno 	scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
881e66f787SSean Bruno 	sas->valid = CTS_SAS_VALID_SPEED;
891e66f787SSean Bruno 	cts->ccb_h.status = CAM_REQ_CMP;
901e66f787SSean Bruno 
911e66f787SSean Bruno 	DBG_FUNC("OUT\n");
921e66f787SSean Bruno }
931e66f787SSean Bruno 
941e66f787SSean Bruno /*
951e66f787SSean Bruno  *  Add the target to CAM layer and rescan, when a new device is found
961e66f787SSean Bruno  */
971e66f787SSean Bruno void os_add_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) {
981e66f787SSean Bruno 	union ccb			*ccb;
991e66f787SSean Bruno 
1001e66f787SSean Bruno 	DBG_FUNC("IN\n");
1011e66f787SSean Bruno 
1021e66f787SSean Bruno 	if(softs->os_specific.sim_registered) {
1031e66f787SSean Bruno 		if ((ccb = xpt_alloc_ccb_nowait()) == NULL) {
1041e66f787SSean Bruno 			DBG_ERR("rescan failed (can't allocate CCB)\n");
1051e66f787SSean Bruno 			return;
1061e66f787SSean Bruno 		}
1071e66f787SSean Bruno 
1081e66f787SSean Bruno 		if (xpt_create_path(&ccb->ccb_h.path, NULL,
1091e66f787SSean Bruno 			cam_sim_path(softs->os_specific.sim),
1101e66f787SSean Bruno 			device->target, device->lun) != CAM_REQ_CMP) {
1111e66f787SSean Bruno 			DBG_ERR("rescan failed (can't create path)\n");
1121e66f787SSean Bruno 			xpt_free_ccb(ccb);
1131e66f787SSean Bruno 			return;
1141e66f787SSean Bruno 		}
1151e66f787SSean Bruno 		xpt_rescan(ccb);
1161e66f787SSean Bruno 	}
1171e66f787SSean Bruno 
1181e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1191e66f787SSean Bruno }
1201e66f787SSean Bruno 
1211e66f787SSean Bruno /*
1221e66f787SSean Bruno  * Remove the device from CAM layer when deleted or hot removed
1231e66f787SSean Bruno  */
1241e66f787SSean Bruno void os_remove_device(pqisrc_softstate_t *softs,
1251e66f787SSean Bruno         pqi_scsi_dev_t *device) {
1261e66f787SSean Bruno 	struct cam_path *tmppath;
1271e66f787SSean Bruno 
1281e66f787SSean Bruno 	DBG_FUNC("IN\n");
1291e66f787SSean Bruno 
1301e66f787SSean Bruno 	if(softs->os_specific.sim_registered) {
1311e66f787SSean Bruno 		if (xpt_create_path(&tmppath, NULL,
1321e66f787SSean Bruno 			cam_sim_path(softs->os_specific.sim),
1331e66f787SSean Bruno 			device->target, device->lun) != CAM_REQ_CMP) {
1341e66f787SSean Bruno 			DBG_ERR("unable to create path for async event");
1351e66f787SSean Bruno 			return;
1361e66f787SSean Bruno 		}
1371e66f787SSean Bruno 		xpt_async(AC_LOST_DEVICE, tmppath, NULL);
1381e66f787SSean Bruno 		xpt_free_path(tmppath);
1391e66f787SSean Bruno 		pqisrc_free_device(softs, device);
1401e66f787SSean Bruno 	}
1411e66f787SSean Bruno 
1421e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1431e66f787SSean Bruno 
1441e66f787SSean Bruno }
1451e66f787SSean Bruno 
1461e66f787SSean Bruno /*
1471e66f787SSean Bruno  * Function to release the frozen simq
1481e66f787SSean Bruno  */
1491e66f787SSean Bruno static void pqi_release_camq( rcb_t *rcb )
1501e66f787SSean Bruno {
1511e66f787SSean Bruno 	pqisrc_softstate_t *softs;
1521e66f787SSean Bruno 	struct ccb_scsiio *csio;
1531e66f787SSean Bruno 
1541e66f787SSean Bruno 	csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
1551e66f787SSean Bruno 	softs = rcb->softs;
1561e66f787SSean Bruno 
1571e66f787SSean Bruno 	DBG_FUNC("IN\n");
1581e66f787SSean Bruno 
1591e66f787SSean Bruno 	if (softs->os_specific.pqi_flags & PQI_FLAG_BUSY) {
1601e66f787SSean Bruno 		softs->os_specific.pqi_flags &= ~PQI_FLAG_BUSY;
1611e66f787SSean Bruno 		if (csio->ccb_h.status & CAM_RELEASE_SIMQ)
1621e66f787SSean Bruno 			xpt_release_simq(xpt_path_sim(csio->ccb_h.path), 0);
1631e66f787SSean Bruno 		else
1641e66f787SSean Bruno 			csio->ccb_h.status |= CAM_RELEASE_SIMQ;
1651e66f787SSean Bruno 	}
1661e66f787SSean Bruno 
1671e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1681e66f787SSean Bruno }
1691e66f787SSean Bruno 
1701e66f787SSean Bruno /*
1711e66f787SSean Bruno  * Function to dma-unmap the completed request
1721e66f787SSean Bruno  */
1731e66f787SSean Bruno static void pqi_unmap_request(void *arg)
1741e66f787SSean Bruno {
1751e66f787SSean Bruno 	pqisrc_softstate_t *softs;
1761e66f787SSean Bruno 	rcb_t *rcb;
1771e66f787SSean Bruno 
1781e66f787SSean Bruno 	DBG_IO("IN rcb = %p\n", arg);
1791e66f787SSean Bruno 
1801e66f787SSean Bruno 	rcb = (rcb_t *)arg;
1811e66f787SSean Bruno 	softs = rcb->softs;
1821e66f787SSean Bruno 
1831e66f787SSean Bruno 	if (!(rcb->cm_flags & PQI_CMD_MAPPED))
1841e66f787SSean Bruno 		return;
1851e66f787SSean Bruno 
1861e66f787SSean Bruno 	if (rcb->bcount != 0 ) {
1871e66f787SSean Bruno 		if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE)
1881e66f787SSean Bruno 			bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
1891e66f787SSean Bruno 					rcb->cm_datamap,
1901e66f787SSean Bruno 					BUS_DMASYNC_POSTREAD);
1911e66f787SSean Bruno 		if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE)
1921e66f787SSean Bruno 			bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
1931e66f787SSean Bruno 					rcb->cm_datamap,
1941e66f787SSean Bruno 					BUS_DMASYNC_POSTWRITE);
1951e66f787SSean Bruno 		bus_dmamap_unload(softs->os_specific.pqi_buffer_dmat,
1961e66f787SSean Bruno 					rcb->cm_datamap);
1971e66f787SSean Bruno 	}
1981e66f787SSean Bruno 	rcb->cm_flags &= ~PQI_CMD_MAPPED;
1991e66f787SSean Bruno 
2001e66f787SSean Bruno 	if(rcb->sgt && rcb->nseg)
2011e66f787SSean Bruno 		os_mem_free(rcb->softs, (void*)rcb->sgt,
2021e66f787SSean Bruno 			rcb->nseg*sizeof(sgt_t));
2031e66f787SSean Bruno 
2041e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, rcb->tag);
2051e66f787SSean Bruno 
2061e66f787SSean Bruno 	DBG_IO("OUT\n");
2071e66f787SSean Bruno }
2081e66f787SSean Bruno 
2091e66f787SSean Bruno /*
2101e66f787SSean Bruno  * Construct meaningful LD name for volume here.
2111e66f787SSean Bruno  */
2121e66f787SSean Bruno static void
2131e66f787SSean Bruno smartpqi_fix_ld_inquiry(pqisrc_softstate_t *softs, struct ccb_scsiio *csio)
2141e66f787SSean Bruno {
2151e66f787SSean Bruno 	struct scsi_inquiry_data *inq = NULL;
2161e66f787SSean Bruno 	uint8_t *cdb = NULL;
2171e66f787SSean Bruno 	pqi_scsi_dev_t *device = NULL;
2181e66f787SSean Bruno 
2191e66f787SSean Bruno 	DBG_FUNC("IN\n");
2201e66f787SSean Bruno 
2211e66f787SSean Bruno  	cdb = (csio->ccb_h.flags & CAM_CDB_POINTER) ?
2221e66f787SSean Bruno 		(uint8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes;
2231e66f787SSean Bruno 	if(cdb[0] == INQUIRY &&
2241e66f787SSean Bruno 		(cdb[1] & SI_EVPD) == 0 &&
2251e66f787SSean Bruno 		(csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
2261e66f787SSean Bruno 		csio->dxfer_len >= SHORT_INQUIRY_LENGTH) {
2271e66f787SSean Bruno 
2281e66f787SSean Bruno 		inq = (struct scsi_inquiry_data *)csio->data_ptr;
2291e66f787SSean Bruno 
2301e66f787SSean Bruno 		device = softs->device_list[csio->ccb_h.target_id][csio->ccb_h.target_lun];
2311e66f787SSean Bruno 
2321e66f787SSean Bruno 		/* Let the disks be probed and dealt with via CAM. Only for LD
2331e66f787SSean Bruno 		  let it fall through and inquiry be tweaked */
2341e66f787SSean Bruno 		if( !device || 	!pqisrc_is_logical_device(device) ||
2351e66f787SSean Bruno 				(device->devtype != DISK_DEVICE)  ||
2361e66f787SSean Bruno 				pqisrc_is_external_raid_device(device)) {
2371e66f787SSean Bruno  	 		return;
2381e66f787SSean Bruno 		}
2391e66f787SSean Bruno 
2401e66f787SSean Bruno 		strncpy(inq->vendor, "MSCC",
2411e66f787SSean Bruno        			SID_VENDOR_SIZE);
2421e66f787SSean Bruno 		strncpy(inq->product,
2431e66f787SSean Bruno 			pqisrc_raidlevel_to_string(device->raid_level),
2441e66f787SSean Bruno        			SID_PRODUCT_SIZE);
2451e66f787SSean Bruno 		strncpy(inq->revision, device->volume_offline?"OFF":"OK",
2461e66f787SSean Bruno        			SID_REVISION_SIZE);
2471e66f787SSean Bruno     	}
2481e66f787SSean Bruno 
2491e66f787SSean Bruno 	DBG_FUNC("OUT\n");
2501e66f787SSean Bruno }
2511e66f787SSean Bruno 
2521e66f787SSean Bruno /*
2531e66f787SSean Bruno  * Handle completion of a command - pass results back through the CCB
2541e66f787SSean Bruno  */
2551e66f787SSean Bruno void
2561e66f787SSean Bruno os_io_response_success(rcb_t *rcb)
2571e66f787SSean Bruno {
2581e66f787SSean Bruno 	struct ccb_scsiio		*csio;
2591e66f787SSean Bruno 
2601e66f787SSean Bruno 	DBG_IO("IN rcb = %p\n", rcb);
2611e66f787SSean Bruno 
2621e66f787SSean Bruno 	if (rcb == NULL)
2631e66f787SSean Bruno 		panic("rcb is null");
2641e66f787SSean Bruno 
2651e66f787SSean Bruno 	csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
2661e66f787SSean Bruno 
2671e66f787SSean Bruno 	if (csio == NULL)
2681e66f787SSean Bruno 		panic("csio is null");
2691e66f787SSean Bruno 
2701e66f787SSean Bruno 	rcb->status = REQUEST_SUCCESS;
2711e66f787SSean Bruno 	csio->ccb_h.status = CAM_REQ_CMP;
2721e66f787SSean Bruno 
2731e66f787SSean Bruno 	smartpqi_fix_ld_inquiry(rcb->softs, csio);
2741e66f787SSean Bruno 	pqi_release_camq(rcb);
2751e66f787SSean Bruno 	pqi_unmap_request(rcb);
2761e66f787SSean Bruno 	xpt_done((union ccb *)csio);
2771e66f787SSean Bruno 
2781e66f787SSean Bruno 	DBG_IO("OUT\n");
2791e66f787SSean Bruno }
2801e66f787SSean Bruno 
2811e66f787SSean Bruno /*
2821e66f787SSean Bruno  * Error response handling for raid IO
2831e66f787SSean Bruno  */
2841e66f787SSean Bruno void os_raid_response_error(rcb_t *rcb, raid_path_error_info_elem_t *err_info)
2851e66f787SSean Bruno {
2861e66f787SSean Bruno 	struct ccb_scsiio *csio;
2871e66f787SSean Bruno 	pqisrc_softstate_t *softs;
2881e66f787SSean Bruno 
2891e66f787SSean Bruno 	DBG_IO("IN\n");
2901e66f787SSean Bruno 
2911e66f787SSean Bruno 	csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
2921e66f787SSean Bruno 
2931e66f787SSean Bruno 	if (csio == NULL)
2941e66f787SSean Bruno 		panic("csio is null");
2951e66f787SSean Bruno 
2961e66f787SSean Bruno 	softs = rcb->softs;
2971e66f787SSean Bruno 
2981e66f787SSean Bruno 	ASSERT(err_info != NULL);
2991e66f787SSean Bruno 	csio->scsi_status = err_info->status;
3001e66f787SSean Bruno 	csio->ccb_h.status = CAM_REQ_CMP_ERR;
3011e66f787SSean Bruno 
3021e66f787SSean Bruno 	if (csio->ccb_h.func_code == XPT_SCSI_IO) {
3031e66f787SSean Bruno 		/*
3041e66f787SSean Bruno 		 * Handle specific SCSI status values.
3051e66f787SSean Bruno 		 */
3061e66f787SSean Bruno 		switch(csio->scsi_status) {
3071e66f787SSean Bruno 			case PQI_RAID_STATUS_QUEUE_FULL:
3081e66f787SSean Bruno 				csio->ccb_h.status = CAM_REQ_CMP;
3091e66f787SSean Bruno 				DBG_ERR("Queue Full error");
3101e66f787SSean Bruno 				break;
3111e66f787SSean Bruno 				/* check condition, sense data included */
3121e66f787SSean Bruno 			case PQI_RAID_STATUS_CHECK_CONDITION:
3131e66f787SSean Bruno 				{
3141e66f787SSean Bruno 				uint16_t sense_data_len =
3151e66f787SSean Bruno 					LE_16(err_info->sense_data_len);
3161e66f787SSean Bruno 				uint8_t *sense_data = NULL;
3171e66f787SSean Bruno 				if (sense_data_len)
3181e66f787SSean Bruno 					sense_data = err_info->data;
3191e66f787SSean Bruno 				memset(&csio->sense_data, 0, csio->sense_len);
3201e66f787SSean Bruno 				sense_data_len = (sense_data_len >
3211e66f787SSean Bruno 						csio->sense_len) ?
3221e66f787SSean Bruno 						csio->sense_len :
3231e66f787SSean Bruno 						sense_data_len;
3241e66f787SSean Bruno 				if (sense_data)
3251e66f787SSean Bruno 					memcpy(&csio->sense_data, sense_data,
3261e66f787SSean Bruno 						sense_data_len);
3271e66f787SSean Bruno 				if (csio->sense_len > sense_data_len)
3281e66f787SSean Bruno 					csio->sense_resid = csio->sense_len
3291e66f787SSean Bruno 							- sense_data_len;
3301e66f787SSean Bruno 					else
3311e66f787SSean Bruno 						csio->sense_resid = 0;
3321e66f787SSean Bruno 				csio->ccb_h.status = CAM_SCSI_STATUS_ERROR
3331e66f787SSean Bruno 							| CAM_AUTOSNS_VALID
3341e66f787SSean Bruno 							| CAM_REQ_CMP_ERR;
3351e66f787SSean Bruno 
3361e66f787SSean Bruno 				}
3371e66f787SSean Bruno 				break;
3381e66f787SSean Bruno 
3391e66f787SSean Bruno 			case PQI_RAID_DATA_IN_OUT_UNDERFLOW:
3401e66f787SSean Bruno 				{
3411e66f787SSean Bruno 				uint32_t resid = 0;
3421e66f787SSean Bruno 				resid = rcb->bcount-err_info->data_out_transferred;
3431e66f787SSean Bruno 			    	csio->resid  = resid;
3441e66f787SSean Bruno 				csio->ccb_h.status = CAM_REQ_CMP;
3451e66f787SSean Bruno 				break;
3461e66f787SSean Bruno 				}
3471e66f787SSean Bruno 			default:
3481e66f787SSean Bruno 				csio->ccb_h.status = CAM_REQ_CMP;
3491e66f787SSean Bruno 				break;
3501e66f787SSean Bruno 		}
3511e66f787SSean Bruno 	}
3521e66f787SSean Bruno 
3531e66f787SSean Bruno 	if (softs->os_specific.pqi_flags & PQI_FLAG_BUSY) {
3541e66f787SSean Bruno 		softs->os_specific.pqi_flags &= ~PQI_FLAG_BUSY;
3551e66f787SSean Bruno 		if (csio->ccb_h.status & CAM_RELEASE_SIMQ)
3561e66f787SSean Bruno 			xpt_release_simq(xpt_path_sim(csio->ccb_h.path), 0);
3571e66f787SSean Bruno 		else
3581e66f787SSean Bruno 			csio->ccb_h.status |= CAM_RELEASE_SIMQ;
3591e66f787SSean Bruno 	}
3601e66f787SSean Bruno 
3611e66f787SSean Bruno 	pqi_unmap_request(rcb);
3621e66f787SSean Bruno 	xpt_done((union ccb *)csio);
3631e66f787SSean Bruno 
3641e66f787SSean Bruno 	DBG_IO("OUT\n");
3651e66f787SSean Bruno }
3661e66f787SSean Bruno 
3671e66f787SSean Bruno 
3681e66f787SSean Bruno /*
3691e66f787SSean Bruno  * Error response handling for aio.
3701e66f787SSean Bruno  */
3711e66f787SSean Bruno void os_aio_response_error(rcb_t *rcb, aio_path_error_info_elem_t *err_info)
3721e66f787SSean Bruno {
3731e66f787SSean Bruno 	struct ccb_scsiio *csio;
3741e66f787SSean Bruno 	pqisrc_softstate_t *softs;
3751e66f787SSean Bruno 
3761e66f787SSean Bruno 	DBG_IO("IN\n");
3771e66f787SSean Bruno 
3781e66f787SSean Bruno         if (rcb == NULL)
3791e66f787SSean Bruno 		panic("rcb is null");
3801e66f787SSean Bruno 
3811e66f787SSean Bruno 	rcb->status = REQUEST_SUCCESS;
3821e66f787SSean Bruno 	csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
3831e66f787SSean Bruno 	if (csio == NULL)
3841e66f787SSean Bruno                 panic("csio is null");
3851e66f787SSean Bruno 
3861e66f787SSean Bruno 	softs = rcb->softs;
3871e66f787SSean Bruno 
3881e66f787SSean Bruno 	switch (err_info->service_resp) {
3891e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_COMPLETE:
3901e66f787SSean Bruno 			csio->ccb_h.status = err_info->status;
3911e66f787SSean Bruno 			break;
3921e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_FAILURE:
3931e66f787SSean Bruno 			switch(err_info->status) {
3941e66f787SSean Bruno 				case PQI_AIO_STATUS_IO_ABORTED:
3951e66f787SSean Bruno 					csio->ccb_h.status = CAM_REQ_ABORTED;
3961e66f787SSean Bruno 					DBG_WARN_BTL(rcb->dvp, "IO aborted\n");
3971e66f787SSean Bruno 					break;
3981e66f787SSean Bruno 				case PQI_AIO_STATUS_UNDERRUN:
3991e66f787SSean Bruno 					csio->ccb_h.status = CAM_REQ_CMP;
4001e66f787SSean Bruno 					csio->resid =
4011e66f787SSean Bruno 						LE_32(err_info->resd_count);
4021e66f787SSean Bruno 					break;
4031e66f787SSean Bruno 				case PQI_AIO_STATUS_OVERRUN:
4041e66f787SSean Bruno 					csio->ccb_h.status = CAM_REQ_CMP;
4051e66f787SSean Bruno 					break;
4061e66f787SSean Bruno 				case PQI_AIO_STATUS_AIO_PATH_DISABLED:
4071e66f787SSean Bruno 					DBG_WARN_BTL(rcb->dvp,"AIO Path Disabled\n");
4081e66f787SSean Bruno 					rcb->dvp->offload_enabled = false;
4091e66f787SSean Bruno 					csio->ccb_h.status |= CAM_REQUEUE_REQ;
4101e66f787SSean Bruno 					break;
4111e66f787SSean Bruno 				case PQI_AIO_STATUS_IO_ERROR:
4121e66f787SSean Bruno 				case PQI_AIO_STATUS_IO_NO_DEVICE:
4131e66f787SSean Bruno 				case PQI_AIO_STATUS_INVALID_DEVICE:
4141e66f787SSean Bruno 				default:
4151e66f787SSean Bruno 					DBG_WARN_BTL(rcb->dvp,"IO Error/Invalid/No device\n");
4161e66f787SSean Bruno 					csio->ccb_h.status |=
4171e66f787SSean Bruno 						CAM_SCSI_STATUS_ERROR;
4181e66f787SSean Bruno 					break;
4191e66f787SSean Bruno 			}
4201e66f787SSean Bruno 			break;
4211e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_TMF_COMPLETE:
4221e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_TMF_SUCCEEDED:
4231e66f787SSean Bruno 			csio->ccb_h.status = CAM_REQ_CMP;
4241e66f787SSean Bruno 			break;
4251e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_TMF_REJECTED:
4261e66f787SSean Bruno 		case PQI_AIO_SERV_RESPONSE_TMF_INCORRECT_LUN:
4271e66f787SSean Bruno 			DBG_WARN_BTL(rcb->dvp,"TMF rejected/Incorrect Lun\n");
4281e66f787SSean Bruno 			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
4291e66f787SSean Bruno 			break;
4301e66f787SSean Bruno 		default:
4311e66f787SSean Bruno 			DBG_WARN_BTL(rcb->dvp,"Scsi Status Error\n");
4321e66f787SSean Bruno 			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
4331e66f787SSean Bruno 			break;
4341e66f787SSean Bruno 	}
4351e66f787SSean Bruno 	if(err_info->data_pres == DATA_PRESENT_SENSE_DATA ) {
4361e66f787SSean Bruno 		csio->scsi_status = PQI_AIO_STATUS_CHECK_CONDITION;
4371e66f787SSean Bruno 		uint8_t *sense_data = NULL;
4381e66f787SSean Bruno 		unsigned sense_data_len = LE_16(err_info->data_len);
4391e66f787SSean Bruno 		if (sense_data_len)
4401e66f787SSean Bruno 			sense_data = err_info->data;
4411e66f787SSean Bruno 		DBG_ERR_BTL(rcb->dvp, "SCSI_STATUS_CHECK_COND  sense size %u\n",
4421e66f787SSean Bruno 			sense_data_len);
4431e66f787SSean Bruno 		memset(&csio->sense_data, 0, csio->sense_len);
4441e66f787SSean Bruno 		if (sense_data)
4451e66f787SSean Bruno 			memcpy(&csio->sense_data, sense_data, ((sense_data_len >
4461e66f787SSean Bruno                         	csio->sense_len) ? csio->sense_len : sense_data_len));
4471e66f787SSean Bruno 		if (csio->sense_len > sense_data_len)
4481e66f787SSean Bruno 			csio->sense_resid = csio->sense_len - sense_data_len;
4491e66f787SSean Bruno         	else
4501e66f787SSean Bruno 			csio->sense_resid = 0;
4511e66f787SSean Bruno 		csio->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
4521e66f787SSean Bruno 	}
4531e66f787SSean Bruno 
4541e66f787SSean Bruno 	smartpqi_fix_ld_inquiry(softs, csio);
4551e66f787SSean Bruno 	pqi_release_camq(rcb);
4561e66f787SSean Bruno 	pqi_unmap_request(rcb);
4571e66f787SSean Bruno 	xpt_done((union ccb *)csio);
4581e66f787SSean Bruno 	DBG_IO("OUT\n");
4591e66f787SSean Bruno }
4601e66f787SSean Bruno 
461*7000d321SEdward Tomasz Napierala static void
462*7000d321SEdward Tomasz Napierala pqi_freeze_ccb(union ccb *ccb)
463*7000d321SEdward Tomasz Napierala {
464*7000d321SEdward Tomasz Napierala 	if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
465*7000d321SEdward Tomasz Napierala 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
466*7000d321SEdward Tomasz Napierala 		xpt_freeze_devq(ccb->ccb_h.path, 1);
467*7000d321SEdward Tomasz Napierala 	}
468*7000d321SEdward Tomasz Napierala }
469*7000d321SEdward Tomasz Napierala 
4701e66f787SSean Bruno /*
4711e66f787SSean Bruno  * Command-mapping helper function - populate this command's s/g table.
4721e66f787SSean Bruno  */
4731e66f787SSean Bruno static void
4741e66f787SSean Bruno pqi_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
4751e66f787SSean Bruno {
4761e66f787SSean Bruno 	pqisrc_softstate_t *softs;
4771e66f787SSean Bruno 	rcb_t *rcb;
4781e66f787SSean Bruno 
4791e66f787SSean Bruno 	rcb = (rcb_t *)arg;
4801e66f787SSean Bruno 	softs = rcb->softs;
4811e66f787SSean Bruno 
4821e66f787SSean Bruno 	if(  error || nseg > softs->pqi_cap.max_sg_elem )
4831e66f787SSean Bruno 	{
484*7000d321SEdward Tomasz Napierala 		rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
485*7000d321SEdward Tomasz Napierala 		pqi_freeze_ccb(rcb->cm_ccb);
4861e66f787SSean Bruno 		DBG_ERR_BTL(rcb->dvp, "map failed err = %d or nseg(%d) > sgelem(%d)\n",
4871e66f787SSean Bruno 			error, nseg, softs->pqi_cap.max_sg_elem);
4881e66f787SSean Bruno 		pqi_unmap_request(rcb);
4891e66f787SSean Bruno 		xpt_done((union ccb *)rcb->cm_ccb);
4901e66f787SSean Bruno 		return;
4911e66f787SSean Bruno 	}
4921e66f787SSean Bruno 
4931e66f787SSean Bruno 	rcb->sgt = os_mem_alloc(softs, nseg * sizeof(rcb_t));
4944f4463dfSEdward Tomasz Napierala 	if (rcb->sgt == NULL) {
495*7000d321SEdward Tomasz Napierala 		rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
496*7000d321SEdward Tomasz Napierala 		pqi_freeze_ccb(rcb->cm_ccb);
4974f4463dfSEdward Tomasz Napierala 		DBG_ERR_BTL(rcb->dvp, "os_mem_alloc() failed; nseg = %d\n", nseg);
4984f4463dfSEdward Tomasz Napierala 		pqi_unmap_request(rcb);
4994f4463dfSEdward Tomasz Napierala 		xpt_done((union ccb *)rcb->cm_ccb);
5004f4463dfSEdward Tomasz Napierala 		return;
5014f4463dfSEdward Tomasz Napierala 	}
5024f4463dfSEdward Tomasz Napierala 
5031e66f787SSean Bruno 	rcb->nseg = nseg;
5041e66f787SSean Bruno 	for (int i = 0; i < nseg; i++) {
5051e66f787SSean Bruno 		rcb->sgt[i].addr = segs[i].ds_addr;
5061e66f787SSean Bruno 		rcb->sgt[i].len = segs[i].ds_len;
5071e66f787SSean Bruno 		rcb->sgt[i].flags = 0;
5081e66f787SSean Bruno 	}
5091e66f787SSean Bruno 
5101e66f787SSean Bruno 	if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE)
5111e66f787SSean Bruno 		bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
5121e66f787SSean Bruno 			rcb->cm_datamap, BUS_DMASYNC_PREREAD);
5131e66f787SSean Bruno 	if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE)
5141e66f787SSean Bruno 		bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
5151e66f787SSean Bruno 			rcb->cm_datamap, BUS_DMASYNC_PREWRITE);
5161e66f787SSean Bruno 
5171e66f787SSean Bruno 	/* Call IO functions depending on pd or ld */
5181e66f787SSean Bruno 	rcb->status = REQUEST_PENDING;
5191e66f787SSean Bruno 
5201e66f787SSean Bruno 	error = pqisrc_build_send_io(softs, rcb);
5211e66f787SSean Bruno 
5221e66f787SSean Bruno 	if (error) {
5231e66f787SSean Bruno 		rcb->req_pending = false;
524*7000d321SEdward Tomasz Napierala 		rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
525*7000d321SEdward Tomasz Napierala 		pqi_freeze_ccb(rcb->cm_ccb);
5261e66f787SSean Bruno 		DBG_ERR_BTL(rcb->dvp, "Build IO failed, error = %d\n", error);
5271e66f787SSean Bruno 	   	pqi_unmap_request(rcb);
5281e66f787SSean Bruno 		xpt_done((union ccb *)rcb->cm_ccb);
5291e66f787SSean Bruno 		return;
5301e66f787SSean Bruno 	}
5311e66f787SSean Bruno }
5321e66f787SSean Bruno 
5331e66f787SSean Bruno /*
5341e66f787SSean Bruno  * Function to dma-map the request buffer
5351e66f787SSean Bruno  */
5361e66f787SSean Bruno static int pqi_map_request( rcb_t *rcb )
5371e66f787SSean Bruno {
5381e66f787SSean Bruno 	pqisrc_softstate_t *softs = rcb->softs;
5391e66f787SSean Bruno 	int error = PQI_STATUS_SUCCESS;
5401e66f787SSean Bruno 	union ccb *ccb = rcb->cm_ccb;
5411e66f787SSean Bruno 
5421e66f787SSean Bruno 	DBG_FUNC("IN\n");
5431e66f787SSean Bruno 
5441e66f787SSean Bruno 	/* check that mapping is necessary */
5451e66f787SSean Bruno 	if (rcb->cm_flags & PQI_CMD_MAPPED)
5461e66f787SSean Bruno 		return(0);
5471e66f787SSean Bruno 	rcb->cm_flags |= PQI_CMD_MAPPED;
5481e66f787SSean Bruno 
5491e66f787SSean Bruno 	if (rcb->bcount) {
5501e66f787SSean Bruno 		error = bus_dmamap_load_ccb(softs->os_specific.pqi_buffer_dmat,
5511e66f787SSean Bruno 			rcb->cm_datamap, ccb, pqi_request_map_helper, rcb, 0);
5521e66f787SSean Bruno 		if (error != 0){
5531e66f787SSean Bruno 			DBG_ERR_BTL(rcb->dvp, "bus_dmamap_load_ccb failed = %d count = %d\n",
5541e66f787SSean Bruno 					error, rcb->bcount);
5551e66f787SSean Bruno 			return error;
5561e66f787SSean Bruno 		}
5571e66f787SSean Bruno 	} else {
5581e66f787SSean Bruno 		/*
5591e66f787SSean Bruno 		 * Set up the command to go to the controller.  If there are no
5601e66f787SSean Bruno 		 * data buffers associated with the command then it can bypass
5611e66f787SSean Bruno 		 * busdma.
5621e66f787SSean Bruno 		 */
5631e66f787SSean Bruno 		/* Call IO functions depending on pd or ld */
5641e66f787SSean Bruno 		rcb->status = REQUEST_PENDING;
5651e66f787SSean Bruno 
5661e66f787SSean Bruno 		error = pqisrc_build_send_io(softs, rcb);
5671e66f787SSean Bruno 
5681e66f787SSean Bruno 	}
5691e66f787SSean Bruno 
5701e66f787SSean Bruno 	DBG_FUNC("OUT error = %d\n", error);
5711e66f787SSean Bruno 
5721e66f787SSean Bruno 	return error;
5731e66f787SSean Bruno }
5741e66f787SSean Bruno 
5751e66f787SSean Bruno /*
5761e66f787SSean Bruno  * Function to clear the request control block
5771e66f787SSean Bruno  */
5781e66f787SSean Bruno void os_reset_rcb( rcb_t *rcb )
5791e66f787SSean Bruno {
5801e66f787SSean Bruno 	rcb->error_info = NULL;
5811e66f787SSean Bruno 	rcb->req = NULL;
5821e66f787SSean Bruno 	rcb->status = -1;
5831e66f787SSean Bruno 	rcb->tag = INVALID_ELEM;
5841e66f787SSean Bruno 	rcb->dvp = NULL;
5851e66f787SSean Bruno 	rcb->cdbp = NULL;
5861e66f787SSean Bruno 	rcb->softs = NULL;
5871e66f787SSean Bruno 	rcb->cm_flags = 0;
5881e66f787SSean Bruno 	rcb->cm_data = NULL;
5891e66f787SSean Bruno 	rcb->bcount = 0;
5901e66f787SSean Bruno 	rcb->nseg = 0;
5911e66f787SSean Bruno 	rcb->sgt = NULL;
5921e66f787SSean Bruno 	rcb->cm_ccb = NULL;
5931e66f787SSean Bruno 	rcb->encrypt_enable = false;
5941e66f787SSean Bruno 	rcb->ioaccel_handle = 0;
5951e66f787SSean Bruno 	rcb->resp_qid = 0;
5961e66f787SSean Bruno 	rcb->req_pending = false;
5971e66f787SSean Bruno }
5981e66f787SSean Bruno 
5991e66f787SSean Bruno /*
6001e66f787SSean Bruno  * Callback function for the lun rescan
6011e66f787SSean Bruno  */
6021e66f787SSean Bruno static void smartpqi_lunrescan_cb(struct cam_periph *periph, union ccb *ccb)
6031e66f787SSean Bruno {
6041e66f787SSean Bruno         xpt_free_path(ccb->ccb_h.path);
6051e66f787SSean Bruno         xpt_free_ccb(ccb);
6061e66f787SSean Bruno }
6071e66f787SSean Bruno 
6081e66f787SSean Bruno 
6091e66f787SSean Bruno /*
6101e66f787SSean Bruno  * Function to rescan the lun
6111e66f787SSean Bruno  */
6121e66f787SSean Bruno static void smartpqi_lun_rescan(struct pqisrc_softstate *softs, int target,
6131e66f787SSean Bruno 			int lun)
6141e66f787SSean Bruno {
6151e66f787SSean Bruno 	union ccb   *ccb = NULL;
6161e66f787SSean Bruno 	cam_status  status = 0;
6171e66f787SSean Bruno 	struct cam_path     *path = NULL;
6181e66f787SSean Bruno 
6191e66f787SSean Bruno 	DBG_FUNC("IN\n");
6201e66f787SSean Bruno 
6211e66f787SSean Bruno 	ccb = xpt_alloc_ccb_nowait();
6221e66f787SSean Bruno 	status = xpt_create_path(&path, NULL,
6231e66f787SSean Bruno 				cam_sim_path(softs->os_specific.sim), target, lun);
6241e66f787SSean Bruno 	if (status != CAM_REQ_CMP) {
6251e66f787SSean Bruno 		DBG_ERR("xpt_create_path status(%d) != CAM_REQ_CMP \n",
6261e66f787SSean Bruno 				 status);
6271e66f787SSean Bruno 		xpt_free_ccb(ccb);
6281e66f787SSean Bruno 		return;
6291e66f787SSean Bruno 	}
6301e66f787SSean Bruno 
6311e66f787SSean Bruno 	bzero(ccb, sizeof(union ccb));
6321e66f787SSean Bruno 	xpt_setup_ccb(&ccb->ccb_h, path, 5);
6331e66f787SSean Bruno 	ccb->ccb_h.func_code = XPT_SCAN_LUN;
6341e66f787SSean Bruno 	ccb->ccb_h.cbfcnp = smartpqi_lunrescan_cb;
6351e66f787SSean Bruno 	ccb->crcn.flags = CAM_FLAG_NONE;
6361e66f787SSean Bruno 
6371e66f787SSean Bruno 	xpt_action(ccb);
6381e66f787SSean Bruno 
6391e66f787SSean Bruno 	DBG_FUNC("OUT\n");
6401e66f787SSean Bruno }
6411e66f787SSean Bruno 
6421e66f787SSean Bruno /*
6431e66f787SSean Bruno  * Function to rescan the lun under each target
6441e66f787SSean Bruno  */
6451e66f787SSean Bruno void smartpqi_target_rescan(struct pqisrc_softstate *softs)
6461e66f787SSean Bruno {
6471e66f787SSean Bruno 	int target = 0, lun = 0;
6481e66f787SSean Bruno 
6491e66f787SSean Bruno 	DBG_FUNC("IN\n");
6501e66f787SSean Bruno 
6511e66f787SSean Bruno 	for(target = 0; target < PQI_MAX_DEVICES; target++){
6521e66f787SSean Bruno 		for(lun = 0; lun < PQI_MAX_MULTILUN; lun++){
6531e66f787SSean Bruno 			if(softs->device_list[target][lun]){
6541e66f787SSean Bruno 				smartpqi_lun_rescan(softs, target, lun);
6551e66f787SSean Bruno 			}
6561e66f787SSean Bruno 		}
6571e66f787SSean Bruno 	}
6581e66f787SSean Bruno 
6591e66f787SSean Bruno 	DBG_FUNC("OUT\n");
6601e66f787SSean Bruno }
6611e66f787SSean Bruno 
6621e66f787SSean Bruno /*
6631e66f787SSean Bruno  * Set the mode of tagged command queueing for the current task.
6641e66f787SSean Bruno  */
6651e66f787SSean Bruno uint8_t os_get_task_attr(rcb_t *rcb)
6661e66f787SSean Bruno {
6671e66f787SSean Bruno 	union ccb *ccb = rcb->cm_ccb;
6681e66f787SSean Bruno 	uint8_t tag_action = SOP_TASK_ATTRIBUTE_SIMPLE;
6691e66f787SSean Bruno 
6701e66f787SSean Bruno 	switch(ccb->csio.tag_action) {
6711e66f787SSean Bruno 	case MSG_HEAD_OF_Q_TAG:
6721e66f787SSean Bruno 		tag_action = SOP_TASK_ATTRIBUTE_HEAD_OF_QUEUE;
6731e66f787SSean Bruno 		break;
6741e66f787SSean Bruno 	case MSG_ORDERED_Q_TAG:
6751e66f787SSean Bruno 		tag_action = SOP_TASK_ATTRIBUTE_ORDERED;
6761e66f787SSean Bruno 		break;
6771e66f787SSean Bruno 	case MSG_SIMPLE_Q_TAG:
6781e66f787SSean Bruno 	default:
6791e66f787SSean Bruno 		tag_action = SOP_TASK_ATTRIBUTE_SIMPLE;
6801e66f787SSean Bruno 		break;
6811e66f787SSean Bruno 	}
6821e66f787SSean Bruno 	return tag_action;
6831e66f787SSean Bruno }
6841e66f787SSean Bruno 
6851e66f787SSean Bruno /*
6861e66f787SSean Bruno  * Complete all outstanding commands
6871e66f787SSean Bruno  */
6881e66f787SSean Bruno void os_complete_outstanding_cmds_nodevice(pqisrc_softstate_t *softs)
6891e66f787SSean Bruno {
6901e66f787SSean Bruno 	int tag = 0;
6911e66f787SSean Bruno 
6921e66f787SSean Bruno 	DBG_FUNC("IN\n");
6931e66f787SSean Bruno 
6941e66f787SSean Bruno 	for (tag = 1; tag < softs->max_outstanding_io; tag++) {
6951e66f787SSean Bruno 		rcb_t *prcb = &softs->rcb[tag];
6961e66f787SSean Bruno 		if(prcb->req_pending && prcb->cm_ccb ) {
6971e66f787SSean Bruno 			prcb->req_pending = false;
6981e66f787SSean Bruno 			prcb->cm_ccb->ccb_h.status = CAM_REQ_ABORTED | CAM_REQ_CMP;
6991e66f787SSean Bruno 			xpt_done((union ccb *)prcb->cm_ccb);
7001e66f787SSean Bruno 			prcb->cm_ccb = NULL;
7011e66f787SSean Bruno 		}
7021e66f787SSean Bruno 	}
7031e66f787SSean Bruno 
7041e66f787SSean Bruno 	DBG_FUNC("OUT\n");
7051e66f787SSean Bruno }
7061e66f787SSean Bruno 
7071e66f787SSean Bruno /*
7081e66f787SSean Bruno  * IO handling functionality entry point
7091e66f787SSean Bruno  */
7101e66f787SSean Bruno static int pqisrc_io_start(struct cam_sim *sim, union ccb *ccb)
7111e66f787SSean Bruno {
7121e66f787SSean Bruno 	rcb_t *rcb;
7131e66f787SSean Bruno 	uint32_t tag, no_transfer = 0;
7141e66f787SSean Bruno 	pqisrc_softstate_t *softs = (struct pqisrc_softstate *)
7151e66f787SSean Bruno 					cam_sim_softc(sim);
7161e66f787SSean Bruno 	int32_t error = PQI_STATUS_FAILURE;
7171e66f787SSean Bruno 	pqi_scsi_dev_t *dvp;
7181e66f787SSean Bruno 
7191e66f787SSean Bruno 	DBG_FUNC("IN\n");
7201e66f787SSean Bruno 
7211e66f787SSean Bruno 	if( softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun] == NULL ) {
7221e66f787SSean Bruno 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
7231e66f787SSean Bruno 		DBG_INFO("Device  = %d not there\n", ccb->ccb_h.target_id);
7241e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
7251e66f787SSean Bruno 	}
7261e66f787SSean Bruno 
7271e66f787SSean Bruno 	dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
7281e66f787SSean Bruno 	/* Check  controller state */
7291e66f787SSean Bruno 	if (IN_PQI_RESET(softs)) {
7301e66f787SSean Bruno 		ccb->ccb_h.status = CAM_SCSI_BUS_RESET
7311e66f787SSean Bruno 					| CAM_BUSY | CAM_REQ_INPROG;
7321e66f787SSean Bruno 		DBG_WARN("Device  = %d BUSY/IN_RESET\n", ccb->ccb_h.target_id);
7331e66f787SSean Bruno 		return error;
7341e66f787SSean Bruno 	}
7351e66f787SSean Bruno 	/* Check device state */
7361e66f787SSean Bruno 	if (pqisrc_ctrl_offline(softs) || DEV_GONE(dvp)) {
7371e66f787SSean Bruno 		ccb->ccb_h.status = CAM_DEV_NOT_THERE | CAM_REQ_CMP;
7381e66f787SSean Bruno 		DBG_WARN("Device  = %d GONE/OFFLINE\n", ccb->ccb_h.target_id);
7391e66f787SSean Bruno 		return error;
7401e66f787SSean Bruno 	}
7411e66f787SSean Bruno 	/* Check device reset */
7421e66f787SSean Bruno 	if (DEV_RESET(dvp)) {
7431e66f787SSean Bruno 		ccb->ccb_h.status = CAM_SCSI_BUSY | CAM_REQ_INPROG | CAM_BUSY;
7441e66f787SSean Bruno 		DBG_WARN("Device %d reset returned busy\n", ccb->ccb_h.target_id);
7451e66f787SSean Bruno 		return error;
7461e66f787SSean Bruno 	}
7471e66f787SSean Bruno 
7481e66f787SSean Bruno 	if (dvp->expose_device == false) {
7491e66f787SSean Bruno 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
7501e66f787SSean Bruno 		DBG_INFO("Device  = %d not exposed\n", ccb->ccb_h.target_id);
7511e66f787SSean Bruno 		return error;
7521e66f787SSean Bruno 	}
7531e66f787SSean Bruno 
7541e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
7551e66f787SSean Bruno 	if( tag == INVALID_ELEM ) {
7561e66f787SSean Bruno 		DBG_ERR("Get Tag failed\n");
7571e66f787SSean Bruno 		xpt_freeze_simq(softs->os_specific.sim, 1);
7581e66f787SSean Bruno 		softs->os_specific.pqi_flags |= PQI_FLAG_BUSY;
7591e66f787SSean Bruno 		ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_RELEASE_SIMQ);
7601e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
7611e66f787SSean Bruno 	}
7621e66f787SSean Bruno 
7631e66f787SSean Bruno 	DBG_IO("tag = %d &softs->taglist : %p\n", tag, &softs->taglist);
7641e66f787SSean Bruno 
7651e66f787SSean Bruno 	rcb = &softs->rcb[tag];
7661e66f787SSean Bruno 	os_reset_rcb( rcb );
7671e66f787SSean Bruno 	rcb->tag = tag;
7681e66f787SSean Bruno 	rcb->softs = softs;
7691e66f787SSean Bruno 	rcb->cmdlen = ccb->csio.cdb_len;
7701e66f787SSean Bruno 	ccb->ccb_h.sim_priv.entries[0].ptr = rcb;
7711e66f787SSean Bruno 
7721e66f787SSean Bruno 	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
7731e66f787SSean Bruno 		case CAM_DIR_IN:
7741e66f787SSean Bruno 			rcb->data_dir = SOP_DATA_DIR_FROM_DEVICE;
7751e66f787SSean Bruno 			break;
7761e66f787SSean Bruno 		case CAM_DIR_OUT:
7771e66f787SSean Bruno 			rcb->data_dir = SOP_DATA_DIR_TO_DEVICE;
7781e66f787SSean Bruno 			break;
7791e66f787SSean Bruno 		case CAM_DIR_NONE:
7801e66f787SSean Bruno 			no_transfer = 1;
7811e66f787SSean Bruno 			break;
7821e66f787SSean Bruno 		default:
7831e66f787SSean Bruno 			DBG_ERR("Unknown Dir\n");
7841e66f787SSean Bruno 			break;
7851e66f787SSean Bruno 	}
7861e66f787SSean Bruno 	rcb->cm_ccb = ccb;
7871e66f787SSean Bruno 	rcb->dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
7881e66f787SSean Bruno 
7891e66f787SSean Bruno 	if (!no_transfer) {
7901e66f787SSean Bruno 		rcb->cm_data = (void *)ccb->csio.data_ptr;
7911e66f787SSean Bruno 		rcb->bcount = ccb->csio.dxfer_len;
7921e66f787SSean Bruno 	} else {
7931e66f787SSean Bruno 		rcb->cm_data = NULL;
7941e66f787SSean Bruno 		rcb->bcount = 0;
7951e66f787SSean Bruno 	}
7961e66f787SSean Bruno 	/*
7971e66f787SSean Bruno 	 * Submit the request to the adapter.
7981e66f787SSean Bruno 	 *
7991e66f787SSean Bruno 	 * Note that this may fail if we're unable to map the request (and
8001e66f787SSean Bruno 	 * if we ever learn a transport layer other than simple, may fail
8011e66f787SSean Bruno 	 * if the adapter rejects the command).
8021e66f787SSean Bruno 	 */
8031e66f787SSean Bruno 	if ((error = pqi_map_request(rcb)) != 0) {
8041e66f787SSean Bruno 		rcb->req_pending = false;
8051e66f787SSean Bruno 		xpt_freeze_simq(softs->os_specific.sim, 1);
8061e66f787SSean Bruno 		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
8071e66f787SSean Bruno 		if (error == EINPROGRESS) {
8081e66f787SSean Bruno 			DBG_WARN("In Progress on %d\n", ccb->ccb_h.target_id);
8091e66f787SSean Bruno 			error = 0;
8101e66f787SSean Bruno 		} else {
8111e66f787SSean Bruno 			ccb->ccb_h.status |= CAM_REQUEUE_REQ;
8121e66f787SSean Bruno 			DBG_WARN("Requeue req error = %d target = %d\n", error,
8131e66f787SSean Bruno 				ccb->ccb_h.target_id);
8141e66f787SSean Bruno 			pqi_unmap_request(rcb);
8151e66f787SSean Bruno 		}
8161e66f787SSean Bruno 	}
8171e66f787SSean Bruno 
8181e66f787SSean Bruno 	DBG_FUNC("OUT error = %d\n", error);
8191e66f787SSean Bruno 	return error;
8201e66f787SSean Bruno }
8211e66f787SSean Bruno 
8221e66f787SSean Bruno /*
8231e66f787SSean Bruno  * Abort a task, task management functionality
8241e66f787SSean Bruno  */
8251e66f787SSean Bruno static int
8261e66f787SSean Bruno pqisrc_scsi_abort_task(pqisrc_softstate_t *softs,  union ccb *ccb)
8271e66f787SSean Bruno {
8281e66f787SSean Bruno 	rcb_t *rcb = ccb->ccb_h.sim_priv.entries[0].ptr;
8291e66f787SSean Bruno 	uint32_t abort_tag = rcb->tag;
8301e66f787SSean Bruno 	uint32_t tag = 0;
8311e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
8321e66f787SSean Bruno 	uint16_t qid;
8331e66f787SSean Bruno 
8341e66f787SSean Bruno     DBG_FUNC("IN\n");
8351e66f787SSean Bruno 
8361e66f787SSean Bruno 	qid = (uint16_t)rcb->resp_qid;
8371e66f787SSean Bruno 
8381e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
8391e66f787SSean Bruno 	rcb = &softs->rcb[tag];
8401e66f787SSean Bruno 	rcb->tag = tag;
8411e66f787SSean Bruno 	rcb->resp_qid = qid;
8421e66f787SSean Bruno 
8431e66f787SSean Bruno 	rval = pqisrc_send_tmf(softs, rcb->dvp, rcb, abort_tag,
8441e66f787SSean Bruno 		SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK);
8451e66f787SSean Bruno 
8461e66f787SSean Bruno 	if (PQI_STATUS_SUCCESS == rval) {
8471e66f787SSean Bruno 		rval = rcb->status;
8481e66f787SSean Bruno 		if (REQUEST_SUCCESS == rval) {
8491e66f787SSean Bruno 			ccb->ccb_h.status = CAM_REQ_ABORTED;
8501e66f787SSean Bruno 		}
8511e66f787SSean Bruno 	}
8521e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, abort_tag);
8531e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist,rcb->tag);
8541e66f787SSean Bruno 
8551e66f787SSean Bruno 	DBG_FUNC("OUT rval = %d\n", rval);
8561e66f787SSean Bruno 
8571e66f787SSean Bruno 	return rval;
8581e66f787SSean Bruno }
8591e66f787SSean Bruno 
8601e66f787SSean Bruno /*
8611e66f787SSean Bruno  * Abort a taskset, task management functionality
8621e66f787SSean Bruno  */
8631e66f787SSean Bruno static int
8641e66f787SSean Bruno pqisrc_scsi_abort_task_set(pqisrc_softstate_t *softs, union ccb *ccb)
8651e66f787SSean Bruno {
8661e66f787SSean Bruno 	rcb_t *rcb = NULL;
8671e66f787SSean Bruno 	uint32_t tag = 0;
8681e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
8691e66f787SSean Bruno 
8701e66f787SSean Bruno 	DBG_FUNC("IN\n");
8711e66f787SSean Bruno 
8721e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
8731e66f787SSean Bruno 	rcb = &softs->rcb[tag];
8741e66f787SSean Bruno 	rcb->tag = tag;
8751e66f787SSean Bruno 
8761e66f787SSean Bruno 	rval = pqisrc_send_tmf(softs, rcb->dvp, rcb, 0,
8771e66f787SSean Bruno 			SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK_SET);
8781e66f787SSean Bruno 
8791e66f787SSean Bruno 	if (rval == PQI_STATUS_SUCCESS) {
8801e66f787SSean Bruno 		rval = rcb->status;
8811e66f787SSean Bruno 	}
8821e66f787SSean Bruno 
8831e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist,rcb->tag);
8841e66f787SSean Bruno 
8851e66f787SSean Bruno 	DBG_FUNC("OUT rval = %d\n", rval);
8861e66f787SSean Bruno 
8871e66f787SSean Bruno 	return rval;
8881e66f787SSean Bruno }
8891e66f787SSean Bruno 
8901e66f787SSean Bruno /*
8911e66f787SSean Bruno  * Target reset task management functionality
8921e66f787SSean Bruno  */
8931e66f787SSean Bruno static int
8941e66f787SSean Bruno pqisrc_target_reset( pqisrc_softstate_t *softs,  union ccb *ccb)
8951e66f787SSean Bruno {
8961e66f787SSean Bruno 	pqi_scsi_dev_t *devp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
8971e66f787SSean Bruno 	rcb_t *rcb = NULL;
8981e66f787SSean Bruno 	uint32_t tag = 0;
8991e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
9001e66f787SSean Bruno 
9011e66f787SSean Bruno 	DBG_FUNC("IN\n");
9021e66f787SSean Bruno 
9031e66f787SSean Bruno 	if (devp == NULL) {
9041e66f787SSean Bruno 		DBG_ERR("bad target t%d\n", ccb->ccb_h.target_id);
9051e66f787SSean Bruno 		return (-1);
9061e66f787SSean Bruno 	}
9071e66f787SSean Bruno 
9081e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
9091e66f787SSean Bruno 	rcb = &softs->rcb[tag];
9101e66f787SSean Bruno 	rcb->tag = tag;
9111e66f787SSean Bruno 
9121e66f787SSean Bruno 	devp->reset_in_progress = true;
9131e66f787SSean Bruno 	rval = pqisrc_send_tmf(softs, devp, rcb, 0,
9141e66f787SSean Bruno 		SOP_TASK_MANAGEMENT_LUN_RESET);
9151e66f787SSean Bruno 	if (PQI_STATUS_SUCCESS == rval) {
9161e66f787SSean Bruno 		rval = rcb->status;
9171e66f787SSean Bruno 	}
9181e66f787SSean Bruno 	devp->reset_in_progress = false;
9191e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist,rcb->tag);
9201e66f787SSean Bruno 
9211e66f787SSean Bruno 	DBG_FUNC("OUT rval = %d\n", rval);
9221e66f787SSean Bruno 
9231e66f787SSean Bruno 	return ((rval == REQUEST_SUCCESS) ?
9241e66f787SSean Bruno 		PQI_STATUS_SUCCESS : PQI_STATUS_FAILURE);
9251e66f787SSean Bruno }
9261e66f787SSean Bruno 
9271e66f787SSean Bruno /*
9281e66f787SSean Bruno  * cam entry point of the smartpqi module.
9291e66f787SSean Bruno  */
9301e66f787SSean Bruno static void smartpqi_cam_action(struct cam_sim *sim, union ccb *ccb)
9311e66f787SSean Bruno {
9321e66f787SSean Bruno 	struct pqisrc_softstate *softs = cam_sim_softc(sim);
9331e66f787SSean Bruno 	struct ccb_hdr  *ccb_h = &ccb->ccb_h;
9341e66f787SSean Bruno 
9351e66f787SSean Bruno 	DBG_FUNC("IN\n");
9361e66f787SSean Bruno 
9371e66f787SSean Bruno 	switch (ccb_h->func_code) {
9381e66f787SSean Bruno 		case XPT_SCSI_IO:
9391e66f787SSean Bruno 		{
9401e66f787SSean Bruno 			if(!pqisrc_io_start(sim, ccb)) {
9411e66f787SSean Bruno 				return;
9421e66f787SSean Bruno 			}
9431e66f787SSean Bruno 			break;
9441e66f787SSean Bruno 		}
9451e66f787SSean Bruno 		case XPT_CALC_GEOMETRY:
9461e66f787SSean Bruno 		{
9471e66f787SSean Bruno 			struct ccb_calc_geometry *ccg;
9481e66f787SSean Bruno 			ccg = &ccb->ccg;
9491e66f787SSean Bruno 			if (ccg->block_size == 0) {
9501e66f787SSean Bruno 				ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
9511e66f787SSean Bruno 				ccb->ccb_h.status = CAM_REQ_INVALID;
9521e66f787SSean Bruno 				break;
9531e66f787SSean Bruno 			}
9541e66f787SSean Bruno 			cam_calc_geometry(ccg, /* extended */ 1);
9551e66f787SSean Bruno 			ccb->ccb_h.status = CAM_REQ_CMP;
9561e66f787SSean Bruno 			break;
9571e66f787SSean Bruno 		}
9581e66f787SSean Bruno 		case XPT_PATH_INQ:
9591e66f787SSean Bruno 		{
9601e66f787SSean Bruno 			update_sim_properties(sim, &ccb->cpi);
9611e66f787SSean Bruno 			ccb->ccb_h.status = CAM_REQ_CMP;
9621e66f787SSean Bruno 			break;
9631e66f787SSean Bruno 		}
9641e66f787SSean Bruno 		case XPT_GET_TRAN_SETTINGS:
9651e66f787SSean Bruno 			get_transport_settings(softs, &ccb->cts);
9661e66f787SSean Bruno 			ccb->ccb_h.status = CAM_REQ_CMP;
9671e66f787SSean Bruno 			break;
9681e66f787SSean Bruno 		case XPT_ABORT:
9691e66f787SSean Bruno 			if(pqisrc_scsi_abort_task(softs,  ccb)) {
9701e66f787SSean Bruno 				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
9711e66f787SSean Bruno 				xpt_done(ccb);
9721e66f787SSean Bruno 				DBG_ERR("Abort task failed on %d\n",
9731e66f787SSean Bruno 					ccb->ccb_h.target_id);
9741e66f787SSean Bruno 				return;
9751e66f787SSean Bruno 			}
9761e66f787SSean Bruno 			break;
9771e66f787SSean Bruno 		case XPT_TERM_IO:
9781e66f787SSean Bruno 			if (pqisrc_scsi_abort_task_set(softs,  ccb)) {
9791e66f787SSean Bruno 				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
9801e66f787SSean Bruno 				DBG_ERR("Abort task set failed on %d\n",
9811e66f787SSean Bruno 					ccb->ccb_h.target_id);
9821e66f787SSean Bruno 				xpt_done(ccb);
9831e66f787SSean Bruno 				return;
9841e66f787SSean Bruno 			}
9851e66f787SSean Bruno 			break;
9861e66f787SSean Bruno 		case XPT_RESET_DEV:
9871e66f787SSean Bruno 			if(pqisrc_target_reset(softs,  ccb)) {
9881e66f787SSean Bruno 				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
9891e66f787SSean Bruno 				DBG_ERR("Target reset failed on %d\n",
9901e66f787SSean Bruno 					ccb->ccb_h.target_id);
9911e66f787SSean Bruno 				xpt_done(ccb);
9921e66f787SSean Bruno 				return;
9931e66f787SSean Bruno 			} else {
9941e66f787SSean Bruno 				ccb->ccb_h.status = CAM_REQ_CMP;
9951e66f787SSean Bruno 			}
9961e66f787SSean Bruno 			break;
9971e66f787SSean Bruno 		case XPT_RESET_BUS:
9981e66f787SSean Bruno 			ccb->ccb_h.status = CAM_REQ_CMP;
9991e66f787SSean Bruno 			break;
10001e66f787SSean Bruno 		case XPT_SET_TRAN_SETTINGS:
10011e66f787SSean Bruno 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
10021e66f787SSean Bruno 			return;
10031e66f787SSean Bruno 		default:
10041e66f787SSean Bruno 			DBG_WARN("UNSUPPORTED FUNC CODE\n");
10051e66f787SSean Bruno 			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
10061e66f787SSean Bruno 			break;
10071e66f787SSean Bruno 	}
10081e66f787SSean Bruno 	xpt_done(ccb);
10091e66f787SSean Bruno 
10101e66f787SSean Bruno 	DBG_FUNC("OUT\n");
10111e66f787SSean Bruno }
10121e66f787SSean Bruno 
10131e66f787SSean Bruno /*
10141e66f787SSean Bruno  * Function to poll the response, when interrupts are unavailable
10151e66f787SSean Bruno  * This also serves supporting crash dump.
10161e66f787SSean Bruno  */
10171e66f787SSean Bruno static void smartpqi_poll(struct cam_sim *sim)
10181e66f787SSean Bruno {
10191e66f787SSean Bruno 	struct pqisrc_softstate *softs = cam_sim_softc(sim);
10201e66f787SSean Bruno 	int i;
10211e66f787SSean Bruno 
10221e66f787SSean Bruno 	for (i = 1; i < softs->intr_count; i++ )
10231e66f787SSean Bruno 		pqisrc_process_response_queue(softs, i);
10241e66f787SSean Bruno }
10251e66f787SSean Bruno 
10261e66f787SSean Bruno /*
10271e66f787SSean Bruno  * Function to adjust the queue depth of a device
10281e66f787SSean Bruno  */
10291e66f787SSean Bruno void smartpqi_adjust_queue_depth(struct cam_path *path, uint32_t queue_depth)
10301e66f787SSean Bruno {
10311e66f787SSean Bruno 	struct ccb_relsim crs;
10321e66f787SSean Bruno 
10331e66f787SSean Bruno 	DBG_INFO("IN\n");
10341e66f787SSean Bruno 
10351e66f787SSean Bruno 	xpt_setup_ccb(&crs.ccb_h, path, 5);
10361e66f787SSean Bruno 	crs.ccb_h.func_code = XPT_REL_SIMQ;
10371e66f787SSean Bruno 	crs.ccb_h.flags = CAM_DEV_QFREEZE;
10381e66f787SSean Bruno 	crs.release_flags = RELSIM_ADJUST_OPENINGS;
10391e66f787SSean Bruno 	crs.openings = queue_depth;
10401e66f787SSean Bruno 	xpt_action((union ccb *)&crs);
10411e66f787SSean Bruno 	if(crs.ccb_h.status != CAM_REQ_CMP) {
10421e66f787SSean Bruno 		printf("XPT_REL_SIMQ failed stat=%d\n", crs.ccb_h.status);
10431e66f787SSean Bruno 	}
10441e66f787SSean Bruno 
10451e66f787SSean Bruno 	DBG_INFO("OUT\n");
10461e66f787SSean Bruno }
10471e66f787SSean Bruno 
10481e66f787SSean Bruno /*
10491e66f787SSean Bruno  * Function to register async callback for setting queue depth
10501e66f787SSean Bruno  */
10511e66f787SSean Bruno static void
10521e66f787SSean Bruno smartpqi_async(void *callback_arg, u_int32_t code,
10531e66f787SSean Bruno 		struct cam_path *path, void *arg)
10541e66f787SSean Bruno {
10551e66f787SSean Bruno 	struct pqisrc_softstate *softs;
10561e66f787SSean Bruno 	softs = (struct pqisrc_softstate*)callback_arg;
10571e66f787SSean Bruno 
10581e66f787SSean Bruno 	DBG_FUNC("IN\n");
10591e66f787SSean Bruno 
10601e66f787SSean Bruno 	switch (code) {
10611e66f787SSean Bruno 		case AC_FOUND_DEVICE:
10621e66f787SSean Bruno 		{
10631e66f787SSean Bruno 			struct ccb_getdev *cgd;
10641e66f787SSean Bruno 			cgd = (struct ccb_getdev *)arg;
10651e66f787SSean Bruno 			if (cgd == NULL) {
10661e66f787SSean Bruno 				break;
10671e66f787SSean Bruno 			}
10681e66f787SSean Bruno 			uint32_t t_id = cgd->ccb_h.target_id;
10691e66f787SSean Bruno 
10701e66f787SSean Bruno 			if (t_id <= (PQI_CTLR_INDEX - 1)) {
10711e66f787SSean Bruno 				if (softs != NULL) {
10721e66f787SSean Bruno 					pqi_scsi_dev_t *dvp = softs->device_list[t_id][cgd->ccb_h.target_lun];
10731e66f787SSean Bruno 					smartpqi_adjust_queue_depth(path,
10741e66f787SSean Bruno 							dvp->queue_depth);
10751e66f787SSean Bruno 				}
10761e66f787SSean Bruno 			}
10771e66f787SSean Bruno 			break;
10781e66f787SSean Bruno 		}
10791e66f787SSean Bruno 		default:
10801e66f787SSean Bruno 			break;
10811e66f787SSean Bruno 	}
10821e66f787SSean Bruno 
10831e66f787SSean Bruno 	DBG_FUNC("OUT\n");
10841e66f787SSean Bruno }
10851e66f787SSean Bruno 
10861e66f787SSean Bruno /*
10871e66f787SSean Bruno  * Function to register sim with CAM layer for smartpqi driver
10881e66f787SSean Bruno  */
10891e66f787SSean Bruno int register_sim(struct pqisrc_softstate *softs, int card_index)
10901e66f787SSean Bruno {
10911e66f787SSean Bruno 	int error = 0;
10921e66f787SSean Bruno 	int max_transactions;
10931e66f787SSean Bruno 	union ccb   *ccb = NULL;
10941e66f787SSean Bruno 	cam_status status = 0;
10951e66f787SSean Bruno 	struct ccb_setasync csa;
10961e66f787SSean Bruno 	struct cam_sim *sim;
10971e66f787SSean Bruno 
10981e66f787SSean Bruno 	DBG_FUNC("IN\n");
10991e66f787SSean Bruno 
11001e66f787SSean Bruno 	max_transactions = softs->max_io_for_scsi_ml;
11011e66f787SSean Bruno 	softs->os_specific.devq = cam_simq_alloc(max_transactions);
11021e66f787SSean Bruno 	if (softs->os_specific.devq == NULL) {
11031e66f787SSean Bruno 		DBG_ERR("cam_simq_alloc failed txns = %d\n",
11041e66f787SSean Bruno 			max_transactions);
11051e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
11061e66f787SSean Bruno 	}
11071e66f787SSean Bruno 
11081e66f787SSean Bruno 	sim = cam_sim_alloc(smartpqi_cam_action, \
11091e66f787SSean Bruno 				smartpqi_poll, "smartpqi", softs, \
11101e66f787SSean Bruno 				card_index, &softs->os_specific.cam_lock, \
11111e66f787SSean Bruno 				1, max_transactions, softs->os_specific.devq);
11121e66f787SSean Bruno 	if (sim == NULL) {
11131e66f787SSean Bruno 		DBG_ERR("cam_sim_alloc failed txns = %d\n",
11141e66f787SSean Bruno 			max_transactions);
11151e66f787SSean Bruno 		cam_simq_free(softs->os_specific.devq);
11161e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
11171e66f787SSean Bruno 	}
11181e66f787SSean Bruno 
11191e66f787SSean Bruno 	softs->os_specific.sim = sim;
11201e66f787SSean Bruno 	mtx_lock(&softs->os_specific.cam_lock);
11211e66f787SSean Bruno 	status = xpt_bus_register(sim, softs->os_specific.pqi_dev, 0);
11221e66f787SSean Bruno 	if (status != CAM_SUCCESS) {
11231e66f787SSean Bruno 		DBG_ERR("xpt_bus_register failed status=%d\n", status);
11241e66f787SSean Bruno 		cam_sim_free(softs->os_specific.sim, FALSE);
11251e66f787SSean Bruno 		cam_simq_free(softs->os_specific.devq);
11261e66f787SSean Bruno 		mtx_unlock(&softs->os_specific.cam_lock);
11271e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
11281e66f787SSean Bruno 	}
11291e66f787SSean Bruno 
11301e66f787SSean Bruno 	softs->os_specific.sim_registered = TRUE;
11311e66f787SSean Bruno 	ccb = xpt_alloc_ccb_nowait();
11321e66f787SSean Bruno 	if (ccb == NULL) {
11331e66f787SSean Bruno 		DBG_ERR("xpt_create_path failed\n");
11341e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
11351e66f787SSean Bruno 	}
11361e66f787SSean Bruno 
11371e66f787SSean Bruno 	if (xpt_create_path(&ccb->ccb_h.path, NULL,
11381e66f787SSean Bruno 			cam_sim_path(softs->os_specific.sim),
11391e66f787SSean Bruno 			CAM_TARGET_WILDCARD,
11401e66f787SSean Bruno 			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
11411e66f787SSean Bruno 		DBG_ERR("xpt_create_path failed\n");
11421e66f787SSean Bruno 		xpt_free_ccb(ccb);
11431e66f787SSean Bruno 		xpt_bus_deregister(cam_sim_path(softs->os_specific.sim));
11441e66f787SSean Bruno 		cam_sim_free(softs->os_specific.sim, TRUE);
11451e66f787SSean Bruno 		mtx_unlock(&softs->os_specific.cam_lock);
11461e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
11471e66f787SSean Bruno 	}
11481e66f787SSean Bruno 	/*
11491e66f787SSean Bruno  	 * Callback to set the queue depth per target which is
11501e66f787SSean Bruno 	 * derived from the FW.
11511e66f787SSean Bruno  	 */
11521e66f787SSean Bruno 	softs->os_specific.path = ccb->ccb_h.path;
11531e66f787SSean Bruno 	xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5);
11541e66f787SSean Bruno 	csa.ccb_h.func_code = XPT_SASYNC_CB;
11551e66f787SSean Bruno 	csa.event_enable = AC_FOUND_DEVICE;
11561e66f787SSean Bruno 	csa.callback = smartpqi_async;
11571e66f787SSean Bruno 	csa.callback_arg = softs;
11581e66f787SSean Bruno 	xpt_action((union ccb *)&csa);
11591e66f787SSean Bruno 	if (csa.ccb_h.status != CAM_REQ_CMP) {
11601e66f787SSean Bruno 		DBG_ERR("Unable to register smartpqi_aysnc handler: %d!\n",
11611e66f787SSean Bruno 			csa.ccb_h.status);
11621e66f787SSean Bruno 	}
11631e66f787SSean Bruno 
11641e66f787SSean Bruno 	mtx_unlock(&softs->os_specific.cam_lock);
11651e66f787SSean Bruno 	DBG_INFO("OUT\n");
11661e66f787SSean Bruno 	return error;
11671e66f787SSean Bruno }
11681e66f787SSean Bruno 
11691e66f787SSean Bruno /*
11701e66f787SSean Bruno  * Function to deregister smartpqi sim from cam layer
11711e66f787SSean Bruno  */
11721e66f787SSean Bruno void deregister_sim(struct pqisrc_softstate *softs)
11731e66f787SSean Bruno {
11741e66f787SSean Bruno 	struct ccb_setasync csa;
11751e66f787SSean Bruno 
11761e66f787SSean Bruno 	DBG_FUNC("IN\n");
11771e66f787SSean Bruno 
11781e66f787SSean Bruno 	if (softs->os_specific.mtx_init) {
11791e66f787SSean Bruno 		mtx_lock(&softs->os_specific.cam_lock);
11801e66f787SSean Bruno 	}
11811e66f787SSean Bruno 
11821e66f787SSean Bruno 
11831e66f787SSean Bruno 	xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5);
11841e66f787SSean Bruno 	csa.ccb_h.func_code = XPT_SASYNC_CB;
11851e66f787SSean Bruno 	csa.event_enable = 0;
11861e66f787SSean Bruno 	csa.callback = smartpqi_async;
11871e66f787SSean Bruno 	csa.callback_arg = softs;
11881e66f787SSean Bruno 	xpt_action((union ccb *)&csa);
11891e66f787SSean Bruno 	xpt_free_path(softs->os_specific.path);
11901e66f787SSean Bruno 
11911e66f787SSean Bruno 	xpt_release_simq(softs->os_specific.sim, 0);
11921e66f787SSean Bruno 
11931e66f787SSean Bruno 	xpt_bus_deregister(cam_sim_path(softs->os_specific.sim));
11941e66f787SSean Bruno 	softs->os_specific.sim_registered = FALSE;
11951e66f787SSean Bruno 
11961e66f787SSean Bruno 	if (softs->os_specific.sim) {
11971e66f787SSean Bruno 		cam_sim_free(softs->os_specific.sim, FALSE);
11981e66f787SSean Bruno 		softs->os_specific.sim = NULL;
11991e66f787SSean Bruno 	}
12001e66f787SSean Bruno 	if (softs->os_specific.mtx_init) {
12011e66f787SSean Bruno 		mtx_unlock(&softs->os_specific.cam_lock);
12021e66f787SSean Bruno 	}
12031e66f787SSean Bruno 	if (softs->os_specific.devq != NULL) {
12041e66f787SSean Bruno 		cam_simq_free(softs->os_specific.devq);
12051e66f787SSean Bruno 	}
12061e66f787SSean Bruno 	if (softs->os_specific.mtx_init) {
12071e66f787SSean Bruno 		mtx_destroy(&softs->os_specific.cam_lock);
12081e66f787SSean Bruno 		softs->os_specific.mtx_init = FALSE;
12091e66f787SSean Bruno 	}
12101e66f787SSean Bruno 
12111e66f787SSean Bruno 	mtx_destroy(&softs->os_specific.map_lock);
12121e66f787SSean Bruno 
12131e66f787SSean Bruno 	DBG_FUNC("OUT\n");
12141e66f787SSean Bruno }
1215