[SCSI] lpfc 8.3.45: Incorporated support of a low-latency io path
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:

committed by
James Bottomley

parent
2a2719d370
commit
1ba981fd3a
@@ -68,6 +68,17 @@ struct scsi_dif_tuple {
|
||||
__be32 ref_tag; /* Target LBA or indirect LBA */
|
||||
};
|
||||
|
||||
static struct lpfc_rport_data *
|
||||
lpfc_rport_data_from_scsi_device(struct scsi_device *sdev)
|
||||
{
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *)sdev->host->hostdata;
|
||||
|
||||
if (vport->phba->cfg_EnableXLane)
|
||||
return ((struct lpfc_device_data *)sdev->hostdata)->rport_data;
|
||||
else
|
||||
return (struct lpfc_rport_data *)sdev->hostdata;
|
||||
}
|
||||
|
||||
static void
|
||||
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
|
||||
static void
|
||||
@@ -306,7 +317,7 @@ lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
|
||||
old_queue_depth = sdev->queue_depth;
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
|
||||
new_queue_depth = sdev->queue_depth;
|
||||
rdata = sdev->hostdata;
|
||||
rdata = lpfc_rport_data_from_scsi_device(sdev);
|
||||
if (rdata)
|
||||
lpfc_send_sdev_queuedepth_change_event(phba, vport,
|
||||
rdata->pnode, sdev->lun,
|
||||
@@ -1502,7 +1513,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
|
||||
}
|
||||
|
||||
/* Next check if we need to match the remote NPortID or WWPN */
|
||||
rdata = sc->device->hostdata;
|
||||
rdata = lpfc_rport_data_from_scsi_device(sc->device);
|
||||
if (rdata && rdata->pnode) {
|
||||
ndlp = rdata->pnode;
|
||||
|
||||
@@ -3507,6 +3518,14 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
|
||||
* we need to set word 4 of IOCB here
|
||||
*/
|
||||
iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
|
||||
|
||||
/*
|
||||
* If the OAS driver feature is enabled and the lun is enabled for
|
||||
* OAS, set the oas iocb related flags.
|
||||
*/
|
||||
if ((phba->cfg_EnableXLane) && ((struct lpfc_device_data *)
|
||||
scsi_cmnd->device->hostdata)->oas_enabled)
|
||||
lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4691,12 +4710,13 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||
struct lpfc_rport_data *rdata;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
struct lpfc_scsi_buf *lpfc_cmd;
|
||||
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
|
||||
int err;
|
||||
|
||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||
err = fc_remote_port_chkready(rport);
|
||||
if (err) {
|
||||
cmnd->result = err;
|
||||
@@ -5179,10 +5199,11 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
|
||||
static int
|
||||
lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||
struct lpfc_rport_data *rdata;
|
||||
struct lpfc_nodelist *pnode;
|
||||
unsigned long later;
|
||||
|
||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||
if (!rdata) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
||||
"0797 Tgt Map rport failure: rdata x%p\n", rdata);
|
||||
@@ -5200,7 +5221,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
|
||||
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
|
||||
return SUCCESS;
|
||||
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
|
||||
rdata = cmnd->device->hostdata;
|
||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||
if (!rdata)
|
||||
return FAILED;
|
||||
pnode = rdata->pnode;
|
||||
@@ -5272,13 +5293,14 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct Scsi_Host *shost = cmnd->device->host;
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||
struct lpfc_rport_data *rdata;
|
||||
struct lpfc_nodelist *pnode;
|
||||
unsigned tgt_id = cmnd->device->id;
|
||||
unsigned int lun_id = cmnd->device->lun;
|
||||
struct lpfc_scsi_event_header scsi_event;
|
||||
int status;
|
||||
|
||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||
if (!rdata) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||
"0798 Device Reset rport failure: rdata x%p\n", rdata);
|
||||
@@ -5341,13 +5363,14 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct Scsi_Host *shost = cmnd->device->host;
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
|
||||
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
|
||||
struct lpfc_rport_data *rdata;
|
||||
struct lpfc_nodelist *pnode;
|
||||
unsigned tgt_id = cmnd->device->id;
|
||||
unsigned int lun_id = cmnd->device->lun;
|
||||
struct lpfc_scsi_event_header scsi_event;
|
||||
int status;
|
||||
|
||||
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
|
||||
if (!rdata) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
|
||||
"0799 Target Reset rport failure: rdata x%p\n", rdata);
|
||||
@@ -5547,11 +5570,45 @@ lpfc_slave_alloc(struct scsi_device *sdev)
|
||||
uint32_t num_to_alloc = 0;
|
||||
int num_allocated = 0;
|
||||
uint32_t sdev_cnt;
|
||||
struct lpfc_device_data *device_data;
|
||||
unsigned long flags;
|
||||
struct lpfc_name target_wwpn;
|
||||
|
||||
if (!rport || fc_remote_port_chkready(rport))
|
||||
return -ENXIO;
|
||||
|
||||
sdev->hostdata = rport->dd_data;
|
||||
if (phba->cfg_EnableXLane) {
|
||||
|
||||
/*
|
||||
* Check to see if the device data structure for the lun
|
||||
* exists. If not, create one.
|
||||
*/
|
||||
|
||||
u64_to_wwn(rport->port_name, target_wwpn.u.wwn);
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
device_data = __lpfc_get_device_data(phba,
|
||||
&phba->luns,
|
||||
&vport->fc_portname,
|
||||
&target_wwpn,
|
||||
sdev->lun);
|
||||
if (!device_data) {
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
device_data = lpfc_create_device_data(phba,
|
||||
&vport->fc_portname,
|
||||
&target_wwpn,
|
||||
sdev->lun, true);
|
||||
if (!device_data)
|
||||
return -ENOMEM;
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
list_add_tail(&device_data->listentry, &phba->luns);
|
||||
}
|
||||
device_data->rport_data = rport->dd_data;
|
||||
device_data->available = true;
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
sdev->hostdata = device_data;
|
||||
} else {
|
||||
sdev->hostdata = rport->dd_data;
|
||||
}
|
||||
sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
|
||||
|
||||
/*
|
||||
@@ -5641,11 +5698,344 @@ lpfc_slave_destroy(struct scsi_device *sdev)
|
||||
{
|
||||
struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
unsigned long flags;
|
||||
struct lpfc_device_data *device_data = sdev->hostdata;
|
||||
|
||||
atomic_dec(&phba->sdev_cnt);
|
||||
if ((phba->cfg_EnableXLane) && (device_data)) {
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
device_data->available = false;
|
||||
if (!device_data->oas_enabled)
|
||||
lpfc_delete_device_data(phba, device_data);
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
}
|
||||
sdev->hostdata = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_create_device_data - creates and initializes device data structure for OAS
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @vport_wwpn: Pointer to vport's wwpn information
|
||||
* @target_wwpn: Pointer to target's wwpn information
|
||||
* @lun: Lun on target
|
||||
* @atomic_create: Flag to indicate if memory should be allocated using the
|
||||
* GFP_ATOMIC flag or not.
|
||||
*
|
||||
* This routine creates a device data structure which will contain identifying
|
||||
* information for the device (host wwpn, target wwpn, lun), state of OAS,
|
||||
* whether or not the corresponding lun is available by the system,
|
||||
* and pointer to the rport data.
|
||||
*
|
||||
* Return codes:
|
||||
* NULL - Error
|
||||
* Pointer to lpfc_device_data - Success
|
||||
**/
|
||||
struct lpfc_device_data*
|
||||
lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
|
||||
struct lpfc_name *target_wwpn, uint64_t lun,
|
||||
bool atomic_create)
|
||||
{
|
||||
|
||||
struct lpfc_device_data *lun_info;
|
||||
int memory_flags;
|
||||
|
||||
if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
|
||||
!(phba->cfg_EnableXLane))
|
||||
return NULL;
|
||||
|
||||
/* Attempt to create the device data to contain lun info */
|
||||
|
||||
if (atomic_create)
|
||||
memory_flags = GFP_ATOMIC;
|
||||
else
|
||||
memory_flags = GFP_KERNEL;
|
||||
lun_info = mempool_alloc(phba->device_data_mem_pool, memory_flags);
|
||||
if (!lun_info)
|
||||
return NULL;
|
||||
INIT_LIST_HEAD(&lun_info->listentry);
|
||||
lun_info->rport_data = NULL;
|
||||
memcpy(&lun_info->device_id.vport_wwpn, vport_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
memcpy(&lun_info->device_id.target_wwpn, target_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
lun_info->device_id.lun = lun;
|
||||
lun_info->oas_enabled = false;
|
||||
lun_info->available = false;
|
||||
return lun_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_delete_device_data - frees a device data structure for OAS
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @lun_info: Pointer to device data structure to free.
|
||||
*
|
||||
* This routine frees the previously allocated device data structure passed.
|
||||
*
|
||||
**/
|
||||
void
|
||||
lpfc_delete_device_data(struct lpfc_hba *phba,
|
||||
struct lpfc_device_data *lun_info)
|
||||
{
|
||||
|
||||
if (unlikely(!phba) || !lun_info ||
|
||||
!(phba->cfg_EnableXLane))
|
||||
return;
|
||||
|
||||
if (!list_empty(&lun_info->listentry))
|
||||
list_del(&lun_info->listentry);
|
||||
mempool_free(lun_info, phba->device_data_mem_pool);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* __lpfc_get_device_data - returns the device data for the specified lun
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @list: Point to list to search.
|
||||
* @vport_wwpn: Pointer to vport's wwpn information
|
||||
* @target_wwpn: Pointer to target's wwpn information
|
||||
* @lun: Lun on target
|
||||
*
|
||||
* This routine searches the list passed for the specified lun's device data.
|
||||
* This function does not hold locks, it is the responsibility of the caller
|
||||
* to ensure the proper lock is held before calling the function.
|
||||
*
|
||||
* Return codes:
|
||||
* NULL - Error
|
||||
* Pointer to lpfc_device_data - Success
|
||||
**/
|
||||
struct lpfc_device_data*
|
||||
__lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list,
|
||||
struct lpfc_name *vport_wwpn,
|
||||
struct lpfc_name *target_wwpn, uint64_t lun)
|
||||
{
|
||||
|
||||
struct lpfc_device_data *lun_info;
|
||||
|
||||
if (unlikely(!phba) || !list || !vport_wwpn || !target_wwpn ||
|
||||
!phba->cfg_EnableXLane)
|
||||
return NULL;
|
||||
|
||||
/* Check to see if the lun is already enabled for OAS. */
|
||||
|
||||
list_for_each_entry(lun_info, list, listentry) {
|
||||
if ((memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
|
||||
sizeof(struct lpfc_name)) == 0) &&
|
||||
(memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
|
||||
sizeof(struct lpfc_name)) == 0) &&
|
||||
(lun_info->device_id.lun == lun))
|
||||
return lun_info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_find_next_oas_lun - searches for the next oas lun
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @vport_wwpn: Pointer to vport's wwpn information
|
||||
* @target_wwpn: Pointer to target's wwpn information
|
||||
* @starting_lun: Pointer to the lun to start searching for
|
||||
* @found_vport_wwpn: Pointer to the found lun's vport wwpn information
|
||||
* @found_target_wwpn: Pointer to the found lun's target wwpn information
|
||||
* @found_lun: Pointer to the found lun.
|
||||
* @found_lun_status: Pointer to status of the found lun.
|
||||
*
|
||||
* This routine searches the luns list for the specified lun
|
||||
* or the first lun for the vport/target. If the vport wwpn contains
|
||||
* a zero value then a specific vport is not specified. In this case
|
||||
* any vport which contains the lun will be considered a match. If the
|
||||
* target wwpn contains a zero value then a specific target is not specified.
|
||||
* In this case any target which contains the lun will be considered a
|
||||
* match. If the lun is found, the lun, vport wwpn, target wwpn and lun status
|
||||
* are returned. The function will also return the next lun if available.
|
||||
* If the next lun is not found, starting_lun parameter will be set to
|
||||
* NO_MORE_OAS_LUN.
|
||||
*
|
||||
* Return codes:
|
||||
* non-0 - Error
|
||||
* 0 - Success
|
||||
**/
|
||||
bool
|
||||
lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
|
||||
struct lpfc_name *target_wwpn, uint64_t *starting_lun,
|
||||
struct lpfc_name *found_vport_wwpn,
|
||||
struct lpfc_name *found_target_wwpn,
|
||||
uint64_t *found_lun,
|
||||
uint32_t *found_lun_status)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
struct lpfc_device_data *lun_info;
|
||||
struct lpfc_device_id *device_id;
|
||||
uint64_t lun;
|
||||
bool found = false;
|
||||
|
||||
if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
|
||||
!starting_lun || !found_vport_wwpn ||
|
||||
!found_target_wwpn || !found_lun || !found_lun_status ||
|
||||
(*starting_lun == NO_MORE_OAS_LUN) ||
|
||||
!phba->cfg_EnableXLane)
|
||||
return false;
|
||||
|
||||
lun = *starting_lun;
|
||||
*found_lun = NO_MORE_OAS_LUN;
|
||||
*starting_lun = NO_MORE_OAS_LUN;
|
||||
|
||||
/* Search for lun or the lun closet in value */
|
||||
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
list_for_each_entry(lun_info, &phba->luns, listentry) {
|
||||
if (((wwn_to_u64(vport_wwpn->u.wwn) == 0) ||
|
||||
(memcmp(&lun_info->device_id.vport_wwpn, vport_wwpn,
|
||||
sizeof(struct lpfc_name)) == 0)) &&
|
||||
((wwn_to_u64(target_wwpn->u.wwn) == 0) ||
|
||||
(memcmp(&lun_info->device_id.target_wwpn, target_wwpn,
|
||||
sizeof(struct lpfc_name)) == 0)) &&
|
||||
(lun_info->oas_enabled)) {
|
||||
device_id = &lun_info->device_id;
|
||||
if ((!found) &&
|
||||
((lun == FIND_FIRST_OAS_LUN) ||
|
||||
(device_id->lun == lun))) {
|
||||
*found_lun = device_id->lun;
|
||||
memcpy(found_vport_wwpn,
|
||||
&device_id->vport_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
memcpy(found_target_wwpn,
|
||||
&device_id->target_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
if (lun_info->available)
|
||||
*found_lun_status =
|
||||
OAS_LUN_STATUS_EXISTS;
|
||||
else
|
||||
*found_lun_status = 0;
|
||||
if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT)
|
||||
memset(vport_wwpn, 0x0,
|
||||
sizeof(struct lpfc_name));
|
||||
if (phba->cfg_oas_flags & OAS_FIND_ANY_TARGET)
|
||||
memset(target_wwpn, 0x0,
|
||||
sizeof(struct lpfc_name));
|
||||
found = true;
|
||||
} else if (found) {
|
||||
*starting_lun = device_id->lun;
|
||||
memcpy(vport_wwpn, &device_id->vport_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
memcpy(target_wwpn, &device_id->target_wwpn,
|
||||
sizeof(struct lpfc_name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_enable_oas_lun - enables a lun for OAS operations
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @vport_wwpn: Pointer to vport's wwpn information
|
||||
* @target_wwpn: Pointer to target's wwpn information
|
||||
* @lun: Lun
|
||||
*
|
||||
* This routine enables a lun for oas operations. The routines does so by
|
||||
* doing the following :
|
||||
*
|
||||
* 1) Checks to see if the device data for the lun has been created.
|
||||
* 2) If found, sets the OAS enabled flag if not set and returns.
|
||||
* 3) Otherwise, creates a device data structure.
|
||||
* 4) If successfully created, indicates the device data is for an OAS lun,
|
||||
* indicates the lun is not available and add to the list of luns.
|
||||
*
|
||||
* Return codes:
|
||||
* false - Error
|
||||
* true - Success
|
||||
**/
|
||||
bool
|
||||
lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
|
||||
struct lpfc_name *target_wwpn, uint64_t lun)
|
||||
{
|
||||
|
||||
struct lpfc_device_data *lun_info;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
|
||||
!phba->cfg_EnableXLane)
|
||||
return false;
|
||||
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
|
||||
/* Check to see if the device data for the lun has been created */
|
||||
lun_info = __lpfc_get_device_data(phba, &phba->luns, vport_wwpn,
|
||||
target_wwpn, lun);
|
||||
if (lun_info) {
|
||||
if (!lun_info->oas_enabled)
|
||||
lun_info->oas_enabled = true;
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Create an lun info structure and add to list of luns */
|
||||
lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
|
||||
false);
|
||||
if (lun_info) {
|
||||
lun_info->oas_enabled = true;
|
||||
lun_info->available = false;
|
||||
list_add_tail(&lun_info->listentry, &phba->luns);
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return true;
|
||||
}
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_disable_oas_lun - disables a lun for OAS operations
|
||||
* @pha: Pointer to host bus adapter structure.
|
||||
* @vport_wwpn: Pointer to vport's wwpn information
|
||||
* @target_wwpn: Pointer to target's wwpn information
|
||||
* @lun: Lun
|
||||
*
|
||||
* This routine disables a lun for oas operations. The routines does so by
|
||||
* doing the following :
|
||||
*
|
||||
* 1) Checks to see if the device data for the lun is created.
|
||||
* 2) If present, clears the flag indicating this lun is for OAS.
|
||||
* 3) If the lun is not available by the system, the device data is
|
||||
* freed.
|
||||
*
|
||||
* Return codes:
|
||||
* false - Error
|
||||
* true - Success
|
||||
**/
|
||||
bool
|
||||
lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
|
||||
struct lpfc_name *target_wwpn, uint64_t lun)
|
||||
{
|
||||
|
||||
struct lpfc_device_data *lun_info;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(!phba) || !vport_wwpn || !target_wwpn ||
|
||||
!phba->cfg_EnableXLane)
|
||||
return false;
|
||||
|
||||
spin_lock_irqsave(&phba->devicelock, flags);
|
||||
|
||||
/* Check to see if the lun is available. */
|
||||
lun_info = __lpfc_get_device_data(phba,
|
||||
&phba->luns, vport_wwpn,
|
||||
target_wwpn, lun);
|
||||
if (lun_info) {
|
||||
lun_info->oas_enabled = false;
|
||||
if (!lun_info->available)
|
||||
lpfc_delete_device_data(phba, lun_info);
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&phba->devicelock, flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct scsi_host_template lpfc_template = {
|
||||
.module = THIS_MODULE,
|
||||
|
Reference in New Issue
Block a user