diff --git a/share/man/man4/smartpqi.4 b/share/man/man4/smartpqi.4 --- a/share/man/man4/smartpqi.4 +++ b/share/man/man4/smartpqi.4 @@ -1,5 +1,7 @@ -.\" Copyright (c) 2018 Murthy Bhat -.\" All rights reserved. +.\" Copyright (C) 2019-2023, Microchip Technology Inc. and its subsidiaries +.\" Copyright (C) 2016-2018, Microsemi Corporation +.\" Copyright (C) 2016, PMC-Sierra, Inc. +.\" Written by John Hall .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -22,25 +24,23 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD$ stable/10/share/man/man4/smartpqi.4 195614 2017-01-11 08:10:18Z jkim $ -.Dd April 6, 2018 +.\" $Id$ +.Dd $Mdocdate$ .Dt SMARTPQI 4 .Os .Sh NAME .Nm smartpqi -.Nd Microsemi smartpqi SCSI driver for PQI controllers +.Nd "Microchip Smart Storage SCSI driver" .Sh SYNOPSIS -To compile this driver into the kernel, -place the following lines in your -kernel configuration file: +To compile this driver into the kernel, place these lines in the kernel +configuration file: .Bd -ragged -offset indent .Cd device pci .Cd device scbus .Cd device smartpqi .Ed .Pp -Alternatively, to load the driver as a -module at boot time, place the following line in +The driver can be loaded as a module at boot time by placing this line in .Xr loader.conf 5 : .Bd -literal -offset indent smartpqi_load="YES" @@ -48,36 +48,33 @@ .Sh DESCRIPTION The .Nm -SCSI driver provides support for the new generation of PQI controllers from -Microsemi. -The -.Nm -driver is the first SCSI driver to implement the PQI queuing model. -.Pp -The -.Nm -driver will replace the aacraid driver for Adaptec Series 9 controllers. -.Pp -The -.Pa /dev/smartpqi? -device nodes provide access to the management interface of the controller. -One node exists per installed card. +driver provides support for Microchip Technology Inc. / Adaptec SmartRaid and +SmartHBA SATA/SAS/NVME PCIe controllers .Sh HARDWARE Controllers supported by the .Nm -driver include: +driver include, but not limited to: .Pp .Bl -bullet -compact .It HPE Gen10 Smart Array Controller Family .It -OEM Controllers based on the Microsemi Chipset +Adaptec SmartRaid and SmartHBA Controllers +.It +OEM Controllers based on the Microchip Technology Inc. SmartROC +and SmartIOC Chipsets .El .Sh FILES -.Bl -tag -width /boot/kernel/aac.ko -compact +.Bl -tag -width /boot/kernel/smartpqi.ko -compact .It Pa /dev/smartpqi? smartpqi management interface .El +.Sh NOTES +.Ss Configuration +To configure a Microchip Smart Storage controller, +refer to the User Guide for the controller, +which can be found by searching for the specific controller at +https://www.microchip.com/design-centers/storage .Sh SEE ALSO .Xr kld 4 , .Xr linux 4 , @@ -87,17 +84,13 @@ .Xr loader.conf 5 , .Xr camcontrol 8 , .Xr kldload 8 -.Rs -.%T "Microsemi Website" -.%U https://www.microsemi.com/ -.Re .Sh HISTORY The .Nm driver first appeared in .Fx 11.1 . .Sh AUTHORS -.An Murthy Bhat -.Aq murthy.bhat@microsemi.com +.An John Hall +.Aq john.hall@microchip.com .Sh BUGS The controller is not actually paused on suspend/resume. diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -372,6 +372,7 @@ dev/smartpqi/smartpqi_cmd.c optional smartpqi dev/smartpqi/smartpqi_discovery.c optional smartpqi dev/smartpqi/smartpqi_event.c optional smartpqi +dev/smartpqi/smartpqi_features.c optional smartpqi dev/smartpqi/smartpqi_helper.c optional smartpqi dev/smartpqi/smartpqi_init.c optional smartpqi dev/smartpqi/smartpqi_intr.c optional smartpqi diff --git a/sys/dev/smartpqi/smartpqi_cam.c b/sys/dev/smartpqi/smartpqi_cam.c --- a/sys/dev/smartpqi/smartpqi_cam.c +++ b/sys/dev/smartpqi/smartpqi_cam.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -49,12 +49,15 @@ cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; cpi->hba_eng_cnt = 0; cpi->max_lun = PQI_MAX_MULTILUN; - cpi->max_target = 1088; + cpi->max_target = MAX_TARGET_DEVICES; cpi->maxio = (softs->pqi_cap.max_sg_elem - 1) * PAGE_SIZE; cpi->initiator_id = 255; - strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); - strlcpy(cpi->hba_vid, "Microsemi", HBA_IDLEN); - strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN-1); + cpi->sim_vid[sizeof(cpi->sim_vid)-1] = '\0'; + strncpy(cpi->hba_vid, "Microsemi", HBA_IDLEN-1); + cpi->hba_vid[sizeof(cpi->hba_vid)-1] = '\0'; + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN-1); + cpi->dev_name[sizeof(cpi->dev_name)-1] = '\0'; cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = cam_sim_bus(sim); cpi->base_transfer_speed = 1200000; /* Base bus speed in KB/sec */ @@ -73,7 +76,7 @@ } /* - * Get transport settings of the smartpqi adapter + * Get transport settings of the smartpqi adapter. */ static void get_transport_settings(struct pqisrc_softstate *softs, @@ -84,7 +87,7 @@ struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; DBG_FUNC("IN\n"); - + cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_SPC4; cts->transport = XPORT_SPI; @@ -106,10 +109,12 @@ os_add_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { union ccb *ccb; + uint64_t lun; DBG_FUNC("IN\n"); - if(softs->os_specific.sim_registered) { + lun = (device->is_multi_lun) ? CAM_LUN_WILDCARD : device->lun; + if(softs->os_specific.sim_registered) { if ((ccb = xpt_alloc_ccb_nowait()) == NULL) { DBG_ERR("rescan failed (can't allocate CCB)\n"); return; @@ -117,7 +122,7 @@ if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(softs->os_specific.sim), - device->target, device->lun) != CAM_REQ_CMP) { + device->target, lun) != CAM_REQ_CMP) { DBG_ERR("rescan failed (can't create path)\n"); xpt_free_ccb(ccb); return; @@ -134,20 +139,25 @@ void os_remove_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { - struct cam_path *tmppath; + struct cam_path *tmppath = NULL; + uint64_t lun; DBG_FUNC("IN\n"); - + + lun = (device->is_multi_lun) ? CAM_LUN_WILDCARD : device->lun; if(softs->os_specific.sim_registered) { - if (xpt_create_path(&tmppath, NULL, + if (xpt_create_path(&tmppath, NULL, cam_sim_path(softs->os_specific.sim), - device->target, device->lun) != CAM_REQ_CMP) { - DBG_ERR("unable to create path for async event"); + device->target, lun) != CAM_REQ_CMP) { + DBG_ERR("unable to create path for async event\n"); return; } xpt_async(AC_LOST_DEVICE, tmppath, NULL); xpt_free_path(tmppath); - softs->device_list[device->target][device->lun] = NULL; + /* softs->device_list[device->target][device->lun] = NULL; */ + int index = pqisrc_find_device_list_index(softs,device); + if (index >= 0 && index < PQI_MAX_DEVICES) + softs->dev_list[index] = NULL; pqisrc_free_device(softs, device); } @@ -191,22 +201,20 @@ return; if (rcb->bcount != 0 ) { - if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE) + if ((rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, - rcb->cm_datamap, - BUS_DMASYNC_POSTREAD); - if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE) + rcb->cm_datamap,BUS_DMASYNC_POSTREAD); + if ((rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, - rcb->cm_datamap, - BUS_DMASYNC_POSTWRITE); + rcb->cm_datamap,BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(softs->os_specific.pqi_buffer_dmat, - rcb->cm_datamap); + rcb->cm_datamap); } rcb->cm_flags &= ~PQI_CMD_MAPPED; if(rcb->sgt && rcb->nseg) os_mem_free(rcb->softs, (void*)rcb->sgt, - rcb->nseg*sizeof(sgt_t)); + rcb->nseg*sizeof(sgt_t)); DBG_IO("OUT\n"); } @@ -242,6 +250,7 @@ cdb = (csio->ccb_h.flags & CAM_CDB_POINTER) ? (uint8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes; + if(cdb[0] == INQUIRY && (cdb[1] & SI_EVPD) == 0 && (csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN && @@ -249,23 +258,31 @@ inq = (struct scsi_inquiry_data *)csio->data_ptr; - device = softs->device_list[csio->ccb_h.target_id][csio->ccb_h.target_lun]; + /* device = softs->device_list[csio->ccb_h.target_id][csio->ccb_h.target_lun]; */ + int target = csio->ccb_h.target_id; + int lun = csio->ccb_h.target_lun; + int index = pqisrc_find_btl_list_index(softs,softs->bus_id,target,lun); + if (index != INVALID_ELEM) + device = softs->dev_list[index]; /* Let the disks be probed and dealt with via CAM. Only for LD let it fall through and inquiry be tweaked */ - if (!device || !pqisrc_is_logical_device(device) || - (device->devtype != DISK_DEVICE) || + if( !device || !pqisrc_is_logical_device(device) || + (device->devtype != DISK_DEVICE) || pqisrc_is_external_raid_device(device)) { return; } strncpy(inq->vendor, device->vendor, - SID_VENDOR_SIZE); + SID_VENDOR_SIZE-1); + inq->vendor[sizeof(inq->vendor)-1] = '\0'; strncpy(inq->product, pqisrc_raidlevel_to_string(device->raid_level), - SID_PRODUCT_SIZE); + SID_PRODUCT_SIZE-1); + inq->product[sizeof(inq->product)-1] = '\0'; strncpy(inq->revision, device->volume_offline?"OFF":"OK", - SID_REVISION_SIZE); + SID_REVISION_SIZE-1); + inq->revision[sizeof(inq->revision)-1] = '\0'; } DBG_FUNC("OUT\n"); @@ -308,7 +325,7 @@ if (csio == NULL) panic("csio is null"); - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; csio->ccb_h.status = CAM_REQ_CMP; pqi_complete_scsi_io(csio, rcb); @@ -383,10 +400,11 @@ uint8_t *sense_data = NULL; if (sense_data_len) sense_data = err_info->data; + copy_sense_data_to_csio(csio, sense_data, sense_data_len); csio->ccb_h.status = CAM_SCSI_STATUS_ERROR - | CAM_AUTOSNS_VALID - | CAM_REQ_CMP_ERR; + | CAM_AUTOSNS_VALID + | CAM_REQ_CMP_ERR; } break; @@ -425,7 +443,7 @@ if (rcb == NULL) panic("rcb is null"); - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio; if (csio == NULL) panic("csio is null"); @@ -462,7 +480,7 @@ /* Timed out TMF response comes here */ if (rcb->tm_req) { rcb->req_pending = false; - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; DBG_ERR("AIO Disabled for TMF\n"); return; } @@ -484,14 +502,14 @@ case PQI_AIO_SERV_RESPONSE_TMF_SUCCEEDED: DBG_ERR("PQI_AIO_SERV_RESPONSE_TMF %s\n", (err_info->service_resp == PQI_AIO_SERV_RESPONSE_TMF_COMPLETE) ? "COMPLETE" : "SUCCEEDED"); - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; rcb->req_pending = false; return; case PQI_AIO_SERV_RESPONSE_TMF_REJECTED: case PQI_AIO_SERV_RESPONSE_TMF_INCORRECT_LUN: DBG_ERR("PQI_AIO_SERV_RESPONSE_TMF %s\n", (err_info->service_resp == PQI_AIO_SERV_RESPONSE_TMF_REJECTED) ? "REJECTED" : "INCORRECT LUN"); - rcb->status = REQUEST_FAILED; + rcb->status = PQI_STATUS_TIMEOUT; rcb->req_pending = false; return; default: @@ -536,8 +554,9 @@ pqisrc_softstate_t *softs = rcb->softs; union ccb *ccb; - if (error || nseg > softs->pqi_cap.max_sg_elem) { - DBG_ERR_BTL(rcb->dvp, "map failed err = %d or nseg(%d) > sgelem(%d)\n", + if (error || nseg > softs->pqi_cap.max_sg_elem) + { + DBG_ERR_BTL(rcb->dvp, "map failed err = %d or nseg(%d) > sgelem(%u)\n", error, nseg, softs->pqi_cap.max_sg_elem); goto error_io; } @@ -556,15 +575,15 @@ rcb->sgt[i].flags = 0; } - if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE) - bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, - rcb->cm_datamap, BUS_DMASYNC_PREREAD); - if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE) - bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, - rcb->cm_datamap, BUS_DMASYNC_PREWRITE); + if ((rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, + rcb->cm_datamap, BUS_DMASYNC_PREREAD); + if ((rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat, + rcb->cm_datamap, BUS_DMASYNC_PREWRITE); /* Call IO functions depending on pd or ld */ - rcb->status = REQUEST_PENDING; + rcb->status = PQI_STATUS_FAILURE; error = pqisrc_build_send_io(softs, rcb); @@ -607,7 +626,7 @@ bsd_status = bus_dmamap_load_ccb(softs->os_specific.pqi_buffer_dmat, rcb->cm_datamap, ccb, pqi_request_map_helper, rcb, 0); if (bsd_status != BSD_SUCCESS && bsd_status != EINPROGRESS) { - DBG_ERR_BTL(rcb->dvp, "bus_dmamap_load_ccb failed, return status = %d transfer length = %d\n", + DBG_ERR_BTL(rcb->dvp, "bus_dmamap_load_ccb failed, return status = %d transfer length = %u\n", bsd_status, rcb->bcount); return bsd_status; } @@ -618,7 +637,7 @@ * busdma. */ /* Call IO functions depending on pd or ld */ - rcb->status = REQUEST_PENDING; + rcb->status = PQI_STATUS_FAILURE; if (pqisrc_build_send_io(softs, rcb) != PQI_STATUS_SUCCESS) { bsd_status = EIO; @@ -695,7 +714,7 @@ return; } - bzero(ccb, sizeof(union ccb)); + memset(ccb, 0, sizeof(union ccb)); xpt_setup_ccb(&ccb->ccb_h, path, 5); ccb->ccb_h.func_code = XPT_SCAN_LUN; ccb->ccb_h.cbfcnp = smartpqi_lunrescan_cb; @@ -712,15 +731,17 @@ void smartpqi_target_rescan(struct pqisrc_softstate *softs) { - int target = 0, lun = 0; + pqi_scsi_dev_t *device; + int index; DBG_FUNC("IN\n"); - for(target = 0; target < PQI_MAX_DEVICES; target++){ - for(lun = 0; lun < PQI_MAX_MULTILUN; lun++){ - if(softs->device_list[target][lun]){ - smartpqi_lun_rescan(softs, target, lun); - } + for(index = 0; index < PQI_MAX_DEVICES; index++){ + /* if(softs->device_list[target][lun]){ */ + if(softs->dev_list[index] != NULL) { + device = softs->dev_list[index]; + DBG_INFO("calling smartpqi_lun_rescan with TL = %d:%d\n",device->target,device->lun); + smartpqi_lun_rescan(softs, device->target, device->lun); } } @@ -758,7 +779,7 @@ os_complete_outstanding_cmds_nodevice(pqisrc_softstate_t *softs) { int tag = 0; - pqi_scsi_dev_t *dvp = NULL; + pqi_scsi_dev_t *dvp = NULL; DBG_FUNC("IN\n"); @@ -771,7 +792,6 @@ pqi_complete_scsi_io(&prcb->cm_ccb->csio, prcb); if (dvp) pqisrc_decrement_device_active_io(softs, dvp); - } } @@ -785,21 +805,36 @@ pqisrc_io_start(struct cam_sim *sim, union ccb *ccb) { rcb_t *rcb; - uint32_t tag, no_transfer = 0; + uint32_t tag; pqisrc_softstate_t *softs = (struct pqisrc_softstate *) cam_sim_softc(sim); int32_t error; pqi_scsi_dev_t *dvp; + int target, lun, index; DBG_FUNC("IN\n"); - if (softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun] == NULL) { + /* if( softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun] == NULL ) { */ + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + index = pqisrc_find_btl_list_index(softs,softs->bus_id,target,lun); + + if (index == INVALID_ELEM) { + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + DBG_INFO("Invalid index/device!!!, Device BTL %u:%d:%d\n", softs->bus_id, target, lun); + return ENXIO; + } + + if( softs->dev_list[index] == NULL ) { ccb->ccb_h.status = CAM_DEV_NOT_THERE; DBG_INFO("Device = %d not there\n", ccb->ccb_h.target_id); return ENXIO; } - dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; + /* DBG_INFO("starting IO on BTL = %d:%d:%d index = %d\n",softs->bus_id,target,lun,index); */ + + /* dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; */ + dvp = softs->dev_list[index]; /* Check controller state */ if (IN_PQI_RESET(softs)) { ccb->ccb_h.status = CAM_SCSI_BUS_RESET @@ -827,7 +862,7 @@ } tag = pqisrc_get_tag(&softs->taglist); - if (tag == INVALID_ELEM) { + if( tag == INVALID_ELEM ) { DBG_ERR("Get Tag failed\n"); xpt_freeze_simq(softs->os_specific.sim, 1); softs->os_specific.pqi_flags |= PQI_FLAG_BUSY; @@ -835,7 +870,7 @@ return EIO; } - DBG_IO("tag = %d &softs->taglist : %p\n", tag, &softs->taglist); + DBG_IO("tag = %u &softs->taglist : %p\n", tag, &softs->taglist); rcb = &softs->rcb[tag]; os_reset_rcb(rcb); @@ -844,30 +879,13 @@ rcb->cmdlen = ccb->csio.cdb_len; ccb->ccb_h.sim_priv.entries[0].ptr = rcb; - switch (ccb->ccb_h.flags & CAM_DIR_MASK) { - case CAM_DIR_IN: - rcb->data_dir = SOP_DATA_DIR_FROM_DEVICE; - break; - case CAM_DIR_OUT: - rcb->data_dir = SOP_DATA_DIR_TO_DEVICE; - break; - case CAM_DIR_NONE: - no_transfer = 1; - break; - default: - DBG_ERR("Unknown Dir\n"); - break; - } rcb->cm_ccb = ccb; - rcb->dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; + /* rcb->dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; */ + rcb->dvp = softs->dev_list[index]; + + rcb->cm_data = (void *)ccb->csio.data_ptr; + rcb->bcount = ccb->csio.dxfer_len; - if (!no_transfer) { - rcb->cm_data = (void *)ccb->csio.data_ptr; - rcb->bcount = ccb->csio.dxfer_len; - } else { - rcb->cm_data = NULL; - rcb->bcount = 0; - } /* * Submit the request to the adapter. * @@ -900,7 +918,7 @@ pqi_tmf_status_to_bsd_tmf_status(int pqi_status, rcb_t *rcb) { if (PQI_STATUS_SUCCESS == pqi_status && - REQUEST_SUCCESS == rcb->status) + PQI_STATUS_SUCCESS == rcb->status) return BSD_SUCCESS; else return EIO; @@ -912,8 +930,8 @@ static int pqisrc_scsi_abort_task(pqisrc_softstate_t *softs, union ccb *ccb) { - struct ccb_hdr *ccb_h = &ccb->ccb_h; rcb_t *rcb = NULL; + struct ccb_hdr *ccb_h = &ccb->ccb_h; rcb_t *prcb = ccb->ccb_h.sim_priv.entries[0].ptr; uint32_t tag; int rval; @@ -924,7 +942,7 @@ rcb = &softs->rcb[tag]; rcb->tag = tag; - if (!rcb->dvp) { + if (rcb->dvp == NULL) { DBG_ERR("dvp is null, tmf type : 0x%x\n", ccb_h->func_code); rval = ENXIO; goto error_tmf; @@ -963,8 +981,9 @@ tag = pqisrc_get_tag(&softs->taglist); rcb = &softs->rcb[tag]; rcb->tag = tag; + rcb->cm_ccb = ccb; - if (!rcb->dvp) { + if (rcb->dvp == NULL) { DBG_ERR("dvp is null, tmf type : 0x%x\n", ccb_h->func_code); rval = ENXIO; goto error_tmf; @@ -992,24 +1011,38 @@ static int pqisrc_target_reset( pqisrc_softstate_t *softs, union ccb *ccb) { + + /* pqi_scsi_dev_t *devp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; */ struct ccb_hdr *ccb_h = &ccb->ccb_h; - pqi_scsi_dev_t *devp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun]; rcb_t *rcb = NULL; uint32_t tag; int rval; + int bus, target, lun; + int index; + DBG_FUNC("IN\n"); + bus = softs->bus_id; + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + + index = pqisrc_find_btl_list_index(softs,bus,target,lun); + if (index == INVALID_ELEM) { + DBG_ERR("device not found at BTL %d:%d:%d\n",bus,target,lun); + return (-1); + } + + pqi_scsi_dev_t *devp = softs->dev_list[index]; if (devp == NULL) { DBG_ERR("bad target %d, tmf type : 0x%x\n", ccb_h->target_id, ccb_h->func_code); - return ENXIO; + return (-1); } tag = pqisrc_get_tag(&softs->taglist); rcb = &softs->rcb[tag]; rcb->tag = tag; - - devp->reset_in_progress = true; + rcb->cm_ccb = ccb; rcb->tm_req = true; @@ -1017,6 +1050,7 @@ SOP_TASK_MANAGEMENT_LUN_RESET); rval = pqi_tmf_status_to_bsd_tmf_status(rval, rcb); + devp->reset_in_progress = false; os_reset_rcb(rcb); @@ -1137,9 +1171,9 @@ { struct ccb_relsim crs; - DBG_INFO("IN\n"); + DBG_FUNC("IN\n"); - memset(&crs, 0, sizeof(crs)); + memset(&crs, 0, sizeof(struct ccb_relsim)); xpt_setup_ccb(&crs.ccb_h, path, 5); crs.ccb_h.func_code = XPT_REL_SIMQ; crs.ccb_h.flags = CAM_DEV_QFREEZE; @@ -1150,7 +1184,7 @@ printf("XPT_REL_SIMQ failed stat=%d\n", crs.ccb_h.status); } - DBG_INFO("OUT\n"); + DBG_FUNC("OUT\n"); } /* @@ -1175,15 +1209,20 @@ } uint32_t t_id = cgd->ccb_h.target_id; - if (t_id <= (PQI_CTLR_INDEX - 1)) { + /* if (t_id <= (PQI_CTLR_INDEX - 1)) { */ + if (t_id >= PQI_CTLR_INDEX) { if (softs != NULL) { - pqi_scsi_dev_t *dvp = softs->device_list[t_id][cgd->ccb_h.target_lun]; - if (dvp == NULL) { - DBG_ERR("Target is null, target id=%d\n", t_id); - break; + /* pqi_scsi_dev_t *dvp = softs->device_list[t_id][cgd->ccb_h.target_lun]; */ + int lun = cgd->ccb_h.target_lun; + int index = pqisrc_find_btl_list_index(softs,softs->bus_id,t_id,lun); + if (index != INVALID_ELEM) { + pqi_scsi_dev_t *dvp = softs->dev_list[index]; + if (dvp == NULL) { + DBG_ERR("Target is null, target id=%u\n", t_id); + break; + } + smartpqi_adjust_queue_depth(path, dvp->queue_depth); } - smartpqi_adjust_queue_depth(path, - dvp->queue_depth); } } break; @@ -1203,7 +1242,7 @@ { int max_transactions; union ccb *ccb = NULL; - int error; + cam_status status = 0; struct ccb_setasync csa; struct cam_sim *sim; @@ -1230,9 +1269,9 @@ softs->os_specific.sim = sim; mtx_lock(&softs->os_specific.cam_lock); - error = xpt_bus_register(sim, softs->os_specific.pqi_dev, 0); - if (error != CAM_SUCCESS) { - DBG_ERR("xpt_bus_register failed errno %d\n", error); + status = xpt_bus_register(sim, softs->os_specific.pqi_dev, 0); + if (status != CAM_SUCCESS) { + DBG_ERR("xpt_bus_register failed status=%d\n", status); cam_sim_free(softs->os_specific.sim, FALSE); cam_simq_free(softs->os_specific.devq); mtx_unlock(&softs->os_specific.cam_lock); @@ -1258,11 +1297,11 @@ return ENXIO; } /* - * Callback to set the queue depth per target which is + * Callback to set the queue depth per target which is * derived from the FW. - */ + */ softs->os_specific.path = ccb->ccb_h.path; - memset(&csa, 0, sizeof(csa)); + memset(&csa, 0, sizeof(struct ccb_setasync)); xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_FOUND_DEVICE; @@ -1270,12 +1309,12 @@ csa.callback_arg = softs; xpt_action((union ccb *)&csa); if (csa.ccb_h.status != CAM_REQ_CMP) { - DBG_ERR("Unable to register smartpqi_aysnc handler: %d!\n", + DBG_ERR("Unable to register smartpqi_aysnc handler: %d!\n", csa.ccb_h.status); } mtx_unlock(&softs->os_specific.cam_lock); - DBG_INFO("OUT\n"); + DBG_FUNC("OUT\n"); return BSD_SUCCESS; } @@ -1287,15 +1326,14 @@ deregister_sim(struct pqisrc_softstate *softs) { struct ccb_setasync csa; - + DBG_FUNC("IN\n"); if (softs->os_specific.mtx_init) { mtx_lock(&softs->os_specific.cam_lock); } - - memset(&csa, 0, sizeof(csa)); + memset(&csa, 0, sizeof(struct ccb_setasync)); xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = 0; @@ -1331,23 +1369,23 @@ void os_rescan_target(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { - struct cam_path *tmppath; + struct cam_path *tmppath = NULL; - DBG_FUNC("IN\n"); + DBG_FUNC("IN\n"); - if(softs->os_specific.sim_registered) { - if (xpt_create_path(&tmppath, NULL, - cam_sim_path(softs->os_specific.sim), - device->target, device->lun) != CAM_REQ_CMP) { - DBG_ERR("unable to create path for async event!!! Bus: %d Target: %d Lun: %d\n", - device->bus, device->target, device->lun); - return; - } - xpt_async(AC_INQ_CHANGED, tmppath, NULL); - xpt_free_path(tmppath); - } + if(softs->os_specific.sim_registered) { + if (xpt_create_path(&tmppath, NULL, + cam_sim_path(softs->os_specific.sim), + device->target, device->lun) != CAM_REQ_CMP) { + DBG_ERR("unable to create path for async event!!! Bus: %d Target: %d Lun: %d\n", + device->bus, device->target, device->lun); + return; + } + xpt_async(AC_INQ_CHANGED, tmppath, NULL); + xpt_free_path(tmppath); + } - device->scsi_rescan = false; + device->scsi_rescan = false; - DBG_FUNC("OUT\n"); + DBG_FUNC("OUT\n"); } diff --git a/sys/dev/smartpqi/smartpqi_cmd.c b/sys/dev/smartpqi/smartpqi_cmd.c --- a/sys/dev/smartpqi/smartpqi_cmd.c +++ b/sys/dev/smartpqi/smartpqi_cmd.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,10 +36,14 @@ char *slot = NULL; uint32_t offset; iu_header_t *hdr = (iu_header_t *)req; + /*TODO : Can be fixed a size copying of IU ? */ uint32_t iu_len = hdr->iu_length + 4 ; /* header size */ int i = 0; DBG_FUNC("IN\n"); + /* The code below assumes we only take 1 element (no spanning) */ + ASSERT(iu_len <= ib_q->elem_size); + PQI_LOCK(&ib_q->lock); /* Check queue full */ @@ -55,15 +59,15 @@ /* Copy the IU */ memcpy(slot, req, iu_len); - DBG_INFO("IU : \n"); + DBG_IO("IU : \n"); for(i = 0; i< iu_len; i++) - DBG_INFO(" IU [ %d ] : %x\n", i, *((unsigned char *)(slot + i))); + DBG_IO(" IU [ %d ] : %x\n", i, *((unsigned char *)(slot + i))); /* Update the local PI */ ib_q->pi_local = (ib_q->pi_local + 1) % ib_q->num_elem; - DBG_INFO("ib_q->pi_local : %x IU size : %d\n", + DBG_IO("ib_q->pi_local : %x IU size : %d\n", ib_q->pi_local, hdr->iu_length); - DBG_INFO("*ib_q->ci_virt_addr: %x\n", + DBG_IO("*ib_q->ci_virt_addr: %x\n", *(ib_q->ci_virt_addr)); /* Inform the fw about the new IU */ diff --git a/sys/dev/smartpqi/smartpqi_defines.h b/sys/dev/smartpqi/smartpqi_defines.h --- a/sys/dev/smartpqi/smartpqi_defines.h +++ b/sys/dev/smartpqi/smartpqi_defines.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,34 +27,65 @@ #ifndef _PQI_DEFINES_H #define _PQI_DEFINES_H -#define PQI_STATUS_FAILURE -1 -#define PQI_STATUS_TIMEOUT -2 -#define PQI_STATUS_QFULL -3 -#define PQI_STATUS_SUCCESS 0 +#define SIS_POLL_WAIT +#define DEVICE_HINT + +#ifndef CT_ASSERT +/* If the OS hasn't specified a preferred compile time assert, create one */ +#if !defined(__C_ASSERT__) + #define CT_ASSERT(e) extern char __assert_test_case[1 - (2*(!(e)))] +#else + #define CT_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#endif +#endif +#define PQI_STATUS_FAILURE -1 +#define PQI_STATUS_TIMEOUT -2 +#define PQI_STATUS_QFULL -3 +#define PQI_STATUS_SUCCESS 0 + +#define BITS_PER_BYTE 8 +#define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0 +#define PQI_VENDOR_GENERAL_HOST_MEMORY_UPDATE 1 +#define PQI_REQUEST_HEADER_LENGTH 4 /* Maximum timeout for internal command completion */ -#define TIMEOUT_INFINITE ((uint32_t) (-1)) -#define PQISRC_CMD_TIMEOUT TIMEOUT_INFINITE +#define TIMEOUT_INFINITE ((uint32_t) (-1)) +#define PQISRC_CMD_TIMEOUT TIMEOUT_INFINITE #define PQISRC_PASSTHROUGH_CMD_TIMEOUT PQISRC_CMD_TIMEOUT /* Delay in milli seconds */ -#define PQISRC_TMF_TIMEOUT (OS_TMF_TIMEOUT_SEC * 1000) +#define PQISRC_TMF_TIMEOUT (OS_TMF_TIMEOUT_SEC * 1000) /* Delay in micro seconds */ -#define PQISRC_PENDING_IO_TIMEOUT_USEC 30000000 /* 30 seconds */ +#define PQISRC_PENDING_IO_TIMEOUT_USEC 30000000 /* 30 seconds */ /* If want to disable atomic operations on device active io, then set to zero */ -#define PQISRC_DEVICE_IO_COUNTER 1 +#define PQISRC_DEVICE_IO_COUNTER 1 + +/* #define SHARE_EVENT_QUEUE_FOR_IO 1 */ -#define INVALID_ELEM 0xffff +#define INVALID_ELEM 0xffff #ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/* defines for stream detection */ +#define TICKS ticks + +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFFF #endif -#define PQISRC_ROUNDUP(x, y) (((x) + (y) - 1) / (y) * (y)) -#define PQISRC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) +#define PQISRC_ROUND_UP(x, y) (((x) + (y) - 1) / (y) * (y)) +#define PQISRC_ROUND_DOWN(x, y) (((x) / (y)) * (y)) +#define PQISRC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) + +#if !defined(offsetofend) +#define offsetofend(TYPE, MEMBER) \ + (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER)) +#endif #define ALIGN_BOUNDARY(a, n) { \ if (a % n) \ @@ -98,7 +129,7 @@ LOCK_SLEEP }; -#define LOCKNAME_SIZE 32 +#define LOCKNAME_SIZE 32 #define INTR_TYPE_NONE 0x0 #define INTR_TYPE_FIXED 0x1 @@ -108,17 +139,12 @@ #define SIS_ENABLE_INTX 0x80 #define PQISRC_LEGACY_INTX_MASK 0x1 -#define DMA_TO_VIRT(mem) ((mem)->virt_addr) -#define DMA_PHYS_LOW(mem) (((mem)->dma_addr) & 0x00000000ffffffff) -#define DMA_PHYS_HIGH(mem) ((((mem)->dma_addr) & 0xffffffff00000000) >> 32) - +#define DMA_TO_VIRT(mem) ((mem)->virt_addr) +#define DMA_PHYS_LOW(mem) (((mem)->dma_addr) & 0x00000000ffffffff) +#define DMA_PHYS_HIGH(mem) ((((mem)->dma_addr) & 0xffffffff00000000) >> 32) -typedef enum REQUEST_STATUS { - REQUEST_SUCCESS = 0, - REQUEST_PENDING = -1, - REQUEST_FAILED = -2, -}REQUEST_STATUS_T; typedef enum IO_PATH { + UNKNOWN_PATH, AIO_PATH, RAID_PATH }IO_PATH_T; @@ -179,44 +205,84 @@ #define PQI_CTRL_KERNEL_UP_AND_RUNNING 0x80 #define PQI_CTRL_KERNEL_PANIC 0x100 -#define SIS_CTL_TO_HOST_DB_DISABLE_ALL 0xFFFFFFFF -#define SIS_CTL_TO_HOST_DB_CLEAR 0x00001000 -#define SIS_CMD_SUBMIT 0x00000200 /* Bit 9 */ -#define SIS_CMD_COMPLETE 0x00001000 /* Bit 12 */ +#define SIS_CTL_TO_HOST_DB_DISABLE_ALL 0xFFFFFFFF +#define SIS_CTL_TO_HOST_DB_CLEAR 0x00001000 +#define SIS_CMD_SUBMIT 0x00000200 /* Bit 9 */ +#define SIS_CMD_COMPLETE 0x00001000 /* Bit 12 */ #define SIS_CMD_STATUS_SUCCESS 0x1 /* PQI specific */ /* defines */ -#define PQISRC_PQI_REG_OFFSET 0x4000 -#define PQISRC_MAX_OUTSTANDING_REQ 4096 -#define PQISRC_MAX_ADMIN_IB_QUEUE_ELEM_NUM 16 -#define PQISRC_MAX_ADMIN_OB_QUEUE_ELEM_NUM 16 - - +#define PQISRC_PQI_REG_OFFSET 0x4000 -#define PQI_MIN_OP_IB_QUEUE_ID 1 -#define PQI_OP_EVENT_QUEUE_ID 1 -#define PQI_MIN_OP_OB_QUEUE_ID 2 -#define PQISRC_MAX_SUPPORTED_OP_IB_Q 128 +/* Number of Queues this driver compile can potentially support */ +#define PQISRC_MAX_SUPPORTED_OP_IB_Q 128 #define PQISRC_MAX_SUPPORTED_OP_RAID_IB_Q (PQISRC_MAX_SUPPORTED_OP_IB_Q / 2) #define PQISRC_MAX_SUPPORTED_OP_AIO_IB_Q (PQISRC_MAX_SUPPORTED_OP_RAID_IB_Q) -#define PQISRC_MAX_OP_IB_QUEUE_ELEM_NUM (PQISRC_MAX_OUTSTANDING_REQ / PQISRC_MAX_SUPPORTED_OP_IB_Q) -#define PQISRC_MAX_OP_OB_QUEUE_ELEM_NUM PQISRC_MAX_OUTSTANDING_REQ -#define PQISRC_MIN_OP_OB_QUEUE_ELEM_NUM 2 -#define PQISRC_MAX_SUPPORTED_OP_OB_Q 64 -#define PQISRC_OP_MAX_IBQ_ELEM_SIZE 8 /* 8 * 16 = 128 bytes */ -#define PQISRC_OP_MIN_IBQ_ELEM_SIZE 2 /* 2 * 16 = 32 bytes */ -#define PQISRC_OP_OBQ_ELEM_SIZE 1 /* 16 bytes */ -#define PQISRC_ADMIN_IBQ_ELEM_SIZE 2 /* 2 * 16 = 32 bytes */ -#define PQISRC_INTR_COALSC_GRAN 0 -#define PQISRC_PROTO_BIT_MASK 0 -#define PQISRC_SGL_SUPPORTED_BIT_MASK 0 - -#define PQISRC_NUM_EVENT_Q_ELEM 32 -#define PQISRC_EVENT_Q_ELEM_SIZE 32 +#define PQISRC_MAX_SUPPORTED_OP_OB_Q 64 + + +/* PQI Capability maxes (from controller) */ +#define PQISRC_MAX_ELEMENTS 8192 +#define PQISRC_OP_MIN_ELEM_SIZE 1 /* 16 bytes */ +#define PQISRC_OP_MAX_ELEM_SIZE 8 /* 8 * 16 = 128 bytes */ +#define PQISRC_MAX_SPANNING_IU_LENGTH 1152 +#define PQISRC_MAX_OUTSTANDING_REQ 4096 +/* #define PQISRC_MAX_OP_IB_QUEUE_ELEM_NUM (PQISRC_MAX_OUTSTANDING_REQ / PQISRC_MAX_SUPPORTED_OP_IB_Q) */ +/* #define PQISRC_MAX_OP_OB_QUEUE_ELEM_NUM PQISRC_MAX_OUTSTANDING_REQ */ +/* #define PQISRC_MIN_OP_OB_QUEUE_ELEM_NUM 2 */ + +#ifdef DEVICE_HINT +#define PQISRC_MIN_OUTSTANDING_REQ (PQI_RESERVED_IO_SLOTS_CNT + OS_MIN_OUTSTANDING_REQ) +#endif + + +/* Queue IDs Enumeration */ +#define PQI_ADMIN_IB_QUEUE_ID 0 +#define PQI_ADMIN_OB_QUEUE_ID 0 +#define PQI_MIN_OP_IB_QUEUE_ID 1 +#define PQI_OP_EVENT_QUEUE_ID 1 +#define PQI_MIN_OP_OB_QUEUE_ID 2 + + +/* PQI IU Element Sizes */ +#define PQISRC_ADMIN_IBQ_ELEM_SIZE_BYTES 64 +#define PQISRC_ADMIN_OBQ_ELEM_SIZE_BYTES 64 +#define PQISRC_OP_IBQ_ELEM_SIZE_BYTES 128 +#define PQISRC_OP_OBQ_ELEM_SIZE_BYTES 16 +#define PQISRC_EVENT_Q_ELEM_SIZE_BYTES 32 + + +/* Number of elements this driver compile will potentially use */ +#define PQISRC_MAX_ADMIN_IB_QUEUE_ELEM_NUM 16 +#define PQISRC_MAX_ADMIN_OB_QUEUE_ELEM_NUM 16 +#define PQISRC_MAX_EVENT_QUEUE_ELEM_NUM 32 +#define PQISRC_MAX_SPANNING_ELEMS 9 + +/* setting maximums for adv aio */ +#define PQISRC_MAX_AIO_RAID5_OR_6_WRITE (8*1024) /* 8 KiB */ +#define PQISRC_MAX_AIO_RAID1_OR_10_WRITE_2DRV 0x0000 /* No Limit */ +#define PQISRC_MAX_AIO_RAID1_OR_10_WRITE_3DRV 0x0000 /* No Limit */ +#define PQISRC_MAX_AIO_NVME_CRYPTO (32*1024) /* 32 KiB */ +#define PQISRC_MAX_AIO_NO_LIMIT 0x0000 /* No Limit */ +#define PQISRC_MAX_AIO_RW_XFER_SAS_SATA_CRYPTO 0x0000 /* No Limit */ +#define PQISRC_MAX_AIO_RW_XFER_NVME_CRYPTO (32*1024) + +#define SENSE_FEATURES_CRYPTO_OFFSET offsetof(bmic_sense_feature_page_io_aio_subpage_t, max_aio_rw_xfer_crypto_sas_sata) +#define MINIMUM_AIO_SUBPAGE_LENGTH \ + (offsetofend(bmic_sense_feature_page_io_aio_subpage_t, \ + max_aio_write_raid1_10_3drv) - \ + (sizeof(((bmic_sense_feature_page_io_aio_subpage_t *)0)->header))) + +/* Not used or useful yet */ +/* #define PQISRC_INTR_COALSC_GRAN 0 */ +/* #define PQISRC_PROTO_BIT_MASK 0 */ +/* #define PQISRC_SGL_SUPPORTED_BIT_MASK 0 */ + +#define PQISRC_MAX_SUPPORTED_MIRRORS 3 /* PQI Registers state status */ #define PQI_RESET_ACTION_RESET 0x1 @@ -249,12 +315,20 @@ PQI_DEV_STATE_ADMIN_QUEUE_PAIR_READY ) #define PQISRC_PQI_DEVICE_SIGNATURE "PQI DREG" -#define PQI_ADMINQ_ELEM_ARRAY_ALIGN 64 -#define PQI_ADMINQ_CI_PI_ALIGN 64 -#define PQI_OPQ_ELEM_ARRAY_ALIGN 64 -#define PQI_OPQ_CI_PI_ALIGN 4 -#define PQI_ADDR_ALIGN_MASK_64 0x3F /* lsb 6 bits */ -#define PQI_ADDR_ALIGN_MASK_4 0x3 /* lsb 2 bits */ + +#define PQI_ADDR_ALIGN_MASK_4K 0xFFF/* lsb 12 bits */ +#define PQI_ADDR_ALIGN_MASK_1K 0x3FF/* lsb 10 bits */ +#define PQI_ADDR_ALIGN_MASK_64 0x3F /* lsb 6 bits */ +#define PQI_ADDR_ALIGN_MASK_4 0x3 /* lsb 2 bits */ +#define PQI_ADDR_ALIGN 4096 +#define PQI_ADDR_ALIGN_MASK PQI_ADDR_ALIGN_MASK_4K + + +#define PQI_FORCE_IQ_ELEMENTS 32 /* 4096/128 = 32 (see PQISRC_OP_IBQ_ELEM_SIZE_BYTES) */ +#define PQI_FORCE_OQ_ELEMENTS 256 /* 4096/16 = 256 (see PQISRC_OP_OBQ_ELEM_SIZE_BYTES) */ + +#define PQI_CI_PI_ALIGN 64 +#define PQI_CI_PI_ALIGN_MASK PQI_ADDR_ALIGN_MASK_64 #define PQISRC_PQIMODE_READY_TIMEOUT (30 * 1000 ) /* 30 secs */ #define PQISRC_MODE_READY_POLL_INTERVAL 1000 /* 1 msec */ @@ -271,37 +345,38 @@ /* PQI configuration table section IDs */ #define PQI_CONF_TABLE_ALL_SECTIONS (-1) -#define PQI_CONF_TABLE_SECTION_GENERAL_INFO 0 +#define PQI_CONF_TABLE_SECTION_GENERAL_INFO 0 #define PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES 1 #define PQI_CONF_TABLE_SECTION_FIRMWARE_ERRATA 2 -#define PQI_CONF_TABLE_SECTION_DEBUG 3 -#define PQI_CONF_TABLE_SECTION_HEARTBEAT 4 - - -#define PQI_FIRMWARE_FEATURE_OFA 0 -#define PQI_FIRMWARE_FEATURE_SMP 1 -#define PQI_FIRMWARE_FEATURE_MAX_KNOWN 2 -#define PQI_FIRMWARE_FEATURE_AIO_READ_RAID_0 3 -#define PQI_FIRMWARE_FEATURE_AIO_READ_RAID_1_10 4 -#define PQI_FIRMWARE_FEATURE_AIO_READ_RAID_5_50 5 -#define PQI_FIRMWARE_FEATURE_AIO_READ_RAID_6_60 6 -#define PQI_FIRMWARE_FEATURE_AIO_WRITE_RAID_0 7 -#define PQI_FIRMWARE_FEATURE_AIO_WRITE_RAID_1_10 8 -#define PQI_FIRMWARE_FEATURE_AIO_WRITE_RAID_5_50 9 -#define PQI_FIRMWARE_FEATURE_AIO_WRITE_RAID_6_60 10 -#define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE 11 -#define PQI_FIRMWARE_FEATURE_SATA_WWN_FOR_DEV_UNIQUE_ID 12 -#define PQI_FIRMWARE_FEATURE_TIMEOUT_IN_RAID_IU_SUPPORT 13 -#define PQI_FIRMWARE_FEATURE_TIMEOUT_IN_TMF_IU_SUPPORT 14 -#define PQI_FIRMWARE_FEATURE_MAXIMUM 14 - -#define CTRLR_HEARTBEAT_CNT(softs) \ - LE_64(PCI_MEM_GET64(softs, softs->heartbeat_counter_abs_addr, softs->heartbeat_counter_off)) +#define PQI_CONF_TABLE_SECTION_DEBUG 3 +#define PQI_CONF_TABLE_SECTION_HEARTBEAT 4 +#define PQI_CONF_TABLE_SOFT_RESET 5 + +/* PQI feature bits as defined in PQI_SPEC.doc */ +#define PQI_FIRMWARE_FEATURE_OFA 0 +#define PQI_FIRMWARE_FEATURE_SMP 1 +#define PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE 2 +#define PQI_FIRMWARE_FEATURE_RAID_0_READ_BYPASS 3 +#define PQI_FIRMWARE_FEATURE_RAID_1_READ_BYPASS 4 +#define PQI_FIRMWARE_FEATURE_RAID_5_READ_BYPASS 5 +#define PQI_FIRMWARE_FEATURE_RAID_6_READ_BYPASS 6 +#define PQI_FIRMWARE_FEATURE_RAID_0_WRITE_BYPASS 7 +#define PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS 8 +#define PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS 9 +#define PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS 10 +#define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE 11 +#define PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN 12 +#define PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT 13 +#define PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT 14 +#define PQI_FIRMWARE_FEATURE_MAXIMUM 14 +#define PQI_FIRMWARE_FEATURE_PAGE83_IDENTIFIER_FOR_RPL_WWID 16 + +#define CTRLR_HEARTBEAT_CNT(softs) LE_64(PCI_MEM_GET64(softs, softs->heartbeat_counter_abs_addr, softs->heartbeat_counter_off)) #define PQI_HEARTBEAT_TIMEOUT_SEC (10) /* 10 sec interval */ #define PQI_HOST_WELLNESS_TIMEOUT_SEC (24*3600) /* pqi-2r00a table 36 */ -#define PQI_ADMIN_QUEUE_MSIX_DISABLE (0x80000000) +#define PQI_ADMIN_QUEUE_MSIX_DISABLE (0x80000000) #define PQI_ADMIN_QUEUE_MSIX_ENABLE (0 << 31) #define PQI_ADMIN_QUEUE_CONF_FUNC_CREATE_Q_PAIR 0x01 @@ -326,6 +401,10 @@ #define PQI_IU_TYPE_RAID_PATH_IO_REQUEST 0x14 #define PQI_IU_TYPE_AIO_PATH_IO_REQUEST 0x15 #define PQI_REQUEST_IU_AIO_TASK_MANAGEMENT 0x16 +#define PQI_IU_TYPE_RAID5_WRITE_BYPASS_REQUEST 0x18 +#define PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST 0x19 +#define PQI_IU_TYPE_RAID1_WRITE_BYPASS_REQUEST 0x1A +#define PQI_REQUEST_IU_AIO_BYPASS_TASK_MGMT 0x20 #define PQI_REQUEST_IU_GENERAL_ADMIN 0x60 #define PQI_REQUEST_IU_REPORT_VENDOR_EVENT_CONFIG 0x72 #define PQI_REQUEST_IU_SET_VENDOR_EVENT_CONFIG 0x73 @@ -349,13 +428,13 @@ #define PQI_FUNCTION_CHANGE_OPERATIONAL_IQ_PROP 0x14 #define PQI_CHANGE_OP_IQ_PROP_ASSIGN_AIO 1 -#define PQI_DEFAULT_IB_QUEUE 0 +#define PQI_DEFAULT_IB_QUEUE 0 #define PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE 0 -#define PQI_VENDOR_RESPONSE_IU_SUCCESS 0 -#define PQI_VENDOR_RESPONSE_IU_UNSUCCESS 1 +#define PQI_VENDOR_RESPONSE_IU_SUCCESS 0 +#define PQI_VENDOR_RESPONSE_IU_UNSUCCESS 1 #define PQI_VENDOR_RESPONSE_IU_INVALID_PARAM 2 -#define PQI_VENDOR_RESPONSE_IU_INSUFF_RESRC 3 +#define PQI_VENDOR_RESPONSE_IU_INSUFF_RESRC 3 /* Interface macros */ @@ -371,16 +450,30 @@ #define PQI_GET_CTRL_MODE(softs) \ (PCI_MEM_GET32(softs, &softs->ioa_reg->scratchpad0, LEGACY_SIS_SCR0)) -#define PQI_SAVE_CTRL_MODE(softs, mode) \ - PCI_MEM_PUT32(softs, &softs->ioa_reg->scratchpad0, LEGACY_SIS_SCR0, mode) +#define PQI_SAVE_CTRL_MODE(softs, mode) { \ + PCI_MEM_PUT32(softs, &softs->ioa_reg->scratchpad0, LEGACY_SIS_SCR0, mode); \ + OS_SLEEP(1000); \ + } -#define PQISRC_MAX_TARGETID 1024 -#define PQISRC_MAX_TARGETLUN 64 +#define LEGACY_SIS_SCR_REG_LENGTH 4 +#define LEGACY_SIS_SCR1 LEGACY_SIS_SCR0 + LEGACY_SIS_SCR_REG_LENGTH +#define PQI_GET_CTRL_TYPE(softs) \ + ((PCI_MEM_GET32(softs, &softs->ioa_reg->scratchpad1, LEGACY_SIS_SCR1)) \ + & 0x0000FFFF) + +/* smart raid-hba pqi functional spec, scratchpad register 1 spec */ +#define PQI_CTRL_PRODUCT_ID_GEN1 0x0000 +#define PQI_CTRL_PRODUCT_ID_GEN2_REV_A 0x0007 +#define PQI_CTRL_PRODUCT_ID_GEN2_REV_B 0x0107 + +#define PQISRC_MAX_TARGETID 1024 +#define PQISRC_MAX_TARGETLUN 64 /* Vendor specific IU Type for Event config Cmds */ -#define PQI_REQUEST_IU_REPORT_EVENT_CONFIG 0x72 -#define PQI_REQUEST_IU_SET_EVENT_CONFIG 0x73 -#define PQI_REQUEST_IU_ACKNOWLEDGE_VENDOR_EVENT 0xf6 +#define PQI_REQUEST_IU_REPORT_EVENT_CONFIG 0x72 +#define PQI_REQUEST_IU_SET_EVENT_CONFIG 0x73 +#define PQI_REQUEST_IU_ACKNOWLEDGE_VENDOR_EVENT 0xf6 + #define PQI_RESPONSE_IU_GENERAL_MANAGEMENT 0x81 #define PQI_MANAGEMENT_CMD_RESP_TIMEOUT 3000 @@ -409,40 +502,42 @@ /* Device flags */ -#define PQISRC_DFLAG_VALID (1 << 0) -#define PQISRC_DFLAG_CONFIGURING (1 << 1) +#define PQISRC_DFLAG_VALID (1 << 0) +#define PQISRC_DFLAG_CONFIGURING (1 << 1) -#define MAX_EMBEDDED_SG_IN_FIRST_IU 4 -#define MAX_EMBEDDED_SG_IN_IU 8 +#define MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT 4 +#define MAX_EMBEDDED_SG_IN_FIRST_IU_RAID56_AIO 3 +#define MAX_EMBEDDED_SG_IN_IU 8 #define SG_FLAG_LAST 0x40000000 #define SG_FLAG_CHAIN 0x80000000 -#define IN_PQI_RESET(softs) (softs->ctlr_state & PQI_BUS_RESET) -#define DEV_GONE(dev) (!dev || (dev->invalid == true)) -#define IS_AIO_PATH(dev) (dev->aio_enabled) -#define IS_RAID_PATH(dev) (!dev->aio_enabled) +#define IN_PQI_RESET(softs) (softs->ctlr_state & PQI_BUS_RESET) +#define DEV_GONE(dev) (!dev || (dev->invalid == true)) +#define IS_AIO_PATH(dev) (dev->aio_enabled) +#define IS_RAID_PATH(dev) (!dev->aio_enabled) -#define DEVICE_RESET(dvp) (dvp->reset_in_progress) +#define DEVICE_RESET(dvp) (dvp->reset_in_progress) /* SOP data direction flags */ -#define SOP_DATA_DIR_NONE 0x00 -#define SOP_DATA_DIR_FROM_DEVICE 0x01 -#define SOP_DATA_DIR_TO_DEVICE 0x02 -#define SOP_DATA_DIR_BIDIRECTIONAL 0x03 -#define SOP_PARTIAL_DATA_BUFFER 0x04 +#define SOP_DATA_DIR_UNKNOWN 0xFF +#define SOP_DATA_DIR_NONE 0x00 +#define SOP_DATA_DIR_FROM_DEVICE 0x01 +#define SOP_DATA_DIR_TO_DEVICE 0x02 +#define SOP_DATA_DIR_BIDIRECTIONAL 0x03 +#define SOP_PARTIAL_DATA_BUFFER 0x04 -#define PQISRC_DMA_VALID (1 << 0) -#define PQISRC_CMD_NO_INTR (1 << 1) +#define PQISRC_DMA_VALID (1 << 0) +#define PQISRC_CMD_NO_INTR (1 << 1) -#define SOP_TASK_ATTRIBUTE_SIMPLE 0 +#define SOP_TASK_ATTRIBUTE_SIMPLE 0 #define SOP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 1 -#define SOP_TASK_ATTRIBUTE_ORDERED 2 -#define SOP_TASK_ATTRIBUTE_ACA 4 +#define SOP_TASK_ATTRIBUTE_ORDERED 2 +#define SOP_TASK_ATTRIBUTE_ACA 4 -#define SOP_TASK_MANAGEMENT_FUNCTION_COMPLETE 0x0 -#define SOP_TASK_MANAGEMENT_FUNCTION_REJECTED 0x4 +#define SOP_TASK_MANAGEMENT_FUNCTION_COMPLETE 0x0 +#define SOP_TASK_MANAGEMENT_FUNCTION_REJECTED 0x4 #define SOP_TASK_MANAGEMENT_FUNCTION_FAILED 0x5 -#define SOP_TASK_MANAGEMENT_FUNCTION_SUCCEEDED 0x8 +#define SOP_TASK_MANAGEMENT_FUNCTION_SUCCEEDED 0x8 #define SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK 0x01 #define SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK_SET 0x02 #define SOP_TASK_MANAGEMENT_LUN_RESET 0x8 @@ -499,13 +594,15 @@ #define PQI_RAID_STATUS_UNDERRUN PQI_AIO_STATUS_UNDERRUN #define PQI_RAID_STATUS_OVERRUN PQI_AIO_STATUS_OVERRUN +#define NUM_STREAMS_PER_LUN 8 + /* VPD inquiry pages */ #define SCSI_VPD_SUPPORTED_PAGES 0x0 /* standard page */ -#define SCSI_VPD_DEVICE_ID 0x83 /* standard page */ +#define SCSI_VPD_DEVICE_ID 0x83 /* standard page */ #define SA_VPD_PHYS_DEVICE_ID 0xc0 /* vendor-specific page */ #define SA_VPD_LV_DEVICE_GEOMETRY 0xc1 /* vendor-specific page */ #define SA_VPD_LV_IOACCEL_STATUS 0xc2 /* vendor-specific page */ -#define SA_VPD_LV_STATUS 0xc3 /* vendor-specific page */ +#define SA_VPD_LV_STATUS 0xc3 /* vendor-specific page */ #define VPD_PAGE (1 << 8) @@ -555,10 +652,17 @@ #define MAX_RAW_M16_QDEPTH 2032 #define PQI_PTRAID_UPDATE_ON_RESCAN_LUNS 0x80000000 -#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" +#define RAID_CTLR_LUNID ((uint8_t *) "\0\0\0\0\0\0\0\0") + +/* SCSI Cmds @todo: move SCMD_READ_6, etc. into library */ +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SENSE 0x1a +#define SCSI_REPORT_LUNS 0xa0 +#define SCSI_LOG_SENSE 0x4d +#define SCSI_ATA_PASSTHRU16 0x85 -#define SA_CACHE_FLUSH 0x1 #define PQISRC_INQUIRY_TIMEOUT 30 + #define SA_INQUIRY 0x12 #define SA_REPORT_LOG 0xc2 /* Report Logical LUNs */ #define SA_REPORT_PHYS 0xc3 /* Report Physical LUNs */ @@ -570,10 +674,8 @@ #define SCSI_SENSE_RESPONSE_72 0x72 #define SCSI_SENSE_RESPONSE_73 0x73 -#define SA_REPORT_LOG_EXTENDED 0x1 -#define SA_REPORT_PHYS_EXTENDED 0x2 - -#define SA_CACHE_FLUSH_BUF_LEN 4 +#define SA_REPORT_LOG_EXTENDED 0x1 +#define SA_REPORT_PHYS_EXTENDED 0x2 #define GET_SCSI_SNO(cmd) (cmd->cmdId.serialNumber) @@ -636,11 +738,14 @@ #define PQI_MAX_DEVICES (PQI_MAX_LOGICALS + PQI_MAX_PHYSICALS + 1) /* 1 for controller device entry */ #define PQI_MAX_EXT_TARGETS 32 -#define PQI_CTLR_INDEX (PQI_MAX_DEVICES - 1) +#define PQI_CTLR_INDEX 0 #define PQI_PD_INDEX(t) (t + PQI_MAX_LOGICALS) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define MAX_TARGET_DEVICES 1024 +#define MAX_TARGET_BIT 1025 +#define SLOT_AVAILABLE false +#define SLOT_TAKEN true #define PQI_NO_MEM 2 @@ -648,6 +753,7 @@ DEVICE_NOT_FOUND, DEVICE_CHANGED, DEVICE_UNCHANGED, + DEVICE_IN_REMOVE, } device_status_t; #define SA_RAID_0 0 @@ -666,19 +772,27 @@ #define BIT3 (1 << 3) #define BITS_PER_BYTE 8 + + +/* Vendor Specific (BMIC) Op Code */ +#define BMIC_READ 0x26 +#define BMIC_WRITE 0x27 +#define IS_BMIC_OPCODE(opcode) (opcode == BMIC_READ || opcode == BMIC_WRITE) /* BMIC commands */ -#define BMIC_IDENTIFY_CONTROLLER 0x11 +#define BMIC_IDENTIFY_CONTROLLER 0x11 #define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 -#define BMIC_READ 0x26 -#define BMIC_WRITE 0x27 +#define BMIC_SENSE_FEATURE 0x61 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 #define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66 -#define BMIC_CACHE_FLUSH 0xc2 -#define BMIC_FLASH_FIRMWARE 0xf7 -#define BMIC_WRITE_HOST_WELLNESS 0xa5 -#define BMIC_SET_DIAGS_OPTIONS 0xf4 -#define BMIC_SENSE_DIAGS_OPTIONS 0xf5 +#define BMIC_WRITE_HOST_WELLNESS 0xa5 +#define BMIC_CACHE_FLUSH 0xc2 +#define BMIC_SET_DIAGS_OPTIONS 0xf4 +#define BMIC_SENSE_DIAGS_OPTIONS 0xf5 +#define BMIC_FLASH_FIRMWARE 0xf7 +/* Sense Feature Pages/Subpages */ +#define IO_SENSE_FEATURES_PAGE 0x08 +#define SENSE_FEATURES_AIO_SUBPAGE 0x02 #define MASKED_DEVICE(lunid) ((lunid)[3] & 0xC0) #define BMIC_GET_LEVEL_2_BUS(lunid) ((lunid)[7] & 0x3F) @@ -700,9 +814,20 @@ PQI_RESERVED_IO_SLOTS_TMF + \ PQI_RESERVED_IO_SLOTS_SYNC_REQUESTS) +/* Defines for counter flags */ +#define COUNTER_FLAG_CLEAR_COUNTS 0x0001 +#define COUNTER_FLAG_ONLY_NON_ZERO 0x0002 + /* Defines for print flags */ -#define PRINT_FLAG_HDR_COLUMN 0x0001 +#define PRINT_FLAG_HDR_COLUMN 0x0001 + +/* Function-specific debug flags */ +#if 0 +#define DEBUG_AIO /* show AIO eligibility, IU, etc. (very spammy!) */ +#define DEBUG_AIO_LOCATOR /* show AIO row/column etc. calc. */ +#define DEBUG_RAID_MAP /* show AIO raid map content from FW */ +#endif static inline uint16_t GET_LE16(const uint8_t *p) { @@ -754,8 +879,27 @@ PUT_BE32(val, p + 4); } -#define OS_FREEBSD -#define SIS_POLL_WAIT + +/* Calculates percentage of val vs total, i.e. 20 out of 100 --> 20% */ +static inline uint64_t CALC_PERCENT_TOTAL(uint64_t val, uint64_t total) +{ + uint64_t percent = 0; + if (total) + percent = (val * 100) / total; + return percent; +} + +/* Calculates percentage of a vs b, i.e. 50 vs 100 -> 50/150 -> 33% */ +#define CALC_PERCENT_VS(a, b) (CALC_PERCENT_TOTAL(a, (a+b))) + +#define STREAM_DETECTION "stream_disable" +#define SATA_UNIQUE_WWN "sata_unique_wwn_disable" +#define AIO_RAID1_WRITE_BYPASS "aio_raid1_write_disable" +#define AIO_RAID5_WRITE_BYPASS "aio_raid5_write_disable" +#define AIO_RAID6_WRITE_BYPASS "aio_raid6_write_disable" +#define ADAPTER_QUEUE_DEPTH "queue_depth" +#define SCATTER_GATHER_COUNT "sg_count" +#define QUEUE_COUNT "queue_count" #define OS_ATTRIBUTE_PACKED __attribute__((__packed__)) #define OS_ATTRIBUTE_ALIGNED(n) __attribute__((aligned(n))) @@ -793,19 +937,18 @@ typedef uint8_t *passthru_buf_type_t; - -#define PQISRC_OS_VERSION 1 -#define PQISRC_FEATURE_VERSION 4014 -#define PQISRC_PATCH_VERSION 0 -#define PQISRC_BUILD_VERSION 105 +#define PQISRC_DRIVER_MAJOR __FreeBSD__ +#define PQISRC_DRIVER_MINOR 4410 +#define PQISRC_DRIVER_RELEASE 0 +#define PQISRC_DRIVER_REVISION 2005 #define STR(s) # s -#define PQISRC_VERSION(a, b, c, d) STR(a.b.c.d) -#define PQISRC_DRIVER_VERSION PQISRC_VERSION(PQISRC_OS_VERSION, \ - PQISRC_FEATURE_VERSION, \ - PQISRC_PATCH_VERSION, \ - PQISRC_BUILD_VERSION) - +#define PQISRC_VERSION(a, b, c, d) STR(a.b.c-d) +#define PQISRC_DRIVER_VERSION PQISRC_VERSION(PQISRC_DRIVER_MAJOR, \ + PQISRC_DRIVER_MINOR, \ + PQISRC_DRIVER_RELEASE, \ + PQISRC_DRIVER_REVISION) + /* End Management interface */ #ifdef ASSERT @@ -880,7 +1023,6 @@ #define LEGACY_SIS_SRCV_MAILBOX 0x1000 /* mailbox (20 bytes) */ #define LEGACY_SIS_SRCV_OFFSET_MAILBOX_7 0x101C /* mailbox 7 register offset */ - #define LEGACY_SIS_ODR_SHIFT 12 /* outbound doorbell shift */ #define LEGACY_SIS_IDR_SHIFT 9 /* inbound doorbell shift */ @@ -892,7 +1034,7 @@ #define PQI_SIGNATURE 0x4000 #define PQI_ADMINQ_CONFIG 0x4008 #define PQI_ADMINQ_CAP 0x4010 -#define PQI_LEGACY_INTR_STATUS 0x4018 +#define PQI_LEGACY_INTR_STATUS 0x4018 #define PQI_LEGACY_INTR_MASK_SET 0x401C #define PQI_LEGACY_INTR_MASK_CLR 0x4020 #define PQI_DEV_STATUS 0x4040 @@ -912,7 +1054,7 @@ #define OS_BUSYWAIT(x) DELAY(x) #define OS_SLEEP(timeout) \ DELAY(timeout); - + /* TMF request timeout is 600 Sec */ #define OS_TMF_TIMEOUT_SEC (10 * 60) @@ -950,14 +1092,14 @@ typedef uint8_t os_dev_info_t; typedef struct OS_SPECIFIC { - device_t pqi_dev; + device_t pqi_dev; struct resource *pqi_regs_res0; /* reg. if. window */ int pqi_regs_rid0; /* resource ID */ bus_dma_tag_t pqi_parent_dmat; /* parent DMA tag */ bus_dma_tag_t pqi_buffer_dmat; /* controller hardware interface */ - int pqi_hwif; + int pqi_hwif; struct resource *pqi_irq[PQI_MAX_MSIX]; /* interrupt */ int pqi_irq_rid[PQI_MAX_MSIX]; void *intrcookie[PQI_MAX_MSIX]; @@ -980,49 +1122,61 @@ struct callout heartbeat_timeout_id; /* heart beat event handling */ } OS_SPECIFIC_T; -typedef bus_addr_t dma_addr_t; + +typedef struct device_hints { + uint8_t stream_status: 1; + uint8_t sata_unique_wwn_status: 1; + uint8_t aio_raid1_write_status: 1; + uint8_t aio_raid5_write_status: 1; + uint8_t aio_raid6_write_status: 1; + uint32_t queue_depth; + uint32_t sg_segments; + uint32_t cpu_count; +} device_hint; + +typedef bus_addr_t dma_addr_t; /* Register access macros */ #define PCI_MEM_GET32( _softs, _absaddr, _offset ) \ - bus_space_read_4(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset) + bus_space_read_4(_softs->pci_mem_handle.pqi_btag, \ + _softs->pci_mem_handle.pqi_bhandle, _offset) #if defined(__i386__) #define PCI_MEM_GET64( _softs, _absaddr, _offset ) ({ \ (uint64_t)bus_space_read_4(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset) + \ - ((uint64_t)bus_space_read_4(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset + 4) << 32); \ + _softs->pci_mem_handle.pqi_bhandle, _offset) + \ + ((uint64_t)bus_space_read_4(_softs->pci_mem_handle.pqi_btag, \ + _softs->pci_mem_handle.pqi_bhandle, _offset + 4) << 32); \ }) #else #define PCI_MEM_GET64(_softs, _absaddr, _offset ) \ - bus_space_read_8(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset) + bus_space_read_8(_softs->pci_mem_handle.pqi_btag, \ + _softs->pci_mem_handle.pqi_bhandle, _offset) #endif #define PCI_MEM_PUT32( _softs, _absaddr, _offset, _val ) \ - bus_space_write_4(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset, _val) + bus_space_write_4(_softs->pci_mem_handle.pqi_btag, \ + _softs->pci_mem_handle.pqi_bhandle, _offset, _val) #if defined(__i386__) #define PCI_MEM_PUT64( _softs, _absaddr, _offset, _val ) \ bus_space_write_4(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset, _val); \ + _softs->pci_mem_handle.pqi_bhandle, _offset, _val); \ bus_space_write_4(_softs->pci_mem_handle.pqi_btag, \ _softs->pci_mem_handle.pqi_bhandle, _offset + 4, _val >> 32); #else #define PCI_MEM_PUT64( _softs, _absaddr, _offset, _val ) \ - bus_space_write_8(_softs->pci_mem_handle.pqi_btag, \ - _softs->pci_mem_handle.pqi_bhandle, _offset, _val) + bus_space_write_8(_softs->pci_mem_handle.pqi_btag, \ + _softs->pci_mem_handle.pqi_bhandle, _offset, _val) #endif #define PCI_MEM_GET_BUF(_softs, _absaddr, _offset, buf, size) \ bus_space_read_region_1(_softs->pci_mem_handle.pqi_btag,\ _softs->pci_mem_handle.pqi_bhandle, _offset, buf, size) - + /* Lock */ typedef struct mtx OS_LOCK_T; typedef struct sema OS_SEMA_LOCK_T; @@ -1038,8 +1192,7 @@ #define PQI_LOCK(_lock) OS_ACQUIRE_SPINLOCK(_lock) #define PQI_UNLOCK(_lock) OS_RELEASE_SPINLOCK(_lock) -#define OS_GET_CDBP(rcb) \ - ((rcb->cm_ccb->ccb_h.flags & CAM_CDB_POINTER) ? rcb->cm_ccb->csio.cdb_io.cdb_ptr : rcb->cm_ccb->csio.cdb_io.cdb_bytes) +#define OS_GET_CDBP(rcb) ((rcb->cm_ccb->ccb_h.flags & CAM_CDB_POINTER) ? rcb->cm_ccb->csio.cdb_io.cdb_ptr : rcb->cm_ccb->csio.cdb_io.cdb_bytes) #define GET_SCSI_BUFFLEN(rcb) (rcb->cm_ccb->csio.dxfer_len) #define IS_OS_SCSICMD(rcb) (rcb && !rcb->tm_req && rcb->cm_ccb) @@ -1070,8 +1223,14 @@ #define SCMD_WRITE_16 WRITE_16 /* FreeBSD status macros */ -#define BSD_SUCCESS 0 +#define BSD_SUCCESS 0 +#define DEVICE_HINT_SUCCESS 0 +/* Min outstanding commands that driver can register with CAM layer.*/ +#define OS_MIN_OUTSTANDING_REQ 6 +#define BSD_MIN_SG_SEGMENTS 16 + +#define DISABLE_ERR_RESP_VERBOSE 1 /* Debug facility */ @@ -1110,17 +1269,17 @@ } \ }while(0); -#define DBG_TRACEIO(fmt,args...) \ +#define DBG_DISC(fmt,args...) \ do { \ - if (logging_level & PQISRC_FLAGS_TRACEIO) { \ - printf("[TRACEIO]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ + if (logging_level & PQISRC_FLAGS_DISC) { \ + printf("[DISC]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ } \ }while(0); -#define DBG_DISC(fmt,args...) \ +#define DBG_TRACEIO(fmt,args...) \ do { \ - if (logging_level & PQISRC_FLAGS_DISC) { \ - printf("[DISC]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ + if (logging_level & PQISRC_FLAGS_TRACEIO) { \ + printf("[TRACEIO]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ } \ }while(0); @@ -1137,6 +1296,12 @@ printf("[ERROR]::[%u:%u.%u][CPU %d][%s][%d]:"fmt,softs->bus_id,softs->device_id,softs->func_id,curcpu,__func__,__LINE__,##args); \ } \ }while(0); +#define DBG_ERR_NO_SOFTS(fmt,args...) \ + do { \ + if (logging_level & PQISRC_FLAGS_ERROR) { \ + printf("[ERROR]::[CPU %d][%s][%d]:"fmt,curcpu,__func__,__LINE__,##args); \ + } \ + }while(0); #define DBG_IO(fmt,args...) \ do { \ if (logging_level & PQISRC_FLAGS_TRACEIO) { \ @@ -1147,21 +1312,21 @@ #define DBG_ERR_BTL(device,fmt,args...) \ do { \ if (logging_level & PQISRC_FLAGS_ERROR) { \ - printf("[ERROR]::[%u:%u.%u][%u,%u,%u][CPU %d][%s][%d]:"fmt, softs->bus_id, softs->device_id, softs->func_id, device->bus, device->target, device->lun,curcpu,__func__,__LINE__,##args); \ + printf("[ERROR]::[%u:%u.%u][%d,%d,%d][CPU %d][%s][%d]:"fmt, softs->bus_id, softs->device_id, softs->func_id, device->bus, device->target, device->lun,curcpu,__func__,__LINE__,##args); \ } \ }while(0); #define DBG_WARN_BTL(device,fmt,args...) \ do { \ if (logging_level & PQISRC_FLAGS_WARN) { \ - printf("[WARN]:[%u:%u.%u][%u,%u,%u][CPU %d][%s][%d]:"fmt, softs->bus_id, softs->device_id, softs->func_id, device->bus, device->target, device->lun,curcpu,__func__,__LINE__,##args);\ + printf("[WARN]:[%u:%u.%u][%d,%d,%d][CPU %d][%s][%d]:"fmt, softs->bus_id, softs->device_id, softs->func_id, device->bus, device->target, device->lun,curcpu,__func__,__LINE__,##args);\ } \ }while(0); #define DBG_NOTE(fmt,args...) \ do { \ if (logging_level & PQISRC_FLAGS_NOTE) { \ - printf("[INFO]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ + printf("[NOTE]:[ %s ] [ %d ]"fmt,__func__,__LINE__,##args); \ } \ }while(0); diff --git a/sys/dev/smartpqi/smartpqi_discovery.c b/sys/dev/smartpqi/smartpqi_discovery.c --- a/sys/dev/smartpqi/smartpqi_discovery.c +++ b/sys/dev/smartpqi/smartpqi_discovery.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,153 +26,398 @@ #include "smartpqi_includes.h" -#define MAX_RETRIES 3 -#define PQISRC_INQUIRY_TIMEOUT 30 - -/* Validate the scsi sense response code */ -static inline -boolean_t pqisrc_scsi_sense_valid(const struct sense_header_scsi *sshdr) +/* + * Populate the controller's advanced aio features via BMIC cmd. + */ +int +pqisrc_QuerySenseFeatures(pqisrc_softstate_t *softs) { - DBG_FUNC("IN\n"); + bmic_sense_feature_aio_buffer_t *features; + int ret; + pqisrc_raid_req_t request; - if (!sshdr) - return false; + /* Initializing defaults for AIO support subpage */ + softs->max_aio_write_raid5_6 = + PQISRC_MAX_AIO_RAID5_OR_6_WRITE; + softs->max_aio_write_raid1_10_2drv = + PQISRC_MAX_AIO_RAID1_OR_10_WRITE_2DRV; + softs->max_aio_write_raid1_10_3drv = + PQISRC_MAX_AIO_RAID1_OR_10_WRITE_3DRV; + softs->max_aio_rw_xfer_crypto_nvme = + PQISRC_MAX_AIO_RW_XFER_NVME_CRYPTO; + softs->max_aio_rw_xfer_crypto_sas_sata = + PQISRC_MAX_AIO_RW_XFER_SAS_SATA_CRYPTO; + +#ifdef DEVICE_HINT + softs->enable_stream_detection = softs->hint.stream_status; +#endif - DBG_FUNC("OUT\n"); + /* Implement SENSE_FEATURE BMIC to populate AIO limits */ + features = os_mem_alloc(softs, sizeof(*features)); + if (!features) { + DBG_ERR("Failed to allocate memory for sense aio features.\n"); + goto err; + } + memset(features, 0, sizeof(*features)); + + memset(&request, 0, sizeof(request)); + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_READ; + request.cmd.cdb[2] = IO_SENSE_FEATURES_PAGE; + request.cmd.cdb[3] = SENSE_FEATURES_AIO_SUBPAGE; + request.cmd.bmic_cdb.cmd = BMIC_SENSE_FEATURE; + request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*features)); + ret = pqisrc_prepare_send_ctrlr_request(softs, &request, + features, sizeof(*features)); - return (sshdr->response_code & 0x70) == 0x70; + if (ret) + goto free_err; + + /* If AIO subpage was valid, use values from that page */ + if (features->aio_subpage.header.total_length >= + MINIMUM_AIO_SUBPAGE_LENGTH) { + DBG_INIT("AIO support subpage valid. total_length = 0x%0x.\n", + features->aio_subpage.header.total_length); + softs->adv_aio_capable = true; + + /* AIO transfer limits are reported in kbytes, so x 1024. + * Values of 0 mean 'no limit'. + */ + + softs->max_aio_write_raid5_6 = + (features->aio_subpage.max_aio_write_raid5_6 == 0) ? + PQISRC_MAX_AIO_NO_LIMIT : + features->aio_subpage.max_aio_write_raid5_6 * 1024; + softs->max_aio_write_raid1_10_2drv = + (features->aio_subpage.max_aio_write_raid1_10_2drv + == 0) ? PQISRC_MAX_AIO_NO_LIMIT : + features->aio_subpage.max_aio_write_raid1_10_2drv + * 1024; + softs->max_aio_write_raid1_10_3drv = + (features->aio_subpage.max_aio_write_raid1_10_3drv + == 0) ? PQISRC_MAX_AIO_NO_LIMIT : + features->aio_subpage.max_aio_write_raid1_10_3drv + * 1024; + softs->max_aio_rw_xfer_crypto_nvme = + (features->aio_subpage.max_aio_rw_xfer_crypto_nvme + == 0) ? PQISRC_MAX_AIO_NO_LIMIT : + features->aio_subpage.max_aio_rw_xfer_crypto_nvme + * 1024; + softs->max_aio_rw_xfer_crypto_sas_sata = + (features->aio_subpage.max_aio_rw_xfer_crypto_sas_sata + == 0) ? PQISRC_MAX_AIO_NO_LIMIT : + features->aio_subpage.max_aio_rw_xfer_crypto_sas_sata + * 1024; + + DBG_INIT("softs->max_aio_write_raid5_6: 0x%x\n", + softs->max_aio_write_raid5_6); + DBG_INIT("softs->max_aio_write_raid1_10_2drv: 0x%x\n", + softs->max_aio_write_raid1_10_2drv); + DBG_INIT("softs->max_aio_write_raid1_10_3drv: 0x%x\n", + softs->max_aio_write_raid1_10_3drv); + DBG_INIT("softs->max_aio_rw_xfer_crypto_nvme: 0x%x\n", + softs->max_aio_rw_xfer_crypto_nvme); + DBG_INIT("softs->max_aio_rw_xfer_crypto_sas_sata: 0x%x\n", + softs->max_aio_rw_xfer_crypto_sas_sata); + + } else { + DBG_WARN("Problem getting AIO support subpage settings. " + "Disabling advanced AIO writes.\n"); + softs->adv_aio_capable = false; + } + + + os_mem_free(softs, features, sizeof(*features)); + return ret; +free_err: + os_mem_free(softs, features, sizeof(*features)); +err: + return PQI_STATUS_FAILURE; } /* - * Initialize target ID pool for HBA/PDs . + * Initialize target ID pool for exposed physical devices . */ void -pqisrc_init_targetid_pool(pqisrc_softstate_t *softs) +pqisrc_init_bitmap(pqisrc_softstate_t *softs) { - int i, tid = PQI_MAX_PHYSICALS + PQI_MAX_LOGICALS - 1; + memset(&softs->bit_map, SLOT_AVAILABLE, sizeof(softs->bit_map)); +} - for(i = 0; i < PQI_MAX_PHYSICALS; i++) { - softs->tid_pool.tid[i] = tid--; +void +pqisrc_remove_target_bit(pqisrc_softstate_t *softs, int target) +{ + if((target == PQI_CTLR_INDEX) || (target == INVALID_ELEM)) { + DBG_ERR("Invalid target ID\n"); + return; } - softs->tid_pool.index = i - 1; + DBG_DISC("Giving back target %d\n", target); + softs->bit_map.bit_vector[target] = SLOT_AVAILABLE; } +/* Use bit map to find availible targets */ int -pqisrc_alloc_tid(pqisrc_softstate_t *softs) +pqisrc_find_avail_target(pqisrc_softstate_t *softs) { - if(softs->tid_pool.index <= -1) { - DBG_ERR("Target ID exhausted\n"); - return INVALID_ELEM; + int avail_target; + for(avail_target = 1; avail_target < MAX_TARGET_BIT; avail_target++) { + if(softs->bit_map.bit_vector[avail_target] == SLOT_AVAILABLE){ + softs->bit_map.bit_vector[avail_target] = SLOT_TAKEN; + DBG_DISC("Avail_target is %d\n", avail_target); + return avail_target; + } } - - return softs->tid_pool.tid[softs->tid_pool.index--]; + DBG_ERR("No available targets\n"); + return INVALID_ELEM; } -void -pqisrc_free_tid(pqisrc_softstate_t *softs, int tid) +/* Subroutine used to set Bus-Target-Lun for the requested device */ +static inline void +pqisrc_set_btl(pqi_scsi_dev_t *device, int bus, int target, int lun) { - if(softs->tid_pool.index >= (PQI_MAX_PHYSICALS - 1)) { - DBG_ERR("Target ID queue is full\n"); - return; - } + DBG_FUNC("IN\n"); + + device->bus = bus; + device->target = target; + device->lun = lun; - softs->tid_pool.index++; - softs->tid_pool.tid[softs->tid_pool.index] = tid; + DBG_FUNC("OUT\n"); } -/* Update scsi sense info to a local buffer*/ +/* Add all exposed physical devices, logical devices, controller devices, PT RAID +* devices and multi-lun devices */ boolean_t -pqisrc_update_scsi_sense(const uint8_t *buff, int len, - struct sense_header_scsi *header) +pqisrc_add_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, + uint8_t *scsi3addr) { + /* Add physical devices with targets that need + * targets */ + int j; + int tid = 0; + unsigned char addr1[8], addr2[8]; + pqi_scsi_dev_t *temp_device; + + /* If controller device, add it to list because its lun/bus/target + * values are already set */ + if(pqisrc_is_hba_lunid(scsi3addr)) + goto add_device_to_dev_list; + + /* If exposed physical device give it a target then add it + * to the dev list */ + if(!pqisrc_is_logical_device(device)) { + tid = pqisrc_find_avail_target(softs); + if(INVALID_ELEM != tid){ + pqisrc_set_btl(device, PQI_PHYSICAL_DEVICE_BUS, tid, 0); + goto add_device_to_dev_list; + } + } - DBG_FUNC("IN\n"); - - if (!buff || !len) - return false; + /* If external raid device , assign target from the target pool. + * If a non-zero lun device, search through the list & find the + * device which has same target (byte 2 of LUN address). + * Assign the same target for this new lun. */ + if (pqisrc_is_external_raid_device(device)) { + memcpy(addr1, device->scsi3addr, 8); + for(j = 0; j < PQI_MAX_DEVICES; j++) { + if(softs->dev_list[j] == NULL) + continue; + temp_device = softs->dev_list[j]; + memcpy(addr2, temp_device->scsi3addr, 8); + if (addr1[2] == addr2[2]) { + pqisrc_set_btl(device, PQI_EXTERNAL_RAID_VOLUME_BUS, + temp_device->target,device->scsi3addr[0]); + goto add_device_to_dev_list; + } + } + tid = pqisrc_find_avail_target(softs); + if(INVALID_ELEM != tid){ + pqisrc_set_btl(device, PQI_EXTERNAL_RAID_VOLUME_BUS, tid, device->scsi3addr[0]); + goto add_device_to_dev_list; + } + } - memset(header, 0, sizeof(struct sense_header_scsi)); + /* If logical device, add it to list because its lun/bus/target + * values are already set */ + if(pqisrc_is_logical_device(device) && !pqisrc_is_external_raid_device(device)) + goto add_device_to_dev_list; + + /* This is a non-zero lun of a multi-lun device. + * Search through our list and find the device which + * has the same 8 byte LUN address, except with bytes 4 and 5. + * Assign the same bus and target for this new LUN. + * Use the logical unit number from the firmware. */ + memcpy(addr1, device->scsi3addr, 8); + addr1[4] = 0; + addr1[5] = 0; + for(j = 0; j < PQI_MAX_DEVICES; j++) { + if(softs->dev_list[j] == NULL) + continue; + temp_device = softs->dev_list[j]; + memcpy(addr2, temp_device->scsi3addr, 8); + addr2[4] = 0; + addr2[5] = 0; + /* If addresses are the same, except for bytes 4 and 5 + * then the passed-in device is an additional lun of a + * previously added multi-lun device. Use the same target + * id as that previous device. Otherwise, use the new + * target id */ + if(memcmp(addr1, addr2, 8) == 0) { + pqisrc_set_btl(device, temp_device->bus, + temp_device->target, temp_device->scsi3addr[4]); + goto add_device_to_dev_list; + } + } + DBG_ERR("The device is not a physical, lun or ptraid device" + "B %d: T %d: L %d\n", device->bus, device->target, + device->lun ); + return false; + +add_device_to_dev_list: + /* Actually add the device to the driver list + * softs->dev_list */ + softs->num_devs++; + for(j = 0; j < PQI_MAX_DEVICES; j++) { + if(softs->dev_list[j]) + continue; + softs->dev_list[j] = device; + break; + } + DBG_NOTE("Added device [%d of %d]: B %d: T %d: L %d\n", + j, softs->num_devs, device->bus, device->target, + device->lun); + return true; +} - header->response_code = (buff[0] & 0x7f); +/* Return a given index for a specific bus, target, lun within the +* softs dev_list (This function is specifically for freebsd)*/ +int +pqisrc_find_btl_list_index(pqisrc_softstate_t *softs, + int bus, int target, int lun) +{ - if (!pqisrc_scsi_sense_valid(header)) - return false; + int index; + pqi_scsi_dev_t *temp_device; + for(index = 0; index < PQI_MAX_DEVICES; index++) { + if(softs->dev_list[index] == NULL) + continue; + temp_device = softs->dev_list[index]; + /* Match the devices then return the location + * of that device for further use*/ + if(bus == softs->bus_id && + target == temp_device->target && + lun == temp_device->lun){ + DBG_DISC("Returning device list index %d\n", index); + return index; - if (header->response_code >= 0x72) { - /* descriptor format */ - if (len > 1) - header->sense_key = (buff[1] & 0xf); - if (len > 2) - header->asc = buff[2]; - if (len > 3) - header->ascq = buff[3]; - if (len > 7) - header->additional_length = buff[7]; - } else { - /* fixed format */ - if (len > 2) - header->sense_key = (buff[2] & 0xf); - if (len > 7) { - len = (len < (buff[7] + 8)) ? - len : (buff[7] + 8); - if (len > 12) - header->asc = buff[12]; - if (len > 13) - header->ascq = buff[13]; + } + if ((temp_device->is_physical_device) && (target == temp_device->target) + && (temp_device->is_multi_lun)) { + return index; } } - - DBG_FUNC("OUT\n"); - - return true; + return INVALID_ELEM; } -/* - * Function used to build the internal raid request and analyze the response - */ +/* Return a given index for a specific device within the +* softs dev_list */ int -pqisrc_build_send_raid_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, - void *buff, size_t datasize, uint8_t cmd, uint16_t vpd_page, uint8_t *scsi3addr, - raid_path_error_info_elem_t *error_info) +pqisrc_find_device_list_index(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { - uint8_t *cdb; - int ret = PQI_STATUS_SUCCESS; - uint32_t tag = 0; - struct dma_mem device_mem; - sgt_t *sgd; + int index; + pqi_scsi_dev_t *temp_device; + for(index = 0; index < PQI_MAX_DEVICES; index++) { + if(softs->dev_list[index] == NULL) + continue; + temp_device = softs->dev_list[index]; + /* Match the devices then return the location + * of that device for further use*/ + if(device->bus == temp_device->bus && + device->target == temp_device->target + && device->lun == temp_device->lun){ + DBG_DISC("Returning device list index %d\n", index); + return index; - ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; - ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; + } + } + return INVALID_ELEM; +} - rcb_t *rcb = NULL; +/* Delete a given device from the softs dev_list*/ +int +pqisrc_delete_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) +{ - DBG_FUNC("IN\n"); + int index; + index = pqisrc_find_device_list_index(softs, device); + if (0 <= index && index < MAX_TARGET_BIT) { + softs->dev_list[index] = NULL; + softs->num_devs--; + DBG_NOTE("Removing device : B %d: T %d: L %d positioned at %d\n", + device->bus, device->target, device->lun, softs->num_devs); + return PQI_STATUS_SUCCESS; + } + if (index == INVALID_ELEM) { + DBG_NOTE("Invalid device, either it was already removed " + "or never added\n"); + return PQI_STATUS_FAILURE; + } + DBG_ERR("This is a bogus device\n"); + return PQI_STATUS_FAILURE; +} - memset(&device_mem, 0, sizeof(struct dma_mem)); +int +pqisrc_simple_dma_alloc(pqisrc_softstate_t *softs, struct dma_mem *device_mem, + size_t datasize, sgt_t *sgd) +{ + int ret = PQI_STATUS_SUCCESS; + + memset(device_mem, 0, sizeof(struct dma_mem)); /* for TUR datasize: 0 buff: NULL */ if (datasize) { - device_mem.tag = "device_mem"; - device_mem.size = datasize; - device_mem.align = PQISRC_DEFAULT_DMA_ALIGN; - ret = os_dma_mem_alloc(softs, &device_mem); + os_strlcpy(device_mem->tag, "device_mem", sizeof(device_mem->tag)); + device_mem->size = datasize; + device_mem->align = PQISRC_DEFAULT_DMA_ALIGN; + + ret = os_dma_mem_alloc(softs, device_mem); if (ret) { DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret); return ret; } - sgd = (sgt_t *)&request->sg_descriptors[0]; + ASSERT(device_mem->size == datasize); - sgd->addr = device_mem.dma_addr; + sgd->addr = device_mem->dma_addr; sgd->len = datasize; sgd->flags = SG_FLAG_LAST; } + return ret; +} + +/* + * Function used to build the internal raid request and analyze the response + */ +static int +pqisrc_build_send_raid_request(pqisrc_softstate_t *softs, struct dma_mem device_mem, + pqisrc_raid_req_t *request, void *buff, + size_t datasize, uint8_t cmd, uint8_t *scsi3addr, + raid_path_error_info_elem_t *error_info) +{ + + uint32_t tag = 0; + int ret = PQI_STATUS_SUCCESS; + + ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; + ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; + + rcb_t *rcb = NULL; + /* Build raid path request */ request->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; @@ -183,86 +428,6 @@ request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE; request->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; - cdb = request->cdb; - - switch (cmd) { - case SA_INQUIRY: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = SA_INQUIRY; - if (vpd_page & VPD_PAGE) { - cdb[1] = 0x1; - cdb[2] = (uint8_t)vpd_page; - } - cdb[4] = (uint8_t)datasize; - if (softs->timeout_in_passthrough) { - request->timeout_in_sec = PQISRC_INQUIRY_TIMEOUT; - } - break; - case SA_REPORT_LOG: - case SA_REPORT_PHYS: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = cmd; - if (cmd == SA_REPORT_PHYS) - cdb[1] = SA_REPORT_PHYS_EXTENDED; - else - cdb[1] = SA_REPORT_LOG_EXTENDED; - cdb[8] = (uint8_t)((datasize) >> 8); - cdb[9] = (uint8_t)datasize; - break; - case PQI_LOG_EXT_QUEUE_ENABLE: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = SA_REPORT_LOG; - cdb[1] = (PQI_LOG_EXT_QUEUE_DEPTH_ENABLED | SA_REPORT_LOG_EXTENDED); - cdb[8] = (uint8_t)((datasize) >> 8); - cdb[9] = (uint8_t)datasize; - break; - case TEST_UNIT_READY: - request->data_direction = SOP_DATA_DIR_NONE; - break; - case SA_GET_RAID_MAP: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = SA_CISS_READ; - cdb[1] = cmd; - cdb[8] = (uint8_t)((datasize) >> 8); - cdb[9] = (uint8_t)datasize; - break; - case SA_CACHE_FLUSH: - request->data_direction = SOP_DATA_DIR_FROM_DEVICE; - memcpy(device_mem.virt_addr, buff, datasize); - cdb[0] = BMIC_WRITE; - cdb[6] = BMIC_CACHE_FLUSH; - cdb[7] = (uint8_t)((datasize) << 8); - cdb[8] = (uint8_t)((datasize) >> 8); - break; - case BMIC_IDENTIFY_CONTROLLER: - case BMIC_IDENTIFY_PHYSICAL_DEVICE: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = BMIC_READ; - cdb[6] = cmd; - cdb[7] = (uint8_t)((datasize) << 8); - cdb[8] = (uint8_t)((datasize) >> 8); - break; - case BMIC_WRITE_HOST_WELLNESS: - request->data_direction = SOP_DATA_DIR_FROM_DEVICE; - memcpy(device_mem.virt_addr, buff, datasize); - cdb[0] = BMIC_WRITE; - cdb[6] = cmd; - cdb[7] = (uint8_t)((datasize) << 8); - cdb[8] = (uint8_t)((datasize) >> 8); - break; - case BMIC_SENSE_SUBSYSTEM_INFORMATION: - request->data_direction = SOP_DATA_DIR_TO_DEVICE; - cdb[0] = BMIC_READ; - cdb[6] = cmd; - cdb[7] = (uint8_t)((datasize) << 8); - cdb[8] = (uint8_t)((datasize) >> 8); - break; - default: - DBG_ERR("unknown command 0x%x", cmd); - ret = PQI_STATUS_FAILURE; - return ret; - } - tag = pqisrc_get_tag(&softs->taglist); if (INVALID_ELEM == tag) { DBG_ERR("Tag not available\n"); @@ -312,7 +477,7 @@ ret = PQI_STATUS_SUCCESS; } else{ - DBG_DISC("Error!! Bus=%u Target=%u, Cmd=0x%x," + DBG_WARN("Bus=%u Target=%u, Cmd=0x%x," "Ret=%d\n", BMIC_GET_LEVEL_2_BUS(scsi3addr), BMIC_GET_LEVEL_TWO_TARGET(scsi3addr), cmd, ret); @@ -344,7 +509,44 @@ return ret; } -/* common function used to send report physical and logical luns cmnds*/ +/* Use this if you need to specify specific target or if you want error info */ +int +pqisrc_prepare_send_raid(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, + void *buff, size_t datasize, uint8_t *scsi3addr, + raid_path_error_info_elem_t *error_info) +{ + struct dma_mem device_mem; + int ret = PQI_STATUS_SUCCESS; + uint8_t cmd = IS_BMIC_OPCODE(request->cmd.cdb[0]) ? request->cmd.cdb[6] : request->cmd.cdb[0]; + + ret = pqisrc_simple_dma_alloc(softs, &device_mem, datasize, request->sg_descriptors); + if (PQI_STATUS_SUCCESS != ret){ + DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret); + return ret; + } + + /* If we are sending out data, copy it over to dma buf */ + if (datasize && buff && request->data_direction == SOP_DATA_DIR_FROM_DEVICE) + memcpy(device_mem.virt_addr, buff, datasize); + + ret = pqisrc_build_send_raid_request(softs, device_mem, request, buff, datasize, + cmd, scsi3addr, error_info); + + return ret; +} + +/* Use this to target controller and don't care about error info */ +int +pqisrc_prepare_send_ctrlr_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, + void *buff, size_t datasize) +{ + raid_path_error_info_elem_t error_info; /* will be thrown away */ + uint8_t *scsi3addr = RAID_CTLR_LUNID; + + return pqisrc_prepare_send_raid(softs, request, buff, datasize, scsi3addr, &error_info); +} + +/* common function used to send report physical and logical luns cmds */ static int pqisrc_report_luns(pqisrc_softstate_t *softs, uint8_t cmd, void *buff, size_t buf_len) @@ -355,8 +557,29 @@ DBG_FUNC("IN\n"); memset(&request, 0, sizeof(request)); - ret = pqisrc_build_send_raid_request(softs, &request, buff, - buf_len, cmd, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); + + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + + switch (cmd) { + case SA_REPORT_LOG: + request.cmd.cdb[0] = SA_REPORT_LOG; + request.cmd.cdb[1] = SA_REPORT_LOG_EXTENDED; + break; + case SA_REPORT_PHYS: + request.cmd.cdb[0] = SA_REPORT_PHYS; + request.cmd.cdb[1] = SA_REPORT_PHYS_EXTENDED; + break; + /* @todo: 0x56 does not exist, this is kludgy, need to pass in options */ + case PQI_LOG_EXT_QUEUE_ENABLE: + request.cmd.cdb[0] = SA_REPORT_LOG; + request.cmd.cdb[1] = (PQI_LOG_EXT_QUEUE_DEPTH_ENABLED | SA_REPORT_LOG_EXTENDED); + break; + } + + request.cmd.cdb[8] = (uint8_t)((buf_len) >> 8); + request.cmd.cdb[9] = (uint8_t)buf_len; + + ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, buf_len); DBG_FUNC("OUT\n"); @@ -464,7 +687,7 @@ } if (list_len == 0) { - DBG_INFO("list_len is 0\n"); + DBG_DISC("list_len is 0\n"); memcpy(lun_data, &report_lun_header, sizeof(report_lun_header)); goto out; } @@ -527,11 +750,22 @@ return ret; } +#ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG + /* Save the report_log_dev buffer for deciding rescan requirement from OS driver*/ + if(softs->log_dev_data_length != *log_data_length) { + if(softs->log_dev_list) + os_mem_free(softs, softs->log_dev_list, softs->log_dev_data_length); + softs->log_dev_list = os_mem_alloc(softs, *log_data_length); + } + memcpy(softs->log_dev_list, *logical_dev_list, *log_data_length); + softs->log_dev_data_length = *log_data_length; +#endif + ret = pqisrc_get_queue_lun_list(softs, PQI_LOG_EXT_QUEUE_ENABLE, queue_dev_list, queue_data_length); - if (ret) { - DBG_ERR("report logical LUNs failed"); - return ret; - } + if (ret) { + DBG_ERR("report logical LUNs failed"); + return ret; + } logdev_data = *logical_dev_list; @@ -573,34 +807,21 @@ return ret; } -/* Subroutine used to set Bus-Target-Lun for the requested device */ -static inline void -pqisrc_set_btl(pqi_scsi_dev_t *device, - int bus, int target, int lun) -{ - DBG_FUNC("IN\n"); - - device->bus = bus; - device->target = target; - device->lun = lun; - - DBG_FUNC("OUT\n"); -} - -inline -boolean_t pqisrc_is_external_raid_device(pqi_scsi_dev_t *device) +inline boolean_t +pqisrc_is_external_raid_device(pqi_scsi_dev_t *device) { return device->is_external_raid_device; } -static inline boolean_t pqisrc_is_external_raid_addr(uint8_t *scsi3addr) +static inline boolean_t +pqisrc_is_external_raid_addr(uint8_t *scsi3addr) { return scsi3addr[2] != 0; } /* Function used to assign Bus-Target-Lun for the requested device */ static void -pqisrc_assign_btl(pqi_scsi_dev_t *device) +pqisrc_assign_btl(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { uint8_t *scsi3addr; uint32_t lunid; @@ -613,26 +834,22 @@ lunid = GET_LE32(scsi3addr); if (pqisrc_is_hba_lunid(scsi3addr)) { - /* The specified device is the controller. */ - pqisrc_set_btl(device, PQI_HBA_BUS, PQI_CTLR_INDEX, (lunid & 0x3fff) + 1); + /* The specified device is the controller. */ + pqisrc_set_btl(device, PQI_HBA_BUS, PQI_CTLR_INDEX, (lunid & 0x3fff)); device->target_lun_valid = true; return; } + /* When the specified device is a logical volume, + * physicals will be given targets in pqisrc update + * device list in pqisrc scan devices. */ if (pqisrc_is_logical_device(device)) { - if (pqisrc_is_external_raid_device(device)) { - DBG_DISC("External Raid Device!!!"); - bus = PQI_EXTERNAL_RAID_VOLUME_BUS; - target = (lunid >> 16) & 0x3fff; - lun = lunid & 0xff; - } else { bus = PQI_RAID_VOLUME_BUS; lun = (lunid & 0x3fff) + 1; target = 0; - } - pqisrc_set_btl(device, bus, target, lun); - device->target_lun_valid = true; - return; + pqisrc_set_btl(device, bus, target, lun); + device->target_lun_valid = true; + return; } DBG_FUNC("OUT\n"); @@ -650,38 +867,25 @@ DBG_FUNC("IN\n"); memset(&request, 0, sizeof(request)); - ret = pqisrc_build_send_raid_request(softs, &request, buff, buf_len, - SA_INQUIRY, vpd_page, scsi3addr, &error_info); - - DBG_FUNC("OUT\n"); - return ret; -} - -#if 0 -/* Function used to parse the sense information from response */ -static void -pqisrc_fetch_sense_info(const uint8_t *sense_data, - unsigned sense_data_length, uint8_t *sense_key, uint8_t *asc, uint8_t *ascq) -{ - struct sense_header_scsi header; - DBG_FUNC("IN\n"); - - *sense_key = 0; - *ascq = 0; - *asc = 0; + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + request.cmd.cdb[0] = SA_INQUIRY; + if (vpd_page & VPD_PAGE) { + request.cmd.cdb[1] = 0x1; + request.cmd.cdb[2] = (uint8_t)vpd_page; + } + ASSERT(buf_len < 256); + request.cmd.cdb[4] = (uint8_t)buf_len; - if (pqisrc_update_scsi_sense(sense_data, sense_data_length, &header)) { - *sense_key = header.sense_key; - *asc = header.asc; - *ascq = header.ascq; + if (softs->timeout_in_passthrough) { + request.timeout_in_sec = PQISRC_INQUIRY_TIMEOUT; } - DBG_DISC("sense_key: %x asc: %x ascq: %x\n", *sense_key, *asc, *ascq); + pqisrc_prepare_send_raid(softs, &request, buff, buf_len, scsi3addr, &error_info); DBG_FUNC("OUT\n"); + return ret; } -#endif /* Determine logical volume status from vpd buffer.*/ static void pqisrc_get_dev_vol_status(pqisrc_softstate_t *softs, @@ -732,6 +936,7 @@ return; } + /* Validate the RAID map parameters */ static int pqisrc_raid_map_validation(pqisrc_softstate_t *softs, @@ -740,6 +945,7 @@ char *error_msg; uint32_t raidmap_size; uint32_t r5or6_blocks_per_row; +/* unsigned phys_dev_num; */ DBG_FUNC("IN\n"); @@ -792,48 +998,45 @@ pqisrc_get_device_raidmap(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { int ret = PQI_STATUS_SUCCESS; - int raidmap_size; + int raidmap_alloc_size = sizeof(pqisrc_raid_map_t); + int raidmap_reported_size; + int structure_size; + int ii; + int *next_offload_to_mirror; pqisrc_raid_req_t request; pqisrc_raid_map_t *raid_map; DBG_FUNC("IN\n"); - raid_map = os_mem_alloc(softs, sizeof(*raid_map)); - if (!raid_map) - return PQI_STATUS_FAILURE; - - memset(&request, 0, sizeof(request)); - ret = pqisrc_build_send_raid_request(softs, &request, raid_map, sizeof(*raid_map), - SA_GET_RAID_MAP, 0, device->scsi3addr, NULL); - - if (ret) { - DBG_ERR("error in build send raid req ret=%d\n", ret); - goto err_out; - } - - raidmap_size = LE_32(raid_map->structure_size); - if (raidmap_size > sizeof(*raid_map)) { - DBG_NOTE("Raid map is larger than 1024 entries, request once again"); - os_mem_free(softs, (char*)raid_map, sizeof(*raid_map)); - - raid_map = os_mem_alloc(softs, raidmap_size); + for (ii = 0; ii < 2; ii++) + { + raid_map = os_mem_alloc(softs, raidmap_alloc_size); if (!raid_map) return PQI_STATUS_FAILURE; + memset(&request, 0, sizeof(request)); + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + request.cmd.cdb[0] = SA_CISS_READ; + request.cmd.cdb[1] = SA_GET_RAID_MAP; + request.cmd.cdb[8] = (uint8_t)((raidmap_alloc_size) >> 8); + request.cmd.cdb[9] = (uint8_t)(raidmap_alloc_size); + + ret = pqisrc_prepare_send_raid(softs, &request, raid_map, raidmap_alloc_size, device->scsi3addr, NULL); - ret = pqisrc_build_send_raid_request(softs, &request, raid_map, raidmap_size, - SA_GET_RAID_MAP, 0, device->scsi3addr, NULL); if (ret) { DBG_ERR("error in build send raid req ret=%d\n", ret); goto err_out; } - if(LE_32(raid_map->structure_size) != raidmap_size) { - DBG_WARN("Expected raid map size %d bytes and got %d bytes\n", - raidmap_size,LE_32(raid_map->structure_size)); - goto err_out; - } + raidmap_reported_size = LE_32(raid_map->structure_size); + if (raidmap_reported_size <= raidmap_alloc_size) + break; + + DBG_NOTE("Raid map is larger than 1024 entries, request once again"); + os_mem_free(softs, (char*)raid_map, raidmap_alloc_size); + + raidmap_alloc_size = raidmap_reported_size; } ret = pqisrc_raid_map_validation(softs, device, raid_map); @@ -842,7 +1045,15 @@ goto err_out; } + structure_size = raid_map->data_disks_per_row * sizeof(*next_offload_to_mirror); + next_offload_to_mirror = os_mem_alloc(softs, structure_size); + if (!next_offload_to_mirror) { + ret = PQI_STATUS_FAILURE; + goto err_out; + } + device->raid_map = raid_map; + device->offload_to_mirror = next_offload_to_mirror; DBG_FUNC("OUT\n"); return 0; @@ -928,7 +1139,7 @@ { int ret = PQI_STATUS_SUCCESS; uint8_t *inq_buff; - int retry = MAX_RETRIES; + int retry = 3; DBG_FUNC("IN\n"); @@ -996,8 +1207,14 @@ DBG_FUNC("IN\n"); memset(&request, 0, sizeof(request)); - ret = pqisrc_build_send_raid_request(softs, &request, buff, sizeof(*buff), - BMIC_IDENTIFY_CONTROLLER, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); + + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_READ; + request.cmd.bmic_cdb.cmd = BMIC_IDENTIFY_CONTROLLER; + request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*buff)); + + ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, sizeof(*buff)); + DBG_FUNC("OUT\n"); return ret; @@ -1055,11 +1272,16 @@ memset(&request, 0, sizeof(request)); bmic_device_index = BMIC_GET_DRIVE_NUMBER(device->scsi3addr); - request.cdb[2] = (uint8_t)bmic_device_index; - request.cdb[9] = (uint8_t)(bmic_device_index >> 8); - ret = pqisrc_build_send_raid_request(softs, &request, buff, buf_len, - BMIC_IDENTIFY_PHYSICAL_DEVICE, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); + request.data_direction = SOP_DATA_DIR_TO_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_READ; + request.cmd.bmic_cdb.cmd = BMIC_IDENTIFY_PHYSICAL_DEVICE; + request.cmd.bmic_cdb.xfer_len = BE_16(buf_len); + request.cmd.cdb[2] = (uint8_t)bmic_device_index; + request.cmd.cdb[9] = (uint8_t)(bmic_device_index >> 8); + + ret = pqisrc_prepare_send_ctrlr_request(softs, &request, buff, buf_len); + DBG_FUNC("OUT\n"); return ret; } @@ -1097,6 +1319,9 @@ &id_phys->alternate_paths_phys_connector, sizeof(device->phys_connector)); device->bay = id_phys->phys_bay_in_box; + if (id_phys->multi_lun_device_lun_count) { + device->is_multi_lun = true; + } DBG_DISC("BMIC DEV_TYPE: %x QUEUE DEPTH: 0x%x \n", device->device_type, device->queue_depth); DBG_FUNC("OUT\n"); @@ -1104,28 +1329,28 @@ /* Function used to find the entry of the device in a list */ -static -device_status_t pqisrc_scsi_find_entry(pqisrc_softstate_t *softs, +static device_status_t +pqisrc_scsi_find_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device_to_find, pqi_scsi_dev_t **same_device) { pqi_scsi_dev_t *device; - int i,j; + int i; DBG_FUNC("IN\n"); for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - if (pqisrc_scsi3addr_equal(device_to_find->scsi3addr, - device->scsi3addr)) { - *same_device = device; - if (pqisrc_device_equal(device_to_find, device)) { - if (device_to_find->volume_offline) - return DEVICE_CHANGED; - return DEVICE_UNCHANGED; - } - return DEVICE_CHANGED; + device = softs->dev_list[i]; + if(device == NULL) + continue; + if (pqisrc_scsi3addr_equal(device_to_find->scsi3addr, + device->scsi3addr)) { + *same_device = device; + if (device->in_remove == true) + return DEVICE_IN_REMOVE; + if (pqisrc_device_equal(device_to_find, device)) { + if (device_to_find->volume_offline) + return DEVICE_CHANGED; + return DEVICE_UNCHANGED; } + return DEVICE_CHANGED; } } DBG_FUNC("OUT\n"); @@ -1148,10 +1373,10 @@ device_exist->is_physical_device = new_device->is_physical_device; device_exist->is_external_raid_device = new_device->is_external_raid_device; - - if ((device_exist->volume_status == SA_LV_QUEUED_FOR_EXPANSION || - device_exist->volume_status == SA_LV_UNDERGOING_EXPANSION) && - new_device->volume_status == SA_LV_OK) { + /* Whenever a logical device expansion happens, reprobe of + * all existing LDs will be triggered, which is resulting + * in updating the size to the os. */ + if ((softs->ld_rescan) && (pqisrc_is_logical_device(device_exist))) { device_exist->scsi_rescan = true; } @@ -1170,105 +1395,19 @@ device_exist->offload_config = new_device->offload_config; device_exist->offload_enabled_pending = new_device->offload_enabled_pending; - device_exist->offload_to_mirror = 0; + if (device_exist->offload_to_mirror) + os_mem_free(softs, + (int *) device_exist->offload_to_mirror, + sizeof(*(device_exist->offload_to_mirror))); + device_exist->offload_to_mirror = new_device->offload_to_mirror; if (device_exist->raid_map) os_mem_free(softs, - (char *)device_exist->raid_map, - sizeof(*device_exist->raid_map)); + (char *)device_exist->raid_map, + sizeof(*device_exist->raid_map)); device_exist->raid_map = new_device->raid_map; - /* To prevent this from being freed later. */ + /* To prevent these from being freed later. */ new_device->raid_map = NULL; - DBG_FUNC("OUT\n"); -} - -/* Validate the ioaccel_handle for a newly added device */ -static -pqi_scsi_dev_t *pqisrc_identify_device_via_ioaccel( - pqisrc_softstate_t *softs, uint32_t ioaccel_handle) -{ - pqi_scsi_dev_t *device; - int i,j; - DBG_FUNC("IN\n"); - for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - if (device->devtype != DISK_DEVICE) - continue; - if (pqisrc_is_logical_device(device)) - continue; - if (device->ioaccel_handle == ioaccel_handle) - return device; - } - } - DBG_FUNC("OUT\n"); - - return NULL; -} - -/* Get the scsi device queue depth */ -static void -pqisrc_update_log_dev_qdepth(pqisrc_softstate_t *softs) -{ - unsigned i; - unsigned phys_dev_num; - unsigned num_raidmap_entries; - unsigned queue_depth; - pqisrc_raid_map_t *raid_map; - pqi_scsi_dev_t *device; - raidmap_data_t *dev_data; - pqi_scsi_dev_t *phys_disk; - unsigned j; - unsigned k; - - DBG_FUNC("IN\n"); - - for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - if (device->devtype != DISK_DEVICE) - continue; - if (!pqisrc_is_logical_device(device)) - continue; - if (pqisrc_is_external_raid_device(device)) - continue; - device->queue_depth = PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; - raid_map = device->raid_map; - if (!raid_map) - return; - dev_data = raid_map->dev_data; - phys_dev_num = LE_16(raid_map->layout_map_count) * - (LE_16(raid_map->data_disks_per_row) + - LE_16(raid_map->metadata_disks_per_row)); - num_raidmap_entries = phys_dev_num * - LE_16(raid_map->row_cnt); - - queue_depth = 0; - for (k = 0; k < num_raidmap_entries; k++) { - phys_disk = pqisrc_identify_device_via_ioaccel(softs, - dev_data[k].ioaccel_handle); - - if (!phys_disk) { - DBG_WARN( - "Failed to find physical disk handle for logical drive %016llx\n", - (unsigned long long)BE_64(device->scsi3addr[0])); - device->offload_enabled = false; - device->offload_enabled_pending = false; - if (raid_map) - os_mem_free(softs, (char *)raid_map, sizeof(*raid_map)); - device->raid_map = NULL; - return; - } - - queue_depth += phys_disk->queue_depth; - } - - device->queue_depth = queue_depth; - } /* end inner loop */ - }/* end outer loop */ + new_device->offload_to_mirror = NULL; DBG_FUNC("OUT\n"); } @@ -1281,6 +1420,9 @@ device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status); device->invalid = false; + device->schedule_rescan = false; + device->softs = softs; + device->in_remove = false; if(device->expose_device) { pqisrc_init_device_active_io(softs, device); @@ -1299,7 +1441,6 @@ DBG_FUNC("IN\n"); DBG_NOTE("vendor: %s model: %s bus:%d target:%d lun:%d is_physical_device:0x%x expose_device:0x%x volume_offline 0x%x volume_status 0x%x \n", device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status); - device->invalid = true; if (device->expose_device == false) { /*Masked physical devices are not been exposed to storage stack. @@ -1307,6 +1448,7 @@ *device memory, Target ID,etc., here. */ DBG_NOTE("Deallocated Masked Device Resources.\n"); + /* softs->device_list[device->target][device->lun] = NULL; */ pqisrc_free_device(softs,device); return; } @@ -1317,6 +1459,7 @@ DBG_FUNC("OUT\n"); } + /* * When exposing new device to OS fails then adjst list according to the * mid scsi list @@ -1324,6 +1467,9 @@ static void pqisrc_adjust_list(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { + int i; + unsigned char addr1[8], addr2[8]; + pqi_scsi_dev_t *temp_device; DBG_FUNC("IN\n"); if (!device) { @@ -1332,7 +1478,36 @@ } OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); - softs->device_list[device->target][device->lun] = NULL; + uint8_t *scsi3addr; + /*For external raid device, there can be multiple luns + *with same target. So while freeing external raid device, + *free target only after removing all luns with same target.*/ + if (pqisrc_is_external_raid_device(device)) { + memcpy(addr1, device->scsi3addr, 8); + for(i = 0; i < PQI_MAX_DEVICES; i++) { + if(softs->dev_list[i] == NULL) + continue; + temp_device = softs->dev_list[i]; + memcpy(addr2, temp_device->scsi3addr, 8); + if(memcmp(addr1, addr2, 8) == 0) { + continue; + } + if (addr1[2] == addr2[2]) { + break; + } + } + if(i == PQI_MAX_DEVICES) { + pqisrc_remove_target_bit(softs, device->target); + } + } + + if(pqisrc_delete_softs_entry(softs, device) == PQI_STATUS_SUCCESS){ + scsi3addr = device->scsi3addr; + if (!pqisrc_is_logical_device(device) && !MASKED_DEVICE(scsi3addr)){ + DBG_NOTE("About to remove target bit %d \n", device->target); + pqisrc_remove_target_bit(softs, device->target); + } + } OS_RELEASE_SPINLOCK(&softs->devlist_lock); pqisrc_device_mem_free(softs, device); @@ -1341,7 +1516,7 @@ /* Debug routine used to display the RAID volume status of the device */ static void -pqisrc_display_volume_status(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) +pqisrc_display_volume_status(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { char *status; @@ -1391,6 +1566,7 @@ break; case SA_LV_QUEUED_FOR_EXPANSION: status = "Volume queued for expansion"; + break; case SA_LV_EJECTED: status = "Volume ejected"; break; @@ -1414,7 +1590,7 @@ break; } - DBG_DISC("scsi BTL %d:%d:%d %s\n", + DBG_NOTE("scsi BTL %d:%d:%d %s\n", device->bus, device->target, device->lun, status); DBG_FUNC("OUT\n"); } @@ -1428,6 +1604,9 @@ if (device->raid_map) { os_mem_free(softs, (char *)device->raid_map, sizeof(pqisrc_raid_map_t)); } + if (device->offload_to_mirror) { + os_mem_free(softs, (int *)device->offload_to_mirror, sizeof(*(device->offload_to_mirror))); + } os_mem_free(softs, (char *)device,sizeof(*device)); DBG_FUNC("OUT\n"); @@ -1435,11 +1614,13 @@ /* OS should call this function to free the scsi device */ void -pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t *device) +pqisrc_free_device(pqisrc_softstate_t * softs, pqi_scsi_dev_t *device) { rcb_t *rcb; - int i; - + uint8_t *scsi3addr; + int i, index; + pqi_scsi_dev_t *temp_device; + unsigned char addr1[8], addr2[8]; /* Clear the "device" field in the rcb. * Response coming after device removal shouldn't access this field */ @@ -1451,21 +1632,53 @@ rcb->dvp = NULL; } } + /* Find the entry in device list for the freed device softs->dev_list[i]& + *make it NULL before freeing the device memory + */ + index = pqisrc_find_device_list_index(softs, device); OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); - - if (!pqisrc_is_logical_device(device)) { - pqisrc_free_tid(softs,device->target); + scsi3addr = device->scsi3addr; + if (!pqisrc_is_logical_device(device) && !MASKED_DEVICE(scsi3addr)) { + DBG_NOTE("Giving back target %i \n", device->target); + pqisrc_remove_target_bit(softs, device->target); + } + /*For external raid device, there can be multiple luns + *with same target. So while freeing external raid device, + *free target only after removing all luns with same target.*/ + if (pqisrc_is_external_raid_device(device)) { + memcpy(addr1, device->scsi3addr, 8); + for(i = 0; i < PQI_MAX_DEVICES; i++) { + if(softs->dev_list[i] == NULL) + continue; + temp_device = softs->dev_list[i]; + memcpy(addr2, temp_device->scsi3addr, 8); + if(memcmp(addr1, addr2, 8) == 0) { + continue; + } + if (addr1[2] == addr2[2]) { + break; + } + } + if(i == PQI_MAX_DEVICES) { + pqisrc_remove_target_bit(softs, device->target); + } } - softs->device_list[device->target][device->lun] = NULL; - - pqisrc_device_mem_free(softs, device); + if (index >= 0 && index < PQI_MAX_DEVICES) + softs->dev_list[index] = NULL; + if (device->expose_device == true){ + pqisrc_delete_softs_entry(softs, device); + DBG_NOTE("Removed memory for device : B %d: T %d: L %d\n", + device->bus, device->target, device->lun); + pqisrc_device_mem_free(softs, device); + } OS_RELEASE_SPINLOCK(&softs->devlist_lock); } + /* Update the newly added devices to the device list */ static void pqisrc_update_device_list(pqisrc_softstate_t *softs, @@ -1479,9 +1692,7 @@ pqi_scsi_dev_t **added = NULL; pqi_scsi_dev_t **removed = NULL; int nadded = 0, nremoved = 0; - int j; - int tid = 0; - boolean_t driver_queue_depth_flag = false; + uint8_t *scsi3addr; DBG_FUNC("IN\n"); @@ -1496,13 +1707,13 @@ OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - device->device_gone = true; - } + if(softs->dev_list[i] == NULL) + continue; + device = softs->dev_list[i]; + device->device_gone = true; } + + /* TODO:Remove later */ DBG_IO("Device list used an array\n"); for (i = 0; i < num_new_devices; i++) { device = new_device_list[i]; @@ -1525,21 +1736,33 @@ /* Actual device gone need to add device to list*/ device->new_device = true; break; + case DEVICE_IN_REMOVE: + /*Older device with same target/lun is in removal stage*/ + /*New device will be added/scanned when same target/lun + * device_list[] gets removed from the OS target + * free call*/ + device->new_device = false; + same_device->schedule_rescan = true; + break; default: break; } } + /* Process all devices that have gone away. */ - for(i = 0, nremoved = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) + for(i = 0; i < PQI_MAX_DEVICES; i++) { + device = softs->dev_list[i]; + if(device == NULL) + continue; + if (device->device_gone) { + if(device->in_remove == true) + { continue; - device = softs->device_list[i][j]; - if (device->device_gone) { - softs->device_list[device->target][device->lun] = NULL; - removed[nremoved] = device; - nremoved++; } + device->in_remove = true; + removed[nremoved] = device; + softs->num_devs--; + nremoved++; } } @@ -1551,39 +1774,32 @@ if (device->volume_offline) continue; - /* physical device */ - if (!pqisrc_is_logical_device(device)) { - tid = pqisrc_alloc_tid(softs); - if(INVALID_ELEM != tid) - pqisrc_set_btl(device, PQI_PHYSICAL_DEVICE_BUS, tid, 0); - } - - /* This is not expected. We may lose the reference to the old device entry. - * If the target & lun ids are same, it is supposed to detect as an existing - * device, and not as a new device - */ - if(softs->device_list[device->target][device->lun] != NULL) { - DBG_WARN("Overwriting T : %d L :%d\n",device->target,device->lun); + /* Find out which devices to add to the driver list + * in softs->dev_list */ + scsi3addr = device->scsi3addr; + if (device->expose_device || !MASKED_DEVICE(scsi3addr)){ + if(pqisrc_add_softs_entry(softs, device, scsi3addr)){ + /* To prevent this entry from being freed later. */ + new_device_list[i] = NULL; + added[nadded] = device; + nadded++; + } } - softs->device_list[device->target][device->lun] = device; - - DBG_DISC("Added device %p at B : %d T : %d L : %d\n",device, - device->bus,device->target,device->lun); - /* To prevent this entry from being freed later. */ - new_device_list[i] = NULL; - added[nadded] = device; - nadded++; } - for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - device->offload_enabled = device->offload_enabled_pending; + device = softs->dev_list[i]; + if(device == NULL) + continue; + if (device->offload_enabled != device->offload_enabled_pending) + { + DBG_NOTE("[%d:%d:%d]Changing AIO to %d (was %d)\n", + device->bus, device->target, device->lun, + device->offload_enabled_pending, + device->offload_enabled); } + device->offload_enabled = device->offload_enabled_pending; } OS_RELEASE_SPINLOCK(&softs->devlist_lock); @@ -1594,36 +1810,34 @@ continue; pqisrc_display_device_info(softs, "removed", device); pqisrc_remove_device(softs, device); - } + OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); + for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - /* - * Notify the OS upper layer if the queue depth of any existing device has - * changed. - */ - if (device->queue_depth != - device->advertised_queue_depth) { - device->advertised_queue_depth = device->queue_depth; - /* TBD: Call OS upper layer function to change device Q depth */ - } - if (device->firmware_queue_depth_set == false) - driver_queue_depth_flag = true; - if (device->scsi_rescan) - os_rescan_target(softs, device); + if(softs->dev_list[i] == NULL) + continue; + device = softs->dev_list[i]; + if (device->in_remove) + continue; + /* + * If firmware queue depth is corrupt or not working + * use the PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH + * which is 0. That means there is no limit to the + * queue depth all the way up to the controller + * queue depth + */ + if (pqisrc_is_logical_device(device) && + device->firmware_queue_depth_set == false) + device->queue_depth = PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; + + if (device->scsi_rescan) { + os_rescan_target(softs, device); } } - /* - * If firmware queue depth is corrupt or not working - * use driver method to re-calculate the queue depth - * for all logical devices - */ - if (driver_queue_depth_flag) - pqisrc_update_log_dev_qdepth(softs); + softs->ld_rescan = false; + + OS_RELEASE_SPINLOCK(&softs->devlist_lock); for(i = 0; i < nadded; i++) { device = added[i]; @@ -1631,8 +1845,7 @@ ret = pqisrc_add_device(softs, device); if (ret) { DBG_WARN("scsi %d:%d:%d addition failed, device not added\n", - device->bus, device->target, - device->lun); + device->bus, device->target, device->lun); pqisrc_adjust_list(softs, device); continue; } @@ -1654,6 +1867,15 @@ } } + for (i = 0; i < PQI_MAX_DEVICES; i++) { + device = softs->dev_list[i]; + if(device == NULL) + continue; + DBG_DISC("Current device %d : B%d:T%d:L%d\n", + i, device->bus, device->target, + device->lun); + } + free_and_out: if (added) os_mem_free(softs, (char *)added, @@ -1701,16 +1923,21 @@ strncpy(host_wellness_driver_ver->driver_version + strlen(softs->os_name), PQISRC_DRIVER_VERSION, sizeof(host_wellness_driver_ver->driver_version) - strlen(softs->os_name)); } else { - DBG_DISC("OS name length(%lu) is longer than buffer of driver_version\n", - strlen(softs->os_name)); + DBG_DISC("OS name length(%u) is longer than buffer of driver_version\n", + (unsigned int)strlen(softs->os_name)); } host_wellness_driver_ver->driver_version[sizeof(host_wellness_driver_ver->driver_version) - 1] = '\0'; host_wellness_driver_ver->end_tag[0] = 'Z'; host_wellness_driver_ver->end_tag[1] = 'Z'; - rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_driver_ver,data_length, - BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); + + request.data_direction = SOP_DATA_DIR_FROM_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_WRITE; + request.cmd.bmic_cdb.cmd = BMIC_WRITE_HOST_WELLNESS; + request.cmd.bmic_cdb.xfer_len = BE_16(data_length); + + rval = pqisrc_prepare_send_ctrlr_request(softs, &request, host_wellness_driver_ver, data_length); os_mem_free(softs, (char *)host_wellness_driver_ver, data_length); @@ -1757,15 +1984,27 @@ host_wellness_time->end_tag[0] = 'Z'; host_wellness_time->end_tag[1] = 'Z'; - rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_time,data_length, - BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); + + request.data_direction = SOP_DATA_DIR_FROM_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_WRITE; + request.cmd.bmic_cdb.cmd = BMIC_WRITE_HOST_WELLNESS; + request.cmd.bmic_cdb.xfer_len = BE_16(data_length); + + rval = pqisrc_prepare_send_ctrlr_request(softs, &request, host_wellness_time, data_length); os_mem_free(softs, (char *)host_wellness_time, data_length); DBG_FUNC("OUT"); return rval; } - +static void +pqisrc_get_device_vpd_info(pqisrc_softstate_t *softs, + bmic_ident_physdev_t *bmic_phy_info,pqi_scsi_dev_t *device) +{ + DBG_FUNC("IN\n"); + memcpy(&device->wwid, &bmic_phy_info->padding[79], sizeof(device->wwid)); + DBG_FUNC("OUT\n"); +} /* * Function used to perform a rescan of scsi devices * for any config change events @@ -1774,7 +2013,7 @@ pqisrc_scan_devices(pqisrc_softstate_t *softs) { boolean_t is_physical_device; - int ret = PQI_STATUS_FAILURE; + int ret; int i; int new_dev_cnt; int phy_log_dev_cnt; @@ -1794,7 +2033,9 @@ bmic_ident_physdev_t *bmic_phy_info = NULL; pqi_scsi_dev_t **new_device_list = NULL; pqi_scsi_dev_t *device = NULL; - +#ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG + int num_ext_raid_devices = 0; +#endif DBG_FUNC("IN\n"); @@ -1815,7 +2056,7 @@ / sizeof(logical_queue_dev_list->lun_entries[0]); - DBG_DISC("physical_cnt %d logical_cnt %d queue_cnt %d\n", physical_cnt, logical_cnt, logical_queue_cnt); + DBG_DISC("physical_cnt %u logical_cnt %u queue_cnt %u\n", physical_cnt, logical_cnt, logical_queue_cnt); if (physical_cnt) { bmic_phy_info = os_mem_alloc(softs, sizeof(*bmic_phy_info)); @@ -1863,6 +2104,9 @@ /* Save the target sas adderess for external raid device */ if(lun_ext_entry->device_type == CONTROLLER_DEVICE) { +#ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG + num_ext_raid_devices++; +#endif int target = lun_ext_entry->lunid[3] & 0x3f; softs->target_sas_addr[target] = BE_64(lun_ext_entry->wwid); } @@ -1881,9 +2125,9 @@ device->is_external_raid_device = pqisrc_is_external_raid_addr(scsi3addr); /* The multiplier is the value we multiply the queue - * depth value with to get the actual queue depth. - * If multiplier is 1 multiply by 256 if - * multiplier 0 then multiply by 16 */ + * depth value with to get the actual queue depth. + * If multiplier is 1 multiply by 256 if + * multiplier 0 then multiply by 16 */ multiplier = logical_queue_dev_list->lun_entries[i - physical_cnt].multiplier; qdepth = logical_queue_dev_list->lun_entries[i - physical_cnt].queue_depth; if (multiplier) { @@ -1898,11 +2142,12 @@ device->queue_depth = softs->adapterQDepth; } if ((multiplier == 1) && - (qdepth <= 0 || qdepth >= MAX_RAW_M256_QDEPTH)) + (qdepth >= MAX_RAW_M256_QDEPTH)) device->firmware_queue_depth_set = false; if ((multiplier == 0) && - (qdepth <= 0 || qdepth >= MAX_RAW_M16_QDEPTH)) + (qdepth >= MAX_RAW_M16_QDEPTH)) device->firmware_queue_depth_set = false; + } @@ -1915,12 +2160,12 @@ continue; } /* Set controller queue depth to what - * it was from the scsi midlayer */ + * it was from the scsi midlayer */ if (device->devtype == RAID_DEVICE) { device->firmware_queue_depth_set = true; device->queue_depth = softs->adapterQDepth; } - pqisrc_assign_btl(device); + pqisrc_assign_btl(softs, device); /* * Expose all devices except for physical devices that @@ -1954,9 +2199,12 @@ if (device->is_physical_device) { device->ioaccel_handle = lun_ext_entry->ioaccel_handle; - device->sas_address = BE_64(lun_ext_entry->wwid); pqisrc_get_physical_device_info(softs, device, bmic_phy_info); + if ( (!softs->page83id_in_rpl) && (bmic_phy_info->device_type == BMIC_DEVICE_TYPE_SATA)) { + pqisrc_get_device_vpd_info(softs, bmic_phy_info, device); + } + device->sas_address = BE_64(device->wwid); } new_dev_cnt++; break; @@ -1987,7 +2235,12 @@ } } DBG_DISC("new_dev_cnt %d\n", new_dev_cnt); - +#ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG + if(num_ext_raid_devices) + os_start_rescan_timer(softs); + else + os_stop_rescan_timer(softs); +#endif pqisrc_update_device_list(softs, new_device_list, new_dev_cnt); err_out: @@ -2002,7 +2255,7 @@ } } os_mem_free(softs, (char *)new_device_list, - sizeof(*new_device_list) * ndev_allocated); + sizeof(*new_device_list) * ndev_allocated); } if(physical_dev_list) os_mem_free(softs, (char *)physical_dev_list, phys_data_length); @@ -2025,18 +2278,15 @@ void pqisrc_cleanup_devices(pqisrc_softstate_t *softs) { - - int i = 0,j = 0; - pqi_scsi_dev_t *dvp = NULL; + int i = 0; + pqi_scsi_dev_t *device = NULL; DBG_FUNC("IN\n"); - - for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if (softs->device_list[i][j] == NULL) - continue; - dvp = softs->device_list[i][j]; - pqisrc_device_mem_free(softs, dvp); - } + for(i = 0; i < PQI_MAX_DEVICES; i++) { + if(softs->dev_list[i] == NULL) + continue; + device = softs->dev_list[i]; + pqisrc_device_mem_free(softs, device); } + DBG_FUNC("OUT\n"); } diff --git a/sys/dev/smartpqi/smartpqi_event.c b/sys/dev/smartpqi/smartpqi_event.c --- a/sys/dev/smartpqi/smartpqi_event.c +++ b/sys/dev/smartpqi/smartpqi_event.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,6 +62,7 @@ struct pqi_event *event) { + int ret; pqi_event_acknowledge_request_t request; ib_queue_t *ib_q = &softs->op_raid_ib_q[0]; int tmo = PQISRC_EVENT_ACK_RESP_TIMEOUT; @@ -77,8 +78,11 @@ request.additional_event_id = event->additional_event_id; /* Submit Event Acknowledge */ - - pqisrc_submit_cmnd(softs, ib_q, &request); + ret = pqisrc_submit_cmnd(softs, ib_q, &request); + if (ret != PQI_STATUS_SUCCESS) { + DBG_ERR("Unable to submit acknowledge command\n"); + goto out; + } /* * We have to special-case this type of request because the firmware @@ -91,9 +95,10 @@ if (tmo <= 0) { DBG_ERR("wait for event acknowledge timed out\n"); DBG_ERR("tmo : %d\n",tmo); - } + } - DBG_FUNC(" OUT\n"); +out: + DBG_FUNC("OUT\n"); } /* @@ -178,11 +183,10 @@ event_q = &softs->event_q; obq_ci = event_q->ci_local; obq_pi = *(event_q->pi_virt_addr); - DBG_INFO("Initial Event_q ci : %d Event_q pi : %d\n", obq_ci, obq_pi); while(1) { int event_index; - DBG_INFO("queue_id : %d ci : %d pi : %d\n",obq_id, obq_ci, obq_pi); + DBG_INFO("Event queue_id : %d, ci : %u, pi : %u\n",obq_id, obq_ci, obq_pi); if (obq_pi == obq_ci) break; @@ -191,10 +195,13 @@ /* Copy the response */ memcpy(&response, event_q->array_virt_addr + (obq_ci * event_q->elem_size), sizeof(pqi_event_response_t)); - DBG_INFO("response.header.iu_type : 0x%x \n", response.header.iu_type); - DBG_INFO("response.event_type : 0x%x \n", response.event_type); + DBG_INIT("event iu_type=0x%x event_type=0x%x\n", + response.header.iu_type, response.event_type); event_index = pqisrc_event_type_to_event_index(response.event_type); + if ( event_index == PQI_EVENT_LOGICAL_DEVICE) { + softs->ld_rescan = true; + } if (event_index >= 0) { if(response.request_acknowledge) { @@ -224,6 +231,58 @@ } +/* + * Function used to build and send the vendor general request + * Used for configuring PQI feature bits between firmware and driver + */ +int +pqisrc_build_send_vendor_request(pqisrc_softstate_t *softs, + struct pqi_vendor_general_request *request) +{ + int ret = PQI_STATUS_SUCCESS; + ib_queue_t *op_ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; + ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; + + rcb_t *rcb = NULL; + + /* Get the tag */ + request->request_id = pqisrc_get_tag(&softs->taglist); + if (INVALID_ELEM == request->request_id) { + DBG_ERR("Tag not available\n"); + ret = PQI_STATUS_FAILURE; + goto err_notag; + } + + request->response_id = ob_q->q_id; + + rcb = &softs->rcb[request->request_id]; + + rcb->req_pending = true; + rcb->tag = request->request_id; + + ret = pqisrc_submit_cmnd(softs, op_ib_q, request); + + if (ret != PQI_STATUS_SUCCESS) { + DBG_ERR("Unable to submit command\n"); + goto err_out; + } + + ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_CMD_TIMEOUT); + if (ret != PQI_STATUS_SUCCESS) { + DBG_ERR("Management request timed out!\n"); + goto err_out; + } + + ret = rcb->status; + +err_out: + os_reset_rcb(rcb); + pqisrc_put_tag(&softs->taglist, request->request_id); +err_notag: + DBG_FUNC("OUT \n"); + return ret; +} + /* * Function used to send a general management request to adapter. */ @@ -248,6 +307,7 @@ rcb = &softs->rcb[request->request_id]; rcb->req_pending = true; rcb->tag = request->request_id; + /* Submit command on operational raid ib queue */ ret = pqisrc_submit_cmnd(softs, op_ib_q, request); if (ret != PQI_STATUS_SUCCESS) { @@ -256,6 +316,7 @@ } ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_CMD_TIMEOUT); + if (ret != PQI_STATUS_SUCCESS) { DBG_ERR("Management request timed out !!\n"); goto err_cmd; @@ -331,7 +392,7 @@ DBG_FUNC(" IN\n"); memset(&buf_report_event, 0, sizeof(struct dma_mem)); - buf_report_event.tag = "pqi_report_event_buf" ; + os_strlcpy(buf_report_event.tag, "pqi_report_event_buf", sizeof(buf_report_event.tag)); ; buf_report_event.size = alloc_size; buf_report_event.align = PQISRC_DEFAULT_DMA_ALIGN; @@ -392,7 +453,7 @@ DBG_FUNC(" IN\n"); memset(&buf_set_event, 0, sizeof(struct dma_mem)); - buf_set_event.tag = "pqi_set_event_buf"; + os_strlcpy(buf_set_event.tag, "pqi_set_event_buf", sizeof(buf_set_event.tag)); buf_set_event.size = alloc_size; buf_set_event.align = PQISRC_DEFAULT_DMA_ALIGN; diff --git a/sys/dev/smartpqi/smartpqi_features.c b/sys/dev/smartpqi/smartpqi_features.c new file mode 100644 --- /dev/null +++ b/sys/dev/smartpqi/smartpqi_features.c @@ -0,0 +1,520 @@ +/*- + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "smartpqi_includes.h" + +/* + * Checks a firmware feature status, given bit position. + */ +static inline boolean_t +pqi_is_firmware_feature_supported( + struct pqi_config_table_firmware_features *firmware_features, + unsigned int bit_position) +{ + unsigned int byte_index; + + byte_index = bit_position / BITS_PER_BYTE; + + if (byte_index >= firmware_features->num_elements) { + DBG_ERR_NO_SOFTS("Invalid byte index for bit position %u\n", + bit_position); + return false; + } + + return (firmware_features->features_supported[byte_index] & + (1 << (bit_position % BITS_PER_BYTE))) ? true : false; +} + +/* + * Counts down into the enabled section of firmware + * features and reports current enabled status, given + * bit position. + */ +static inline boolean_t +pqi_is_firmware_feature_enabled( + struct pqi_config_table_firmware_features *firmware_features, + uint8_t *firmware_features_iomem_addr, + unsigned int bit_position) +{ + unsigned int byte_index; + uint8_t *features_enabled_iomem_addr; + + byte_index = (bit_position / BITS_PER_BYTE) + + (firmware_features->num_elements * 2); + + features_enabled_iomem_addr = firmware_features_iomem_addr + + offsetof(struct pqi_config_table_firmware_features, + features_supported) + byte_index; + + return (*features_enabled_iomem_addr & + (1 << (bit_position % BITS_PER_BYTE))) ? true : false; +} + +/* + * Sets the given bit position for the driver to request the indicated + * firmware feature be enabled. + */ +static inline void +pqi_request_firmware_feature( + struct pqi_config_table_firmware_features *firmware_features, + unsigned int bit_position) +{ + unsigned int byte_index; + + /* byte_index adjusted to index into requested start bits */ + byte_index = (bit_position / BITS_PER_BYTE) + + firmware_features->num_elements; + + /* setting requested bits of local firmware_features */ + firmware_features->features_supported[byte_index] |= + (1 << (bit_position % BITS_PER_BYTE)); +} + +/* + * Creates and sends the request for firmware to update the config + * table. + */ +static int +pqi_config_table_update(pqisrc_softstate_t *softs, + uint16_t first_section, uint16_t last_section) +{ + struct pqi_vendor_general_request request; + int ret; + + memset(&request, 0, sizeof(request)); + + request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL; + request.header.iu_length = sizeof(request) - PQI_REQUEST_HEADER_LENGTH; + request.function_code = PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE; + request.data.config_table_update.first_section = first_section; + request.data.config_table_update.last_section = last_section; + + ret = pqisrc_build_send_vendor_request(softs, &request); + + if (ret != PQI_STATUS_SUCCESS) { + DBG_ERR("Failed to submit vendor general request IU, Ret status: %d\n", ret); + } + + return ret; +} + +/* + * Copies requested features bits into firmware config table, + * checks for support, and returns status of updating the config table. + */ +static int +pqi_enable_firmware_features(pqisrc_softstate_t *softs, + struct pqi_config_table_firmware_features *firmware_features, + uint8_t *firmware_features_abs_addr) +{ + uint8_t *features_requested; + uint8_t *features_requested_abs_addr; + uint16_t *host_max_known_feature_iomem_addr; + uint16_t pqi_max_feature = PQI_FIRMWARE_FEATURE_MAXIMUM; + + features_requested = firmware_features->features_supported + + firmware_features->num_elements; + + features_requested_abs_addr = firmware_features_abs_addr + + (features_requested - (uint8_t*)firmware_features); + /* + * NOTE: This memcpy is writing to a BAR-mapped address + * which may not be safe for all OSes without proper API + */ + memcpy(features_requested_abs_addr, features_requested, + firmware_features->num_elements); + + if (pqi_is_firmware_feature_supported(firmware_features, + PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE)) { + host_max_known_feature_iomem_addr = + (uint16_t*)(features_requested_abs_addr + + (firmware_features->num_elements * 2) + sizeof(uint16_t)); + /* + * NOTE: This writes to a BAR-mapped address + * which may not be safe for all OSes without proper API + */ + *host_max_known_feature_iomem_addr = pqi_max_feature; + } + + return pqi_config_table_update(softs, + PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES, + PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES); +} + +typedef struct pqi_firmware_feature pqi_firmware_feature_t; +typedef void (*feature_status_fn)(pqisrc_softstate_t *softs, + pqi_firmware_feature_t *firmware_feature); + +struct pqi_firmware_feature { + char *feature_name; + unsigned int feature_bit; + boolean_t supported; + boolean_t enabled; + feature_status_fn feature_status; +}; + +static void +pqi_firmware_feature_status(pqisrc_softstate_t *softs, + struct pqi_firmware_feature *firmware_feature) +{ + if (!firmware_feature->supported) { + DBG_NOTE("%s not supported by controller\n", + firmware_feature->feature_name); + return; + } + + if (firmware_feature->enabled) { + DBG_NOTE("%s enabled\n", firmware_feature->feature_name); + return; + } + + DBG_NOTE("failed to enable %s\n", firmware_feature->feature_name); +} + +static void +pqi_ctrl_update_feature_flags(pqisrc_softstate_t *softs, + struct pqi_firmware_feature *firmware_feature) +{ + switch (firmware_feature->feature_bit) { + case PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS: + softs->aio_raid1_write_bypass = firmware_feature->enabled; + break; + case PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS: + softs->aio_raid5_write_bypass = firmware_feature->enabled; + break; + case PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS: + softs->aio_raid6_write_bypass = firmware_feature->enabled; + break; + case PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT: + softs->timeout_in_passthrough = true; + break; + case PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT: + softs->timeout_in_tmf = true; + break; + case PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN: + break; + case PQI_FIRMWARE_FEATURE_PAGE83_IDENTIFIER_FOR_RPL_WWID: + softs->page83id_in_rpl = true; + break; + default: + DBG_NOTE("Nothing to do\n"); + return; + break; + } + /* for any valid feature, also go update the feature status. */ + pqi_firmware_feature_status(softs, firmware_feature); +} + + +static inline void +pqi_firmware_feature_update(pqisrc_softstate_t *softs, + struct pqi_firmware_feature *firmware_feature) +{ + if (firmware_feature->feature_status) + firmware_feature->feature_status(softs, firmware_feature); +} + +/* Defines PQI features that driver wishes to support */ +static struct pqi_firmware_feature pqi_firmware_features[] = { +#if 0 + { + .feature_name = "Online Firmware Activation", + .feature_bit = PQI_FIRMWARE_FEATURE_OFA, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "Serial Management Protocol", + .feature_bit = PQI_FIRMWARE_FEATURE_SMP, + .feature_status = pqi_firmware_feature_status, + }, +#endif + { + .feature_name = "SATA WWN Unique ID", + .feature_bit = PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "RAID IU Timeout", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "TMF IU Timeout", + .feature_bit = PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "Support for RPL WWID filled by Page83 identifier", + .feature_bit = PQI_FIRMWARE_FEATURE_PAGE83_IDENTIFIER_FOR_RPL_WWID, + .feature_status = pqi_ctrl_update_feature_flags, + }, + /* Features independent of Maximum Known Feature should be added + before Maximum Known Feature*/ + { + .feature_name = "Maximum Known Feature", + .feature_bit = PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 0 Read Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_0_READ_BYPASS, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 1 Read Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_1_READ_BYPASS, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 5 Read Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_5_READ_BYPASS, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 6 Read Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_6_READ_BYPASS, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 0 Write Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_0_WRITE_BYPASS, + .feature_status = pqi_firmware_feature_status, + }, + { + .feature_name = "RAID 1 Write Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "RAID 5 Write Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "RAID 6 Write Bypass", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS, + .feature_status = pqi_ctrl_update_feature_flags, + }, +#if 0 + { + .feature_name = "New Soft Reset Handshake", + .feature_bit = PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE, + .feature_status = pqi_ctrl_update_feature_flags, + }, +#endif + +}; + +static void +pqi_process_firmware_features(pqisrc_softstate_t *softs, + void *features, void *firmware_features_abs_addr) +{ + int rc; + struct pqi_config_table_firmware_features *firmware_features = features; + unsigned int i; + unsigned int num_features_supported; + + /* Iterates through local PQI feature support list to + see if the controller also supports the feature */ + for (i = 0, num_features_supported = 0; + i < ARRAY_SIZE(pqi_firmware_features); i++) { + /*Check if SATA_WWN_FOR_DEV_UNIQUE_ID feature enabled by setting module + parameter if not avoid checking for the feature*/ + if ((pqi_firmware_features[i].feature_bit == + PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN) && + (!softs->sata_unique_wwn)) { + continue; + } + if (pqi_is_firmware_feature_supported(firmware_features, + pqi_firmware_features[i].feature_bit)) { + pqi_firmware_features[i].supported = true; + num_features_supported++; + } else { + DBG_WARN("Feature %s is not supported by firmware\n", + pqi_firmware_features[i].feature_name); + pqi_firmware_feature_update(softs, + &pqi_firmware_features[i]); + + /* if max known feature bit isn't supported, + * then no other feature bits are supported. + */ + if (pqi_firmware_features[i].feature_bit == + PQI_FIRMWARE_FEATURE_MAX_KNOWN_FEATURE) + break; + } + } + + DBG_INFO("Num joint features supported : %u \n", num_features_supported); + + if (num_features_supported == 0) + return; + + /* request driver features that are also on firmware-supported list */ + for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { + if (!pqi_firmware_features[i].supported) + continue; +#ifdef DEVICE_HINT + if (check_device_hint_status(softs, pqi_firmware_features[i].feature_bit)) + continue; +#endif + pqi_request_firmware_feature(firmware_features, + pqi_firmware_features[i].feature_bit); + } + + /* enable the features that were successfully requested. */ + rc = pqi_enable_firmware_features(softs, firmware_features, + firmware_features_abs_addr); + if (rc) { + DBG_ERR("failed to enable firmware features in PQI configuration table\n"); + for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { + if (!pqi_firmware_features[i].supported) + continue; + pqi_firmware_feature_update(softs, + &pqi_firmware_features[i]); + } + return; + } + + /* report the features that were successfully enabled. */ + for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { + if (!pqi_firmware_features[i].supported) + continue; + if (pqi_is_firmware_feature_enabled(firmware_features, + firmware_features_abs_addr, + pqi_firmware_features[i].feature_bit)) { + pqi_firmware_features[i].enabled = true; + } else { + DBG_WARN("Feature %s could not be enabled.\n", + pqi_firmware_features[i].feature_name); + } + pqi_firmware_feature_update(softs, + &pqi_firmware_features[i]); + } +} + +static void +pqi_init_firmware_features(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { + pqi_firmware_features[i].supported = false; + pqi_firmware_features[i].enabled = false; + } +} + +static void +pqi_process_firmware_features_section(pqisrc_softstate_t *softs, + void *features, void *firmware_features_abs_addr) +{ + pqi_init_firmware_features(); + pqi_process_firmware_features(softs, features, firmware_features_abs_addr); +} + + +/* + * Get the PQI configuration table parameters. + * Currently using for heart-beat counter scratch-pad register. + */ +int +pqisrc_process_config_table(pqisrc_softstate_t *softs) +{ + int ret = PQI_STATUS_FAILURE; + uint32_t config_table_size; + uint32_t section_off; + uint8_t *config_table_abs_addr; + struct pqi_conf_table *conf_table; + struct pqi_conf_table_section_header *section_hdr; + + config_table_size = softs->pqi_cap.conf_tab_sz; + + if (config_table_size < sizeof(*conf_table) || + config_table_size > PQI_CONF_TABLE_MAX_LEN) { + DBG_ERR("Invalid PQI conf table length of %u\n", + config_table_size); + return ret; + } + + conf_table = os_mem_alloc(softs, config_table_size); + if (!conf_table) { + DBG_ERR("Failed to allocate memory for PQI conf table\n"); + return ret; + } + + config_table_abs_addr = (uint8_t *)(softs->pci_mem_base_vaddr + + softs->pqi_cap.conf_tab_off); + + PCI_MEM_GET_BUF(softs, config_table_abs_addr, + softs->pqi_cap.conf_tab_off, + (uint8_t*)conf_table, config_table_size); + + if (memcmp(conf_table->sign, PQI_CONF_TABLE_SIGNATURE, + sizeof(conf_table->sign)) != 0) { + DBG_ERR("Invalid PQI config signature\n"); + goto out; + } + + section_off = LE_32(conf_table->first_section_off); + + while (section_off) { + + if (section_off+ sizeof(*section_hdr) >= config_table_size) { + DBG_INFO("Reached end of PQI config table. Breaking off.\n"); + break; + } + + section_hdr = (struct pqi_conf_table_section_header *)((uint8_t *)conf_table + section_off); + + switch (LE_16(section_hdr->section_id)) { + case PQI_CONF_TABLE_SECTION_GENERAL_INFO: + break; + case PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES: + pqi_process_firmware_features_section(softs, section_hdr, (config_table_abs_addr + section_off)); + break; + case PQI_CONF_TABLE_SECTION_FIRMWARE_ERRATA: + case PQI_CONF_TABLE_SECTION_DEBUG: + break; + case PQI_CONF_TABLE_SECTION_HEARTBEAT: + softs->heartbeat_counter_off = softs->pqi_cap.conf_tab_off + + section_off + + offsetof(struct pqi_conf_table_heartbeat, heartbeat_counter); + softs->heartbeat_counter_abs_addr = (uint64_t *)(softs->pci_mem_base_vaddr + + softs->heartbeat_counter_off); + ret = PQI_STATUS_SUCCESS; + break; + case PQI_CONF_TABLE_SOFT_RESET: + break; + default: + DBG_NOTE("unrecognized PQI config table section ID: 0x%x\n", + LE_16(section_hdr->section_id)); + break; + } + section_off = LE_16(section_hdr->next_section_off); + } +out: + os_mem_free(softs, (void *)conf_table,config_table_size); + return ret; +} diff --git a/sys/dev/smartpqi/smartpqi_cmd.c b/sys/dev/smartpqi/smartpqi_helper.h copy from sys/dev/smartpqi/smartpqi_cmd.c copy to sys/dev/smartpqi/smartpqi_helper.h --- a/sys/dev/smartpqi/smartpqi_cmd.c +++ b/sys/dev/smartpqi/smartpqi_helper.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,51 +24,43 @@ */ -#include "smartpqi_includes.h" +#ifndef _PQI_HELPER_H +#define _PQI_HELPER_H -/* - * Function to submit the request to the adapter. - */ -int -pqisrc_submit_cmnd(pqisrc_softstate_t *softs, ib_queue_t *ib_q, void *req) +inline uint64_t +pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { - char *slot = NULL; - uint32_t offset; - iu_header_t *hdr = (iu_header_t *)req; - uint32_t iu_len = hdr->iu_length + 4 ; /* header size */ - int i = 0; - DBG_FUNC("IN\n"); - - PQI_LOCK(&ib_q->lock); - - /* Check queue full */ - if ((ib_q->pi_local + 1) % ib_q->num_elem == *(ib_q->ci_virt_addr)) { - DBG_WARN("OUT Q full\n"); - PQI_UNLOCK(&ib_q->lock); - return PQI_STATUS_QFULL; - } - - /* Get the slot */ - offset = ib_q->pi_local * ib_q->elem_size; - slot = ib_q->array_virt_addr + offset; +#if PQISRC_DEVICE_IO_COUNTER + /*Increment device active io count by one*/ + return OS_ATOMIC64_INC(&device->active_requests); +#endif +} - /* Copy the IU */ - memcpy(slot, req, iu_len); - DBG_INFO("IU : \n"); - for(i = 0; i< iu_len; i++) - DBG_INFO(" IU [ %d ] : %x\n", i, *((unsigned char *)(slot + i))); +inline uint64_t +pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) +{ +#if PQISRC_DEVICE_IO_COUNTER + /*Decrement device active io count by one*/ + return OS_ATOMIC64_DEC(&device->active_requests); +#endif +} - /* Update the local PI */ - ib_q->pi_local = (ib_q->pi_local + 1) % ib_q->num_elem; - DBG_INFO("ib_q->pi_local : %x IU size : %d\n", - ib_q->pi_local, hdr->iu_length); - DBG_INFO("*ib_q->ci_virt_addr: %x\n", - *(ib_q->ci_virt_addr)); +inline void +pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) +{ +#if PQISRC_DEVICE_IO_COUNTER + /* Reset device count to Zero */ + OS_ATOMIC64_INIT(&device->active_requests, 0); +#endif +} - /* Inform the fw about the new IU */ - PCI_MEM_PUT32(softs, ib_q->pi_register_abs, ib_q->pi_register_offset, ib_q->pi_local); - PQI_UNLOCK(&ib_q->lock); - DBG_FUNC("OUT\n"); - return PQI_STATUS_SUCCESS; +inline uint64_t +pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) +{ +#if PQISRC_DEVICE_IO_COUNTER + /* read device active count*/ + return OS_ATOMIC64_READ(&device->active_requests); +#endif } +#endif /* _PQI_HELPER_H */ diff --git a/sys/dev/smartpqi/smartpqi_helper.c b/sys/dev/smartpqi/smartpqi_helper.c --- a/sys/dev/smartpqi/smartpqi_helper.c +++ b/sys/dev/smartpqi/smartpqi_helper.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,57 +26,6 @@ #include "smartpqi_includes.h" -/* read and modify controller diagnostic option - PQI_PTRAID_UPDATE_ON_RESCAN_LUNS */ -void -pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *softs) -{ - int ret = PQI_STATUS_SUCCESS; - uint32_t diags_options = 0; - pqisrc_raid_req_t request; - - DBG_NOTE("IN\n"); - - memset(&request, 0, sizeof(request)); - /* read diags options of controller */ - ret = pqisrc_build_send_raid_request(softs, &request, - (void*)&diags_options, - sizeof(diags_options), - BMIC_SENSE_DIAGS_OPTIONS, - 0, (uint8_t *)RAID_CTLR_LUNID, NULL); - if (ret != PQI_STATUS_SUCCESS) { - DBG_WARN("Request failed for BMIC Sense Diags Option command." - "ret:%d\n",ret); - return; - } - DBG_NOTE("diags options data after read: %#x\n",diags_options); - diags_options |= PQI_PTRAID_UPDATE_ON_RESCAN_LUNS; - DBG_NOTE("diags options data to write: %#x\n",diags_options); - memset(&request, 0, sizeof(request)); - /* write specified diags options to controller */ - ret = pqisrc_build_send_raid_request(softs, &request, - (void*)&diags_options, - sizeof(diags_options), - BMIC_SET_DIAGS_OPTIONS, - 0, (uint8_t *)RAID_CTLR_LUNID, NULL); - if (ret != PQI_STATUS_SUCCESS) - DBG_WARN("Request failed for BMIC Set Diags Option command." - "ret:%d\n",ret); -#if 0 - diags_options = 0; - memset(&request, 0, sizeof(request)); - ret = pqisrc_build_send_raid_request(softs, &request, - (void*)&diags_options, - sizeof(diags_options), - BMIC_SENSE_DIAGS_OPTIONS, - 0, (uint8_t *)RAID_CTLR_LUNID, NULL); - if (ret != PQI_STATUS_SUCCESS) - DBG_WARN("Request failed for BMIC Sense Diags Option command." - "ret:%d\n",ret); - DBG_NOTE("diags options after re-read: %#x\n",diags_options); -#endif - DBG_NOTE("OUT\n"); -} - /* * Function used to validate the adapter health. */ @@ -89,7 +38,6 @@ return !softs->ctrl_online; } - /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx * mask clear pqi register */ @@ -97,20 +45,14 @@ pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx) { uint32_t intx_mask; - uint32_t *reg_addr __unused; - - DBG_FUNC("IN\n"); - if (enable_intx) - reg_addr = &softs->pqi_reg->legacy_intr_mask_clr; - else - reg_addr = &softs->pqi_reg->legacy_intr_mask_set; + DBG_FUNC("IN\n"); - intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR); + intx_mask = PCI_MEM_GET32(softs, 0, PQI_LEGACY_INTR_MASK_CLR); intx_mask |= PQISRC_LEGACY_INTX_MASK; - PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask); + PCI_MEM_PUT32(softs, 0, PQI_LEGACY_INTR_MASK_CLR ,intx_mask); - DBG_FUNC("OUT\n"); + DBG_FUNC("OUT\n"); } /* @@ -120,16 +62,14 @@ pqisrc_take_devices_offline(pqisrc_softstate_t *softs) { pqi_scsi_dev_t *device = NULL; - int i,j; + int i; DBG_FUNC("IN\n"); for(i = 0; i < PQI_MAX_DEVICES; i++) { - for(j = 0; j < PQI_MAX_MULTILUN; j++) { - if(softs->device_list[i][j] == NULL) - continue; - device = softs->device_list[i][j]; - pqisrc_remove_device(softs, device); - } + device = softs->dev_list[i]; + if(device == NULL) + continue; + pqisrc_remove_device(softs, device); } DBG_FUNC("OUT\n"); @@ -143,17 +83,17 @@ { DBG_FUNC("IN\n"); - softs->ctrl_online = false; - int lockupcode = 0; + softs->ctrl_online = false; + if (SIS_IS_KERNEL_PANIC(softs)) { - lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7); - DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode); - } - else { - pqisrc_trigger_nmi_sis(softs); - } + lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7); + DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode); + } + else { + pqisrc_trigger_nmi_sis(softs); + } os_complete_outstanding_cmds_nodevice(softs); pqisrc_wait_for_rescan_complete(softs); @@ -169,23 +109,34 @@ pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs) { uint8_t take_offline = false; + uint64_t new_heartbeat; + static uint32_t running_ping_cnt = 0; DBG_FUNC("IN\n"); - if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) { + new_heartbeat = CTRLR_HEARTBEAT_CNT(softs); + DBG_IO("heartbeat old=%lx new=%lx\n", softs->prev_heartbeat_count, new_heartbeat); + + if (new_heartbeat == softs->prev_heartbeat_count) { take_offline = true; goto take_ctrl_offline; } - softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs); - DBG_INFO("CTRLR_HEARTBEAT_CNT(softs) = %lx \ - softs->prev_heartbeat_count = %lx\n", - CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count); + +#if 1 + /* print every 30 calls (should print once/minute) */ + running_ping_cnt++; + + if ((running_ping_cnt % 30) == 0) + print_all_counters(softs, COUNTER_FLAG_ONLY_NON_ZERO); +#endif + + softs->prev_heartbeat_count = new_heartbeat; take_ctrl_offline: if (take_offline){ DBG_ERR("controller is offline\n"); - pqisrc_take_ctrl_offline(softs); os_stop_heartbeat_timer(softs); + pqisrc_take_ctrl_offline(softs); } DBG_FUNC("OUT\n"); } @@ -253,7 +204,7 @@ boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr) { - return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID); + return pqisrc_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID); } /* Function used to validate type of device */ @@ -287,8 +238,8 @@ "RAID 1(1+0)", "RAID 5", "RAID 5+1", - "RAID ADG", - "RAID 1(ADM)", + "RAID 6", + "RAID 1(Triple)", }; /* Get the RAID level from the index */ @@ -417,6 +368,7 @@ } +#if 0 uint32_t pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { @@ -436,7 +388,7 @@ check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { uint32_t tag = softs->max_outstanding_io, active_requests; - uint64_t timeout = 0, delay_in_usec = 1000; //In micro Seconds + uint64_t timeout = 0, delay_in_usec = 1000; /* In micro Seconds */ rcb_t* rcb; DBG_FUNC("IN\n"); @@ -451,7 +403,7 @@ do { rcb = &softs->rcb[tag]; if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) { - OS_BUSYWAIT(delay_in_usec); + OS_SLEEP(delay_in_usec); timeout += delay_in_usec; } else @@ -461,49 +413,25 @@ return; } } while(tag); - } - -inline uint64_t -pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) -{ -#if PQISRC_DEVICE_IO_COUNTER - /*Increment device active io count by one*/ - return OS_ATOMIC64_INC(&device->active_requests); #endif -} -inline uint64_t -pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) -{ -#if PQISRC_DEVICE_IO_COUNTER - /*Decrement device active io count by one*/ - return OS_ATOMIC64_DEC(&device->active_requests); -#endif -} +extern inline uint64_t +pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); -inline void -pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) -{ -#if PQISRC_DEVICE_IO_COUNTER - /* Reset device count to Zero */ - OS_ATOMIC64_INIT(&device->active_requests, 0); -#endif -} +extern inline uint64_t +pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); -inline uint64_t -pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) -{ -#if PQISRC_DEVICE_IO_COUNTER - /* read device active count*/ - return OS_ATOMIC64_READ(&device->active_requests); -#endif -} +extern inline void +pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); + +extern inline uint64_t +pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); void pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { - uint64_t timeout_in_usec = 0, delay_in_usec = 1000; //In microseconds + uint64_t timeout_in_usec = 0, delay_in_usec = 1000; /* In microseconds */ DBG_FUNC("IN\n"); @@ -511,16 +439,16 @@ return; #if PQISRC_DEVICE_IO_COUNTER - DBG_NOTE("Device Outstanding IO count = %ld\n", pqisrc_read_device_active_io(softs, device)); + DBG_WARN_BTL(device,"Device Outstanding IO count = %lu\n", pqisrc_read_device_active_io(softs, device)); while(pqisrc_read_device_active_io(softs, device)) { - OS_BUSYWAIT(delay_in_usec); // In microseconds + OS_BUSYWAIT(delay_in_usec); /* In microseconds */ if(!softs->ctrl_online) { DBG_WARN("Controller Offline was detected.\n"); } timeout_in_usec += delay_in_usec; if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) { - DBG_WARN("timed out waiting for pending IO. DeviceOutStandingIo's=%ld\n", + DBG_WARN_BTL(device,"timed out waiting for pending IO. DeviceOutStandingIo's=%lu\n", pqisrc_read_device_active_io(softs, device)); return; } diff --git a/sys/dev/smartpqi/smartpqi_includes.h b/sys/dev/smartpqi/smartpqi_includes.h --- a/sys/dev/smartpqi/smartpqi_includes.h +++ b/sys/dev/smartpqi/smartpqi_includes.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,11 +77,10 @@ #include - #include "smartpqi_defines.h" #include "smartpqi_structures.h" #include "smartpqi_prototypes.h" #include "smartpqi_ioctl.h" +#include "smartpqi_helper.h" - -#endif // _PQI_INCLUDES_H +#endif /* _PQI_INCLUDES_H*/ diff --git a/sys/dev/smartpqi/smartpqi_init.c b/sys/dev/smartpqi/smartpqi_init.c --- a/sys/dev/smartpqi/smartpqi_init.c +++ b/sys/dev/smartpqi/smartpqi_init.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,9 +26,6 @@ #include "smartpqi_includes.h" -/* 5 mins timeout for quiesce */ -#define PQI_QUIESCE_TIMEOUT 300000 - /* * Request the adapter to get PQI capabilities supported. */ @@ -36,7 +33,7 @@ pqisrc_report_pqi_capability(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; - + DBG_FUNC("IN\n"); gen_adm_req_iu_t admin_req; @@ -49,7 +46,6 @@ capability = os_mem_alloc(softs, sizeof(*capability)); if (!capability) { DBG_ERR("Failed to allocate memory for capability\n"); - ret = PQI_STATUS_FAILURE; goto err_out; } @@ -57,7 +53,7 @@ memset(&admin_resp, 0, sizeof(admin_resp)); memset(&pqi_cap_dma_buf, 0, sizeof(struct dma_mem)); - pqi_cap_dma_buf.tag = "pqi_cap_buf"; + os_strlcpy(pqi_cap_dma_buf.tag, "pqi_cap_buf", sizeof(pqi_cap_dma_buf.tag)); pqi_cap_dma_buf.size = REPORT_PQI_DEV_CAP_DATA_BUF_SIZE; pqi_cap_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN; @@ -110,6 +106,12 @@ DBG_INIT("softs->ib_spanning_supported: %d\n", softs->ib_spanning_supported); DBG_INIT("softs->ob_spanning_supported: %d\n", softs->ob_spanning_supported); + /* Not expecting these to change, could cause problems if they do */ + ASSERT(softs->pqi_dev_cap.max_iq_elem_len == PQISRC_OP_MAX_ELEM_SIZE); + ASSERT(softs->pqi_dev_cap.min_iq_elem_len == PQISRC_OP_MIN_ELEM_SIZE); + ASSERT(softs->max_ib_iu_length_per_fw == PQISRC_MAX_SPANNING_IU_LENGTH); + ASSERT(softs->ib_spanning_supported == true); + os_mem_free(softs, (void *)capability, REPORT_PQI_DEV_CAP_DATA_BUF_SIZE); @@ -135,6 +137,7 @@ void pqisrc_free_rcb(pqisrc_softstate_t *softs, int req_count) { + uint32_t num_req; size_t size; int i; @@ -152,6 +155,7 @@ /* * Allocate memory for rcb and SG descriptors. + * TODO : Sg list should be created separately */ static int pqisrc_allocate_rcb(pqisrc_softstate_t *softs) @@ -168,11 +172,11 @@ /* Set maximum outstanding requests */ /* The valid tag values are from 1, 2, ..., softs->max_outstanding_io * The rcb will be accessed by using the tag as index - * As 0 tag index is not used, we need to allocate one extra. + * As 0 tag index is not used, we need to allocate one extra. */ softs->max_outstanding_io = softs->pqi_cap.max_outstanding_io; num_req = softs->max_outstanding_io + 1; - DBG_INIT("Max Outstanding IO reset to %d\n", num_req); + DBG_INIT("Max Outstanding IO reset to %u\n", num_req); alloc_size = num_req * sizeof(rcb_t); @@ -192,9 +196,10 @@ prcb = &softs->rcb[1]; /* Initialize rcb */ for(i=1; i < num_req; i++) { + /* TODO:Here tag is local variable */ char tag[15]; sprintf(tag, "sg_dma_buf%d", i); - softs->sg_dma_desc[i].tag = tag; + os_strlcpy(softs->sg_dma_desc[i].tag, tag, sizeof(softs->sg_dma_desc[i].tag)); softs->sg_dma_desc[i].size = sg_buf_size; softs->sg_dma_desc[i].align = PQISRC_DEFAULT_DMA_ALIGN; @@ -231,7 +236,9 @@ DBG_INIT("softs->intr_count : %d softs->num_cpus_online : %d", softs->intr_count, softs->num_cpus_online); - + + /* TODO : Get the number of IB and OB queues from OS layer */ + if (softs->intr_count == 1 || softs->num_cpus_online == 1) { /* Share the event and Operational queue. */ softs->num_op_obq = 1; @@ -244,32 +251,33 @@ softs->share_opq_and_eventq = false; } /* If the available interrupt count is more than one, - we dont need to share the interrupt for IO and event queue */ + we don’t need to share the interrupt for IO and event queue */ if (softs->intr_count > 1) softs->share_opq_and_eventq = false; - DBG_INIT("softs->num_op_obq : %d\n",softs->num_op_obq); + DBG_INIT("softs->num_op_obq : %u\n",softs->num_op_obq); + + /* TODO : Reset the interrupt count based on number of queues*/ softs->num_op_raid_ibq = softs->num_op_obq; softs->num_op_aio_ibq = softs->num_op_raid_ibq; - softs->ibq_elem_size = softs->pqi_dev_cap.max_iq_elem_len * 16; - softs->obq_elem_size = softs->pqi_dev_cap.max_oq_elem_len * 16; + softs->max_ibq_elem_size = softs->pqi_dev_cap.max_iq_elem_len * 16; + softs->max_obq_elem_size = softs->pqi_dev_cap.max_oq_elem_len * 16; if (softs->max_ib_iu_length_per_fw == 256 && softs->ob_spanning_supported) { /* older f/w that doesn't actually support spanning. */ - softs->max_ib_iu_length = softs->ibq_elem_size; + softs->max_ib_iu_length = softs->max_ibq_elem_size; } else { /* max. inbound IU length is an multiple of our inbound element size. */ - softs->max_ib_iu_length = - (softs->max_ib_iu_length_per_fw / softs->ibq_elem_size) * - softs->ibq_elem_size; - + softs->max_ib_iu_length = PQISRC_ROUND_DOWN(softs->max_ib_iu_length_per_fw, + softs->max_ibq_elem_size); } + /* If Max. Outstanding IO came with Max. Spanning element count then, needed elements per IO are multiplication of Max.Outstanding IO and Max.Spanning element */ total_iq_elements = (softs->max_outstanding_io * - (softs->max_ib_iu_length / softs->ibq_elem_size)); + (softs->max_ib_iu_length / softs->max_ibq_elem_size)); softs->num_elem_per_op_ibq = total_iq_elements / softs->num_op_raid_ibq; softs->num_elem_per_op_ibq = MIN(softs->num_elem_per_op_ibq, @@ -279,15 +287,23 @@ softs->num_elem_per_op_obq = MIN(softs->num_elem_per_op_obq, softs->pqi_dev_cap.max_oq_elements); - softs->max_sg_per_iu = ((softs->max_ib_iu_length - - softs->ibq_elem_size) / - sizeof(sgt_t)) + - MAX_EMBEDDED_SG_IN_FIRST_IU; + /* spanning elements should be 9 (1152/128) */ + softs->max_spanning_elems = softs->max_ib_iu_length/softs->max_ibq_elem_size; + ASSERT(softs->max_spanning_elems == PQISRC_MAX_SPANNING_ELEMS); + + /* max SGs should be 8 (128/16) */ + softs->max_sg_per_single_iu_element = softs->max_ibq_elem_size / sizeof(sgt_t); + ASSERT(softs->max_sg_per_single_iu_element == MAX_EMBEDDED_SG_IN_IU); - DBG_INIT("softs->max_ib_iu_length: %d\n", softs->max_ib_iu_length); - DBG_INIT("softs->num_elem_per_op_ibq: %d\n", softs->num_elem_per_op_ibq); - DBG_INIT("softs->num_elem_per_op_obq: %d\n", softs->num_elem_per_op_obq); - DBG_INIT("softs->max_sg_per_iu: %d\n", softs->max_sg_per_iu); + /* max SGs for spanning cmd should be 68*/ + softs->max_sg_per_spanning_cmd = (softs->max_spanning_elems - 1) * softs->max_sg_per_single_iu_element; + softs->max_sg_per_spanning_cmd += MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT; + + DBG_INIT("softs->max_ib_iu_length: %d\n", softs->max_ib_iu_length); /* 1152 per FW advertisement */ + DBG_INIT("softs->num_elem_per_op_ibq: %u\n", softs->num_elem_per_op_ibq); /* 32 for xcal */ + DBG_INIT("softs->num_elem_per_op_obq: %u\n", softs->num_elem_per_op_obq); /* 256 for xcal */ + DBG_INIT("softs->max_spanning_elems: %d\n", softs->max_spanning_elems); /* 9 */ + DBG_INIT("softs->max_sg_per_spanning_cmd: %u\n", softs->max_sg_per_spanning_cmd); /* 68 until we add AIO writes */ DBG_FUNC("OUT\n"); } @@ -384,293 +400,6 @@ return ret; } -/* PQI Feature processing */ -static int -pqisrc_config_table_update(struct pqisrc_softstate *softs, - uint16_t first_section, uint16_t last_section) -{ - pqi_vendor_general_request_t request; - int ret = PQI_STATUS_FAILURE; - - memset(&request, 0, sizeof(request)); - - request.header.iu_type = PQI_REQUEST_IU_VENDOR_GENERAL; - request.header.iu_length = sizeof(request) - PQI_REQUEST_HEADER_LENGTH; - request.function_code = PQI_VENDOR_GENERAL_CONFIG_TABLE_UPDATE; - request.data.config_table_update.first_section = first_section; - request.data.config_table_update.last_section = last_section; - - ret = pqisrc_build_send_vendor_request(softs, &request, NULL); - - if (ret != PQI_STATUS_SUCCESS) { - DBG_ERR("Failed to submit vendor general request IU, Ret status: %d\n", ret); - return PQI_STATUS_FAILURE; - } - - return PQI_STATUS_SUCCESS; -} - -static inline -boolean_t pqi_is_firmware_feature_supported( - struct pqi_conf_table_firmware_features *firmware_feature_list, - unsigned int bit_position) -{ - unsigned int byte_index; - - byte_index = bit_position / BITS_PER_BYTE; - - if (byte_index >= firmware_feature_list->num_elements) - return false; - - return firmware_feature_list->features_supported[byte_index] & - (1 << (bit_position % BITS_PER_BYTE)) ? true : false; -} - -static inline -boolean_t pqi_is_firmware_feature_enabled( - struct pqi_conf_table_firmware_features *firmware_feature_list, - uint8_t *firmware_features_addr, unsigned int bit_position) -{ - unsigned int byte_index; - uint8_t *feature_enabled_addr; - - byte_index = (bit_position / BITS_PER_BYTE) + - (firmware_feature_list->num_elements * 2); - - feature_enabled_addr = firmware_features_addr + - offsetof(struct pqi_conf_table_firmware_features, - features_supported) + byte_index; - - return *feature_enabled_addr & - (1 << (bit_position % BITS_PER_BYTE)) ? true : false; -} - -static inline void -pqi_request_firmware_feature( - struct pqi_conf_table_firmware_features *firmware_feature_list, - unsigned int bit_position) -{ - unsigned int byte_index; - - byte_index = (bit_position / BITS_PER_BYTE) + - firmware_feature_list->num_elements; - - firmware_feature_list->features_supported[byte_index] |= - (1 << (bit_position % BITS_PER_BYTE)); -} - -/* Update PQI config table firmware features section and inform the firmware */ -static int -pqisrc_set_host_requested_firmware_feature(pqisrc_softstate_t *softs, - struct pqi_conf_table_firmware_features *firmware_feature_list) -{ - uint8_t *request_feature_addr; - void *request_feature_abs_addr; - - request_feature_addr = firmware_feature_list->features_supported + - firmware_feature_list->num_elements; - request_feature_abs_addr = softs->fw_features_section_abs_addr + - (request_feature_addr - (uint8_t*)firmware_feature_list); - - os_io_memcpy(request_feature_abs_addr, request_feature_addr, - firmware_feature_list->num_elements); - - return pqisrc_config_table_update(softs, - PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES, - PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES); -} - -/* Check firmware has enabled the feature specified in the respective bit position. */ -inline boolean_t -pqisrc_is_firmware_feature_enabled(pqisrc_softstate_t *softs, - struct pqi_conf_table_firmware_features *firmware_feature_list, uint16_t bit_position) -{ - uint16_t byte_index; - uint8_t *features_enabled_abs_addr; - - byte_index = (bit_position / BITS_PER_BYTE) + - (firmware_feature_list->num_elements * 2); - - features_enabled_abs_addr = softs->fw_features_section_abs_addr + - offsetof(struct pqi_conf_table_firmware_features,features_supported) + byte_index; - - return *features_enabled_abs_addr & - (1 << (bit_position % BITS_PER_BYTE)) ? true : false; -} - -static void -pqi_firmware_feature_status(struct pqisrc_softstate *softs, - struct pqi_firmware_feature *firmware_feature) -{ - switch(firmware_feature->feature_bit) { - case PQI_FIRMWARE_FEATURE_OFA: - break; - case PQI_FIRMWARE_FEATURE_TIMEOUT_IN_RAID_IU_SUPPORT: - softs->timeout_in_passthrough = true; - break; - case PQI_FIRMWARE_FEATURE_TIMEOUT_IN_TMF_IU_SUPPORT: - softs->timeout_in_tmf = true; - break; - default: - DBG_NOTE("Nothing to do \n"); - } -} - -/* Firmware features supported by the driver */ -static struct -pqi_firmware_feature pqi_firmware_features[] = { - { - .feature_name = "Support timeout for pass-through commands", - .feature_bit = PQI_FIRMWARE_FEATURE_TIMEOUT_IN_RAID_IU_SUPPORT, - .feature_status = pqi_firmware_feature_status, - }, - { - .feature_name = "Support timeout for LUN Reset TMF", - .feature_bit = PQI_FIRMWARE_FEATURE_TIMEOUT_IN_TMF_IU_SUPPORT, - .feature_status = pqi_firmware_feature_status, - } -}; - -static void -pqisrc_process_firmware_features(pqisrc_softstate_t *softs) -{ - int rc; - struct pqi_conf_table_firmware_features *firmware_feature_list; - unsigned int i; - unsigned int num_features_requested; - - firmware_feature_list = (struct pqi_conf_table_firmware_features*) - softs->fw_features_section_abs_addr; - - /* Check features and request those supported by firmware and driver.*/ - for (i = 0, num_features_requested = 0; - i < ARRAY_SIZE(pqi_firmware_features); i++) { - /* Firmware support it ? */ - if (pqi_is_firmware_feature_supported(firmware_feature_list, - pqi_firmware_features[i].feature_bit)) { - pqi_request_firmware_feature(firmware_feature_list, - pqi_firmware_features[i].feature_bit); - pqi_firmware_features[i].supported = true; - num_features_requested++; - DBG_NOTE("%s supported by driver, requesting firmware to enable it\n", - pqi_firmware_features[i].feature_name); - } else { - DBG_NOTE("%s supported by driver, but not by current firmware\n", - pqi_firmware_features[i].feature_name); - } - } - if (num_features_requested == 0) - return; - - rc = pqisrc_set_host_requested_firmware_feature(softs, firmware_feature_list); - if (rc) { - DBG_ERR("Failed to update pqi config table\n"); - return; - } - - for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { - if (pqi_is_firmware_feature_enabled(firmware_feature_list, - softs->fw_features_section_abs_addr, pqi_firmware_features[i].feature_bit)) { - pqi_firmware_features[i].enabled = true; - DBG_NOTE("Firmware feature %s enabled \n",pqi_firmware_features[i].feature_name); - if(pqi_firmware_features[i].feature_status) - pqi_firmware_features[i].feature_status(softs, &(pqi_firmware_features[i])); - } - } -} - -/* - * Get the PQI configuration table parameters. - * Currently using for heart-beat counter scratch-pad register. - */ -int -pqisrc_process_config_table(pqisrc_softstate_t *softs) -{ - int ret = PQI_STATUS_FAILURE; - uint32_t config_table_size; - uint32_t section_off; - uint8_t *config_table_abs_addr __unused; - struct pqi_conf_table *conf_table; - struct pqi_conf_table_section_header *section_hdr; - - config_table_size = softs->pqi_cap.conf_tab_sz; - - if (config_table_size < sizeof(*conf_table) || - config_table_size > PQI_CONF_TABLE_MAX_LEN) { - DBG_ERR("Invalid PQI conf table length of %u\n", - config_table_size); - return ret; - } - - conf_table = os_mem_alloc(softs, config_table_size); - if (!conf_table) { - DBG_ERR("Failed to allocate memory for PQI conf table\n"); - return ret; - } - - if (config_table_size < sizeof(conf_table) || - config_table_size > PQI_CONF_TABLE_MAX_LEN) { - DBG_ERR("Invalid PQI conf table length of %u\n", - config_table_size); - goto out; - } - - config_table_abs_addr = (uint8_t *)(softs->pci_mem_base_vaddr + - softs->pqi_cap.conf_tab_off); - - PCI_MEM_GET_BUF(softs, config_table_abs_addr, - softs->pqi_cap.conf_tab_off, - (uint8_t*)conf_table, config_table_size); - - - if (memcmp(conf_table->sign, PQI_CONF_TABLE_SIGNATURE, - sizeof(conf_table->sign)) != 0) { - DBG_ERR("Invalid PQI config signature\n"); - goto out; - } - - section_off = LE_32(conf_table->first_section_off); - - while (section_off) { - - if (section_off+ sizeof(*section_hdr) >= config_table_size) { - DBG_INFO("Reached end of PQI config table. Breaking off.\n"); - break; - } - - section_hdr = (struct pqi_conf_table_section_header *)((uint8_t *)conf_table + section_off); - - switch (LE_16(section_hdr->section_id)) { - case PQI_CONF_TABLE_SECTION_GENERAL_INFO: - case PQI_CONF_TABLE_SECTION_FIRMWARE_ERRATA: - case PQI_CONF_TABLE_SECTION_DEBUG: - break; - case PQI_CONF_TABLE_SECTION_FIRMWARE_FEATURES: - softs->fw_features_section_off = softs->pqi_cap.conf_tab_off + section_off; - softs->fw_features_section_abs_addr = softs->pci_mem_base_vaddr + softs->fw_features_section_off; - pqisrc_process_firmware_features(softs); - break; - case PQI_CONF_TABLE_SECTION_HEARTBEAT: - softs->heartbeat_counter_off = softs->pqi_cap.conf_tab_off + - section_off + - offsetof(struct pqi_conf_table_heartbeat, - heartbeat_counter); - softs->heartbeat_counter_abs_addr = (uint64_t *)(softs->pci_mem_base_vaddr + - softs->heartbeat_counter_off); - ret = PQI_STATUS_SUCCESS; - break; - default: - DBG_INFO("unrecognized PQI config table section ID: 0x%x\n", - LE_16(section_hdr->section_id)); - break; - } - section_off = LE_16(section_hdr->next_section_off); - } -out: - os_mem_free(softs, (void *)conf_table,config_table_size); - return ret; -} - /* Wait for PQI reset completion for the adapter*/ int pqisrc_wait_for_pqi_reset_completion(pqisrc_softstate_t *softs) @@ -721,6 +450,7 @@ val |= SIS_PQI_RESET_QUIESCE; PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, LEGACY_SIS_IDBR, LE_32(val)); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ ret = pqisrc_sis_wait_for_db_bit_to_clear(softs, SIS_PQI_RESET_QUIESCE); if (ret) { DBG_ERR("failed with error %d during quiesce\n", ret); @@ -734,6 +464,7 @@ PCI_MEM_PUT32(softs, &softs->pqi_reg->dev_reset, PQI_DEV_RESET, LE_32(pqi_reset_reg.all_bits)); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ ret = pqisrc_wait_for_pqi_reset_completion(softs); if (ret) { @@ -827,10 +558,9 @@ /* Create Operational queues */ ret = pqisrc_create_op_queues(softs); if(ret) { - DBG_ERR("Failed to create op queue\n"); - ret = PQI_STATUS_FAILURE; - goto err_create_opq; - } + DBG_ERR("Failed to create op queue\n"); + goto err_create_opq; + } softs->ctrl_online = true; @@ -851,13 +581,14 @@ return PQI_STATUS_FAILURE; } +/* */ int pqisrc_force_sis(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; if (SIS_IS_KERNEL_PANIC(softs)) { - DBG_INIT("Controller FW is not running"); + DBG_ERR("Controller FW is not running\n"); return PQI_STATUS_FAILURE; } @@ -888,18 +619,22 @@ return ret; } -static int +/* 5 mins timeout for quiesce */ +#define PQI_QUIESCE_TIMEOUT 300000 + +int pqisrc_wait_for_cmnd_complete(pqisrc_softstate_t *softs) { + int count = 0; int ret = PQI_STATUS_SUCCESS; - DBG_NOTE("softs->taglist.num_elem : %d",softs->taglist.num_elem); + DBG_NOTE("softs->taglist.num_elem : %u",softs->taglist.num_elem); if (softs->taglist.num_elem == softs->max_outstanding_io) return ret; else { - DBG_WARN("%d commands pending\n", + DBG_WARN("%u commands pending\n", softs->max_outstanding_io - softs->taglist.num_elem); while(1) { @@ -928,7 +663,7 @@ return ret; } -static void +void pqisrc_complete_internal_cmds(pqisrc_softstate_t *softs) { @@ -938,7 +673,7 @@ for (tag = 1; tag <= softs->max_outstanding_io; tag++) { rcb = &softs->rcb[tag]; if(rcb->req_pending && is_internal_req(rcb)) { - rcb->status = REQUEST_FAILED; + rcb->status = PQI_STATUS_TIMEOUT; rcb->req_pending = false; } } @@ -951,7 +686,7 @@ void pqisrc_pqi_uninit(pqisrc_softstate_t *softs) { - int i, ret; + int ret; DBG_FUNC("IN\n"); @@ -975,25 +710,10 @@ softs->devlist_lockcreated = false; } - for (i = 0; i < softs->num_op_raid_ibq; i++) { - /* OP RAID IB Q */ - if(softs->op_raid_ib_q[i].lockcreated==true){ - OS_UNINIT_PQILOCK(&softs->op_raid_ib_q[i].lock); - softs->op_raid_ib_q[i].lockcreated = false; - } - /* OP AIO IB Q */ - if(softs->op_aio_ib_q[i].lockcreated==true){ - OS_UNINIT_PQILOCK(&softs->op_aio_ib_q[i].lock); - softs->op_aio_ib_q[i].lockcreated = false; - } - } - - /* Free Op queues */ - os_dma_mem_free(softs, &softs->op_ibq_dma_mem); - os_dma_mem_free(softs, &softs->op_obq_dma_mem); - os_dma_mem_free(softs, &softs->event_q_dma_mem); - - + /* Free all queues */ + pqisrc_destroy_op_ib_queues(softs); + pqisrc_destroy_op_ob_queues(softs); + pqisrc_destroy_event_queue(softs); /* Free rcb */ pqisrc_free_rcb(softs, softs->max_outstanding_io + 1); @@ -1001,13 +721,8 @@ /* Free request id lists */ pqisrc_destroy_taglist(softs,&softs->taglist); - if(softs->admin_ib_queue.lockcreated==true) { - OS_UNINIT_PQILOCK(&softs->admin_ib_queue.lock); - softs->admin_ib_queue.lockcreated = false; - } - /* Free Admin Queue */ - os_dma_mem_free(softs, &softs->admin_queue_dma_mem); + pqisrc_destroy_admin_queue(softs); /* Switch back to SIS mode */ if (pqisrc_force_sis(softs)) { @@ -1017,6 +732,30 @@ DBG_FUNC("OUT\n"); } + +/* + * Function to do any sanity checks for OS macros + */ +void +sanity_check_os_behavior(pqisrc_softstate_t *softs) +{ +#ifdef OS_ATOMIC64_INC + OS_ATOMIC64_T atomic_test_var = 0; + OS_ATOMIC64_T atomic_ret = 0; + + atomic_ret = OS_ATOMIC64_INC(&atomic_test_var); + ASSERT(atomic_ret == 1); + + atomic_ret = OS_ATOMIC64_INC(&atomic_test_var); + ASSERT(atomic_ret == 2); + + atomic_ret = OS_ATOMIC64_DEC(&atomic_test_var); + ASSERT(atomic_ret == 1); +#else + DBG_INIT("OS needs to define/implement atomic macros\n"); +#endif +} + /* * Function to initialize the adapter settings. */ @@ -1024,25 +763,54 @@ pqisrc_init(pqisrc_softstate_t *softs) { int ret = 0; - int i = 0, j = 0; + uint32_t ctrl_type; DBG_FUNC("IN\n"); + sanity_check_os_behavior(softs); + check_struct_sizes(); - /* Init the Sync interface */ - ret = pqisrc_sis_init(softs); - if (ret) { - DBG_ERR("SIS Init failed with error %d\n", ret); + /*Get verbose flags, defined in OS code XX_debug.h or so*/ +#ifdef DISABLE_ERR_RESP_VERBOSE + softs->err_resp_verbose = false; +#else + softs->err_resp_verbose = true; +#endif + + /* prevent attachment of revA hardware. */ + ctrl_type = PQI_GET_CTRL_TYPE(softs); + if (ctrl_type == PQI_CTRL_PRODUCT_ID_GEN2_REV_A) { + DBG_ERR("adapter at B.D.F=%u.%u.%u: unsupported RevA card.\n", + softs->bus_id, softs->device_id, softs->func_id); + ret = PQI_STATUS_FAILURE; goto err_out; } + /* Increment the global adapter ID and tie it to this BDF */ +#ifdef OS_ATOMIC64_INC + static OS_ATOMIC64_T g_adapter_cnt = 0; + softs->adapter_num = (uint8_t)OS_ATOMIC64_INC(&g_adapter_cnt); +#else + static uint64_t g_adapter_cnt = 0; + softs->adapter_num = (uint8_t)++g_adapter_cnt; +#endif + DBG_NOTE("Initializing adapter %u\n", (uint32_t)softs->adapter_num); + ret = os_create_semaphore("scan_lock", 1, &softs->scan_lock); if(ret != PQI_STATUS_SUCCESS){ DBG_ERR(" Failed to initialize scan lock\n"); - goto err_scan_lock; + goto err_out; } + /* Init the Sync interface */ + ret = pqisrc_sis_init(softs); + if (ret) { + DBG_ERR("SIS Init failed with error %d\n", ret); + goto err_sis; + } + + /* Init the PQI interface */ ret = pqisrc_pqi_init(softs); if (ret) { @@ -1058,25 +826,25 @@ } /* Report event configuration */ - ret = pqisrc_report_event_config(softs); - if(ret){ - DBG_ERR(" Failed to configure Report events\n"); + ret = pqisrc_report_event_config(softs); + if(ret){ + DBG_ERR(" Failed to configure Report events\n"); goto err_event; } /* Set event configuration*/ - ret = pqisrc_set_event_config(softs); - if(ret){ - DBG_ERR(" Failed to configure Set events\n"); - goto err_event; - } + ret = pqisrc_set_event_config(softs); + if(ret){ + DBG_ERR(" Failed to configure Set events\n"); + goto err_event; + } /* Check for For PQI spanning */ ret = pqisrc_get_ctrl_fw_version(softs); - if(ret){ - DBG_ERR(" Failed to get ctrl fw version\n"); - goto err_fw_version; - } + if(ret){ + DBG_ERR(" Failed to get ctrl fw version\n"); + goto err_fw_version; + } /* update driver version in to FW */ ret = pqisrc_write_driver_version_to_host_wellness(softs); @@ -1085,6 +853,12 @@ goto err_host_wellness; } + /* Setup sense features */ + ret = pqisrc_QuerySenseFeatures(softs); + if (ret) { + DBG_ERR("Failed to get sense features\n"); + goto err_sense; + } os_strlcpy(softs->devlist_lock_name, "devlist_lock", LOCKNAME_SIZE); ret = os_init_spinlock(softs, &softs->devlist_lock, softs->devlist_lock_name); @@ -1104,12 +878,8 @@ softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs) - OS_FW_HEARTBEAT_TIMER_INTERVAL; - /* Init device list */ - for(i = 0; i < PQI_MAX_DEVICES; i++) - for(j = 0; j < PQI_MAX_MULTILUN; j++) - softs->device_list[i][j] = NULL; - - pqisrc_init_targetid_pool(softs); + memset(softs->dev_list, 0, sizeof(*softs->dev_list)); + pqisrc_init_bitmap(softs); DBG_FUNC("OUT\n"); return ret; @@ -1124,11 +894,12 @@ err_event: err_host_wellness: err_intr: +err_sense: pqisrc_pqi_uninit(softs); err_pqi: - os_destroy_semaphore(&softs->scan_lock); -err_scan_lock: pqisrc_sis_uninit(softs); +err_sis: + os_destroy_semaphore(&softs->scan_lock); err_out: DBG_FUNC("OUT failed\n"); return ret; @@ -1162,16 +933,18 @@ memset(&request, 0, sizeof(request)); - rval = pqisrc_build_send_raid_request(softs, &request, flush_buff, - sizeof(*flush_buff), SA_CACHE_FLUSH, 0, - (uint8_t *)RAID_CTLR_LUNID, NULL); + request.data_direction = SOP_DATA_DIR_FROM_DEVICE; + request.cmd.bmic_cdb.op_code = BMIC_WRITE; + request.cmd.bmic_cdb.cmd = BMIC_CACHE_FLUSH; + request.cmd.bmic_cdb.xfer_len = BE_16(sizeof(*flush_buff)); + + rval = pqisrc_prepare_send_ctrlr_request(softs, &request, flush_buff, sizeof(*flush_buff)); + if (rval) { DBG_ERR("error in build send raid req ret=%d\n", rval); } - if (flush_buff) - os_mem_free(softs, (void *)flush_buff, - sizeof(pqisrc_bmic_flush_cache_t)); + os_mem_free(softs, (void *)flush_buff, sizeof(pqisrc_bmic_flush_cache_t)); DBG_FUNC("OUT\n"); diff --git a/sys/dev/smartpqi/smartpqi_intr.c b/sys/dev/smartpqi/smartpqi_intr.c --- a/sys/dev/smartpqi/smartpqi_intr.c +++ b/sys/dev/smartpqi/smartpqi_intr.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,7 @@ #include "smartpqi_includes.h" + /* * Function to get processor count */ @@ -34,6 +35,7 @@ { DBG_FUNC("IN\n"); softs->num_cpus_online = mp_ncpus; + bsd_set_hint_adapter_cpu_config(softs); DBG_FUNC("OUT\n"); return PQI_STATUS_SUCCESS; @@ -86,10 +88,10 @@ softs->intr_count = 1; } - DBG_FUNC("OUT\n"); - error = bsd_status_to_pqi_status(BSD_SUCCESS); + DBG_FUNC("OUT\n"); + return error; } @@ -117,7 +119,7 @@ DBG_FUNC("IN\n"); - if (softs == NULL) + if (!softs) return; pqisrc_process_response_queue(softs, oq_id); @@ -138,7 +140,7 @@ DBG_FUNC("IN\n"); - if (softs == NULL) + if (!softs) return; pqisrc_process_response_queue(softs, oq_id); @@ -155,7 +157,7 @@ DBG_FUNC("IN\n"); - if (softs == NULL) + if (!softs) return; pqisrc_process_event_intr_src(softs, oq_id); @@ -170,10 +172,12 @@ register_legacy_intr(pqisrc_softstate_t *softs) { int error = BSD_SUCCESS; - device_t dev = softs->os_specific.pqi_dev; + device_t dev; DBG_FUNC("IN\n"); + dev = softs->os_specific.pqi_dev; + softs->os_specific.pqi_irq_rid[0] = 0; softs->os_specific.pqi_irq[0] = bus_alloc_resource_any(dev, \ SYS_RES_IRQ, &softs->os_specific.pqi_irq_rid[0], @@ -216,12 +220,13 @@ int i = 0; device_t dev = softs->os_specific.pqi_dev; int msix_count = softs->intr_count; + size_t msix_size = sizeof(pqi_intr_ctx_t) * msix_count; DBG_FUNC("IN\n"); - softs->os_specific.msi_ctx = os_mem_alloc(softs, sizeof(pqi_intr_ctx_t) * msix_count); + softs->os_specific.msi_ctx = os_mem_alloc(softs, msix_size); if (!softs->os_specific.msi_ctx) { - DBG_ERR("Memory allocation failed\n"); + DBG_ERR("Memory allocation failed, Requested memory:%lu bytes\n", (unsigned long)msix_size); return ENXIO; } @@ -282,7 +287,7 @@ return error; } softs->os_specific.intr_registered[i] = TRUE; - /* Add interrupt handlers*/ + /* Add interrupt handlers*/ for (i = 1; i < msix_count; ++i) { softs->os_specific.pqi_irq_rid[i] = i+1; softs->os_specific.pqi_irq[i] = \ @@ -335,7 +340,7 @@ bsd_status = register_msix_intr(softs); } - if(bsd_status) + if (bsd_status) DBG_WARN("interrupt registration is failed, error = %d\n", bsd_status); pqi_status = bsd_status_to_pqi_status(bsd_status); @@ -422,8 +427,8 @@ if (softs->os_specific.msi_enabled) { pci_release_msi(dev); softs->os_specific.msi_enabled = FALSE; - } - + } + DBG_FUNC("OUT\n"); return PQI_STATUS_SUCCESS; diff --git a/sys/dev/smartpqi/smartpqi_ioctl.h b/sys/dev/smartpqi/smartpqi_ioctl.h --- a/sys/dev/smartpqi/smartpqi_ioctl.h +++ b/sys/dev/smartpqi/smartpqi_ioctl.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,7 @@ /* IOCTL passthrough macros and structures */ #define SENSEINFOBYTES 32 /* note that this value may vary - between host implementations */ + between host implementations */ /* transfer direction */ #define PQIIOCTL_NONE 0x00 diff --git a/sys/dev/smartpqi/smartpqi_ioctl.c b/sys/dev/smartpqi/smartpqi_ioctl.c --- a/sys/dev/smartpqi/smartpqi_ioctl.c +++ b/sys/dev/smartpqi/smartpqi_ioctl.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,7 +51,7 @@ } /* - * Device open function for ioctl entry + * Device open function for ioctl entry */ static int smartpqi_open(struct cdev *cdev, int flags, int devtype, @@ -81,10 +81,10 @@ DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); - driver_info->major_version = PQISRC_OS_VERSION; - driver_info->minor_version = PQISRC_FEATURE_VERSION; - driver_info->release_version = PQISRC_PATCH_VERSION; - driver_info->build_revision = PQISRC_BUILD_VERSION; + driver_info->major_version = PQISRC_DRIVER_MAJOR; + driver_info->minor_version = PQISRC_DRIVER_MINOR; + driver_info->release_version = PQISRC_DRIVER_RELEASE; + driver_info->build_revision = PQISRC_DRIVER_REVISION; driver_info->max_targets = PQI_MAX_DEVICES - 1; driver_info->max_io = softs->max_io_for_scsi_ml; driver_info->max_transfer_length = softs->pqi_cap.max_transfer_size; @@ -117,6 +117,7 @@ vendor = pci_get_vendor(dev); device = pci_get_device(dev); pci_info->chip_id = ((device << 16) & 0xffff0000) | vendor; + DBG_FUNC("OUT\n"); } @@ -175,6 +176,7 @@ } DBG_FUNC("OUT error = %d\n", bsd_status); + return bsd_status; } @@ -232,7 +234,7 @@ int pqisrc_passthru_ioctl(struct pqisrc_softstate *softs, void *arg, int mode) { - int ret = PQI_STATUS_SUCCESS; + int ret; char *drv_buf = NULL; uint32_t tag = 0; IOCTL_Command_struct *iocommand = (IOCTL_Command_struct *)arg; @@ -246,18 +248,18 @@ memset(&request, 0, sizeof(request)); memset(&error_info, 0, sizeof(error_info)); - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); if (pqisrc_ctrl_offline(softs)) return PQI_STATUS_FAILURE; if (!arg) - return (PQI_STATUS_FAILURE); + return PQI_STATUS_FAILURE; if (iocommand->buf_size < 1 && iocommand->Request.Type.Direction != PQIIOCTL_NONE) return PQI_STATUS_FAILURE; - if (iocommand->Request.CDBLen > sizeof(request.cdb)) + if (iocommand->Request.CDBLen > sizeof(request.cmd.cdb)) return PQI_STATUS_FAILURE; switch (iocommand->Request.Type.Direction) { @@ -272,26 +274,23 @@ if (iocommand->buf_size > 0) { memset(&ioctl_dma_buf, 0, sizeof(struct dma_mem)); - ioctl_dma_buf.tag = "Ioctl_PassthruCmd_Buffer"; + os_strlcpy(ioctl_dma_buf.tag, "Ioctl_PassthruCmd_Buffer", sizeof(ioctl_dma_buf.tag)); ioctl_dma_buf.size = iocommand->buf_size; ioctl_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN; /* allocate memory */ ret = os_dma_mem_alloc(softs, &ioctl_dma_buf); if (ret) { DBG_ERR("Failed to Allocate dma mem for Ioctl PassthruCmd Buffer : %d\n", ret); - ret = PQI_STATUS_FAILURE; goto out; } - DBG_INFO("ioctl_dma_buf.dma_addr = %p\n",(void*)ioctl_dma_buf.dma_addr); - DBG_INFO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr); + DBG_IO("ioctl_dma_buf.dma_addr = %p\n",(void*)ioctl_dma_buf.dma_addr); + DBG_IO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr); drv_buf = (char *)ioctl_dma_buf.virt_addr; if (iocommand->Request.Type.Direction & PQIIOCTL_WRITE) { - if ((ret = os_copy_from_user(softs, (void *)drv_buf, - (void *)iocommand->buf, - iocommand->buf_size, mode)) != 0) { - ret = PQI_STATUS_FAILURE; + ret = os_copy_from_user(softs, (void *)drv_buf, (void *)iocommand->buf, iocommand->buf_size, mode); + if (ret != 0) { goto free_mem; } } @@ -302,7 +301,7 @@ PQI_REQUEST_HEADER_LENGTH; memcpy(request.lun_number, iocommand->LUN_info.LunAddrBytes, sizeof(request.lun_number)); - memcpy(request.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen); + memcpy(request.cmd.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen); request.additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; switch (iocommand->Request.Type.Direction) { @@ -330,7 +329,6 @@ tag = pqisrc_get_tag(&softs->taglist); if (INVALID_ELEM == tag) { DBG_ERR("Tag not available\n"); - ret = PQI_STATUS_FAILURE; goto free_mem; } request.request_id = tag; @@ -352,8 +350,7 @@ goto err_out; } - ret = pqisrc_wait_on_condition(softs, rcb, - PQISRC_PASSTHROUGH_CMD_TIMEOUT); + ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_PASSTHROUGH_CMD_TIMEOUT); if (ret != PQI_STATUS_SUCCESS) { DBG_ERR("Passthru IOCTL cmd timed out !!\n"); goto err_out; @@ -386,29 +383,29 @@ iocommand->error_info.SenseLen = sense_data_length; } - if (error_info.data_out_result == - PQI_RAID_DATA_IN_OUT_UNDERFLOW){ - rcb->status = REQUEST_SUCCESS; + if (error_info.data_out_result == PQI_RAID_DATA_IN_OUT_UNDERFLOW) { + rcb->status = PQI_STATUS_SUCCESS; } } - if (rcb->status == REQUEST_SUCCESS && iocommand->buf_size > 0 && + if (rcb->status == PQI_STATUS_SUCCESS && iocommand->buf_size > 0 && (iocommand->Request.Type.Direction & PQIIOCTL_READ)) { - if ((ret = os_copy_to_user(softs, (void*)iocommand->buf, - (void*)drv_buf, iocommand->buf_size, mode)) != 0) { - DBG_ERR("Failed to copy the response\n"); - goto err_out; + ret = os_copy_to_user(softs, (void*)iocommand->buf, (void*)drv_buf, iocommand->buf_size, mode); + if (ret != 0) { + DBG_ERR("Failed to copy the response\n"); + goto err_out; } } os_reset_rcb(rcb); pqisrc_put_tag(&softs->taglist, request.request_id); if (iocommand->buf_size > 0) - os_dma_mem_free(softs,&ioctl_dma_buf); + os_dma_mem_free(softs,&ioctl_dma_buf); DBG_FUNC("OUT\n"); - return ret; + return PQI_STATUS_SUCCESS; + err_out: os_reset_rcb(rcb); pqisrc_put_tag(&softs->taglist, request.request_id); diff --git a/sys/dev/smartpqi/smartpqi_main.c b/sys/dev/smartpqi/smartpqi_main.c --- a/sys/dev/smartpqi/smartpqi_main.c +++ b/sys/dev/smartpqi/smartpqi_main.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,7 +29,6 @@ */ #include "smartpqi_includes.h" -#include "smartpqi_prototypes.h" CTASSERT(BSD_SUCCESS == PQI_STATUS_SUCCESS); @@ -60,6 +59,7 @@ {0x9005, 0x028f, 0x103c, 0x652, PQI_HWIF_SRCV, "E208i-c SR Gen10"}, {0x9005, 0x028f, 0x103c, 0x654, PQI_HWIF_SRCV, "E208i-a SR Gen10"}, {0x9005, 0x028f, 0x103c, 0x655, PQI_HWIF_SRCV, "P408e-m SR Gen10"}, + {0x9005, 0x028f, 0x9005, 0x659, PQI_HWIF_SRCV, "2100C8iOXS"}, /* (MSCC PM8221 8x12G based) */ {0x9005, 0x028f, 0x103c, 0x700, PQI_HWIF_SRCV, "P204i-c SR Gen10"}, @@ -67,7 +67,7 @@ {0x9005, 0x028f, 0x193d, 0x1104, PQI_HWIF_SRCV, "UN RAID P2404-Mf-4i-2GB"}, {0x9005, 0x028f, 0x193d, 0x1106, PQI_HWIF_SRCV, "UN RAID P2404-Mf-4i-1GB"}, {0x9005, 0x028f, 0x193d, 0x1108, PQI_HWIF_SRCV, "UN RAID P4408-Ma-8i-2GB"}, - + {0x9005, 0x028f, 0x193d, 0x1109, PQI_HWIF_SRCV, "UN RAID P4408-Mr-8i-2GB"}, /* (MSCC PM8204 8x12G based) */ {0x9005, 0x028f, 0x9005, 0x800, PQI_HWIF_SRCV, "SmartRAID 3154-8i"}, @@ -81,14 +81,15 @@ {0x9005, 0x028f, 0x152d, 0x8a22, PQI_HWIF_SRCV, "QS-8204-8i"}, {0x9005, 0x028f, 0x193d, 0xf460, PQI_HWIF_SRCV, "UN RAID P460-M4"}, {0x9005, 0x028f, 0x193d, 0xf461, PQI_HWIF_SRCV, "UN RAID P460-B4"}, - {0x9005, 0x028f, 0x1bd4, 0x004b, PQI_HWIF_SRCV, "INSPUR PM8204-2GB"}, - {0x9005, 0x028f, 0x1bd4, 0x004c, PQI_HWIF_SRCV, "INSPUR PM8204-4GB"}, + {0x9005, 0x028f, 0x1bd4, 0x004b, PQI_HWIF_SRCV, "PM8204-2GB"}, + {0x9005, 0x028f, 0x1bd4, 0x004c, PQI_HWIF_SRCV, "PM8204-4GB"}, {0x9005, 0x028f, 0x193d, 0x1105, PQI_HWIF_SRCV, "UN RAID P4408-Mf-8i-2GB"}, {0x9005, 0x028f, 0x193d, 0x1107, PQI_HWIF_SRCV, "UN RAID P4408-Mf-8i-4GB"}, {0x9005, 0x028f, 0x1d8d, 0x800, PQI_HWIF_SRCV, "Fiberhome SmartRAID AIS-8204-8i"}, {0x9005, 0x028f, 0x9005, 0x0808, PQI_HWIF_SRCV, "SmartRAID 3101E-4i"}, {0x9005, 0x028f, 0x9005, 0x0809, PQI_HWIF_SRCV, "SmartRAID 3102E-8i"}, {0x9005, 0x028f, 0x9005, 0x080a, PQI_HWIF_SRCV, "SmartRAID 3152-8i/N"}, + {0x9005, 0x028f, 0x1cc4, 0x0101, PQI_HWIF_SRCV, "Ramaxel FBGF-RAD PM8204"}, /* (MSCC PM8222 8x12G based) */ {0x9005, 0x028f, 0x9005, 0x900, PQI_HWIF_SRCV, "SmartHBA 2100-8i"}, @@ -105,12 +106,13 @@ {0x9005, 0x028f, 0x193d, 0x8461, PQI_HWIF_SRCV, "UN HBA H460-B1"}, {0x9005, 0x028f, 0x193d, 0xc460, PQI_HWIF_SRCV, "UN RAID P460-M2"}, {0x9005, 0x028f, 0x193d, 0xc461, PQI_HWIF_SRCV, "UN RAID P460-B2"}, - {0x9005, 0x028f, 0x1bd4, 0x004a, PQI_HWIF_SRCV, "INSPUR PM8222-SHBA"}, + {0x9005, 0x028f, 0x1bd4, 0x004a, PQI_HWIF_SRCV, "PM8222-SHBA"}, {0x9005, 0x028f, 0x13fe, 0x8312, PQI_HWIF_SRCV, "MIC-8312BridgeB"}, - {0x9005, 0x028f, 0x1bd4, 0x004f, PQI_HWIF_SRCV, "INSPUR PM8222-HBA"}, + {0x9005, 0x028f, 0x1bd4, 0x004f, PQI_HWIF_SRCV, "PM8222-HBA"}, {0x9005, 0x028f, 0x1d8d, 0x908, PQI_HWIF_SRCV, "Fiberhome SmartHBA AIS-8222-8i"}, - {0x9005, 0x028f, 0x1bd4, 0x006C, PQI_HWIF_SRCV, "INSPUR RS0800M5E8i"}, - {0x9005, 0x028f, 0x1bd4, 0x006D, PQI_HWIF_SRCV, "INSPUR RS0800M5H8i"}, + {0x9005, 0x028f, 0x1bd4, 0x006C, PQI_HWIF_SRCV, "RS0800M5E8i"}, + {0x9005, 0x028f, 0x1bd4, 0x006D, PQI_HWIF_SRCV, "RS0800M5H8i"}, + {0x9005, 0x028f, 0x1cc4, 0x0201, PQI_HWIF_SRCV, "Ramaxel FBGF-RAD PM8222"}, /* (SRCx MSCC FVB 24x12G based) */ {0x9005, 0x028f, 0x103c, 0x1001, PQI_HWIF_SRCV, "MSCC FVB"}, @@ -124,17 +126,26 @@ {0x9005, 0x028f, 0x9005, 0x1302, PQI_HWIF_SRCV, "SmartHBA 2100-8i8e"}, {0x9005, 0x028f, 0x9005, 0x1303, PQI_HWIF_SRCV, "SmartHBA 2100-24i"}, {0x9005, 0x028f, 0x105b, 0x1321, PQI_HWIF_SRCV, "8242-24i"}, - {0x9005, 0x028f, 0x1bd4, 0x0045, PQI_HWIF_SRCV, "INSPUR SMART-HBA 8242-24i"}, + {0x9005, 0x028f, 0x1bd4, 0x0045, PQI_HWIF_SRCV, "SMART-HBA 8242-24i"}, + {0x9005, 0x028f, 0x1bd4, 0x006B, PQI_HWIF_SRCV, "RS0800M5H24i"}, + {0x9005, 0x028f, 0x1bd4, 0x0070, PQI_HWIF_SRCV, "RS0800M5E24i"}, /* (MSCC PM8236 16x12G based) */ {0x9005, 0x028f, 0x152d, 0x8a24, PQI_HWIF_SRCV, "QS-8236-16i"}, {0x9005, 0x028f, 0x9005, 0x1380, PQI_HWIF_SRCV, "SmartRAID 3154-16i"}, - {0x9005, 0x028f, 0x1bd4, 0x0046, PQI_HWIF_SRCV, "INSPUR RAID 8236-16i"}, + {0x9005, 0x028f, 0x1bd4, 0x0046, PQI_HWIF_SRCV, "RAID 8236-16i"}, {0x9005, 0x028f, 0x1d8d, 0x806, PQI_HWIF_SRCV, "Fiberhome SmartRAID AIS-8236-16i"}, + {0x9005, 0x028f, 0x1cf2, 0x0B27, PQI_HWIF_SRCV, "ZTE SmartROC3100 SDPSA/B-18i 4G"}, + {0x9005, 0x028f, 0x1cf2, 0x0B45, PQI_HWIF_SRCV, "ZTE SmartROC3100 SDPSA/B_L-18i 2G"}, + {0x9005, 0x028f, 0x1cf2, 0x5445, PQI_HWIF_SRCV, "ZTE SmartROC3100 RM241-18i 2G"}, + {0x9005, 0x028f, 0x1cf2, 0x5446, PQI_HWIF_SRCV, "ZTE SmartROC3100 RM242-18i 4G"}, {0x9005, 0x028f, 0x1cf2, 0x5449, PQI_HWIF_SRCV, "ZTE SmartROC3100 RS241-18i 2G"}, {0x9005, 0x028f, 0x1cf2, 0x544A, PQI_HWIF_SRCV, "ZTE SmartROC3100 RS242-18i 4G"}, {0x9005, 0x028f, 0x1cf2, 0x544D, PQI_HWIF_SRCV, "ZTE SmartROC3100 RM241B-18i 2G"}, {0x9005, 0x028f, 0x1cf2, 0x544E, PQI_HWIF_SRCV, "ZTE SmartROC3100 RM242B-18i 4G"}, + {0x9005, 0x028f, 0x1bd4, 0x006F, PQI_HWIF_SRCV, "RS0804M5R16i"}, + + /* (MSCC PM8237 24x12G based) */ {0x9005, 0x028f, 0x103c, 0x1100, PQI_HWIF_SRCV, "P816i-a SR Gen10"}, @@ -145,18 +156,24 @@ {0x9005, 0x028f, 0x9005, 0x1280, PQI_HWIF_SRCV, "HBA 1100-16i"}, {0x9005, 0x028f, 0x9005, 0x1281, PQI_HWIF_SRCV, "HBA 1100-16e"}, {0x9005, 0x028f, 0x105b, 0x1211, PQI_HWIF_SRCV, "8238-16i"}, - {0x9005, 0x028f, 0x1bd4, 0x0048, PQI_HWIF_SRCV, "INSPUR SMART-HBA 8238-16i"}, + {0x9005, 0x028f, 0x1bd4, 0x0048, PQI_HWIF_SRCV, "SMART-HBA 8238-16i"}, {0x9005, 0x028f, 0x9005, 0x1282, PQI_HWIF_SRCV, "SmartHBA 2100-16i"}, {0x9005, 0x028f, 0x1d8d, 0x916, PQI_HWIF_SRCV, "Fiberhome SmartHBA AIS-8238-16i"}, {0x9005, 0x028f, 0x1458, 0x1000, PQI_HWIF_SRCV, "GIGABYTE SmartHBA CLN1832"}, + {0x9005, 0x028f, 0x1cf2, 0x0B29, PQI_HWIF_SRCV, "ZTE SmartIOC2100 SDPSA/B_I-18i"}, + {0x9005, 0x028f, 0x1cf2, 0x5447, PQI_HWIF_SRCV, "ZTE SmartIOC2100 RM243-18i"}, + {0x9005, 0x028f, 0x1cf2, 0x544B, PQI_HWIF_SRCV, "ZTE SmartIOC2100 RS243-18i"}, {0x9005, 0x028f, 0x1cf2, 0x544F, PQI_HWIF_SRCV, "ZTE SmartIOC2100 RM243B-18i"}, + {0x9005, 0x028f, 0x1bd4, 0x0071, PQI_HWIF_SRCV, "RS0800M5H16i"}, + {0x9005, 0x028f, 0x1bd4, 0x0072, PQI_HWIF_SRCV, "RS0800M5E16i"}, /* (MSCC PM8240 24x12G based) */ {0x9005, 0x028f, 0x152d, 0x8a36, PQI_HWIF_SRCV, "QS-8240-24i"}, {0x9005, 0x028f, 0x9005, 0x1200, PQI_HWIF_SRCV, "SmartRAID 3154-24i"}, {0x9005, 0x028f, 0x9005, 0x1201, PQI_HWIF_SRCV, "SmartRAID 3154-8i16e"}, {0x9005, 0x028f, 0x9005, 0x1202, PQI_HWIF_SRCV, "SmartRAID 3154-8i8e"}, - {0x9005, 0x028f, 0x1bd4, 0x0047, PQI_HWIF_SRCV, "INSPUR RAID 8240-24i"}, + {0x9005, 0x028f, 0x1bd4, 0x0047, PQI_HWIF_SRCV, "RAID 8240-24i"}, + {0x9005, 0x028f, 0x1dfc, 0x3161, PQI_HWIF_SRCV, "NTCOM SAS3 RAID-24i"}, {0x9005, 0x028f, 0x1F0C, 0x3161, PQI_HWIF_SRCV, "NT RAID 3100-24i"}, /* Huawei ID's */ @@ -166,22 +183,127 @@ {0x9005, 0x028f, 0x19e5, 0xd22c, PQI_HWIF_SRCV, "SR455C-M 4G"}, {0x9005, 0x028f, 0x19e5, 0xd229, PQI_HWIF_SRCV, "SR155-M"}, {0x9005, 0x028f, 0x19e5, 0xd22b, PQI_HWIF_SRCV, "SR455C-ME 4G"}, + + /* (MSCC PM8252 8x12G based) */ + {0x9005, 0x028f, 0x193d, 0x110b, PQI_HWIF_SRCV, "UN HBA H4508-Mf-8i"}, + {0x9005, 0x028f, 0x1bd4, 0x0052, PQI_HWIF_SRCV, "MT0801M6E"}, + {0x9005, 0x028f, 0x1bd4, 0x0054, PQI_HWIF_SRCV, "MT0800M6H"}, + {0x9005, 0x028f, 0x1bd4, 0x0086, PQI_HWIF_SRCV, "RT0800M7E"}, + {0x9005, 0x028f, 0x1bd4, 0x0087, PQI_HWIF_SRCV, "RT0800M7H"}, + {0x9005, 0x028f, 0x1f51, 0x1001, PQI_HWIF_SRCV, "SmartHBA P6600-8i"}, + {0x9005, 0x028f, 0x1f51, 0x1003, PQI_HWIF_SRCV, "SmartHBA P6600-8e"}, + {0x9005, 0x028f, 0x9005, 0x1460, PQI_HWIF_SRCV, "HBA 1200"}, + {0x9005, 0x028f, 0x9005, 0x1461, PQI_HWIF_SRCV, "SmartHBA 2200"}, + {0x9005, 0x028f, 0x9005, 0x1462, PQI_HWIF_SRCV, "HBA 1200-8i"}, + /* (MSCC PM8254 32x12G based) */ + {0x9005, 0x028f, 0x1bd4, 0x0051, PQI_HWIF_SRCV, "MT0804M6R"}, + {0x9005, 0x028f, 0x1bd4, 0x0053, PQI_HWIF_SRCV, "MT0808M6R"}, + {0x9005, 0x028f, 0x1bd4, 0x0088, PQI_HWIF_SRCV, "RT0804M7R"}, + {0x9005, 0x028f, 0x1bd4, 0x0089, PQI_HWIF_SRCV, "RT0808M7R"}, + {0x9005, 0x028f, 0x1f51, 0x1002, PQI_HWIF_SRCV, "SmartRAID P7604-8i"}, + {0x9005, 0x028f, 0x1f51, 0x1004, PQI_HWIF_SRCV, "SmartRAID P7604-8e"}, + {0x9005, 0x028f, 0x9005, 0x14a0, PQI_HWIF_SRCV, "SmartRAID 3254-8i"}, + {0x9005, 0x028f, 0x9005, 0x14a1, PQI_HWIF_SRCV, "SmartRAID 3204-8i"}, {0x9005, 0x028f, 0x9005, 0x14a2, PQI_HWIF_SRCV, "SmartRAID 3252-8i"}, {0x9005, 0x028f, 0x9005, 0x14a4, PQI_HWIF_SRCV, "SmartRAID 3254-8i /e"}, {0x9005, 0x028f, 0x9005, 0x14a5, PQI_HWIF_SRCV, "SmartRAID 3252-8i /e"}, {0x9005, 0x028f, 0x9005, 0x14a6, PQI_HWIF_SRCV, "SmartRAID 3204-8i /e"}, -/* (MSCC PM8265 16x12G based) */ + + /* (MSCC PM8262 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x14c0, PQI_HWIF_SRCV, "SmartHBA 2200-16i"}, + {0x9005, 0x028f, 0x9005, 0x14c1, PQI_HWIF_SRCV, "HBA 1200-16i"}, + {0x9005, 0x028f, 0x9005, 0x14c3, PQI_HWIF_SRCV, "HBA 1200-16e"}, + {0x9005, 0x028f, 0x9005, 0x14c4, PQI_HWIF_SRCV, "HBA 1200-8e"}, + {0x9005, 0x028f, 0x1f51, 0x1005, PQI_HWIF_SRCV, "SmartHBA P6600-16i"}, + {0x9005, 0x028f, 0x1f51, 0x1007, PQI_HWIF_SRCV, "SmartHBA P6600-8i8e"}, + {0x9005, 0x028f, 0x1f51, 0x1009, PQI_HWIF_SRCV, "SmartHBA P6600-16e"}, + {0x9005, 0x028f, 0x1cf2, 0x54dc, PQI_HWIF_SRCV, "ZTE SmartIOC2200 RM346-16i"}, + {0x9005, 0x028f, 0x1cf2, 0x0806, PQI_HWIF_SRCV, "ZTE SmartIOC2200 RS346-16i"}, + + /* (MSCC PM8264 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x14b0, PQI_HWIF_SRCV, "SmartRAID 3254-16i"}, + {0x9005, 0x028f, 0x9005, 0x14b1, PQI_HWIF_SRCV, "SmartRAID 3258-16i"}, + {0x9005, 0x028f, 0x1f51, 0x1006, PQI_HWIF_SRCV, "SmartRAID P7608-16i"}, + {0x9005, 0x028f, 0x1f51, 0x1008, PQI_HWIF_SRCV, "SmartRAID P7608-8i8e"}, + {0x9005, 0x028f, 0x1f51, 0x100a, PQI_HWIF_SRCV, "SmartRAID P7608-16e"}, + {0x9005, 0x028f, 0x1cf2, 0x54da, PQI_HWIF_SRCV, "ZTE SmartROC3200 RM344-16i 4G"}, + {0x9005, 0x028f, 0x1cf2, 0x54db, PQI_HWIF_SRCV, "ZTE SmartROC3200 RM345-16i 8G"}, + {0x9005, 0x028f, 0x1cf2, 0x0804, PQI_HWIF_SRCV, "ZTE SmartROC3200 RS344-16i 4G"}, + {0x9005, 0x028f, 0x1cf2, 0x0805, PQI_HWIF_SRCV, "ZTE SmartROC3200 RS345-16i 8G"}, + + /* (MSCC PM8265 16x12G based) */ + {0x9005, 0x028f, 0x1590, 0x02dc, PQI_HWIF_SRCV, "SR416i-a Gen10+"}, + {0x9005, 0x028f, 0x9005, 0x1470, PQI_HWIF_SRCV, "SmartRAID 3200"}, + {0x9005, 0x028f, 0x9005, 0x1471, PQI_HWIF_SRCV, "SmartRAID 3254-16i /e"}, + {0x9005, 0x028f, 0x9005, 0x1472, PQI_HWIF_SRCV, "SmartRAID 3258-16i /e"}, + {0x9005, 0x028f, 0x9005, 0x1473, PQI_HWIF_SRCV, "SmartRAID 3284-16io /e/uC"}, {0x9005, 0x028f, 0x9005, 0x1474, PQI_HWIF_SRCV, "SmartRAID 3254-16io /e"}, -/* (MSCC PM8270 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1475, PQI_HWIF_SRCV, "SmartRAID 3254-16e /e"}, + + /* (MSCC PM8266 16x12G based) */ + {0x9005, 0x028f, 0x1014, 0x0718, PQI_HWIF_SRCV, "IBM 4-Port 24G SAS"}, + {0x9005, 0x028f, 0x9005, 0x1490, PQI_HWIF_SRCV, "HBA 1200p Ultra"}, + {0x9005, 0x028f, 0x9005, 0x1491, PQI_HWIF_SRCV, "SmartHBA 2200p Ultra"}, + {0x9005, 0x028f, 0x9005, 0x1402, PQI_HWIF_SRCV, "HBA Ultra 1200P-16i"}, + {0x9005, 0x028f, 0x9005, 0x1441, PQI_HWIF_SRCV, "HBA Ultra 1200P-32i"}, + + /* (MSCC PM8268 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x14d0, PQI_HWIF_SRCV, "SmartRAID Ultra 3258P-16i"}, + + /* (MSCC PM8269 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1400, PQI_HWIF_SRCV, "SmartRAID Ultra 3258P-16i /e"}, + + /* (MSCC PM8270 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1410, PQI_HWIF_SRCV, "HBA Ultra 1200P-16e"}, + {0x9005, 0x028f, 0x9005, 0x1411, PQI_HWIF_SRCV, "HBA 1200 Ultra"}, + {0x9005, 0x028f, 0x9005, 0x1412, PQI_HWIF_SRCV, "SmartHBA 2200 Ultra"}, {0x9005, 0x028f, 0x9005, 0x1463, PQI_HWIF_SRCV, "SmartHBA 2200-8io /e"}, {0x9005, 0x028f, 0x9005, 0x14c2, PQI_HWIF_SRCV, "SmartHBA 2200-16io /e"}, + + /* (MSCC PM8271 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x14e0, PQI_HWIF_SRCV, "SmartIOC PM8271"}, + + /* (MSCC PM8272 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1420, PQI_HWIF_SRCV, "SmartRAID Ultra 3254-16e"}, + + /* (MSCC PM8273 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1430, PQI_HWIF_SRCV, "SmartRAID Ultra 3254-16e /e"}, + + /* (MSCC PM8274 16x12G based) */ + {0x9005, 0x028f, 0x1e93, 0x1000, PQI_HWIF_SRCV, "ByteHBA JGH43024-8"}, + {0x9005, 0x028f, 0x1e93, 0x1001, PQI_HWIF_SRCV, "ByteHBA JGH43034-8"}, + {0x9005, 0x028f, 0x1e93, 0x1005, PQI_HWIF_SRCV, "ByteHBA JGH43014-8"}, + + /* (MSCC PM8275 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x14f0, PQI_HWIF_SRCV, "SmartIOC PM8275"}, + + /* (MSCC PM8276 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1480, PQI_HWIF_SRCV, "SmartRAID 3200 Ultra"}, + {0x9005, 0x028f, 0x1e93, 0x1002, PQI_HWIF_SRCV, "ByteHBA JGH44014-8"}, + + /* (MSCC PM8278 16x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1440, PQI_HWIF_SRCV, "SmartRAID Ultra 3258P-32i"}, + /* (MSCC PM8279 32x12G based) */ + {0x9005, 0x028f, 0x9005, 0x1450, PQI_HWIF_SRCV, "SmartRAID Ultra 3258P-32i /e"}, + {0x9005, 0x028f, 0x1590, 0x0294, PQI_HWIF_SRCV, "SR932i-p Gen10+"}, {0x9005, 0x028f, 0x1590, 0x0381, PQI_HWIF_SRCV, "SR932i-p Gen11"}, {0x9005, 0x028f, 0x1590, 0x0382, PQI_HWIF_SRCV, "SR308i-p Gen11"}, {0x9005, 0x028f, 0x1590, 0x0383, PQI_HWIF_SRCV, "SR308i-o Gen11"}, {0x9005, 0x028f, 0x1590, 0x02db, PQI_HWIF_SRCV, "SR416ie-m Gen11"}, {0x9005, 0x028f, 0x1590, 0x032e, PQI_HWIF_SRCV, "SR416i-o Gen11"}, + {0x9005, 0x028f, 0x9005, 0x1452, PQI_HWIF_SRCV, "SmartRAID 3200p Ultra"}, + + /* (MSCC HBA/SMARTHBA/CFF SmartRAID - Lenovo 8X12G 16X12G based) */ + {0x9005, 0x028f, 0x1d49, 0x0220, PQI_HWIF_SRCV, "4350-8i SAS/SATA HBA"}, + {0x9005, 0x028f, 0x1d49, 0x0221, PQI_HWIF_SRCV, "4350-16i SAS/SATA HBA"}, + {0x9005, 0x028f, 0x1d49, 0x0520, PQI_HWIF_SRCV, "5350-8i"}, + {0x9005, 0x028f, 0x1d49, 0x0522, PQI_HWIF_SRCV, "5350-8i INTR"}, + {0x9005, 0x028f, 0x1d49, 0x0620, PQI_HWIF_SRCV, "9350-8i 2GB Flash"}, + {0x9005, 0x028f, 0x1d49, 0x0621, PQI_HWIF_SRCV, "9350-8i 2GB Flash INTR"}, + {0x9005, 0x028f, 0x1d49, 0x0622, PQI_HWIF_SRCV, "9350-16i 4GB Flash"}, + {0x9005, 0x028f, 0x1d49, 0x0623, PQI_HWIF_SRCV, "9350-16i 4GB Flash INTR"}, {0, 0, 0, 0, 0, 0} }; @@ -195,11 +317,26 @@ /* * Function to identify the installed adapter. */ -static struct -pqi_ident *pqi_find_ident(device_t dev) +static struct pqi_ident * +pqi_find_ident(device_t dev) { struct pqi_ident *m; u_int16_t vendid, devid, sub_vendid, sub_devid; + static long AllowWildcards = 0xffffffff; + int result; + +#ifdef DEVICE_HINT + if (AllowWildcards == 0xffffffff) + { + result = resource_long_value("smartpqi", 0, "allow_wildcards", &AllowWildcards); + + /* the default case if the hint is not found is to allow wildcards */ + if (result != DEVICE_HINT_SUCCESS) { + AllowWildcards = 1; + } + } + +#endif vendid = pci_get_vendor(dev); devid = pci_get_device(dev); @@ -216,7 +353,16 @@ for (m = pqi_family_identifiers; m->vendor != 0; m++) { if ((m->vendor == vendid) && (m->device == devid)) { - return (m); + if (AllowWildcards != 0) + { + DBG_NOTE("Controller device ID matched using wildcards\n"); + return (m); + } + else + { + DBG_NOTE("Controller not probed because device ID wildcards are disabled\n") + return (NULL); + } } } @@ -253,6 +399,97 @@ } +static void read_device_hint_resource(struct pqisrc_softstate *softs, + char *keyword, uint32_t *value) +{ + DBG_FUNC("IN\n"); + + device_t dev = softs->os_specific.pqi_dev; + + if (resource_long_value("smartpqi", device_get_unit(dev), keyword, (long *)value) == DEVICE_HINT_SUCCESS) { + if (*value) { + /* set resource to 1 for disabling the + * firmware feature in device hint file. */ + *value = 0; + + } + else { + /* set resource to 0 for enabling the + * firmware feature in device hint file. */ + *value = 1; + } + } + else { + /* Enabled by default */ + *value = 1; + } + + DBG_NOTE("SmartPQI Device Hint: %s, Is it enabled = %u\n", keyword, *value); + + DBG_FUNC("OUT\n"); +} + +static void read_device_hint_decimal_value(struct pqisrc_softstate *softs, + char *keyword, uint32_t *value) +{ + DBG_FUNC("IN\n"); + + device_t dev = softs->os_specific.pqi_dev; + + if (resource_long_value("smartpqi", device_get_unit(dev), keyword, (long *)value) == DEVICE_HINT_SUCCESS) { + /* Nothing to do here. Value reads + * directly from Device.Hint file */ + } + else { + /* Set to max to determine the value */ + *value = 0XFFFF; + } + + DBG_FUNC("OUT\n"); +} + +static void smartpqi_read_all_device_hint_file_entries(struct pqisrc_softstate *softs) +{ + uint32_t value = 0; + + DBG_FUNC("IN\n"); + + /* hint.smartpqi.0.stream_disable = "0" */ + read_device_hint_resource(softs, STREAM_DETECTION, &value); + softs->hint.stream_status = value; + + /* hint.smartpqi.0.sata_unique_wwn_disable = "0" */ + read_device_hint_resource(softs, SATA_UNIQUE_WWN, &value); + softs->hint.sata_unique_wwn_status = value; + + /* hint.smartpqi.0.aio_raid1_write_disable = "0" */ + read_device_hint_resource(softs, AIO_RAID1_WRITE_BYPASS, &value); + softs->hint.aio_raid1_write_status = value; + + /* hint.smartpqi.0.aio_raid5_write_disable = "0" */ + read_device_hint_resource(softs, AIO_RAID5_WRITE_BYPASS, &value); + softs->hint.aio_raid5_write_status = value; + + /* hint.smartpqi.0.aio_raid6_write_disable = "0" */ + read_device_hint_resource(softs, AIO_RAID6_WRITE_BYPASS, &value); + softs->hint.aio_raid6_write_status = value; + + /* hint.smartpqi.0.queue_depth = "0" */ + read_device_hint_decimal_value(softs, ADAPTER_QUEUE_DEPTH, &value); + softs->hint.queue_depth = value; + + /* hint.smartpqi.0.sg_count = "0" */ + read_device_hint_decimal_value(softs, SCATTER_GATHER_COUNT, &value); + softs->hint.sg_segments = value; + + /* hint.smartpqi.0.queue_count = "0" */ + read_device_hint_decimal_value(softs, QUEUE_COUNT, &value); + softs->hint.cpu_count = value; + + DBG_FUNC("IN\n"); +} + + /* * Allocate resources for our device, set up the bus interface. * Initialize the PQI related functionality, scan devices, register sim to @@ -261,7 +498,7 @@ static int smartpqi_attach(device_t dev) { - struct pqisrc_softstate *softs = NULL; + struct pqisrc_softstate *softs; struct pqi_ident *id = NULL; int error = BSD_SUCCESS; u_int32_t command = 0, i = 0; @@ -368,6 +605,8 @@ softs->os_specific.sim_registered = FALSE; softs->os_name = "FreeBSD "; + smartpqi_read_all_device_hint_file_entries(softs); + /* Initialize the PQI library */ error = pqisrc_init(softs); if (error != PQI_STATUS_SUCCESS) { @@ -379,17 +618,17 @@ error = BSD_SUCCESS; } - mtx_init(&softs->os_specific.cam_lock, "cam_lock", NULL, MTX_DEF); - softs->os_specific.mtx_init = TRUE; - mtx_init(&softs->os_specific.map_lock, "map_lock", NULL, MTX_DEF); + mtx_init(&softs->os_specific.cam_lock, "cam_lock", NULL, MTX_DEF); + softs->os_specific.mtx_init = TRUE; + mtx_init(&softs->os_specific.map_lock, "map_lock", NULL, MTX_DEF); - callout_init(&softs->os_specific.wellness_periodic, 1); - callout_init(&softs->os_specific.heartbeat_timeout_id, 1); + callout_init(&softs->os_specific.wellness_periodic, 1); + callout_init(&softs->os_specific.heartbeat_timeout_id, 1); - /* - * Create DMA tag for mapping buffers into controller-addressable space. - */ - if (bus_dma_tag_create(softs->os_specific.pqi_parent_dmat,/* parent */ + /* + * Create DMA tag for mapping buffers into controller-addressable space. + */ + if (bus_dma_tag_create(softs->os_specific.pqi_parent_dmat,/* parent */ PAGE_SIZE, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR,/* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -409,7 +648,7 @@ for( i = 1; i <= softs->pqi_cap.max_outstanding_io; i++, rcbp++ ) { if ((error = bus_dmamap_create(softs->os_specific.pqi_buffer_dmat, 0, &rcbp->cm_datamap)) != 0) { DBG_ERR("Cant create datamap for buf @" - "rcbp = %p maxio = %d error = %d\n", + "rcbp = %p maxio = %u error = %d\n", rcbp, softs->pqi_cap.max_outstanding_io, error); goto dma_out; } @@ -425,6 +664,9 @@ error = ENXIO; goto out; } + else { + error = BSD_SUCCESS; + } error = register_sim(softs, card_index); if (error) { @@ -443,6 +685,7 @@ card_index, error); goto out; } + goto out; dma_out: @@ -452,6 +695,7 @@ softs->os_specific.pqi_regs_res0); out: DBG_FUNC("OUT error = %d\n", error); + return(error); } @@ -479,6 +723,8 @@ if (rval != PQI_STATUS_SUCCESS) { DBG_ERR("Unable to flush adapter cache! rval = %d\n", rval); rval = EIO; + } else { + rval = BSD_SUCCESS; } } @@ -558,10 +804,11 @@ } DBG_FUNC("OUT\n"); - + return bsd_status; } + /* * PCI bus interface. */ diff --git a/sys/dev/smartpqi/smartpqi_mem.c b/sys/dev/smartpqi/smartpqi_mem.c --- a/sys/dev/smartpqi/smartpqi_mem.c +++ b/sys/dev/smartpqi/smartpqi_mem.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -168,9 +168,9 @@ void *os_mem_alloc(pqisrc_softstate_t *softs, size_t size) { - void *addr = NULL; + void *addr; - /* DBG_FUNC("IN\n"); */ + /* DBG_FUNC("IN\n"); */ addr = malloc((unsigned long)size, M_SMARTPQI, M_NOWAIT | M_ZERO); @@ -184,7 +184,7 @@ * Mem resource deallocation wrapper function */ void -os_mem_free(pqisrc_softstate_t *softs, char *addr, size_t size) +os_mem_free(pqisrc_softstate_t *softs, void *addr, size_t size) { /* DBG_FUNC("IN\n"); */ @@ -205,6 +205,6 @@ if (softs->os_specific.pqi_regs_res0 != NULL) bus_release_resource(softs->os_specific.pqi_dev, SYS_RES_MEMORY, - softs->os_specific.pqi_regs_rid0, + softs->os_specific.pqi_regs_rid0, softs->os_specific.pqi_regs_res0); } diff --git a/sys/dev/smartpqi/smartpqi_misc.c b/sys/dev/smartpqi/smartpqi_misc.c --- a/sys/dev/smartpqi/smartpqi_misc.c +++ b/sys/dev/smartpqi/smartpqi_misc.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,13 +27,13 @@ #include "smartpqi_includes.h" /* - * Populate hostwellness time variables in bcd format from FreeBSD format + * Populate hostwellness time variables in bcd format from FreeBSD format. */ void os_get_time(struct bmic_host_wellness_time *host_wellness_time) { struct timespec ts; - struct clocktime ct; + struct clocktime ct = {0}; getnanotime(&ts); clock_ts_to_ct(&ts, &ct); @@ -111,8 +111,9 @@ os_init_spinlock(struct pqisrc_softstate *softs, struct mtx *lock, char *lockname) { - mtx_init(lock, lockname, NULL, MTX_SPIN); - return 0; + mtx_init(lock, lockname, NULL, MTX_SPIN); + return 0; + } /* @@ -180,3 +181,132 @@ else return PQI_STATUS_FAILURE; } + +/* Return true : If the feature is disabled from device hints. + * Return false : If the feature is enabled from device hints. + * Return default: The feature status is not deciding from hints. + * */ +boolean_t +check_device_hint_status(struct pqisrc_softstate *softs, unsigned int feature_bit) +{ + DBG_FUNC("IN\n"); + + switch(feature_bit) { + case PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS: + if (!softs->hint.aio_raid1_write_status) + return true; + break; + case PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS: + if (!softs->hint.aio_raid5_write_status) + return true; + break; + case PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS: + if (!softs->hint.aio_raid6_write_status) + return true; + break; + case PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN: + if (!softs->hint.sata_unique_wwn_status) + return true; + break; + default: + return false; + } + + DBG_FUNC("OUT\n"); + + return false; +} + +static void +bsd_set_hint_adapter_queue_depth(struct pqisrc_softstate *softs) +{ + uint32_t queue_depth = softs->pqi_cap.max_outstanding_io; + + DBG_FUNC("IN\n"); + + if ((!softs->hint.queue_depth) || (softs->hint.queue_depth > + softs->pqi_cap.max_outstanding_io)) { + /* Nothing to do here. Supported queue depth + * is already set by controller/driver */ + } + else if (softs->hint.queue_depth < PQISRC_MIN_OUTSTANDING_REQ) { + /* Nothing to do here. Supported queue depth + * is already set by controller/driver */ + } + else { + /* Set Device.Hint queue depth here */ + softs->pqi_cap.max_outstanding_io = + softs->hint.queue_depth; + } + + DBG_NOTE("Adapter queue depth before hint set = %u, Queue depth after hint set = %u\n", + queue_depth, softs->pqi_cap.max_outstanding_io); + + DBG_FUNC("OUT\n"); +} + +static void +bsd_set_hint_scatter_gather_config(struct pqisrc_softstate *softs) +{ + uint32_t pqi_sg_segments = softs->pqi_cap.max_sg_elem; + + DBG_FUNC("IN\n"); + + /* At least > 16 sg's required to wotk hint correctly. + * Default the sg count set by driver/controller. */ + + if ((!softs->hint.sg_segments) || (softs->hint.sg_segments > + softs->pqi_cap.max_sg_elem)) { + /* Nothing to do here. Supported sg count + * is already set by controller/driver. */ + } + else if (softs->hint.sg_segments < BSD_MIN_SG_SEGMENTS) + { + /* Nothing to do here. Supported sg count + * is already set by controller/driver. */ + } + else { + /* Set Device.Hint sg count here */ + softs->pqi_cap.max_sg_elem = softs->hint.sg_segments; + } + + DBG_NOTE("SG segments before hint set = %u, SG segments after hint set = %u\n", + pqi_sg_segments, softs->pqi_cap.max_sg_elem); + + DBG_FUNC("OUT\n"); +} + +void +bsd_set_hint_adapter_cap(struct pqisrc_softstate *softs) +{ + DBG_FUNC("IN\n"); + + bsd_set_hint_adapter_queue_depth(softs); + bsd_set_hint_scatter_gather_config(softs); + + DBG_FUNC("OUT\n"); +} + +void +bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate *softs) +{ + DBG_FUNC("IN\n"); + + /* online cpu count decides the no.of queues the driver can create, + * and msi interrupt count as well. + * If the cpu count is "zero" set by hint file then the driver + * can have "one" queue and "one" legacy interrupt. (It shares event queue for + * operational IB queue). + * Check for os_get_intr_config function for interrupt assignment.*/ + + if (softs->hint.cpu_count > softs->num_cpus_online) { + /* Nothing to do here. Supported cpu count + * already fetched from hardware */ + } + else { + /* Set Device.Hint cpu count here */ + softs->num_cpus_online = softs->hint.cpu_count; + } + + DBG_FUNC("OUT\n"); +} diff --git a/sys/dev/smartpqi/smartpqi_prototypes.h b/sys/dev/smartpqi/smartpqi_prototypes.h --- a/sys/dev/smartpqi/smartpqi_prototypes.h +++ b/sys/dev/smartpqi/smartpqi_prototypes.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,15 +29,19 @@ /* Function prototypes */ -/*pqi_init.c */ +/*smartpqi_init.c */ int pqisrc_init(pqisrc_softstate_t *); void pqisrc_uninit(pqisrc_softstate_t *); void pqisrc_pqi_uninit(pqisrc_softstate_t *); int pqisrc_process_config_table(pqisrc_softstate_t *); int pqisrc_flush_cache(pqisrc_softstate_t *, enum pqisrc_flush_cache_event_type); int pqisrc_wait_for_pqi_reset_completion(pqisrc_softstate_t *); +int pqisrc_wait_for_cmnd_complete(pqisrc_softstate_t *); +void pqisrc_complete_internal_cmds(pqisrc_softstate_t *); +void sanity_check_os_behavior(pqisrc_softstate_t *); -/* pqi_sis.c*/ + +/* smartpqi_sis.c*/ int pqisrc_sis_init(pqisrc_softstate_t *); void pqisrc_sis_uninit(pqisrc_softstate_t *); int pqisrc_reenable_sis(pqisrc_softstate_t *); @@ -50,17 +54,21 @@ void sis_disable_interrupt(pqisrc_softstate_t*); -/* pqi_queue.c */ +/* smartpqi_queue.c */ int pqisrc_submit_admin_req(pqisrc_softstate_t *, gen_adm_req_iu_t *, gen_adm_resp_iu_t *); int pqisrc_create_admin_queue(pqisrc_softstate_t *); int pqisrc_destroy_admin_queue(pqisrc_softstate_t *); int pqisrc_create_op_queues(pqisrc_softstate_t *); +int pqisrc_allocate_and_init_inbound_q(pqisrc_softstate_t *, ib_queue_t *, + char *); +int pqisrc_allocate_and_init_outbound_q(pqisrc_softstate_t *, ob_queue_t *, + char *); -/* pqi_cmd.c */ +/* smartpqi_cmd.c */ int pqisrc_submit_cmnd(pqisrc_softstate_t *,ib_queue_t *,void *); -/* pqi_tag.c */ +/* smartpqi_tag.c */ #ifndef LOCKFREE_STACK int pqisrc_init_taglist(pqisrc_softstate_t *,pqi_taglist_t *,uint32_t); void pqisrc_destroy_taglist(pqisrc_softstate_t *,pqi_taglist_t *); @@ -73,26 +81,37 @@ uint32_t pqisrc_get_tag(lockless_stack_t *); #endif /* LOCKFREE_STACK */ -/* pqi_discovery.c */ +/* smartpqi_discovery.c */ void pqisrc_remove_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); +boolean_t pqisrc_add_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, + uint8_t *scsi3addr); int pqisrc_get_ctrl_fw_version(pqisrc_softstate_t *); int pqisrc_rescan_devices(pqisrc_softstate_t *); int pqisrc_scan_devices(pqisrc_softstate_t *); -void pqisrc_process_raid_path_io_response(pqisrc_softstate_t *, uint16_t, struct pqi_io_response *); -void pqisrc_process_io_error_response(pqisrc_softstate_t *, int, uint16_t, struct pqi_io_response *); void pqisrc_cleanup_devices(pqisrc_softstate_t *); void pqisrc_device_mem_free(pqisrc_softstate_t *, pqi_scsi_dev_t *); boolean_t pqisrc_is_external_raid_device(pqi_scsi_dev_t *device); void pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t *device); -void pqisrc_init_targetid_pool(pqisrc_softstate_t *softs); -int pqisrc_alloc_tid(pqisrc_softstate_t *softs); -void pqisrc_free_tid(pqisrc_softstate_t *softs, int); +void pqisrc_init_bitmap(pqisrc_softstate_t *softs); +void pqisrc_remove_target_bit(pqisrc_softstate_t *softs, int target); +int pqisrc_find_avail_target(pqisrc_softstate_t *softs); +int pqisrc_find_device_list_index(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device); +int pqisrc_find_btl_list_index(pqisrc_softstate_t *softs, + int bus, int target, int lun); +int pqisrc_delete_softs_entry(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device); int pqisrc_get_physical_logical_luns(pqisrc_softstate_t *softs, uint8_t cmd, - reportlun_data_ext_t **buff, size_t *data_length); + reportlun_data_ext_t **buff, size_t *data_length); int pqisrc_send_scsi_inquiry(pqisrc_softstate_t *softs, uint8_t *scsi3addr, uint16_t vpd_page, uint8_t *buff, int buf_len); +int pqisrc_simple_dma_alloc(pqisrc_softstate_t *, struct dma_mem *, size_t, + sgt_t *); +int pqisrc_prepare_send_raid(pqisrc_softstate_t *, pqisrc_raid_req_t *, + void *, size_t , uint8_t *, raid_path_error_info_elem_t *); + -/* pqi_helper.c */ +/* smartpqi_helper.c */ boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *); void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *); int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb, @@ -109,14 +128,13 @@ void pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *); void pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *, pqi_scsi_dev_t *); +int pqisrc_QuerySenseFeatures(pqisrc_softstate_t *); void check_device_pending_commands_to_complete(pqisrc_softstate_t *, pqi_scsi_dev_t *); uint32_t pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *, pqi_scsi_dev_t *); - -/* pqi_response.c */ -void pqisrc_signal_event(pqisrc_softstate_t *softs, rcb_t *rcb); +/* smartpqi_response.c */ void pqisrc_process_internal_raid_response_success(pqisrc_softstate_t *, rcb_t *); void pqisrc_process_internal_raid_response_error(pqisrc_softstate_t *, @@ -129,39 +147,73 @@ void pqisrc_process_raid_response_error(pqisrc_softstate_t *, rcb_t *, uint16_t); void pqisrc_process_response_queue(pqisrc_softstate_t *, int); - - - -/* pqi_request.c */ -int pqisrc_build_send_vendor_request(pqisrc_softstate_t*, - pqi_vendor_general_request_t *, - raid_path_error_info_elem_t *); +void pqisrc_show_aio_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, + aio_path_error_info_elem_t *aio_err); +void pqisrc_show_raid_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, + raid_path_error_info_elem_t *aio_err); +boolean_t suppress_innocuous_error_prints(pqisrc_softstate_t *softs, + rcb_t *rcb); +uint8_t pqisrc_get_cmd_from_rcb(rcb_t *); +boolean_t pqisrc_is_innocuous_error(pqisrc_softstate_t *, rcb_t *, void *); + + +/* smartpqi_request.c */ +int pqisrc_build_send_vendor_request(pqisrc_softstate_t *softs, + struct pqi_vendor_general_request *request); int pqisrc_build_send_io(pqisrc_softstate_t *,rcb_t *); - - -int pqisrc_send_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, - pqi_scsi_dev_t *device, rcb_t *rcb, uint8_t*); - - +int pqisrc_build_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device, rcb_t *rcb); int pqisrc_send_tmf(pqisrc_softstate_t *, pqi_scsi_dev_t *, rcb_t *, rcb_t *, int); int pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t *softs); int pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t *softs); +extern inline void pqisrc_aio_build_cdb(aio_req_locator_t *, uint32_t, + rcb_t *, uint8_t *); +extern inline boolean_t pqisrc_aio_req_too_big(pqisrc_softstate_t *, pqi_scsi_dev_t *, + rcb_t *, aio_req_locator_t *, uint32_t); +void pqisrc_build_aio_common(pqisrc_softstate_t *, pqi_aio_req_t *, + rcb_t *, uint32_t); +void pqisrc_build_aio_R1_write(pqisrc_softstate_t *, + pqi_aio_raid1_write_req_t *, rcb_t *, uint32_t); +void pqisrc_build_aio_R5or6_write(pqisrc_softstate_t *, + pqi_aio_raid5or6_write_req_t *, rcb_t *, uint32_t); +void pqisrc_show_cdb(pqisrc_softstate_t *softs, char *msg, rcb_t *rcb, uint8_t *cdb); void pqisrc_print_buffer(pqisrc_softstate_t *softs, char *msg, void *user_buf, uint32_t total_len, uint32_t flags); +void pqisrc_show_rcb_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg, void *err_info); +void pqisrc_show_aio_io(pqisrc_softstate_t *, rcb_t *, + pqi_aio_req_t *, uint32_t); +void pqisrc_show_aio_common(pqisrc_softstate_t *, rcb_t *, pqi_aio_req_t *); +void pqisrc_show_aio_R1_write(pqisrc_softstate_t *, rcb_t *, + pqi_aio_raid1_write_req_t *); +void pqisrc_show_aio_R5or6_write(pqisrc_softstate_t *, rcb_t *, + pqi_aio_raid5or6_write_req_t *); +boolean_t pqisrc_cdb_is_write(uint8_t *); +void print_this_counter(pqisrc_softstate_t *softs, io_counters_t *pcounter, char *msg); +void print_all_counters(pqisrc_softstate_t *softs, uint32_t flags); char *io_path_to_ascii(IO_PATH_T path); +void int_to_scsilun(uint64_t, uint8_t *); +boolean_t pqisrc_cdb_is_read(uint8_t *); +void pqisrc_build_aio_io(pqisrc_softstate_t *, rcb_t *, pqi_aio_req_t *, uint32_t); +uint8_t pqisrc_get_aio_data_direction(rcb_t *); +uint8_t pqisrc_get_raid_data_direction(rcb_t *); +void dump_tmf_details(pqisrc_softstate_t *, rcb_t *, char *); +io_type_t get_io_type_from_cdb(uint8_t *); +OS_ATOMIC64_T increment_this_counter(io_counters_t *, IO_PATH_T , io_type_t ); +boolean_t +is_buffer_zero(void *, uint32_t ); + + -/* pqi_event.c*/ + +/* smartpqi_event.c*/ int pqisrc_report_event_config(pqisrc_softstate_t *); int pqisrc_set_event_config(pqisrc_softstate_t *); int pqisrc_process_event_intr_src(pqisrc_softstate_t *,int); void pqisrc_ack_all_events(void *arg); void pqisrc_wait_for_rescan_complete(pqisrc_softstate_t *softs); -boolean_t pqisrc_update_scsi_sense(const uint8_t *, int, - struct sense_header_scsi *); -int pqisrc_build_send_raid_request(pqisrc_softstate_t *, pqisrc_raid_req_t *, - void *, size_t, uint8_t, uint16_t, uint8_t *, - raid_path_error_info_elem_t *); +int pqisrc_prepare_send_ctrlr_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, + void *buff, size_t datasize); int pqisrc_submit_management_req(pqisrc_softstate_t *, pqi_event_config_request_t *); @@ -185,102 +237,86 @@ int pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *); int pqisrc_create_delete_adminq(pqisrc_softstate_t *, uint32_t); void pqisrc_print_adminq_config(pqisrc_softstate_t *); -int pqisrc_delete_op_queue(pqisrc_softstate_t *, - uint32_t, boolean_t); +int pqisrc_delete_op_queue(pqisrc_softstate_t *, uint32_t, boolean_t); void pqisrc_destroy_event_queue(pqisrc_softstate_t *); - void pqisrc_destroy_op_ib_queues(pqisrc_softstate_t *); - void pqisrc_destroy_op_ob_queues(pqisrc_softstate_t *); - -int pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t *, - ib_queue_t *, uint32_t); -int pqisrc_create_op_obq(pqisrc_softstate_t *, - ob_queue_t *); -int pqisrc_create_op_ibq(pqisrc_softstate_t *, - ib_queue_t *); +int pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t *, ib_queue_t *, + uint32_t); +int pqisrc_create_op_obq(pqisrc_softstate_t *, ob_queue_t *); +int pqisrc_create_op_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_create_op_aio_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_create_op_raid_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t *); int pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *); +int pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *); int pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t *); int pqisrc_process_task_management_response(pqisrc_softstate_t *, pqi_tmf_resp_t *); -/*Device outstanding Io count*/ -uint64_t pqisrc_increment_device_active_io(pqisrc_softstate_t *, - pqi_scsi_dev_t *); -uint64_t pqisrc_decrement_device_active_io(pqisrc_softstate_t *, - pqi_scsi_dev_t *); -void pqisrc_init_device_active_io(pqisrc_softstate_t *, - pqi_scsi_dev_t *); -uint64_t pqisrc_read_device_active_io(pqisrc_softstate_t *, - pqi_scsi_dev_t *); - -/* pqi_ioctl.c*/ - -int -pqisrc_passthru_ioctl(struct pqisrc_softstate *, void *, int); - - +/* smartpqi_ioctl.c*/ +int pqisrc_passthru_ioctl(struct pqisrc_softstate *, void *, int); /* Functions Prototypes */ -/* FreeBSD_mem.c */ +/* smartpqi_mem.c */ int os_dma_mem_alloc(pqisrc_softstate_t *,struct dma_mem *); void os_dma_mem_free(pqisrc_softstate_t *,struct dma_mem *); void *os_mem_alloc(pqisrc_softstate_t *,size_t); -void os_mem_free(pqisrc_softstate_t *,char *,size_t); +void os_mem_free(pqisrc_softstate_t *,void *,size_t); void os_resource_free(pqisrc_softstate_t *); int os_dma_setup(pqisrc_softstate_t *); int os_dma_destroy(pqisrc_softstate_t *); void os_update_dma_attributes(pqisrc_softstate_t *); -/* FreeBSD intr.c */ +/* smartpqi_intr.c */ int os_get_intr_config(pqisrc_softstate_t *); int os_setup_intr(pqisrc_softstate_t *); int os_destroy_intr(pqisrc_softstate_t *); int os_get_processor_config(pqisrc_softstate_t *); void os_free_intr_config(pqisrc_softstate_t *); -/* FreeBSD_ioctl.c */ +/* smartpqi_ioctl.c */ int os_copy_to_user(struct pqisrc_softstate *, void *, void *, int, int); int os_copy_from_user(struct pqisrc_softstate *, void *, void *, int, int); int create_char_dev(struct pqisrc_softstate *, int); void destroy_char_dev(struct pqisrc_softstate *); - -/* FreeBSD_misc.c*/ + +/* smartpqi_misc.c*/ int os_init_spinlock(struct pqisrc_softstate *, struct mtx *, char *); void os_uninit_spinlock(struct mtx *); int os_create_semaphore(const char *, int,struct sema *); int os_destroy_semaphore(struct sema *); void os_sema_lock(struct sema *); void os_sema_unlock(struct sema *); +void bsd_set_hint_adapter_cap(struct pqisrc_softstate *); +void bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate *); int os_strlcpy(char *dst, char *src, int len); void os_complete_outstanding_cmds_nodevice(pqisrc_softstate_t *); void os_stop_heartbeat_timer(pqisrc_softstate_t *); void os_start_heartbeat_timer(void *); -/* FreeBSD_cam.c */ +/* smartpqi_cam.c */ uint8_t os_get_task_attr(rcb_t *); void smartpqi_target_rescan(struct pqisrc_softstate *); void os_rescan_target(struct pqisrc_softstate *, pqi_scsi_dev_t *); -/* FreeBSD_intr.c FreeBSD_main.c */ +/* smartpqi_intr.c smartpqi_main.c */ void pqisrc_event_worker(void *, int); void os_add_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); -void os_remove_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); +void os_remove_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); void os_io_response_success(rcb_t *); void os_aio_response_error(rcb_t *, aio_path_error_info_elem_t *); +boolean_t check_device_hint_status(struct pqisrc_softstate *, unsigned int ); void smartpqi_adjust_queue_depth(struct cam_path *, uint32_t ); void os_raid_response_error(rcb_t *, raid_path_error_info_elem_t *); void os_wellness_periodic(void *); void os_reset_rcb( rcb_t *); int register_sim(struct pqisrc_softstate *, int); void deregister_sim(struct pqisrc_softstate *); -int check_for_scsi_opcode(uint8_t *, boolean_t *, uint64_t *, +int check_for_scsi_opcode(uint8_t *, boolean_t *, uint64_t *, uint32_t *); int register_legacy_intr(pqisrc_softstate_t *); int register_msix_intr(pqisrc_softstate_t *); @@ -292,5 +328,4 @@ /* Domain status conversion */ int bsd_status_to_pqi_status(int ); - -#endif // _SMARTPQI_PROTOTYPES_H +#endif diff --git a/sys/dev/smartpqi/smartpqi_queue.c b/sys/dev/smartpqi/smartpqi_queue.c --- a/sys/dev/smartpqi/smartpqi_queue.c +++ b/sys/dev/smartpqi/smartpqi_queue.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,7 @@ /* * Submit an admin IU to the adapter. + * TODO : Admin command implemented using polling, * Add interrupt support, if required */ int @@ -120,10 +121,10 @@ softs->admin_ib_queue.elem_size = ((val & 0xFF0000) >> 16) * 16; softs->admin_ob_queue.elem_size = ((val & 0xFF000000) >> 24) * 16; - DBG_FUNC(" softs->admin_ib_queue.num_elem : %d\n", - softs->admin_ib_queue.num_elem); - DBG_FUNC(" softs->admin_ib_queue.elem_size : %d\n", - softs->admin_ib_queue.elem_size); + DBG_INIT(" admin ib: num_elem=%u elem_size=%u\n", + softs->admin_ib_queue.num_elem, softs->admin_ib_queue.elem_size); + DBG_INIT(" admin ob: num_elem=%u elem_size=%u\n", + softs->admin_ob_queue.num_elem, softs->admin_ob_queue.elem_size); } /* @@ -142,79 +143,136 @@ } /* - * Allocate DMA memory for admin queue and initialize. + * Allocate DMA memory for inbound queue and initialize. */ int -pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *softs) +pqisrc_allocate_and_init_inbound_q(pqisrc_softstate_t *softs, ib_queue_t *ib_q, char *tag) { + struct dma_mem *dma_mem = &ib_q->alloc_dma; uint32_t ib_array_size = 0; - uint32_t ob_array_size = 0; uint32_t alloc_size = 0; char *virt_addr = NULL; dma_addr_t dma_addr = 0; int ret = PQI_STATUS_SUCCESS; - ib_array_size = (softs->admin_ib_queue.num_elem * - softs->admin_ib_queue.elem_size); + ib_array_size = ib_q->num_elem * ib_q->elem_size; + ASSERT(ib_array_size > 0); - ob_array_size = (softs->admin_ob_queue.num_elem * - softs->admin_ob_queue.elem_size); + alloc_size = ib_array_size + PQI_CI_PI_ALIGN + PQI_ADDR_ALIGN; /* for IB CI and OB PI */ - alloc_size = ib_array_size + ob_array_size + - 2 * sizeof(uint32_t) + PQI_ADDR_ALIGN_MASK_64 + 1; /* for IB CI and OB PI */ - /* Allocate memory for Admin Q */ - softs->admin_queue_dma_mem.tag = "admin_queue"; - softs->admin_queue_dma_mem.size = alloc_size; - softs->admin_queue_dma_mem.align = PQI_ADMINQ_ELEM_ARRAY_ALIGN; - ret = os_dma_mem_alloc(softs, &softs->admin_queue_dma_mem); + /* Allocate memory for the Q */ + memset(dma_mem, 0, sizeof(*dma_mem)); + os_strlcpy(dma_mem->tag, tag, sizeof(dma_mem->tag)); + dma_mem->size = alloc_size; + dma_mem->align = PQI_ADDR_ALIGN; + ret = os_dma_mem_alloc(softs, &ib_q->alloc_dma); if (ret) { - DBG_ERR("Failed to Allocate Admin Q ret : %d\n", ret); + DBG_ERR("Failed to Allocate Q tag=%s ret=%d\n", dma_mem->tag, ret); goto err_out; } + DBG_INIT("alloc tag=%s size=0x%x align=0x%x virt_addr=%p dma_addr=%p\n", + dma_mem->tag, dma_mem->size, dma_mem->align, dma_mem->virt_addr, (void*)dma_mem->dma_addr); + /* Setup the address */ - virt_addr = softs->admin_queue_dma_mem.virt_addr; - dma_addr = softs->admin_queue_dma_mem.dma_addr; + virt_addr = dma_mem->virt_addr; + dma_addr = dma_mem->dma_addr; + ASSERT(!((uint64_t)virt_addr & PQI_ADDR_ALIGN_MASK)); + ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK)); /* IB */ - softs->admin_ib_queue.q_id = 0; - softs->admin_ib_queue.array_virt_addr = virt_addr; - softs->admin_ib_queue.array_dma_addr = dma_addr; - softs->admin_ib_queue.pi_local = 0; - /* OB */ - softs->admin_ob_queue.q_id = 0; - softs->admin_ob_queue.array_virt_addr = virt_addr + ib_array_size; - softs->admin_ob_queue.array_dma_addr = dma_addr + ib_array_size; - softs->admin_ob_queue.ci_local = 0; + ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK)); + ib_q->array_virt_addr = virt_addr; + ib_q->array_dma_addr = dma_addr; + ib_q->pi_local = 0; + + /* update addr for the next user */ + virt_addr += ib_array_size; + dma_addr += ib_array_size; /* IB CI */ - softs->admin_ib_queue.ci_virt_addr = - (uint32_t*)((uint8_t*)softs->admin_ob_queue.array_virt_addr - + ob_array_size); - softs->admin_ib_queue.ci_dma_addr = - (dma_addr_t)((uint8_t*)softs->admin_ob_queue.array_dma_addr + - ob_array_size); + ASSERT(!(dma_addr & PQI_CI_PI_ALIGN_MASK)); + ib_q->ci_virt_addr = (uint32_t*)virt_addr; + ib_q->ci_dma_addr = dma_addr; + + /* update addr for the next user */ + virt_addr += PQI_CI_PI_ALIGN; + + DBG_INIT("ib_q: virt_addr=%p, ci_dma_addr=%p elem=%u size=%u\n", + ib_q->array_virt_addr, (void*)ib_q->ci_dma_addr, ib_q->num_elem, ib_array_size); + + /* Verify we aren't out of bounds from allocation */ + ASSERT(virt_addr <= ((char*)dma_mem->virt_addr + alloc_size)); + + DBG_FUNC("OUT\n"); + return ret; + +err_out: + DBG_FUNC("failed OUT\n"); + return PQI_STATUS_FAILURE; +} + + +/* + * Allocate DMA memory for outbound queue and initialize. + */ +int +pqisrc_allocate_and_init_outbound_q(pqisrc_softstate_t *softs, ob_queue_t *ob_q, + char *tag) +{ + struct dma_mem *dma_mem = &ob_q->alloc_dma; + uint32_t ob_array_size = 0; + uint32_t alloc_size = 0; + char *virt_addr = NULL; + dma_addr_t dma_addr = 0; + int ret = PQI_STATUS_SUCCESS; + + ob_array_size = ob_q->num_elem * ob_q->elem_size; + ASSERT(ob_array_size > 0); + + alloc_size = ob_array_size + PQI_CI_PI_ALIGN + PQI_ADDR_ALIGN; /* for OB PI */ + + /* Allocate memory for the Q */ + memset(dma_mem, 0, sizeof(*dma_mem)); + os_strlcpy(dma_mem->tag, tag, sizeof(dma_mem->tag)); + dma_mem->size = alloc_size; + dma_mem->align = PQI_ADDR_ALIGN; + ret = os_dma_mem_alloc(softs, &ob_q->alloc_dma); + if (ret) { + DBG_ERR("Failed to Allocate Q tag=%s ret=%d\n", dma_mem->tag, ret); + goto err_out; + } + + DBG_INIT("alloc tag=%s size=0x%x align=0x%x virt_addr=%p dma_addr=%p\n", + dma_mem->tag, dma_mem->size, dma_mem->align, dma_mem->virt_addr, (void*)dma_mem->dma_addr); + + /* Setup the address */ + virt_addr = dma_mem->virt_addr; + dma_addr = dma_mem->dma_addr; + ASSERT(!((uint64_t)virt_addr & PQI_ADDR_ALIGN_MASK)); + ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK)); + + ob_q->array_virt_addr = virt_addr; + ob_q->array_dma_addr = dma_addr; + ob_q->ci_local = 0; + + /* update addr for the next user */ + virt_addr += ob_array_size; + dma_addr += ob_array_size; /* OB PI */ - softs->admin_ob_queue.pi_virt_addr = - (uint32_t*)((uint8_t*)(softs->admin_ib_queue.ci_virt_addr) + - PQI_ADDR_ALIGN_MASK_64 + 1); - softs->admin_ob_queue.pi_dma_addr = - (dma_addr_t)((uint8_t*)(softs->admin_ib_queue.ci_dma_addr) + - PQI_ADDR_ALIGN_MASK_64 + 1); - - DBG_INIT("softs->admin_ib_queue.ci_dma_addr : %p,softs->admin_ob_queue.pi_dma_addr :%p\n", - (void*)softs->admin_ib_queue.ci_dma_addr, (void*)softs->admin_ob_queue.pi_dma_addr ); - - /* Verify alignment */ - ASSERT(!(softs->admin_ib_queue.array_dma_addr & - PQI_ADDR_ALIGN_MASK_64)); - ASSERT(!(softs->admin_ib_queue.ci_dma_addr & - PQI_ADDR_ALIGN_MASK_64)); - ASSERT(!(softs->admin_ob_queue.array_dma_addr & - PQI_ADDR_ALIGN_MASK_64)); - ASSERT(!(softs->admin_ob_queue.pi_dma_addr & - PQI_ADDR_ALIGN_MASK_64)); + ASSERT(!(dma_addr & PQI_CI_PI_ALIGN_MASK)); + ob_q->pi_virt_addr = (uint32_t*)virt_addr; + ob_q->pi_dma_addr = dma_addr; + + /* update addr to show the end next user */ + virt_addr += PQI_CI_PI_ALIGN; + + DBG_INIT("ob_q: virt_addr=%p, pi_dma_addr=%p elem=%u size=%u\n", + ob_q->array_virt_addr, (void*)ob_q->pi_dma_addr, ob_q->num_elem, ob_array_size); + + /* Verify we aren't out of bounds from allocation */ + ASSERT(virt_addr <= ((char*)dma_mem->virt_addr + alloc_size)); DBG_FUNC("OUT\n"); return ret; @@ -224,6 +282,36 @@ return PQI_STATUS_FAILURE; } +/* + * Allocate DMA memory for admin queue and initialize. + */ +int pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *softs) +{ + int ret; + ib_queue_t *admin_ib_q = &softs->admin_ib_queue; + ob_queue_t *admin_ob_q = &softs->admin_ob_queue; + + ret = pqisrc_allocate_and_init_inbound_q(softs, admin_ib_q, "admin_queue"); + if (!ret) { + admin_ib_q->q_id = PQI_ADMIN_IB_QUEUE_ID; + ret = pqisrc_allocate_and_init_outbound_q(softs, admin_ob_q, "admin_queue"); + if(!ret) + admin_ob_q->q_id = PQI_ADMIN_OB_QUEUE_ID; + else { + if(softs->admin_ib_queue.lockcreated==true) { + OS_UNINIT_PQILOCK(&softs->admin_ib_queue.lock); + softs->admin_ib_queue.lockcreated = false; + } + if (softs->admin_ib_queue.alloc_dma.virt_addr) + os_dma_mem_free(softs, &softs->admin_ib_queue.alloc_dma); + } + } + else + DBG_ERR("Failed to create Admin Queue pair\n"); + + return ret; +} + /* * Subroutine used to create (or) delete the admin queue requested. */ @@ -264,17 +352,17 @@ (void*)softs->admin_ib_queue.array_dma_addr); DBG_INFO(" softs->admin_ib_queue.array_virt_addr : %p\n", (void*)softs->admin_ib_queue.array_virt_addr); - DBG_INFO(" softs->admin_ib_queue.num_elem : %d\n", + DBG_INFO(" softs->admin_ib_queue.num_elem : %u\n", softs->admin_ib_queue.num_elem); - DBG_INFO(" softs->admin_ib_queue.elem_size : %d\n", + DBG_INFO(" softs->admin_ib_queue.elem_size : %u\n", softs->admin_ib_queue.elem_size); DBG_INFO(" softs->admin_ob_queue.array_dma_addr : %p\n", (void*)softs->admin_ob_queue.array_dma_addr); DBG_INFO(" softs->admin_ob_queue.array_virt_addr : %p\n", (void*)softs->admin_ob_queue.array_virt_addr); - DBG_INFO(" softs->admin_ob_queue.num_elem : %d\n", + DBG_INFO(" softs->admin_ob_queue.num_elem : %u\n", softs->admin_ob_queue.num_elem); - DBG_INFO(" softs->admin_ob_queue.elem_size : %d\n", + DBG_INFO(" softs->admin_ob_queue.elem_size : %u\n", softs->admin_ob_queue.elem_size); DBG_INFO(" softs->admin_ib_queue.pi_register_abs : %p\n", (void*)softs->admin_ib_queue.pi_register_abs); @@ -289,6 +377,7 @@ pqisrc_create_admin_queue(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; +/* struct pqi_dev_adminq_cap *pqi_cap; */ uint32_t admin_q_param = 0; DBG_FUNC("IN\n"); @@ -371,8 +460,11 @@ return ret; err_lock: +#if 0 + pqisrc_create_delete_adminq(softs, PQI_ADMIN_QUEUE_CONF_FUNC_DEL_Q_PAIR); +#endif err_q_create: - os_dma_mem_free(softs, &softs->admin_queue_dma_mem); + pqisrc_destroy_admin_queue(softs); err_out: DBG_FUNC("failed OUT\n"); return ret; @@ -425,13 +517,14 @@ int ret = PQI_STATUS_SUCCESS; ret = pqisrc_delete_op_queue(softs, softs->event_q.q_id, false); if (ret) { - DBG_ERR("Failed to Delete Event Q %d\n", softs->event_q.q_id); + DBG_ERR("Failed to Delete Event Q %u\n", softs->event_q.q_id); } softs->event_q.created = false; } /* Free the memory */ - os_dma_mem_free(softs, &softs->event_q_dma_mem); + if (softs->event_q.alloc_dma.virt_addr) + os_dma_mem_free(softs, &softs->event_q.alloc_dma); DBG_FUNC("OUT\n"); } @@ -444,44 +537,42 @@ { int ret = PQI_STATUS_SUCCESS; ib_queue_t *op_ib_q = NULL; + uint32_t total_op_ibq = softs->num_op_raid_ibq; int i; DBG_FUNC("IN\n"); - for (i = 0; i < softs->num_op_raid_ibq; i++) { - /* OP RAID IB Q */ + for (i = 0; i < total_op_ibq; i++) { + int repeat = 0; + /* RAID first */ op_ib_q = &softs->op_raid_ib_q[i]; +release_queue: if (op_ib_q->created == true) { - ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id, true); + ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id, + true); if (ret) { - DBG_ERR("Failed to Delete Raid IB Q %d\n",op_ib_q->q_id); + DBG_ERR("Failed to Delete IB Q %u\n", + op_ib_q->q_id); } op_ib_q->created = false; } - if(op_ib_q->lockcreated==true){ - OS_UNINIT_PQILOCK(&op_ib_q->lock); - op_ib_q->lockcreated = false; - } - - /* OP AIO IB Q */ - op_ib_q = &softs->op_aio_ib_q[i]; - if (op_ib_q->created == true) { - ret = pqisrc_delete_op_queue(softs, op_ib_q->q_id, true); - if (ret) { - DBG_ERR("Failed to Delete AIO IB Q %d\n",op_ib_q->q_id); - } - op_ib_q->created = false; + if (op_ib_q->lockcreated == true) { + OS_UNINIT_PQILOCK(&op_ib_q->lock); + op_ib_q->lockcreated = false; } - if(op_ib_q->lockcreated==true){ - OS_UNINIT_PQILOCK(&op_ib_q->lock); - op_ib_q->lockcreated = false; - } + /* Free the memory */ + if (op_ib_q->alloc_dma.virt_addr) + os_dma_mem_free(softs, &op_ib_q->alloc_dma); + + if (repeat < 1) { + repeat++; + op_ib_q = &softs->op_aio_ib_q[i]; + goto release_queue; + } } - /* Free the memory */ - os_dma_mem_free(softs, &softs->op_ibq_dma_mem); DBG_FUNC("OUT\n"); } @@ -493,23 +584,27 @@ { int ret = PQI_STATUS_SUCCESS; int i; + ob_queue_t *op_ob_q = NULL; DBG_FUNC("IN\n"); for (i = 0; i < softs->num_op_obq; i++) { - ob_queue_t *op_ob_q = NULL; op_ob_q = &softs->op_ob_q[i]; + if (op_ob_q->created == true) { ret = pqisrc_delete_op_queue(softs, op_ob_q->q_id, false); if (ret) { - DBG_ERR("Failed to Delete OB Q %d\n",op_ob_q->q_id); + DBG_ERR("Failed to Delete OB Q %u\n",op_ob_q->q_id); } op_ob_q->created = false; } + + /* Free the memory */ + if (op_ob_q->alloc_dma.virt_addr) + os_dma_mem_free(softs, &op_ob_q->alloc_dma); } /* Free the memory */ - os_dma_mem_free(softs, &softs->op_obq_dma_mem); DBG_FUNC("OUT\n"); } @@ -522,11 +617,22 @@ int ret = PQI_STATUS_SUCCESS; DBG_FUNC("IN\n"); + + if(softs->admin_ib_queue.lockcreated==true) { + OS_UNINIT_PQILOCK(&softs->admin_ib_queue.lock); + softs->admin_ib_queue.lockcreated = false; + } + #if 0 ret = pqisrc_create_delete_adminq(softs, PQI_ADMIN_QUEUE_CONF_FUNC_DEL_Q_PAIR); #endif - os_dma_mem_free(softs, &softs->admin_queue_dma_mem); + + if (softs->admin_ib_queue.alloc_dma.virt_addr) + os_dma_mem_free(softs, &softs->admin_ib_queue.alloc_dma); + + if (softs->admin_ob_queue.alloc_dma.virt_addr) + os_dma_mem_free(softs, &softs->admin_ob_queue.alloc_dma); DBG_FUNC("OUT\n"); return ret; @@ -689,15 +795,8 @@ pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; - uint32_t alloc_size = 0; uint32_t num_elem; - char *virt_addr = NULL; - dma_addr_t dma_addr = 0; - uint64_t event_q_pi_dma_start_offset = 0; - uint32_t event_q_pi_virt_start_offset = 0; - char *event_q_pi_virt_start_addr = NULL; - ob_queue_t *event_q = NULL; - + ob_queue_t *event_q = &softs->event_q; DBG_FUNC("IN\n"); @@ -710,47 +809,26 @@ * for queue size calculation. */ #ifdef SHARE_EVENT_QUEUE_FOR_IO - num_elem = MIN(softs->num_elem_per_op_obq, PQISRC_NUM_EVENT_Q_ELEM); + num_elem = MIN(softs->num_elem_per_op_obq, PQISRC_MAX_EVENT_QUEUE_ELEM_NUM); #else - num_elem = PQISRC_NUM_EVENT_Q_ELEM; + num_elem = PQISRC_MAX_EVENT_QUEUE_ELEM_NUM; #endif - alloc_size = num_elem * PQISRC_EVENT_Q_ELEM_SIZE; - event_q_pi_dma_start_offset = alloc_size; - event_q_pi_virt_start_offset = alloc_size; - alloc_size += sizeof(uint32_t); /*For IBQ CI*/ + event_q->num_elem = num_elem; + event_q->elem_size = PQISRC_EVENT_Q_ELEM_SIZE_BYTES; + + ret = pqisrc_allocate_and_init_outbound_q(softs, event_q, "event_queue"); - /* Allocate memory for event queues */ - softs->event_q_dma_mem.tag = "event_queue"; - softs->event_q_dma_mem.size = alloc_size; - softs->event_q_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN; - ret = os_dma_mem_alloc(softs, &softs->event_q_dma_mem); if (ret) { - DBG_ERR("Failed to Allocate Event Q ret : %d\n" - , ret); + DBG_ERR("Failed to Allocate EventQ\n"); goto err_out; } - - /* Set up the address */ - virt_addr = softs->event_q_dma_mem.virt_addr; - dma_addr = softs->event_q_dma_mem.dma_addr; - event_q_pi_dma_start_offset += dma_addr; - event_q_pi_virt_start_addr = virt_addr + event_q_pi_virt_start_offset; - - event_q = &softs->event_q; - ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64)); - FILL_QUEUE_ARRAY_ADDR(event_q,virt_addr,dma_addr); event_q->q_id = PQI_OP_EVENT_QUEUE_ID; - event_q->num_elem = num_elem; - event_q->elem_size = PQISRC_EVENT_Q_ELEM_SIZE; - event_q->pi_dma_addr = event_q_pi_dma_start_offset; - event_q->pi_virt_addr = (uint32_t *)event_q_pi_virt_start_addr; event_q->intr_msg_num = 0; /* vector zero for event */ - ASSERT(!(event_q->pi_dma_addr & PQI_ADDR_ALIGN_MASK_4)); ret = pqisrc_create_op_obq(softs,event_q); if (ret) { - DBG_ERR("Failed to Create EventQ %d\n",event_q->q_id); + DBG_ERR("Failed to Create EventQ %u\n",event_q->q_id); goto err_out_create; } event_q->created = true; @@ -772,115 +850,62 @@ pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; - uint32_t alloc_size = 0; - char *virt_addr = NULL; - dma_addr_t dma_addr = 0; - uint32_t ibq_size = 0; - uint64_t ib_ci_dma_start_offset = 0; - char *ib_ci_virt_start_addr = NULL; - uint32_t ib_ci_virt_start_offset = 0; - uint32_t ibq_id = PQI_MIN_OP_IB_QUEUE_ID; ib_queue_t *op_ib_q = NULL; - uint32_t num_op_ibq = softs->num_op_raid_ibq + - softs->num_op_aio_ibq; + uint32_t ibq_id = PQI_MIN_OP_IB_QUEUE_ID; + uint32_t total_op_ibq = softs->num_op_raid_ibq + softs->num_op_aio_ibq; int i = 0; + char *string = NULL; DBG_FUNC("IN\n"); - /* Calculate memory requirements */ - ibq_size = softs->num_elem_per_op_ibq * softs->ibq_elem_size; - alloc_size = num_op_ibq * ibq_size; - /* CI indexes starts after Queue element array */ - ib_ci_dma_start_offset = alloc_size; - ib_ci_virt_start_offset = alloc_size; - alloc_size += num_op_ibq * sizeof(uint32_t); /*For IBQ CI*/ - - /* Allocate memory for IB queues */ - softs->op_ibq_dma_mem.tag = "op_ib_queue"; - softs->op_ibq_dma_mem.size = alloc_size; - softs->op_ibq_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN; - ret = os_dma_mem_alloc(softs, &softs->op_ibq_dma_mem); - if (ret) { - DBG_ERR("Failed to Allocate Operational IBQ memory ret : %d\n", - ret); - goto err_out; - } - - /* Set up the address */ - virt_addr = softs->op_ibq_dma_mem.virt_addr; - dma_addr = softs->op_ibq_dma_mem.dma_addr; - ib_ci_dma_start_offset += dma_addr; - ib_ci_virt_start_addr = virt_addr + ib_ci_virt_start_offset; - ASSERT(softs->num_op_raid_ibq == softs->num_op_aio_ibq); - for (i = 0; i < softs->num_op_raid_ibq; i++) { - /* OP RAID IB Q */ - op_ib_q = &softs->op_raid_ib_q[i]; - ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64)); - FILL_QUEUE_ARRAY_ADDR(op_ib_q,virt_addr,dma_addr); - op_ib_q->q_id = ibq_id++; + for (i = 0; i < total_op_ibq; i++) { - snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "raid_ibqlock%d", i); - ret = OS_INIT_PQILOCK(softs, &op_ib_q->lock, op_ib_q->lockname); - if(ret){ - /* TODO: error handling */ - DBG_ERR("raid_ibqlock %d init failed\n", i); - op_ib_q->lockcreated = false; - goto err_lock; + /* OP RAID IB Q */ + if (i % 2 == 0) + { + op_ib_q = &softs->op_raid_ib_q[i/2]; + string = "raid"; + } + else + { + op_ib_q = &softs->op_aio_ib_q[i/2]; + string = "aio"; } - op_ib_q->lockcreated = true; + /* Allocate memory for IB queues */ op_ib_q->num_elem = softs->num_elem_per_op_ibq; - op_ib_q->elem_size = softs->ibq_elem_size; - op_ib_q->ci_dma_addr = ib_ci_dma_start_offset + - (2 * i * sizeof(uint32_t)); - op_ib_q->ci_virt_addr = (uint32_t*)(ib_ci_virt_start_addr + - (2 * i * sizeof(uint32_t))); - ASSERT(!(op_ib_q->ci_dma_addr & PQI_ADDR_ALIGN_MASK_4)); - - ret = pqisrc_create_op_raid_ibq(softs, op_ib_q); + op_ib_q->elem_size = softs->max_ibq_elem_size; + + ret = pqisrc_allocate_and_init_inbound_q(softs, op_ib_q, "op_ib_queue"); if (ret) { - DBG_ERR("[ %s ] Failed to Create OP Raid IBQ %d\n", - __func__, op_ib_q->q_id); - goto err_out_create; + DBG_ERR("Failed to Allocate Operational IBQ memory ret : %d\n", + ret); + goto err_out; } - op_ib_q->created = true; - - /* OP AIO IB Q */ - virt_addr += ibq_size; - dma_addr += ibq_size; - op_ib_q = &softs->op_aio_ib_q[i]; - ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64)); - FILL_QUEUE_ARRAY_ADDR(op_ib_q,virt_addr,dma_addr); op_ib_q->q_id = ibq_id++; - snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "aio_ibqlock%d", i); + + snprintf(op_ib_q->lockname, LOCKNAME_SIZE, "%s_ibqlock_%d", string, i); ret = OS_INIT_PQILOCK(softs, &op_ib_q->lock, op_ib_q->lockname); - if(ret){ - /* TODO: error handling */ - DBG_ERR("aio_ibqlock %d init failed\n", i); - op_ib_q->lockcreated = false; - goto err_lock; - } - op_ib_q->lockcreated = true; + if(ret){ + /* TODO: error handling */ + DBG_ERR("%s %d init failed\n", string, i); + op_ib_q->lockcreated = false; + goto err_lock; + } + op_ib_q->lockcreated = true; - op_ib_q->num_elem = softs->num_elem_per_op_ibq; - op_ib_q->elem_size = softs->ibq_elem_size; - op_ib_q->ci_dma_addr = ib_ci_dma_start_offset + - (((2 * i) + 1) * sizeof(uint32_t)); - op_ib_q->ci_virt_addr = (uint32_t*)(ib_ci_virt_start_addr + - (((2 * i) + 1) * sizeof(uint32_t))); - ASSERT(!(op_ib_q->ci_dma_addr & PQI_ADDR_ALIGN_MASK_4)); - - ret = pqisrc_create_op_aio_ibq(softs, op_ib_q); + if (i % 2 == 0) + ret = pqisrc_create_op_raid_ibq(softs, op_ib_q); + else + ret = pqisrc_create_op_aio_ibq(softs, op_ib_q); if (ret) { - DBG_ERR("Failed to Create OP AIO IBQ %d\n",op_ib_q->q_id); + DBG_ERR("Failed to Create OP IBQ type=%s id=%u\n", + string, op_ib_q->q_id); goto err_out_create; } op_ib_q->created = true; - - virt_addr += ibq_size; - dma_addr += ibq_size; } DBG_FUNC("OUT\n"); @@ -888,8 +913,8 @@ err_lock: err_out_create: - pqisrc_destroy_op_ib_queues(softs); err_out: + pqisrc_destroy_op_ib_queues(softs); DBG_FUNC("OUT failed %d\n", ret); return PQI_STATUS_FAILURE; } @@ -901,16 +926,8 @@ pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t *softs) { int ret = PQI_STATUS_SUCCESS; - uint32_t alloc_size = 0; - char *virt_addr = NULL; - dma_addr_t dma_addr = 0; - uint32_t obq_size = 0; - uint64_t ob_pi_dma_start_offset = 0; - uint32_t ob_pi_virt_start_offset = 0; - char *ob_pi_virt_start_addr = NULL; uint32_t obq_id = PQI_MIN_OP_OB_QUEUE_ID; ob_queue_t *op_ob_q = NULL; - uint32_t num_op_obq = softs->num_op_obq; int i = 0; DBG_FUNC("IN\n"); @@ -923,65 +940,41 @@ */ ALIGN_BOUNDARY(softs->num_elem_per_op_obq, 4); - obq_size = softs->num_elem_per_op_obq * softs->obq_elem_size; - alloc_size += num_op_obq * obq_size; - /* PI indexes starts after Queue element array */ - ob_pi_dma_start_offset = alloc_size; - ob_pi_virt_start_offset = alloc_size; - alloc_size += num_op_obq * sizeof(uint32_t); /*For OBQ PI*/ - - /* Allocate memory for OB queues */ - softs->op_obq_dma_mem.tag = "op_ob_queue"; - softs->op_obq_dma_mem.size = alloc_size; - softs->op_obq_dma_mem.align = PQI_OPQ_ELEM_ARRAY_ALIGN; - ret = os_dma_mem_alloc(softs, &softs->op_obq_dma_mem); - if (ret) { - DBG_ERR("Failed to Allocate Operational OBQ memory ret : %d\n", - ret); - goto err_out; - } - /* Set up the address */ - virt_addr = softs->op_obq_dma_mem.virt_addr; - dma_addr = softs->op_obq_dma_mem.dma_addr; - ob_pi_dma_start_offset += dma_addr; - ob_pi_virt_start_addr = virt_addr + ob_pi_virt_start_offset; - - DBG_INFO("softs->num_op_obq %d\n",softs->num_op_obq); + DBG_INIT("softs->num_op_obq %u max_obq_elem_size=%u\n",softs->num_op_obq, softs->max_obq_elem_size); for (i = 0; i < softs->num_op_obq; i++) { op_ob_q = &softs->op_ob_q[i]; - ASSERT(!(dma_addr & PQI_ADDR_ALIGN_MASK_64)); - FILL_QUEUE_ARRAY_ADDR(op_ob_q,virt_addr,dma_addr); + + /* Allocate memory for OB queues */ + op_ob_q->num_elem = softs->num_elem_per_op_obq; + op_ob_q->elem_size = PQISRC_OP_OBQ_ELEM_SIZE_BYTES; + ret = pqisrc_allocate_and_init_outbound_q(softs, op_ob_q, "op_ob_queue"); + if (ret) { + DBG_ERR("Failed to Allocate Operational OBQ memory ret : %d\n", + ret); + goto err_out; + } op_ob_q->q_id = obq_id++; if(softs->share_opq_and_eventq == true) op_ob_q->intr_msg_num = i; else op_ob_q->intr_msg_num = i + 1; /* msg num zero for event */ - op_ob_q->num_elem = softs->num_elem_per_op_obq; - op_ob_q->elem_size = softs->obq_elem_size; - op_ob_q->pi_dma_addr = ob_pi_dma_start_offset + - (i * sizeof(uint32_t)); - op_ob_q->pi_virt_addr = (uint32_t*)(ob_pi_virt_start_addr + - (i * sizeof(uint32_t))); - ASSERT(!(op_ob_q->pi_dma_addr & PQI_ADDR_ALIGN_MASK_4)); - - ret = pqisrc_create_op_obq(softs,op_ob_q); + + ret = pqisrc_create_op_obq(softs, op_ob_q); if (ret) { - DBG_ERR("Failed to Create OP OBQ %d\n",op_ob_q->q_id); + DBG_ERR("Failed to Create OP OBQ %u\n",op_ob_q->q_id); goto err_out_create; } op_ob_q->created = true; - virt_addr += obq_size; - dma_addr += obq_size; } DBG_FUNC("OUT\n"); return ret; err_out_create: - pqisrc_destroy_op_ob_queues(softs); err_out: + pqisrc_destroy_op_ob_queues(softs); DBG_FUNC("OUT failed %d\n", ret); return PQI_STATUS_FAILURE; } diff --git a/sys/dev/smartpqi/smartpqi_request.c b/sys/dev/smartpqi/smartpqi_request.c --- a/sys/dev/smartpqi/smartpqi_request.c +++ b/sys/dev/smartpqi/smartpqi_request.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,37 +26,37 @@ #include "smartpqi_includes.h" -/* - * Attempt to perform offload RAID mapping for a logical volume I/O. - */ - -#define HPSA_RAID_0 0 -#define HPSA_RAID_4 1 -#define HPSA_RAID_1 2 /* also used for RAID 10 */ -#define HPSA_RAID_5 3 /* also used for RAID 50 */ -#define HPSA_RAID_51 4 -#define HPSA_RAID_6 5 /* also used for RAID 60 */ -#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */ -#define HPSA_RAID_MAX HPSA_RAID_ADM -#define HPSA_RAID_UNKNOWN 0xff +/* Change this if need to debug why AIO is not being used */ +#define DBG_AIO DBG_IO #define SG_FLAG_LAST 0x40000000 #define SG_FLAG_CHAIN 0x80000000 +/* Local Prototypes */ +static void pqisrc_increment_io_counters(pqisrc_softstate_t *softs, rcb_t *rcb); +static int fill_lba_for_scsi_rw(pqisrc_softstate_t *softs, uint8_t *cdb, aio_req_locator_t *l); + + /* Subroutine to find out embedded sgl count in IU */ static inline uint32_t -pqisrc_embedded_sgl_count(uint32_t elem_alloted) +pqisrc_embedded_sgl_count(uint32_t elem_alloted, uint8_t iu_type) { - uint32_t embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU; - DBG_FUNC(" IN "); + uint32_t embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT; + + DBG_FUNC("IN\n"); + + if (iu_type == PQI_IU_TYPE_RAID5_WRITE_BYPASS_REQUEST || + iu_type == PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST) + embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU_RAID56_AIO; + /** calculate embedded sgl count using num_elem_alloted for IO **/ if(elem_alloted - 1) embedded_sgl_count += ((elem_alloted - 1) * MAX_EMBEDDED_SG_IN_IU); - DBG_IO("embedded_sgl_count :%d\n",embedded_sgl_count); + /* DBG_IO("embedded_sgl_count :%d\n", embedded_sgl_count); */ - DBG_FUNC(" OUT "); + DBG_FUNC("OUT\n"); return embedded_sgl_count; @@ -68,7 +68,7 @@ { uint32_t contiguous_free_elem = 0; - DBG_FUNC(" IN "); + DBG_FUNC("IN\n"); if(pi >= ci) { contiguous_free_elem = (elem_in_q - pi); @@ -78,33 +78,41 @@ contiguous_free_elem = (ci - pi - 1); } - DBG_FUNC(" OUT "); + DBG_FUNC("OUT\n"); return contiguous_free_elem; } /* Subroutine to find out num of elements need for the request */ static uint32_t -pqisrc_num_elem_needed(pqisrc_softstate_t *softs, uint32_t SG_Count) +pqisrc_num_elem_needed(pqisrc_softstate_t *softs, uint32_t SG_Count, + pqi_scsi_dev_t *devp, boolean_t is_write, IO_PATH_T io_path) { uint32_t num_sg; uint32_t num_elem_required = 1; - DBG_FUNC(" IN "); - DBG_IO("SGL_Count :%d",SG_Count); + uint32_t sg_in_first_iu = MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT; + + DBG_FUNC("IN\n"); + DBG_IO("SGL_Count :%u\n",SG_Count); + + if ((devp->raid_level == SA_RAID_5 || devp->raid_level == SA_RAID_6) + && is_write && (io_path == AIO_PATH)) + sg_in_first_iu = MAX_EMBEDDED_SG_IN_FIRST_IU_RAID56_AIO; /******** If SG_Count greater than max sg per IU i.e 4 or 68 (4 is with out spanning or 68 is with spanning) chaining is required. - OR, If SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU then, + OR, If SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU_* then, on these two cases one element is enough. ********/ - if(SG_Count > softs->max_sg_per_iu || SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU) + if(SG_Count > softs->max_sg_per_spanning_cmd || + SG_Count <= sg_in_first_iu) return num_elem_required; /* SGL Count Other Than First IU */ - num_sg = SG_Count - MAX_EMBEDDED_SG_IN_FIRST_IU; + num_sg = SG_Count - sg_in_first_iu; num_elem_required += PQISRC_DIV_ROUND_UP(num_sg, MAX_EMBEDDED_SG_IN_IU); - DBG_FUNC(" OUT "); + DBG_FUNC("OUT\n"); return num_elem_required; } @@ -119,19 +127,21 @@ sgt_t *sg_chain = NULL; boolean_t partial = false; - DBG_FUNC(" IN "); + DBG_FUNC("IN\n"); - DBG_IO("SGL_Count :%d",num_sg); + /* DBG_IO("SGL_Count :%d",num_sg); */ if (0 == num_sg) { goto out; } - if (num_sg <= pqisrc_embedded_sgl_count(num_elem_alloted)) { + if (num_sg <= pqisrc_embedded_sgl_count(num_elem_alloted, + iu_hdr->iu_type)) { + for (i = 0; i < num_sg; i++, sgt++) { - sgt->addr= OS_GET_IO_SG_ADDR(rcb,i); - sgt->len= OS_GET_IO_SG_LEN(rcb,i); - sgt->flags= 0; - } + sgt->addr= OS_GET_IO_SG_ADDR(rcb,i); + sgt->len= OS_GET_IO_SG_LEN(rcb,i); + sgt->flags= 0; + } sg_array[num_sg - 1].flags = SG_FLAG_LAST; } else { @@ -157,17 +167,44 @@ } out: iu_hdr->iu_length = num_sg * sizeof(sgt_t); - DBG_FUNC(" OUT "); + DBG_FUNC("OUT\n"); return partial; } +#if 0 +static inline void +pqisrc_show_raid_req(pqisrc_softstate_t *softs, pqisrc_raid_req_t *raid_req) +{ + DBG_IO("%30s: 0x%x\n", "raid_req->header.iu_type", + raid_req->header.iu_type); + DBG_IO("%30s: 0x%d\n", "raid_req->response_queue_id", + raid_req->response_queue_id); + DBG_IO("%30s: 0x%x\n", "raid_req->request_id", + raid_req->request_id); + DBG_IO("%30s: 0x%x\n", "raid_req->buffer_length", + raid_req->buffer_length); + DBG_IO("%30s: 0x%x\n", "raid_req->task_attribute", + raid_req->task_attribute); + DBG_IO("%30s: 0x%llx\n", "raid_req->lun_number", + *((long long unsigned int*)raid_req->lun_number)); + DBG_IO("%30s: 0x%x\n", "raid_req->error_index", + raid_req->error_index); + DBG_IO("%30s: 0x%p\n", "raid_req->sg_descriptors[0].addr", + (void *)raid_req->sg_descriptors[0].addr); + DBG_IO("%30s: 0x%x\n", "raid_req->sg_descriptors[0].len", + raid_req->sg_descriptors[0].len); + DBG_IO("%30s: 0x%x\n", "raid_req->sg_descriptors[0].flags", + raid_req->sg_descriptors[0].flags); +} +#endif + /*Subroutine used to Build the RAID request */ static void pqisrc_build_raid_io(pqisrc_softstate_t *softs, rcb_t *rcb, pqisrc_raid_req_t *raid_req, uint32_t num_elem_alloted) { - DBG_FUNC(" IN "); + DBG_FUNC("IN\n"); raid_req->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; raid_req->header.comp_feature = 0; @@ -185,15 +222,16 @@ raid_req->fence = 0; raid_req->error_index = raid_req->request_id; raid_req->reserved2 = 0; - raid_req->task_attribute = OS_GET_TASK_ATTR(rcb); - raid_req->command_priority = 0; + raid_req->task_attribute = OS_GET_TASK_ATTR(rcb); + raid_req->command_priority = 0; raid_req->reserved3 = 0; raid_req->reserved4 = 0; raid_req->reserved5 = 0; + raid_req->ml_device_lun_number = (uint8_t)rcb->cm_ccb->ccb_h.target_lun; /* As cdb and additional_cdb_bytes are contiguous, update them in a single statement */ - memcpy(raid_req->cdb, rcb->cdbp, rcb->cmdlen); + memcpy(raid_req->cmd.cdb, rcb->cdbp, rcb->cmdlen); #if 0 DBG_IO("CDB :"); for(i = 0; i < rcb->cmdlen ; i++) @@ -235,32 +273,70 @@ offsetof(pqisrc_raid_req_t, sg_descriptors) - sizeof(iu_header_t); #if 0 - DBG_IO("raid_req->header.iu_type : 0x%x", raid_req->header.iu_type); - DBG_IO("raid_req->response_queue_id :%d\n"raid_req->response_queue_id); - DBG_IO("raid_req->request_id : 0x%x", raid_req->request_id); - DBG_IO("raid_req->buffer_length : 0x%x", raid_req->buffer_length); - DBG_IO("raid_req->task_attribute : 0x%x", raid_req->task_attribute); - DBG_IO("raid_req->lun_number : 0x%x", raid_req->lun_number); - DBG_IO("raid_req->error_index : 0x%x", raid_req->error_index); - DBG_IO("raid_req->sg_descriptors[0].addr : %p", (void*)raid_req->sg_descriptors[0].addr); - DBG_IO("raid_req->sg_descriptors[0].len : 0x%x", raid_req->sg_descriptors[0].len); - DBG_IO("raid_req->sg_descriptors[0].flags : 0%x", raid_req->sg_descriptors[0].flags); + pqisrc_show_raid_req(softs, raid_req); #endif rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_raid_response_error; rcb->resp_qid = raid_req->response_queue_id; - DBG_FUNC(" OUT "); + DBG_FUNC("OUT\n"); } -/*Subroutine used to Build the AIO request */ -static void -pqisrc_build_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb, - pqi_aio_req_t *aio_req, uint32_t num_elem_alloted) +/* We will need to expand this to handle different types of + * aio request structures. + */ +#if 0 +static inline void +pqisrc_show_aio_req(pqisrc_softstate_t *softs, pqi_aio_req_t *aio_req) { - DBG_FUNC(" IN "); + DBG_IO("%30s: 0x%x\n", "aio_req->header.iu_type", + aio_req->header.iu_type); + DBG_IO("%30s: 0x%x\n", "aio_req->resp_qid", + aio_req->response_queue_id); + DBG_IO("%30s: 0x%x\n", "aio_req->req_id", + aio_req->req_id); + DBG_IO("%30s: 0x%x\n", "aio_req->nexus", + aio_req->nexus); + DBG_IO("%30s: 0x%x\n", "aio_req->buf_len", + aio_req->buf_len); + DBG_IO("%30s: 0x%x\n", "aio_req->cmd_flags.data_dir", + aio_req->cmd_flags.data_dir); + DBG_IO("%30s: 0x%x\n", "aio_req->attr_prio.task_attr", + aio_req->attr_prio.task_attr); + DBG_IO("%30s: 0x%x\n", "aio_req->err_idx", + aio_req->err_idx); + DBG_IO("%30s: 0x%x\n", "aio_req->num_sg", + aio_req->num_sg); + DBG_IO("%30s: 0x%p\n", "aio_req->sg_desc[0].addr", + (void *)aio_req->sg_desc[0].addr); + DBG_IO("%30s: 0x%x\n", "aio_req->sg_desc[0].len", + aio_req->sg_desc[0].len); + DBG_IO("%30s: 0x%x\n", "aio_req->sg_desc[0].flags", + aio_req->sg_desc[0].flags); +} +#endif + +void +int_to_scsilun(uint64_t lun, uint8_t *scsi_lun) +{ + int i; + + memset(scsi_lun, 0, sizeof(lun)); + for (i = 0; i < sizeof(lun); i += 2) { + scsi_lun[i] = (lun >> 8) & 0xFF; + scsi_lun[i+1] = lun & 0xFF; + lun = lun >> 16; + } +} + +/*Subroutine used to populate AIO IUs. */ +void +pqisrc_build_aio_common(pqisrc_softstate_t *softs, pqi_aio_req_t *aio_req, + rcb_t *rcb, uint32_t num_elem_alloted) +{ + DBG_FUNC("IN\n"); aio_req->header.iu_type = PQI_IU_TYPE_AIO_PATH_IO_REQUEST; aio_req->header.comp_feature = 0; aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); @@ -271,80 +347,648 @@ aio_req->res1[1] = 0; aio_req->nexus = rcb->ioaccel_handle; aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); - aio_req->data_dir = rcb->data_dir; - aio_req->mem_type = 0; - aio_req->fence = 0; - aio_req->res2 = 0; - aio_req->task_attr = OS_GET_TASK_ATTR(rcb); - aio_req->cmd_prio = 0; - aio_req->res3 = 0; + aio_req->cmd_flags.data_dir = rcb->data_dir; + aio_req->cmd_flags.mem_type = 0; + aio_req->cmd_flags.fence = 0; + aio_req->cmd_flags.res2 = 0; + aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); + aio_req->attr_prio.cmd_prio = 0; + aio_req->attr_prio.res3 = 0; aio_req->err_idx = aio_req->req_id; aio_req->cdb_len = rcb->cmdlen; - if(rcb->cmdlen > sizeof(aio_req->cdb)) + if (rcb->cmdlen > sizeof(aio_req->cdb)) rcb->cmdlen = sizeof(aio_req->cdb); memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); + memset(aio_req->res4, 0, sizeof(aio_req->res4)); + + uint64_t lun = rcb->cm_ccb->ccb_h.target_lun; + if (lun && (rcb->dvp->is_multi_lun)) { + int_to_scsilun(lun, aio_req->lun); + } + else { + memset(aio_req->lun, 0, sizeof(aio_req->lun)); + } + + /* handle encryption fields */ + if (rcb->encrypt_enable == true) { + aio_req->cmd_flags.encrypt_enable = true; + aio_req->encrypt_key_index = + LE_16(rcb->enc_info.data_enc_key_index); + aio_req->encrypt_twk_low = + LE_32(rcb->enc_info.encrypt_tweak_lower); + aio_req->encrypt_twk_high = + LE_32(rcb->enc_info.encrypt_tweak_upper); + } else { + aio_req->cmd_flags.encrypt_enable = 0; + aio_req->encrypt_key_index = 0; + aio_req->encrypt_twk_high = 0; + aio_req->encrypt_twk_low = 0; + } + /* Frame SGL Descriptor */ + aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, + &aio_req->header, num_elem_alloted); + + aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); + + /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ + + aio_req->header.iu_length += offsetof(pqi_aio_req_t, sg_desc) - + sizeof(iu_header_t); + /* set completion and error handlers. */ + rcb->success_cmp_callback = pqisrc_process_io_response_success; + rcb->error_cmp_callback = pqisrc_process_aio_response_error; + rcb->resp_qid = aio_req->response_queue_id; + DBG_FUNC("OUT\n"); + +} +/*Subroutine used to show standard AIO IU fields */ +void +pqisrc_show_aio_common(pqisrc_softstate_t *softs, rcb_t *rcb, + pqi_aio_req_t *aio_req) +{ +#ifdef DEBUG_AIO + DBG_INFO("AIO IU Content, tag# 0x%08x", rcb->tag); + DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); + DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); + DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); + DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); + DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); + DBG_INFO("%15s: 0x%x\n", "nexus", aio_req->nexus); + DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); + DBG_INFO("%15s:\n", "cmd_flags"); + DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); + DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); + DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); + DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); + DBG_INFO("%15s: 0x%x\n", "encryption", + aio_req->cmd_flags.encrypt_enable); + DBG_INFO("%15s:\n", "attr_prio"); + DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); + DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); + DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); + DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); + DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); + pqisrc_show_cdb(softs, "AIOC", rcb, aio_req->cdb); + DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); + DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); + DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); #if 0 - DBG_IO("CDB : \n"); - for(int i = 0; i < rcb->cmdlen ; i++) - DBG_IO(" 0x%x \n",aio_req->cdb[i]); + DBG_INFO("%15s: 0x%x\n", "lun", aio_req->lun); + DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", + (void *)aio_req->sg_desc[0].addr); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", + aio_req->sg_desc[0].len); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", + aio_req->sg_desc[0].flags); #endif - memset(aio_req->lun,0,sizeof(aio_req->lun)); - memset(aio_req->res4,0,sizeof(aio_req->res4)); - - if(rcb->encrypt_enable == true) { - aio_req->encrypt_enable = true; - aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index); - aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower); - aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper); +#endif /* DEBUG_AIO */ +} + +/*Subroutine used to populate AIO RAID 1 write bypass IU. */ +void +pqisrc_build_aio_R1_write(pqisrc_softstate_t *softs, + pqi_aio_raid1_write_req_t *aio_req, rcb_t *rcb, + uint32_t num_elem_alloted) +{ + DBG_FUNC("IN\n"); + if (!rcb->dvp) { + DBG_WARN("%s: DEBUG: dev ptr is null", __func__); + return; + } + if (!rcb->dvp->raid_map) { + DBG_WARN("%s: DEBUG: raid_map is null", __func__); + return; + } + + aio_req->header.iu_type = PQI_IU_TYPE_RAID1_WRITE_BYPASS_REQUEST; + aio_req->header.comp_feature = 0; + aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); + aio_req->work_area[0] = 0; + aio_req->work_area[1] = 0; + aio_req->req_id = rcb->tag; + aio_req->volume_id = (LE_32(rcb->dvp->scsi3addr[0]) & 0x3FFF); + aio_req->nexus_1 = rcb->it_nexus[0]; + aio_req->nexus_2 = rcb->it_nexus[1]; + aio_req->nexus_3 = rcb->it_nexus[2]; + aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); + aio_req->cmd_flags.data_dir = rcb->data_dir; + aio_req->cmd_flags.mem_type = 0; + aio_req->cmd_flags.fence = 0; + aio_req->cmd_flags.res2 = 0; + aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); + aio_req->attr_prio.cmd_prio = 0; + aio_req->attr_prio.res3 = 0; + if(rcb->cmdlen > sizeof(aio_req->cdb)) + rcb->cmdlen = sizeof(aio_req->cdb); + memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); + aio_req->err_idx = aio_req->req_id; + aio_req->cdb_len = rcb->cmdlen; + aio_req->num_drives = LE_16(rcb->dvp->raid_map->layout_map_count); + + /* handle encryption fields */ + if (rcb->encrypt_enable == true) { + aio_req->cmd_flags.encrypt_enable = true; + aio_req->encrypt_key_index = + LE_16(rcb->enc_info.data_enc_key_index); + aio_req->encrypt_twk_low = + LE_32(rcb->enc_info.encrypt_tweak_lower); + aio_req->encrypt_twk_high = + LE_32(rcb->enc_info.encrypt_tweak_upper); } else { - aio_req->encrypt_enable = 0; + aio_req->cmd_flags.encrypt_enable = 0; aio_req->encrypt_key_index = 0; aio_req->encrypt_twk_high = 0; aio_req->encrypt_twk_low = 0; } - /* Frame SGL Descriptor */ - aio_req->partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, - &aio_req->header, num_elem_alloted); + aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, + &aio_req->header, num_elem_alloted); aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); - DBG_INFO("aio_req->num_sg :%d",aio_req->num_sg); + /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ - aio_req->header.iu_length += offsetof(pqi_aio_req_t, sg_desc) - + aio_req->header.iu_length += offsetof(pqi_aio_raid1_write_req_t, sg_desc) - sizeof(iu_header_t); + + /* set completion and error handlers. */ + rcb->success_cmp_callback = pqisrc_process_io_response_success; + rcb->error_cmp_callback = pqisrc_process_aio_response_error; + rcb->resp_qid = aio_req->response_queue_id; + DBG_FUNC("OUT\n"); + +} + +/*Subroutine used to show AIO RAID1 Write bypass IU fields */ +void +pqisrc_show_aio_R1_write(pqisrc_softstate_t *softs, rcb_t *rcb, + pqi_aio_raid1_write_req_t *aio_req) +{ + +#ifdef DEBUG_AIO + DBG_INFO("AIO RAID1 Write IU Content, tag# 0x%08x", rcb->tag); + DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); + DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); + DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); + DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); + DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); + DBG_INFO("%15s: 0x%x\n", "volume_id", aio_req->volume_id); + DBG_INFO("%15s: 0x%x\n", "nexus_1", aio_req->nexus_1); + DBG_INFO("%15s: 0x%x\n", "nexus_2", aio_req->nexus_2); + DBG_INFO("%15s: 0x%x\n", "nexus_3", aio_req->nexus_3); + DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); + DBG_INFO("%15s:\n", "cmd_flags"); + DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); + DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); + DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); + DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); + DBG_INFO("%15s: 0x%x\n", "encryption", + aio_req->cmd_flags.encrypt_enable); + DBG_INFO("%15s:\n", "attr_prio"); + DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); + DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); + DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); + pqisrc_show_cdb(softs, "AIOR1W", rcb, aio_req->cdb); + DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); + DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); + DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); + DBG_INFO("%15s: 0x%x\n", "num_drives", aio_req->num_drives); + DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); + DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); #if 0 - DBG_IO("aio_req->header.iu_type : 0x%x \n",aio_req->header.iu_type); - DBG_IO("aio_req->resp_qid :0x%x",aio_req->resp_qid); - DBG_IO("aio_req->req_id : 0x%x \n",aio_req->req_id); - DBG_IO("aio_req->nexus : 0x%x \n",aio_req->nexus); - DBG_IO("aio_req->buf_len : 0x%x \n",aio_req->buf_len); - DBG_IO("aio_req->data_dir : 0x%x \n",aio_req->data_dir); - DBG_IO("aio_req->task_attr : 0x%x \n",aio_req->task_attr); - DBG_IO("aio_req->err_idx : 0x%x \n",aio_req->err_idx); - DBG_IO("aio_req->num_sg :%d",aio_req->num_sg); - DBG_IO("aio_req->sg_desc[0].addr : %p \n", (void*)aio_req->sg_desc[0].addr); - DBG_IO("aio_req->sg_desc[0].len : 0%x \n", aio_req->sg_desc[0].len); - DBG_IO("aio_req->sg_desc[0].flags : 0%x \n", aio_req->sg_desc[0].flags); + DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", + (void *)aio_req->sg_desc[0].addr); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", + aio_req->sg_desc[0].len); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", + aio_req->sg_desc[0].flags); #endif +#endif /* DEBUG_AIO */ +} +/*Subroutine used to populate AIO Raid5 or 6 write bypass IU */ +void +pqisrc_build_aio_R5or6_write(pqisrc_softstate_t *softs, + pqi_aio_raid5or6_write_req_t *aio_req, rcb_t *rcb, + uint32_t num_elem_alloted) +{ + DBG_FUNC("IN\n"); + uint32_t index; + unsigned num_data_disks; + unsigned num_metadata_disks; + unsigned total_disks; + num_data_disks = LE_16(rcb->dvp->raid_map->data_disks_per_row); + num_metadata_disks = LE_16(rcb->dvp->raid_map->metadata_disks_per_row); + total_disks = num_data_disks + num_metadata_disks; + + index = PQISRC_DIV_ROUND_UP(rcb->raid_map_index + 1, total_disks); + index *= total_disks; + index -= num_metadata_disks; + + switch (rcb->dvp->raid_level) { + case SA_RAID_5: + aio_req->header.iu_type = + PQI_IU_TYPE_RAID5_WRITE_BYPASS_REQUEST; + break; + case SA_RAID_6: + aio_req->header.iu_type = + PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST; + break; + default: + DBG_ERR("WRONG RAID TYPE FOR FUNCTION\n"); + } + aio_req->header.comp_feature = 0; + aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); + aio_req->work_area[0] = 0; + aio_req->work_area[1] = 0; + aio_req->req_id = rcb->tag; + aio_req->volume_id = (LE_32(rcb->dvp->scsi3addr[0]) & 0x3FFF); + aio_req->data_it_nexus = rcb->dvp->raid_map->dev_data[rcb->raid_map_index].ioaccel_handle; + aio_req->p_parity_it_nexus = + rcb->dvp->raid_map->dev_data[index].ioaccel_handle; + if (aio_req->header.iu_type == + PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST) { + aio_req->q_parity_it_nexus = + rcb->dvp->raid_map->dev_data[index + 1].ioaccel_handle; + } + aio_req->xor_multiplier = + rcb->dvp->raid_map->dev_data[rcb->raid_map_index].xor_mult[1]; + aio_req->row = rcb->row_num; + /*aio_req->reserved = rcb->row_num * rcb->blocks_per_row + + rcb->dvp->raid_map->disk_starting_blk;*/ + aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); + aio_req->cmd_flags.data_dir = rcb->data_dir; + aio_req->cmd_flags.mem_type = 0; + aio_req->cmd_flags.fence = 0; + aio_req->cmd_flags.res2 = 0; + aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); + aio_req->attr_prio.cmd_prio = 0; + aio_req->attr_prio.res3 = 0; + if (rcb->cmdlen > sizeof(aio_req->cdb)) + rcb->cmdlen = sizeof(aio_req->cdb); + memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); + aio_req->err_idx = aio_req->req_id; + aio_req->cdb_len = rcb->cmdlen; +#if 0 + /* Stubbed out for later */ + aio_req->header.iu_type = iu_type; + aio_req->data_it_nexus = ; + aio_req->p_parity_it_nexus = ; + aio_req->q_parity_it_nexus = ; + aio_req->row = ; + aio_req->stripe_lba = ; +#endif + /* handle encryption fields */ + if (rcb->encrypt_enable == true) { + aio_req->cmd_flags.encrypt_enable = true; + aio_req->encrypt_key_index = + LE_16(rcb->enc_info.data_enc_key_index); + aio_req->encrypt_twk_low = + LE_32(rcb->enc_info.encrypt_tweak_lower); + aio_req->encrypt_twk_high = + LE_32(rcb->enc_info.encrypt_tweak_upper); + } else { + aio_req->cmd_flags.encrypt_enable = 0; + aio_req->encrypt_key_index = 0; + aio_req->encrypt_twk_high = 0; + aio_req->encrypt_twk_low = 0; + } + /* Frame SGL Descriptor */ + aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, + &aio_req->header, num_elem_alloted); + + aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); + + /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ + + aio_req->header.iu_length += offsetof(pqi_aio_raid5or6_write_req_t, sg_desc) - + sizeof(iu_header_t); + /* set completion and error handlers. */ rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_aio_response_error; rcb->resp_qid = aio_req->response_queue_id; + DBG_FUNC("OUT\n"); + +} + +/*Subroutine used to show AIO RAID5/6 Write bypass IU fields */ +void +pqisrc_show_aio_R5or6_write(pqisrc_softstate_t *softs, rcb_t *rcb, + pqi_aio_raid5or6_write_req_t *aio_req) +{ +#ifdef DEBUG_AIO + DBG_INFO("AIO RAID5or6 Write IU Content, tag# 0x%08x\n", rcb->tag); + DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); + DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); + DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); + DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); + DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); + DBG_INFO("%15s: 0x%x\n", "volume_id", aio_req->volume_id); + DBG_INFO("%15s: 0x%x\n", "data_it_nexus", + aio_req->data_it_nexus); + DBG_INFO("%15s: 0x%x\n", "p_parity_it_nexus", + aio_req->p_parity_it_nexus); + DBG_INFO("%15s: 0x%x\n", "q_parity_it_nexus", + aio_req->q_parity_it_nexus); + DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); + DBG_INFO("%15s:\n", "cmd_flags"); + DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); + DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); + DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); + DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); + DBG_INFO("%15s: 0x%x\n", "encryption", + aio_req->cmd_flags.encrypt_enable); + DBG_INFO("%15s:\n", "attr_prio"); + DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); + DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); + DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); + pqisrc_show_cdb(softs, "AIOR56W", rcb, aio_req->cdb); + DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); + DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); + DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); + DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); + DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); + DBG_INFO("%15s: 0x%lx\n", "row", aio_req->row); +#if 0 + DBG_INFO("%15s: 0x%lx\n", "stripe_lba", aio_req->stripe_lba); + DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", + (void *)aio_req->sg_desc[0].addr); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", + aio_req->sg_desc[0].len); + DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", + aio_req->sg_desc[0].flags); +#endif +#endif /* DEBUG_AIO */ +} - DBG_FUNC(" OUT "); +/* Is the cdb a read command? */ +boolean_t +pqisrc_cdb_is_read(uint8_t *cdb) +{ + if (cdb[0] == SCMD_READ_6 || cdb[0] == SCMD_READ_10 || + cdb[0] == SCMD_READ_12 || cdb[0] == SCMD_READ_16) + return true; + return false; +} + +/* Is the cdb a write command? */ +boolean_t +pqisrc_cdb_is_write(uint8_t *cdb) +{ + if (cdb == NULL) + return false; + if (cdb[0] == SCMD_WRITE_6 || cdb[0] == SCMD_WRITE_10 || + cdb[0] == SCMD_WRITE_12 || cdb[0] == SCMD_WRITE_16) + return true; + return false; } -/*Function used to build and send RAID/AIO */ +/*Subroutine used to show the AIO request */ +void +pqisrc_show_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb, + pqi_aio_req_t *aio_req, uint32_t num_elem_alloted) +{ + boolean_t is_write; + DBG_FUNC("IN\n"); + + is_write = pqisrc_cdb_is_write(rcb->cdbp); + + if (!is_write) { + pqisrc_show_aio_common(softs, rcb, aio_req); + goto out; + } + + switch (rcb->dvp->raid_level) { + case SA_RAID_0: + pqisrc_show_aio_common(softs, rcb, aio_req); + break; + case SA_RAID_1: + case SA_RAID_ADM: + pqisrc_show_aio_R1_write(softs, rcb, + (pqi_aio_raid1_write_req_t *)aio_req); + break; + case SA_RAID_5: + case SA_RAID_6: + pqisrc_show_aio_R5or6_write(softs, rcb, + (pqi_aio_raid5or6_write_req_t *)aio_req); + break; + } + +out: + DBG_FUNC("OUT\n"); + +} + + +void +pqisrc_build_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb, + pqi_aio_req_t *aio_req, uint32_t num_elem_alloted) +{ + boolean_t is_write; + DBG_FUNC("IN\n"); + + is_write = pqisrc_cdb_is_write(rcb->cdbp); + + if (is_write) { + switch (rcb->dvp->raid_level) { + case SA_RAID_0: + pqisrc_build_aio_common(softs, aio_req, + rcb, num_elem_alloted); + break; + case SA_RAID_1: + case SA_RAID_ADM: + pqisrc_build_aio_R1_write(softs, + (pqi_aio_raid1_write_req_t *)aio_req, + rcb, num_elem_alloted); + + break; + case SA_RAID_5: + case SA_RAID_6: + pqisrc_build_aio_R5or6_write(softs, + (pqi_aio_raid5or6_write_req_t *)aio_req, + rcb, num_elem_alloted); + break; + } + } else { + pqisrc_build_aio_common(softs, aio_req, rcb, num_elem_alloted); + } + + pqisrc_show_aio_io(softs, rcb, aio_req, num_elem_alloted); + + DBG_FUNC("OUT\n"); +} + +/* + * Return true from this function to prevent AIO from handling this request. + * True is returned if the request is determined to be part of a stream, or + * if the controller does not handle AIO at the appropriate RAID level. + */ +static boolean_t +pqisrc_is_parity_write_stream(pqisrc_softstate_t *softs, rcb_t *rcb) +{ + os_ticks_t oldest_ticks; + uint8_t lru_index; + int i; + int rc; + pqi_scsi_dev_t *device; + struct pqi_stream_data *pqi_stream_data; + aio_req_locator_t loc; + + DBG_FUNC("IN\n"); + + rc = fill_lba_for_scsi_rw(softs, rcb->cdbp , &loc); + if (rc != PQI_STATUS_SUCCESS) { + return false; + } + + /* check writes only */ + if (!pqisrc_cdb_is_write(rcb->cdbp)) { + return false; + } + + if (!softs->enable_stream_detection) { + return false; + } + + device = rcb->dvp; + if (!device) { + return false; + } + + /* + * check for R5/R6 streams. + */ + if (device->raid_level != SA_RAID_5 && device->raid_level != SA_RAID_6) { + return false; + } + + /* + * If controller does not support AIO R{5,6} writes, need to send + * requests down non-aio path. + */ + if ((device->raid_level == SA_RAID_5 && !softs->aio_raid5_write_bypass) || + (device->raid_level == SA_RAID_6 && !softs->aio_raid6_write_bypass)) { + return true; + } + + lru_index = 0; + oldest_ticks = INT_MAX; + for (i = 0; i < NUM_STREAMS_PER_LUN; i++) { + pqi_stream_data = &device->stream_data[i]; + /* + * check for adjacent request or request is within + * the previous request. + */ + if ((pqi_stream_data->next_lba && + loc.block.first >= pqi_stream_data->next_lba) && + loc.block.first <= pqi_stream_data->next_lba + + loc.block.cnt) { + pqi_stream_data->next_lba = loc.block.first + + loc.block.cnt; + pqi_stream_data->last_accessed = TICKS; + return true; + } + + /* unused entry */ + if (pqi_stream_data->last_accessed == 0) { + lru_index = i; + break; + } + + /* Find entry with oldest last accessed time */ + if (pqi_stream_data->last_accessed <= oldest_ticks) { + oldest_ticks = pqi_stream_data->last_accessed; + lru_index = i; + } + } + + /* + * Set LRU entry + */ + pqi_stream_data = &device->stream_data[lru_index]; + pqi_stream_data->last_accessed = TICKS; + pqi_stream_data->next_lba = loc.block.first + loc.block.cnt; + + DBG_FUNC("OUT\n"); + + return false; +} + +/** + Determine if a request is eligible for AIO. Build/map + the request if using AIO path to a RAID volume. + + return the path that should be used for this request +*/ +static IO_PATH_T +determine_io_path_build_bypass(pqisrc_softstate_t *softs,rcb_t *rcb) +{ + IO_PATH_T io_path = AIO_PATH; + pqi_scsi_dev_t *devp = rcb->dvp; + int ret = PQI_STATUS_FAILURE; + + /* Default to using the host CDB directly (will be used if targeting RAID + path or HBA mode */ + rcb->cdbp = OS_GET_CDBP(rcb); + + if(!rcb->aio_retry) { + + /** IO for Physical Drive, Send in AIO PATH **/ + if(IS_AIO_PATH(devp)) { + rcb->ioaccel_handle = devp->ioaccel_handle; + return io_path; + } + + /** IO for RAID Volume, ByPass IO, Send in AIO PATH unless part of stream **/ + if (devp->offload_enabled && !pqisrc_is_parity_write_stream(softs, rcb)) { + ret = pqisrc_build_scsi_cmd_raidbypass(softs, devp, rcb); + } + + if (PQI_STATUS_FAILURE == ret) { + io_path = RAID_PATH; + } else { + ASSERT(rcb->cdbp == rcb->bypass_cdb); + } + } else { + /* Retrying failed AIO IO */ + io_path = RAID_PATH; + } + + return io_path; +} + +uint8_t +pqisrc_get_aio_data_direction(rcb_t *rcb) +{ + switch (rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: return SOP_DATA_DIR_FROM_DEVICE; + case CAM_DIR_OUT: return SOP_DATA_DIR_TO_DEVICE; + case CAM_DIR_NONE: return SOP_DATA_DIR_NONE; + default: return SOP_DATA_DIR_UNKNOWN; + } +} + +uint8_t +pqisrc_get_raid_data_direction(rcb_t *rcb) +{ + switch (rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: return SOP_DATA_DIR_TO_DEVICE; + case CAM_DIR_OUT: return SOP_DATA_DIR_FROM_DEVICE; + case CAM_DIR_NONE: return SOP_DATA_DIR_NONE; + default: return SOP_DATA_DIR_UNKNOWN; + } +} + +/* Function used to build and send RAID/AIO */ int pqisrc_build_send_io(pqisrc_softstate_t *softs,rcb_t *rcb) { ib_queue_t *ib_q_array = softs->op_aio_ib_q; ib_queue_t *ib_q = NULL; char *ib_iu = NULL; - IO_PATH_T io_path = AIO_PATH; + IO_PATH_T io_path; uint32_t TraverseCount = 0; int first_qindex = OS_GET_IO_REQ_QINDEX(softs, rcb); int qindex = first_qindex; @@ -352,43 +996,32 @@ uint32_t num_elem_needed; uint32_t num_elem_alloted = 0; pqi_scsi_dev_t *devp = rcb->dvp; - uint8_t raidbypass_cdb[16]; + boolean_t is_write; - DBG_FUNC(" IN "); + DBG_FUNC("IN\n"); - if(!rcb->aio_retry) { - rcb->cdbp = OS_GET_CDBP(rcb); - if(IS_AIO_PATH(devp)) { - /** IO for Physical Drive **/ - /** Send in AIO PATH**/ - rcb->ioaccel_handle = devp->ioaccel_handle; - } else { - int ret = PQI_STATUS_FAILURE; - /** IO for RAID Volume **/ - if (devp->offload_enabled) { - /** ByPass IO ,Send in AIO PATH **/ - ret = pqisrc_send_scsi_cmd_raidbypass(softs, - devp, rcb, raidbypass_cdb); - } - if (PQI_STATUS_FAILURE == ret) { - /** Send in RAID PATH **/ - io_path = RAID_PATH; - num_op_ib_q = softs->num_op_raid_ibq; - ib_q_array = softs->op_raid_ib_q; - } else { - rcb->cdbp = raidbypass_cdb; - } - } - } else { - /* Retrying failed AIO IO */ - io_path = RAID_PATH; - rcb->cdbp = OS_GET_CDBP(rcb); + /* Note: this will determine if the request is eligble for AIO */ + io_path = determine_io_path_build_bypass(softs, rcb); + + if (io_path == RAID_PATH) + { + /* Update direction for RAID path */ + rcb->data_dir = pqisrc_get_raid_data_direction(rcb); num_op_ib_q = softs->num_op_raid_ibq; ib_q_array = softs->op_raid_ib_q; } + else { + rcb->data_dir = pqisrc_get_aio_data_direction(rcb); + if (rcb->data_dir == SOP_DATA_DIR_UNKNOWN) { + DBG_ERR("Unknown Direction\n"); + } + } - num_elem_needed = pqisrc_num_elem_needed(softs, OS_GET_IO_SG_COUNT(rcb)); - DBG_IO("num_elem_needed :%d",num_elem_needed); + is_write = pqisrc_cdb_is_write(rcb->cdbp); + /* coverity[unchecked_value] */ + num_elem_needed = pqisrc_num_elem_needed(softs, + OS_GET_IO_SG_COUNT(rcb), devp, is_write, io_path); + DBG_IO("num_elem_needed :%u",num_elem_needed); do { uint32_t num_elem_available; @@ -397,7 +1030,7 @@ num_elem_available = pqisrc_contiguous_free_elem(ib_q->pi_local, *(ib_q->ci_virt_addr), ib_q->num_elem); - DBG_IO("num_elem_avialable :%d\n",num_elem_available); + DBG_IO("num_elem_avialable :%u\n",num_elem_available); if(num_elem_available >= num_elem_needed) { num_elem_alloted = num_elem_needed; break; @@ -414,7 +1047,7 @@ } }while(TraverseCount < 2); - DBG_IO("num_elem_alloted :%d",num_elem_alloted); + DBG_IO("num_elem_alloted :%u",num_elem_alloted); if (num_elem_alloted == 0) { DBG_WARN("OUT: IB Queues were full\n"); return PQI_STATUS_QFULL; @@ -426,12 +1059,12 @@ ib_iu = ib_q->array_virt_addr + (ib_q->pi_local * ib_q->elem_size); if(io_path == AIO_PATH) { - /** Build AIO structure **/ - pqisrc_build_aio_io(softs, rcb, (pqi_aio_req_t*)ib_iu, - num_elem_alloted); + /* Fill in the AIO IU per request and raid type */ + pqisrc_build_aio_io(softs, rcb, (pqi_aio_req_t *)ib_iu, + num_elem_alloted); } else { /** Build RAID structure **/ - pqisrc_build_raid_io(softs, rcb, (pqisrc_raid_req_t*)ib_iu, + pqisrc_build_raid_io(softs, rcb, (pqisrc_raid_req_t *)ib_iu, num_elem_alloted); } @@ -439,81 +1072,595 @@ rcb->req_q = ib_q; rcb->path = io_path; + pqisrc_increment_io_counters(softs, rcb); + /* Update the local PI */ ib_q->pi_local = (ib_q->pi_local + num_elem_alloted) % ib_q->num_elem; - DBG_INFO("ib_q->pi_local : %x\n", ib_q->pi_local); - DBG_INFO("*ib_q->ci_virt_addr: %x\n",*(ib_q->ci_virt_addr)); + DBG_IO("ib_q->pi_local : %x\n", ib_q->pi_local); + DBG_IO("*ib_q->ci_virt_addr: %x\n",*(ib_q->ci_virt_addr)); /* Inform the fw about the new IU */ PCI_MEM_PUT32(softs, ib_q->pi_register_abs, ib_q->pi_register_offset, ib_q->pi_local); - PQI_UNLOCK(&ib_q->lock); - DBG_FUNC(" OUT "); - return PQI_STATUS_SUCCESS; + PQI_UNLOCK(&ib_q->lock); + DBG_FUNC("OUT\n"); + return PQI_STATUS_SUCCESS; +} + +/* Subroutine used to set encryption info as part of RAID bypass IO*/ +static inline void +pqisrc_set_enc_info(struct pqi_enc_info *enc_info, + struct raid_map *raid_map, uint64_t first_block) +{ + uint32_t volume_blk_size; + + /* + * Set the encryption tweak values based on logical block address. + * If the block size is 512, the tweak value is equal to the LBA. + * For other block sizes, tweak value is (LBA * block size) / 512. + */ + volume_blk_size = GET_LE32((uint8_t *)&raid_map->volume_blk_size); + if (volume_blk_size != 512) + first_block = (first_block * volume_blk_size) / 512; + + enc_info->data_enc_key_index = + GET_LE16((uint8_t *)&raid_map->data_encryption_key_index); + enc_info->encrypt_tweak_upper = ((uint32_t)(((first_block) >> 16) >> 16)); + enc_info->encrypt_tweak_lower = ((uint32_t)(first_block)); +} + + +/* + * Attempt to perform offload RAID mapping for a logical volume I/O. + */ + +#define HPSA_RAID_0 0 +#define HPSA_RAID_4 1 +#define HPSA_RAID_1 2 /* also used for RAID 10 */ +#define HPSA_RAID_5 3 /* also used for RAID 50 */ +#define HPSA_RAID_51 4 +#define HPSA_RAID_6 5 /* also used for RAID 60 */ +#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */ +#define HPSA_RAID_MAX HPSA_RAID_ADM +#define HPSA_RAID_UNKNOWN 0xff + +/* Subroutine used to parse the scsi opcode and build the CDB for RAID bypass*/ +static int +fill_lba_for_scsi_rw(pqisrc_softstate_t *softs, uint8_t *cdb, aio_req_locator_t *l) +{ + + if (!l) { + DBG_INFO("No locator ptr: AIO ineligible"); + return PQI_STATUS_FAILURE; + } + + if (cdb == NULL) + return PQI_STATUS_FAILURE; + + switch (cdb[0]) { + case SCMD_WRITE_6: + l->is_write = true; + /* coverity[fallthrough] */ + case SCMD_READ_6: + l->block.first = (uint64_t)(((cdb[1] & 0x1F) << 16) | + (cdb[2] << 8) | cdb[3]); + l->block.cnt = (uint32_t)cdb[4]; + if (l->block.cnt == 0) + l->block.cnt = 256; /*blkcnt 0 means 256 */ + break; + case SCMD_WRITE_10: + l->is_write = true; + /* coverity[fallthrough] */ + case SCMD_READ_10: + l->block.first = (uint64_t)GET_BE32(&cdb[2]); + l->block.cnt = (uint32_t)GET_BE16(&cdb[7]); + break; + case SCMD_WRITE_12: + l->is_write = true; + /* coverity[fallthrough] */ + case SCMD_READ_12: + l->block.first = (uint64_t)GET_BE32(&cdb[2]); + l->block.cnt = GET_BE32(&cdb[6]); + break; + case SCMD_WRITE_16: + l->is_write = true; + /* coverity[fallthrough] */ + case SCMD_READ_16: + l->block.first = GET_BE64(&cdb[2]); + l->block.cnt = GET_BE32(&cdb[10]); + break; + default: + /* Process via normal I/O path. */ + DBG_AIO("NOT read or write 6/10/12/16: AIO ineligible"); + return PQI_STATUS_FAILURE; + } + return PQI_STATUS_SUCCESS; +} + + +/* determine whether writes to certain types of RAID are supported. */ +inline boolean_t +pqisrc_is_supported_write(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device) +{ + + DBG_FUNC("IN\n"); + + /* Raid0 was always supported */ + if (device->raid_level == SA_RAID_0) + return true; + + /* module params for individual adv. aio write features may be on, + * which affects ALL controllers, but some controllers + * do not support adv. aio write. + */ + if (!softs->adv_aio_capable) + return false; + + /* if the raid write bypass feature is turned on, + * then the write is supported. + */ + switch (device->raid_level) { + case SA_RAID_1: + case SA_RAID_ADM: + if (softs->aio_raid1_write_bypass) + return true; + break; + case SA_RAID_5: + if (softs->aio_raid5_write_bypass) + return true; + break; + case SA_RAID_6: + if (softs->aio_raid6_write_bypass) + return true; + } + + /* otherwise, it must be an unsupported write. */ + DBG_IO("AIO ineligible: write not supported for raid type\n"); + DBG_FUNC("OUT\n"); + return false; + +} + +/* check for zero-byte transfers, invalid blocks, and wraparound */ +static inline boolean_t +pqisrc_is_invalid_block(pqisrc_softstate_t *softs, aio_req_locator_t *l) +{ + DBG_FUNC("IN\n"); + + if (l->block.cnt == 0) { + DBG_AIO("AIO ineligible: blk_cnt=0\n"); + DBG_FUNC("OUT\n"); + return true; + } + + if (l->block.last < l->block.first || + l->block.last >= + GET_LE64((uint8_t *)&l->raid_map->volume_blk_cnt)) { + DBG_AIO("AIO ineligible: last block < first\n"); + DBG_FUNC("OUT\n"); + return true; + } + + DBG_FUNC("OUT\n"); + return false; +} + +/* Compute various attributes of request's location */ +static inline boolean_t +pqisrc_calc_disk_params(pqisrc_softstate_t *softs, aio_req_locator_t *l, rcb_t *rcb) +{ + DBG_FUNC("IN\n"); + + /* grab #disks, strip size, and layout map count from raid map */ + l->row.data_disks = + GET_LE16((uint8_t *)&l->raid_map->data_disks_per_row); + l->strip_sz = + GET_LE16((uint8_t *)(&l->raid_map->strip_size)); + l->map.layout_map_count = + GET_LE16((uint8_t *)(&l->raid_map->layout_map_count)); + + /* Calculate stripe information for the request. */ + l->row.blks_per_row = l->row.data_disks * l->strip_sz; + if (!l->row.blks_per_row || !l->strip_sz) { + DBG_AIO("AIO ineligible\n"); + DBG_FUNC("OUT\n"); + return false; + } + /* use __udivdi3 ? */ + rcb->blocks_per_row = l->row.blks_per_row; + l->row.first = l->block.first / l->row.blks_per_row; + rcb->row_num = l->row.first; + l->row.last = l->block.last / l->row.blks_per_row; + l->row.offset_first = (uint32_t)(l->block.first - + (l->row.first * l->row.blks_per_row)); + l->row.offset_last = (uint32_t)(l->block.last - + (l->row.last * l->row.blks_per_row)); + l->col.first = l->row.offset_first / l->strip_sz; + l->col.last = l->row.offset_last / l->strip_sz; + + DBG_FUNC("OUT\n"); + return true; +} + +/* Not AIO-eligible if it isnt' a single row/column. */ +static inline boolean_t +pqisrc_is_single_row_column(pqisrc_softstate_t *softs, aio_req_locator_t *l) +{ + boolean_t ret = true; + DBG_FUNC("IN\n"); + + if (l->row.first != l->row.last || l->col.first != l->col.last) { + DBG_AIO("AIO ineligible\n"); + ret = false; + } + DBG_FUNC("OUT\n"); + return ret; +} + +/* figure out disks/row, row, and map index. */ +static inline boolean_t +pqisrc_set_map_row_and_idx(pqisrc_softstate_t *softs, aio_req_locator_t *l, rcb_t *rcb) +{ + if (!l->row.data_disks) { + DBG_INFO("AIO ineligible: no data disks?\n"); + return false; + } + + l->row.total_disks = l->row.data_disks + + LE_16(l->raid_map->metadata_disks_per_row); + + l->map.row = ((uint32_t)(l->row.first >> + l->raid_map->parity_rotation_shift)) % + GET_LE16((uint8_t *)(&l->raid_map->row_cnt)); + + l->map.idx = (l->map.row * l->row.total_disks) + l->col.first; + rcb->raid_map_index = l->map.idx; + rcb->raid_map_row = l->map.row; + + return true; +} + +/* set the mirror for a raid 1/10/ADM */ +static inline void +pqisrc_set_read_mirror(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device, aio_req_locator_t *l) +{ + /* Avoid direct use of device->offload_to_mirror within this + * function since multiple threads might simultaneously + * increment it beyond the range of device->layout_map_count -1. + */ + + int mirror = device->offload_to_mirror[l->map.idx]; + int next_mirror = mirror + 1; + + if (next_mirror >= l->map.layout_map_count) + next_mirror = 0; + + device->offload_to_mirror[l->map.idx] = next_mirror; + l->map.idx += mirror * l->row.data_disks; +} + +/* collect ioaccel handles for mirrors of given location. */ +static inline boolean_t +pqisrc_set_write_mirrors( + pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device, + aio_req_locator_t *l, + rcb_t *rcb) +{ + uint32_t mirror = 0; + uint32_t index; + + if (l->map.layout_map_count > PQISRC_MAX_SUPPORTED_MIRRORS) + return false; + + do { + index = l->map.idx + (l->row.data_disks * mirror); + rcb->it_nexus[mirror] = + l->raid_map->dev_data[index].ioaccel_handle; + mirror++; + } while (mirror != l->map.layout_map_count); + + return true; +} + +/* Make sure first and last block are in the same R5/R6 RAID group. */ +static inline boolean_t +pqisrc_is_r5or6_single_group(pqisrc_softstate_t *softs, aio_req_locator_t *l) +{ + boolean_t ret = true; + + DBG_FUNC("IN\n"); + l->r5or6.row.blks_per_row = l->strip_sz * l->row.data_disks; + l->stripesz = l->r5or6.row.blks_per_row * l->map.layout_map_count; + l->group.first = (l->block.first % l->stripesz) / + l->r5or6.row.blks_per_row; + l->group.last = (l->block.last % l->stripesz) / + l->r5or6.row.blks_per_row; + + if (l->group.first != l->group.last) { + DBG_AIO("AIO ineligible"); + ret = false; + } + + DBG_FUNC("OUT\n"); + ASSERT(ret == true); + return ret; +} +/* Make sure R5 or R6 request doesn't span rows. */ +static inline boolean_t +pqisrc_is_r5or6_single_row(pqisrc_softstate_t *softs, aio_req_locator_t *l) +{ + boolean_t ret = true; + + DBG_FUNC("IN\n"); + + /* figure row nums containing first & last block */ + l->row.first = l->r5or6.row.first = + l->block.first / l->stripesz; + l->r5or6.row.last = l->block.last / l->stripesz; + + if (l->r5or6.row.first != l->r5or6.row.last) { + DBG_AIO("AIO ineligible"); + ret = false; + } + + DBG_FUNC("OUT\n"); + ASSERT(ret == true); + return ret; +} + +/* Make sure R5 or R6 request doesn't span columns. */ +static inline boolean_t +pqisrc_is_r5or6_single_column(pqisrc_softstate_t *softs, aio_req_locator_t *l) +{ + boolean_t ret = true; + + /* Find the columns of the first and last block */ + l->row.offset_first = l->r5or6.row.offset_first = + (uint32_t)((l->block.first % l->stripesz) % + l->r5or6.row.blks_per_row); + l->r5or6.row.offset_last = + (uint32_t)((l->block.last % l->stripesz) % + l->r5or6.row.blks_per_row); + + l->col.first = l->r5or6.row.offset_first / l->strip_sz; + l->r5or6.col.first = l->col.first; + l->r5or6.col.last = l->r5or6.row.offset_last / l->strip_sz; + + if (l->r5or6.col.first != l->r5or6.col.last) { + DBG_AIO("AIO ineligible"); + ret = false; + } + + ASSERT(ret == true); + return ret; +} + + +/* Set the map row and index for a R5 or R6 AIO request */ +static inline void +pqisrc_set_r5or6_row_and_index(aio_req_locator_t *l, + rcb_t *rcb) +{ + l->map.row = ((uint32_t) + (l->row.first >> l->raid_map->parity_rotation_shift)) % + GET_LE16((uint8_t *)(&l->raid_map->row_cnt)); + + l->map.idx = (l->group.first * + (GET_LE16((uint8_t *)(&l->raid_map->row_cnt)) + * l->row.total_disks)) + + (l->map.row * l->row.total_disks) + + l->col.first; + + rcb->raid_map_index = l->map.idx; + rcb->raid_map_row = l->map.row; +} + +/* calculate physical disk block for aio request */ +static inline boolean_t +pqisrc_calc_aio_block(aio_req_locator_t *l) +{ + boolean_t ret = true; + + l->block.disk_block = + GET_LE64((uint8_t *) (&l->raid_map->disk_starting_blk)) + + (l->row.first * l->strip_sz) + + ((uint64_t)(l->row.offset_first) - (uint64_t)(l->col.first) * l->strip_sz); + + /* any values we should be checking here? if not convert to void */ + return ret; +} + +/* Handle differing logical/physical block sizes. */ +static inline uint32_t +pqisrc_handle_blk_size_diffs(aio_req_locator_t *l) +{ + uint32_t disk_blk_cnt; + disk_blk_cnt = l->block.cnt; + + if (l->raid_map->phys_blk_shift) { + l->block.disk_block <<= l->raid_map->phys_blk_shift; + disk_blk_cnt <<= l->raid_map->phys_blk_shift; + } + return disk_blk_cnt; +} + +/* Make sure AIO request doesn't exceed the max that AIO device can + * handle based on dev type, Raid level, and encryption status. + * TODO: make limits dynamic when this becomes possible. + */ +inline boolean_t +pqisrc_aio_req_too_big(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device, rcb_t *rcb, + aio_req_locator_t *l, uint32_t disk_blk_cnt) +{ + boolean_t ret = false; + uint32_t dev_max; + uint32_t size = disk_blk_cnt * device->raid_map->volume_blk_size; + dev_max = size; + + /* filter for nvme crypto */ + if (device->is_nvme && rcb->encrypt_enable) { + if (softs->max_aio_rw_xfer_crypto_nvme != 0) { + dev_max = MIN(dev_max,softs->max_aio_rw_xfer_crypto_nvme); + } + } + + /* filter for RAID 5/6/50/60 */ + if (!device->is_physical_device && + (device->raid_level == SA_RAID_5 || + device->raid_level == SA_RAID_51 || + device->raid_level == SA_RAID_6)) { + if (softs->max_aio_write_raid5_6 != 0) { + dev_max = MIN(dev_max,softs->max_aio_write_raid5_6); + } + } + + /* filter for RAID ADM */ + if (!device->is_physical_device && + (device->raid_level == SA_RAID_ADM) && + (softs->max_aio_write_raid1_10_3drv != 0)) { + dev_max = MIN(dev_max, + softs->max_aio_write_raid1_10_3drv); + } + + /* filter for RAID 1/10 */ + if (!device->is_physical_device && + (device->raid_level == SA_RAID_1) && + (softs->max_aio_write_raid1_10_2drv != 0)) { + dev_max = MIN(dev_max, + softs->max_aio_write_raid1_10_2drv); + } + + + if (size > dev_max) { + DBG_AIO("AIO ineligible: size=%u, max=%u", size, dev_max); + ret = true; + } + + return ret; } -/* Subroutine used to set encryption info as part of RAID bypass IO*/ + +#ifdef DEBUG_RAID_MAP static inline void -pqisrc_set_enc_info(struct pqi_enc_info *enc_info, - struct raid_map *raid_map, uint64_t first_block) +pqisrc_aio_show_raid_map(pqisrc_softstate_t *softs, struct raid_map *m) { - uint32_t volume_blk_size; + int i; - /* - * Set the encryption tweak values based on logical block address. - * If the block size is 512, the tweak value is equal to the LBA. - * For other block sizes, tweak value is (LBA * block size) / 512. - */ - volume_blk_size = GET_LE32((uint8_t *)&raid_map->volume_blk_size); - if (volume_blk_size != 512) - first_block = (first_block * volume_blk_size) / 512; + if (!m) { + DBG_WARN("No RAID MAP!\n"); + return; + } + DBG_INFO("======= Raid Map ================\n"); + DBG_INFO("%-25s: 0x%x\n", "StructureSize", m->structure_size); + DBG_INFO("%-25s: 0x%x\n", "LogicalBlockSize", m->volume_blk_size); + DBG_INFO("%-25s: 0x%lx\n", "LogicalBlockCount", m->volume_blk_cnt); + DBG_INFO("%-25s: 0x%x\n", "PhysicalBlockShift", m->phys_blk_shift); + DBG_INFO("%-25s: 0x%x\n", "ParityRotationShift", + m->parity_rotation_shift); + DBG_INFO("%-25s: 0x%x\n", "StripSize", m->strip_size); + DBG_INFO("%-25s: 0x%lx\n", "DiskStartingBlock", m->disk_starting_blk); + DBG_INFO("%-25s: 0x%lx\n", "DiskBlockCount", m->disk_blk_cnt); + DBG_INFO("%-25s: 0x%x\n", "DataDisksPerRow", m->data_disks_per_row); + DBG_INFO("%-25s: 0x%x\n", "MetdataDisksPerRow", + m->metadata_disks_per_row); + DBG_INFO("%-25s: 0x%x\n", "RowCount", m->row_cnt); + DBG_INFO("%-25s: 0x%x\n", "LayoutMapCnt", m->layout_map_count); + DBG_INFO("%-25s: 0x%x\n", "fEncryption", m->flags); + DBG_INFO("%-25s: 0x%x\n", "DEK", m->data_encryption_key_index); + for (i = 0; i < RAID_MAP_MAX_ENTRIES; i++) { + if (m->dev_data[i].ioaccel_handle == 0) + break; + DBG_INFO("%-25s: %d: 0x%04x\n", "ioaccel_handle, disk", + i, m->dev_data[i].ioaccel_handle); + } +} +#endif /* DEBUG_RAID_MAP */ - enc_info->data_enc_key_index = - GET_LE16((uint8_t *)&raid_map->data_encryption_key_index); - enc_info->encrypt_tweak_upper = ((uint32_t)(((first_block) >> 16) >> 16)); - enc_info->encrypt_tweak_lower = ((uint32_t)(first_block)); +static inline void +pqisrc_aio_show_locator_info(pqisrc_softstate_t *softs, + aio_req_locator_t *l, uint32_t disk_blk_cnt, rcb_t *rcb) +{ +#ifdef DEBUG_AIO_LOCATOR + pqisrc_aio_show_raid_map(softs, l->raid_map); + + DBG_INFO("======= AIO Locator Content, tag#0x%08x =====\n", rcb->tag); + DBG_INFO("%-25s: 0x%lx\n", "block.first", l->block.first); + DBG_INFO("%-25s: 0x%lx\n", "block.last", l->block.last); + DBG_INFO("%-25s: 0x%x\n", "block.cnt", l->block.cnt); + DBG_INFO("%-25s: 0x%lx\n", "block.disk_block", l->block.disk_block); + DBG_INFO("%-25s: 0x%x\n", "row.blks_per_row", l->row.blks_per_row); + DBG_INFO("%-25s: 0x%lx\n", "row.first", l->row.first); + DBG_INFO("%-25s: 0x%lx\n", "row.last", l->row.last); + DBG_INFO("%-25s: 0x%x\n", "row.offset_first", l->row.offset_first); + DBG_INFO("%-25s: 0x%x\n", "row.offset_last", l->row.offset_last); + DBG_INFO("%-25s: 0x%x\n", "row.data_disks", l->row.data_disks); + DBG_INFO("%-25s: 0x%x\n", "row.total_disks", l->row.total_disks); + DBG_INFO("%-25s: 0x%x\n", "col.first", l->col.first); + DBG_INFO("%-25s: 0x%x\n", "col.last", l->col.last); + + if (l->raid_level == SA_RAID_5 || l->raid_level == SA_RAID_6) { + DBG_INFO("%-25s: 0x%x\n", "r5or6.row.blks_per_row", + l->r5or6.row.blks_per_row); + DBG_INFO("%-25s: 0x%lx\n", "r5or6.row.first", l->r5or6.row.first); + DBG_INFO("%-25s: 0x%lx\n", "r5or6.row.last", l->r5or6.row.last); + DBG_INFO("%-25s: 0x%x\n", "r5or6.row.offset_first", + l->r5or6.row.offset_first); + DBG_INFO("%-25s: 0x%x\n", "r5or6.row.offset_last", + l->r5or6.row.offset_last); + DBG_INFO("%-25s: 0x%x\n", "r5or6.row.data_disks", + l->r5or6.row.data_disks); + DBG_INFO("%-25s: 0x%x\n", "r5or6.row.total_disks", + l->r5or6.row.total_disks); + DBG_INFO("%-25s: 0x%x\n", "r5or6.col.first", l->r5or6.col.first); + DBG_INFO("%-25s: 0x%x\n", "r5or6.col.last", l->r5or6.col.last); + } + DBG_INFO("%-25s: 0x%x\n", "map.row", l->map.row); + DBG_INFO("%-25s: 0x%x\n", "map.idx", l->map.idx); + DBG_INFO("%-25s: 0x%x\n", "map.layout_map_count", + l->map.layout_map_count); + DBG_INFO("%-25s: 0x%x\n", "group.first", l->group.first); + DBG_INFO("%-25s: 0x%x\n", "group.last", l->group.last); + DBG_INFO("%-25s: 0x%x\n", "group.cur", l->group.cur); + DBG_INFO("%-25s: %d\n", "is_write", l->is_write); + DBG_INFO("%-25s: 0x%x\n", "stripesz", l->stripesz); + DBG_INFO("%-25s: 0x%x\n", "strip_sz", l->strip_sz); + DBG_INFO("%-25s: %d\n", "offload_to_mirror", l->offload_to_mirror); + DBG_INFO("%-25s: %d\n", "raid_level", l->raid_level); + +#endif /* DEBUG_AIO_LOCATOR */ } -/* Subroutine used to parse the scsi opcode and build the CDB for RAID bypass*/ -int -check_for_scsi_opcode(uint8_t *cdb, boolean_t *is_write, uint64_t *fst_blk, - uint32_t *blk_cnt) +/* build the aio cdb */ +inline void +pqisrc_aio_build_cdb(aio_req_locator_t *l, + uint32_t disk_blk_cnt, rcb_t *rcb, uint8_t *cdb) { + uint8_t cdb_length; - switch (cdb[0]) { - case SCMD_WRITE_6: - *is_write = true; - case SCMD_READ_6: - *fst_blk = (uint64_t)(((cdb[1] & 0x1F) << 16) | - (cdb[2] << 8) | cdb[3]); - *blk_cnt = (uint32_t)cdb[4]; - if (*blk_cnt == 0) - *blk_cnt = 256; - break; - case SCMD_WRITE_10: - *is_write = true; - case SCMD_READ_10: - *fst_blk = (uint64_t)GET_BE32(&cdb[2]); - *blk_cnt = (uint32_t)GET_BE16(&cdb[7]); - break; - case SCMD_WRITE_12: - *is_write = true; - case SCMD_READ_12: - *fst_blk = (uint64_t)GET_BE32(&cdb[2]); - *blk_cnt = GET_BE32(&cdb[6]); - break; - case SCMD_WRITE_16: - *is_write = true; - case SCMD_READ_16: - *fst_blk = GET_BE64(&cdb[2]); - *blk_cnt = GET_BE32(&cdb[10]); - break; - default: - /* Process via normal I/O path. */ - return PQI_STATUS_FAILURE; + if (l->block.disk_block > 0xffffffff) { + cdb[0] = l->is_write ? SCMD_WRITE_16 : SCMD_READ_16; + cdb[1] = 0; + PUT_BE64(l->block.disk_block, &cdb[2]); + PUT_BE32(disk_blk_cnt, &cdb[10]); + cdb[15] = 0; + cdb_length = 16; + } else { + cdb[0] = l->is_write ? SCMD_WRITE_10 : SCMD_READ_10; + cdb[1] = 0; + PUT_BE32(l->block.disk_block, &cdb[2]); + cdb[6] = 0; + PUT_BE16(disk_blk_cnt, &cdb[7]); + cdb[9] = 0; + cdb_length = 10; } - return PQI_STATUS_SUCCESS; + + rcb->cmdlen = cdb_length; + } /* print any arbitrary buffer of length total_len */ @@ -532,6 +1679,8 @@ if (user_buf == NULL) return; + memset(line_buf, 0, LINE_BUF_LEN); + /* Print index columns */ if (flags & PRINT_FLAG_HDR_COLUMN) { @@ -539,9 +1688,9 @@ { line_len += snprintf(line_buf + line_len, (LINE_BUF_LEN - line_len), "%02d ", ii); if ((line_len + 4) >= LINE_BUF_LEN) - break; + break; } - DBG_NOTE("%15.15s:[ %s ]\n", "header", line_buf); + DBG_INFO("%15.15s:[ %s ]\n", "header", line_buf); } /* Print index columns */ @@ -556,10 +1705,64 @@ buf_consumed++; if (buf_consumed >= total_len || (line_len + 4) >= LINE_BUF_LEN) - break; + break; } - DBG_NOTE("%15.15s:[ %s ]\n", msg, line_buf); + DBG_INFO("%15.15s:[ %s ]\n", msg, line_buf); + } +} + +/* print CDB with column header */ +void +pqisrc_show_cdb(pqisrc_softstate_t *softs, char *msg, rcb_t *rcb, uint8_t *cdb) +{ + /* Print the CDB contents */ + pqisrc_print_buffer(softs, msg, cdb, rcb->cmdlen, PRINT_FLAG_HDR_COLUMN); +} + +void +pqisrc_show_rcb_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg, void *err_info) +{ + pqi_scsi_dev_t *devp; + + if (rcb == NULL || rcb->dvp == NULL) + { + DBG_ERR("Invalid rcb or dev ptr! rcb=%p\n", rcb); + return; + } + + devp = rcb->dvp; + + /* print the host and mapped CDB */ + DBG_INFO("\n"); + DBG_INFO("----- Start Dump: %s -----\n", msg); + pqisrc_print_buffer(softs, "host cdb", OS_GET_CDBP(rcb), rcb->cmdlen, PRINT_FLAG_HDR_COLUMN); + if (OS_GET_CDBP(rcb) != rcb->cdbp) + pqisrc_print_buffer(softs, "aio mapped cdb", rcb->cdbp, rcb->cmdlen, 0); + + DBG_INFO("tag=0x%x dir=%u host_timeout=%ums\n", rcb->tag, + rcb->data_dir, (uint32_t)rcb->host_timeout_ms); + + DBG_INFO("BTL: %d:%d:%d addr=0x%x\n", devp->bus, devp->target, + devp->lun, GET_LE32(devp->scsi3addr)); + + if (rcb->path == AIO_PATH) + { + DBG_INFO("handle=0x%x\n", rcb->ioaccel_handle); + DBG_INFO("row=%u blk/row=%u index=%u map_row=%u\n", + rcb->row_num, rcb->blocks_per_row, rcb->raid_map_index, rcb->raid_map_row); + + if (err_info) + pqisrc_show_aio_error_info(softs, rcb, err_info); + } + + else /* RAID path */ + { + if (err_info) + pqisrc_show_raid_error_info(softs, rcb, err_info); } + + + DBG_INFO("----- Done -----\n\n"); } @@ -567,238 +1770,116 @@ * Function used to build and send RAID bypass request to the adapter */ int -pqisrc_send_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, - pqi_scsi_dev_t *device, rcb_t *rcb, uint8_t *cdb) +pqisrc_build_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, + pqi_scsi_dev_t *device, rcb_t *rcb) { - struct raid_map *raid_map; - boolean_t is_write = false; - uint32_t map_idx; - uint64_t fst_blk, lst_blk; - uint32_t blk_cnt, blks_per_row; - uint64_t fst_row, lst_row; - uint32_t fst_row_offset, lst_row_offset; - uint32_t fst_col, lst_col; - uint32_t r5or6_blks_per_row; - uint64_t r5or6_fst_row, r5or6_lst_row; - uint32_t r5or6_fst_row_offset, r5or6_lst_row_offset; - uint32_t r5or6_fst_col, r5or6_lst_col; - uint16_t data_disks_per_row, total_disks_per_row; - uint16_t layout_map_count; - uint32_t stripesz; - uint16_t strip_sz; - uint32_t fst_grp, lst_grp, cur_grp; - uint32_t map_row; - uint64_t disk_block; uint32_t disk_blk_cnt; - uint8_t cdb_length; - int offload_to_mirror; - int i; - DBG_FUNC(" IN \n"); - DBG_IO("!!!!!\n"); + struct aio_req_locator loc; + struct aio_req_locator *l = &loc; + int rc; + memset(l, 0, sizeof(*l)); - /* Check for eligible opcode, get LBA and block count. */ - memcpy(cdb, OS_GET_CDBP(rcb), rcb->cmdlen); + DBG_FUNC("IN\n"); - for(i = 0; i < rcb->cmdlen ; i++) - DBG_IO(" CDB [ %d ] : %x\n",i,cdb[i]); - if(check_for_scsi_opcode(cdb, &is_write, - &fst_blk, &blk_cnt) == PQI_STATUS_FAILURE) - return PQI_STATUS_FAILURE; - /* Check for write to non-RAID-0. */ - if (is_write && device->raid_level != SA_RAID_0) + if (device == NULL) { + DBG_INFO("device is NULL\n"); return PQI_STATUS_FAILURE; - - if(blk_cnt == 0) + } + if (device->raid_map == NULL) { + DBG_INFO("tag=0x%x BTL: %d:%d:%d Raid map is NULL\n", + rcb->tag, device->bus, device->target, device->lun); return PQI_STATUS_FAILURE; + } - lst_blk = fst_blk + blk_cnt - 1; - raid_map = device->raid_map; - - /* Check for invalid block or wraparound. */ - if (lst_blk >= GET_LE64((uint8_t *)&raid_map->volume_blk_cnt) || - lst_blk < fst_blk) + /* Check for eligible op, get LBA and block count. */ + rc = fill_lba_for_scsi_rw(softs, OS_GET_CDBP(rcb), l); + if (rc == PQI_STATUS_FAILURE) return PQI_STATUS_FAILURE; - data_disks_per_row = GET_LE16((uint8_t *)&raid_map->data_disks_per_row); - strip_sz = GET_LE16((uint8_t *)(&raid_map->strip_size)); - layout_map_count = GET_LE16((uint8_t *)(&raid_map->layout_map_count)); - - /* Calculate stripe information for the request. */ - blks_per_row = data_disks_per_row * strip_sz; - if (!blks_per_row) - return PQI_STATUS_FAILURE; /*Send the IO in raid path itself, not AIO or raidbypass*/ - - /* use __udivdi3 ? */ - fst_row = fst_blk / blks_per_row; - lst_row = lst_blk / blks_per_row; - fst_row_offset = (uint32_t)(fst_blk - (fst_row * blks_per_row)); - lst_row_offset = (uint32_t)(lst_blk - (lst_row * blks_per_row)); - fst_col = fst_row_offset / strip_sz; - lst_col = lst_row_offset / strip_sz; - - /* If this isn't a single row/column then give to the controller. */ - if (fst_row != lst_row || fst_col != lst_col) + if (l->is_write && !pqisrc_is_supported_write(softs, device)) return PQI_STATUS_FAILURE; - /* Proceeding with driver mapping. */ - total_disks_per_row = data_disks_per_row + - GET_LE16((uint8_t *)(&raid_map->metadata_disks_per_row)); - map_row = ((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) % - GET_LE16((uint8_t *)(&raid_map->row_cnt)); - map_idx = (map_row * total_disks_per_row) + fst_col; - - /* RAID 1 */ - if (device->raid_level == SA_RAID_1) { - if (device->offload_to_mirror) - map_idx += data_disks_per_row; - device->offload_to_mirror = !device->offload_to_mirror; - } else if (device->raid_level == SA_RAID_ADM) { - /* RAID ADM */ - /* - * Handles N-way mirrors (R1-ADM) and R10 with # of drives - * divisible by 3. - */ - offload_to_mirror = device->offload_to_mirror; - if (offload_to_mirror == 0) { - /* use physical disk in the first mirrored group. */ - map_idx %= data_disks_per_row; - } else { - do { - /* - * Determine mirror group that map_idx - * indicates. - */ - cur_grp = map_idx / data_disks_per_row; - - if (offload_to_mirror != cur_grp) { - if (cur_grp < - layout_map_count - 1) { - /* - * Select raid index from - * next group. - */ - map_idx += data_disks_per_row; - cur_grp++; - } else { - /* - * Select raid index from first - * group. - */ - map_idx %= data_disks_per_row; - cur_grp = 0; - } - } - } while (offload_to_mirror != cur_grp); - } - - /* Set mirror group to use next time. */ - offload_to_mirror = - (offload_to_mirror >= layout_map_count - 1) ? - 0 : offload_to_mirror + 1; - if(offload_to_mirror >= layout_map_count) - return PQI_STATUS_FAILURE; + l->raid_map = device->raid_map; + l->block.last = l->block.first + l->block.cnt - 1; + l->raid_level = device->raid_level; - device->offload_to_mirror = offload_to_mirror; - /* - * Avoid direct use of device->offload_to_mirror within this - * function since multiple threads might simultaneously - * increment it beyond the range of device->layout_map_count -1. - */ - } else if ((device->raid_level == SA_RAID_5 || - device->raid_level == SA_RAID_6) && layout_map_count > 1) { - /* RAID 50/60 */ - /* Verify first and last block are in same RAID group */ - r5or6_blks_per_row = strip_sz * data_disks_per_row; - stripesz = r5or6_blks_per_row * layout_map_count; + if (pqisrc_is_invalid_block(softs, l)) + return PQI_STATUS_FAILURE; - fst_grp = (fst_blk % stripesz) / r5or6_blks_per_row; - lst_grp = (lst_blk % stripesz) / r5or6_blks_per_row; + if (!pqisrc_calc_disk_params(softs, l, rcb)) + return PQI_STATUS_FAILURE; - if (fst_grp != lst_grp) - return PQI_STATUS_FAILURE; + if (!pqisrc_is_single_row_column(softs, l)) + return PQI_STATUS_FAILURE; - /* Verify request is in a single row of RAID 5/6 */ - fst_row = r5or6_fst_row = - fst_blk / stripesz; - r5or6_lst_row = lst_blk / stripesz; + if (!pqisrc_set_map_row_and_idx(softs, l, rcb)) + return PQI_STATUS_FAILURE; - if (r5or6_fst_row != r5or6_lst_row) - return PQI_STATUS_FAILURE; + /* Proceeding with driver mapping. */ - /* Verify request is in a single column */ - fst_row_offset = r5or6_fst_row_offset = - (uint32_t)((fst_blk % stripesz) % - r5or6_blks_per_row); - r5or6_lst_row_offset = - (uint32_t)((lst_blk % stripesz) % - r5or6_blks_per_row); + switch (device->raid_level) { + case SA_RAID_1: + case SA_RAID_ADM: + if (l->is_write) { + if (!pqisrc_set_write_mirrors(softs, device, l, rcb)) + return PQI_STATUS_FAILURE; + } else + pqisrc_set_read_mirror(softs, device, l); + break; + case SA_RAID_5: + case SA_RAID_6: + if (l->map.layout_map_count > 1 || l->is_write) { - fst_col = r5or6_fst_row_offset / strip_sz; - r5or6_fst_col = fst_col; - r5or6_lst_col = r5or6_lst_row_offset / strip_sz; + if (!pqisrc_is_r5or6_single_group(softs, l)) + return PQI_STATUS_FAILURE; - if (r5or6_fst_col != r5or6_lst_col) - return PQI_STATUS_FAILURE; + if (!pqisrc_is_r5or6_single_row(softs, l)) + return PQI_STATUS_FAILURE; - /* Request is eligible */ - map_row = - ((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) % - GET_LE16((uint8_t *)(&raid_map->row_cnt)); + if (!pqisrc_is_r5or6_single_column(softs, l)) + return PQI_STATUS_FAILURE; - map_idx = (fst_grp * - (GET_LE16((uint8_t *)(&raid_map->row_cnt)) * - total_disks_per_row)) + - (map_row * total_disks_per_row) + fst_col; + pqisrc_set_r5or6_row_and_index(l, rcb); + } + break; } - rcb->ioaccel_handle = raid_map->dev_data[map_idx].ioaccel_handle; - disk_block = GET_LE64((uint8_t *)(&raid_map->disk_starting_blk)) + - fst_row * strip_sz + - (fst_row_offset - fst_col * strip_sz); - disk_blk_cnt = blk_cnt; - - /* Handle differing logical/physical block sizes. */ - if (raid_map->phys_blk_shift) { - disk_block <<= raid_map->phys_blk_shift; - disk_blk_cnt <<= raid_map->phys_blk_shift; + if (l->map.idx >= RAID_MAP_MAX_ENTRIES) { + DBG_INFO("AIO ineligible: index exceeds max map entries"); + return PQI_STATUS_FAILURE; } - if (disk_blk_cnt > 0xffff) + rcb->ioaccel_handle = + l->raid_map->dev_data[l->map.idx].ioaccel_handle; + + if (!pqisrc_calc_aio_block(l)) return PQI_STATUS_FAILURE; - /* Build the new CDB for the physical disk I/O. */ - if (disk_block > 0xffffffff) { - cdb[0] = is_write ? SCMD_WRITE_16 : SCMD_READ_16; - cdb[1] = 0; - PUT_BE64(disk_block, &cdb[2]); - PUT_BE32(disk_blk_cnt, &cdb[10]); - cdb[14] = 0; - cdb[15] = 0; - cdb_length = 16; - } else { - cdb[0] = is_write ? SCMD_WRITE_10 : SCMD_READ_10; - cdb[1] = 0; - PUT_BE32(disk_block, &cdb[2]); - cdb[6] = 0; - PUT_BE16(disk_blk_cnt, &cdb[7]); - cdb[9] = 0; - cdb_length = 10; - } + disk_blk_cnt = pqisrc_handle_blk_size_diffs(l); + - if (GET_LE16((uint8_t *)(&raid_map->flags)) & + /* Set encryption flag if needed. */ + rcb->encrypt_enable = false; + if (GET_LE16((uint8_t *)(&l->raid_map->flags)) & RAID_MAP_ENCRYPTION_ENABLED) { - pqisrc_set_enc_info(&rcb->enc_info, raid_map, - fst_blk); + pqisrc_set_enc_info(&rcb->enc_info, l->raid_map, + l->block.first); rcb->encrypt_enable = true; - } else { - rcb->encrypt_enable = false; } - rcb->cmdlen = cdb_length; + if (pqisrc_aio_req_too_big(softs, device, rcb, l, disk_blk_cnt)) + return PQI_STATUS_FAILURE; + + /* set the cdb ptr to the local bypass cdb */ + rcb->cdbp = &rcb->bypass_cdb[0]; + + /* Build the new CDB for the physical disk I/O. */ + pqisrc_aio_build_cdb(l, disk_blk_cnt, rcb, rcb->cdbp); + pqisrc_aio_show_locator_info(softs, l, disk_blk_cnt, rcb); - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); return PQI_STATUS_SUCCESS; } @@ -806,6 +1887,7 @@ /* Function used to submit an AIO TMF to the adapter * DEVICE_RESET is not supported. */ + static int pqisrc_send_aio_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp, rcb_t *rcb, rcb_t *rcb_to_manage, int tmf_type) @@ -813,32 +1895,46 @@ int rval = PQI_STATUS_SUCCESS; pqi_aio_tmf_req_t tmf_req; ib_queue_t *op_ib_q = NULL; + boolean_t is_write; memset(&tmf_req, 0, sizeof(pqi_aio_tmf_req_t)); - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); tmf_req.header.iu_type = PQI_REQUEST_IU_AIO_TASK_MANAGEMENT; tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t); tmf_req.req_id = rcb->tag; tmf_req.error_idx = rcb->tag; tmf_req.nexus = devp->ioaccel_handle; - //memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun)); + /* memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun)); */ tmf_req.tmf = tmf_type; tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb); op_ib_q = &softs->op_aio_ib_q[0]; + is_write = pqisrc_cdb_is_write(rcb->cdbp); + + uint64_t lun = rcb->cm_ccb->ccb_h.target_lun; + if (lun && (rcb->dvp->is_multi_lun)) { + int_to_scsilun(lun, tmf_req.lun); + } + else { + memset(tmf_req.lun, 0, sizeof(tmf_req.lun)); + } if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { tmf_req.req_id_to_manage = rcb_to_manage->tag; tmf_req.nexus = rcb_to_manage->ioaccel_handle; } - DBG_INFO("tmf_req.header.iu_type : %x tmf_req.req_id_to_manage :%d \n",tmf_req.header.iu_type,tmf_req.req_id_to_manage); - DBG_INFO("tmf_req.req_id : %d tmf_req.nexus : %x tmf_req.tmf %x QID : %d\n",tmf_req.req_id,tmf_req.nexus,tmf_req.tmf,op_ib_q->q_id); + if (devp->raid_level == SA_RAID_1 || + devp->raid_level == SA_RAID_5 || + devp->raid_level == SA_RAID_6) { + if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK && is_write) + tmf_req.header.iu_type = PQI_REQUEST_IU_AIO_BYPASS_TASK_MGMT; + } DBG_WARN("aio tmf: iu_type=0x%x req_id_to_manage=0x%x\n", tmf_req.header.iu_type, tmf_req.req_id_to_manage); - DBG_WARN("aio tmf: req_id=0x%x nexus=0x%x tmf=0x%x QID=%d\n", + DBG_WARN("aio tmf: req_id=0x%x nexus=0x%x tmf=0x%x QID=%u\n", tmf_req.req_id, tmf_req.nexus, tmf_req.tmf, op_ib_q->q_id); rcb->path = AIO_PATH; @@ -858,13 +1954,13 @@ rcb->status = rval; } - if (rcb->status != REQUEST_SUCCESS) { + if (rcb->status != PQI_STATUS_SUCCESS) { DBG_ERR_BTL(devp, "Task Management failed tmf_type:%d " "stat:0x%x\n", tmf_type, rcb->status); rval = PQI_STATUS_FAILURE; } - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); return rval; } @@ -879,13 +1975,15 @@ memset(&tmf_req, 0, sizeof(pqi_raid_tmf_req_t)); - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); tmf_req.header.iu_type = PQI_REQUEST_IU_RAID_TASK_MANAGEMENT; tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t); tmf_req.req_id = rcb->tag; memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun)); + tmf_req.ml_device_lun_number = (uint8_t)rcb->cm_ccb->ccb_h.target_lun; + tmf_req.tmf = tmf_type; tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb); @@ -897,7 +1995,7 @@ if (softs->timeout_in_tmf && tmf_type == SOP_TASK_MANAGEMENT_LUN_RESET) { - /* OS_TMF_TIMEOUT_SEC - 1 to accommodate driver processing */ + /* OS_TMF_TIMEOUT_SEC - 1 to accomodate driver processing */ tmf_req.timeout_in_sec = OS_TMF_TIMEOUT_SEC - 1; /* if OS tmf timeout is 0, set minimum value for timeout */ if (!tmf_req.timeout_in_sec) @@ -905,6 +2003,10 @@ } op_ib_q = &softs->op_raid_ib_q[0]; + + DBG_WARN("raid tmf: iu_type=0x%x req_id_to_manage=%d\n", + tmf_req.header.iu_type, tmf_req.req_id_to_manage); + rcb->path = RAID_PATH; rcb->req_pending = true; /* Timedout tmf response goes here */ @@ -922,25 +2024,50 @@ rcb->status = rval; } - if (rcb->status != REQUEST_SUCCESS) { + if (rcb->status != PQI_STATUS_SUCCESS) { DBG_NOTE("Task Management failed tmf_type:%d " "stat:0x%x\n", tmf_type, rcb->status); rval = PQI_STATUS_FAILURE; } - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); return rval; } +void +dump_tmf_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg) +{ + uint32_t qid = rcb->req_q ? rcb->req_q->q_id : -1; + + DBG_INFO("%s: pending=%d path=%d tag=0x%x=%u qid=%u timeout=%ums\n", + msg, rcb->req_pending, rcb->path, rcb->tag, + rcb->tag, qid, (uint32_t)rcb->host_timeout_ms); +} + int pqisrc_send_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp, rcb_t *rcb, rcb_t *rcb_to_manage, int tmf_type) { int ret = PQI_STATUS_SUCCESS; - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); + + DBG_WARN("sending TMF. io outstanding=%u\n", + softs->max_outstanding_io - softs->taglist.num_elem); + + rcb->is_abort_cmd_from_host = true; rcb->softs = softs; + /* No target rcb for general purpose TMFs like LUN RESET */ + if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) + { + rcb_to_manage->host_wants_to_abort_this = true; + dump_tmf_details(softs, rcb_to_manage, "rcb_to_manage"); + } + + + dump_tmf_details(softs, rcb, "rcb"); + if(!devp->is_physical_device) { if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { if(rcb_to_manage->path == AIO_PATH) { @@ -962,93 +2089,236 @@ ret = pqisrc_send_raid_tmf(softs, devp, rcb, rcb_to_manage, tmf_type); } - DBG_FUNC("IN"); + DBG_FUNC("OUT\n"); return ret; } -/* - * Function used to build and send the vendor general request - * Used for configuring PQI feature bits between firmware and driver - */ -int -pqisrc_build_send_vendor_request( - pqisrc_softstate_t *softs, - pqi_vendor_general_request_t *request, - raid_path_error_info_elem_t *error_info) +/* return index into the global (softs) counters based on raid level */ +static counter_types_t +get_counter_index(rcb_t *rcb) { - int ret = PQI_STATUS_SUCCESS; - ib_queue_t *op_ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; - ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; + if (IS_AIO_PATH(rcb->dvp)) + return HBA_COUNTER; + + switch (rcb->dvp->raid_level) { + case SA_RAID_0: return RAID0_COUNTER; + case SA_RAID_1: + case SA_RAID_ADM: return RAID1_COUNTER; + case SA_RAID_5: return RAID5_COUNTER; + case SA_RAID_6: return RAID6_COUNTER; + case SA_RAID_UNKNOWN: + default: + { + static boolean_t asserted = false; + if (!asserted) + { + asserted = true; + ASSERT(rcb->path == RAID_PATH); + ASSERT(0); + } + return UNKNOWN_COUNTER; + } + } +} - rcb_t *rcb = NULL; +/* return the counter type as ASCII-string */ +static char * +counter_type_to_raid_ascii(counter_types_t type) +{ + switch (type) + { + case UNKNOWN_COUNTER: return "Unknown"; + case HBA_COUNTER: return "HbaPath"; + case RAID0_COUNTER: return "Raid0"; + case RAID1_COUNTER: return "Raid1"; + case RAID5_COUNTER: return "Raid5"; + case RAID6_COUNTER: return "Raid6"; + default: return "Unsupported"; + } +} - uint16_t request_id = 0; +/* return the path as ASCII-string */ +char * +io_path_to_ascii(IO_PATH_T path) +{ + switch (path) + { + case AIO_PATH: return "Aio"; + case RAID_PATH: return "Raid"; + default: return "Unknown"; + } +} - /* Get the tag */ - request_id = pqisrc_get_tag(&softs->taglist); - if (INVALID_ELEM == request_id) { - DBG_ERR("Tag not available\n"); - ret = PQI_STATUS_FAILURE; - goto err_notag; +/* return the io type as ASCII-string */ +static char * +io_type_to_ascii(io_type_t io_type) +{ + switch (io_type) + { + case UNKNOWN_IO_TYPE: return "Unknown"; + case READ_IO_TYPE: return "Read"; + case WRITE_IO_TYPE: return "Write"; + case NON_RW_IO_TYPE: return "NonRW"; + default: return "Unsupported"; } +} + - ((pqi_vendor_general_request_t *)request)->request_id = request_id; - ((pqi_vendor_general_request_t *)request)->response_queue_id = ob_q->q_id; +/* return the io type based on cdb */ +io_type_t +get_io_type_from_cdb(uint8_t *cdb) +{ + if (cdb == NULL) + return UNKNOWN_IO_TYPE; - rcb = &softs->rcb[request_id]; + else if (pqisrc_cdb_is_read(cdb)) + return READ_IO_TYPE; - rcb->req_pending = true; - rcb->tag = request_id; + else if (pqisrc_cdb_is_write(cdb)) + return WRITE_IO_TYPE; - ret = pqisrc_submit_cmnd(softs, op_ib_q, request); + return NON_RW_IO_TYPE; +} - if (ret != PQI_STATUS_SUCCESS) { - DBG_ERR("Unable to submit command\n"); - goto err_out; - } +/* increment this counter based on path and read/write */ +OS_ATOMIC64_T +increment_this_counter(io_counters_t *pcounter, IO_PATH_T path, io_type_t io_type) +{ + OS_ATOMIC64_T ret_val; - ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_CMD_TIMEOUT); - if (ret != PQI_STATUS_SUCCESS) { - DBG_ERR("Management request timed out!\n"); - goto err_out; + if (path == AIO_PATH) + { + if (io_type == READ_IO_TYPE) + ret_val = OS_ATOMIC64_INC(&pcounter->aio_read_cnt); + else if (io_type == WRITE_IO_TYPE) + ret_val = OS_ATOMIC64_INC(&pcounter->aio_write_cnt); + else + ret_val = OS_ATOMIC64_INC(&pcounter->aio_non_read_write); + } + else + { + if (io_type == READ_IO_TYPE) + ret_val = OS_ATOMIC64_INC(&pcounter->raid_read_cnt); + else if (io_type == WRITE_IO_TYPE) + ret_val = OS_ATOMIC64_INC(&pcounter->raid_write_cnt); + else + ret_val = OS_ATOMIC64_INC(&pcounter->raid_non_read_write); } - ret = rcb->status; - if (ret) { - ret = PQI_STATUS_FAILURE; - if(error_info) { - // TODO: config table err handling. - } - } else { - if(error_info) { - ret = PQI_STATUS_SUCCESS; - memset(error_info, 0, sizeof(*error_info)); - } + return ret_val; +} + +/* increment appropriate counter(s) anytime we post a new request */ +static void +pqisrc_increment_io_counters(pqisrc_softstate_t *softs, rcb_t *rcb) +{ + io_type_t io_type = get_io_type_from_cdb(rcb->cdbp); + counter_types_t type_index = get_counter_index(rcb); + io_counters_t *pcounter = &softs->counters[type_index]; + OS_ATOMIC64_T ret_val; + + ret_val = increment_this_counter(pcounter, rcb->path, io_type); + +#if 1 /* leave this enabled while we gain confidence for each io path */ + if (ret_val == 1) + { + char *raid_type = counter_type_to_raid_ascii(type_index); + char *path = io_path_to_ascii(rcb->path); + char *io_ascii = io_type_to_ascii(io_type); + + DBG_INFO("Got first path/type hit. " + "Path=%s RaidType=%s IoType=%s\n", + path, raid_type, io_ascii); } +#endif - os_reset_rcb(rcb); - pqisrc_put_tag(&softs->taglist, ((pqi_vendor_general_request_t *)request)->request_id); - DBG_FUNC("OUT\n"); - return ret; + /* @todo future: may want to make a per-dev counter */ +} -err_out: - DBG_ERR("Vender general request submission failed.\n"); - os_reset_rcb(rcb); - pqisrc_put_tag(&softs->taglist, ((pqi_vendor_general_request_t *)request)->request_id); -err_notag: - DBG_FUNC("FAILED \n"); - return ret; +/* public routine to print a particular counter with header msg */ +void +print_this_counter(pqisrc_softstate_t *softs, io_counters_t *pcounter, char *msg) +{ + io_counters_t counter; + uint32_t percent_reads; + uint32_t percent_aio; + + if (!softs->log_io_counters) + return; + + /* Use a cached copy so percentages are based on the data that is printed */ + memcpy(&counter, pcounter, sizeof(counter)); + + DBG_NOTE("Counter: %s (ptr=%p)\n", msg, pcounter); + + percent_reads = CALC_PERCENT_VS(counter.aio_read_cnt + counter.raid_read_cnt, + counter.aio_write_cnt + counter.raid_write_cnt); + + percent_aio = CALC_PERCENT_VS(counter.aio_read_cnt + counter.aio_write_cnt, + counter.raid_read_cnt + counter.raid_write_cnt); + + DBG_NOTE(" R/W Percentages: Reads=%3u%% AIO=%3u%%\n", percent_reads, percent_aio); + + /* Print the Read counts */ + percent_aio = CALC_PERCENT_VS(counter.aio_read_cnt, counter.raid_read_cnt); + DBG_NOTE(" Reads : AIO=%8u(%3u%%) RAID=%8u\n", + (uint32_t)counter.aio_read_cnt, percent_aio, (uint32_t)counter.raid_read_cnt); + + /* Print the Write counts */ + percent_aio = CALC_PERCENT_VS(counter.aio_write_cnt, counter.raid_write_cnt); + DBG_NOTE(" Writes: AIO=%8u(%3u%%) RAID=%8u\n", + (uint32_t)counter.aio_write_cnt, percent_aio, (uint32_t)counter.raid_write_cnt); + + /* Print the Non-Rw counts */ + percent_aio = CALC_PERCENT_VS(counter.aio_non_read_write, counter.raid_non_read_write); + DBG_NOTE(" Non-RW: AIO=%8u(%3u%%) RAID=%8u\n", + (uint32_t)counter.aio_non_read_write, percent_aio, (uint32_t)counter.raid_non_read_write); } -/* return the path as ASCII-string */ -char * -io_path_to_ascii(IO_PATH_T path) +/* return true if buffer is all zeroes */ +boolean_t +is_buffer_zero(void *buffer, uint32_t size) { - switch (path) + char *buf = buffer; + DWORD ii; + + if (buffer == NULL || size == 0) + return false; + + for (ii = 0; ii < size; ii++) { - case AIO_PATH: return "Aio"; - case RAID_PATH: return "Raid"; - default: return "Unknown"; + if (buf[ii] != 0x00) + return false; + } + return true; +} + +/* public routine to print a all global counter types */ +void +print_all_counters(pqisrc_softstate_t *softs, uint32_t flags) +{ + int ii; + io_counters_t *pcounter; + char *raid_type; + + for (ii = 0; ii < MAX_IO_COUNTER; ii++) + { + pcounter = &softs->counters[ii]; + raid_type = counter_type_to_raid_ascii(ii); + + if ((flags & COUNTER_FLAG_ONLY_NON_ZERO) && + is_buffer_zero(pcounter, sizeof(*pcounter))) + { + continue; + } + + print_this_counter(softs, pcounter, raid_type); + } + + if (flags & COUNTER_FLAG_CLEAR_COUNTS) + { + DBG_NOTE("Clearing all counters\n"); + memset(softs->counters, 0, sizeof(softs->counters)); } } diff --git a/sys/dev/smartpqi/smartpqi_response.c b/sys/dev/smartpqi/smartpqi_response.c --- a/sys/dev/smartpqi/smartpqi_response.c +++ b/sys/dev/smartpqi/smartpqi_response.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,12 +32,29 @@ void pqisrc_process_internal_raid_response_success(pqisrc_softstate_t *softs,rcb_t *rcb) { - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; rcb->req_pending = false; - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); +} + +/* Safely determines if cdb is available and if so, will return SCSI opcode or + BMIC cmd if BMIC op code is detected */ +uint8_t +pqisrc_get_cmd_from_rcb(rcb_t *rcb) +{ + uint8_t opcode = 0xFF; + + if (rcb && rcb->cdbp) + { + opcode = rcb->cdbp[0]; + if (IS_BMIC_OPCODE(opcode)) + return rcb->cdbp[6]; + } + + return opcode; } /* @@ -49,33 +66,40 @@ { raid_path_error_info_elem_t error_info; - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); rcb->error_info = (char *) (softs->err_buf_dma_mem.virt_addr) + (err_idx * PQI_ERROR_BUFFER_ELEMENT_LENGTH); memcpy(&error_info, rcb->error_info, sizeof(error_info)); - DBG_INFO("error_status 0x%x data_in_result 0x%x data_out_result 0x%x\n", - error_info.status, error_info.data_in_result, error_info.data_out_result); - - rcb->status = REQUEST_FAILED; + rcb->status = PQI_STATUS_TIMEOUT; switch (error_info.data_out_result) { case PQI_RAID_DATA_IN_OUT_GOOD: if (error_info.status == PQI_RAID_DATA_IN_OUT_GOOD) - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; break; case PQI_RAID_DATA_IN_OUT_UNDERFLOW: if (error_info.status == PQI_RAID_DATA_IN_OUT_GOOD || error_info.status == PQI_RAID_STATUS_CHECK_CONDITION) - rcb->status = REQUEST_SUCCESS; + rcb->status = PQI_STATUS_SUCCESS; break; + default: + DBG_WARN("error_status 0x%x data_in_result 0x%x data_out_result 0x%x cmd rcb tag 0x%x\n", + error_info.status, error_info.data_in_result, error_info.data_out_result, rcb->tag); + } + + if (rcb->status != PQI_STATUS_SUCCESS) + { + DBG_INFO("error_status=0x%x data_in=0x%x data_out=0x%x detail=0x%x\n", + error_info.status, error_info.data_in_result, error_info.data_out_result, + pqisrc_get_cmd_from_rcb(rcb)); } rcb->req_pending = false; - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); } /* @@ -84,11 +108,11 @@ void pqisrc_process_io_response_success(pqisrc_softstate_t *softs, rcb_t *rcb) { - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); os_io_response_success(rcb); - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); } static void @@ -120,6 +144,23 @@ } } +/* Suppress common errors unless verbose debug flag is on */ +boolean_t +suppress_innocuous_error_prints(pqisrc_softstate_t *softs, rcb_t *rcb) +{ + uint8_t opcode = rcb->cdbp ? rcb->cdbp[0] : 0xFF; + + if ((opcode == SCSI_INQUIRY || /* 0x12 */ + opcode == SCSI_MODE_SENSE || /* 0x1a */ + opcode == SCSI_REPORT_LUNS || /* 0xa0 */ + opcode == SCSI_LOG_SENSE || /* 0x4d */ + opcode == SCSI_ATA_PASSTHRU16) /* 0x85 */ + && (softs->err_resp_verbose == false)) + return true; + + return false; +} + static void pqisrc_show_sense_data_simple(pqisrc_softstate_t *softs, rcb_t *rcb, sense_data_u_t *sense_data) { @@ -136,6 +177,9 @@ void pqisrc_show_sense_data_full(pqisrc_softstate_t *softs, rcb_t *rcb, sense_data_u_t *sense_data) { + if (suppress_innocuous_error_prints(softs, rcb)) + return; + pqisrc_print_buffer(softs, "sense data", sense_data, 32, 0); pqisrc_show_sense_data_simple(softs, rcb, sense_data); @@ -144,6 +188,105 @@ } +/* dumps the aio error info and sense data then breaks down the output */ +void +pqisrc_show_aio_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, aio_path_error_info_elem_t *aio_err) +{ + DBG_NOTE("\n"); + DBG_NOTE("aio err: status=0x%x serv_resp=0x%x data_pres=0x%x data_len=0x%x\n", + aio_err->status, aio_err->service_resp, aio_err->data_pres, aio_err->data_len); + + pqisrc_print_buffer(softs, "aio err info", aio_err, + offsetof(aio_path_error_info_elem_t, data), PRINT_FLAG_HDR_COLUMN); + + pqisrc_show_sense_data_full(softs, rcb, &aio_err->sense_data); +} + + +/* dumps the raid error info and sense data then breaks down the output */ +void +pqisrc_show_raid_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, raid_path_error_info_elem_t *raid_err) +{ + DBG_NOTE("\n"); + DBG_NOTE("raid err: data_in=0x%x out=0x%x status=0x%x sense_len=0x%x resp_len=0x%x\n", + raid_err->data_in_result, raid_err->data_in_result, + raid_err->status, raid_err->sense_data_len, raid_err->resp_data_len); + + pqisrc_print_buffer(softs, "raid err info", raid_err, + offsetof(raid_path_error_info_elem_t, data), PRINT_FLAG_HDR_COLUMN); + + pqisrc_show_sense_data_full(softs, rcb, &raid_err->sense_data); +} + +/* return true if this an innocuous error */ +boolean_t +pqisrc_is_innocuous_error(pqisrc_softstate_t *softs, rcb_t *rcb, void *err_info) +{ + uint8_t opcode = rcb->cdbp ? rcb->cdbp[0] : 0xFF; + + /* These SCSI cmds are frequently cause "underrun" and other minor "error" + conditions while determining log page length, support, etc. */ + if (opcode != SCSI_INQUIRY && /* 0x12 */ + opcode != SCSI_MODE_SENSE && /* 0x1a */ + opcode != SCSI_REPORT_LUNS && /* 0xa0 */ + opcode != SCSI_LOG_SENSE && /* 0x4d */ + opcode != SCSI_ATA_PASSTHRU16) /* 0x85 */ + { + return false; + } + + /* treat all cmds above as innocuous unless verbose flag is set. */ + if (softs->err_resp_verbose == false) + return true; + + if (rcb->path == AIO_PATH) + { + aio_path_error_info_elem_t *aio_err = err_info; + uint8_t key, asc, ascq; + + /* Byte[0]=Status=0x51, Byte[1]=service_resp=0x01 */ + if (aio_err->status == PQI_AIO_STATUS_UNDERRUN && + aio_err->service_resp == PQI_AIO_SERV_RESPONSE_FAILURE) + { + return true; + } + + /* get the key info so we can apply more filters... */ + pqisrc_extract_sense_data(&aio_err->sense_data, &key, &asc, &ascq); + + /* Seeing a lot of invalid field in CDB for REPORT LUNs on AIO path. + Example CDB = a0 00 11 00 00 00 00 00 20 08 00 00 + So filter out the full dump info for now. Also wonder if we should + just send REPORT LUNS to raid path? */ + if (opcode == SCSI_REPORT_LUNS && + key == 5 && asc == 0x24) + { + pqisrc_show_sense_data_simple(softs, rcb, &aio_err->sense_data); + return true; + } + + /* may want to return true here eventually? */ + } + else + { + raid_path_error_info_elem_t *raid_err = err_info; + + /* Byte[1]=data_out=0x01 */ + if (raid_err->data_out_result == PQI_RAID_DATA_IN_OUT_UNDERFLOW) + return true; + + /* We get these a alot: leave a tiny breadcrumb about the error, + but don't do full spew about it */ + if (raid_err->status == PQI_AIO_STATUS_CHECK_CONDITION) + { + pqisrc_show_sense_data_simple(softs, rcb, &raid_err->sense_data); + return true; + } + } + + return false; +} + /* * Process the error info for AIO in the case of failure. */ @@ -153,20 +296,30 @@ { aio_path_error_info_elem_t *err_info = NULL; - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); + + ASSERT(rcb->path == AIO_PATH); err_info = (aio_path_error_info_elem_t*) softs->err_buf_dma_mem.virt_addr + err_idx; if(err_info == NULL) { - DBG_ERR("err_info structure is NULL err_idx :%x", err_idx); + DBG_ERR("err_info structure is NULL err_idx :%x\n", err_idx); return; } + /* filter out certain underrun/success "errors" from printing */ + if (!pqisrc_is_innocuous_error(softs, rcb, err_info)) { + + if (softs->err_resp_verbose == true) + pqisrc_show_rcb_details(softs, rcb, + "aio error", err_info); + } + os_aio_response_error(rcb, err_info); - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); } /* @@ -178,20 +331,31 @@ { raid_path_error_info_elem_t *err_info = NULL; - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); + + ASSERT(rcb->path == RAID_PATH); err_info = (raid_path_error_info_elem_t*) softs->err_buf_dma_mem.virt_addr + err_idx; if(err_info == NULL) { - DBG_ERR("err_info structure is NULL err_idx :%x", err_idx); + DBG_ERR("err_info structure is NULL err_idx :%x\n", err_idx); return; } + /* filter out certain underrun/success "errors" from printing */ + if (!pqisrc_is_innocuous_error(softs, rcb, err_info)) { + + if( softs->err_resp_verbose == true ) + pqisrc_show_rcb_details(softs, rcb, + "raid error", err_info); + + } + os_raid_response_error(rcb, err_info); - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); } /* @@ -201,7 +365,7 @@ pqisrc_process_task_management_response(pqisrc_softstate_t *softs, pqi_tmf_resp_t *tmf_resp) { - int ret = REQUEST_SUCCESS; + int ret = PQI_STATUS_SUCCESS; uint32_t tag = (uint32_t)tmf_resp->req_id; rcb_t *rcb = &softs->rcb[tag]; @@ -212,18 +376,19 @@ switch (tmf_resp->resp_code) { case SOP_TASK_MANAGEMENT_FUNCTION_COMPLETE: case SOP_TASK_MANAGEMENT_FUNCTION_SUCCEEDED: - ret = REQUEST_SUCCESS; + ret = PQI_STATUS_SUCCESS; break; default: - DBG_WARN("TMF Failed, Response code : 0x%x\n", tmf_resp->resp_code); - ret = REQUEST_FAILED; + DBG_ERR("Tag #0x%08x TMF Failed, Response code : 0x%x\n", + rcb->tag, tmf_resp->resp_code); + ret = PQI_STATUS_TIMEOUT; break; } rcb->status = ret; rcb->req_pending = false; - DBG_FUNC("OUT"); + DBG_FUNC("OUT\n"); return ret; } @@ -231,7 +396,7 @@ pqisrc_process_vendor_general_response(pqi_vendor_general_response_t *response) { - int ret = REQUEST_SUCCESS; + int ret = PQI_STATUS_SUCCESS; switch(response->status) { case PQI_VENDOR_RESPONSE_IU_SUCCESS: @@ -239,7 +404,7 @@ case PQI_VENDOR_RESPONSE_IU_UNSUCCESS: case PQI_VENDOR_RESPONSE_IU_INVALID_PARAM: case PQI_VENDOR_RESPONSE_IU_INSUFF_RESRC: - ret = REQUEST_FAILED; + ret = PQI_STATUS_TIMEOUT; break; } @@ -256,21 +421,22 @@ ob_queue_t *ob_q; struct pqi_io_response *response; uint32_t oq_pi, oq_ci; - pqi_scsi_dev_t *dvp = NULL; + pqi_scsi_dev_t *dvp = NULL; + - DBG_FUNC("IN"); + DBG_FUNC("IN\n"); ob_q = &softs->op_ob_q[oq_id - 1]; /* zero for event Q */ oq_ci = ob_q->ci_local; oq_pi = *(ob_q->pi_virt_addr); - DBG_INFO("ci : %d pi : %d qid : %d\n", oq_ci, oq_pi, ob_q->q_id); + DBG_IO("ci : %u pi : %u qid : %u\n", oq_ci, oq_pi, ob_q->q_id); while (1) { + boolean_t os_scsi_cmd = false; rcb_t *rcb = NULL; uint32_t tag = 0; uint32_t offset; - boolean_t os_scsi_cmd = false; if (oq_pi == oq_ci) break; @@ -282,7 +448,7 @@ rcb = &softs->rcb[tag]; /* Make sure we are processing a valid response. */ if ((rcb->tag != tag) || (rcb->req_pending == false)) { - DBG_ERR("No such request pending with tag : %x", tag); + DBG_ERR("No such request pending with tag : %x rcb->tag : %x", tag, rcb->tag); oq_ci = (oq_ci + 1) % ob_q->num_elem; break; } @@ -291,13 +457,21 @@ * pqisrc_wait_on_condition(softs,rcb,timeout). */ if (rcb->timedout) { - DBG_WARN("timed out request completing from firmware, driver already completed it with failure , free the tag %d\n", tag); + DBG_WARN("timed out request completing from firmware, driver already completed it with failure , free the tag 0x%x\n", tag); oq_ci = (oq_ci + 1) % ob_q->num_elem; os_reset_rcb(rcb); pqisrc_put_tag(&softs->taglist, tag); break; } + if (rcb->host_wants_to_abort_this) + { + DBG_INFO("cmd that was aborted came back. tag=%u\n", rcb->tag); + } + if (rcb->is_abort_cmd_from_host) + { + DBG_INFO("abort cmd came back. tag=%u\n", rcb->tag); + } if (IS_OS_SCSICMD(rcb)) { dvp = rcb->dvp; if (dvp) @@ -306,8 +480,7 @@ DBG_WARN("Received IO completion for the Null device!!!\n"); } - - DBG_INFO("response.header.iu_type : %x \n", response->header.iu_type); + DBG_IO("response.header.iu_type : %x \n", response->header.iu_type); switch (response->header.iu_type) { case PQI_RESPONSE_IU_RAID_PATH_IO_SUCCESS: @@ -315,7 +488,6 @@ rcb->success_cmp_callback(softs, rcb); if (os_scsi_cmd) pqisrc_decrement_device_active_io(softs, dvp); - break; case PQI_RESPONSE_IU_RAID_PATH_IO_ERROR: case PQI_RESPONSE_IU_AIO_PATH_IO_ERROR: @@ -345,6 +517,6 @@ ob_q->ci_local = oq_ci; PCI_MEM_PUT32(softs, ob_q->ci_register_abs, - ob_q->ci_register_offset, ob_q->ci_local ); - DBG_FUNC("OUT"); + ob_q->ci_register_offset, ob_q->ci_local ); + DBG_FUNC("OUT\n"); } diff --git a/sys/dev/smartpqi/smartpqi_sis.c b/sys/dev/smartpqi/smartpqi_sis.c --- a/sys/dev/smartpqi/smartpqi_sis.c +++ b/sys/dev/smartpqi/smartpqi_sis.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,6 +39,7 @@ db_reg &= ~SIS_ENABLE_MSIX; PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, LEGACY_SIS_IDBR, db_reg); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ DBG_FUNC("OUT\n"); } @@ -55,6 +56,7 @@ db_reg |= SIS_ENABLE_INTX; PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, LEGACY_SIS_IDBR, db_reg); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ if (pqisrc_sis_wait_for_db_bit_to_clear(softs,SIS_ENABLE_INTX) != PQI_STATUS_SUCCESS) { DBG_ERR("Failed to wait for enable intx db bit to clear\n"); @@ -74,6 +76,7 @@ db_reg &= ~SIS_ENABLE_INTX; PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, LEGACY_SIS_IDBR, db_reg); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ DBG_FUNC("OUT\n"); } @@ -90,7 +93,7 @@ break; case INTR_TYPE_MSI: case INTR_TYPE_MSIX: - sis_disable_msix(softs); + sis_disable_msix(softs); break; default: DBG_ERR("Inerrupt mode none!\n"); @@ -124,6 +127,7 @@ PCI_MEM_PUT32(softs, &softs->ioa_reg->host_to_ioa_db, LEGACY_SIS_IDBR, LE_32(REENABLE_SIS)); + OS_SLEEP(1000); /* 1 ms delay for PCI W/R ordering issue */ COND_WAIT(((PCI_MEM_GET32(softs, &softs->ioa_reg->ioa_to_host_db, LEGACY_SIS_ODBR_R) & REENABLE_SIS) == 0), timeout) @@ -284,6 +288,21 @@ softs->pqi_cap.max_sg_elem = mb[1]; softs->pqi_cap.max_transfer_size = mb[2]; softs->pqi_cap.max_outstanding_io = mb[3]; + if (softs->pqi_cap.max_outstanding_io > + PQISRC_MAX_OUTSTANDING_REQ) { + DBG_WARN("Controller-supported max outstanding " + "commands %u reduced to %d to align with " + "driver-supported max.\n", + softs->pqi_cap.max_outstanding_io, + PQISRC_MAX_OUTSTANDING_REQ); + softs->pqi_cap.max_outstanding_io = + PQISRC_MAX_OUTSTANDING_REQ; + } + +#ifdef DEVICE_HINT + bsd_set_hint_adapter_cap(softs); +#endif + softs->pqi_cap.conf_tab_off = mb[4]; softs->pqi_cap.conf_tab_sz = mb[5]; @@ -295,6 +314,11 @@ softs->pqi_cap.max_transfer_size); DBG_INIT("max_outstanding_io = %x\n", softs->pqi_cap.max_outstanding_io); + /* DBG_INIT("config_table_offset = %x\n", + softs->pqi_cap.conf_tab_off); + DBG_INIT("config_table_size = %x\n", + softs->pqi_cap.conf_tab_sz); + */ } DBG_FUNC("OUT\n"); @@ -318,7 +342,7 @@ memset(&init_struct_mem, 0, sizeof(struct dma_mem)); init_struct_mem.size = sizeof(struct init_base_struct); init_struct_mem.align = PQISRC_INIT_STRUCT_DMA_ALIGN; - init_struct_mem.tag = "init_struct"; + os_strlcpy(init_struct_mem.tag, "init_struct", sizeof(init_struct_mem.tag)); ret = os_dma_mem_alloc(softs, &init_struct_mem); if (ret) { DBG_ERR("Failed to Allocate error buffer ret : %d\n", @@ -337,7 +361,7 @@ /* Allocate error buffer */ softs->err_buf_dma_mem.align = PQISRC_ERR_BUF_DMA_ALIGN; - softs->err_buf_dma_mem.tag = "error_buffer"; + os_strlcpy(softs->err_buf_dma_mem.tag, "error_buffer", sizeof(softs->err_buf_dma_mem.tag)); ret = os_dma_mem_alloc(softs, &softs->err_buf_dma_mem); if (ret) { DBG_ERR("Failed to Allocate error buffer ret : %d\n", @@ -422,7 +446,7 @@ if (ext_prop & SIS_SUPPORT_PQI_RESET_QUIESCE) softs->pqi_reset_quiesce_allowed = true; - /* Send GET_COMM_PREFERRED_SETTINGS (26h) */ + /* Send GET_COMM_PREFERRED_SETTINGS (26h), TODO : is it required */ ret = pqisrc_get_preferred_settings(softs); if (ret) { DBG_ERR("Failed to get adapter pref settings\n"); diff --git a/sys/dev/smartpqi/smartpqi_structures.h b/sys/dev/smartpqi/smartpqi_structures.h --- a/sys/dev/smartpqi/smartpqi_structures.h +++ b/sys/dev/smartpqi/smartpqi_structures.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,9 @@ #ifndef _PQI_STRUCTURES_H #define _PQI_STRUCTURES_H + +#include "smartpqi_defines.h" + struct bmic_host_wellness_driver_version { uint8_t start_tag[4]; uint8_t driver_version_tag[2]; @@ -36,6 +39,7 @@ }OS_ATTRIBUTE_PACKED; + struct bmic_host_wellness_time { uint8_t start_tag[4]; uint8_t time_tag[2]; @@ -53,6 +57,7 @@ }OS_ATTRIBUTE_PACKED; + /* As per PQI Spec pqi-2r00a , 6.2.2. */ /* device capability register , for admin q table 24 */ @@ -187,15 +192,17 @@ /* Memory descriptor for DMA memory allocation */ typedef struct dma_mem { void *virt_addr; - dma_addr_t dma_addr; + dma_addr_t dma_addr; uint32_t size; uint32_t align; - char *tag; - bus_dma_tag_t dma_tag; - bus_dmamap_t dma_map; + char tag[32]; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; }dma_mem_t; -/* Lock should be 8 byte aligned */ +/* Lock should be 8 byte aligned + TODO : need to apply aligned for lock alone ? +*/ #ifndef LOCKFREE_STACK @@ -433,27 +440,6 @@ uint32_t additional_event_id; }; -typedef struct pqi_vendor_general_request { - iu_header_t header; - uint16_t response_queue_id; - uint8_t work_area[2]; - uint16_t request_id; - uint16_t function_code; - union { - struct { - uint16_t first_section; - uint16_t last_section; - uint8_t reserved1[48]; - } OS_ATTRIBUTE_PACKED config_table_update; - - struct { - uint64_t buffer_address; - uint32_t buffer_length; - uint8_t reserved2[40]; - } OS_ATTRIBUTE_PACKED ofa_memory_allocation; - } data; -} OS_ATTRIBUTE_PACKED pqi_vendor_general_request_t; - typedef struct pqi_vendor_general_response { iu_header_t header; uint16_t reserved1; @@ -474,29 +460,30 @@ } OS_ATTRIBUTE_PACKED op_q_params; + /* "Fixed Format Sense Data" (0x70 or 0x71) (Table 45 in SPC5) */ typedef struct sense_data_fixed { - uint8_t response_code : 7; // Byte 0, 0x70 or 0x71 - uint8_t valid : 1; // Byte 0, bit 7 - uint8_t byte_1; // Byte 1 - uint8_t sense_key : 4; // Byte 2, bit 0-3 (Key) - uint8_t byte_2_other : 4; // Byte 2, bit 4-7 - uint32_t information; // Byte 3-6, big-endian like block # in CDB - uint8_t addtnl_length; // Byte 7 - uint8_t cmd_specific[4]; // Byte 8-11 - uint8_t sense_code; // Byte 12 (ASC) - uint8_t sense_qual; // Byte 13 (ASCQ) - uint8_t fru_code; // Byte 14 - uint8_t sense_key_specific[3]; // Byte 15-17 - uint8_t addtnl_sense[1]; // Byte 18+ + uint8_t response_code : 7; /* Byte 0, 0x70 or 0x71 */ + uint8_t valid : 1; /* Byte 0, bit 7 */ + uint8_t byte_1; /* Byte 1 */ + uint8_t sense_key : 4; /* Byte 2, bit 0-3 (Key) */ + uint8_t byte_2_other : 4; /* Byte 2, bit 4-7 */ + uint32_t information; /* Byte 3-6, big-endian like block # in CDB */ + uint8_t addtnl_length; /* Byte 7 */ + uint8_t cmd_specific[4]; /* Byte 8-11 */ + uint8_t sense_code; /* Byte 12 (ASC) */ + uint8_t sense_qual; /* Byte 13 (ASCQ) */ + uint8_t fru_code; /* Byte 14 */ + uint8_t sense_key_specific[3]; /* Byte 15-17 */ + uint8_t addtnl_sense[1]; /* Byte 18+ */ } OS_ATTRIBUTE_PACKED sense_data_fixed_t; /* Generic Sense Data Descriptor (Table 29 in SPC5) */ typedef struct descriptor_entry { - uint8_t desc_type; // Byte 9/0 - uint8_t desc_type_length; // Byte 10/1 + uint8_t desc_type; /* Byte 9/0 */ + uint8_t desc_type_length; /* Byte 10/1 */ union { /* Sense data descriptor specific */ @@ -504,10 +491,10 @@ /* Information (Type 0) (Table 31 is SPC5) */ struct { - uint8_t byte_2_rsvd : 7; // Byte 11/2 - uint8_t valid : 1; // Byte 11/2, bit 7 - uint8_t byte_3; // Byte 12/3 - uint8_t information[8]; // Byte 13-20/4-11 + uint8_t byte_2_rsvd : 7; /* Byte 11/2 */ + uint8_t valid : 1; /* Byte 11/2, bit 7 */ + uint8_t byte_3; /* Byte 12/3 */ + uint8_t information[8]; /* Byte 13-20/4-11 */ } OS_ATTRIBUTE_PACKED type_0; }u; @@ -515,15 +502,15 @@ /* "Descriptor Format Sense Data" (0x72 or 0x73) (Table 28 in SPC5) */ typedef struct sense_data_descriptor { - uint8_t response_code : 7; // Byte 0, 0x72 or 0x73 - uint8_t byte_0_rsvd: 1; // Byte 0, bit 7 - uint8_t sense_key : 4; // Byte 1, bit 0-3 (Key) - uint8_t byte_1_other : 4; // Byte 1, bit 4-7 - uint8_t sense_code; // Byte 2 (ASC) - uint8_t sense_qual; // Byte 3 (ASCQ) - uint8_t byte4_6[3]; // Byte 4-6 - uint8_t more_length; // Byte 7 - descriptor_entry_t descriptor_list; // Bytes 8+ + uint8_t response_code : 7; /* Byte 0, 0x72 or 0x73 */ + uint8_t byte_0_rsvd: 1; /* Byte 0, bit 7 */ + uint8_t sense_key : 4; /* Byte 1, bit 0-3 (Key) */ + uint8_t byte_1_other : 4; /* Byte 1, bit 4-7 */ + uint8_t sense_code; /* Byte 2 (ASC) */ + uint8_t sense_qual; /* Byte 3 (ASCQ) */ + uint8_t byte4_6[3]; /* Byte 4-6 */ + uint8_t more_length; /* Byte 7 */ + descriptor_entry_t descriptor_list; /* Bytes 8+ */ } OS_ATTRIBUTE_PACKED sense_data_descriptor_t; @@ -535,20 +522,18 @@ } sense_data_u_t; - - /* Driver will use this structure to interpret the error info element returned from a failed requests */ typedef struct raid_path_error_info_elem { - uint8_t data_in_result; /* !< Byte 0. See SOP spec Table 77. */ - uint8_t data_out_result; /* !< Byte 1. See SOP spec Table 78. */ - uint8_t reserved[3]; /* !< Bytes 2-4. */ - uint8_t status; /* !< Byte 5. See SAM-5 specification "Status" codes Table 40. Defined in Storport.h */ - uint16_t status_qual; /* !< Bytes 6-7. See SAM-5 specification Table 43. */ - uint16_t sense_data_len; /* !< Bytes 8-9. See SOP specification table 79. */ - uint16_t resp_data_len; /* !< Bytes 10-11. See SOP specification table 79. */ - uint32_t data_in_transferred; /* !< Bytes 12-15. If "dada_in_result = 0x01 (DATA_IN BUFFER UNDERFLOW)", Indicates the number of contiguous bytes starting with offset zero in Data-In buffer else Ignored. */ - uint32_t data_out_transferred; /* !< Bytes 16-19. If "data_out_result = 0x01 (DATA_OUT BUFFER UNDERFLOW)", Indicates the number of contiguous bytes starting with offset zero in Data-Out buffer else Ignored. */ + uint8_t data_in_result; /* !< Byte 0. See SOP spec Table 77. */ + uint8_t data_out_result; /* !< Byte 1. See SOP spec Table 78. */ + uint8_t reserved[3]; /* !< Bytes 2-4. */ + uint8_t status; /* !< Byte 5. See SAM-5 specification "Status" codes Table 40.*/ + uint16_t status_qual; /* !< Bytes 6-7. See SAM-5 specification Table 43. */ + uint16_t sense_data_len; /* !< Bytes 8-9. See SOP specification table 79. */ + uint16_t resp_data_len; /* !< Bytes 10-11. See SOP specification table 79. */ + uint32_t data_in_transferred; /* !< Bytes 12-15. If "dada_in_result = 0x01 (DATA_IN BUFFER UNDERFLOW)", Indicates the number of contiguous bytes starting with offset zero in Data-In buffer else Ignored. */ + uint32_t data_out_transferred;/* !< Bytes 16-19. If "data_out_result = 0x01 (DATA_OUT BUFFER UNDERFLOW)", Indicates the number of contiguous bytes starting with offset zero in Data-Out buffer else Ignored. */ union { sense_data_u_t sense_data; @@ -560,22 +545,26 @@ typedef enum error_data_present { - DATA_PRESENT_NO_DATA = 0, /* !< No data present in Data buffer. */ - DATA_PRESENT_RESPONSE_DATA = 1, /* !< Response data is present in Data buffer. */ - DATA_PRESENT_SENSE_DATA = 2 /* !< Sense data is present in Data buffer. */ + DATA_PRESENT_NO_DATA = 0, /* !< No data present in Data buffer. */ + DATA_PRESENT_RESPONSE_DATA = 1, /* !< Response data is present in Data buffer. */ + DATA_PRESENT_SENSE_DATA = 2 /* !< Sense data is present in Data buffer. */ } error_data_present_t; typedef struct aio_path_error_info_elem { - uint8_t status; /* !< Byte 0. See SAM-5 specification "SCSI Status" codes Table 40. Defined in Storport.h */ - uint8_t service_resp; /* !< Byte 1. SCSI Service Response. */ - uint8_t data_pres; /* !< Byte 2. Bits [7:2] reserved. Bits [1:0] - 0=No data, 1=Response data, 2=Sense data. */ - uint8_t reserved1; /* !< Byte 3. Reserved. */ - uint32_t resd_count; /* !< Bytes 4-7. The residual data length in bytes. Need the original transfer size and if Status is OverRun or UnderRun. */ - uint16_t data_len; /* !< Bytes 8-9. The amount of Sense data or Response data returned in Response/Sense Data buffer. */ - uint16_t reserved2; /* !< Bytes 10. Reserved. */ - uint8_t data[256]; /* !< Bytes 11-267. Response data buffer or Sense data buffer but not both. */ - uint8_t padding[8]; /* !< Bytes 268-275. Padding to make AIO_PATH_ERROR_INFO_ELEMENT = RAID_PATH_ERROR_INFO_ELEMENT */ + uint8_t status; /* !< Byte 0. See SAM-5 specification "SCSI Status" codes Table 40.*/ + uint8_t service_resp; /* !< Byte 1. SCSI Service Response. */ + uint8_t data_pres; /* !< Byte 2. Bits [7:2] reserved. Bits [1:0] - 0=No data, 1=Response data, 2=Sense data. */ + uint8_t reserved1; /* !< Byte 3. Reserved. */ + uint32_t resd_count; /* !< Bytes 4-7. The residual data length in bytes. Need the original transfer size and if Status is OverRun or UnderRun. */ + uint16_t data_len; /* !< Bytes 8-9. The amount of Sense data or Response data returned in Response/Sense Data buffer. */ + uint16_t reserved2; /* !< Bytes 10-11. Reserved. */ + union + { + sense_data_u_t sense_data; /* */ + uint8_t data[256]; /* !< Bytes 12-267. Response data buffer or Sense data buffer but not both. */ + }; + uint8_t padding[8]; /* !< Bytes 268-275. Padding to make AIO_PATH_ERROR_INFO_ELEMENT = RAID_PATH_ERROR_INFO_ELEMENT */ }OS_ATTRIBUTE_PACKED aio_path_error_info_elem_t; struct init_base_struct { @@ -603,6 +592,7 @@ boolean_t lockcreated; char lockname[LOCKNAME_SIZE]; OS_PQILOCK_T lock OS_ATTRIBUTE_ALIGNED(8); + struct dma_mem alloc_dma; }ib_queue_t; typedef struct ob_queue { @@ -618,6 +608,7 @@ uint32_t *pi_virt_addr; dma_addr_t pi_dma_addr; boolean_t created; + struct dma_mem alloc_dma; }ob_queue_t; typedef struct pqisrc_sg_desc{ @@ -670,23 +661,33 @@ /* IO path */ -typedef struct pqi_aio_req { - iu_header_t header; - uint16_t response_queue_id; - uint8_t work_area[2]; - uint16_t req_id; - uint8_t res1[2]; - uint32_t nexus; - uint32_t buf_len; +typedef struct iu_cmd_flags +{ uint8_t data_dir : 2; uint8_t partial : 1; uint8_t mem_type : 1; uint8_t fence : 1; uint8_t encrypt_enable : 1; uint8_t res2 : 2; +}OS_ATTRIBUTE_PACKED iu_cmd_flags_t; + +typedef struct iu_attr_prio +{ uint8_t task_attr : 3; uint8_t cmd_prio : 4; uint8_t res3 : 1; +}OS_ATTRIBUTE_PACKED iu_attr_prio_t; + +typedef struct pqi_aio_req { + iu_header_t header; + uint16_t response_queue_id; + uint8_t work_area[2]; + uint16_t req_id; + uint8_t res1[2]; + uint32_t nexus; + uint32_t buf_len; + iu_cmd_flags_t cmd_flags; + iu_attr_prio_t attr_prio; uint16_t encrypt_key_index; uint32_t encrypt_twk_low; uint32_t encrypt_twk_high; @@ -699,6 +700,55 @@ sgt_t sg_desc[4]; }OS_ATTRIBUTE_PACKED pqi_aio_req_t; +typedef struct pqi_aio_raid1_write_req { + iu_header_t header; + uint16_t response_queue_id; + uint8_t work_area[2]; + uint16_t req_id; + uint16_t volume_id; /* ID of raid volume */ + uint32_t nexus_1; /* 1st drive in RAID 1 */ + uint32_t nexus_2; /* 2nd drive in RAID 1 */ + uint32_t nexus_3; /* 3rd drive in RAID 1 */ + uint32_t buf_len; + iu_cmd_flags_t cmd_flags; + iu_attr_prio_t attr_prio; + uint16_t encrypt_key_index; + uint8_t cdb[16]; + uint16_t err_idx; + uint8_t num_sg; + uint8_t cdb_len; + uint8_t num_drives; /* drives in raid1 (2 or 3) */ + uint8_t reserved_bytes[3]; + uint32_t encrypt_twk_low; + uint32_t encrypt_twk_high; + sgt_t sg_desc[4]; +}OS_ATTRIBUTE_PACKED pqi_aio_raid1_write_req_t; + +typedef struct pqi_aio_raid5or6_write_req { + iu_header_t header; + uint16_t response_queue_id; + uint8_t work_area[2]; + uint16_t req_id; + uint16_t volume_id; /* ID of raid volume */ + uint32_t data_it_nexus; /* IT nexus of data drive */ + uint32_t p_parity_it_nexus;/* It nexus of p parity disk */ + uint32_t q_parity_it_nexus;/* It nexus of q parity disk (R6) */ + uint32_t buf_len; + iu_cmd_flags_t cmd_flags; + iu_attr_prio_t attr_prio; + uint16_t encrypt_key_index; + uint8_t cdb[16]; + uint16_t err_idx; + uint8_t num_sg; + uint8_t cdb_len; + uint8_t xor_multiplier; /* for generating RAID 6 Q parity */ + uint8_t reserved[3]; + uint32_t encrypt_twk_low; + uint32_t encrypt_twk_high; + uint64_t row; /* logical lba / blocks per row */ + uint8_t reserved2[8]; /* changed to reserved, used to stripe_lba */ + sgt_t sg_desc[3]; /* only 3 entries for R5/6 */ +}OS_ATTRIBUTE_PACKED pqi_aio_raid5or6_write_req_t; typedef struct pqisrc_raid_request { iu_header_t header; @@ -722,28 +772,43 @@ uint8_t reserved4 : 2; uint8_t additional_cdb_bytes_usage : 3; uint8_t reserved5 : 3; - uint8_t cdb[16]; - uint8_t reserved[12]; + union + { + uint8_t cdb[16]; + struct + { + uint8_t op_code; /* Byte 0. SCSI opcode (0x26 or 0x27) */ + uint8_t lun_lower; /* Byte 1 */ + uint32_t detail; /* Byte 2-5 */ + uint8_t cmd; /* Byte 6. Vendor specific op code. */ + uint16_t xfer_len; /* Byte 7-8 */ + uint8_t lun_upper; /* Byte 9 */ + uint8_t unused[6]; /* Bytes 10-15. */ + }OS_ATTRIBUTE_PACKED bmic_cdb; + }OS_ATTRIBUTE_PACKED cmd; + uint8_t reserved[11]; + uint8_t ml_device_lun_number; uint32_t timeout_in_sec; sgt_t sg_descriptors[4]; -} OS_ATTRIBUTE_PACKED pqisrc_raid_req_t; +}OS_ATTRIBUTE_PACKED pqisrc_raid_req_t; typedef struct pqi_raid_tmf_req { - iu_header_t header; - uint16_t resp_qid; - uint8_t work_area[2]; - uint16_t req_id; - uint16_t nexus; - uint8_t res1[2]; - uint16_t timeout_in_sec; - uint8_t lun[8]; - uint16_t protocol_spec; - uint16_t obq_id_to_manage; - uint16_t req_id_to_manage; - uint8_t tmf; - uint8_t res2 : 7; - uint8_t fence : 1; + iu_header_t header; + uint16_t resp_qid; + uint8_t work_area[2]; + uint16_t req_id; + uint16_t nexus; + uint8_t res1[1]; + uint8_t ml_device_lun_number; + uint16_t timeout_in_sec; + uint8_t lun[8]; + uint16_t protocol_spec; + uint16_t obq_id_to_manage; + uint16_t req_id_to_manage; + uint8_t tmf; + uint8_t res2 : 7; + uint8_t fence : 1; } OS_ATTRIBUTE_PACKED pqi_raid_tmf_req_t; typedef struct pqi_aio_tmf_req { @@ -788,6 +853,12 @@ uint32_t encrypt_tweak_upper; }; +typedef uint32_t os_ticks_t; + +struct pqi_stream_data { + uint64_t next_lba; + os_ticks_t last_accessed; +}; typedef struct pqi_scsi_device { device_type_t devtype; /* as reported by INQUIRY command */ @@ -810,13 +881,13 @@ uint8_t device_gone : 1; uint8_t new_device : 1; uint8_t volume_offline : 1; - uint8_t scsi_rescan : 1; + uint8_t is_nvme : 1; + uint8_t scsi_rescan : 1; uint8_t vendor[8]; /* bytes 8-15 of inquiry data */ uint8_t model[16]; /* bytes 16-31 of inquiry data */ uint64_t sas_address; uint8_t raid_level; uint16_t queue_depth; /* max. queue_depth for this device */ - uint16_t advertised_queue_depth; uint32_t ioaccel_handle; uint8_t volume_status; uint8_t active_path_index; @@ -827,7 +898,7 @@ int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ int offload_enabled_pending; - int offload_to_mirror; /* Send next I/O accelerator RAID + int *offload_to_mirror; /* Send next I/O accelerator RAID offload request to mirror drive. */ struct raid_map *raid_map; /* I/O accelerator RAID map */ @@ -838,33 +909,13 @@ boolean_t path_destroyed; boolean_t firmware_queue_depth_set; OS_ATOMIC64_T active_requests; -}pqi_scsi_dev_t; - -typedef struct pqisrc_softstate pqisrc_softstate_t; -typedef struct pqi_firmware_feature pqi_firmware_feature_t; -typedef void (*feature_status_fn)(pqisrc_softstate_t *softs, - pqi_firmware_feature_t *firmware_feature); - -struct pqi_firmware_feature { - char *feature_name; - unsigned int feature_bit; - boolean_t supported; - boolean_t enabled; - feature_status_fn feature_status; -}; - -struct pqi_conf_table_firmware_features { - struct pqi_conf_table_section_header header; - uint16_t num_elements; - uint8_t features_supported[]; -}; + struct pqisrc_softstate *softs; + boolean_t schedule_rescan; + boolean_t in_remove; + struct pqi_stream_data stream_data[NUM_STREAMS_PER_LUN]; + boolean_t is_multi_lun; -struct pqi_conf_table_section_info { - struct pqisrc_softstate *softs; - void *section; - uint32_t section_offset; - void *section_addr; -}; +}pqi_scsi_dev_t; struct sense_header_scsi { /* See SPC-3 section 4.5 */ uint8_t response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */ @@ -877,8 +928,6 @@ uint8_t additional_length; /* always 0 for fixed sense format */ }OS_ATTRIBUTE_PACKED; - - typedef struct report_lun_header { uint32_t list_length; uint8_t extended_response; @@ -924,7 +973,7 @@ typedef struct reportlun_queue_depth_data { reportlun_header_t header; - reportlun_queue_depth_entry_t lun_entries[1]; /* lun list with Queue Depth values for each lun */ + reportlun_queue_depth_entry_t lun_entries[1]; /* lun list with Queue Depth values for each lun */ }OS_ATTRIBUTE_PACKED reportlun_queue_depth_data_t; typedef struct raidmap_data { @@ -958,6 +1007,59 @@ raidmap_data_t dev_data[RAID_MAP_MAX_ENTRIES]; }OS_ATTRIBUTE_PACKED pqisrc_raid_map_t; +typedef struct aio_row { + uint32_t blks_per_row; /* blocks per row */ + uint64_t first; /* first row */ + uint64_t last; /* last row */ + uint32_t offset_first; /* offset in first row */ + uint32_t offset_last; /* offset in last row */ + uint16_t data_disks; /* number of data disks per row */ + uint16_t total_disks; /* data + parity disks per row. */ +}OS_ATTRIBUTE_PACKED pqisrc_aio_row_t; + +typedef struct aio_column { + uint32_t first; /* 1st column of req */ + uint32_t last; /* last column of req */ +}OS_ATTRIBUTE_PACKED pqisrc_aio_column_t; + +typedef struct aio_block { + uint64_t first; /* 1st block number of req */ + uint64_t last; /* last block number of req */ + uint32_t cnt; /* total blocks in req */ + uint64_t disk_block; /* block number of phys disk */ +}OS_ATTRIBUTE_PACKED pqisrc_aio_block_t; + +typedef struct aio_r5or6_loc { + struct aio_row row; /* row information */ + struct aio_column col; /* column information */ +}OS_ATTRIBUTE_PACKED pqisrc_aio_r5or6_loc_t; + +typedef struct aio_map { + uint32_t row; + uint32_t idx; /* index into array of handles */ + uint16_t layout_map_count; +}OS_ATTRIBUTE_PACKED pqisrc_aio_map_t; + +typedef struct aio_disk_group { + uint32_t first; /* first group */ + uint32_t last; /* last group */ + uint32_t cur; /* current group */ +}OS_ATTRIBUTE_PACKED pqisrc_aio_disk_group_t; + +typedef struct aio_req_locator { + uint8_t raid_level; + struct raid_map *raid_map; /* relevant raid map */ + struct aio_block block; /* block range and count */ + struct aio_row row; /* row range and offset info */ + struct aio_column col; /* first/last column info */ + struct aio_r5or6_loc r5or6; /* Raid 5/6-specific bits */ + struct aio_map map; /* map row, count, and index */ + struct aio_disk_group group; /* first, last, and curr group */ + boolean_t is_write; + uint32_t stripesz; + uint16_t strip_sz; + int offload_to_mirror; +}OS_ATTRIBUTE_PACKED aio_req_locator_t; typedef struct bmic_ident_ctrl { uint8_t conf_ld_count; @@ -1042,6 +1144,55 @@ uint8_t padding[112]; }OS_ATTRIBUTE_PACKED bmic_ident_physdev_t; +typedef struct bmic_sense_feature { + uint8_t opcode; + uint8_t reserved1[1]; + uint8_t page; + uint8_t sub_page; + uint8_t reserved2[2]; + uint8_t cmd; + uint16_t transfer_length; + uint8_t reserved3[7]; +}OS_ATTRIBUTE_PACKED bmic_sense_feature_t; + +typedef struct bmic_sense_feature_buffer_header { + uint8_t page; + uint8_t sub_page; + uint16_t buffer_length; +} OS_ATTRIBUTE_PACKED bmic_sense_feature_buffer_header_t; + +typedef struct bmic_sense_feature_page_header { + uint8_t page; + uint8_t sub_page; + uint16_t total_length; /** Total length of the page. + * The length is the same wheteher the request buffer is too short or not. + * When printing out the page, only print the buffer length. */ +} OS_ATTRIBUTE_PACKED bmic_sense_feature_page_header_t; + +typedef struct bmic_sense_feature_page_io { + struct bmic_sense_feature_page_header header; + uint8_t flags1; +} OS_ATTRIBUTE_PACKED bmic_sense_feature_page_io_t; + +typedef struct bmic_sense_feature_page_io_aio_subpage { + struct bmic_sense_feature_page_header header; + uint8_t fw_aio_read_support; + uint8_t driver_aio_read_support; + uint8_t fw_aio_write_support; + uint8_t driver_aio_write_support; + uint16_t max_aio_rw_xfer_crypto_sas_sata; /* in kb */ + uint16_t max_aio_rw_xfer_crypto_nvme; /* in kb */ + uint16_t max_aio_write_raid5_6; /* in kb */ + uint16_t max_aio_write_raid1_10_2drv; /* in kb */ + uint16_t max_aio_write_raid1_10_3drv; /* in kb */ +} OS_ATTRIBUTE_PACKED bmic_sense_feature_page_io_aio_subpage_t; + +typedef struct bmic_sense_feature_aio_buffer { + struct bmic_sense_feature_buffer_header header; + struct bmic_sense_feature_page_io_aio_subpage aio_subpage; +} OS_ATTRIBUTE_PACKED bmic_sense_feature_aio_buffer_t; + + typedef struct pqisrc_bmic_flush_cache { uint8_t disable_cache; uint8_t power_action; @@ -1067,7 +1218,7 @@ typedef struct request_container_block { void *req; void *error_info; - REQUEST_STATUS_T status; + int status; uint32_t tag; sgt_t *sg_chain_virt; dma_addr_t sg_chain_dma; @@ -1076,34 +1227,71 @@ struct pqisrc_softstate *softs; success_callback success_cmp_callback; error_callback error_cmp_callback; - uint8_t *cdbp; + uint8_t *cdbp; /* points to either the bypass_cdb below or original host cdb */ + uint8_t bypass_cdb[16]; /* bypass cmds will use this cdb memory */ int cmdlen; uint32_t bcount; /* buffer size in byte */ uint32_t ioaccel_handle; boolean_t encrypt_enable; struct pqi_enc_info enc_info; + uint32_t row_num; + uint32_t blocks_per_row; + uint32_t raid_map_index; + uint32_t raid_map_row; ib_queue_t *req_q; - int path; + IO_PATH_T path; int resp_qid; boolean_t req_pending; + uint32_t it_nexus[PQISRC_MAX_SUPPORTED_MIRRORS]; boolean_t timedout; int tm_req; int aio_retry; + boolean_t is_abort_cmd_from_host; /* true if this is a TMF abort */ + boolean_t host_wants_to_abort_this; /* set to true to ID the request targeted by TMF */ + uint64_t submit_time_user_secs; /* host submit time in user seconds */ + uint64_t host_timeout_ms; /* original host timeout value in msec */ int cm_flags; void *cm_data; /* pointer to data in kernel space */ bus_dmamap_t cm_datamap; uint32_t nseg; union ccb *cm_ccb; sgt_t *sgt; /* sg table */ - }rcb_t; -typedef struct tid_pool { - int tid[PQI_MAX_PHYSICALS]; - int index; -}tid_pool_t; +typedef struct bit_map { + boolean_t bit_vector[MAX_TARGET_BIT]; +}bit_map_t; -struct pqisrc_softstate { +typedef enum _io_type +{ + UNKNOWN_IO_TYPE, /* IO Type is TBD or cannot be determined */ + NON_RW_IO_TYPE, /* IO Type is non-Read/Write opcode (could separate BMIC, etc. if we wanted) */ + READ_IO_TYPE, /* IO Type is SCSI Read */ + WRITE_IO_TYPE, /* IO Type is SCSI Write */ +} io_type_t; + +typedef enum _counter_types +{ + UNKNOWN_COUNTER, + HBA_COUNTER, + RAID0_COUNTER, + RAID1_COUNTER, + RAID5_COUNTER, + RAID6_COUNTER, + MAX_IO_COUNTER, +} counter_types_t; + +typedef struct _io_counters +{ + OS_ATOMIC64_T raid_read_cnt; + OS_ATOMIC64_T raid_write_cnt; + OS_ATOMIC64_T aio_read_cnt; + OS_ATOMIC64_T aio_write_cnt; + OS_ATOMIC64_T raid_non_read_write; + OS_ATOMIC64_T aio_non_read_write; +} io_counters_t; + +typedef struct pqisrc_softstate { OS_SPECIFIC_T os_specific; struct ioa_registers *ioa_reg; struct pqi_registers *pqi_reg; @@ -1120,11 +1308,7 @@ uint16_t subsysid; /* sub system id */ controller_state_t ctlr_state; struct dma_mem err_buf_dma_mem; - struct dma_mem admin_queue_dma_mem; - struct dma_mem op_ibq_dma_mem; - struct dma_mem op_obq_dma_mem; - struct dma_mem event_q_dma_mem; - struct dma_mem sg_dma_desc[PQISRC_MAX_OUTSTANDING_REQ]; + struct dma_mem sg_dma_desc[PQISRC_MAX_OUTSTANDING_REQ + 1]; ib_queue_t admin_ib_queue; ob_queue_t admin_ob_queue; ob_queue_t event_q; @@ -1138,12 +1322,14 @@ uint32_t num_op_obq; uint32_t num_elem_per_op_ibq; uint32_t num_elem_per_op_obq; - uint32_t ibq_elem_size; - uint32_t obq_elem_size; + uint32_t max_ibq_elem_size; + uint32_t max_obq_elem_size; pqi_dev_cap_t pqi_dev_cap; uint16_t max_ib_iu_length_per_fw; - uint16_t max_ib_iu_length; - unsigned max_sg_per_iu; + uint16_t max_ib_iu_length; /* should be 1152 */ + uint16_t max_spanning_elems; /* should be 9 spanning elements */ + unsigned max_sg_per_single_iu_element; /* should be 8 */ + unsigned max_sg_per_spanning_cmd; /* should be 68, 67 with AIO writes */ uint8_t ib_spanning_supported : 1; uint8_t ob_spanning_supported : 1; pqi_event_config_t event_config; @@ -1151,6 +1337,7 @@ int intr_type; int intr_count; int num_cpus_online; + int num_devs; boolean_t share_opq_and_eventq; rcb_t *rcb; #ifndef LOCKFREE_STACK @@ -1162,27 +1349,117 @@ OS_LOCK_T devlist_lock OS_ATTRIBUTE_ALIGNED(8); char devlist_lock_name[LOCKNAME_SIZE]; pqi_scsi_dev_t *device_list[PQI_MAX_DEVICES][PQI_MAX_MULTILUN]; + pqi_scsi_dev_t *dev_list[PQI_MAX_DEVICES]; OS_SEMA_LOCK_T scan_lock; uint8_t lun_count[PQI_MAX_DEVICES]; uint64_t target_sas_addr[PQI_MAX_EXT_TARGETS]; + uint64_t phys_list_pos; uint64_t prev_heartbeat_count; uint64_t *heartbeat_counter_abs_addr; uint64_t heartbeat_counter_off; - uint8_t *fw_features_section_abs_addr; - uint64_t fw_features_section_off; uint32_t bus_id; uint32_t device_id; uint32_t func_id; + uint8_t adapter_num; /* globally unique adapter number */ char *os_name; boolean_t ctrl_online; uint8_t pqi_reset_quiesce_allowed : 1; boolean_t ctrl_in_pqi_mode; - tid_pool_t tid_pool; + bit_map_t bit_map; uint32_t adapterQDepth; uint32_t dma_mem_consumed; + boolean_t adv_aio_capable; + boolean_t aio_raid1_write_bypass; + boolean_t aio_raid5_write_bypass; + boolean_t aio_raid6_write_bypass; + boolean_t enable_stream_detection; + uint16_t max_aio_write_raid5_6; /* bytes */ + uint16_t max_aio_write_raid1_10_2drv; /* bytes */ + uint16_t max_aio_write_raid1_10_3drv; /* bytes */ + uint16_t max_aio_rw_xfer_crypto_nvme; /* bytes */ + uint16_t max_aio_rw_xfer_crypto_sas_sata; /* bytes */ + io_counters_t counters[MAX_IO_COUNTER]; + boolean_t log_io_counters; + boolean_t ld_rescan; + +#ifdef PQI_NEED_RESCAN_TIMER_FOR_RBOD_HOTPLUG + reportlun_data_ext_t *log_dev_list; + size_t log_dev_data_length; + uint32_t num_ptraid_targets; +#endif boolean_t timeout_in_passthrough; boolean_t timeout_in_tmf; -}; + boolean_t sata_unique_wwn; + boolean_t page83id_in_rpl; + boolean_t err_resp_verbose; + +#ifdef DEVICE_HINT + device_hint hint; +#endif + +}pqisrc_softstate_t; + +struct pqi_config_table { + uint8_t signature[8]; /* "CFGTABLE" */ + uint32_t first_section_offset; /* offset in bytes from the base */ + /* address of this table to the */ + /* first section */ +}OS_ATTRIBUTE_PACKED; + +struct pqi_config_table_section_header { + uint16_t section_id; /* as defined by the */ + /* PQI_CONFIG_TABLE_SECTION_* */ + /* manifest constants above */ + uint16_t next_section_offset; /* offset in bytes from base */ + /* address of the table of the */ + /* next section or 0 if last entry */ +}OS_ATTRIBUTE_PACKED; + +struct pqi_config_table_general_info { + struct pqi_config_table_section_header header; + uint32_t section_length; /* size of this section in bytes */ + /* including the section header */ + uint32_t max_outstanding_requests; /* max. outstanding */ + /* commands supported by */ + /* the controller */ + uint32_t max_sg_size; /* max. transfer size of a single */ + /* command */ + uint32_t max_sg_per_request; /* max. number of scatter-gather */ + /* entries supported in a single */ + /* command */ +}OS_ATTRIBUTE_PACKED; + +struct pqi_config_table_firmware_features { + struct pqi_config_table_section_header header; + uint16_t num_elements; + uint8_t features_supported[]; +/* u8 features_requested_by_host[]; */ +/* u8 features_enabled[]; */ +/* The 2 fields below are only valid if the MAX_KNOWN_FEATURE bit is set. */ +/* uint16_t firmware_max_known_feature; */ +/* uint16_t host_max_known_feature; */ +}OS_ATTRIBUTE_PACKED; + +typedef struct pqi_vendor_general_request { + iu_header_t header; /* bytes 0-3 */ + uint16_t response_id; /* bytes 4-5 */ + uint16_t work; /* bytes 6-7 */ + uint16_t request_id; + uint16_t function_code; + union { + struct { + uint16_t first_section; + uint16_t last_section; + uint8_t reserved[48]; + } OS_ATTRIBUTE_PACKED config_table_update; + + struct { + uint64_t buffer_address; + uint32_t buffer_length; + uint8_t reserved[40]; + } OS_ATTRIBUTE_PACKED ofa_memory_allocation; + } data; +}OS_ATTRIBUTE_PACKED pqi_vendor_general_request_t; typedef struct vpd_logical_volume_status { uint8_t peripheral_info; diff --git a/sys/dev/smartpqi/smartpqi_tag.c b/sys/dev/smartpqi/smartpqi_tag.c --- a/sys/dev/smartpqi/smartpqi_tag.c +++ b/sys/dev/smartpqi/smartpqi_tag.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,7 +36,7 @@ { OS_ACQUIRE_SPINLOCK(&(taglist->lock)); - DBG_FUNC("IN\n"); +/* DBG_FUNC("IN\n");*/ ASSERT(taglist->num_elem < taglist->max_elem); @@ -48,7 +48,7 @@ OS_RELEASE_SPINLOCK(&taglist->lock); - DBG_FUNC("OUT\n"); +/* DBG_FUNC("OUT\n");*/ } /* @@ -101,14 +101,14 @@ goto err_out; } - os_strlcpy(taglist->lockname, "tag_lock", LOCKNAME_SIZE); - ret = os_init_spinlock(softs, &taglist->lock, taglist->lockname); - if(ret){ - DBG_ERR("tag lock initialization failed\n"); - taglist->lockcreated=false; - goto err_lock; + os_strlcpy(taglist->lockname, "tag_lock", LOCKNAME_SIZE); + ret = os_init_spinlock(softs, &taglist->lock, taglist->lockname); + if(ret){ + DBG_ERR("tag lock initialization failed\n"); + taglist->lockcreated=false; + goto err_lock; } - taglist->lockcreated = true; + taglist->lockcreated = true; /* indices 1 to max_elem are considered as valid tags */ for (i=1; i <= max_elem; i++) { @@ -120,8 +120,8 @@ return ret; err_lock: - os_mem_free(softs, (char *)taglist->elem_array, - (taglist->max_elem * sizeof(uint32_t))); + os_mem_free(softs, (char *)taglist->elem_array, + (taglist->max_elem * sizeof(uint32_t))); taglist->elem_array = NULL; err_out: DBG_FUNC("OUT failed\n"); @@ -139,10 +139,10 @@ (taglist->max_elem * sizeof(uint32_t))); taglist->elem_array = NULL; - if(taglist->lockcreated==true){ - os_uninit_spinlock(&taglist->lock); - taglist->lockcreated = false; - } + if(taglist->lockcreated==true){ + os_uninit_spinlock(&taglist->lock); + taglist->lockcreated = false; + } DBG_FUNC("OUT\n"); } @@ -215,7 +215,7 @@ union head_list cur_head, new_head; DBG_FUNC("IN\n"); - DBG_INFO("push tag :%d\n",index); + DBG_INFO("push tag :%u\n",index); if (index >= stack->max_elem) { ASSERT(false); @@ -264,7 +264,7 @@ stack->next_index_array[cur_head.top.index] = 0; stack->num_elem--; - DBG_INFO("pop tag: %d\n",cur_head.top.index); + DBG_INFO("pop tag: %u\n",cur_head.top.index); DBG_FUNC("OUT\n"); return cur_head.top.index; /*tag*/ } diff --git a/sys/modules/smartpqi/Makefile b/sys/modules/smartpqi/Makefile --- a/sys/modules/smartpqi/Makefile +++ b/sys/modules/smartpqi/Makefile @@ -4,7 +4,7 @@ .PATH: ${SRCTOP}/sys/dev/${KMOD} -SRCS=smartpqi_mem.c smartpqi_intr.c smartpqi_main.c smartpqi_cam.c smartpqi_ioctl.c smartpqi_misc.c smartpqi_sis.c smartpqi_init.c smartpqi_queue.c smartpqi_tag.c smartpqi_cmd.c smartpqi_request.c smartpqi_response.c smartpqi_event.c smartpqi_helper.c smartpqi_discovery.c +SRCS=smartpqi_mem.c smartpqi_intr.c smartpqi_main.c smartpqi_cam.c smartpqi_ioctl.c smartpqi_misc.c smartpqi_sis.c smartpqi_init.c smartpqi_queue.c smartpqi_tag.c smartpqi_cmd.c smartpqi_request.c smartpqi_response.c smartpqi_event.c smartpqi_helper.c smartpqi_discovery.c smartpqi_features.c SRCS+= device_if.h bus_if.h pci_if.h opt_scsi.h opt_cam.h