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