summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c234
1 files changed, 166 insertions, 68 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index b16bb2c9978..c818a725596 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -19,6 +19,7 @@
* included with this package. *
*******************************************************************/
#include <linux/pci.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
@@ -622,6 +623,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
unsigned long iflag = 0;
struct lpfc_iocbq *iocbq;
int i;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
@@ -650,6 +652,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
psb->exch_busy = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ if (pring->txq_cnt)
+ lpfc_worker_wake_up(phba);
return;
}
@@ -746,7 +750,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
int status = 0, index;
int bcnt;
int non_sequential_xri = 0;
- int rc = 0;
LIST_HEAD(sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
@@ -773,6 +776,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
/* Allocate iotag for psb->cur_iocbq. */
iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
if (iotag == 0) {
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+ psb->data, psb->dma_handle);
kfree(psb);
break;
}
@@ -857,7 +862,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -876,7 +880,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -886,7 +889,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
}
- return bcnt + non_sequential_xri - rc;
+ return bcnt + non_sequential_xri;
}
/**
@@ -1140,37 +1143,47 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
}
/*
- * Given a scsi cmnd, determine the BlockGuard profile to be used
- * with the cmd
+ * Given a scsi cmnd, determine the BlockGuard opcodes to be used with it
+ * @sc: The SCSI command to examine
+ * @txopt: (out) BlockGuard operation for transmitted data
+ * @rxopt: (out) BlockGuard operation for received data
+ *
+ * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
+ *
*/
static int
-lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
+lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+ uint8_t *txop, uint8_t *rxop)
{
uint8_t guard_type = scsi_host_get_guard(sc->device->host);
- uint8_t ret_prof = LPFC_PROF_INVALID;
+ uint8_t ret = 0;
if (guard_type == SHOST_DIX_GUARD_IP) {
switch (scsi_get_prot_op(sc)) {
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
- ret_prof = LPFC_PROF_AST2;
+ *txop = BG_OP_IN_CSUM_OUT_NODIF;
+ *rxop = BG_OP_IN_NODIF_OUT_CSUM;
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
- ret_prof = LPFC_PROF_A1;
+ *txop = BG_OP_IN_NODIF_OUT_CRC;
+ *rxop = BG_OP_IN_CRC_OUT_NODIF;
break;
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- ret_prof = LPFC_PROF_AST1;
+ *txop = BG_OP_IN_CSUM_OUT_CRC;
+ *rxop = BG_OP_IN_CRC_OUT_CSUM;
break;
case SCSI_PROT_NORMAL:
default:
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
- "9063 BLKGRD:Bad op/guard:%d/%d combination\n",
+ "9063 BLKGRD: Bad op/guard:%d/%d combination\n",
scsi_get_prot_op(sc), guard_type);
+ ret = 1;
break;
}
@@ -1178,12 +1191,14 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
switch (scsi_get_prot_op(sc)) {
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
- ret_prof = LPFC_PROF_A1;
+ *txop = BG_OP_IN_NODIF_OUT_CRC;
+ *rxop = BG_OP_IN_CRC_OUT_NODIF;
break;
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- ret_prof = LPFC_PROF_C1;
+ *txop = BG_OP_IN_CRC_OUT_CRC;
+ *rxop = BG_OP_IN_CRC_OUT_CRC;
break;
case SCSI_PROT_READ_INSERT:
@@ -1193,6 +1208,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9075 BLKGRD: Bad op/guard:%d/%d combination\n",
scsi_get_prot_op(sc), guard_type);
+ ret = 1;
break;
}
} else {
@@ -1200,7 +1216,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
BUG();
}
- return ret_prof;
+ return ret;
}
struct scsi_dif_tuple {
@@ -1265,7 +1281,9 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
* The buffer list consists of just one protection group described
* below:
* +-------------------------+
- * start of prot group --> | PDE_1 |
+ * start of prot group --> | PDE_5 |
+ * +-------------------------+
+ * | PDE_6 |
* +-------------------------+
* | Data BDE |
* +-------------------------+
@@ -1283,30 +1301,58 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct ulp_bde64 *bpl, int datasegcnt)
{
struct scatterlist *sgde = NULL; /* s/g data entry */
- struct lpfc_pde *pde1 = NULL;
+ struct lpfc_pde5 *pde5 = NULL;
+ struct lpfc_pde6 *pde6 = NULL;
dma_addr_t physaddr;
- int i = 0, num_bde = 0;
+ int i = 0, num_bde = 0, status;
int datadir = sc->sc_data_direction;
- int prof = LPFC_PROF_INVALID;
unsigned blksize;
uint32_t reftag;
uint16_t apptagmask, apptagval;
+ uint8_t txop, rxop;
- pde1 = (struct lpfc_pde *) bpl;
- prof = lpfc_sc_to_sli_prof(phba, sc);
-
- if (prof == LPFC_PROF_INVALID)
+ status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+ if (status)
goto out;
- /* extract some info from the scsi command for PDE1*/
+ /* extract some info from the scsi command for pde*/
blksize = lpfc_cmd_blksize(sc);
lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
- /* setup PDE1 with what we have */
- lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
- BG_EC_STOP_ERR);
- lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+ /* setup PDE5 with what we have */
+ pde5 = (struct lpfc_pde5 *) bpl;
+ memset(pde5, 0, sizeof(struct lpfc_pde5));
+ bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+ pde5->reftag = reftag;
+
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+ /* advance bpl and increment bde count */
+ num_bde++;
+ bpl++;
+ pde6 = (struct lpfc_pde6 *) bpl;
+
+ /* setup PDE6 with the rest of the info */
+ memset(pde6, 0, sizeof(struct lpfc_pde6));
+ bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+ bf_set(pde6_optx, pde6, txop);
+ bf_set(pde6_oprx, pde6, rxop);
+ if (datadir == DMA_FROM_DEVICE) {
+ bf_set(pde6_ce, pde6, 1);
+ bf_set(pde6_re, pde6, 1);
+ bf_set(pde6_ae, pde6, 1);
+ }
+ bf_set(pde6_ai, pde6, 1);
+ bf_set(pde6_apptagval, pde6, apptagval);
+
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
+ /* advance bpl and increment bde count */
num_bde++;
bpl++;
@@ -1341,15 +1387,17 @@ out:
* The buffer list for this type consists of one or more of the
* protection groups described below:
* +-------------------------+
- * start of first prot group --> | PDE_1 |
+ * start of first prot group --> | PDE_5 |
* +-------------------------+
- * | PDE_3 (Prot BDE) |
+ * | PDE_6 |
+ * +-------------------------+
+ * | PDE_7 (Prot BDE) |
* +-------------------------+
* | Data BDE |
* +-------------------------+
* |more Data BDE's ... (opt)|
* +-------------------------+
- * start of new prot group --> | PDE_1 |
+ * start of new prot group --> | PDE_5 |
* +-------------------------+
* | ... |
* +-------------------------+
@@ -1368,19 +1416,21 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
{
struct scatterlist *sgde = NULL; /* s/g data entry */
struct scatterlist *sgpe = NULL; /* s/g prot entry */
- struct lpfc_pde *pde1 = NULL;
+ struct lpfc_pde5 *pde5 = NULL;
+ struct lpfc_pde6 *pde6 = NULL;
struct ulp_bde64 *prot_bde = NULL;
dma_addr_t dataphysaddr, protphysaddr;
unsigned short curr_data = 0, curr_prot = 0;
unsigned int split_offset, protgroup_len;
unsigned int protgrp_blks, protgrp_bytes;
unsigned int remainder, subtotal;
- int prof = LPFC_PROF_INVALID;
+ int status;
int datadir = sc->sc_data_direction;
unsigned char pgdone = 0, alldone = 0;
unsigned blksize;
uint32_t reftag;
uint16_t apptagmask, apptagval;
+ uint8_t txop, rxop;
int num_bde = 0;
sgpe = scsi_prot_sglist(sc);
@@ -1393,34 +1443,58 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
return 0;
}
- prof = lpfc_sc_to_sli_prof(phba, sc);
- if (prof == LPFC_PROF_INVALID)
+ status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+ if (status)
goto out;
- /* extract some info from the scsi command for PDE1*/
+ /* extract some info from the scsi command */
blksize = lpfc_cmd_blksize(sc);
lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
split_offset = 0;
do {
- /* setup the first PDE_1 */
- pde1 = (struct lpfc_pde *) bpl;
+ /* setup PDE5 with what we have */
+ pde5 = (struct lpfc_pde5 *) bpl;
+ memset(pde5, 0, sizeof(struct lpfc_pde5));
+ bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+ pde5->reftag = reftag;
- lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
- BG_EC_STOP_ERR);
- lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+ /* Endian convertion if necessary for PDE5 */
+ pde5->word0 = cpu_to_le32(pde5->word0);
+ pde5->reftag = cpu_to_le32(pde5->reftag);
+ /* advance bpl and increment bde count */
+ num_bde++;
+ bpl++;
+ pde6 = (struct lpfc_pde6 *) bpl;
+
+ /* setup PDE6 with the rest of the info */
+ memset(pde6, 0, sizeof(struct lpfc_pde6));
+ bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+ bf_set(pde6_optx, pde6, txop);
+ bf_set(pde6_oprx, pde6, rxop);
+ bf_set(pde6_ce, pde6, 1);
+ bf_set(pde6_re, pde6, 1);
+ bf_set(pde6_ae, pde6, 1);
+ bf_set(pde6_ai, pde6, 1);
+ bf_set(pde6_apptagval, pde6, apptagval);
+
+ /* Endian convertion if necessary for PDE6 */
+ pde6->word0 = cpu_to_le32(pde6->word0);
+ pde6->word1 = cpu_to_le32(pde6->word1);
+ pde6->word2 = cpu_to_le32(pde6->word2);
+
+ /* advance bpl and increment bde count */
num_bde++;
bpl++;
/* setup the first BDE that points to protection buffer */
prot_bde = (struct ulp_bde64 *) bpl;
protphysaddr = sg_dma_address(sgpe);
- prot_bde->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
- prot_bde->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+ prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
+ prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
protgroup_len = sg_dma_len(sgpe);
-
/* must be integer multiple of the DIF block length */
BUG_ON(protgroup_len % 8);
@@ -1428,10 +1502,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
protgrp_bytes = protgrp_blks * blksize;
prot_bde->tus.f.bdeSize = protgroup_len;
- if (datadir == DMA_TO_DEVICE)
- prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- else
- prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR;
prot_bde->tus.w = le32_to_cpu(bpl->tus.w);
curr_prot++;
@@ -1483,6 +1554,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* Move to the next s/g segment if possible */
sgde = sg_next(sgde);
+
}
/* are we done ? */
@@ -1505,7 +1577,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
out:
-
return num_bde;
}
/*
@@ -1827,8 +1898,8 @@ out:
* field of @lpfc_cmd for device with SLI-4 interface spec.
*
* Return codes:
- * 1 - Error
- * 0 - Success
+ * 1 - Error
+ * 0 - Success
**/
static int
lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
@@ -1936,8 +2007,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
* lpfc_hba struct.
*
* Return codes:
- * 1 - Error
- * 0 - Success
+ * 1 - Error
+ * 0 - Success
**/
static inline int
lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
@@ -2241,15 +2312,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
- struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+ struct scsi_cmnd *cmd;
int result;
struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
- struct Scsi_Host *shost = cmd->device->host;
+ struct Scsi_Host *shost;
uint32_t queue_depth, scsi_id;
+ /* Sanity check on return of outstanding command */
+ if (!(lpfc_cmd->pCmd))
+ return;
+ cmd = lpfc_cmd->pCmd;
+ shost = cmd->device->host;
+
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
/* pick up SLI4 exhange busy status from HBA */
@@ -2311,7 +2388,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
case IOSTAT_LOCAL_REJECT:
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
- lpfc_cmd->result == IOERR_ABORT_REQUESTED) {
+ lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
+ lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
cmd->result = ScsiResult(DID_REQUEUE, 0);
break;
}
@@ -2380,14 +2458,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
spin_unlock_irqrestore(shost->host_lock, flags);
} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
- if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
+ if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
time_after(jiffies, pnode->last_change_time +
msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
spin_lock_irqsave(shost->host_lock, flags);
- pnode->cmd_qdepth += pnode->cmd_qdepth *
- LPFC_TGTQ_RAMPUP_PCENT / 100;
- if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
- pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
+ depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
+ / 100;
+ depth = depth ? depth : 1;
+ pnode->cmd_qdepth += depth;
+ if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
+ pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
pnode->last_change_time = jiffies;
spin_unlock_irqrestore(shost->host_lock, flags);
}
@@ -2842,8 +2922,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
goto out_fail_command;
}
- if (vport->cfg_max_scsicmpl_time &&
- (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth))
+ if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
goto out_host_busy;
lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -2989,7 +3068,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
int ret = SUCCESS;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -3173,7 +3254,9 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
lpfc_taskmgmt_name(task_mgmt_cmd),
tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
iocbqrsp->iocb.un.ulpWord[4]);
- } else
+ } else if (status == IOCB_BUSY)
+ ret = FAILED;
+ else
ret = SUCCESS;
lpfc_sli_release_iocbq(phba, iocbqrsp);
@@ -3305,7 +3388,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3370,7 +3455,9 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
return FAILED;
}
pnode = rdata->pnode;
- fc_block_scsi_eh(cmnd);
+ status = fc_block_scsi_eh(cmnd);
+ if (status)
+ return status;
status = lpfc_chk_tgt_mapped(vport, cmnd);
if (status == FAILED) {
@@ -3436,7 +3523,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
- fc_block_scsi_eh(cmnd);
+ ret = fc_block_scsi_eh(cmnd);
+ if (ret)
+ return ret;
/*
* Since the driver manages a single bus device, reset all
@@ -3509,11 +3598,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t total = 0;
uint32_t num_to_alloc = 0;
int num_allocated = 0;
+ uint32_t sdev_cnt;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
sdev->hostdata = rport->dd_data;
+ sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
* Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -3525,6 +3616,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
total = phba->total_scsi_bufs;
num_to_alloc = vport->cfg_lun_queue_depth + 2;
+ /* If allocated buffers are enough do nothing */
+ if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total)
+ return 0;
+
/* Allow some exchanges to be available always to complete discovery */
if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
@@ -3606,6 +3701,9 @@ lpfc_slave_configure(struct scsi_device *sdev)
static void
lpfc_slave_destroy(struct scsi_device *sdev)
{
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ atomic_dec(&phba->sdev_cnt);
sdev->hostdata = NULL;
return;
}