/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2005 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/delay.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#define LPFC_ABORT_WAIT 2
+static inline void
+lpfc_block_requests(struct lpfc_hba * phba)
+{
+ down(&phba->hba_can_block);
+ scsi_block_requests(phba->host);
+}
+
+static inline void
+lpfc_unblock_requests(struct lpfc_hba * phba)
+{
+ scsi_unblock_requests(phba->host);
+ up(&phba->hba_can_block);
+}
+
/*
* This routine allocates a scsi buffer, which contains all the necessary
* information needed to initiate a SCSI I/O. The non-DMAable buffer region
lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
{
unsigned long iflag = 0;
+ /*
+ * There are only two special cases to consider. (1) the scsi command
+ * requested scatter-gather usage or (2) the scsi command allocated
+ * a request buffer, but did not request use_sg. There is a third
+ * case, but it does not require resource deallocation.
+ */
+ if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
+ dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
+ psb->seg_cnt, psb->pCmd->sc_data_direction);
+ } else {
+ if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
+ dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
+ psb->pCmd->request_bufflen,
+ psb->pCmd->sc_data_direction);
+ }
+ }
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->pCmd = NULL;
return 0;
}
-static void
-lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
-{
- /*
- * There are only two special cases to consider. (1) the scsi command
- * requested scatter-gather usage or (2) the scsi command allocated
- * a request buffer, but did not request use_sg. There is a third
- * case, but it does not require resource deallocation.
- */
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
-}
-
static void
lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
{
sdev = cmd->device;
cmd->scsi_done(cmd);
- if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
- return;
- }
-
- if (!result && pnode != NULL &&
+ if (!result &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
((jiffies - pnode->last_q_full_time) >
* Check for queue full. If the lun is reporting queue full, then
* back off the lun queue depth to prevent target overloads.
*/
- if (result == SAM_STAT_TASK_SET_FULL && pnode != NULL) {
+ if (result == SAM_STAT_TASK_SET_FULL) {
pnode->last_q_full_time = jiffies;
shost_for_each_device(tmp_sdev, sdev->host) {
}
}
- lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
static int
lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd,
- unsigned int lun,
uint8_t task_mgmt_cmd)
{
struct lpfc_sli *psli;
struct lpfc_iocbq *piocbq;
IOCB_t *piocb;
struct fcp_cmnd *fcp_cmnd;
- struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
+ struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device;
+ struct lpfc_rport_data *rdata = scsi_dev->hostdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
- int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun);
+ int_to_scsilun(lpfc_cmd->pCmd->device->lun,
+ &lpfc_cmd->fcp_cmnd->fcp_lun);
fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
piocb->ulpCommand = CMD_FCP_ICMND64_CR;
piocb->ulpTimeout = lpfc_cmd->timeout;
}
+ lpfc_cmd->rdata = rdata;
+
+ switch (task_mgmt_cmd) {
+ case FCP_LUN_RESET:
+ /* Issue LUN Reset to TGT <num> LUN <num> */
+ lpfc_printf_log(phba,
+ KERN_INFO,
+ LOG_FCP,
+ "%d:0703 Issue LUN Reset to TGT %d LUN %d "
+ "Data: x%x x%x\n",
+ phba->brd_no,
+ scsi_dev->id, scsi_dev->lun,
+ ndlp->nlp_rpi, ndlp->nlp_flag);
+
+ break;
+ case FCP_ABORT_TASK_SET:
+ /* Issue Abort Task Set to TGT <num> LUN <num> */
+ lpfc_printf_log(phba,
+ KERN_INFO,
+ LOG_FCP,
+ "%d:0701 Issue Abort Task Set to TGT %d LUN %d "
+ "Data: x%x x%x\n",
+ phba->brd_no,
+ scsi_dev->id, scsi_dev->lun,
+ ndlp->nlp_rpi, ndlp->nlp_flag);
+
+ break;
+ case FCP_TARGET_RESET:
+ /* Issue Target Reset to TGT <num> */
+ lpfc_printf_log(phba,
+ KERN_INFO,
+ LOG_FCP,
+ "%d:0702 Issue Target Reset to TGT %d "
+ "Data: x%x x%x\n",
+ phba->brd_no,
+ scsi_dev->id, ndlp->nlp_rpi,
+ ndlp->nlp_flag);
+ break;
+ }
+
return (1);
}
static int
-lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
- unsigned tgt_id, unsigned int lun,
- struct lpfc_rport_data *rdata)
+lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
{
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
- lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
- FCP_TARGET_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
if (!ret)
return FAILED;
if (!iocbqrsp)
return FAILED;
- /* Issue Target Reset to TGT <num> */
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0702 Issue Target Reset to TGT %d "
- "Data: x%x x%x\n",
- phba->brd_no, tgt_id, rdata->pnode->nlp_rpi,
- rdata->pnode->nlp_flag);
-
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
const char *
lpfc_info(struct Scsi_Host *host)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0];
int len;
static char lpfcinfobuf[384];
lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
struct lpfc_hba *phba =
- (struct lpfc_hba *) cmnd->device->host->hostdata;
+ (struct lpfc_hba *) cmnd->device->host->hostdata[0];
struct lpfc_sli *psli = &phba->sli;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
return 0;
out_host_busy_free_buf:
- lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
return 0;
}
-static void
-lpfc_block_error_handler(struct scsi_cmnd *cmnd)
-{
- struct Scsi_Host *shost = cmnd->device->host;
- struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
-
- spin_lock_irq(shost->host_lock);
- while (rport->port_state == FC_PORTSTATE_BLOCKED) {
- spin_unlock_irq(shost->host_lock);
- msleep(1000);
- spin_lock_irq(shost->host_lock);
- }
- spin_unlock_irq(shost->host_lock);
- return;
-}
static int
lpfc_abort_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
struct lpfc_iocbq *iocb;
struct lpfc_iocbq *abtsiocb;
unsigned int loop_count = 0;
int ret = SUCCESS;
- lpfc_block_error_handler(cmnd);
+ lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
cmnd->device->lun, cmnd->serial_number);
spin_unlock_irq(shost->host_lock);
+ lpfc_unblock_requests(phba);
return ret;
}
lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
struct lpfc_scsi_buf *lpfc_cmd;
struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
int ret = FAILED;
int cnt, loopcnt;
- lpfc_block_error_handler(cmnd);
+ lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock);
/*
* If target is not in a MAPPED state, delay the reset until
if (lpfc_cmd == NULL)
goto out;
+ lpfc_cmd->pCmd = cmnd;
lpfc_cmd->timeout = 60;
lpfc_cmd->scsi_hba = phba;
- lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
- FCP_LUN_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
if (!ret)
goto out_free_scsi_buf;
if (iocbqrsp == NULL)
goto out_free_scsi_buf;
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0703 Issue LUN Reset to TGT %d LUN %d "
- "Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
- cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
-
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
cmd_status = iocbqrsp->iocb.ulpStatus;
lpfc_sli_release_iocbq(phba, iocbqrsp);
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
/*
* All outstanding txcmplq I/Os should have been aborted by the device.
}
out_free_scsi_buf:
- lpfc_release_scsi_buf(phba, lpfc_cmd);
-
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 SCSI layer issued LUN reset (%d, %d) "
"Data: x%x x%x x%x\n",
out:
spin_unlock_irq(shost->host_lock);
+ lpfc_unblock_requests(phba);
return ret;
}
lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
struct lpfc_nodelist *ndlp = NULL;
int match;
int ret = FAILED, i, err_count = 0;
int cnt, loopcnt;
+ unsigned int midlayer_id = 0;
struct lpfc_scsi_buf * lpfc_cmd;
- lpfc_block_error_handler(cmnd);
+ lpfc_block_requests(phba);
spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba);
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
+ lpfc_cmd->pCmd = cmnd;
lpfc_cmd->scsi_hba = phba;
/*
* targets known to the driver. Should any target reset
* fail, this routine returns failure to the midlayer.
*/
- for (i = 0; i < LPFC_MAX_TARGET; i++) {
+ midlayer_id = cmnd->device->id;
+ for (i = 0; i < MAX_FCP_TARGET; i++) {
/* Search the mapped list for this target ID */
match = 0;
list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
- ndlp->rport->dd_data);
+ lpfc_cmd->pCmd->device->id = i;
+ lpfc_cmd->pCmd->device->hostdata = ndlp->rport->dd_data;
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0700 Bus Reset on target %d failed\n",
+ "%d:0713 Bus Reset on target %d failed\n",
phba->brd_no, i);
err_count++;
}
* the targets. Unfortunately, some targets do not abide by
* this forcing the driver to double check.
*/
+ cmnd->device->id = midlayer_id;
cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST);
if (cnt)
phba->brd_no, ret);
out:
spin_unlock_irq(shost->host_lock);
+ lpfc_unblock_requests(phba);
return ret;
}
static int
lpfc_slave_alloc(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0];
struct lpfc_scsi_buf *scsi_buf = NULL;
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
uint32_t total = 0, i;
static int
lpfc_slave_configure(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata;
+ struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata[0];
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)