diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 234 |
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; } |