Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (182 commits) [SCSI] aacraid: add an ifdef'd device delete case instead of taking the device offline [SCSI] aacraid: prohibit access to array container space [SCSI] aacraid: add support for handling ATA pass-through commands. [SCSI] aacraid: expose physical devices for models with newer firmware [SCSI] aacraid: respond automatically to volumes added by config tool [SCSI] fcoe: fix fcoe module ref counting [SCSI] libfcoe: FIP Keep-Alive messages for VPorts are sent with incorrect port_id and wwn [SCSI] libfcoe: Fix incorrect MAC address clearing [SCSI] fcoe: fix a circular locking issue with rtnl and sysfs mutex [SCSI] libfc: Move the port_id into lport [SCSI] fcoe: move link speed checking into its own routine [SCSI] libfc: Remove extra pointer check [SCSI] libfc: Remove unused fc_get_host_port_type [SCSI] fcoe: fixes wrong error exit in fcoe_create [SCSI] libfc: set seq_id for incoming sequence [SCSI] qla2xxx: Updates to ISP82xx support. [SCSI] qla2xxx: Optionally disable target reset. [SCSI] qla2xxx: ensure flash operation and host reset via sg_reset are mutually exclusive [SCSI] qla2xxx: Silence bogus warning by gcc for wrap and did. [SCSI] qla2xxx: T10 DIF support added. ...
This commit is contained in:
commit
33cf23b0a5
161 changed files with 15308 additions and 4156 deletions
23
MAINTAINERS
23
MAINTAINERS
|
@ -131,19 +131,12 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/net/typhoon*
|
||||
|
||||
3W-9XXX SATA-RAID CONTROLLER DRIVER
|
||||
M: Adam Radford <linuxraid@amcc.com>
|
||||
3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
|
||||
M: Adam Radford <linuxraid@lsi.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
W: http://www.amcc.com
|
||||
W: http://www.lsi.com
|
||||
S: Supported
|
||||
F: drivers/scsi/3w-9xxx*
|
||||
|
||||
3W-XXXX ATA-RAID CONTROLLER DRIVER
|
||||
M: Adam Radford <linuxraid@amcc.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
W: http://www.amcc.com
|
||||
S: Supported
|
||||
F: drivers/scsi/3w-xxxx*
|
||||
F: drivers/scsi/3w-*
|
||||
|
||||
53C700 AND 53C700-66 SCSI DRIVER
|
||||
M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
|
||||
|
@ -4621,6 +4614,14 @@ S: Supported
|
|||
F: Documentation/scsi/LICENSE.qla2xxx
|
||||
F: drivers/scsi/qla2xxx/
|
||||
|
||||
QLOGIC QLA4XXX iSCSI DRIVER
|
||||
M: Ravi Anand <ravi.anand@qlogic.com>
|
||||
M: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
|
||||
M: iscsi-driver@qlogic.com
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/scsi/qla4xxx/
|
||||
|
||||
QLOGIC QLA3XXX NETWORK DRIVER
|
||||
M: Ron Mercer <ron.mercer@qlogic.com>
|
||||
M: linux-driver@qlogic.com
|
||||
|
|
|
@ -5064,7 +5064,7 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
|
|||
if (!timeleft) {
|
||||
printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
|
||||
ioc->name, __func__);
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
}
|
||||
goto out;
|
||||
|
@ -6456,10 +6456,15 @@ out:
|
|||
issue_hard_reset = 0;
|
||||
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
|
||||
ioc->name, __func__);
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
if (retry_count == 0) {
|
||||
if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
|
||||
retry_count++;
|
||||
} else
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
/* attempt one retry for a timed out command */
|
||||
if (!retry_count) {
|
||||
if (retry_count < 2) {
|
||||
printk(MYIOC_s_INFO_FMT
|
||||
"Attempting Retry Config request"
|
||||
" type 0x%x, page 0x%x,"
|
||||
|
@ -6904,6 +6909,172 @@ mpt_halt_firmware(MPT_ADAPTER *ioc)
|
|||
}
|
||||
EXPORT_SYMBOL(mpt_halt_firmware);
|
||||
|
||||
/**
|
||||
* mpt_SoftResetHandler - Issues a less expensive reset
|
||||
* @ioc: Pointer to MPT_ADAPTER structure
|
||||
* @sleepFlag: Indicates if sleep or schedule must be called.
|
||||
|
||||
*
|
||||
* Returns 0 for SUCCESS or -1 if FAILED.
|
||||
*
|
||||
* Message Unit Reset - instructs the IOC to reset the Reply Post and
|
||||
* Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
|
||||
* All posted buffers are freed, and event notification is turned off.
|
||||
* IOC doesnt reply to any outstanding request. This will transfer IOC
|
||||
* to READY state.
|
||||
**/
|
||||
int
|
||||
mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
|
||||
{
|
||||
int rc;
|
||||
int ii;
|
||||
u8 cb_idx;
|
||||
unsigned long flags;
|
||||
u32 ioc_state;
|
||||
unsigned long time_count;
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
|
||||
ioc->name));
|
||||
|
||||
ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
|
||||
|
||||
if (mpt_fwfault_debug)
|
||||
mpt_halt_firmware(ioc);
|
||||
|
||||
if (ioc_state == MPI_IOC_STATE_FAULT ||
|
||||
ioc_state == MPI_IOC_STATE_RESET) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"skipping, either in FAULT or RESET state!\n", ioc->name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioc->bus_type == FC) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"skipping, because the bus type is FC!\n", ioc->name));
|
||||
return -1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||
if (ioc->ioc_reset_in_progress) {
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
ioc->ioc_reset_in_progress = 1;
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
|
||||
rc = -1;
|
||||
|
||||
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
|
||||
if (MptResetHandlers[cb_idx])
|
||||
mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||
if (ioc->taskmgmt_in_progress) {
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
/* Disable reply interrupts (also blocks FreeQ) */
|
||||
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
|
||||
ioc->active = 0;
|
||||
time_count = jiffies;
|
||||
|
||||
rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
|
||||
|
||||
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
|
||||
if (MptResetHandlers[cb_idx])
|
||||
mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
|
||||
if (ioc_state != MPI_IOC_STATE_READY)
|
||||
goto out;
|
||||
|
||||
for (ii = 0; ii < 5; ii++) {
|
||||
/* Get IOC facts! Allow 5 retries */
|
||||
rc = GetIocFacts(ioc, sleepFlag,
|
||||
MPT_HOSTEVENT_IOC_RECOVER);
|
||||
if (rc == 0)
|
||||
break;
|
||||
if (sleepFlag == CAN_SLEEP)
|
||||
msleep(100);
|
||||
else
|
||||
mdelay(100);
|
||||
}
|
||||
if (ii == 5)
|
||||
goto out;
|
||||
|
||||
rc = PrimeIocFifos(ioc);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = SendIocInit(ioc, sleepFlag);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = SendEventNotification(ioc, 1, sleepFlag);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (ioc->hard_resets < -1)
|
||||
ioc->hard_resets++;
|
||||
|
||||
/*
|
||||
* At this point, we know soft reset succeeded.
|
||||
*/
|
||||
|
||||
ioc->active = 1;
|
||||
CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
|
||||
|
||||
out:
|
||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||
ioc->ioc_reset_in_progress = 0;
|
||||
ioc->taskmgmt_quiesce_io = 0;
|
||||
ioc->taskmgmt_in_progress = 0;
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
|
||||
if (ioc->active) { /* otherwise, hard reset coming */
|
||||
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
|
||||
if (MptResetHandlers[cb_idx])
|
||||
mpt_signal_reset(cb_idx, ioc,
|
||||
MPT_IOC_POST_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"SoftResetHandler: completed (%d seconds): %s\n",
|
||||
ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
|
||||
((rc == 0) ? "SUCCESS" : "FAILED")));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt_Soft_Hard_ResetHandler - Try less expensive reset
|
||||
* @ioc: Pointer to MPT_ADAPTER structure
|
||||
* @sleepFlag: Indicates if sleep or schedule must be called.
|
||||
|
||||
*
|
||||
* Returns 0 for SUCCESS or -1 if FAILED.
|
||||
* Try for softreset first, only if it fails go for expensive
|
||||
* HardReset.
|
||||
**/
|
||||
int
|
||||
mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
|
||||
int ret = -1;
|
||||
|
||||
ret = mpt_SoftResetHandler(ioc, sleepFlag);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
ret = mpt_HardResetHandler(ioc, sleepFlag);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/*
|
||||
* Reset Handling
|
||||
|
|
|
@ -76,8 +76,8 @@
|
|||
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
|
||||
#endif
|
||||
|
||||
#define MPT_LINUX_VERSION_COMMON "3.04.14"
|
||||
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.14"
|
||||
#define MPT_LINUX_VERSION_COMMON "3.04.15"
|
||||
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.15"
|
||||
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
|
||||
|
||||
#define show_mptmod_ver(s,ver) \
|
||||
|
@ -940,6 +940,7 @@ extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
|
|||
extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
|
||||
extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
|
||||
extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
|
||||
extern int mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
|
||||
extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
|
||||
extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
|
||||
extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
|
||||
|
|
|
@ -128,7 +128,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags
|
|||
struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
|
||||
static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
|
||||
struct buflist *buflist, MPT_ADAPTER *ioc);
|
||||
static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
|
||||
|
||||
/*
|
||||
* Reset Handler cleanup function
|
||||
|
@ -275,45 +274,6 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/* mptctl_timeout_expired
|
||||
*
|
||||
* Expecting an interrupt, however timed out.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
|
||||
ioc->name, __func__));
|
||||
|
||||
if (mpt_fwfault_debug)
|
||||
mpt_halt_firmware(ioc);
|
||||
|
||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||
if (ioc->ioc_reset_in_progress) {
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
|
||||
|
||||
if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
|
||||
return;
|
||||
|
||||
/* Issue a reset for this device.
|
||||
* The IOC is not responding.
|
||||
*/
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
|
||||
ioc->name));
|
||||
CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
}
|
||||
|
||||
static int
|
||||
mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
|
@ -343,12 +303,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* mptctl_bus_reset
|
||||
*
|
||||
* Bus reset code.
|
||||
*
|
||||
*/
|
||||
static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
||||
static int
|
||||
mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
|
||||
{
|
||||
MPT_FRAME_HDR *mf;
|
||||
SCSITaskMgmt_t *pScsiTm;
|
||||
|
@ -359,13 +315,6 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
unsigned long time_count;
|
||||
u16 iocstatus;
|
||||
|
||||
/* bus reset is only good for SCSI IO, RAID PASSTHRU */
|
||||
if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
|
||||
function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
|
||||
"TaskMgmt, not SCSI_IO!!\n", ioc->name));
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
mutex_lock(&ioc->taskmgmt_cmds.mutex);
|
||||
if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
|
||||
|
@ -375,15 +324,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
|
||||
retval = 0;
|
||||
|
||||
/* Send request
|
||||
*/
|
||||
mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
|
||||
if (mf == NULL) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
|
||||
"TaskMgmt, no msg frames!!\n", ioc->name));
|
||||
dtmprintk(ioc,
|
||||
printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
|
||||
ioc->name));
|
||||
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
||||
retval = -ENOMEM;
|
||||
goto mptctl_bus_reset_done;
|
||||
goto tm_done;
|
||||
}
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
|
||||
|
@ -392,10 +340,13 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
pScsiTm = (SCSITaskMgmt_t *) mf;
|
||||
memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
|
||||
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
|
||||
pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
|
||||
pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
|
||||
pScsiTm->TargetID = 0;
|
||||
pScsiTm->Bus = 0;
|
||||
pScsiTm->TaskType = tm_type;
|
||||
if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
|
||||
(ioc->bus_type == FC))
|
||||
pScsiTm->MsgFlags =
|
||||
MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
|
||||
pScsiTm->TargetID = target_id;
|
||||
pScsiTm->Bus = bus_id;
|
||||
pScsiTm->ChainOffset = 0;
|
||||
pScsiTm->Reserved = 0;
|
||||
pScsiTm->Reserved1 = 0;
|
||||
|
@ -413,17 +364,16 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
timeout = 30;
|
||||
break;
|
||||
case SPI:
|
||||
default:
|
||||
timeout = 2;
|
||||
default:
|
||||
timeout = 10;
|
||||
break;
|
||||
}
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"TaskMgmt type=%d timeout=%ld\n",
|
||||
ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
|
||||
dtmprintk(ioc,
|
||||
printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
|
||||
ioc->name, tm_type, timeout));
|
||||
|
||||
INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
|
||||
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
|
||||
time_count = jiffies;
|
||||
if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
|
||||
(ioc->facts.MsgVersion >= MPI_VERSION_01_05))
|
||||
|
@ -432,17 +382,20 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
|
||||
sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
|
||||
if (retval != 0) {
|
||||
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
|
||||
dfailprintk(ioc,
|
||||
printk(MYIOC_s_ERR_FMT
|
||||
"TaskMgmt send_handshake FAILED!"
|
||||
" (ioc %p, mf %p, rc=%d) \n", ioc->name,
|
||||
ioc, mf, retval));
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
mpt_clear_taskmgmt_in_progress_flag(ioc);
|
||||
goto mptctl_bus_reset_done;
|
||||
goto tm_done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now wait for the command to complete */
|
||||
ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
|
||||
|
||||
if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"TaskMgmt failed\n", ioc->name));
|
||||
|
@ -452,14 +405,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
retval = 0;
|
||||
else
|
||||
retval = -1; /* return failure */
|
||||
goto mptctl_bus_reset_done;
|
||||
goto tm_done;
|
||||
}
|
||||
|
||||
if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"TaskMgmt failed\n", ioc->name));
|
||||
retval = -1; /* return failure */
|
||||
goto mptctl_bus_reset_done;
|
||||
goto tm_done;
|
||||
}
|
||||
|
||||
pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
|
||||
|
@ -467,7 +420,7 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
"TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
|
||||
"iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
|
||||
"term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
|
||||
pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
||||
pScsiTmReply->TargetID, tm_type,
|
||||
le16_to_cpu(pScsiTmReply->IOCStatus),
|
||||
le32_to_cpu(pScsiTmReply->IOCLogInfo),
|
||||
pScsiTmReply->ResponseCode,
|
||||
|
@ -485,13 +438,71 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
|
|||
retval = -1; /* return failure */
|
||||
}
|
||||
|
||||
|
||||
mptctl_bus_reset_done:
|
||||
tm_done:
|
||||
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
|
||||
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/* mptctl_timeout_expired
|
||||
*
|
||||
* Expecting an interrupt, however timed out.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret_val = -1;
|
||||
SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
|
||||
u8 function = mf->u.hdr.Function;
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
|
||||
ioc->name, __func__));
|
||||
|
||||
if (mpt_fwfault_debug)
|
||||
mpt_halt_firmware(ioc);
|
||||
|
||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||
if (ioc->ioc_reset_in_progress) {
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
|
||||
|
||||
|
||||
CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
|
||||
|
||||
if (ioc->bus_type == SAS) {
|
||||
if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
|
||||
ret_val = mptctl_do_taskmgmt(ioc,
|
||||
MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
|
||||
scsi_req->Bus, scsi_req->TargetID);
|
||||
else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
|
||||
ret_val = mptctl_do_taskmgmt(ioc,
|
||||
MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
||||
scsi_req->Bus, 0);
|
||||
if (!ret_val)
|
||||
return;
|
||||
} else {
|
||||
if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
|
||||
(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
|
||||
ret_val = mptctl_do_taskmgmt(ioc,
|
||||
MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
||||
scsi_req->Bus, 0);
|
||||
if (!ret_val)
|
||||
return;
|
||||
}
|
||||
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
|
||||
ioc->name));
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
}
|
||||
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/* mptctl_ioc_reset
|
||||
|
@ -1318,6 +1329,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
|
|||
if (ioc->sh) {
|
||||
shost_for_each_device(sdev, ioc->sh) {
|
||||
vdevice = sdev->hostdata;
|
||||
if (vdevice == NULL || vdevice->vtarget == NULL)
|
||||
continue;
|
||||
if (vdevice->vtarget->tflags &
|
||||
MPT_TARGET_FLAGS_RAID_COMPONENT)
|
||||
continue;
|
||||
|
@ -1439,6 +1452,8 @@ mptctl_gettargetinfo (unsigned long arg)
|
|||
if (!maxWordsLeft)
|
||||
continue;
|
||||
vdevice = sdev->hostdata;
|
||||
if (vdevice == NULL || vdevice->vtarget == NULL)
|
||||
continue;
|
||||
if (vdevice->vtarget->tflags &
|
||||
MPT_TARGET_FLAGS_RAID_COMPONENT)
|
||||
continue;
|
||||
|
@ -1967,6 +1982,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
|
|||
struct scsi_target *starget = scsi_target(sdev);
|
||||
VirtTarget *vtarget = starget->hostdata;
|
||||
|
||||
if (vtarget == NULL)
|
||||
continue;
|
||||
|
||||
if ((pScsiReq->TargetID == vtarget->id) &&
|
||||
(pScsiReq->Bus == vtarget->channel) &&
|
||||
(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
|
||||
|
@ -2991,6 +3009,14 @@ static int __init mptctl_init(void)
|
|||
}
|
||||
|
||||
mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
|
||||
if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
|
||||
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
|
||||
mpt_deregister(mptctl_id);
|
||||
misc_deregister(&mptctl_miscdev);
|
||||
err = -EBUSY;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
mpt_reset_register(mptctl_id, mptctl_ioc_reset);
|
||||
mpt_event_register(mptctl_id, mptctl_event_process);
|
||||
|
||||
|
@ -3010,12 +3036,15 @@ static void mptctl_exit(void)
|
|||
printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
|
||||
mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
|
||||
|
||||
/* De-register event handler from base module */
|
||||
mpt_event_deregister(mptctl_id);
|
||||
|
||||
/* De-register reset handler from base module */
|
||||
mpt_reset_deregister(mptctl_id);
|
||||
|
||||
/* De-register callback handler from base module */
|
||||
mpt_deregister(mptctl_taskmgmt_id);
|
||||
mpt_deregister(mptctl_id);
|
||||
mpt_reset_deregister(mptctl_taskmgmt_id);
|
||||
|
||||
mpt_device_driver_deregister(MPTCTL_DRIVER);
|
||||
|
||||
|
|
|
@ -482,6 +482,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
|
|||
if (vtarget) {
|
||||
vtarget->id = pg0->CurrentTargetID;
|
||||
vtarget->channel = pg0->CurrentBus;
|
||||
vtarget->deleted = 0;
|
||||
}
|
||||
}
|
||||
*((struct mptfc_rport_info **)rport->dd_data) = ri;
|
||||
|
@ -1092,6 +1093,8 @@ mptfc_setup_reset(struct work_struct *work)
|
|||
container_of(work, MPT_ADAPTER, fc_setup_reset_work);
|
||||
u64 pn;
|
||||
struct mptfc_rport_info *ri;
|
||||
struct scsi_target *starget;
|
||||
VirtTarget *vtarget;
|
||||
|
||||
/* reset about to happen, delete (block) all rports */
|
||||
list_for_each_entry(ri, &ioc->fc_rports, list) {
|
||||
|
@ -1099,6 +1102,12 @@ mptfc_setup_reset(struct work_struct *work)
|
|||
ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
|
||||
fc_remote_port_delete(ri->rport); /* won't sleep */
|
||||
ri->rport = NULL;
|
||||
starget = ri->starget;
|
||||
if (starget) {
|
||||
vtarget = starget->hostdata;
|
||||
if (vtarget)
|
||||
vtarget->deleted = 1;
|
||||
}
|
||||
|
||||
pn = (u64)ri->pg0.WWPN.High << 32 |
|
||||
(u64)ri->pg0.WWPN.Low;
|
||||
|
@ -1119,6 +1128,8 @@ mptfc_rescan_devices(struct work_struct *work)
|
|||
int ii;
|
||||
u64 pn;
|
||||
struct mptfc_rport_info *ri;
|
||||
struct scsi_target *starget;
|
||||
VirtTarget *vtarget;
|
||||
|
||||
/* start by tagging all ports as missing */
|
||||
list_for_each_entry(ri, &ioc->fc_rports, list) {
|
||||
|
@ -1146,6 +1157,12 @@ mptfc_rescan_devices(struct work_struct *work)
|
|||
MPT_RPORT_INFO_FLAGS_MISSING);
|
||||
fc_remote_port_delete(ri->rport); /* won't sleep */
|
||||
ri->rport = NULL;
|
||||
starget = ri->starget;
|
||||
if (starget) {
|
||||
vtarget = starget->hostdata;
|
||||
if (vtarget)
|
||||
vtarget->deleted = 1;
|
||||
}
|
||||
|
||||
pn = (u64)ri->pg0.WWPN.High << 32 |
|
||||
(u64)ri->pg0.WWPN.Low;
|
||||
|
@ -1358,6 +1375,9 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
|||
unsigned long flags;
|
||||
int rc=1;
|
||||
|
||||
if (ioc->bus_type != FC)
|
||||
return 0;
|
||||
|
||||
devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
|
||||
ioc->name, event));
|
||||
|
||||
|
@ -1396,7 +1416,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
|||
unsigned long flags;
|
||||
|
||||
rc = mptscsih_ioc_reset(ioc,reset_phase);
|
||||
if (rc == 0)
|
||||
if ((ioc->bus_type != FC) || (!rc))
|
||||
return rc;
|
||||
|
||||
|
||||
|
|
|
@ -1894,7 +1894,7 @@ static struct scsi_host_template mptsas_driver_template = {
|
|||
.module = THIS_MODULE,
|
||||
.proc_name = "mptsas",
|
||||
.proc_info = mptscsih_proc_info,
|
||||
.name = "MPT SPI Host",
|
||||
.name = "MPT SAS Host",
|
||||
.info = mptscsih_info,
|
||||
.queuecommand = mptsas_qcmd,
|
||||
.target_alloc = mptsas_target_alloc,
|
||||
|
@ -2038,11 +2038,13 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
|
|||
|
||||
timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
|
||||
10 * HZ);
|
||||
if (!timeleft) {
|
||||
/* On timeout reset the board */
|
||||
if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
||||
error = -ETIME;
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
error = -ETIMEDOUT;
|
||||
if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
|
||||
goto out_unlock;
|
||||
if (!timeleft)
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
@ -2223,11 +2225,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|||
mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
|
||||
|
||||
timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
|
||||
if (!timeleft) {
|
||||
printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
|
||||
/* On timeout reset the board */
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
ret = -ETIMEDOUT;
|
||||
if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
|
||||
ret = -ETIME;
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
mf = NULL;
|
||||
if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
|
||||
goto unmap;
|
||||
if (!timeleft)
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
goto unmap;
|
||||
}
|
||||
mf = NULL;
|
||||
|
@ -2518,6 +2523,12 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
|
|||
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||
|
||||
error = mpt_config(ioc, &cfg);
|
||||
|
||||
if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
|
||||
error = -ENODEV;
|
||||
goto out_free_consistent;
|
||||
}
|
||||
|
||||
if (error)
|
||||
goto out_free_consistent;
|
||||
|
||||
|
@ -2594,14 +2605,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
|
|||
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||
|
||||
error = mpt_config(ioc, &cfg);
|
||||
if (error)
|
||||
goto out_free_consistent;
|
||||
|
||||
if (!buffer->NumPhys) {
|
||||
if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
|
||||
error = -ENODEV;
|
||||
goto out_free_consistent;
|
||||
}
|
||||
|
||||
if (error)
|
||||
goto out_free_consistent;
|
||||
|
||||
/* save config data */
|
||||
port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
|
||||
port_info->phy_info = kcalloc(port_info->num_phys,
|
||||
|
@ -2677,7 +2688,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
|
|||
|
||||
if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
|
||||
error = -ENODEV;
|
||||
goto out;
|
||||
goto out_free_consistent;
|
||||
}
|
||||
|
||||
if (error)
|
||||
|
@ -2833,7 +2844,7 @@ mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
|
|||
if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
|
||||
goto out_free;
|
||||
if (!timeleft)
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
|
@ -4098,6 +4109,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
|||
cfg.pageAddr = (channel << 8) + id;
|
||||
cfg.cfghdr.hdr = &hdr;
|
||||
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
||||
cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
|
||||
|
||||
if (mpt_config(ioc, &cfg) != 0)
|
||||
goto out;
|
||||
|
@ -4717,7 +4729,7 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
|
|||
if (issue_reset) {
|
||||
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
|
||||
ioc->name, __func__);
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
}
|
||||
mptsas_free_fw_event(ioc, fw_event);
|
||||
}
|
||||
|
@ -4779,6 +4791,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
|
|||
struct fw_event_work *fw_event;
|
||||
unsigned long delay;
|
||||
|
||||
if (ioc->bus_type != SAS)
|
||||
return 0;
|
||||
|
||||
/* events turned off due to host reset or driver unloading */
|
||||
if (ioc->fw_events_off)
|
||||
return 0;
|
||||
|
@ -5073,6 +5088,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
|
|||
struct mptsas_portinfo *p, *n;
|
||||
int i;
|
||||
|
||||
if (!ioc->sh) {
|
||||
printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
|
||||
mpt_detach(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
mptsas_shutdown(pdev);
|
||||
|
||||
mptsas_del_device_components(ioc);
|
||||
|
|
|
@ -110,7 +110,7 @@ struct fw_event_work {
|
|||
MPT_ADAPTER *ioc;
|
||||
u32 event;
|
||||
u8 retries;
|
||||
u8 event_data[1];
|
||||
u8 __attribute__((aligned(4))) event_data[1];
|
||||
};
|
||||
|
||||
struct mptsas_discovery_event {
|
||||
|
|
|
@ -1149,11 +1149,6 @@ mptscsih_remove(struct pci_dev *pdev)
|
|||
MPT_SCSI_HOST *hd;
|
||||
int sz1;
|
||||
|
||||
if(!host) {
|
||||
mpt_detach(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
scsi_remove_host(host);
|
||||
|
||||
if((hd = shost_priv(host)) == NULL)
|
||||
|
@ -1711,7 +1706,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
|
|||
if (issue_hard_reset) {
|
||||
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
|
||||
ioc->name, __func__);
|
||||
retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
}
|
||||
|
||||
|
@ -1728,6 +1723,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
|
|||
case FC:
|
||||
return 40;
|
||||
case SAS:
|
||||
return 30;
|
||||
case SPI:
|
||||
default:
|
||||
return 10;
|
||||
|
@ -1777,7 +1773,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
|
|||
ioc->name, SCpnt));
|
||||
SCpnt->result = DID_NO_CONNECT << 16;
|
||||
SCpnt->scsi_done(SCpnt);
|
||||
retval = 0;
|
||||
retval = SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1792,6 +1788,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Task aborts are not supported for volumes.
|
||||
*/
|
||||
if (vdevice->vtarget->raidVolume) {
|
||||
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"task abort: raid volume (sc=%p)\n",
|
||||
ioc->name, SCpnt));
|
||||
SCpnt->result = DID_RESET << 16;
|
||||
retval = FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Find this command
|
||||
*/
|
||||
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
|
||||
|
@ -1991,7 +1998,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
|
|||
/* If our attempts to reset the host failed, then return a failed
|
||||
* status. The host will be taken off line by the SCSI mid-layer.
|
||||
*/
|
||||
retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
if (retval < 0)
|
||||
status = FAILED;
|
||||
else
|
||||
|
@ -2344,6 +2351,8 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
|
|||
starget = scsi_target(sdev);
|
||||
vtarget = starget->hostdata;
|
||||
vdevice = sdev->hostdata;
|
||||
if (!vdevice)
|
||||
return;
|
||||
|
||||
mptscsih_search_running_cmds(hd, vdevice);
|
||||
vtarget->num_luns--;
|
||||
|
@ -3040,7 +3049,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
|
|||
if (!timeleft) {
|
||||
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
|
||||
ioc->name, __func__);
|
||||
mpt_HardResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
}
|
||||
goto out;
|
||||
|
|
|
@ -210,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
|
|||
target->maxOffset = offset;
|
||||
target->maxWidth = width;
|
||||
|
||||
spi_min_period(scsi_target(sdev)) = factor;
|
||||
spi_max_offset(scsi_target(sdev)) = offset;
|
||||
spi_max_width(scsi_target(sdev)) = width;
|
||||
|
||||
target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
|
||||
|
||||
/* Disable unused features.
|
||||
|
@ -558,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
|
|||
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||
cfg.dir = 0;
|
||||
cfg.pageAddr = starget->id;
|
||||
cfg.timeout = 60;
|
||||
|
||||
if (mpt_config(ioc, &cfg)) {
|
||||
starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
|
||||
|
@ -1152,6 +1157,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
|||
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
|
||||
struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
|
||||
|
||||
if (ioc->bus_type != SPI)
|
||||
return 0;
|
||||
|
||||
if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
|
||||
int reason
|
||||
= (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
|
||||
|
@ -1283,6 +1291,8 @@ mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
|||
int rc;
|
||||
|
||||
rc = mptscsih_ioc_reset(ioc, reset_phase);
|
||||
if ((ioc->bus_type != SPI) || (!rc))
|
||||
return rc;
|
||||
|
||||
/* only try to do a renegotiation if we're properly set up
|
||||
* if we get an ioc fault on bringup, ioc->sh will be NULL */
|
||||
|
|
|
@ -425,7 +425,8 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)
|
|||
{
|
||||
while (atomic_read(&adapter->stat_miss) > 0)
|
||||
if (zfcp_fsf_status_read(adapter->qdio)) {
|
||||
if (atomic_read(&adapter->stat_miss) >= 16) {
|
||||
if (atomic_read(&adapter->stat_miss) >=
|
||||
adapter->stat_read_buf_num) {
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
|
||||
NULL);
|
||||
return 1;
|
||||
|
@ -545,6 +546,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
|||
&zfcp_sysfs_adapter_attrs))
|
||||
goto failed;
|
||||
|
||||
/* report size limit per scatter-gather segment */
|
||||
adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN;
|
||||
adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
|
||||
|
||||
if (!zfcp_adapter_scsi_register(adapter))
|
||||
return adapter;
|
||||
|
||||
|
|
|
@ -44,23 +44,6 @@ struct zfcp_reqlist;
|
|||
/********************* SCSI SPECIFIC DEFINES *********************************/
|
||||
#define ZFCP_SCSI_ER_TIMEOUT (10*HZ)
|
||||
|
||||
/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
|
||||
|
||||
/* DMQ bug workaround: don't use last SBALE */
|
||||
#define ZFCP_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
|
||||
|
||||
/* index of last SBALE (with respect to DMQ bug workaround) */
|
||||
#define ZFCP_LAST_SBALE_PER_SBAL (ZFCP_MAX_SBALES_PER_SBAL - 1)
|
||||
|
||||
/* max. number of (data buffer) SBALEs in largest SBAL chain */
|
||||
#define ZFCP_MAX_SBALES_PER_REQ \
|
||||
(FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2)
|
||||
/* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
|
||||
|
||||
#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8)
|
||||
/* max. number of (data buffer) SBALEs in largest SBAL chain
|
||||
multiplied with number of sectors per 4k block */
|
||||
|
||||
/********************* FSF SPECIFIC DEFINES *********************************/
|
||||
|
||||
/* ATTENTION: value must not be used by hardware */
|
||||
|
@ -181,6 +164,7 @@ struct zfcp_adapter {
|
|||
stack abort/command
|
||||
completion races */
|
||||
atomic_t stat_miss; /* # missing status reads*/
|
||||
unsigned int stat_read_buf_num;
|
||||
struct work_struct stat_work;
|
||||
atomic_t status; /* status of this adapter */
|
||||
struct list_head erp_ready_head; /* error recovery for this
|
||||
|
@ -205,6 +189,7 @@ struct zfcp_adapter {
|
|||
struct work_struct scan_work;
|
||||
struct service_level service_level;
|
||||
struct workqueue_struct *work_queue;
|
||||
struct device_dma_parameters dma_parms;
|
||||
};
|
||||
|
||||
struct zfcp_port {
|
||||
|
|
|
@ -714,7 +714,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
|
|||
if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
|
||||
return ZFCP_ERP_FAILED;
|
||||
|
||||
atomic_set(&act->adapter->stat_miss, 16);
|
||||
atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
|
||||
if (zfcp_status_read_refill(act->adapter))
|
||||
return ZFCP_ERP_FAILED;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* External function declarations.
|
||||
*
|
||||
* Copyright IBM Corporation 2002, 2009
|
||||
* Copyright IBM Corporation 2002, 2010
|
||||
*/
|
||||
|
||||
#ifndef ZFCP_EXT_H
|
||||
|
@ -143,9 +143,9 @@ extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
|
|||
/* zfcp_qdio.c */
|
||||
extern int zfcp_qdio_setup(struct zfcp_adapter *);
|
||||
extern void zfcp_qdio_destroy(struct zfcp_qdio *);
|
||||
extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
|
||||
extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
|
||||
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *,
|
||||
struct zfcp_qdio_req *, unsigned long,
|
||||
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
|
||||
struct scatterlist *, int);
|
||||
extern int zfcp_qdio_open(struct zfcp_qdio *);
|
||||
extern void zfcp_qdio_close(struct zfcp_qdio *);
|
||||
|
|
|
@ -400,7 +400,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
|
|||
struct zfcp_adapter *adapter = port->adapter;
|
||||
int ret;
|
||||
|
||||
adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC);
|
||||
adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC);
|
||||
if (!adisc)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -493,7 +493,7 @@ static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)
|
|||
if (!gpn_ft)
|
||||
return NULL;
|
||||
|
||||
req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
|
||||
req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
|
||||
if (!req) {
|
||||
kfree(gpn_ft);
|
||||
gpn_ft = NULL;
|
||||
|
|
|
@ -496,6 +496,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
|||
|
||||
adapter->hydra_version = bottom->adapter_type;
|
||||
adapter->timer_ticks = bottom->timer_interval;
|
||||
adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16);
|
||||
|
||||
if (fc_host_permanent_port_name(shost) == -1)
|
||||
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
|
||||
|
@ -640,37 +641,6 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
|
|||
}
|
||||
}
|
||||
|
||||
static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio)
|
||||
{
|
||||
struct zfcp_qdio_queue *req_q = &qdio->req_q;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (atomic_read(&req_q->count))
|
||||
return 1;
|
||||
spin_unlock_bh(&qdio->req_q_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio)
|
||||
{
|
||||
struct zfcp_adapter *adapter = qdio->adapter;
|
||||
long ret;
|
||||
|
||||
spin_unlock_bh(&qdio->req_q_lock);
|
||||
ret = wait_event_interruptible_timeout(qdio->req_q_wq,
|
||||
zfcp_fsf_sbal_check(qdio), 5 * HZ);
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
if (!ret) {
|
||||
atomic_inc(&qdio->req_q_full);
|
||||
/* assume hanging outbound queue, try queue recovery */
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
|
||||
}
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)
|
||||
{
|
||||
struct zfcp_fsf_req *req;
|
||||
|
@ -705,10 +675,9 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
|
|||
}
|
||||
|
||||
static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
|
||||
u32 fsf_cmd, mempool_t *pool)
|
||||
u32 fsf_cmd, u32 sbtype,
|
||||
mempool_t *pool)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio_queue *req_q = &qdio->req_q;
|
||||
struct zfcp_adapter *adapter = qdio->adapter;
|
||||
struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool);
|
||||
|
||||
|
@ -725,14 +694,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
|
|||
req->adapter = adapter;
|
||||
req->fsf_command = fsf_cmd;
|
||||
req->req_id = adapter->req_no;
|
||||
req->qdio_req.sbal_number = 1;
|
||||
req->qdio_req.sbal_first = req_q->first;
|
||||
req->qdio_req.sbal_last = req_q->first;
|
||||
req->qdio_req.sbale_curr = 1;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].addr = (void *) req->req_id;
|
||||
sbale[0].flags |= SBAL_FLAGS0_COMMAND;
|
||||
|
||||
if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
|
||||
if (likely(pool))
|
||||
|
@ -753,10 +714,11 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
|
|||
req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
|
||||
req->qtcb->header.req_handle = req->req_id;
|
||||
req->qtcb->header.fsf_command = req->fsf_command;
|
||||
sbale[1].addr = (void *) req->qtcb;
|
||||
sbale[1].length = sizeof(struct fsf_qtcb);
|
||||
}
|
||||
|
||||
zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype,
|
||||
req->qtcb, sizeof(struct fsf_qtcb));
|
||||
|
||||
if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
|
||||
zfcp_fsf_req_free(req);
|
||||
return ERR_PTR(-EIO);
|
||||
|
@ -803,24 +765,19 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
|
|||
struct zfcp_adapter *adapter = qdio->adapter;
|
||||
struct zfcp_fsf_req *req;
|
||||
struct fsf_status_read_buffer *sr_buf;
|
||||
struct qdio_buffer_element *sbale;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
|
||||
adapter->pool.status_read_req);
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
req->qdio_req.sbale_curr = 2;
|
||||
|
||||
sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
|
||||
if (!sr_buf) {
|
||||
retval = -ENOMEM;
|
||||
|
@ -828,9 +785,9 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
|
|||
}
|
||||
memset(sr_buf, 0, sizeof(*sr_buf));
|
||||
req->data = sr_buf;
|
||||
sbale = zfcp_qdio_sbale_curr(qdio, &req->qdio_req);
|
||||
sbale->addr = (void *) sr_buf;
|
||||
sbale->length = sizeof(*sr_buf);
|
||||
|
||||
zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf));
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
retval = zfcp_fsf_req_send(req);
|
||||
if (retval)
|
||||
|
@ -907,14 +864,14 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
|
|||
struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
|
||||
struct zfcp_unit *unit)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct zfcp_qdio *qdio = unit->port->adapter->qdio;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.scsi_abort);
|
||||
if (IS_ERR(req)) {
|
||||
req = NULL;
|
||||
|
@ -925,9 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
|
|||
ZFCP_STATUS_COMMON_UNBLOCKED)))
|
||||
goto out_error_free;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->data = unit;
|
||||
req->handler = zfcp_fsf_abort_fcp_command_handler;
|
||||
|
@ -996,21 +951,14 @@ skip_fsfstatus:
|
|||
ct->handler(ct->handler_data);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
|
||||
static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
|
||||
struct zfcp_qdio_req *q_req,
|
||||
struct scatterlist *sg_req,
|
||||
struct scatterlist *sg_resp)
|
||||
{
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
|
||||
sbale[2].addr = sg_virt(sg_req);
|
||||
sbale[2].length = sg_req->length;
|
||||
sbale[3].addr = sg_virt(sg_resp);
|
||||
sbale[3].length = sg_resp->length;
|
||||
sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
}
|
||||
|
||||
static int zfcp_fsf_one_sbal(struct scatterlist *sg)
|
||||
{
|
||||
return sg_is_last(sg) && sg->length <= PAGE_SIZE;
|
||||
zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length);
|
||||
zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length);
|
||||
zfcp_qdio_set_sbale_last(qdio, q_req);
|
||||
}
|
||||
|
||||
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
||||
|
@ -1019,35 +967,34 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
|||
int max_sbals)
|
||||
{
|
||||
struct zfcp_adapter *adapter = req->adapter;
|
||||
struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio,
|
||||
&req->qdio_req);
|
||||
u32 feat = adapter->adapter_features;
|
||||
int bytes;
|
||||
|
||||
if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
|
||||
if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
|
||||
if (!zfcp_qdio_sg_one_sbale(sg_req) ||
|
||||
!zfcp_qdio_sg_one_sbale(sg_resp))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
|
||||
zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
|
||||
sg_req, sg_resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* use single, unchained SBAL if it can hold the request */
|
||||
if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
|
||||
zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
|
||||
if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) {
|
||||
zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
|
||||
sg_req, sg_resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
|
||||
SBAL_FLAGS0_TYPE_WRITE_READ,
|
||||
sg_req, max_sbals);
|
||||
if (bytes <= 0)
|
||||
return -EIO;
|
||||
req->qtcb->bottom.support.req_buf_length = bytes;
|
||||
req->qdio_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
|
||||
zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
|
||||
|
||||
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
|
||||
SBAL_FLAGS0_TYPE_WRITE_READ,
|
||||
sg_resp, max_sbals);
|
||||
req->qtcb->bottom.support.resp_buf_length = bytes;
|
||||
if (bytes <= 0)
|
||||
|
@ -1091,10 +1038,11 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
|
|||
int ret = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool);
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC,
|
||||
SBAL_FLAGS0_TYPE_WRITE_READ, pool);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
ret = PTR_ERR(req);
|
||||
|
@ -1103,7 +1051,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
|
|||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
|
||||
FSF_MAX_SBALS_PER_REQ, timeout);
|
||||
ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
|
||||
if (ret)
|
||||
goto failed_send;
|
||||
|
||||
|
@ -1187,10 +1135,11 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
|
|||
int ret = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL);
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS,
|
||||
SBAL_FLAGS0_TYPE_WRITE_READ, NULL);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
ret = PTR_ERR(req);
|
||||
|
@ -1224,16 +1173,16 @@ out:
|
|||
|
||||
int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req;
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1242,9 +1191,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->qtcb->bottom.config.feature_selection =
|
||||
FSF_FEATURE_CFDC |
|
||||
|
@ -1269,24 +1216,22 @@ out:
|
|||
int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
|
||||
struct fsf_qtcb_bottom_config *data)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out_unlock;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL);
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
|
||||
SBAL_FLAGS0_TYPE_READ, NULL);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
req->handler = zfcp_fsf_exchange_config_data_handler;
|
||||
|
||||
req->qtcb->bottom.config.feature_selection =
|
||||
|
@ -1320,7 +1265,6 @@ out_unlock:
|
|||
int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
|
@ -1328,10 +1272,11 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1340,9 +1285,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_exchange_port_data_handler;
|
||||
req->erp_action = erp_action;
|
||||
|
@ -1368,7 +1311,6 @@ out:
|
|||
int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
|
||||
struct fsf_qtcb_bottom_port *data)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
int retval = -EIO;
|
||||
|
||||
|
@ -1376,10 +1318,11 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out_unlock;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL);
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
|
||||
SBAL_FLAGS0_TYPE_READ, NULL);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
|
@ -1389,9 +1332,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
|
|||
if (data)
|
||||
req->data = data;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_exchange_port_data_handler;
|
||||
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
||||
|
@ -1485,17 +1426,17 @@ out:
|
|||
*/
|
||||
int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
struct zfcp_port *port = erp_action->port;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1504,9 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_open_port_handler;
|
||||
hton24(req->qtcb->bottom.support.d_id, port->d_id);
|
||||
|
@ -1556,16 +1495,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
|
|||
*/
|
||||
int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1574,9 +1513,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_close_port_handler;
|
||||
req->data = erp_action->port;
|
||||
|
@ -1633,16 +1570,16 @@ out:
|
|||
*/
|
||||
int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (unlikely(IS_ERR(req))) {
|
||||
|
@ -1651,9 +1588,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_open_wka_port_handler;
|
||||
hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
|
||||
|
@ -1688,16 +1623,16 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
|
|||
*/
|
||||
int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (unlikely(IS_ERR(req))) {
|
||||
|
@ -1706,9 +1641,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->handler = zfcp_fsf_close_wka_port_handler;
|
||||
req->data = wka_port;
|
||||
|
@ -1782,16 +1715,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
|
|||
*/
|
||||
int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1800,9 +1733,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->data = erp_action->port;
|
||||
req->qtcb->header.port_handle = erp_action->port->handle;
|
||||
|
@ -1954,17 +1885,17 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
|
|||
*/
|
||||
int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_adapter *adapter = erp_action->adapter;
|
||||
struct zfcp_qdio *qdio = adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -1973,9 +1904,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->qtcb->header.port_handle = erp_action->port->handle;
|
||||
req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
|
||||
|
@ -2041,16 +1970,16 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
|
|||
*/
|
||||
int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = erp_action->adapter->qdio;
|
||||
struct zfcp_fsf_req *req;
|
||||
int retval = -EIO;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
|
||||
SBAL_FLAGS0_TYPE_READ,
|
||||
qdio->adapter->pool.erp_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -2059,9 +1988,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
req->qtcb->header.port_handle = erp_action->port->handle;
|
||||
req->qtcb->header.lun_handle = erp_action->unit->handle;
|
||||
|
@ -2289,8 +2216,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE)
|
||||
sbtype = SBAL_FLAGS0_TYPE_WRITE;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
|
||||
adapter->pool.scsi_req);
|
||||
sbtype, adapter->pool.scsi_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
|
@ -2298,7 +2228,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
}
|
||||
|
||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||
get_device(&unit->dev);
|
||||
req->unit = unit;
|
||||
req->data = scsi_cmnd;
|
||||
req->handler = zfcp_fsf_send_fcp_command_handler;
|
||||
|
@ -2323,20 +2252,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|||
break;
|
||||
case DMA_TO_DEVICE:
|
||||
req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
|
||||
sbtype = SBAL_FLAGS0_TYPE_WRITE;
|
||||
break;
|
||||
case DMA_BIDIRECTIONAL:
|
||||
goto failed_scsi_cmnd;
|
||||
}
|
||||
|
||||
get_device(&unit->dev);
|
||||
|
||||
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
||||
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
|
||||
|
||||
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sbtype,
|
||||
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
||||
scsi_sglist(scsi_cmnd),
|
||||
FSF_MAX_SBALS_PER_REQ);
|
||||
ZFCP_FSF_MAX_SBALS_PER_REQ);
|
||||
if (unlikely(real_bytes < 0)) {
|
||||
if (req->qdio_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
|
||||
if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
|
||||
dev_err(&adapter->ccw_device->dev,
|
||||
"Oversize data package, unit 0x%016Lx "
|
||||
"on port 0x%016Lx closed\n",
|
||||
|
@ -2371,7 +2301,6 @@ out:
|
|||
*/
|
||||
struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct fcp_cmnd *fcp_cmnd;
|
||||
struct zfcp_qdio *qdio = unit->port->adapter->qdio;
|
||||
|
@ -2381,10 +2310,11 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
|||
return NULL;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
|
||||
SBAL_FLAGS0_TYPE_WRITE,
|
||||
qdio->adapter->pool.scsi_req);
|
||||
|
||||
if (IS_ERR(req)) {
|
||||
|
@ -2401,9 +2331,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
|
|||
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
|
||||
req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
|
||||
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||
|
||||
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
||||
zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
|
||||
|
@ -2432,7 +2360,6 @@ static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
|
|||
struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
||||
struct zfcp_fsf_cfdc *fsf_cfdc)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
struct zfcp_qdio *qdio = adapter->qdio;
|
||||
struct zfcp_fsf_req *req = NULL;
|
||||
struct fsf_qtcb_bottom_support *bottom;
|
||||
|
@ -2453,10 +2380,10 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
|||
}
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (zfcp_fsf_req_sbal_get(qdio))
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL);
|
||||
req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL);
|
||||
if (IS_ERR(req)) {
|
||||
retval = -EPERM;
|
||||
goto out;
|
||||
|
@ -2464,16 +2391,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
|||
|
||||
req->handler = zfcp_fsf_control_file_handler;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
|
||||
sbale[0].flags |= direction;
|
||||
|
||||
bottom = &req->qtcb->bottom.support;
|
||||
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
|
||||
bottom->option = fsf_cfdc->option;
|
||||
|
||||
bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
||||
direction, fsf_cfdc->sg,
|
||||
FSF_MAX_SBALS_PER_REQ);
|
||||
fsf_cfdc->sg,
|
||||
ZFCP_FSF_MAX_SBALS_PER_REQ);
|
||||
if (bytes != ZFCP_CFDC_MAX_SIZE) {
|
||||
zfcp_fsf_req_free(req);
|
||||
goto out;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Interface to the FSF support functions.
|
||||
*
|
||||
* Copyright IBM Corporation 2002, 2009
|
||||
* Copyright IBM Corporation 2002, 2010
|
||||
*/
|
||||
|
||||
#ifndef FSF_H
|
||||
|
@ -152,7 +152,12 @@
|
|||
#define FSF_CLASS_3 0x00000003
|
||||
|
||||
/* SBAL chaining */
|
||||
#define FSF_MAX_SBALS_PER_REQ 36
|
||||
#define ZFCP_FSF_MAX_SBALS_PER_REQ 36
|
||||
|
||||
/* max. number of (data buffer) SBALEs in largest SBAL chain
|
||||
* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
|
||||
#define ZFCP_FSF_MAX_SBALES_PER_REQ \
|
||||
(ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
|
||||
|
||||
/* logging space behind QTCB */
|
||||
#define FSF_QTCB_LOG_SIZE 1024
|
||||
|
@ -361,7 +366,7 @@ struct fsf_qtcb_bottom_config {
|
|||
u32 adapter_type;
|
||||
u8 res0;
|
||||
u8 peer_d_id[3];
|
||||
u8 res1[2];
|
||||
u16 status_read_buf_num;
|
||||
u16 timer_interval;
|
||||
u8 res2[9];
|
||||
u8 s_id[3];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Setup and helper functions to access QDIO.
|
||||
*
|
||||
* Copyright IBM Corporation 2002, 2009
|
||||
* Copyright IBM Corporation 2002, 2010
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "zfcp"
|
||||
|
@ -151,8 +151,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
|
|||
}
|
||||
|
||||
static struct qdio_buffer_element *
|
||||
zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||
unsigned long sbtype)
|
||||
zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
|
||||
|
@ -180,17 +179,16 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|||
|
||||
/* set storage-block type for new SBAL */
|
||||
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
|
||||
sbale->flags |= sbtype;
|
||||
sbale->flags |= q_req->sbtype;
|
||||
|
||||
return sbale;
|
||||
}
|
||||
|
||||
static struct qdio_buffer_element *
|
||||
zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||
unsigned int sbtype)
|
||||
zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
||||
{
|
||||
if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
|
||||
return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
|
||||
if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL)
|
||||
return zfcp_qdio_sbal_chain(qdio, q_req);
|
||||
q_req->sbale_curr++;
|
||||
return zfcp_qdio_sbale_curr(qdio, q_req);
|
||||
}
|
||||
|
@ -206,62 +204,38 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
|
|||
zfcp_qdio_zero_sbals(sbal, first, count);
|
||||
}
|
||||
|
||||
static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
|
||||
struct zfcp_qdio_req *q_req,
|
||||
unsigned int sbtype, void *start_addr,
|
||||
unsigned int total_length)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
unsigned long remaining, length;
|
||||
void *addr;
|
||||
|
||||
/* split segment up */
|
||||
for (addr = start_addr, remaining = total_length; remaining > 0;
|
||||
addr += length, remaining -= length) {
|
||||
sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
|
||||
if (!sbale) {
|
||||
atomic_inc(&qdio->req_q_full);
|
||||
zfcp_qdio_undo_sbals(qdio, q_req);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* new piece must not exceed next page boundary */
|
||||
length = min(remaining,
|
||||
(PAGE_SIZE - ((unsigned long)addr &
|
||||
(PAGE_SIZE - 1))));
|
||||
sbale->addr = addr;
|
||||
sbale->length = length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
|
||||
* @fsf_req: request to be processed
|
||||
* @sbtype: SBALE flags
|
||||
* @qdio: pointer to struct zfcp_qdio
|
||||
* @q_req: pointer to struct zfcp_qdio_req
|
||||
* @sg: scatter-gather list
|
||||
* @max_sbals: upper bound for number of SBALs to be used
|
||||
* Returns: number of bytes, or error (negativ)
|
||||
*/
|
||||
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||
unsigned long sbtype, struct scatterlist *sg,
|
||||
int max_sbals)
|
||||
struct scatterlist *sg, int max_sbals)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
int retval, bytes = 0;
|
||||
int bytes = 0;
|
||||
|
||||
/* figure out last allowed SBAL */
|
||||
zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
|
||||
|
||||
/* set storage-block type for this request */
|
||||
sbale = zfcp_qdio_sbale_req(qdio, q_req);
|
||||
sbale->flags |= sbtype;
|
||||
sbale->flags |= q_req->sbtype;
|
||||
|
||||
for (; sg; sg = sg_next(sg)) {
|
||||
retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
|
||||
sg_virt(sg), sg->length);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
sbale = zfcp_qdio_sbale_next(qdio, q_req);
|
||||
if (!sbale) {
|
||||
atomic_inc(&qdio->req_q_full);
|
||||
zfcp_qdio_undo_sbals(qdio, q_req);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sbale->addr = sg_virt(sg);
|
||||
sbale->length = sg->length;
|
||||
|
||||
bytes += sg->length;
|
||||
}
|
||||
|
||||
|
@ -272,6 +246,46 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|||
return bytes;
|
||||
}
|
||||
|
||||
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
|
||||
{
|
||||
struct zfcp_qdio_queue *req_q = &qdio->req_q;
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
if (atomic_read(&req_q->count))
|
||||
return 1;
|
||||
spin_unlock_bh(&qdio->req_q_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary
|
||||
* @qdio: pointer to struct zfcp_qdio
|
||||
*
|
||||
* The req_q_lock must be held by the caller of this function, and
|
||||
* this function may only be called from process context; it will
|
||||
* sleep when waiting for a free sbal.
|
||||
*
|
||||
* Returns: 0 on success, -EIO if there is no free sbal after waiting.
|
||||
*/
|
||||
int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
|
||||
{
|
||||
long ret;
|
||||
|
||||
spin_unlock_bh(&qdio->req_q_lock);
|
||||
ret = wait_event_interruptible_timeout(qdio->req_q_wq,
|
||||
zfcp_qdio_sbal_check(qdio), 5 * HZ);
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
if (!ret) {
|
||||
atomic_inc(&qdio->req_q_full);
|
||||
/* assume hanging outbound queue, try queue recovery */
|
||||
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL);
|
||||
}
|
||||
|
||||
spin_lock_bh(&qdio->req_q_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
|
||||
* @qdio: pointer to struct zfcp_qdio
|
||||
|
|
|
@ -11,6 +11,14 @@
|
|||
|
||||
#include <asm/qdio.h>
|
||||
|
||||
#define ZFCP_QDIO_SBALE_LEN PAGE_SIZE
|
||||
|
||||
/* DMQ bug workaround: don't use last SBALE */
|
||||
#define ZFCP_QDIO_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
|
||||
|
||||
/* index of last SBALE (with respect to DMQ bug workaround) */
|
||||
#define ZFCP_QDIO_LAST_SBALE_PER_SBAL (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
|
||||
|
||||
/**
|
||||
* struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
|
||||
* @sbal: qdio buffers
|
||||
|
@ -49,6 +57,7 @@ struct zfcp_qdio {
|
|||
|
||||
/**
|
||||
* struct zfcp_qdio_req - qdio queue related values for a request
|
||||
* @sbtype: sbal type flags for sbale 0
|
||||
* @sbal_number: number of free sbals
|
||||
* @sbal_first: first sbal for this request
|
||||
* @sbal_last: last sbal for this request
|
||||
|
@ -59,6 +68,7 @@ struct zfcp_qdio {
|
|||
* @qdio_inb_usage: usage of inbound queue
|
||||
*/
|
||||
struct zfcp_qdio_req {
|
||||
u32 sbtype;
|
||||
u8 sbal_number;
|
||||
u8 sbal_first;
|
||||
u8 sbal_last;
|
||||
|
@ -106,4 +116,98 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
|||
q_req->sbale_curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_req_init - initialize qdio request
|
||||
* @qdio: request queue where to start putting the request
|
||||
* @q_req: the qdio request to start
|
||||
* @req_id: The request id
|
||||
* @sbtype: type flags to set for all sbals
|
||||
* @data: First data block
|
||||
* @len: Length of first data block
|
||||
*
|
||||
* This is the start of putting the request into the queue, the last
|
||||
* step is passing the request to zfcp_qdio_send. The request queue
|
||||
* lock must be held during the whole process from init to send.
|
||||
*/
|
||||
static inline
|
||||
void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||
unsigned long req_id, u32 sbtype, void *data, u32 len)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
|
||||
q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
|
||||
q_req->sbal_number = 1;
|
||||
q_req->sbtype = sbtype;
|
||||
|
||||
sbale = zfcp_qdio_sbale_req(qdio, q_req);
|
||||
sbale->addr = (void *) req_id;
|
||||
sbale->flags |= SBAL_FLAGS0_COMMAND;
|
||||
sbale->flags |= sbtype;
|
||||
|
||||
q_req->sbale_curr = 1;
|
||||
sbale++;
|
||||
sbale->addr = data;
|
||||
if (likely(data))
|
||||
sbale->length = len;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_fill_next - Fill next sbale, only for single sbal requests
|
||||
* @qdio: pointer to struct zfcp_qdio
|
||||
* @q_req: pointer to struct zfcp_queue_req
|
||||
*
|
||||
* This is only required for single sbal requests, calling it when
|
||||
* wrapping around to the next sbal is a bug.
|
||||
*/
|
||||
static inline
|
||||
void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||
void *data, u32 len)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
|
||||
BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL);
|
||||
q_req->sbale_curr++;
|
||||
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
|
||||
sbale->addr = data;
|
||||
sbale->length = len;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_set_sbale_last - set last entry flag in current sbale
|
||||
* @qdio: pointer to struct zfcp_qdio
|
||||
* @q_req: pointer to struct zfcp_queue_req
|
||||
*/
|
||||
static inline
|
||||
void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio,
|
||||
struct zfcp_qdio_req *q_req)
|
||||
{
|
||||
struct qdio_buffer_element *sbale;
|
||||
|
||||
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
|
||||
sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_sg_one_sbal - check if one sbale is enough for sg data
|
||||
* @sg: The scatterlist where to check the data size
|
||||
*
|
||||
* Returns: 1 when one sbale is enough for the data in the scatterlist,
|
||||
* 0 if not.
|
||||
*/
|
||||
static inline
|
||||
int zfcp_qdio_sg_one_sbale(struct scatterlist *sg)
|
||||
{
|
||||
return sg_is_last(sg) && sg->length <= ZFCP_QDIO_SBALE_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_qdio_skip_to_last_sbale - skip to last sbale in sbal
|
||||
* @q_req: The current zfcp_qdio_req
|
||||
*/
|
||||
static inline
|
||||
void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
|
||||
{
|
||||
q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
|
||||
}
|
||||
|
||||
#endif /* ZFCP_QDIO_H */
|
||||
|
|
|
@ -175,7 +175,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
|||
struct zfcp_fsf_req *old_req, *abrt_req;
|
||||
unsigned long flags;
|
||||
unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
|
||||
int retval = SUCCESS;
|
||||
int retval = SUCCESS, ret;
|
||||
int retry = 3;
|
||||
char *dbf_tag;
|
||||
|
||||
|
@ -200,7 +200,9 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
|||
break;
|
||||
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
ret = fc_block_scsi_eh(scpnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_RUNNING)) {
|
||||
zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
|
||||
|
@ -231,7 +233,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|||
struct zfcp_unit *unit = scpnt->device->hostdata;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
struct zfcp_fsf_req *fsf_req = NULL;
|
||||
int retval = SUCCESS;
|
||||
int retval = SUCCESS, ret;
|
||||
int retry = 3;
|
||||
|
||||
while (retry--) {
|
||||
|
@ -240,7 +242,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|||
break;
|
||||
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
ret = fc_block_scsi_eh(scpnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(atomic_read(&adapter->status) &
|
||||
ZFCP_STATUS_COMMON_RUNNING)) {
|
||||
zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
|
||||
|
@ -276,10 +281,13 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
|
|||
{
|
||||
struct zfcp_unit *unit = scpnt->device->hostdata;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
int ret;
|
||||
|
||||
zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
|
||||
zfcp_erp_wait(adapter);
|
||||
fc_block_scsi_eh(scpnt);
|
||||
ret = fc_block_scsi_eh(scpnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -669,11 +677,12 @@ struct zfcp_data zfcp_data = {
|
|||
.eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
|
||||
.can_queue = 4096,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = ZFCP_MAX_SBALES_PER_REQ,
|
||||
.sg_tablesize = ZFCP_FSF_MAX_SBALES_PER_REQ,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = 1,
|
||||
.sdev_attrs = zfcp_sysfs_sdev_attrs,
|
||||
.max_sectors = (ZFCP_MAX_SBALES_PER_REQ * 8),
|
||||
.max_sectors = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
|
||||
.dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
|
||||
.shost_attrs = zfcp_sysfs_shost_attrs,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
|
||||
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Modifications By: Tom Couch <linuxraid@amcc.com>
|
||||
Written By: Adam Radford <linuxraid@lsi.com>
|
||||
Modifications By: Tom Couch <linuxraid@lsi.com>
|
||||
|
||||
Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
|
||||
Copyright (C) 2010 LSI Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -40,10 +41,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Bugs/Comments/Suggestions should be mailed to:
|
||||
linuxraid@amcc.com
|
||||
linuxraid@lsi.com
|
||||
|
||||
For more information, goto:
|
||||
http://www.amcc.com
|
||||
http://www.lsi.com
|
||||
|
||||
Note: This version of the driver does not contain a bundled firmware
|
||||
image.
|
||||
|
@ -77,6 +78,7 @@
|
|||
Use pci_resource_len() for ioremap().
|
||||
2.26.02.012 - Add power management support.
|
||||
2.26.02.013 - Fix bug in twa_load_sgl().
|
||||
2.26.02.014 - Force 60 second timeout default.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -102,14 +104,14 @@
|
|||
#include "3w-9xxx.h"
|
||||
|
||||
/* Globals */
|
||||
#define TW_DRIVER_VERSION "2.26.02.013"
|
||||
#define TW_DRIVER_VERSION "2.26.02.014"
|
||||
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
|
||||
static unsigned int twa_device_extension_count;
|
||||
static int twa_major = -1;
|
||||
extern struct timezone sys_tz;
|
||||
|
||||
/* Module parameters */
|
||||
MODULE_AUTHOR ("AMCC");
|
||||
MODULE_AUTHOR ("LSI");
|
||||
MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(TW_DRIVER_VERSION);
|
||||
|
@ -1990,6 +1992,15 @@ static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
|
|||
scsi_dma_unmap(cmd);
|
||||
} /* End twa_unmap_scsi_data() */
|
||||
|
||||
/* This function gets called when a disk is coming on-line */
|
||||
static int twa_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
/* Force 60 second timeout */
|
||||
blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
|
||||
|
||||
return 0;
|
||||
} /* End twa_slave_configure() */
|
||||
|
||||
/* scsi_host_template initializer */
|
||||
static struct scsi_host_template driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
|
@ -1999,6 +2010,7 @@ static struct scsi_host_template driver_template = {
|
|||
.bios_param = twa_scsi_biosparam,
|
||||
.change_queue_depth = twa_change_queue_depth,
|
||||
.can_queue = TW_Q_LENGTH-2,
|
||||
.slave_configure = twa_slave_configure,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
|
||||
.max_sectors = TW_MAX_SECTORS,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/*
|
||||
3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
|
||||
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Modifications By: Tom Couch <linuxraid@amcc.com>
|
||||
Written By: Adam Radford <linuxraid@lsi.com>
|
||||
Modifications By: Tom Couch <linuxraid@lsi.com>
|
||||
|
||||
Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
|
||||
Copyright (C) 2010 LSI Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -40,10 +41,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Bugs/Comments/Suggestions should be mailed to:
|
||||
linuxraid@amcc.com
|
||||
linuxraid@lsi.com
|
||||
|
||||
For more information, goto:
|
||||
http://www.amcc.com
|
||||
http://www.lsi.com
|
||||
*/
|
||||
|
||||
#ifndef _3W_9XXX_H
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
|
||||
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Written By: Adam Radford <linuxraid@lsi.com>
|
||||
Modifications By: Joel Jacobson <linux@3ware.com>
|
||||
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
||||
Brad Strand <linux@3ware.com>
|
||||
|
||||
Copyright (C) 1999-2009 3ware Inc.
|
||||
Copyright (C) 1999-2010 3ware Inc.
|
||||
|
||||
Kernel compatibility By: Andre Hedrick <andre@suse.com>
|
||||
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
|
||||
|
@ -47,10 +47,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Bugs/Comments/Suggestions should be mailed to:
|
||||
linuxraid@amcc.com
|
||||
linuxraid@lsi.com
|
||||
|
||||
For more information, goto:
|
||||
http://www.amcc.com
|
||||
http://www.lsi.com
|
||||
|
||||
History
|
||||
-------
|
||||
|
@ -194,6 +194,7 @@
|
|||
1.26.02.002 - Free irq handler in __tw_shutdown().
|
||||
Turn on RCD bit for caching mode page.
|
||||
Serialize reset code.
|
||||
1.26.02.003 - Force 60 second timeout default.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -219,13 +220,13 @@
|
|||
#include "3w-xxxx.h"
|
||||
|
||||
/* Globals */
|
||||
#define TW_DRIVER_VERSION "1.26.02.002"
|
||||
#define TW_DRIVER_VERSION "1.26.02.003"
|
||||
static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
|
||||
static int tw_device_extension_count = 0;
|
||||
static int twe_major = -1;
|
||||
|
||||
/* Module parameters */
|
||||
MODULE_AUTHOR("AMCC");
|
||||
MODULE_AUTHOR("LSI");
|
||||
MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(TW_DRIVER_VERSION);
|
||||
|
@ -2245,6 +2246,15 @@ static void tw_shutdown(struct pci_dev *pdev)
|
|||
__tw_shutdown(tw_dev);
|
||||
} /* End tw_shutdown() */
|
||||
|
||||
/* This function gets called when a disk is coming online */
|
||||
static int tw_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
/* Force 60 second timeout */
|
||||
blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
|
||||
|
||||
return 0;
|
||||
} /* End tw_slave_configure() */
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "3ware Storage Controller",
|
||||
|
@ -2253,6 +2263,7 @@ static struct scsi_host_template driver_template = {
|
|||
.bios_param = tw_scsi_biosparam,
|
||||
.change_queue_depth = tw_change_queue_depth,
|
||||
.can_queue = TW_Q_LENGTH-2,
|
||||
.slave_configure = tw_slave_configure,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = TW_MAX_SGL_LENGTH,
|
||||
.max_sectors = TW_MAX_SECTORS,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
3w-xxxx.h -- 3ware Storage Controller device driver for Linux.
|
||||
|
||||
Written By: Adam Radford <linuxraid@amcc.com>
|
||||
Written By: Adam Radford <linuxraid@lsi.com>
|
||||
Modifications By: Joel Jacobson <linux@3ware.com>
|
||||
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
||||
Brad Strand <linux@3ware.com>
|
||||
|
||||
Copyright (C) 1999-2009 3ware Inc.
|
||||
Copyright (C) 1999-2010 3ware Inc.
|
||||
|
||||
Kernel compatiblity By: Andre Hedrick <andre@suse.com>
|
||||
Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
|
||||
|
@ -45,10 +45,10 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Bugs/Comments/Suggestions should be mailed to:
|
||||
linuxraid@amcc.com
|
||||
linuxraid@lsi.com
|
||||
|
||||
For more information, goto:
|
||||
http://www.amcc.com
|
||||
http://www.lsi.com
|
||||
*/
|
||||
|
||||
#ifndef _3W_XXXX_H
|
||||
|
|
|
@ -162,6 +162,7 @@ scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o
|
|||
scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
|
||||
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
|
||||
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
|
||||
scsi_mod-y += scsi_trace.o
|
||||
|
||||
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
|
||||
|
||||
|
|
|
@ -19,186 +19,190 @@
|
|||
#include "wd33c93.h"
|
||||
#include "a2091.h"
|
||||
|
||||
#include<linux/stat.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
|
||||
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
|
||||
|
||||
static int a2091_release(struct Scsi_Host *instance);
|
||||
|
||||
static irqreturn_t a2091_intr (int irq, void *_instance)
|
||||
static irqreturn_t a2091_intr(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
|
||||
struct Scsi_Host *instance = data;
|
||||
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
|
||||
unsigned int status = regs->ISTR;
|
||||
unsigned long flags;
|
||||
|
||||
status = DMA(instance)->ISTR;
|
||||
if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS))
|
||||
return IRQ_NONE;
|
||||
if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock_irqsave(instance->host_lock, flags);
|
||||
wd33c93_intr(instance);
|
||||
spin_unlock_irqrestore(instance->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
spin_lock_irqsave(instance->host_lock, flags);
|
||||
wd33c93_intr(instance);
|
||||
spin_unlock_irqrestore(instance->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
|
||||
{
|
||||
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
struct WD33C93_hostdata *hdata = shost_priv(instance);
|
||||
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
|
||||
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
|
||||
/* don't allow DMA if the physical address is bad */
|
||||
if (addr & A2091_XFER_MASK)
|
||||
{
|
||||
HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
|
||||
& ~0x1ff;
|
||||
HDATA(instance)->dma_bounce_buffer =
|
||||
kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL);
|
||||
|
||||
/* can't allocate memory; use PIO */
|
||||
if (!HDATA(instance)->dma_bounce_buffer) {
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get the physical address of the bounce buffer */
|
||||
addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer);
|
||||
|
||||
/* the bounce buffer may not be in the first 16M of physmem */
|
||||
/* don't allow DMA if the physical address is bad */
|
||||
if (addr & A2091_XFER_MASK) {
|
||||
/* we could use chipmem... maybe later */
|
||||
kfree (HDATA(instance)->dma_bounce_buffer);
|
||||
HDATA(instance)->dma_bounce_buffer = NULL;
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
return 1;
|
||||
hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
|
||||
hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
|
||||
GFP_KERNEL);
|
||||
|
||||
/* can't allocate memory; use PIO */
|
||||
if (!hdata->dma_bounce_buffer) {
|
||||
hdata->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get the physical address of the bounce buffer */
|
||||
addr = virt_to_bus(hdata->dma_bounce_buffer);
|
||||
|
||||
/* the bounce buffer may not be in the first 16M of physmem */
|
||||
if (addr & A2091_XFER_MASK) {
|
||||
/* we could use chipmem... maybe later */
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
hdata->dma_bounce_buffer = NULL;
|
||||
hdata->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
|
||||
cmd->SCp.this_residual);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy (HDATA(instance)->dma_bounce_buffer,
|
||||
cmd->SCp.ptr, cmd->SCp.this_residual);
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* remember direction */
|
||||
hdata->dma_dir = dir_in;
|
||||
|
||||
regs->CNTR = cntr;
|
||||
|
||||
/* setup DMA *physical* address */
|
||||
regs->ACR = addr;
|
||||
|
||||
if (dir_in) {
|
||||
/* invalidate any cache */
|
||||
cache_clear(addr, cmd->SCp.this_residual);
|
||||
} else {
|
||||
/* push any dirty cache */
|
||||
cache_push(addr, cmd->SCp.this_residual);
|
||||
}
|
||||
}
|
||||
/* start DMA */
|
||||
regs->ST_DMA = 1;
|
||||
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* remember direction */
|
||||
HDATA(cmd->device->host)->dma_dir = dir_in;
|
||||
|
||||
DMA(cmd->device->host)->CNTR = cntr;
|
||||
|
||||
/* setup DMA *physical* address */
|
||||
DMA(cmd->device->host)->ACR = addr;
|
||||
|
||||
if (dir_in){
|
||||
/* invalidate any cache */
|
||||
cache_clear (addr, cmd->SCp.this_residual);
|
||||
}else{
|
||||
/* push any dirty cache */
|
||||
cache_push (addr, cmd->SCp.this_residual);
|
||||
}
|
||||
/* start DMA */
|
||||
DMA(cmd->device->host)->ST_DMA = 1;
|
||||
|
||||
/* return success */
|
||||
return 0;
|
||||
/* return success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
|
||||
int status)
|
||||
int status)
|
||||
{
|
||||
/* disable SCSI interrupts */
|
||||
unsigned short cntr = CNTR_PDMD;
|
||||
struct WD33C93_hostdata *hdata = shost_priv(instance);
|
||||
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
|
||||
|
||||
if (!HDATA(instance)->dma_dir)
|
||||
cntr |= CNTR_DDIR;
|
||||
/* disable SCSI interrupts */
|
||||
unsigned short cntr = CNTR_PDMD;
|
||||
|
||||
/* disable SCSI interrupts */
|
||||
DMA(instance)->CNTR = cntr;
|
||||
if (!hdata->dma_dir)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* flush if we were reading */
|
||||
if (HDATA(instance)->dma_dir) {
|
||||
DMA(instance)->FLUSH = 1;
|
||||
while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
|
||||
;
|
||||
}
|
||||
/* disable SCSI interrupts */
|
||||
regs->CNTR = cntr;
|
||||
|
||||
/* clear a possible interrupt */
|
||||
DMA(instance)->CINT = 1;
|
||||
/* flush if we were reading */
|
||||
if (hdata->dma_dir) {
|
||||
regs->FLUSH = 1;
|
||||
while (!(regs->ISTR & ISTR_FE_FLG))
|
||||
;
|
||||
}
|
||||
|
||||
/* stop DMA */
|
||||
DMA(instance)->SP_DMA = 1;
|
||||
/* clear a possible interrupt */
|
||||
regs->CINT = 1;
|
||||
|
||||
/* restore the CONTROL bits (minus the direction flag) */
|
||||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
/* stop DMA */
|
||||
regs->SP_DMA = 1;
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && HDATA(instance)->dma_bounce_buffer) {
|
||||
if( HDATA(instance)->dma_dir )
|
||||
memcpy (SCpnt->SCp.ptr,
|
||||
HDATA(instance)->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
kfree (HDATA(instance)->dma_bounce_buffer);
|
||||
HDATA(instance)->dma_bounce_buffer = NULL;
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
}
|
||||
/* restore the CONTROL bits (minus the direction flag) */
|
||||
regs->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && hdata->dma_bounce_buffer) {
|
||||
if (hdata->dma_dir)
|
||||
memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
hdata->dma_bounce_buffer = NULL;
|
||||
hdata->dma_bounce_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init a2091_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
static unsigned char called = 0;
|
||||
struct Scsi_Host *instance;
|
||||
unsigned long address;
|
||||
struct zorro_dev *z = NULL;
|
||||
wd33c93_regs regs;
|
||||
int num_a2091 = 0;
|
||||
static unsigned char called = 0;
|
||||
struct Scsi_Host *instance;
|
||||
unsigned long address;
|
||||
struct zorro_dev *z = NULL;
|
||||
wd33c93_regs wdregs;
|
||||
a2091_scsiregs *regs;
|
||||
struct WD33C93_hostdata *hdata;
|
||||
int num_a2091 = 0;
|
||||
|
||||
if (!MACH_IS_AMIGA || called)
|
||||
return 0;
|
||||
called = 1;
|
||||
if (!MACH_IS_AMIGA || called)
|
||||
return 0;
|
||||
called = 1;
|
||||
|
||||
tpnt->proc_name = "A2091";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
tpnt->proc_name = "A2091";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
|
||||
z->id != ZORRO_PROD_CBM_A590_A2091_2)
|
||||
continue;
|
||||
address = z->resource.start;
|
||||
if (!request_mem_region(address, 256, "wd33c93"))
|
||||
continue;
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
|
||||
z->id != ZORRO_PROD_CBM_A590_A2091_2)
|
||||
continue;
|
||||
address = z->resource.start;
|
||||
if (!request_mem_region(address, 256, "wd33c93"))
|
||||
continue;
|
||||
|
||||
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
|
||||
if (instance == NULL)
|
||||
goto release;
|
||||
instance->base = ZTWO_VADDR(address);
|
||||
instance->irq = IRQ_AMIGA_PORTS;
|
||||
instance->unique_id = z->slotaddr;
|
||||
DMA(instance)->DAWR = DAWR_A2091;
|
||||
regs.SASR = &(DMA(instance)->SASR);
|
||||
regs.SCMD = &(DMA(instance)->SCMD);
|
||||
HDATA(instance)->no_sync = 0xff;
|
||||
HDATA(instance)->fast = 0;
|
||||
HDATA(instance)->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
|
||||
if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
|
||||
instance))
|
||||
goto unregister;
|
||||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
num_a2091++;
|
||||
continue;
|
||||
instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
|
||||
if (instance == NULL)
|
||||
goto release;
|
||||
instance->base = ZTWO_VADDR(address);
|
||||
instance->irq = IRQ_AMIGA_PORTS;
|
||||
instance->unique_id = z->slotaddr;
|
||||
regs = (a2091_scsiregs *)(instance->base);
|
||||
regs->DAWR = DAWR_A2091;
|
||||
wdregs.SASR = ®s->SASR;
|
||||
wdregs.SCMD = ®s->SCMD;
|
||||
hdata = shost_priv(instance);
|
||||
hdata->no_sync = 0xff;
|
||||
hdata->fast = 0;
|
||||
hdata->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(instance, wdregs, dma_setup, dma_stop,
|
||||
WD33C93_FS_8_10);
|
||||
if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
|
||||
"A2091 SCSI", instance))
|
||||
goto unregister;
|
||||
regs->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
num_a2091++;
|
||||
continue;
|
||||
|
||||
unregister:
|
||||
scsi_unregister(instance);
|
||||
wd33c93_release();
|
||||
scsi_unregister(instance);
|
||||
release:
|
||||
release_mem_region(address, 256);
|
||||
}
|
||||
release_mem_region(address, 256);
|
||||
}
|
||||
|
||||
return num_a2091;
|
||||
return num_a2091;
|
||||
}
|
||||
|
||||
static int a2091_bus_reset(struct scsi_cmnd *cmd)
|
||||
|
@ -239,10 +243,11 @@ static struct scsi_host_template driver_template = {
|
|||
static int a2091_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
DMA(instance)->CNTR = 0;
|
||||
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
|
||||
|
||||
regs->CNTR = 0;
|
||||
release_mem_region(ZTWO_PADDR(instance->base), 256);
|
||||
free_irq(IRQ_AMIGA_PORTS, instance);
|
||||
wd33c93_release();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -12,38 +12,38 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#ifndef CMD_PER_LUN
|
||||
#define CMD_PER_LUN 2
|
||||
#define CMD_PER_LUN 2
|
||||
#endif
|
||||
|
||||
#ifndef CAN_QUEUE
|
||||
#define CAN_QUEUE 16
|
||||
#define CAN_QUEUE 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if the transfer address ANDed with this results in a non-zero
|
||||
* result, then we can't use DMA.
|
||||
*/
|
||||
#define A2091_XFER_MASK (0xff000001)
|
||||
#define A2091_XFER_MASK (0xff000001)
|
||||
|
||||
typedef struct {
|
||||
unsigned char pad1[64];
|
||||
volatile unsigned short ISTR;
|
||||
volatile unsigned short CNTR;
|
||||
unsigned char pad2[60];
|
||||
volatile unsigned int WTC;
|
||||
volatile unsigned long ACR;
|
||||
unsigned char pad3[6];
|
||||
volatile unsigned short DAWR;
|
||||
unsigned char pad4;
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad5;
|
||||
volatile unsigned char SCMD;
|
||||
unsigned char pad6[76];
|
||||
volatile unsigned short ST_DMA;
|
||||
volatile unsigned short SP_DMA;
|
||||
volatile unsigned short CINT;
|
||||
unsigned char pad7[2];
|
||||
volatile unsigned short FLUSH;
|
||||
unsigned char pad1[64];
|
||||
volatile unsigned short ISTR;
|
||||
volatile unsigned short CNTR;
|
||||
unsigned char pad2[60];
|
||||
volatile unsigned int WTC;
|
||||
volatile unsigned long ACR;
|
||||
unsigned char pad3[6];
|
||||
volatile unsigned short DAWR;
|
||||
unsigned char pad4;
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad5;
|
||||
volatile unsigned char SCMD;
|
||||
unsigned char pad6[76];
|
||||
volatile unsigned short ST_DMA;
|
||||
volatile unsigned short SP_DMA;
|
||||
volatile unsigned short CINT;
|
||||
unsigned char pad7[2];
|
||||
volatile unsigned short FLUSH;
|
||||
} a2091_scsiregs;
|
||||
|
||||
#define DAWR_A2091 (3)
|
||||
|
|
|
@ -19,26 +19,25 @@
|
|||
#include "wd33c93.h"
|
||||
#include "a3000.h"
|
||||
|
||||
#include<linux/stat.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
|
||||
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
|
||||
|
||||
#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
|
||||
|
||||
static struct Scsi_Host *a3000_host = NULL;
|
||||
|
||||
static int a3000_release(struct Scsi_Host *instance);
|
||||
|
||||
static irqreturn_t a3000_intr (int irq, void *dummy)
|
||||
static irqreturn_t a3000_intr(int irq, void *dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int status = DMA(a3000_host)->ISTR;
|
||||
|
||||
if (!(status & ISTR_INT_P))
|
||||
return IRQ_NONE;
|
||||
if (status & ISTR_INTS)
|
||||
{
|
||||
if (status & ISTR_INTS) {
|
||||
spin_lock_irqsave(a3000_host->host_lock, flags);
|
||||
wd33c93_intr (a3000_host);
|
||||
wd33c93_intr(a3000_host);
|
||||
spin_unlock_irqrestore(a3000_host->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -48,162 +47,165 @@ static irqreturn_t a3000_intr (int irq, void *dummy)
|
|||
|
||||
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
|
||||
{
|
||||
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
|
||||
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
|
||||
/*
|
||||
* if the physical address has the wrong alignment, or if
|
||||
* physical address is bad, or if it is a write and at the
|
||||
* end of a physical memory chunk, then allocate a bounce
|
||||
* buffer
|
||||
*/
|
||||
if (addr & A3000_XFER_MASK)
|
||||
{
|
||||
HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
|
||||
& ~0x1ff;
|
||||
HDATA(a3000_host)->dma_bounce_buffer =
|
||||
kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
|
||||
|
||||
/* can't allocate memory; use PIO */
|
||||
if (!HDATA(a3000_host)->dma_bounce_buffer) {
|
||||
HDATA(a3000_host)->dma_bounce_len = 0;
|
||||
return 1;
|
||||
/*
|
||||
* if the physical address has the wrong alignment, or if
|
||||
* physical address is bad, or if it is a write and at the
|
||||
* end of a physical memory chunk, then allocate a bounce
|
||||
* buffer
|
||||
*/
|
||||
if (addr & A3000_XFER_MASK) {
|
||||
hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
|
||||
hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
|
||||
GFP_KERNEL);
|
||||
|
||||
/* can't allocate memory; use PIO */
|
||||
if (!hdata->dma_bounce_buffer) {
|
||||
hdata->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
|
||||
cmd->SCp.this_residual);
|
||||
}
|
||||
|
||||
addr = virt_to_bus(hdata->dma_bounce_buffer);
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy (HDATA(a3000_host)->dma_bounce_buffer,
|
||||
cmd->SCp.ptr, cmd->SCp.this_residual);
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* remember direction */
|
||||
hdata->dma_dir = dir_in;
|
||||
|
||||
DMA(a3000_host)->CNTR = cntr;
|
||||
|
||||
/* setup DMA *physical* address */
|
||||
DMA(a3000_host)->ACR = addr;
|
||||
|
||||
if (dir_in) {
|
||||
/* invalidate any cache */
|
||||
cache_clear(addr, cmd->SCp.this_residual);
|
||||
} else {
|
||||
/* push any dirty cache */
|
||||
cache_push(addr, cmd->SCp.this_residual);
|
||||
}
|
||||
|
||||
addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
|
||||
}
|
||||
/* start DMA */
|
||||
mb(); /* make sure setup is completed */
|
||||
DMA(a3000_host)->ST_DMA = 1;
|
||||
mb(); /* make sure DMA has started before next IO */
|
||||
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* remember direction */
|
||||
HDATA(a3000_host)->dma_dir = dir_in;
|
||||
|
||||
DMA(a3000_host)->CNTR = cntr;
|
||||
|
||||
/* setup DMA *physical* address */
|
||||
DMA(a3000_host)->ACR = addr;
|
||||
|
||||
if (dir_in)
|
||||
/* invalidate any cache */
|
||||
cache_clear (addr, cmd->SCp.this_residual);
|
||||
else
|
||||
/* push any dirty cache */
|
||||
cache_push (addr, cmd->SCp.this_residual);
|
||||
|
||||
/* start DMA */
|
||||
mb(); /* make sure setup is completed */
|
||||
DMA(a3000_host)->ST_DMA = 1;
|
||||
mb(); /* make sure DMA has started before next IO */
|
||||
|
||||
/* return success */
|
||||
return 0;
|
||||
/* return success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
|
||||
int status)
|
||||
{
|
||||
/* disable SCSI interrupts */
|
||||
unsigned short cntr = CNTR_PDMD;
|
||||
struct WD33C93_hostdata *hdata = shost_priv(instance);
|
||||
|
||||
if (!HDATA(instance)->dma_dir)
|
||||
cntr |= CNTR_DDIR;
|
||||
/* disable SCSI interrupts */
|
||||
unsigned short cntr = CNTR_PDMD;
|
||||
|
||||
DMA(instance)->CNTR = cntr;
|
||||
mb(); /* make sure CNTR is updated before next IO */
|
||||
if (!hdata->dma_dir)
|
||||
cntr |= CNTR_DDIR;
|
||||
|
||||
/* flush if we were reading */
|
||||
if (HDATA(instance)->dma_dir) {
|
||||
DMA(instance)->FLUSH = 1;
|
||||
mb(); /* don't allow prefetch */
|
||||
while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
|
||||
barrier();
|
||||
mb(); /* no IO until FLUSH is done */
|
||||
}
|
||||
DMA(instance)->CNTR = cntr;
|
||||
mb(); /* make sure CNTR is updated before next IO */
|
||||
|
||||
/* clear a possible interrupt */
|
||||
/* I think that this CINT is only necessary if you are
|
||||
* using the terminal count features. HM 7 Mar 1994
|
||||
*/
|
||||
DMA(instance)->CINT = 1;
|
||||
|
||||
/* stop DMA */
|
||||
DMA(instance)->SP_DMA = 1;
|
||||
mb(); /* make sure DMA is stopped before next IO */
|
||||
|
||||
/* restore the CONTROL bits (minus the direction flag) */
|
||||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
mb(); /* make sure CNTR is updated before next IO */
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && HDATA(instance)->dma_bounce_buffer) {
|
||||
if (SCpnt) {
|
||||
if (HDATA(instance)->dma_dir && SCpnt)
|
||||
memcpy (SCpnt->SCp.ptr,
|
||||
HDATA(instance)->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
kfree (HDATA(instance)->dma_bounce_buffer);
|
||||
HDATA(instance)->dma_bounce_buffer = NULL;
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
} else {
|
||||
kfree (HDATA(instance)->dma_bounce_buffer);
|
||||
HDATA(instance)->dma_bounce_buffer = NULL;
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
/* flush if we were reading */
|
||||
if (hdata->dma_dir) {
|
||||
DMA(instance)->FLUSH = 1;
|
||||
mb(); /* don't allow prefetch */
|
||||
while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
|
||||
barrier();
|
||||
mb(); /* no IO until FLUSH is done */
|
||||
}
|
||||
|
||||
/* clear a possible interrupt */
|
||||
/* I think that this CINT is only necessary if you are
|
||||
* using the terminal count features. HM 7 Mar 1994
|
||||
*/
|
||||
DMA(instance)->CINT = 1;
|
||||
|
||||
/* stop DMA */
|
||||
DMA(instance)->SP_DMA = 1;
|
||||
mb(); /* make sure DMA is stopped before next IO */
|
||||
|
||||
/* restore the CONTROL bits (minus the direction flag) */
|
||||
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
mb(); /* make sure CNTR is updated before next IO */
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && hdata->dma_bounce_buffer) {
|
||||
if (SCpnt) {
|
||||
if (hdata->dma_dir && SCpnt)
|
||||
memcpy(SCpnt->SCp.ptr,
|
||||
hdata->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
hdata->dma_bounce_buffer = NULL;
|
||||
hdata->dma_bounce_len = 0;
|
||||
} else {
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
hdata->dma_bounce_buffer = NULL;
|
||||
hdata->dma_bounce_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int __init a3000_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
wd33c93_regs regs;
|
||||
wd33c93_regs regs;
|
||||
struct WD33C93_hostdata *hdata;
|
||||
|
||||
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
|
||||
return 0;
|
||||
if (!request_mem_region(0xDD0000, 256, "wd33c93"))
|
||||
return 0;
|
||||
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
|
||||
return 0;
|
||||
if (!request_mem_region(0xDD0000, 256, "wd33c93"))
|
||||
return 0;
|
||||
|
||||
tpnt->proc_name = "A3000";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
tpnt->proc_name = "A3000";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
|
||||
a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
|
||||
if (a3000_host == NULL)
|
||||
goto fail_register;
|
||||
a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
|
||||
if (a3000_host == NULL)
|
||||
goto fail_register;
|
||||
|
||||
a3000_host->base = ZTWO_VADDR(0xDD0000);
|
||||
a3000_host->irq = IRQ_AMIGA_PORTS;
|
||||
DMA(a3000_host)->DAWR = DAWR_A3000;
|
||||
regs.SASR = &(DMA(a3000_host)->SASR);
|
||||
regs.SCMD = &(DMA(a3000_host)->SCMD);
|
||||
HDATA(a3000_host)->no_sync = 0xff;
|
||||
HDATA(a3000_host)->fast = 0;
|
||||
HDATA(a3000_host)->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
|
||||
if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
|
||||
a3000_intr))
|
||||
goto fail_irq;
|
||||
DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
a3000_host->base = ZTWO_VADDR(0xDD0000);
|
||||
a3000_host->irq = IRQ_AMIGA_PORTS;
|
||||
DMA(a3000_host)->DAWR = DAWR_A3000;
|
||||
regs.SASR = &(DMA(a3000_host)->SASR);
|
||||
regs.SCMD = &(DMA(a3000_host)->SCMD);
|
||||
hdata = shost_priv(a3000_host);
|
||||
hdata->no_sync = 0xff;
|
||||
hdata->fast = 0;
|
||||
hdata->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
|
||||
if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
|
||||
a3000_intr))
|
||||
goto fail_irq;
|
||||
DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
|
||||
fail_irq:
|
||||
wd33c93_release();
|
||||
scsi_unregister(a3000_host);
|
||||
scsi_unregister(a3000_host);
|
||||
fail_register:
|
||||
release_mem_region(0xDD0000, 256);
|
||||
return 0;
|
||||
release_mem_region(0xDD0000, 256);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a3000_bus_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
/* FIXME perform bus-specific reset */
|
||||
|
||||
|
||||
/* FIXME 2: kill this entire function, which should
|
||||
cause mid-layer to call wd33c93_host_reset anyway? */
|
||||
|
||||
|
@ -237,11 +239,10 @@ static struct scsi_host_template driver_template = {
|
|||
|
||||
static int a3000_release(struct Scsi_Host *instance)
|
||||
{
|
||||
wd33c93_release();
|
||||
DMA(instance)->CNTR = 0;
|
||||
release_mem_region(0xDD0000, 256);
|
||||
free_irq(IRQ_AMIGA_PORTS, a3000_intr);
|
||||
return 1;
|
||||
DMA(instance)->CNTR = 0;
|
||||
release_mem_region(0xDD0000, 256);
|
||||
free_irq(IRQ_AMIGA_PORTS, a3000_intr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -12,40 +12,40 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#ifndef CMD_PER_LUN
|
||||
#define CMD_PER_LUN 2
|
||||
#define CMD_PER_LUN 2
|
||||
#endif
|
||||
|
||||
#ifndef CAN_QUEUE
|
||||
#define CAN_QUEUE 16
|
||||
#define CAN_QUEUE 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if the transfer address ANDed with this results in a non-zero
|
||||
* result, then we can't use DMA.
|
||||
*/
|
||||
#define A3000_XFER_MASK (0x00000003)
|
||||
#define A3000_XFER_MASK (0x00000003)
|
||||
|
||||
typedef struct {
|
||||
unsigned char pad1[2];
|
||||
volatile unsigned short DAWR;
|
||||
volatile unsigned int WTC;
|
||||
unsigned char pad2[2];
|
||||
volatile unsigned short CNTR;
|
||||
volatile unsigned long ACR;
|
||||
unsigned char pad3[2];
|
||||
volatile unsigned short ST_DMA;
|
||||
unsigned char pad4[2];
|
||||
volatile unsigned short FLUSH;
|
||||
unsigned char pad5[2];
|
||||
volatile unsigned short CINT;
|
||||
unsigned char pad6[2];
|
||||
volatile unsigned short ISTR;
|
||||
unsigned char pad7[30];
|
||||
volatile unsigned short SP_DMA;
|
||||
unsigned char pad8;
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad9;
|
||||
volatile unsigned char SCMD;
|
||||
unsigned char pad1[2];
|
||||
volatile unsigned short DAWR;
|
||||
volatile unsigned int WTC;
|
||||
unsigned char pad2[2];
|
||||
volatile unsigned short CNTR;
|
||||
volatile unsigned long ACR;
|
||||
unsigned char pad3[2];
|
||||
volatile unsigned short ST_DMA;
|
||||
unsigned char pad4[2];
|
||||
volatile unsigned short FLUSH;
|
||||
unsigned char pad5[2];
|
||||
volatile unsigned short CINT;
|
||||
unsigned char pad6[2];
|
||||
volatile unsigned short ISTR;
|
||||
unsigned char pad7[30];
|
||||
volatile unsigned short SP_DMA;
|
||||
unsigned char pad8;
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad9;
|
||||
volatile unsigned char SCMD;
|
||||
} a3000_scsiregs;
|
||||
|
||||
#define DAWR_A3000 (3)
|
||||
|
|
|
@ -328,6 +328,16 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
|
||||
{
|
||||
char inq_data;
|
||||
scsi_sg_copy_to_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
||||
if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
|
||||
inq_data &= 0xdf;
|
||||
scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_get_containers - list containers
|
||||
* @common: adapter to probe
|
||||
|
@ -1598,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
|
|||
int status;
|
||||
struct aac_dev *dev;
|
||||
struct fib * cmd_fibcontext;
|
||||
int cid;
|
||||
|
||||
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
||||
/*
|
||||
|
@ -1647,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd)
|
|||
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
|
||||
break;
|
||||
}
|
||||
|
||||
if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
|
||||
cid = scmd_id(scsicmd);
|
||||
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
|
||||
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
||||
SAM_STAT_CHECK_CONDITION;
|
||||
set_sense(&dev->fsa_dev[cid].sense_data,
|
||||
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
||||
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
||||
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
||||
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
||||
SCSI_SENSE_BUFFERSIZE));
|
||||
scsicmd->scsi_done(scsicmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
|
||||
smp_processor_id(), (unsigned long long)lba, jiffies));
|
||||
if (aac_adapter_bounds(dev,scsicmd,lba))
|
||||
|
@ -1688,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
|
|||
int status;
|
||||
struct aac_dev *dev;
|
||||
struct fib * cmd_fibcontext;
|
||||
int cid;
|
||||
|
||||
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
||||
/*
|
||||
|
@ -1727,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd)
|
|||
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
|
||||
fua = scsicmd->cmnd[1] & 0x8;
|
||||
}
|
||||
|
||||
if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
|
||||
cid = scmd_id(scsicmd);
|
||||
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
|
||||
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
||||
SAM_STAT_CHECK_CONDITION;
|
||||
set_sense(&dev->fsa_dev[cid].sense_data,
|
||||
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
||||
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
||||
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
||||
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
||||
SCSI_SENSE_BUFFERSIZE));
|
||||
scsicmd->scsi_done(scsicmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
|
||||
smp_processor_id(), (unsigned long long)lba, jiffies));
|
||||
if (aac_adapter_bounds(dev,scsicmd,lba))
|
||||
|
@ -2573,6 +2617,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
|
|||
|
||||
scsi_dma_unmap(scsicmd);
|
||||
|
||||
/* expose physical device if expose_physicald flag is on */
|
||||
if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
|
||||
&& expose_physicals > 0)
|
||||
aac_expose_phy_device(scsicmd);
|
||||
|
||||
/*
|
||||
* First check the fib status
|
||||
*/
|
||||
|
@ -2678,8 +2727,22 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
|
|||
scsicmd->cmnd[0],
|
||||
le32_to_cpu(srbreply->scsi_status));
|
||||
#endif
|
||||
scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
|
||||
break;
|
||||
if ((scsicmd->cmnd[0] == ATA_12)
|
||||
|| (scsicmd->cmnd[0] == ATA_16)) {
|
||||
if (scsicmd->cmnd[2] & (0x01 << 5)) {
|
||||
scsicmd->result = DID_OK << 16
|
||||
| COMMAND_COMPLETE << 8;
|
||||
break;
|
||||
} else {
|
||||
scsicmd->result = DID_ERROR << 16
|
||||
| COMMAND_COMPLETE << 8;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
scsicmd->result = DID_ERROR << 16
|
||||
| COMMAND_COMPLETE << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
|
||||
int len;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef AAC_DRIVER_BUILD
|
||||
# define AAC_DRIVER_BUILD 24702
|
||||
# define AAC_DRIVER_BUILD 26400
|
||||
# define AAC_DRIVER_BRANCH "-ms"
|
||||
#endif
|
||||
#define MAXIMUM_NUM_CONTAINERS 32
|
||||
|
@ -26,6 +26,8 @@
|
|||
#define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
|
||||
#define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256)
|
||||
|
||||
#define AAC_DEBUG_INSTRUMENT_AIF_DELETE
|
||||
|
||||
/*
|
||||
* These macros convert from physical channels to virtual channels
|
||||
*/
|
||||
|
|
|
@ -966,6 +966,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
|
|||
device_config_needed =
|
||||
(((__le32 *)aifcmd->data)[0] ==
|
||||
cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
|
||||
if (device_config_needed == ADD) {
|
||||
device = scsi_device_lookup(dev->scsi_host_ptr,
|
||||
channel,
|
||||
id,
|
||||
lun);
|
||||
if (device) {
|
||||
scsi_remove_device(device);
|
||||
scsi_device_put(device);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AifEnEnclosureManagement:
|
||||
|
@ -1123,6 +1133,9 @@ retry_next:
|
|||
if (device) {
|
||||
switch (device_config_needed) {
|
||||
case DELETE:
|
||||
#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
|
||||
scsi_remove_device(device);
|
||||
#else
|
||||
if (scsi_device_online(device)) {
|
||||
scsi_device_set_state(device, SDEV_OFFLINE);
|
||||
sdev_printk(KERN_INFO, device,
|
||||
|
@ -1131,6 +1144,7 @@ retry_next:
|
|||
"array deleted" :
|
||||
"enclosure services event");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ADD:
|
||||
if (!scsi_device_online(device)) {
|
||||
|
@ -1145,12 +1159,16 @@ retry_next:
|
|||
case CHANGE:
|
||||
if ((channel == CONTAINER_CHANNEL)
|
||||
&& (!dev->fsa_dev[container].valid)) {
|
||||
#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
|
||||
scsi_remove_device(device);
|
||||
#else
|
||||
if (!scsi_device_online(device))
|
||||
break;
|
||||
scsi_device_set_state(device, SDEV_OFFLINE);
|
||||
sdev_printk(KERN_INFO, device,
|
||||
"Device offlined - %s\n",
|
||||
"array failed");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
scsi_rescan_device(&device->sdev_gendev);
|
||||
|
|
|
@ -116,35 +116,6 @@ bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SG element for the I/O request given the SG element index
|
||||
*/
|
||||
static inline union bfi_addr_u
|
||||
bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
|
||||
{
|
||||
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
|
||||
struct scatterlist *sge;
|
||||
u64 addr;
|
||||
|
||||
sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
|
||||
addr = (u64) sg_dma_address(sge);
|
||||
|
||||
return *((union bfi_addr_u *) &addr);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
|
||||
{
|
||||
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
|
||||
struct scatterlist *sge;
|
||||
u32 len;
|
||||
|
||||
sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
|
||||
len = sg_dma_len(sge);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Command Reference Number for the I/O request. 0 if none.
|
||||
*/
|
||||
|
|
|
@ -731,6 +731,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
|
|||
static struct fcp_cmnd_s cmnd_z0 = { 0 };
|
||||
struct bfi_sge_s *sge;
|
||||
u32 pgdlen = 0;
|
||||
u64 addr;
|
||||
struct scatterlist *sg;
|
||||
struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
|
||||
|
||||
/**
|
||||
* check for room in queue to send request now
|
||||
|
@ -754,8 +757,10 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
|
|||
*/
|
||||
sge = &m->sges[0];
|
||||
if (ioim->nsges) {
|
||||
sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
|
||||
pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
|
||||
sg = (struct scatterlist *)scsi_sglist(cmnd);
|
||||
addr = bfa_os_sgaddr(sg_dma_address(sg));
|
||||
sge->sga = *(union bfi_addr_u *) &addr;
|
||||
pgdlen = sg_dma_len(sg);
|
||||
sge->sg_len = pgdlen;
|
||||
sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
|
||||
BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
|
||||
|
@ -868,10 +873,16 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
|
|||
struct bfi_sge_s *sge;
|
||||
struct bfa_sgpg_s *sgpg;
|
||||
u32 pgcumsz;
|
||||
u64 addr;
|
||||
struct scatterlist *sg;
|
||||
struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
|
||||
|
||||
sgeid = BFI_SGE_INLINE;
|
||||
ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
|
||||
|
||||
sg = scsi_sglist(cmnd);
|
||||
sg = sg_next(sg);
|
||||
|
||||
do {
|
||||
sge = sgpg->sgpg->sges;
|
||||
nsges = ioim->nsges - sgeid;
|
||||
|
@ -879,9 +890,10 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
|
|||
nsges = BFI_SGPG_DATA_SGES;
|
||||
|
||||
pgcumsz = 0;
|
||||
for (i = 0; i < nsges; i++, sge++, sgeid++) {
|
||||
sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
|
||||
sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
|
||||
for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) {
|
||||
addr = bfa_os_sgaddr(sg_dma_address(sg));
|
||||
sge->sga = *(union bfi_addr_u *) &addr;
|
||||
sge->sg_len = sg_dma_len(sg);
|
||||
pgcumsz += sge->sg_len;
|
||||
|
||||
/**
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
#include <scsi/scsi_transport_fc.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
#define __BIGENDIAN
|
||||
#endif
|
||||
|
||||
#define BFA_ERR KERN_ERR
|
||||
#define BFA_WARNING KERN_WARNING
|
||||
#define BFA_NOTICE KERN_NOTICE
|
||||
|
@ -123,6 +127,15 @@ int bfa_os_MWB(void *);
|
|||
(((_x) & 0x00ff0000) >> 8) | \
|
||||
(((_x) & 0xff000000) >> 24))
|
||||
|
||||
#define bfa_os_swap_sgaddr(_x) ((u64)( \
|
||||
(((u64)(_x) & (u64)0x00000000000000ffull) << 32) | \
|
||||
(((u64)(_x) & (u64)0x000000000000ff00ull) << 32) | \
|
||||
(((u64)(_x) & (u64)0x0000000000ff0000ull) << 32) | \
|
||||
(((u64)(_x) & (u64)0x00000000ff000000ull) << 32) | \
|
||||
(((u64)(_x) & (u64)0x000000ff00000000ull) >> 32) | \
|
||||
(((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32) | \
|
||||
(((u64)(_x) & (u64)0x00ff000000000000ull) >> 32) | \
|
||||
(((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
|
||||
|
||||
#ifndef __BIGENDIAN
|
||||
#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
|
||||
|
@ -133,6 +146,7 @@ int bfa_os_MWB(void *);
|
|||
#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
|
||||
|
||||
#define bfa_os_wtole(_x) (_x)
|
||||
#define bfa_os_sgaddr(_x) (_x)
|
||||
|
||||
#else
|
||||
|
||||
|
@ -141,6 +155,7 @@ int bfa_os_MWB(void *);
|
|||
#define bfa_os_hton3b(_x) (_x)
|
||||
#define bfa_os_htonll(_x) (_x)
|
||||
#define bfa_os_wtole(_x) bfa_os_swap32(_x)
|
||||
#define bfa_os_sgaddr(_x) bfa_os_swap_sgaddr(_x)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -161,12 +176,12 @@ int bfa_os_MWB(void *);
|
|||
#define bfa_os_addr_t char __iomem *
|
||||
#define bfa_os_panic()
|
||||
|
||||
#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr))
|
||||
#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr))
|
||||
#define bfa_os_reg_read(_raddr) readl(_raddr)
|
||||
#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))
|
||||
#define bfa_os_mem_read(_raddr, _off) \
|
||||
bfa_os_ntohl(readl(((_raddr) + (_off))))
|
||||
bfa_os_swap32(readl(((_raddr) + (_off))))
|
||||
#define bfa_os_mem_write(_raddr, _off, _val) \
|
||||
writel(bfa_os_htonl((_val)), ((_raddr) + (_off)))
|
||||
writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))
|
||||
|
||||
#define BFA_TRC_TS(_trcm) \
|
||||
({ \
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include <fcb/bfa_fcb.h>
|
||||
|
||||
BFA_TRC_FILE(LDRV, BFAD);
|
||||
static DEFINE_MUTEX(bfad_mutex);
|
||||
DEFINE_MUTEX(bfad_mutex);
|
||||
LIST_HEAD(bfad_list);
|
||||
static int bfad_inst;
|
||||
int bfad_supported_fc4s;
|
||||
|
@ -299,8 +299,6 @@ bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)
|
|||
complete(vport_drv->comp_del);
|
||||
return;
|
||||
}
|
||||
|
||||
kfree(vport_drv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,7 +481,7 @@ ext:
|
|||
*/
|
||||
bfa_status_t
|
||||
bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
|
||||
struct bfa_port_cfg_s *port_cfg)
|
||||
struct bfa_port_cfg_s *port_cfg, struct device *dev)
|
||||
{
|
||||
struct bfad_vport_s *vport;
|
||||
int rc = BFA_STATUS_OK;
|
||||
|
@ -506,7 +504,8 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
|
|||
goto ext_free_vport;
|
||||
|
||||
if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) {
|
||||
rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port);
|
||||
rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port,
|
||||
dev);
|
||||
if (rc != BFA_STATUS_OK)
|
||||
goto ext_free_fcs_vport;
|
||||
}
|
||||
|
@ -591,7 +590,6 @@ bfad_init_timer(struct bfad_s *bfad)
|
|||
int
|
||||
bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
|
||||
{
|
||||
unsigned long bar0_len;
|
||||
int rc = -ENODEV;
|
||||
|
||||
if (pci_enable_device(pdev)) {
|
||||
|
@ -611,9 +609,7 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
|
|||
goto out_release_region;
|
||||
}
|
||||
|
||||
bfad->pci_bar0_map = pci_resource_start(pdev, 0);
|
||||
bar0_len = pci_resource_len(pdev, 0);
|
||||
bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len);
|
||||
bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
|
||||
if (bfad->pci_bar0_kva == NULL) {
|
||||
BFA_PRINTF(BFA_ERR, "Fail to map bar0\n");
|
||||
|
@ -646,11 +642,7 @@ out:
|
|||
void
|
||||
bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
|
||||
{
|
||||
#if defined(__ia64__)
|
||||
pci_iounmap(pdev, bfad->pci_bar0_kva);
|
||||
#else
|
||||
iounmap(bfad->pci_bar0_kva);
|
||||
#endif
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
|
@ -848,7 +840,8 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
|
|||
goto out;
|
||||
}
|
||||
|
||||
rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port);
|
||||
rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port,
|
||||
&bfad->pcidev->dev);
|
||||
if (rc != BFA_STATUS_OK)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -364,6 +364,152 @@ bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
|
|||
|
||||
}
|
||||
|
||||
static int
|
||||
bfad_im_vport_create(struct fc_vport *fc_vport, bool disable)
|
||||
{
|
||||
char *vname = fc_vport->symbolic_name;
|
||||
struct Scsi_Host *shost = fc_vport->shost;
|
||||
struct bfad_im_port_s *im_port =
|
||||
(struct bfad_im_port_s *) shost->hostdata[0];
|
||||
struct bfad_s *bfad = im_port->bfad;
|
||||
struct bfa_port_cfg_s port_cfg;
|
||||
int status = 0, rc;
|
||||
unsigned long flags;
|
||||
|
||||
memset(&port_cfg, 0, sizeof(port_cfg));
|
||||
|
||||
port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
|
||||
port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name);
|
||||
|
||||
if (strlen(vname) > 0)
|
||||
strcpy((char *)&port_cfg.sym_name, vname);
|
||||
|
||||
port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
|
||||
rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
|
||||
|
||||
if (rc == BFA_STATUS_OK) {
|
||||
struct bfad_vport_s *vport;
|
||||
struct bfa_fcs_vport_s *fcs_vport;
|
||||
struct Scsi_Host *vshost;
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0,
|
||||
port_cfg.pwwn);
|
||||
if (fcs_vport == NULL) {
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
return VPCERR_BAD_WWN;
|
||||
}
|
||||
|
||||
fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
|
||||
if (disable) {
|
||||
bfa_fcs_vport_stop(fcs_vport);
|
||||
fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
|
||||
}
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
|
||||
vport = fcs_vport->vport_drv;
|
||||
vshost = vport->drv_port.im_port->shost;
|
||||
fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn);
|
||||
fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn);
|
||||
fc_vport->dd_data = vport;
|
||||
vport->drv_port.im_port->fc_vport = fc_vport;
|
||||
|
||||
} else if (rc == BFA_STATUS_INVALID_WWN)
|
||||
return VPCERR_BAD_WWN;
|
||||
else if (rc == BFA_STATUS_VPORT_EXISTS)
|
||||
return VPCERR_BAD_WWN;
|
||||
else if (rc == BFA_STATUS_VPORT_MAX)
|
||||
return VPCERR_NO_FABRIC_SUPP;
|
||||
else if (rc == BFA_STATUS_VPORT_WWN_BP)
|
||||
return VPCERR_BAD_WWN;
|
||||
else
|
||||
return FC_VPORT_FAILED;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
bfad_im_vport_delete(struct fc_vport *fc_vport)
|
||||
{
|
||||
struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data;
|
||||
struct bfad_im_port_s *im_port =
|
||||
(struct bfad_im_port_s *) vport->drv_port.im_port;
|
||||
struct bfad_s *bfad = im_port->bfad;
|
||||
struct bfad_port_s *port;
|
||||
struct bfa_fcs_vport_s *fcs_vport;
|
||||
struct Scsi_Host *vshost;
|
||||
wwn_t pwwn;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
struct completion fcomp;
|
||||
|
||||
if (im_port->flags & BFAD_PORT_DELETE)
|
||||
goto free_scsi_host;
|
||||
|
||||
port = im_port->port;
|
||||
|
||||
vshost = vport->drv_port.im_port->shost;
|
||||
pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost));
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
|
||||
if (fcs_vport == NULL)
|
||||
return VPCERR_BAD_WWN;
|
||||
|
||||
vport->drv_port.flags |= BFAD_PORT_DELETE;
|
||||
|
||||
vport->comp_del = &fcomp;
|
||||
init_completion(vport->comp_del);
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
rc = bfa_fcs_vport_delete(&vport->fcs_vport);
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
|
||||
wait_for_completion(vport->comp_del);
|
||||
|
||||
free_scsi_host:
|
||||
bfad_os_scsi_host_free(bfad, im_port);
|
||||
|
||||
kfree(vport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable)
|
||||
{
|
||||
struct bfad_vport_s *vport;
|
||||
struct bfad_s *bfad;
|
||||
struct bfa_fcs_vport_s *fcs_vport;
|
||||
struct Scsi_Host *vshost;
|
||||
wwn_t pwwn;
|
||||
unsigned long flags;
|
||||
|
||||
vport = (struct bfad_vport_s *)fc_vport->dd_data;
|
||||
bfad = vport->drv_port.bfad;
|
||||
vshost = vport->drv_port.im_port->shost;
|
||||
pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
|
||||
if (fcs_vport == NULL)
|
||||
return VPCERR_BAD_WWN;
|
||||
|
||||
if (disable) {
|
||||
bfa_fcs_vport_stop(fcs_vport);
|
||||
fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
|
||||
} else {
|
||||
bfa_fcs_vport_start(fcs_vport);
|
||||
fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fc_function_template bfad_im_fc_function_template = {
|
||||
|
||||
/* Target dynamic attributes */
|
||||
|
@ -413,6 +559,61 @@ struct fc_function_template bfad_im_fc_function_template = {
|
|||
.show_rport_dev_loss_tmo = 1,
|
||||
.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
|
||||
.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
|
||||
|
||||
.vport_create = bfad_im_vport_create,
|
||||
.vport_delete = bfad_im_vport_delete,
|
||||
.vport_disable = bfad_im_vport_disable,
|
||||
};
|
||||
|
||||
struct fc_function_template bfad_im_vport_fc_function_template = {
|
||||
|
||||
/* Target dynamic attributes */
|
||||
.get_starget_port_id = bfad_im_get_starget_port_id,
|
||||
.show_starget_port_id = 1,
|
||||
.get_starget_node_name = bfad_im_get_starget_node_name,
|
||||
.show_starget_node_name = 1,
|
||||
.get_starget_port_name = bfad_im_get_starget_port_name,
|
||||
.show_starget_port_name = 1,
|
||||
|
||||
/* Host dynamic attribute */
|
||||
.get_host_port_id = bfad_im_get_host_port_id,
|
||||
.show_host_port_id = 1,
|
||||
|
||||
/* Host fixed attributes */
|
||||
.show_host_node_name = 1,
|
||||
.show_host_port_name = 1,
|
||||
.show_host_supported_classes = 1,
|
||||
.show_host_supported_fc4s = 1,
|
||||
.show_host_supported_speeds = 1,
|
||||
.show_host_maxframe_size = 1,
|
||||
|
||||
/* More host dynamic attributes */
|
||||
.show_host_port_type = 1,
|
||||
.get_host_port_type = bfad_im_get_host_port_type,
|
||||
.show_host_port_state = 1,
|
||||
.get_host_port_state = bfad_im_get_host_port_state,
|
||||
.show_host_active_fc4s = 1,
|
||||
.get_host_active_fc4s = bfad_im_get_host_active_fc4s,
|
||||
.show_host_speed = 1,
|
||||
.get_host_speed = bfad_im_get_host_speed,
|
||||
.show_host_fabric_name = 1,
|
||||
.get_host_fabric_name = bfad_im_get_host_fabric_name,
|
||||
|
||||
.show_host_symbolic_name = 1,
|
||||
|
||||
/* Statistics */
|
||||
.get_fc_host_stats = bfad_im_get_stats,
|
||||
.reset_fc_host_stats = bfad_im_reset_stats,
|
||||
|
||||
/* Allocation length for host specific data */
|
||||
.dd_fcrport_size = sizeof(struct bfad_itnim_data_s *),
|
||||
|
||||
/* Remote port fixed attributes */
|
||||
.show_rport_maxframe_size = 1,
|
||||
.show_rport_supported_classes = 1,
|
||||
.show_rport_dev_loss_tmo = 1,
|
||||
.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
|
||||
.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -162,7 +162,6 @@ struct bfad_s {
|
|||
const char *pci_name;
|
||||
struct bfa_pcidev_s hal_pcidev;
|
||||
struct bfa_ioc_pci_attr_s pci_attr;
|
||||
unsigned long pci_bar0_map;
|
||||
void __iomem *pci_bar0_kva;
|
||||
struct completion comp;
|
||||
struct completion suspend;
|
||||
|
@ -254,7 +253,7 @@ do { \
|
|||
|
||||
|
||||
bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
|
||||
struct bfa_port_cfg_s *port_cfg);
|
||||
struct bfa_port_cfg_s *port_cfg, struct device *dev);
|
||||
bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
|
||||
struct bfa_port_cfg_s *port_cfg);
|
||||
bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
|
||||
|
@ -294,5 +293,6 @@ extern struct list_head bfad_list;
|
|||
extern int bfa_lun_queue_depth;
|
||||
extern int bfad_supported_fc4s;
|
||||
extern int bfa_linkup_delay;
|
||||
extern struct mutex bfad_mutex;
|
||||
|
||||
#endif /* __BFAD_DRV_H__ */
|
||||
|
|
|
@ -30,6 +30,7 @@ BFA_TRC_FILE(LDRV, IM);
|
|||
|
||||
DEFINE_IDR(bfad_im_port_index);
|
||||
struct scsi_transport_template *bfad_im_scsi_transport_template;
|
||||
struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
|
||||
static void bfad_im_itnim_work_handler(struct work_struct *work);
|
||||
static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
@ -252,7 +253,6 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
|
|||
struct bfa_itnim_s *bfa_itnim;
|
||||
bfa_status_t rc = BFA_STATUS_OK;
|
||||
|
||||
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
|
||||
tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
|
||||
if (!tskim) {
|
||||
BFA_DEV_PRINTF(bfad, BFA_ERR,
|
||||
|
@ -513,11 +513,14 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
|
|||
* Allocate a Scsi_Host for a port.
|
||||
*/
|
||||
int
|
||||
bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
||||
bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
|
||||
struct device *dev)
|
||||
{
|
||||
int error = 1;
|
||||
|
||||
mutex_lock(&bfad_mutex);
|
||||
if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
|
||||
mutex_unlock(&bfad_mutex);
|
||||
printk(KERN_WARNING "idr_pre_get failure\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -525,10 +528,13 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
|||
error = idr_get_new(&bfad_im_port_index, im_port,
|
||||
&im_port->idr_id);
|
||||
if (error) {
|
||||
mutex_unlock(&bfad_mutex);
|
||||
printk(KERN_WARNING "idr_get_new failure\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_unlock(&bfad_mutex);
|
||||
|
||||
im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
|
||||
if (!im_port->shost) {
|
||||
error = 1;
|
||||
|
@ -542,12 +548,15 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
|||
im_port->shost->max_lun = MAX_FCP_LUN;
|
||||
im_port->shost->max_cmd_len = 16;
|
||||
im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
|
||||
im_port->shost->transportt = bfad_im_scsi_transport_template;
|
||||
if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
|
||||
im_port->shost->transportt = bfad_im_scsi_transport_template;
|
||||
else
|
||||
im_port->shost->transportt =
|
||||
bfad_im_scsi_vport_transport_template;
|
||||
|
||||
error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad);
|
||||
error = scsi_add_host(im_port->shost, dev);
|
||||
if (error) {
|
||||
printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n",
|
||||
error);
|
||||
printk(KERN_WARNING "scsi_add_host failure %d\n", error);
|
||||
goto out_fc_rel;
|
||||
}
|
||||
|
||||
|
@ -559,7 +568,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
|||
out_fc_rel:
|
||||
scsi_host_put(im_port->shost);
|
||||
out_free_idr:
|
||||
mutex_lock(&bfad_mutex);
|
||||
idr_remove(&bfad_im_port_index, im_port->idr_id);
|
||||
mutex_unlock(&bfad_mutex);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -567,8 +578,6 @@ out:
|
|||
void
|
||||
bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
bfa_trc(bfad, bfad->inst_no);
|
||||
bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,
|
||||
im_port->shost->host_no);
|
||||
|
@ -578,9 +587,9 @@ bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
|||
scsi_remove_host(im_port->shost);
|
||||
scsi_host_put(im_port->shost);
|
||||
|
||||
spin_lock_irqsave(&bfad->bfad_lock, flags);
|
||||
mutex_lock(&bfad_mutex);
|
||||
idr_remove(&bfad_im_port_index, im_port->idr_id);
|
||||
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
|
||||
mutex_unlock(&bfad_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -589,9 +598,11 @@ bfad_im_port_delete_handler(struct work_struct *work)
|
|||
struct bfad_im_port_s *im_port =
|
||||
container_of(work, struct bfad_im_port_s, port_delete_work);
|
||||
|
||||
bfad_im_scsi_host_free(im_port->bfad, im_port);
|
||||
bfad_im_port_clean(im_port);
|
||||
kfree(im_port);
|
||||
if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
|
||||
im_port->flags |= BFAD_PORT_DELETE;
|
||||
fc_vport_terminate(im_port->fc_vport);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bfa_status_t
|
||||
|
@ -690,23 +701,6 @@ bfad_im_probe_undo(struct bfad_s *bfad)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port,
|
||||
struct bfad_s *bfad)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
|
||||
dev = &bfad->pcidev->dev;
|
||||
else
|
||||
dev = &bfad->pport.im_port->shost->shost_gendev;
|
||||
|
||||
return scsi_add_host(shost, dev);
|
||||
}
|
||||
|
||||
struct Scsi_Host *
|
||||
bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
|
||||
{
|
||||
|
@ -725,7 +719,8 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
|
|||
void
|
||||
bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
|
||||
{
|
||||
flush_workqueue(bfad->im->drv_workq);
|
||||
if (!(im_port->flags & BFAD_PORT_DELETE))
|
||||
flush_workqueue(bfad->im->drv_workq);
|
||||
bfad_im_scsi_host_free(im_port->bfad, im_port);
|
||||
bfad_im_port_clean(im_port);
|
||||
kfree(im_port);
|
||||
|
@ -830,6 +825,13 @@ bfad_im_module_init(void)
|
|||
if (!bfad_im_scsi_transport_template)
|
||||
return BFA_STATUS_ENOMEM;
|
||||
|
||||
bfad_im_scsi_vport_transport_template =
|
||||
fc_attach_transport(&bfad_im_vport_fc_function_template);
|
||||
if (!bfad_im_scsi_vport_transport_template) {
|
||||
fc_release_transport(bfad_im_scsi_transport_template);
|
||||
return BFA_STATUS_ENOMEM;
|
||||
}
|
||||
|
||||
return BFA_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -838,6 +840,8 @@ bfad_im_module_exit(void)
|
|||
{
|
||||
if (bfad_im_scsi_transport_template)
|
||||
fc_release_transport(bfad_im_scsi_transport_template);
|
||||
if (bfad_im_scsi_vport_transport_template)
|
||||
fc_release_transport(bfad_im_scsi_vport_transport_template);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -938,6 +942,7 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
|
|||
bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
|
||||
fc_host_port_name(host) =
|
||||
bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port)));
|
||||
fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
|
||||
|
||||
fc_host_supported_classes(host) = FC_COS_CLASS3;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);
|
|||
void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);
|
||||
void bfad_im_port_clean(struct bfad_im_port_s *im_port);
|
||||
int bfad_im_scsi_host_alloc(struct bfad_s *bfad,
|
||||
struct bfad_im_port_s *im_port);
|
||||
struct bfad_im_port_s *im_port, struct device *dev);
|
||||
void bfad_im_scsi_host_free(struct bfad_s *bfad,
|
||||
struct bfad_im_port_s *im_port);
|
||||
|
||||
|
@ -64,9 +64,11 @@ struct bfad_im_port_s {
|
|||
struct work_struct port_delete_work;
|
||||
int idr_id;
|
||||
u16 cur_scsi_id;
|
||||
u16 flags;
|
||||
struct list_head binding_list;
|
||||
struct Scsi_Host *shost;
|
||||
struct list_head itnim_mapped_list;
|
||||
struct fc_vport *fc_vport;
|
||||
};
|
||||
|
||||
enum bfad_itnim_state {
|
||||
|
@ -140,6 +142,8 @@ void bfad_im_itnim_unmap(struct bfad_im_port_s *im_port,
|
|||
extern struct scsi_host_template bfad_im_scsi_host_template;
|
||||
extern struct scsi_host_template bfad_im_vport_template;
|
||||
extern struct fc_function_template bfad_im_fc_function_template;
|
||||
extern struct fc_function_template bfad_im_vport_fc_function_template;
|
||||
extern struct scsi_transport_template *bfad_im_scsi_transport_template;
|
||||
extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -347,6 +347,7 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
|
|||
|
||||
login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
|
||||
login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
|
||||
login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;
|
||||
|
||||
login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
|
||||
login_wqe->resp_bd_list_addr_hi =
|
||||
|
@ -356,7 +357,6 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
|
|||
(bnx2i_conn->gen_pdu.resp_buf_size <<
|
||||
ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
|
||||
login_wqe->resp_buffer = dword;
|
||||
login_wqe->flags = 0;
|
||||
login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
|
||||
login_wqe->bd_list_addr_hi =
|
||||
(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
|
||||
|
|
|
@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
|
|||
static u32 adapter_count;
|
||||
|
||||
#define DRV_MODULE_NAME "bnx2i"
|
||||
#define DRV_MODULE_VERSION "2.1.0"
|
||||
#define DRV_MODULE_RELDATE "Dec 06, 2009"
|
||||
#define DRV_MODULE_VERSION "2.1.1"
|
||||
#define DRV_MODULE_RELDATE "Mar 24, 2010"
|
||||
|
||||
static char version[] __devinitdata =
|
||||
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
|
||||
|
@ -26,7 +26,8 @@ static char version[] __devinitdata =
|
|||
|
||||
|
||||
MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
|
||||
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
|
||||
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
|
||||
" iSCSI Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_MODULE_VERSION);
|
||||
|
||||
|
@ -289,6 +290,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
|
|||
int rc;
|
||||
|
||||
mutex_lock(&bnx2i_dev_lock);
|
||||
hba->cnic = cnic;
|
||||
rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
|
||||
if (!rc) {
|
||||
hba->age++;
|
||||
|
@ -335,8 +337,7 @@ void bnx2i_ulp_init(struct cnic_dev *dev)
|
|||
if (bnx2i_init_one(hba, dev)) {
|
||||
printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
|
||||
bnx2i_free_hba(hba);
|
||||
} else
|
||||
hba->cnic = dev;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -104,8 +104,10 @@ static int __init cxgb3i_init_module(void)
|
|||
return err;
|
||||
|
||||
err = cxgb3i_pdu_init();
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
cxgb3i_iscsi_cleanup();
|
||||
return err;
|
||||
}
|
||||
|
||||
cxgb3_register_client(&t3c_client);
|
||||
|
||||
|
|
|
@ -285,13 +285,11 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
|
|||
switch (cmd) {
|
||||
case MODE_SELECT:
|
||||
len = sizeof(short_trespass);
|
||||
rq->cmd_flags |= REQ_RW;
|
||||
rq->cmd[1] = 0x10;
|
||||
rq->cmd[4] = len;
|
||||
break;
|
||||
case MODE_SELECT_10:
|
||||
len = sizeof(long_trespass);
|
||||
rq->cmd_flags |= REQ_RW;
|
||||
rq->cmd[1] = 0x10;
|
||||
rq->cmd[8] = len;
|
||||
break;
|
||||
|
|
|
@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *,
|
|||
static int fcoe_percpu_receive_thread(void *);
|
||||
static void fcoe_clean_pending_queue(struct fc_lport *);
|
||||
static void fcoe_percpu_clean(struct fc_lport *);
|
||||
static int fcoe_link_speed_update(struct fc_lport *);
|
||||
static int fcoe_link_ok(struct fc_lport *);
|
||||
|
||||
static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
|
||||
|
@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *);
|
|||
static int fcoe_vport_create(struct fc_vport *, bool disabled);
|
||||
static int fcoe_vport_disable(struct fc_vport *, bool disable);
|
||||
static void fcoe_set_vport_symbolic_name(struct fc_vport *);
|
||||
static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
|
||||
|
||||
static struct libfc_function_template fcoe_libfc_fcn_templ = {
|
||||
.frame_send = fcoe_xmit,
|
||||
|
@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
|
|||
.ddp_done = fcoe_ddp_done,
|
||||
.elsct_send = fcoe_elsct_send,
|
||||
.get_lesb = fcoe_get_lesb,
|
||||
.lport_set_port_id = fcoe_set_port_id,
|
||||
};
|
||||
|
||||
struct fc_function_template fcoe_transport_function = {
|
||||
|
@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
|
|||
port->fcoe_pending_queue_active = 0;
|
||||
setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
|
||||
|
||||
fcoe_link_speed_update(lport);
|
||||
|
||||
if (!lport->vport) {
|
||||
/*
|
||||
* Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
|
||||
|
@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
|
|||
/**
|
||||
* fcoe_shost_config() - Set up the SCSI host associated with a local port
|
||||
* @lport: The local port
|
||||
* @shost: The SCSI host to associate with the local port
|
||||
* @dev: The device associated with the SCSI host
|
||||
*
|
||||
* Must be called after fcoe_lport_config() and fcoe_netdev_config()
|
||||
*
|
||||
* Returns: 0 for success
|
||||
*/
|
||||
static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
|
||||
struct device *dev)
|
||||
static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
|
|||
lport->host->max_lun = FCOE_MAX_LUN;
|
||||
lport->host->max_id = FCOE_MAX_FCP_TARGET;
|
||||
lport->host->max_channel = 0;
|
||||
lport->host->max_cmd_len = FCOE_MAX_CMD_LEN;
|
||||
|
||||
if (lport->vport)
|
||||
lport->host->transportt = fcoe_vport_transport_template;
|
||||
else
|
||||
|
@ -796,6 +801,12 @@ skip_oem:
|
|||
/**
|
||||
* fcoe_if_destroy() - Tear down a SW FCoE instance
|
||||
* @lport: The local port to be destroyed
|
||||
*
|
||||
* Locking: must be called with the RTNL mutex held and RTNL mutex
|
||||
* needed to be dropped by this function since not dropping RTNL
|
||||
* would cause circular locking warning on synchronous fip worker
|
||||
* cancelling thru fcoe_interface_put invoked by this function.
|
||||
*
|
||||
*/
|
||||
static void fcoe_if_destroy(struct fc_lport *lport)
|
||||
{
|
||||
|
@ -818,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
|
|||
/* Free existing transmit skbs */
|
||||
fcoe_clean_pending_queue(lport);
|
||||
|
||||
rtnl_lock();
|
||||
if (!is_zero_ether_addr(port->data_src_addr))
|
||||
dev_uc_del(netdev, port->data_src_addr);
|
||||
rtnl_unlock();
|
||||
|
@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)
|
|||
|
||||
/* Release the Scsi_Host */
|
||||
scsi_host_put(lport->host);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
|||
struct net_device *netdev = fcoe->netdev;
|
||||
struct fc_lport *lport = NULL;
|
||||
struct fcoe_port *port;
|
||||
struct Scsi_Host *shost;
|
||||
int rc;
|
||||
/*
|
||||
* parent is only a vport if npiv is 1,
|
||||
|
@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
|||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
shost = lport->host;
|
||||
port = lport_priv(lport);
|
||||
port->lport = lport;
|
||||
port->fcoe = fcoe;
|
||||
|
@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
|||
}
|
||||
|
||||
if (npiv) {
|
||||
FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
|
||||
FCOE_NETDEV_DBG(netdev, "Setting vport names, "
|
||||
"%16.16llx %16.16llx\n",
|
||||
vport->node_name, vport->port_name);
|
||||
fc_set_wwnn(lport, vport->node_name);
|
||||
fc_set_wwpn(lport, vport->port_name);
|
||||
|
@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
|||
}
|
||||
|
||||
/* configure lport scsi host properties */
|
||||
rc = fcoe_shost_config(lport, shost, parent);
|
||||
rc = fcoe_shost_config(lport, parent);
|
||||
if (rc) {
|
||||
FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "
|
||||
"interface\n");
|
||||
|
@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
|
|||
struct sk_buff *skb;
|
||||
#ifdef CONFIG_SMP
|
||||
struct fcoe_percpu_s *p0;
|
||||
unsigned targ_cpu = smp_processor_id();
|
||||
unsigned targ_cpu = get_cpu();
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
|
||||
|
@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
|
|||
kfree_skb(skb);
|
||||
spin_unlock_bh(&p->fcoe_rx_list.lock);
|
||||
}
|
||||
put_cpu();
|
||||
#else
|
||||
/*
|
||||
* This a non-SMP scenario where the singular Rx thread is
|
||||
|
@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
|
|||
|
||||
return 0;
|
||||
err:
|
||||
fc_lport_get_stats(lport)->ErrorFrames++;
|
||||
|
||||
per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++;
|
||||
put_cpu();
|
||||
err2:
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
|
@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
|
||||
if (unlikely(fh->fh_type == FC_TYPE_ELS) &&
|
||||
fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb))
|
||||
return 0;
|
||||
|
||||
|
@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
|
|||
skb_shinfo(skb)->gso_size = 0;
|
||||
}
|
||||
/* update tx stats: regardless if LLD fails */
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
stats->TxFrames++;
|
||||
stats->TxWords += wlen;
|
||||
put_cpu();
|
||||
|
||||
/* send down to lld */
|
||||
fr_dev(fp) = lport;
|
||||
|
@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
struct fc_frame_header *fh;
|
||||
struct fcoe_crc_eof crc_eof;
|
||||
struct fc_frame *fp;
|
||||
u8 *mac = NULL;
|
||||
struct fcoe_port *port;
|
||||
struct fcoe_hdr *hp;
|
||||
|
||||
|
@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
skb_end_pointer(skb), skb->csum,
|
||||
skb->dev ? skb->dev->name : "<NULL>");
|
||||
|
||||
/*
|
||||
* Save source MAC address before discarding header.
|
||||
*/
|
||||
port = lport_priv(lport);
|
||||
if (skb_is_nonlinear(skb))
|
||||
skb_linearize(skb); /* not ideal */
|
||||
mac = eth_hdr(skb)->h_source;
|
||||
|
||||
/*
|
||||
* Frame length checks and setting up the header pointers
|
||||
|
@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
hp = (struct fcoe_hdr *) skb_network_header(skb);
|
||||
fh = (struct fc_frame_header *) skb_transport_header(skb);
|
||||
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
|
||||
if (stats->ErrorFrames < 5)
|
||||
printk(KERN_WARNING "fcoe: FCoE version "
|
||||
|
@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
"initiator supports version "
|
||||
"%x\n", FC_FCOE_DECAPS_VER(hp),
|
||||
FC_FCOE_VER);
|
||||
stats->ErrorFrames++;
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
skb_pull(skb, sizeof(struct fcoe_hdr));
|
||||
|
@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
fr_sof(fp) = hp->fcoe_sof;
|
||||
|
||||
/* Copy out the CRC and EOF trailer for access */
|
||||
if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof)))
|
||||
goto drop;
|
||||
fr_eof(fp) = crc_eof.fcoe_eof;
|
||||
fr_crc(fp) = crc_eof.fcoe_crc32;
|
||||
if (pskb_trim(skb, fr_len)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
if (pskb_trim(skb, fr_len))
|
||||
goto drop;
|
||||
|
||||
/*
|
||||
* We only check CRC if no offload is available and if it is
|
||||
|
@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb)
|
|||
fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
|
||||
|
||||
fh = fc_frame_header_get(fp);
|
||||
if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
|
||||
fh->fh_type == FC_TYPE_FCP) {
|
||||
fc_exch_recv(lport, fp);
|
||||
return;
|
||||
}
|
||||
if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
|
||||
if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
|
||||
fh->fh_type != FC_TYPE_FCP) &&
|
||||
(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
|
||||
if (le32_to_cpu(fr_crc(fp)) !=
|
||||
~crc32(~0, skb->data, fr_len)) {
|
||||
if (stats->InvalidCRCCount < 5)
|
||||
printk(KERN_WARNING "fcoe: dropping "
|
||||
"frame with CRC error\n");
|
||||
stats->InvalidCRCCount++;
|
||||
stats->ErrorFrames++;
|
||||
fc_frame_free(fp);
|
||||
return;
|
||||
goto drop;
|
||||
}
|
||||
fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
|
||||
}
|
||||
put_cpu();
|
||||
fc_exch_recv(lport, fp);
|
||||
return;
|
||||
|
||||
drop:
|
||||
stats->ErrorFrames++;
|
||||
put_cpu();
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
|
|||
FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
|
||||
"from netdev netlink\n", event);
|
||||
}
|
||||
|
||||
fcoe_link_speed_update(lport);
|
||||
|
||||
if (link_possible && !fcoe_link_ok(lport))
|
||||
fcoe_ctlr_link_up(&fcoe->ctlr);
|
||||
else if (fcoe_ctlr_link_down(&fcoe->ctlr)) {
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
stats->LinkFailureCount++;
|
||||
put_cpu();
|
||||
fcoe_clean_pending_queue(lport);
|
||||
}
|
||||
out:
|
||||
|
@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
|
|||
goto out_nodev;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
if (!rtnl_trylock()) {
|
||||
dev_put(netdev);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
return restart_syscall();
|
||||
}
|
||||
|
||||
fcoe = fcoe_hostlist_lookup_port(netdev);
|
||||
rtnl_unlock();
|
||||
|
||||
if (fcoe)
|
||||
if (fcoe) {
|
||||
fc_fabric_logoff(fcoe->ctlr.lp);
|
||||
else
|
||||
fcoe_ctlr_link_down(&fcoe->ctlr);
|
||||
} else
|
||||
rc = -ENODEV;
|
||||
|
||||
dev_put(netdev);
|
||||
|
@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
|
|||
goto out_nodev;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
if (!rtnl_trylock()) {
|
||||
dev_put(netdev);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
return restart_syscall();
|
||||
}
|
||||
|
||||
fcoe = fcoe_hostlist_lookup_port(netdev);
|
||||
rtnl_unlock();
|
||||
|
||||
if (fcoe)
|
||||
if (fcoe) {
|
||||
if (!fcoe_link_ok(fcoe->ctlr.lp))
|
||||
fcoe_ctlr_link_up(&fcoe->ctlr);
|
||||
rc = fc_fabric_login(fcoe->ctlr.lp);
|
||||
else
|
||||
} else
|
||||
rc = -ENODEV;
|
||||
|
||||
dev_put(netdev);
|
||||
|
@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
|
|||
goto out_nodev;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
if (!rtnl_trylock()) {
|
||||
dev_put(netdev);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
return restart_syscall();
|
||||
}
|
||||
|
||||
fcoe = fcoe_hostlist_lookup_port(netdev);
|
||||
if (!fcoe) {
|
||||
rtnl_unlock();
|
||||
|
@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
|
|||
}
|
||||
list_del(&fcoe->list);
|
||||
fcoe_interface_cleanup(fcoe);
|
||||
rtnl_unlock();
|
||||
/* RTNL mutex is dropped by fcoe_if_destroy */
|
||||
fcoe_if_destroy(fcoe->ctlr.lp);
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
out_putdev:
|
||||
dev_put(netdev);
|
||||
|
@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work)
|
|||
|
||||
port = container_of(work, struct fcoe_port, destroy_work);
|
||||
mutex_lock(&fcoe_config_mutex);
|
||||
rtnl_lock();
|
||||
/* RTNL mutex is dropped by fcoe_if_destroy */
|
||||
fcoe_if_destroy(port->lport);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
}
|
||||
|
@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
|
|||
struct net_device *netdev;
|
||||
|
||||
mutex_lock(&fcoe_config_mutex);
|
||||
|
||||
if (!rtnl_trylock()) {
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
return restart_syscall();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FCOE_MODULE
|
||||
/*
|
||||
* Make sure the module has been initialized, and is not about to be
|
||||
|
@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
|
|||
*/
|
||||
if (THIS_MODULE->state != MODULE_STATE_LIVE) {
|
||||
rc = -ENODEV;
|
||||
goto out_nodev;
|
||||
goto out_nomod;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
|
|||
goto out_nomod;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
netdev = fcoe_if_to_netdev(buffer);
|
||||
if (!netdev) {
|
||||
rc = -ENODEV;
|
||||
|
@ -2122,35 +2153,27 @@ out_free:
|
|||
out_putdev:
|
||||
dev_put(netdev);
|
||||
out_nodev:
|
||||
rtnl_unlock();
|
||||
module_put(THIS_MODULE);
|
||||
out_nomod:
|
||||
rtnl_unlock();
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_link_ok() - Check if the link is OK for a local port
|
||||
* @lport: The local port to check link on
|
||||
*
|
||||
* Any permanently-disqualifying conditions have been previously checked.
|
||||
* This also updates the speed setting, which may change with link for 100/1000.
|
||||
*
|
||||
* This function should probably be checking for PAUSE support at some point
|
||||
* in the future. Currently Per-priority-pause is not determinable using
|
||||
* ethtool, so we shouldn't be restrictive until that problem is resolved.
|
||||
*
|
||||
* Returns: 0 if link is OK for use by FCoE.
|
||||
* fcoe_link_speed_update() - Update the supported and actual link speeds
|
||||
* @lport: The local port to update speeds for
|
||||
*
|
||||
* Returns: 0 if the ethtool query was successful
|
||||
* -1 if the ethtool query failed
|
||||
*/
|
||||
int fcoe_link_ok(struct fc_lport *lport)
|
||||
int fcoe_link_speed_update(struct fc_lport *lport)
|
||||
{
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
struct net_device *netdev = port->fcoe->netdev;
|
||||
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
|
||||
|
||||
if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) &&
|
||||
(!dev_ethtool_get_settings(netdev, &ecmd))) {
|
||||
if (!dev_ethtool_get_settings(netdev, &ecmd)) {
|
||||
lport->link_supported_speeds &=
|
||||
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
|
||||
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
|
||||
|
@ -2169,6 +2192,23 @@ int fcoe_link_ok(struct fc_lport *lport)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_link_ok() - Check if the link is OK for a local port
|
||||
* @lport: The local port to check link on
|
||||
*
|
||||
* Returns: 0 if link is UP and OK, -1 if not
|
||||
*
|
||||
*/
|
||||
int fcoe_link_ok(struct fc_lport *lport)
|
||||
{
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
struct net_device *netdev = port->fcoe->netdev;
|
||||
|
||||
if (netif_oper_up(netdev))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_percpu_clean() - Clear all pending skbs for an local port
|
||||
* @lport: The local port whose skbs are to be cleared
|
||||
|
@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport,
|
|||
lesb->lesb_miss_fka = htonl(mdac);
|
||||
lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_set_port_id() - Callback from libfc when Port_ID is set.
|
||||
* @lport: the local port
|
||||
* @port_id: the port ID
|
||||
* @fp: the received frame, if any, that caused the port_id to be set.
|
||||
*
|
||||
* This routine handles the case where we received a FLOGI and are
|
||||
* entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi()
|
||||
* so it can set the non-mapped mode and gateway address.
|
||||
*
|
||||
* The FLOGI LS_ACC is handled by fcoe_flogi_resp().
|
||||
*/
|
||||
static void fcoe_set_port_id(struct fc_lport *lport,
|
||||
u32 port_id, struct fc_frame *fp)
|
||||
{
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
struct fcoe_interface *fcoe = port->fcoe;
|
||||
|
||||
if (fp && fc_frame_payload_op(fp) == ELS_FLOGI)
|
||||
fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ MODULE_LICENSE("GPL v2");
|
|||
#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */
|
||||
|
||||
static void fcoe_ctlr_timeout(unsigned long);
|
||||
static void fcoe_ctlr_link_work(struct work_struct *);
|
||||
static void fcoe_ctlr_timer_work(struct work_struct *);
|
||||
static void fcoe_ctlr_recv_work(struct work_struct *);
|
||||
|
||||
static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
|
||||
|
@ -116,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
|
|||
spin_lock_init(&fip->lock);
|
||||
fip->flogi_oxid = FC_XID_UNKNOWN;
|
||||
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
|
||||
INIT_WORK(&fip->link_work, fcoe_ctlr_link_work);
|
||||
INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
|
||||
INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
|
||||
skb_queue_head_init(&fip->fip_recv_list);
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
|
|||
fcoe_ctlr_reset_fcfs(fip);
|
||||
spin_unlock_bh(&fip->lock);
|
||||
del_timer_sync(&fip->timer);
|
||||
cancel_work_sync(&fip->link_work);
|
||||
cancel_work_sync(&fip->timer_work);
|
||||
}
|
||||
EXPORT_SYMBOL(fcoe_ctlr_destroy);
|
||||
|
||||
|
@ -257,14 +257,10 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
|
|||
{
|
||||
spin_lock_bh(&fip->lock);
|
||||
if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
|
||||
fip->last_link = 1;
|
||||
fip->link = 1;
|
||||
spin_unlock_bh(&fip->lock);
|
||||
fc_linkup(fip->lp);
|
||||
} else if (fip->state == FIP_ST_LINK_WAIT) {
|
||||
fip->state = fip->mode;
|
||||
fip->last_link = 1;
|
||||
fip->link = 1;
|
||||
spin_unlock_bh(&fip->lock);
|
||||
if (fip->state == FIP_ST_AUTO)
|
||||
LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
|
||||
|
@ -306,9 +302,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
|
|||
LIBFCOE_FIP_DBG(fip, "link down.\n");
|
||||
spin_lock_bh(&fip->lock);
|
||||
fcoe_ctlr_reset(fip);
|
||||
link_dropped = fip->link;
|
||||
fip->link = 0;
|
||||
fip->last_link = 0;
|
||||
link_dropped = fip->state != FIP_ST_LINK_WAIT;
|
||||
fip->state = FIP_ST_LINK_WAIT;
|
||||
spin_unlock_bh(&fip->lock);
|
||||
|
||||
|
@ -349,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
|
|||
|
||||
fcf = fip->sel_fcf;
|
||||
lp = fip->lp;
|
||||
if (!fcf || !fc_host_port_id(lp->host))
|
||||
if (!fcf || !lp->port_id)
|
||||
return;
|
||||
|
||||
len = sizeof(*kal) + ports * sizeof(*vn);
|
||||
|
@ -380,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
|
|||
vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
|
||||
vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
|
||||
memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
|
||||
hton24(vn->fd_fc_id, fc_host_port_id(lp->host));
|
||||
put_unaligned_be64(lp->wwpn, &vn->fd_wwpn);
|
||||
hton24(vn->fd_fc_id, lport->port_id);
|
||||
put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
|
||||
}
|
||||
skb_put(skb, len);
|
||||
skb->protocol = htons(ETH_P_FIP);
|
||||
|
@ -445,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
|
|||
cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
|
||||
|
||||
mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
|
||||
memset(mac, 0, sizeof(mac));
|
||||
memset(mac, 0, sizeof(*mac));
|
||||
mac->fd_desc.fip_dtype = FIP_DT_MAC;
|
||||
mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
|
||||
if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
|
||||
if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
|
||||
memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
|
||||
else if (fip->spma)
|
||||
} else if (fip_flags & FIP_FL_SPMA) {
|
||||
LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
|
||||
memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
|
||||
} else {
|
||||
LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
|
||||
/* FPMA only FLOGI must leave the MAC desc set to all 0s */
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_FIP);
|
||||
skb_reset_mac_header(skb);
|
||||
|
@ -556,7 +555,7 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
|
|||
* fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
|
||||
* @fip: The FCoE controller to free FCFs on
|
||||
*
|
||||
* Called with lock held.
|
||||
* Called with lock held and preemption disabled.
|
||||
*
|
||||
* An FCF is considered old if we have missed three advertisements.
|
||||
* That is, there have been no valid advertisement from it for three
|
||||
|
@ -573,17 +572,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
|
|||
struct fcoe_fcf *next;
|
||||
unsigned long sel_time = 0;
|
||||
unsigned long mda_time = 0;
|
||||
struct fcoe_dev_stats *stats;
|
||||
|
||||
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
|
||||
mda_time = fcf->fka_period + (fcf->fka_period >> 1);
|
||||
if ((fip->sel_fcf == fcf) &&
|
||||
(time_after(jiffies, fcf->time + mda_time))) {
|
||||
mod_timer(&fip->timer, jiffies + mda_time);
|
||||
fc_lport_get_stats(fip->lp)->MissDiscAdvCount++;
|
||||
stats = per_cpu_ptr(fip->lp->dev_stats,
|
||||
smp_processor_id());
|
||||
stats->MissDiscAdvCount++;
|
||||
printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
|
||||
"Advertisement for fab %llx count %lld\n",
|
||||
"Advertisement for fab %16.16llx count %lld\n",
|
||||
fip->lp->host->host_no, fcf->fabric_name,
|
||||
fc_lport_get_stats(fip->lp)->MissDiscAdvCount);
|
||||
stats->MissDiscAdvCount);
|
||||
}
|
||||
if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
|
||||
msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
|
||||
|
@ -593,7 +595,9 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
|
|||
WARN_ON(!fip->fcf_count);
|
||||
fip->fcf_count--;
|
||||
kfree(fcf);
|
||||
fc_lport_get_stats(fip->lp)->VLinkFailureCount++;
|
||||
stats = per_cpu_ptr(fip->lp->dev_stats,
|
||||
smp_processor_id());
|
||||
stats->VLinkFailureCount++;
|
||||
} else if (fcoe_ctlr_mtu_valid(fcf) &&
|
||||
(!sel_time || time_before(sel_time, fcf->time))) {
|
||||
sel_time = fcf->time;
|
||||
|
@ -776,7 +780,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
|
|||
mtu_valid = fcoe_ctlr_mtu_valid(fcf);
|
||||
fcf->time = jiffies;
|
||||
if (!found) {
|
||||
LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n",
|
||||
LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
|
||||
"map %x val %d\n",
|
||||
fcf->fabric_name, fcf->fc_map, mtu_valid);
|
||||
}
|
||||
|
||||
|
@ -906,9 +911,10 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
|
|||
fr_eof(fp) = FC_EOF_T;
|
||||
fr_dev(fp) = lport;
|
||||
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
stats->RxFrames++;
|
||||
stats->RxWords += skb->len / FIP_BPW;
|
||||
put_cpu();
|
||||
|
||||
fc_exch_recv(lport, fp);
|
||||
return;
|
||||
|
@ -942,9 +948,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
|
|||
u32 desc_mask;
|
||||
|
||||
LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
|
||||
if (!fcf)
|
||||
return;
|
||||
if (!fcf || !fc_host_port_id(lport->host))
|
||||
|
||||
if (!fcf || !lport->port_id)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -982,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
|
|||
if (compare_ether_addr(vp->fd_mac,
|
||||
fip->get_src_addr(lport)) == 0 &&
|
||||
get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
|
||||
ntoh24(vp->fd_fc_id) ==
|
||||
fc_host_port_id(lport->host))
|
||||
ntoh24(vp->fd_fc_id) == lport->port_id)
|
||||
desc_mask &= ~BIT(FIP_DT_VN_ID);
|
||||
break;
|
||||
default:
|
||||
|
@ -1006,7 +1010,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
|
|||
LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
|
||||
|
||||
spin_lock_bh(&fip->lock);
|
||||
fc_lport_get_stats(lport)->VLinkFailureCount++;
|
||||
per_cpu_ptr(lport->dev_stats,
|
||||
smp_processor_id())->VLinkFailureCount++;
|
||||
fcoe_ctlr_reset(fip);
|
||||
spin_unlock_bh(&fip->lock);
|
||||
|
||||
|
@ -1102,15 +1107,17 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
|
|||
struct fcoe_fcf *best = NULL;
|
||||
|
||||
list_for_each_entry(fcf, &fip->fcfs, list) {
|
||||
LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x "
|
||||
"val %d\n", fcf->fabric_name, fcf->vfid,
|
||||
LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
|
||||
"VFID %d map %x val %d\n",
|
||||
fcf->fabric_name, fcf->vfid,
|
||||
fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
|
||||
if (!fcoe_ctlr_fcf_usable(fcf)) {
|
||||
LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid "
|
||||
"%savailable\n", fcf->fabric_name,
|
||||
fcf->fc_map, (fcf->flags & FIP_FL_SOL)
|
||||
? "" : "in", (fcf->flags & FIP_FL_AVAIL)
|
||||
? "" : "un");
|
||||
LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
|
||||
"map %x %svalid %savailable\n",
|
||||
fcf->fabric_name, fcf->fc_map,
|
||||
(fcf->flags & FIP_FL_SOL) ? "" : "in",
|
||||
(fcf->flags & FIP_FL_AVAIL) ?
|
||||
"" : "un");
|
||||
continue;
|
||||
}
|
||||
if (!best) {
|
||||
|
@ -1175,7 +1182,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
|
|||
"Starting FCF discovery.\n",
|
||||
fip->lp->host->host_no);
|
||||
fip->reset_req = 1;
|
||||
schedule_work(&fip->link_work);
|
||||
schedule_work(&fip->timer_work);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1201,43 +1208,31 @@ static void fcoe_ctlr_timeout(unsigned long arg)
|
|||
mod_timer(&fip->timer, next_timer);
|
||||
}
|
||||
if (fip->send_ctlr_ka || fip->send_port_ka)
|
||||
schedule_work(&fip->link_work);
|
||||
schedule_work(&fip->timer_work);
|
||||
spin_unlock_bh(&fip->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_ctlr_link_work() - Worker thread function for link changes
|
||||
* fcoe_ctlr_timer_work() - Worker thread function for timer work
|
||||
* @work: Handle to a FCoE controller
|
||||
*
|
||||
* See if the link status has changed and if so, report it.
|
||||
*
|
||||
* This is here because fc_linkup() and fc_linkdown() must not
|
||||
* Sends keep-alives and resets which must not
|
||||
* be called from the timer directly, since they use a mutex.
|
||||
*/
|
||||
static void fcoe_ctlr_link_work(struct work_struct *work)
|
||||
static void fcoe_ctlr_timer_work(struct work_struct *work)
|
||||
{
|
||||
struct fcoe_ctlr *fip;
|
||||
struct fc_lport *vport;
|
||||
u8 *mac;
|
||||
int link;
|
||||
int last_link;
|
||||
int reset;
|
||||
|
||||
fip = container_of(work, struct fcoe_ctlr, link_work);
|
||||
fip = container_of(work, struct fcoe_ctlr, timer_work);
|
||||
spin_lock_bh(&fip->lock);
|
||||
last_link = fip->last_link;
|
||||
link = fip->link;
|
||||
fip->last_link = link;
|
||||
reset = fip->reset_req;
|
||||
fip->reset_req = 0;
|
||||
spin_unlock_bh(&fip->lock);
|
||||
|
||||
if (last_link != link) {
|
||||
if (link)
|
||||
fc_linkup(fip->lp);
|
||||
else
|
||||
fc_linkdown(fip->lp);
|
||||
} else if (reset && link)
|
||||
if (reset)
|
||||
fc_lport_reset(fip->lp);
|
||||
|
||||
if (fip->send_ctlr_ka) {
|
||||
|
@ -1334,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
|
|||
if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
|
||||
memcpy(fip->dest_addr, sa, ETH_ALEN);
|
||||
fip->map_dest = 0;
|
||||
if (fip->state == FIP_ST_NON_FIP)
|
||||
LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, "
|
||||
"using non-FIP mode\n");
|
||||
if (fip->state == FIP_ST_AUTO)
|
||||
LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
|
||||
"Setting non-FIP mode\n");
|
||||
fip->state = FIP_ST_NON_FIP;
|
||||
}
|
||||
spin_unlock_bh(&fip->lock);
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#define DRV_NAME "fnic"
|
||||
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
|
||||
#define DRV_VERSION "1.4.0.98"
|
||||
#define DRV_VERSION "1.4.0.145"
|
||||
#define PFX DRV_NAME ": "
|
||||
#define DFX DRV_NAME "%d: "
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
|||
#define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */
|
||||
#define FNIC_DFLT_QUEUE_DEPTH 32
|
||||
#define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */
|
||||
#define FNIC_MAX_CMD_LEN 16 /* Supported CDB length */
|
||||
|
||||
/*
|
||||
* Tag bits used for special requests.
|
||||
*/
|
||||
|
|
|
@ -617,7 +617,7 @@ void fnic_flush_tx(struct fnic *fnic)
|
|||
struct sk_buff *skb;
|
||||
struct fc_frame *fp;
|
||||
|
||||
while ((skb = skb_dequeue(&fnic->frame_queue))) {
|
||||
while ((skb = skb_dequeue(&fnic->tx_queue))) {
|
||||
fp = (struct fc_frame *)skb;
|
||||
fnic_send_frame(fnic, fp);
|
||||
}
|
||||
|
|
|
@ -556,7 +556,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
|
|||
}
|
||||
host->max_lun = fnic->config.luns_per_tgt;
|
||||
host->max_id = FNIC_MAX_FCP_TARGET;
|
||||
host->max_cmd_len = FNIC_MAX_CMD_LEN;
|
||||
host->max_cmd_len = FCOE_MAX_CMD_LEN;
|
||||
|
||||
fnic_get_res_counts(fnic);
|
||||
|
||||
|
|
|
@ -3842,7 +3842,7 @@ int __init option_setup(char *str)
|
|||
|
||||
TRACE2(("option_setup() str %s\n", str ? str:"NULL"));
|
||||
|
||||
while (cur && isdigit(*cur) && i <= MAXHA) {
|
||||
while (cur && isdigit(*cur) && i < MAXHA) {
|
||||
ints[i++] = simple_strtoul(cur, NULL, 0);
|
||||
if ((cur = strchr(cur, ',')) != NULL) cur++;
|
||||
}
|
||||
|
|
|
@ -19,332 +19,334 @@
|
|||
#include "wd33c93.h"
|
||||
#include "gvp11.h"
|
||||
|
||||
#include<linux/stat.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
|
||||
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
|
||||
|
||||
static irqreturn_t gvp11_intr (int irq, void *_instance)
|
||||
#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
|
||||
|
||||
static irqreturn_t gvp11_intr(int irq, void *_instance)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
|
||||
|
||||
status = DMA(instance)->CNTR;
|
||||
if (!(status & GVP11_DMAC_INT_PENDING))
|
||||
return IRQ_NONE;
|
||||
status = DMA(instance)->CNTR;
|
||||
if (!(status & GVP11_DMAC_INT_PENDING))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock_irqsave(instance->host_lock, flags);
|
||||
wd33c93_intr(instance);
|
||||
spin_unlock_irqrestore(instance->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
spin_lock_irqsave(instance->host_lock, flags);
|
||||
wd33c93_intr(instance);
|
||||
spin_unlock_irqrestore(instance->host_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int gvp11_xfer_mask = 0;
|
||||
|
||||
void gvp11_setup (char *str, int *ints)
|
||||
void gvp11_setup(char *str, int *ints)
|
||||
{
|
||||
gvp11_xfer_mask = ints[1];
|
||||
gvp11_xfer_mask = ints[1];
|
||||
}
|
||||
|
||||
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
|
||||
{
|
||||
unsigned short cntr = GVP11_DMAC_INT_ENABLE;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
int bank_mask;
|
||||
static int scsi_alloc_out_of_range = 0;
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
struct WD33C93_hostdata *hdata = shost_priv(instance);
|
||||
unsigned short cntr = GVP11_DMAC_INT_ENABLE;
|
||||
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
|
||||
int bank_mask;
|
||||
static int scsi_alloc_out_of_range = 0;
|
||||
|
||||
/* use bounce buffer if the physical address is bad */
|
||||
if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
|
||||
{
|
||||
HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
|
||||
& ~0x1ff;
|
||||
/* use bounce buffer if the physical address is bad */
|
||||
if (addr & hdata->dma_xfer_mask) {
|
||||
hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
|
||||
|
||||
if( !scsi_alloc_out_of_range ) {
|
||||
HDATA(cmd->device->host)->dma_bounce_buffer =
|
||||
kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
|
||||
HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
|
||||
if (!scsi_alloc_out_of_range) {
|
||||
hdata->dma_bounce_buffer =
|
||||
kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
|
||||
hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
|
||||
}
|
||||
|
||||
if (scsi_alloc_out_of_range ||
|
||||
!hdata->dma_bounce_buffer) {
|
||||
hdata->dma_bounce_buffer =
|
||||
amiga_chip_alloc(hdata->dma_bounce_len,
|
||||
"GVP II SCSI Bounce Buffer");
|
||||
|
||||
if (!hdata->dma_bounce_buffer) {
|
||||
hdata->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
|
||||
}
|
||||
|
||||
/* check if the address of the bounce buffer is OK */
|
||||
addr = virt_to_bus(hdata->dma_bounce_buffer);
|
||||
|
||||
if (addr & hdata->dma_xfer_mask) {
|
||||
/* fall back to Chip RAM if address out of range */
|
||||
if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
scsi_alloc_out_of_range = 1;
|
||||
} else {
|
||||
amiga_chip_free(hdata->dma_bounce_buffer);
|
||||
}
|
||||
|
||||
hdata->dma_bounce_buffer =
|
||||
amiga_chip_alloc(hdata->dma_bounce_len,
|
||||
"GVP II SCSI Bounce Buffer");
|
||||
|
||||
if (!hdata->dma_bounce_buffer) {
|
||||
hdata->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr = virt_to_bus(hdata->dma_bounce_buffer);
|
||||
hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
|
||||
cmd->SCp.this_residual);
|
||||
}
|
||||
}
|
||||
|
||||
if (scsi_alloc_out_of_range ||
|
||||
!HDATA(cmd->device->host)->dma_bounce_buffer) {
|
||||
HDATA(cmd->device->host)->dma_bounce_buffer =
|
||||
amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
|
||||
"GVP II SCSI Bounce Buffer");
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= GVP11_DMAC_DIR_WRITE;
|
||||
|
||||
if(!HDATA(cmd->device->host)->dma_bounce_buffer)
|
||||
{
|
||||
HDATA(cmd->device->host)->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
hdata->dma_dir = dir_in;
|
||||
DMA(cmd->device->host)->CNTR = cntr;
|
||||
|
||||
HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
|
||||
/* setup DMA *physical* address */
|
||||
DMA(cmd->device->host)->ACR = addr;
|
||||
|
||||
if (dir_in) {
|
||||
/* invalidate any cache */
|
||||
cache_clear(addr, cmd->SCp.this_residual);
|
||||
} else {
|
||||
/* push any dirty cache */
|
||||
cache_push(addr, cmd->SCp.this_residual);
|
||||
}
|
||||
|
||||
/* check if the address of the bounce buffer is OK */
|
||||
addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
|
||||
bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
|
||||
if (bank_mask)
|
||||
DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
|
||||
|
||||
if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
|
||||
/* fall back to Chip RAM if address out of range */
|
||||
if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
|
||||
kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
|
||||
scsi_alloc_out_of_range = 1;
|
||||
} else {
|
||||
amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
|
||||
}
|
||||
|
||||
HDATA(cmd->device->host)->dma_bounce_buffer =
|
||||
amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
|
||||
"GVP II SCSI Bounce Buffer");
|
||||
/* start DMA */
|
||||
DMA(cmd->device->host)->ST_DMA = 1;
|
||||
|
||||
if(!HDATA(cmd->device->host)->dma_bounce_buffer)
|
||||
{
|
||||
HDATA(cmd->device->host)->dma_bounce_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
|
||||
HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
|
||||
}
|
||||
|
||||
if (!dir_in) {
|
||||
/* copy to bounce buffer for a write */
|
||||
memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
|
||||
cmd->SCp.ptr, cmd->SCp.this_residual);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup dma direction */
|
||||
if (!dir_in)
|
||||
cntr |= GVP11_DMAC_DIR_WRITE;
|
||||
|
||||
HDATA(cmd->device->host)->dma_dir = dir_in;
|
||||
DMA(cmd->device->host)->CNTR = cntr;
|
||||
|
||||
/* setup DMA *physical* address */
|
||||
DMA(cmd->device->host)->ACR = addr;
|
||||
|
||||
if (dir_in)
|
||||
/* invalidate any cache */
|
||||
cache_clear (addr, cmd->SCp.this_residual);
|
||||
else
|
||||
/* push any dirty cache */
|
||||
cache_push (addr, cmd->SCp.this_residual);
|
||||
|
||||
if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
|
||||
DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
|
||||
|
||||
/* start DMA */
|
||||
DMA(cmd->device->host)->ST_DMA = 1;
|
||||
|
||||
/* return success */
|
||||
return 0;
|
||||
/* return success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
|
||||
int status)
|
||||
{
|
||||
/* stop DMA */
|
||||
DMA(instance)->SP_DMA = 1;
|
||||
/* remove write bit from CONTROL bits */
|
||||
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
|
||||
struct WD33C93_hostdata *hdata = shost_priv(instance);
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && HDATA(instance)->dma_bounce_buffer) {
|
||||
if (HDATA(instance)->dma_dir && SCpnt)
|
||||
memcpy (SCpnt->SCp.ptr,
|
||||
HDATA(instance)->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
|
||||
if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
|
||||
kfree (HDATA(instance)->dma_bounce_buffer);
|
||||
else
|
||||
amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
|
||||
|
||||
HDATA(instance)->dma_bounce_buffer = NULL;
|
||||
HDATA(instance)->dma_bounce_len = 0;
|
||||
}
|
||||
/* stop DMA */
|
||||
DMA(instance)->SP_DMA = 1;
|
||||
/* remove write bit from CONTROL bits */
|
||||
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
|
||||
|
||||
/* copy from a bounce buffer, if necessary */
|
||||
if (status && hdata->dma_bounce_buffer) {
|
||||
if (hdata->dma_dir && SCpnt)
|
||||
memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
|
||||
SCpnt->SCp.this_residual);
|
||||
|
||||
if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
|
||||
kfree(hdata->dma_bounce_buffer);
|
||||
else
|
||||
amiga_chip_free(hdata->dma_bounce_buffer);
|
||||
|
||||
hdata->dma_bounce_buffer = NULL;
|
||||
hdata->dma_bounce_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_WD33C93
|
||||
|
||||
int __init gvp11_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
static unsigned char called = 0;
|
||||
struct Scsi_Host *instance;
|
||||
unsigned long address;
|
||||
unsigned int epc;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned int default_dma_xfer_mask;
|
||||
wd33c93_regs regs;
|
||||
int num_gvp11 = 0;
|
||||
static unsigned char called = 0;
|
||||
struct Scsi_Host *instance;
|
||||
unsigned long address;
|
||||
unsigned int epc;
|
||||
struct zorro_dev *z = NULL;
|
||||
unsigned int default_dma_xfer_mask;
|
||||
struct WD33C93_hostdata *hdata;
|
||||
wd33c93_regs regs;
|
||||
int num_gvp11 = 0;
|
||||
#ifdef CHECK_WD33C93
|
||||
volatile unsigned char *sasr_3393, *scmd_3393;
|
||||
unsigned char save_sasr;
|
||||
unsigned char q, qq;
|
||||
volatile unsigned char *sasr_3393, *scmd_3393;
|
||||
unsigned char save_sasr;
|
||||
unsigned char q, qq;
|
||||
#endif
|
||||
|
||||
if (!MACH_IS_AMIGA || called)
|
||||
return 0;
|
||||
called = 1;
|
||||
if (!MACH_IS_AMIGA || called)
|
||||
return 0;
|
||||
called = 1;
|
||||
|
||||
tpnt->proc_name = "GVP11";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
tpnt->proc_name = "GVP11";
|
||||
tpnt->proc_info = &wd33c93_proc_info;
|
||||
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
/*
|
||||
* This should (hopefully) be the correct way to identify
|
||||
* all the different GVP SCSI controllers (except for the
|
||||
* SERIES I though).
|
||||
*/
|
||||
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
|
||||
/*
|
||||
* This should (hopefully) be the correct way to identify
|
||||
* all the different GVP SCSI controllers (except for the
|
||||
* SERIES I though).
|
||||
*/
|
||||
|
||||
if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_SERIES_II)
|
||||
default_dma_xfer_mask = ~0x00ffffff;
|
||||
else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_A530_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
|
||||
default_dma_xfer_mask = ~0x01ffffff;
|
||||
else if (z->id == ZORRO_PROD_GVP_A1291 ||
|
||||
z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
|
||||
default_dma_xfer_mask = ~0x07ffffff;
|
||||
else
|
||||
continue;
|
||||
if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_SERIES_II)
|
||||
default_dma_xfer_mask = ~0x00ffffff;
|
||||
else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_A530_SCSI ||
|
||||
z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
|
||||
default_dma_xfer_mask = ~0x01ffffff;
|
||||
else if (z->id == ZORRO_PROD_GVP_A1291 ||
|
||||
z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
|
||||
default_dma_xfer_mask = ~0x07ffffff;
|
||||
else
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Rumors state that some GVP ram boards use the same product
|
||||
* code as the SCSI controllers. Therefore if the board-size
|
||||
* is not 64KB we asume it is a ram board and bail out.
|
||||
*/
|
||||
if (z->resource.end-z->resource.start != 0xffff)
|
||||
/*
|
||||
* Rumors state that some GVP ram boards use the same product
|
||||
* code as the SCSI controllers. Therefore if the board-size
|
||||
* is not 64KB we asume it is a ram board and bail out.
|
||||
*/
|
||||
if (z->resource.end - z->resource.start != 0xffff)
|
||||
continue;
|
||||
|
||||
address = z->resource.start;
|
||||
if (!request_mem_region(address, 256, "wd33c93"))
|
||||
continue;
|
||||
|
||||
#ifdef CHECK_WD33C93
|
||||
|
||||
/*
|
||||
* These darn GVP boards are a problem - it can be tough to tell
|
||||
* whether or not they include a SCSI controller. This is the
|
||||
* ultimate Yet-Another-GVP-Detection-Hack in that it actually
|
||||
* probes for a WD33c93 chip: If we find one, it's extremely
|
||||
* likely that this card supports SCSI, regardless of Product_
|
||||
* Code, Board_Size, etc.
|
||||
*/
|
||||
|
||||
/* Get pointers to the presumed register locations and save contents */
|
||||
|
||||
sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
|
||||
scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
|
||||
save_sasr = *sasr_3393;
|
||||
|
||||
/* First test the AuxStatus Reg */
|
||||
|
||||
q = *sasr_3393; /* read it */
|
||||
if (q & 0x08) /* bit 3 should always be clear */
|
||||
goto release;
|
||||
*sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */
|
||||
if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
|
||||
*sasr_3393 = save_sasr; /* Oops - restore this byte */
|
||||
goto release;
|
||||
}
|
||||
if (*sasr_3393 != q) { /* should still read the same */
|
||||
*sasr_3393 = save_sasr; /* Oops - restore this byte */
|
||||
goto release;
|
||||
}
|
||||
if (*scmd_3393 != q) /* and so should the image at 0x1f */
|
||||
goto release;
|
||||
|
||||
/*
|
||||
* Ok, we probably have a wd33c93, but let's check a few other places
|
||||
* for good measure. Make sure that this works for both 'A and 'B
|
||||
* chip versions.
|
||||
*/
|
||||
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
*scmd_3393 = q;
|
||||
if (qq != q) /* should be read only */
|
||||
goto release;
|
||||
*sasr_3393 = 0x1e; /* this register is unimplemented */
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = 0x1e;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = 0x1e;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = 0x1e;
|
||||
*scmd_3393 = q;
|
||||
if (qq != q || qq != 0xff) /* should be read only, all 1's */
|
||||
goto release;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
*scmd_3393 = q;
|
||||
if (qq != (~q & 0xff)) /* should be read/write */
|
||||
goto release;
|
||||
#endif
|
||||
|
||||
instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
|
||||
if (instance == NULL)
|
||||
goto release;
|
||||
instance->base = ZTWO_VADDR(address);
|
||||
instance->irq = IRQ_AMIGA_PORTS;
|
||||
instance->unique_id = z->slotaddr;
|
||||
|
||||
hdata = shost_priv(instance);
|
||||
if (gvp11_xfer_mask)
|
||||
hdata->dma_xfer_mask = gvp11_xfer_mask;
|
||||
else
|
||||
hdata->dma_xfer_mask = default_dma_xfer_mask;
|
||||
|
||||
DMA(instance)->secret2 = 1;
|
||||
DMA(instance)->secret1 = 0;
|
||||
DMA(instance)->secret3 = 15;
|
||||
while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
|
||||
;
|
||||
DMA(instance)->CNTR = 0;
|
||||
|
||||
DMA(instance)->BANK = 0;
|
||||
|
||||
epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
|
||||
|
||||
/*
|
||||
* Check for 14MHz SCSI clock
|
||||
*/
|
||||
regs.SASR = &(DMA(instance)->SASR);
|
||||
regs.SCMD = &(DMA(instance)->SCMD);
|
||||
hdata->no_sync = 0xff;
|
||||
hdata->fast = 0;
|
||||
hdata->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(instance, regs, dma_setup, dma_stop,
|
||||
(epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
|
||||
: WD33C93_FS_12_15);
|
||||
|
||||
if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
|
||||
"GVP11 SCSI", instance))
|
||||
goto unregister;
|
||||
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
|
||||
num_gvp11++;
|
||||
continue;
|
||||
|
||||
address = z->resource.start;
|
||||
if (!request_mem_region(address, 256, "wd33c93"))
|
||||
continue;
|
||||
|
||||
#ifdef CHECK_WD33C93
|
||||
|
||||
/*
|
||||
* These darn GVP boards are a problem - it can be tough to tell
|
||||
* whether or not they include a SCSI controller. This is the
|
||||
* ultimate Yet-Another-GVP-Detection-Hack in that it actually
|
||||
* probes for a WD33c93 chip: If we find one, it's extremely
|
||||
* likely that this card supports SCSI, regardless of Product_
|
||||
* Code, Board_Size, etc.
|
||||
*/
|
||||
|
||||
/* Get pointers to the presumed register locations and save contents */
|
||||
|
||||
sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
|
||||
scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
|
||||
save_sasr = *sasr_3393;
|
||||
|
||||
/* First test the AuxStatus Reg */
|
||||
|
||||
q = *sasr_3393; /* read it */
|
||||
if (q & 0x08) /* bit 3 should always be clear */
|
||||
goto release;
|
||||
*sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */
|
||||
if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
|
||||
*sasr_3393 = save_sasr; /* Oops - restore this byte */
|
||||
goto release;
|
||||
}
|
||||
if (*sasr_3393 != q) { /* should still read the same */
|
||||
*sasr_3393 = save_sasr; /* Oops - restore this byte */
|
||||
goto release;
|
||||
}
|
||||
if (*scmd_3393 != q) /* and so should the image at 0x1f */
|
||||
goto release;
|
||||
|
||||
|
||||
/* Ok, we probably have a wd33c93, but let's check a few other places
|
||||
* for good measure. Make sure that this works for both 'A and 'B
|
||||
* chip versions.
|
||||
*/
|
||||
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = WD_SCSI_STATUS;
|
||||
*scmd_3393 = q;
|
||||
if (qq != q) /* should be read only */
|
||||
goto release;
|
||||
*sasr_3393 = 0x1e; /* this register is unimplemented */
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = 0x1e;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = 0x1e;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = 0x1e;
|
||||
*scmd_3393 = q;
|
||||
if (qq != q || qq != 0xff) /* should be read only, all 1's */
|
||||
goto release;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
q = *scmd_3393;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
*scmd_3393 = ~q;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
qq = *scmd_3393;
|
||||
*sasr_3393 = WD_TIMEOUT_PERIOD;
|
||||
*scmd_3393 = q;
|
||||
if (qq != (~q & 0xff)) /* should be read/write */
|
||||
goto release;
|
||||
#endif
|
||||
|
||||
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
|
||||
if(instance == NULL)
|
||||
goto release;
|
||||
instance->base = ZTWO_VADDR(address);
|
||||
instance->irq = IRQ_AMIGA_PORTS;
|
||||
instance->unique_id = z->slotaddr;
|
||||
|
||||
if (gvp11_xfer_mask)
|
||||
HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
|
||||
else
|
||||
HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;
|
||||
|
||||
|
||||
DMA(instance)->secret2 = 1;
|
||||
DMA(instance)->secret1 = 0;
|
||||
DMA(instance)->secret3 = 15;
|
||||
while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ;
|
||||
DMA(instance)->CNTR = 0;
|
||||
|
||||
DMA(instance)->BANK = 0;
|
||||
|
||||
epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
|
||||
|
||||
/*
|
||||
* Check for 14MHz SCSI clock
|
||||
*/
|
||||
regs.SASR = &(DMA(instance)->SASR);
|
||||
regs.SCMD = &(DMA(instance)->SCMD);
|
||||
HDATA(instance)->no_sync = 0xff;
|
||||
HDATA(instance)->fast = 0;
|
||||
HDATA(instance)->dma_mode = CTRL_DMA;
|
||||
wd33c93_init(instance, regs, dma_setup, dma_stop,
|
||||
(epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
|
||||
: WD33C93_FS_12_15);
|
||||
|
||||
if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
|
||||
instance))
|
||||
goto unregister;
|
||||
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
|
||||
num_gvp11++;
|
||||
continue;
|
||||
|
||||
unregister:
|
||||
scsi_unregister(instance);
|
||||
wd33c93_release();
|
||||
scsi_unregister(instance);
|
||||
release:
|
||||
release_mem_region(address, 256);
|
||||
}
|
||||
release_mem_region(address, 256);
|
||||
}
|
||||
|
||||
return num_gvp11;
|
||||
return num_gvp11;
|
||||
}
|
||||
|
||||
static int gvp11_bus_reset(struct scsi_cmnd *cmd)
|
||||
|
@ -389,12 +391,11 @@ static struct scsi_host_template driver_template = {
|
|||
int gvp11_release(struct Scsi_Host *instance)
|
||||
{
|
||||
#ifdef MODULE
|
||||
DMA(instance)->CNTR = 0;
|
||||
release_mem_region(ZTWO_PADDR(instance->base), 256);
|
||||
free_irq(IRQ_AMIGA_PORTS, instance);
|
||||
wd33c93_release();
|
||||
DMA(instance)->CNTR = 0;
|
||||
release_mem_region(ZTWO_PADDR(instance->base), 256);
|
||||
free_irq(IRQ_AMIGA_PORTS, instance);
|
||||
#endif
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -15,11 +15,11 @@ int gvp11_detect(struct scsi_host_template *);
|
|||
int gvp11_release(struct Scsi_Host *);
|
||||
|
||||
#ifndef CMD_PER_LUN
|
||||
#define CMD_PER_LUN 2
|
||||
#define CMD_PER_LUN 2
|
||||
#endif
|
||||
|
||||
#ifndef CAN_QUEUE
|
||||
#define CAN_QUEUE 16
|
||||
#define CAN_QUEUE 16
|
||||
#endif
|
||||
|
||||
#ifndef HOSTS_C
|
||||
|
@ -28,24 +28,24 @@ int gvp11_release(struct Scsi_Host *);
|
|||
* if the transfer address ANDed with this results in a non-zero
|
||||
* result, then we can't use DMA.
|
||||
*/
|
||||
#define GVP11_XFER_MASK (0xff000001)
|
||||
#define GVP11_XFER_MASK (0xff000001)
|
||||
|
||||
typedef struct {
|
||||
unsigned char pad1[64];
|
||||
volatile unsigned short CNTR;
|
||||
unsigned char pad2[31];
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad3;
|
||||
volatile unsigned char SCMD;
|
||||
unsigned char pad4[4];
|
||||
volatile unsigned short BANK;
|
||||
unsigned char pad5[6];
|
||||
volatile unsigned long ACR;
|
||||
volatile unsigned short secret1; /* store 0 here */
|
||||
volatile unsigned short ST_DMA;
|
||||
volatile unsigned short SP_DMA;
|
||||
volatile unsigned short secret2; /* store 1 here */
|
||||
volatile unsigned short secret3; /* store 15 here */
|
||||
unsigned char pad1[64];
|
||||
volatile unsigned short CNTR;
|
||||
unsigned char pad2[31];
|
||||
volatile unsigned char SASR;
|
||||
unsigned char pad3;
|
||||
volatile unsigned char SCMD;
|
||||
unsigned char pad4[4];
|
||||
volatile unsigned short BANK;
|
||||
unsigned char pad5[6];
|
||||
volatile unsigned long ACR;
|
||||
volatile unsigned short secret1; /* store 0 here */
|
||||
volatile unsigned short ST_DMA;
|
||||
volatile unsigned short SP_DMA;
|
||||
volatile unsigned short secret2; /* store 1 here */
|
||||
volatile unsigned short secret3; /* store 15 here */
|
||||
} gvp11_scsiregs;
|
||||
|
||||
/* bits in CNTR */
|
||||
|
|
|
@ -2708,14 +2708,6 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
|||
c->Request.CDB[8] = (size >> 8) & 0xFF;
|
||||
c->Request.CDB[9] = size & 0xFF;
|
||||
break;
|
||||
|
||||
case HPSA_READ_CAPACITY:
|
||||
c->Request.CDBLen = 10;
|
||||
c->Request.Type.Attribute = ATTR_SIMPLE;
|
||||
c->Request.Type.Direction = XFER_READ;
|
||||
c->Request.Timeout = 0;
|
||||
c->Request.CDB[0] = cmd;
|
||||
break;
|
||||
case HPSA_CACHE_FLUSH:
|
||||
c->Request.CDBLen = 12;
|
||||
c->Request.Type.Attribute = ATTR_SIMPLE;
|
||||
|
|
|
@ -152,21 +152,6 @@ struct SenseSubsystem_info {
|
|||
u8 reserved1[1108];
|
||||
};
|
||||
|
||||
#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */
|
||||
struct ReadCapdata {
|
||||
u8 total_size[4]; /* Total size in blocks */
|
||||
u8 block_size[4]; /* Size of blocks in bytes */
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* 12 byte commands not implemented in firmware yet. */
|
||||
#define HPSA_READ 0xa8
|
||||
#define HPSA_WRITE 0xaa
|
||||
#endif
|
||||
|
||||
#define HPSA_READ 0x28 /* Read(10) */
|
||||
#define HPSA_WRITE 0x2a /* Write(10) */
|
||||
|
||||
/* BMIC commands */
|
||||
#define BMIC_READ 0x26
|
||||
#define BMIC_WRITE 0x27
|
||||
|
|
|
@ -2245,7 +2245,7 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
|
|||
DECLARE_COMPLETION_ONSTACK(comp);
|
||||
int wait;
|
||||
unsigned long flags;
|
||||
signed long timeout = init_timeout * HZ;
|
||||
signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ;
|
||||
|
||||
ENTER;
|
||||
do {
|
||||
|
@ -3013,6 +3013,7 @@ static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)
|
|||
if (crq->valid & 0x80) {
|
||||
if (++async_crq->cur == async_crq->size)
|
||||
async_crq->cur = 0;
|
||||
rmb();
|
||||
} else
|
||||
crq = NULL;
|
||||
|
||||
|
@ -3035,6 +3036,7 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)
|
|||
if (crq->valid & 0x80) {
|
||||
if (++queue->cur == queue->size)
|
||||
queue->cur = 0;
|
||||
rmb();
|
||||
} else
|
||||
crq = NULL;
|
||||
|
||||
|
@ -3083,12 +3085,14 @@ static void ibmvfc_tasklet(void *data)
|
|||
while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
|
||||
ibmvfc_handle_async(async, vhost);
|
||||
async->valid = 0;
|
||||
wmb();
|
||||
}
|
||||
|
||||
/* Pull all the valid messages off the CRQ */
|
||||
while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
||||
ibmvfc_handle_crq(crq, vhost);
|
||||
crq->valid = 0;
|
||||
wmb();
|
||||
}
|
||||
|
||||
vio_enable_interrupts(vdev);
|
||||
|
@ -3096,10 +3100,12 @@ static void ibmvfc_tasklet(void *data)
|
|||
vio_disable_interrupts(vdev);
|
||||
ibmvfc_handle_async(async, vhost);
|
||||
async->valid = 0;
|
||||
wmb();
|
||||
} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
|
||||
vio_disable_interrupts(vdev);
|
||||
ibmvfc_handle_crq(crq, vhost);
|
||||
crq->valid = 0;
|
||||
wmb();
|
||||
} else
|
||||
done = 1;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT \
|
||||
(IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT)
|
||||
#define IBMVFC_INIT_TIMEOUT 120
|
||||
#define IBMVFC_ABORT_WAIT_TIMEOUT 40
|
||||
#define IBMVFC_MAX_REQUESTS_DEFAULT 100
|
||||
|
||||
#define IBMVFC_DEBUG 0
|
||||
|
|
|
@ -206,8 +206,10 @@ static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)
|
|||
}
|
||||
|
||||
static void
|
||||
iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn)
|
||||
iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
||||
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
|
||||
struct sock *sk = tcp_sw_conn->sock->sk;
|
||||
|
||||
/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
|
||||
|
@ -555,7 +557,7 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
|
|||
return;
|
||||
|
||||
sock_hold(sock->sk);
|
||||
iscsi_sw_tcp_conn_restore_callbacks(tcp_sw_conn);
|
||||
iscsi_sw_tcp_conn_restore_callbacks(conn);
|
||||
sock_put(sock->sk);
|
||||
|
||||
spin_lock_bh(&session->lock);
|
||||
|
|
|
@ -36,7 +36,6 @@ struct iscsi_sw_tcp_send {
|
|||
};
|
||||
|
||||
struct iscsi_sw_tcp_conn {
|
||||
struct iscsi_conn *iscsi_conn;
|
||||
struct socket *sock;
|
||||
|
||||
struct iscsi_sw_tcp_send out;
|
||||
|
|
|
@ -132,7 +132,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
|
|||
switch (fmt) {
|
||||
case ELS_ADDR_FMT_PORT:
|
||||
FC_DISC_DBG(disc, "Port address format for port "
|
||||
"(%6x)\n", ntoh24(pp->rscn_fid));
|
||||
"(%6.6x)\n", ntoh24(pp->rscn_fid));
|
||||
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
|
||||
if (!dp) {
|
||||
redisc = 1;
|
||||
|
@ -440,7 +440,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
|
|||
ids.port_id = ntoh24(np->fp_fid);
|
||||
ids.port_name = ntohll(np->fp_wwpn);
|
||||
|
||||
if (ids.port_id != fc_host_port_id(lport->host) &&
|
||||
if (ids.port_id != lport->port_id &&
|
||||
ids.port_name != lport->wwpn) {
|
||||
rdata = lport->tt.rport_create(lport, ids.port_id);
|
||||
if (rdata) {
|
||||
|
@ -449,7 +449,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
|
|||
} else {
|
||||
printk(KERN_WARNING "libfc: Failed to allocate "
|
||||
"memory for the newly discovered port "
|
||||
"(%6x)\n", ids.port_id);
|
||||
"(%6.6x)\n", ids.port_id);
|
||||
error = -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
|
|||
rdata->ids.port_name = port_name;
|
||||
else if (rdata->ids.port_name != port_name) {
|
||||
FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. "
|
||||
"Port-id %x wwpn %llx\n",
|
||||
"Port-id %6.6x wwpn %16.16llx\n",
|
||||
rdata->ids.port_id, port_name);
|
||||
lport->tt.rport_logoff(rdata);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type,
|
||||
fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
|
||||
return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
|
||||
|
|
|
@ -488,7 +488,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
|
|||
*/
|
||||
spin_lock_bh(&ep->ex_lock);
|
||||
ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */
|
||||
if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT))
|
||||
if (f_ctl & FC_FC_SEQ_INIT)
|
||||
ep->esb_stat &= ~ESB_ST_SEQ_INIT;
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
return error;
|
||||
|
@ -676,9 +676,10 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
|
|||
}
|
||||
memset(ep, 0, sizeof(*ep));
|
||||
|
||||
cpu = smp_processor_id();
|
||||
cpu = get_cpu();
|
||||
pool = per_cpu_ptr(mp->pool, cpu);
|
||||
spin_lock_bh(&pool->lock);
|
||||
put_cpu();
|
||||
index = pool->next_index;
|
||||
/* allocate new exch from pool */
|
||||
while (fc_exch_ptr_get(pool, index)) {
|
||||
|
@ -734,19 +735,14 @@ err:
|
|||
* EM is selected when a NULL match function pointer is encountered
|
||||
* or when a call to a match function returns true.
|
||||
*/
|
||||
static struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
|
||||
struct fc_frame *fp)
|
||||
static inline struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
|
||||
struct fc_frame *fp)
|
||||
{
|
||||
struct fc_exch_mgr_anchor *ema;
|
||||
struct fc_exch *ep;
|
||||
|
||||
list_for_each_entry(ema, &lport->ema_list, ema_list) {
|
||||
if (!ema->match || ema->match(fp)) {
|
||||
ep = fc_exch_em_alloc(lport, ema->mp);
|
||||
if (ep)
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
list_for_each_entry(ema, &lport->ema_list, ema_list)
|
||||
if (!ema->match || ema->match(fp))
|
||||
return fc_exch_em_alloc(lport, ema->mp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -920,13 +916,9 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
|
|||
* Find or create the sequence.
|
||||
*/
|
||||
if (fc_sof_is_init(fr_sof(fp))) {
|
||||
sp = fc_seq_start_next(&ep->seq);
|
||||
if (!sp) {
|
||||
reject = FC_RJT_SEQ_XS; /* exchange shortage */
|
||||
goto rel;
|
||||
}
|
||||
sp->id = fh->fh_seq_id;
|
||||
sp = &ep->seq;
|
||||
sp->ssb_stat |= SSB_ST_RESP;
|
||||
sp->id = fh->fh_seq_id;
|
||||
} else {
|
||||
sp = &ep->seq;
|
||||
if (sp->id != fh->fh_seq_id) {
|
||||
|
@ -1250,9 +1242,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
|
|||
struct fc_frame_header *fh = fc_frame_header_get(fp);
|
||||
struct fc_seq *sp = NULL;
|
||||
struct fc_exch *ep = NULL;
|
||||
enum fc_sof sof;
|
||||
enum fc_eof eof;
|
||||
u32 f_ctl;
|
||||
enum fc_pf_rjt_reason reject;
|
||||
|
||||
/* We can have the wrong fc_lport at this point with NPIV, which is a
|
||||
|
@ -1269,9 +1258,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
|
|||
if (reject == FC_RJT_NONE) {
|
||||
sp = fr_seq(fp); /* sequence will be held */
|
||||
ep = fc_seq_exch(sp);
|
||||
sof = fr_sof(fp);
|
||||
eof = fr_eof(fp);
|
||||
f_ctl = ntoh24(fh->fh_f_ctl);
|
||||
fc_seq_send_ack(sp, fp);
|
||||
|
||||
/*
|
||||
|
@ -1336,17 +1322,15 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
|
|||
goto rel;
|
||||
}
|
||||
sof = fr_sof(fp);
|
||||
sp = &ep->seq;
|
||||
if (fc_sof_is_init(sof)) {
|
||||
sp = fc_seq_start_next(&ep->seq);
|
||||
sp->id = fh->fh_seq_id;
|
||||
sp->ssb_stat |= SSB_ST_RESP;
|
||||
} else {
|
||||
sp = &ep->seq;
|
||||
if (sp->id != fh->fh_seq_id) {
|
||||
atomic_inc(&mp->stats.seq_not_found);
|
||||
goto rel;
|
||||
}
|
||||
sp->id = fh->fh_seq_id;
|
||||
} else if (sp->id != fh->fh_seq_id) {
|
||||
atomic_inc(&mp->stats.seq_not_found);
|
||||
goto rel;
|
||||
}
|
||||
|
||||
f_ctl = ntoh24(fh->fh_f_ctl);
|
||||
fr_seq(fp) = sp;
|
||||
if (f_ctl & FC_FC_SEQ_INIT)
|
||||
|
@ -1763,7 +1747,6 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
|
|||
fc_exch_done(sp);
|
||||
goto out;
|
||||
}
|
||||
sp = fc_seq_start_next(sp);
|
||||
acc = fc_frame_payload_get(fp, sizeof(*acc));
|
||||
memset(acc, 0, sizeof(*acc));
|
||||
acc->reca_cmd = ELS_LS_ACC;
|
||||
|
@ -1944,7 +1927,7 @@ static void fc_exch_rrq(struct fc_exch *ep)
|
|||
did = ep->sid;
|
||||
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did,
|
||||
fc_host_port_id(lport->host), FC_TYPE_ELS,
|
||||
lport->port_id, FC_TYPE_ELS,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
|
||||
if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep,
|
||||
|
|
|
@ -97,7 +97,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
|
|||
static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
|
||||
static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
|
||||
static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
|
||||
static void fc_timeout_error(struct fc_fcp_pkt *);
|
||||
static void fc_fcp_recovery(struct fc_fcp_pkt *);
|
||||
static void fc_fcp_timeout(unsigned long);
|
||||
static void fc_fcp_rec(struct fc_fcp_pkt *);
|
||||
static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
|
||||
|
@ -121,7 +121,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
|
|||
#define FC_DATA_UNDRUN 7
|
||||
#define FC_ERROR 8
|
||||
#define FC_HRD_ERROR 9
|
||||
#define FC_CMD_TIME_OUT 10
|
||||
#define FC_CMD_RECOVERY 10
|
||||
|
||||
/*
|
||||
* Error recovery timeout values.
|
||||
|
@ -446,9 +446,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
len = fr_len(fp) - sizeof(*fh);
|
||||
buf = fc_frame_payload_get(fp, 0);
|
||||
|
||||
/* if this I/O is ddped, update xfer len */
|
||||
fc_fcp_ddp_done(fsp);
|
||||
|
||||
/*
|
||||
* if this I/O is ddped then clear it
|
||||
* and initiate recovery since data
|
||||
* frames are expected to be placed
|
||||
* directly in that case.
|
||||
*/
|
||||
if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
|
||||
fc_fcp_ddp_done(fsp);
|
||||
goto err;
|
||||
}
|
||||
if (offset + len > fsp->data_len) {
|
||||
/* this should never happen */
|
||||
if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
|
||||
|
@ -456,8 +463,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
goto crc_err;
|
||||
FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
|
||||
"data_len %x\n", len, offset, fsp->data_len);
|
||||
fc_fcp_retry_cmd(fsp);
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
if (offset != fsp->xfer_len)
|
||||
fsp->state |= FC_SRB_DISCONTIG;
|
||||
|
@ -478,13 +484,14 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
|
||||
if (~crc != le32_to_cpu(fr_crc(fp))) {
|
||||
crc_err:
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
stats->ErrorFrames++;
|
||||
/* FIXME - per cpu count, not total count! */
|
||||
/* per cpu count, not total count, but OK for limit */
|
||||
if (stats->InvalidCRCCount++ < 5)
|
||||
printk(KERN_WARNING "libfc: CRC error on data "
|
||||
"frame for port (%6x)\n",
|
||||
fc_host_port_id(lport->host));
|
||||
"frame for port (%6.6x)\n",
|
||||
lport->port_id);
|
||||
put_cpu();
|
||||
/*
|
||||
* Assume the frame is total garbage.
|
||||
* We may have copied it over the good part
|
||||
|
@ -493,7 +500,7 @@ crc_err:
|
|||
* Otherwise, ignore it.
|
||||
*/
|
||||
if (fsp->state & FC_SRB_DISCONTIG)
|
||||
fc_fcp_retry_cmd(fsp);
|
||||
goto err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -509,6 +516,9 @@ crc_err:
|
|||
if (unlikely(fsp->state & FC_SRB_RCV_STATUS) &&
|
||||
fsp->xfer_len == fsp->data_len - fsp->scsi_resid)
|
||||
fc_fcp_complete_locked(fsp);
|
||||
return;
|
||||
err:
|
||||
fc_fcp_recovery(fsp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -834,8 +844,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
* exit here
|
||||
*/
|
||||
return;
|
||||
} else
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (flags & FCP_SNS_LEN_VAL) {
|
||||
snsl = ntohl(rp_ex->fr_sns_len);
|
||||
|
@ -885,7 +894,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
return;
|
||||
}
|
||||
fsp->status_code = FC_DATA_OVRRUN;
|
||||
FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, "
|
||||
FC_FCP_DBG(fsp, "tgt %6.6x xfer len %zx greater than expected, "
|
||||
"len %x, data len %x\n",
|
||||
fsp->rport->port_id,
|
||||
fsp->xfer_len, expected_len, fsp->data_len);
|
||||
|
@ -1100,7 +1109,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
|
|||
rpriv = rport->dd_data;
|
||||
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
|
||||
fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
|
||||
rpriv->local_port->port_id, FC_TYPE_FCP,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
|
||||
seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
|
||||
|
@ -1341,7 +1350,7 @@ static void fc_fcp_timeout(unsigned long data)
|
|||
else if (fsp->state & FC_SRB_RCV_STATUS)
|
||||
fc_fcp_complete_locked(fsp);
|
||||
else
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
|
||||
unlock:
|
||||
fc_fcp_unlock_pkt(fsp);
|
||||
|
@ -1373,7 +1382,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
|
|||
|
||||
fr_seq(fp) = fsp->seq_ptr;
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
|
||||
fc_host_port_id(rpriv->local_port->host), FC_TYPE_ELS,
|
||||
rpriv->local_port->port_id, FC_TYPE_ELS,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
|
||||
fc_fcp_rec_resp, fsp,
|
||||
|
@ -1385,7 +1394,7 @@ retry:
|
|||
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
|
||||
fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
|
||||
else
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1454,7 +1463,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
|
|||
fc_fcp_retry_cmd(fsp);
|
||||
break;
|
||||
}
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
break;
|
||||
}
|
||||
} else if (opcode == ELS_LS_ACC) {
|
||||
|
@ -1553,7 +1562,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
break;
|
||||
|
||||
default:
|
||||
FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n",
|
||||
FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n",
|
||||
fsp, fsp->rport->port_id, error);
|
||||
fsp->status_code = FC_CMD_PLOGO;
|
||||
/* fall through */
|
||||
|
@ -1563,13 +1572,13 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
* Assume REC or LS_ACC was lost.
|
||||
* The exchange manager will have aborted REC, so retry.
|
||||
*/
|
||||
FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n",
|
||||
FC_FCP_DBG(fsp, "REC fid %6.6x error error %d retry %d/%d\n",
|
||||
fsp->rport->port_id, error, fsp->recov_retry,
|
||||
FC_MAX_RECOV_RETRY);
|
||||
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
|
||||
fc_fcp_rec(fsp);
|
||||
else
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
break;
|
||||
}
|
||||
fc_fcp_unlock_pkt(fsp);
|
||||
|
@ -1578,12 +1587,12 @@ out:
|
|||
}
|
||||
|
||||
/**
|
||||
* fc_timeout_error() - Handler for fcp_pkt timeouts
|
||||
* @fsp: The FCP packt that has timed out
|
||||
* fc_fcp_recovery() - Handler for fcp_pkt recovery
|
||||
* @fsp: The FCP pkt that needs to be aborted
|
||||
*/
|
||||
static void fc_timeout_error(struct fc_fcp_pkt *fsp)
|
||||
static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)
|
||||
{
|
||||
fsp->status_code = FC_CMD_TIME_OUT;
|
||||
fsp->status_code = FC_CMD_RECOVERY;
|
||||
fsp->cdb_status = 0;
|
||||
fsp->io_status = 0;
|
||||
/*
|
||||
|
@ -1631,7 +1640,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
|
|||
srr->srr_rel_off = htonl(offset);
|
||||
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
|
||||
fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
|
||||
rpriv->local_port->port_id, FC_TYPE_FCP,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
|
||||
seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
|
||||
|
@ -1689,7 +1698,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
|
|||
break;
|
||||
case ELS_LS_RJT:
|
||||
default:
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
break;
|
||||
}
|
||||
fc_fcp_unlock_pkt(fsp);
|
||||
|
@ -1715,7 +1724,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
|
|||
if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
|
||||
fc_fcp_rec(fsp);
|
||||
else
|
||||
fc_timeout_error(fsp);
|
||||
fc_fcp_recovery(fsp);
|
||||
break;
|
||||
case -FC_EX_CLOSED: /* e.g., link failure */
|
||||
/* fall through */
|
||||
|
@ -1810,7 +1819,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
|
|||
/*
|
||||
* setup the data direction
|
||||
*/
|
||||
stats = fc_lport_get_stats(lport);
|
||||
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
|
||||
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
|
||||
fsp->req_flags = FC_SRB_READ;
|
||||
stats->InputRequests++;
|
||||
|
@ -1823,6 +1832,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
|
|||
fsp->req_flags = 0;
|
||||
stats->ControlRequests++;
|
||||
}
|
||||
put_cpu();
|
||||
|
||||
fsp->tgt_flags = rpriv->flags;
|
||||
|
||||
|
@ -1907,6 +1917,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
|
|||
}
|
||||
break;
|
||||
case FC_ERROR:
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
|
||||
"due to FC_ERROR\n");
|
||||
sc_cmd->result = DID_ERROR << 16;
|
||||
break;
|
||||
case FC_DATA_UNDRUN:
|
||||
|
@ -1915,12 +1927,19 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
|
|||
* scsi status is good but transport level
|
||||
* underrun.
|
||||
*/
|
||||
sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ?
|
||||
DID_OK : DID_ERROR) << 16;
|
||||
if (fsp->state & FC_SRB_RCV_STATUS) {
|
||||
sc_cmd->result = DID_OK << 16;
|
||||
} else {
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml"
|
||||
" due to FC_DATA_UNDRUN (trans)\n");
|
||||
sc_cmd->result = DID_ERROR << 16;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* scsi got underrun, this is an error
|
||||
*/
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
|
||||
"due to FC_DATA_UNDRUN (scsi)\n");
|
||||
CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;
|
||||
sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
|
||||
}
|
||||
|
@ -1929,12 +1948,16 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
|
|||
/*
|
||||
* overrun is an error
|
||||
*/
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
|
||||
"due to FC_DATA_OVRRUN\n");
|
||||
sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
|
||||
break;
|
||||
case FC_CMD_ABORTED:
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
|
||||
"due to FC_CMD_ABORTED\n");
|
||||
sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
|
||||
break;
|
||||
case FC_CMD_TIME_OUT:
|
||||
case FC_CMD_RECOVERY:
|
||||
sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
|
||||
break;
|
||||
case FC_CMD_RESET:
|
||||
|
@ -1944,6 +1967,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
|
|||
sc_cmd->result = (DID_NO_CONNECT << 16);
|
||||
break;
|
||||
default:
|
||||
FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
|
||||
"due to unknown error\n");
|
||||
sc_cmd->result = (DID_ERROR << 16);
|
||||
break;
|
||||
}
|
||||
|
@ -2028,7 +2053,7 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
|
|||
if (lport->state != LPORT_ST_READY)
|
||||
return rc;
|
||||
|
||||
FC_SCSI_DBG(lport, "Resetting rport (%6x)\n", rport->port_id);
|
||||
FC_SCSI_DBG(lport, "Resetting rport (%6.6x)\n", rport->port_id);
|
||||
|
||||
fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO);
|
||||
if (fsp == NULL) {
|
||||
|
@ -2076,12 +2101,12 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
|
|||
|
||||
if (fc_fcp_lport_queue_ready(lport)) {
|
||||
shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded "
|
||||
"on port (%6x)\n", fc_host_port_id(lport->host));
|
||||
"on port (%6.6x)\n", lport->port_id);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
shost_printk(KERN_INFO, shost, "libfc: Host reset failed, "
|
||||
"port (%6x) is not ready.\n",
|
||||
fc_host_port_id(lport->host));
|
||||
"port (%6.6x) is not ready.\n",
|
||||
lport->port_id);
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
@ -2166,7 +2191,7 @@ void fc_fcp_destroy(struct fc_lport *lport)
|
|||
|
||||
if (!list_empty(&si->scsi_pkt_queue))
|
||||
printk(KERN_ERR "libfc: Leaked SCSI packets when destroying "
|
||||
"port (%6x)\n", fc_host_port_id(lport->host));
|
||||
"port (%6.6x)\n", lport->port_id);
|
||||
|
||||
mempool_destroy(si->scsi_pkt_pool);
|
||||
kfree(si);
|
||||
|
|
|
@ -45,9 +45,9 @@ extern unsigned int fc_debug_logging;
|
|||
|
||||
#define FC_LPORT_DBG(lport, fmt, args...) \
|
||||
FC_CHECK_LOGGING(FC_LPORT_LOGGING, \
|
||||
printk(KERN_INFO "host%u: lport %6x: " fmt, \
|
||||
printk(KERN_INFO "host%u: lport %6.6x: " fmt, \
|
||||
(lport)->host->host_no, \
|
||||
fc_host_port_id((lport)->host), ##args))
|
||||
(lport)->port_id, ##args))
|
||||
|
||||
#define FC_DISC_DBG(disc, fmt, args...) \
|
||||
FC_CHECK_LOGGING(FC_DISC_LOGGING, \
|
||||
|
@ -57,7 +57,7 @@ extern unsigned int fc_debug_logging;
|
|||
|
||||
#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \
|
||||
FC_CHECK_LOGGING(FC_RPORT_LOGGING, \
|
||||
printk(KERN_INFO "host%u: rport %6x: " fmt, \
|
||||
printk(KERN_INFO "host%u: rport %6.6x: " fmt, \
|
||||
(lport)->host->host_no, \
|
||||
(port_id), ##args))
|
||||
|
||||
|
@ -66,7 +66,7 @@ extern unsigned int fc_debug_logging;
|
|||
|
||||
#define FC_FCP_DBG(pkt, fmt, args...) \
|
||||
FC_CHECK_LOGGING(FC_FCP_LOGGING, \
|
||||
printk(KERN_INFO "host%u: fcp: %6x: " fmt, \
|
||||
printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \
|
||||
(pkt)->lp->host->host_no, \
|
||||
pkt->rport->port_id, ##args))
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
|
|||
struct fc_rport_priv *rdata,
|
||||
enum fc_rport_event event)
|
||||
{
|
||||
FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
|
||||
FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,
|
||||
rdata->ids.port_id);
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
|
@ -183,7 +183,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
|
|||
fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
|
||||
} else {
|
||||
FC_LPORT_DBG(lport, "Received an READY event "
|
||||
"on port (%6x) for the directory "
|
||||
"on port (%6.6x) for the directory "
|
||||
"server, but the lport is not "
|
||||
"in the DNS state, it's in the "
|
||||
"%d state", rdata->ids.port_id,
|
||||
|
@ -228,9 +228,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
|
|||
u64 remote_wwnn)
|
||||
{
|
||||
mutex_lock(&lport->disc.disc_mutex);
|
||||
if (lport->ptp_rdata)
|
||||
if (lport->ptp_rdata) {
|
||||
lport->tt.rport_logoff(lport->ptp_rdata);
|
||||
kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
|
||||
}
|
||||
lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
|
||||
kref_get(&lport->ptp_rdata->kref);
|
||||
lport->ptp_rdata->ids.port_name = remote_wwpn;
|
||||
lport->ptp_rdata->ids.node_name = remote_wwnn;
|
||||
mutex_unlock(&lport->disc.disc_mutex);
|
||||
|
@ -240,17 +243,6 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
|
|||
fc_lport_enter_ready(lport);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_get_host_port_type() - Return the port type of the given Scsi_Host
|
||||
* @shost: The SCSI host whose port type is to be determined
|
||||
*/
|
||||
void fc_get_host_port_type(struct Scsi_Host *shost)
|
||||
{
|
||||
/* TODO - currently just NPORT */
|
||||
fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_get_host_port_type);
|
||||
|
||||
/**
|
||||
* fc_get_host_port_state() - Return the port state of the given Scsi_Host
|
||||
* @shost: The SCSI host whose port state is to be determined
|
||||
|
@ -572,8 +564,8 @@ void __fc_linkup(struct fc_lport *lport)
|
|||
*/
|
||||
void fc_linkup(struct fc_lport *lport)
|
||||
{
|
||||
printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n",
|
||||
lport->host->host_no, fc_host_port_id(lport->host));
|
||||
printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n",
|
||||
lport->host->host_no, lport->port_id);
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
__fc_linkup(lport);
|
||||
|
@ -602,8 +594,8 @@ void __fc_linkdown(struct fc_lport *lport)
|
|||
*/
|
||||
void fc_linkdown(struct fc_lport *lport)
|
||||
{
|
||||
printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n",
|
||||
lport->host->host_no, fc_host_port_id(lport->host));
|
||||
printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n",
|
||||
lport->host->host_no, lport->port_id);
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
__fc_linkdown(lport);
|
||||
|
@ -704,8 +696,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
|
|||
break;
|
||||
case DISC_EV_FAILED:
|
||||
printk(KERN_ERR "host%d: libfc: "
|
||||
"Discovery failed for port (%6x)\n",
|
||||
lport->host->host_no, fc_host_port_id(lport->host));
|
||||
"Discovery failed for port (%6.6x)\n",
|
||||
lport->host->host_no, lport->port_id);
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
fc_lport_enter_reset(lport);
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
|
@ -750,10 +742,14 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
|
|||
struct fc_frame *fp)
|
||||
{
|
||||
if (port_id)
|
||||
printk(KERN_INFO "host%d: Assigned Port ID %6x\n",
|
||||
printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",
|
||||
lport->host->host_no, port_id);
|
||||
|
||||
lport->port_id = port_id;
|
||||
|
||||
/* Update the fc_host */
|
||||
fc_host_port_id(lport->host) = port_id;
|
||||
|
||||
if (lport->tt.lport_set_port_id)
|
||||
lport->tt.lport_set_port_id(lport, port_id, fp);
|
||||
}
|
||||
|
@ -797,11 +793,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
|
|||
remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
|
||||
if (remote_wwpn == lport->wwpn) {
|
||||
printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "
|
||||
"with same WWPN %llx\n",
|
||||
"with same WWPN %16.16llx\n",
|
||||
lport->host->host_no, remote_wwpn);
|
||||
goto out;
|
||||
}
|
||||
FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
|
||||
FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);
|
||||
|
||||
/*
|
||||
* XXX what is the right thing to do for FIDs?
|
||||
|
@ -832,7 +828,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
|
|||
*/
|
||||
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
|
||||
ep = fc_seq_exch(sp);
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
|
||||
FC_TYPE_ELS, f_ctl, 0);
|
||||
lport->tt.seq_send(lport, sp, fp);
|
||||
|
||||
|
@ -947,14 +943,18 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
|
|||
if (lport->dns_rdata)
|
||||
lport->tt.rport_logoff(lport->dns_rdata);
|
||||
|
||||
lport->ptp_rdata = NULL;
|
||||
if (lport->ptp_rdata) {
|
||||
lport->tt.rport_logoff(lport->ptp_rdata);
|
||||
kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
|
||||
lport->ptp_rdata = NULL;
|
||||
}
|
||||
|
||||
lport->tt.disc_stop(lport);
|
||||
|
||||
lport->tt.exch_mgr_reset(lport, 0, 0);
|
||||
fc_host_fabric_name(lport->host) = 0;
|
||||
|
||||
if (fc_host_port_id(lport->host))
|
||||
if (lport->port_id)
|
||||
fc_lport_set_port_id(lport, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -1492,7 +1492,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
|
|||
lport->r_a_tov = 2 * e_d_tov;
|
||||
fc_lport_set_port_id(lport, did, fp);
|
||||
printk(KERN_INFO "host%d: libfc: "
|
||||
"Port (%6x) entered "
|
||||
"Port (%6.6x) entered "
|
||||
"point-to-point mode\n",
|
||||
lport->host->host_no, did);
|
||||
fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
|
||||
|
@ -1699,7 +1699,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
|
|||
fh = fc_frame_header_get(fp);
|
||||
fh->fh_r_ctl = FC_RCTL_ELS_REQ;
|
||||
hton24(fh->fh_d_id, did);
|
||||
hton24(fh->fh_s_id, fc_host_port_id(lport->host));
|
||||
hton24(fh->fh_s_id, lport->port_id);
|
||||
fh->fh_type = FC_TYPE_ELS;
|
||||
hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
|
||||
FC_FC_END_SEQ | FC_FC_SEQ_INIT);
|
||||
|
@ -1759,7 +1759,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
|
|||
fh = fc_frame_header_get(fp);
|
||||
fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;
|
||||
hton24(fh->fh_d_id, did);
|
||||
hton24(fh->fh_s_id, fc_host_port_id(lport->host));
|
||||
hton24(fh->fh_s_id, lport->port_id);
|
||||
fh->fh_type = FC_TYPE_CT;
|
||||
hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
|
||||
FC_FC_END_SEQ | FC_FC_SEQ_INIT);
|
||||
|
|
|
@ -69,12 +69,15 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
|
|||
struct fc_lport *lport = NULL;
|
||||
struct fc_lport *vn_port;
|
||||
|
||||
if (fc_host_port_id(n_port->host) == port_id)
|
||||
if (n_port->port_id == port_id)
|
||||
return n_port;
|
||||
|
||||
if (port_id == FC_FID_FLOGI)
|
||||
return n_port; /* for point-to-point */
|
||||
|
||||
mutex_lock(&n_port->lp_mutex);
|
||||
list_for_each_entry(vn_port, &n_port->vports, list) {
|
||||
if (fc_host_port_id(vn_port->host) == port_id) {
|
||||
if (vn_port->port_id == port_id) {
|
||||
lport = vn_port;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
|
|||
struct fc_els_spp *spp; /* response spp */
|
||||
unsigned int len;
|
||||
unsigned int plen;
|
||||
enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
|
||||
enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
|
||||
enum fc_els_spp_resp resp;
|
||||
struct fc_seq_els_data rjt_data;
|
||||
u32 f_ctl;
|
||||
u32 fcp_parm;
|
||||
u32 roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
rjt_data.fp = NULL;
|
||||
|
||||
rjt_data.fp = NULL;
|
||||
fh = fc_frame_header_get(rx_fp);
|
||||
|
||||
FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
|
||||
fc_rport_state(rdata));
|
||||
|
||||
switch (rdata->rp_state) {
|
||||
case RPORT_ST_PRLI:
|
||||
case RPORT_ST_RTV:
|
||||
case RPORT_ST_READY:
|
||||
case RPORT_ST_ADISC:
|
||||
reason = ELS_RJT_NONE;
|
||||
break;
|
||||
default:
|
||||
fc_frame_free(rx_fp);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
len = fr_len(rx_fp) - sizeof(*fh);
|
||||
pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
|
||||
if (pp == NULL) {
|
||||
reason = ELS_RJT_PROT;
|
||||
explan = ELS_EXPL_INV_LEN;
|
||||
} else {
|
||||
plen = ntohs(pp->prli.prli_len);
|
||||
if ((plen % 4) != 0 || plen > len) {
|
||||
reason = ELS_RJT_PROT;
|
||||
explan = ELS_EXPL_INV_LEN;
|
||||
} else if (plen < len) {
|
||||
len = plen;
|
||||
}
|
||||
plen = pp->prli.prli_spp_len;
|
||||
if ((plen % 4) != 0 || plen < sizeof(*spp) ||
|
||||
plen > len || len < sizeof(*pp)) {
|
||||
reason = ELS_RJT_PROT;
|
||||
explan = ELS_EXPL_INV_LEN;
|
||||
}
|
||||
rspp = &pp->spp;
|
||||
if (!pp)
|
||||
goto reject_len;
|
||||
plen = ntohs(pp->prli.prli_len);
|
||||
if ((plen % 4) != 0 || plen > len || plen < 16)
|
||||
goto reject_len;
|
||||
if (plen < len)
|
||||
len = plen;
|
||||
plen = pp->prli.prli_spp_len;
|
||||
if ((plen % 4) != 0 || plen < sizeof(*spp) ||
|
||||
plen > len || len < sizeof(*pp) || plen < 12)
|
||||
goto reject_len;
|
||||
rspp = &pp->spp;
|
||||
|
||||
fp = fc_frame_alloc(lport, len);
|
||||
if (!fp) {
|
||||
rjt_data.reason = ELS_RJT_UNAB;
|
||||
rjt_data.explan = ELS_EXPL_INSUF_RES;
|
||||
goto reject;
|
||||
}
|
||||
if (reason != ELS_RJT_NONE ||
|
||||
(fp = fc_frame_alloc(lport, len)) == NULL) {
|
||||
rjt_data.reason = reason;
|
||||
rjt_data.explan = explan;
|
||||
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
|
||||
} else {
|
||||
sp = lport->tt.seq_start_next(sp);
|
||||
WARN_ON(!sp);
|
||||
pp = fc_frame_payload_get(fp, len);
|
||||
WARN_ON(!pp);
|
||||
memset(pp, 0, len);
|
||||
pp->prli.prli_cmd = ELS_LS_ACC;
|
||||
pp->prli.prli_spp_len = plen;
|
||||
pp->prli.prli_len = htons(len);
|
||||
len -= sizeof(struct fc_els_prli);
|
||||
sp = lport->tt.seq_start_next(sp);
|
||||
WARN_ON(!sp);
|
||||
pp = fc_frame_payload_get(fp, len);
|
||||
WARN_ON(!pp);
|
||||
memset(pp, 0, len);
|
||||
pp->prli.prli_cmd = ELS_LS_ACC;
|
||||
pp->prli.prli_spp_len = plen;
|
||||
pp->prli.prli_len = htons(len);
|
||||
len -= sizeof(struct fc_els_prli);
|
||||
|
||||
/* reinitialize remote port roles */
|
||||
rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
/* reinitialize remote port roles */
|
||||
rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
|
||||
/*
|
||||
* Go through all the service parameter pages and build
|
||||
* response. If plen indicates longer SPP than standard,
|
||||
* use that. The entire response has been pre-cleared above.
|
||||
*/
|
||||
spp = &pp->spp;
|
||||
while (len >= plen) {
|
||||
spp->spp_type = rspp->spp_type;
|
||||
spp->spp_type_ext = rspp->spp_type_ext;
|
||||
spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
||||
resp = FC_SPP_RESP_ACK;
|
||||
if (rspp->spp_flags & FC_SPP_RPA_VAL)
|
||||
resp = FC_SPP_RESP_NO_PA;
|
||||
switch (rspp->spp_type) {
|
||||
case 0: /* common to all FC-4 types */
|
||||
break;
|
||||
case FC_TYPE_FCP:
|
||||
fcp_parm = ntohl(rspp->spp_params);
|
||||
if (fcp_parm & FCP_SPPF_RETRY)
|
||||
rdata->flags |= FC_RP_FLAGS_RETRY;
|
||||
rdata->supported_classes = FC_COS_CLASS3;
|
||||
if (fcp_parm & FCP_SPPF_INIT_FCN)
|
||||
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
if (fcp_parm & FCP_SPPF_TARG_FCN)
|
||||
roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
rdata->ids.roles = roles;
|
||||
/*
|
||||
* Go through all the service parameter pages and build
|
||||
* response. If plen indicates longer SPP than standard,
|
||||
* use that. The entire response has been pre-cleared above.
|
||||
*/
|
||||
spp = &pp->spp;
|
||||
while (len >= plen) {
|
||||
spp->spp_type = rspp->spp_type;
|
||||
spp->spp_type_ext = rspp->spp_type_ext;
|
||||
spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
||||
resp = FC_SPP_RESP_ACK;
|
||||
|
||||
spp->spp_params =
|
||||
htonl(lport->service_params);
|
||||
break;
|
||||
default:
|
||||
resp = FC_SPP_RESP_INVL;
|
||||
break;
|
||||
}
|
||||
spp->spp_flags |= resp;
|
||||
len -= plen;
|
||||
rspp = (struct fc_els_spp *)((char *)rspp + plen);
|
||||
spp = (struct fc_els_spp *)((char *)spp + plen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send LS_ACC. If this fails, the originator should retry.
|
||||
*/
|
||||
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
|
||||
f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
|
||||
ep = fc_seq_exch(sp);
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
|
||||
FC_TYPE_ELS, f_ctl, 0);
|
||||
lport->tt.seq_send(lport, sp, fp);
|
||||
|
||||
/*
|
||||
* Get lock and re-check state.
|
||||
*/
|
||||
switch (rdata->rp_state) {
|
||||
case RPORT_ST_PRLI:
|
||||
fc_rport_enter_ready(rdata);
|
||||
switch (rspp->spp_type) {
|
||||
case 0: /* common to all FC-4 types */
|
||||
break;
|
||||
case RPORT_ST_READY:
|
||||
case RPORT_ST_ADISC:
|
||||
case FC_TYPE_FCP:
|
||||
fcp_parm = ntohl(rspp->spp_params);
|
||||
if (fcp_parm & FCP_SPPF_RETRY)
|
||||
rdata->flags |= FC_RP_FLAGS_RETRY;
|
||||
rdata->supported_classes = FC_COS_CLASS3;
|
||||
if (fcp_parm & FCP_SPPF_INIT_FCN)
|
||||
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
if (fcp_parm & FCP_SPPF_TARG_FCN)
|
||||
roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
rdata->ids.roles = roles;
|
||||
|
||||
spp->spp_params = htonl(lport->service_params);
|
||||
break;
|
||||
default:
|
||||
resp = FC_SPP_RESP_INVL;
|
||||
break;
|
||||
}
|
||||
spp->spp_flags |= resp;
|
||||
len -= plen;
|
||||
rspp = (struct fc_els_spp *)((char *)rspp + plen);
|
||||
spp = (struct fc_els_spp *)((char *)spp + plen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send LS_ACC. If this fails, the originator should retry.
|
||||
*/
|
||||
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
|
||||
f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
|
||||
ep = fc_seq_exch(sp);
|
||||
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
|
||||
FC_TYPE_ELS, f_ctl, 0);
|
||||
lport->tt.seq_send(lport, sp, fp);
|
||||
|
||||
switch (rdata->rp_state) {
|
||||
case RPORT_ST_PRLI:
|
||||
fc_rport_enter_ready(rdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto drop;
|
||||
|
||||
reject_len:
|
||||
rjt_data.reason = ELS_RJT_PROT;
|
||||
rjt_data.explan = ELS_EXPL_INV_LEN;
|
||||
reject:
|
||||
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
|
||||
drop:
|
||||
fc_frame_free(rx_fp);
|
||||
}
|
||||
|
||||
|
|
|
@ -421,7 +421,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
|
|||
struct iscsi_conn *conn = tcp_conn->iscsi_conn;
|
||||
struct hash_desc *rx_hash = NULL;
|
||||
|
||||
if (conn->datadgst_en &
|
||||
if (conn->datadgst_en &&
|
||||
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
|
||||
rx_hash = tcp_conn->rx_hash;
|
||||
|
||||
|
|
|
@ -395,12 +395,13 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev,
|
|||
void sas_ata_task_abort(struct sas_task *task)
|
||||
{
|
||||
struct ata_queued_cmd *qc = task->uldd_task;
|
||||
struct request_queue *q = qc->scsicmd->device->request_queue;
|
||||
struct completion *waiting;
|
||||
unsigned long flags;
|
||||
|
||||
/* Bounce SCSI-initiated commands to the SCSI EH */
|
||||
if (qc->scsicmd) {
|
||||
struct request_queue *q = qc->scsicmd->device->request_queue;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
blk_abort_request(qc->scsicmd->request);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
|
|
@ -1030,8 +1030,6 @@ int __sas_task_abort(struct sas_task *task)
|
|||
void sas_task_abort(struct sas_task *task)
|
||||
{
|
||||
struct scsi_cmnd *sc = task->uldd_task;
|
||||
struct request_queue *q = sc->device->request_queue;
|
||||
unsigned long flags;
|
||||
|
||||
/* Escape for libsas internal commands */
|
||||
if (!sc) {
|
||||
|
@ -1043,13 +1041,15 @@ void sas_task_abort(struct sas_task *task)
|
|||
|
||||
if (dev_is_sata(task->dev)) {
|
||||
sas_ata_task_abort(task);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
struct request_queue *q = sc->device->request_queue;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
blk_abort_request(sc->request);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
scsi_schedule_eh(sc->device->host);
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
blk_abort_request(sc->request);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
scsi_schedule_eh(sc->device->host);
|
||||
}
|
||||
}
|
||||
|
||||
int sas_slave_alloc(struct scsi_device *scsi_dev)
|
||||
|
|
|
@ -310,7 +310,9 @@ struct lpfc_vport {
|
|||
#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
|
||||
#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
|
||||
#define FC_FABRIC 0x100 /* We are fabric attached */
|
||||
#define FC_VPORT_LOGO_RCVD 0x200 /* LOGO received on vport */
|
||||
#define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */
|
||||
#define FC_LOGO_RCVD_DID_CHNG 0x800 /* FDISC on phys port detect DID chng*/
|
||||
#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
|
||||
#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
|
||||
#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
|
||||
|
@ -554,6 +556,7 @@ struct lpfc_hba {
|
|||
struct lpfc_dmabuf slim2p;
|
||||
|
||||
MAILBOX_t *mbox;
|
||||
uint32_t *mbox_ext;
|
||||
uint32_t *inb_ha_copy;
|
||||
uint32_t *inb_counter;
|
||||
uint32_t inb_last_counter;
|
||||
|
@ -622,6 +625,7 @@ struct lpfc_hba {
|
|||
uint32_t cfg_enable_hba_reset;
|
||||
uint32_t cfg_enable_hba_heartbeat;
|
||||
uint32_t cfg_enable_bg;
|
||||
uint32_t cfg_hostmem_hgp;
|
||||
uint32_t cfg_log_verbose;
|
||||
uint32_t cfg_aer_support;
|
||||
uint32_t cfg_suppress_link_up;
|
||||
|
|
|
@ -869,6 +869,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
|
|||
LPFC_MBOXQ_t *pmboxq;
|
||||
MAILBOX_t *pmb;
|
||||
int rc = 0;
|
||||
uint32_t max_vpi;
|
||||
|
||||
/*
|
||||
* prevent udev from issuing mailbox commands until the port is
|
||||
|
@ -916,11 +917,17 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
|
|||
if (axri)
|
||||
*axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -
|
||||
phba->sli4_hba.max_cfg_param.xri_used;
|
||||
|
||||
/* Account for differences with SLI-3. Get vpi count from
|
||||
* mailbox data and subtract one for max vpi value.
|
||||
*/
|
||||
max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ?
|
||||
(bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0;
|
||||
|
||||
if (mvpi)
|
||||
*mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
|
||||
*mvpi = max_vpi;
|
||||
if (avpi)
|
||||
*avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) -
|
||||
phba->sli4_hba.max_cfg_param.vpi_used;
|
||||
*avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used;
|
||||
} else {
|
||||
if (mrpi)
|
||||
*mrpi = pmb->un.varRdConfig.max_rpi;
|
||||
|
@ -1925,13 +1932,12 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
|
|||
" 2 - select SLI-2 even on SLI-3 capable HBAs,"
|
||||
" 3 - select SLI-3");
|
||||
|
||||
int lpfc_enable_npiv = 0;
|
||||
int lpfc_enable_npiv = 1;
|
||||
module_param(lpfc_enable_npiv, int, 0);
|
||||
MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
|
||||
lpfc_param_show(enable_npiv);
|
||||
lpfc_param_init(enable_npiv, 0, 0, 1);
|
||||
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
|
||||
lpfc_enable_npiv_show, NULL);
|
||||
lpfc_param_init(enable_npiv, 1, 0, 1);
|
||||
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
|
||||
|
||||
/*
|
||||
# lpfc_suppress_link_up: Bring link up at initialization
|
||||
|
|
|
@ -79,6 +79,12 @@ struct lpfc_bsg_iocb {
|
|||
struct lpfc_bsg_mbox {
|
||||
LPFC_MBOXQ_t *pmboxq;
|
||||
MAILBOX_t *mb;
|
||||
struct lpfc_dmabuf *rxbmp; /* for BIU diags */
|
||||
struct lpfc_dmabufext *dmp; /* for BIU diags */
|
||||
uint8_t *ext; /* extended mailbox data */
|
||||
uint32_t mbOffset; /* from app */
|
||||
uint32_t inExtWLen; /* from app */
|
||||
uint32_t outExtWLen; /* from app */
|
||||
|
||||
/* job waiting for this mbox command to finish */
|
||||
struct fc_bsg_job *set_job;
|
||||
|
@ -1708,21 +1714,26 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
|
|||
dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (dmabuf) {
|
||||
dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
|
||||
INIT_LIST_HEAD(&dmabuf->list);
|
||||
bpl = (struct ulp_bde64 *) dmabuf->virt;
|
||||
memset(bpl, 0, sizeof(*bpl));
|
||||
ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
|
||||
bpl->addrHigh =
|
||||
le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl)));
|
||||
bpl->addrLow =
|
||||
le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl)));
|
||||
bpl->tus.f.bdeFlags = 0;
|
||||
bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
|
||||
bpl->tus.w = le32_to_cpu(bpl->tus.w);
|
||||
if (dmabuf->virt) {
|
||||
INIT_LIST_HEAD(&dmabuf->list);
|
||||
bpl = (struct ulp_bde64 *) dmabuf->virt;
|
||||
memset(bpl, 0, sizeof(*bpl));
|
||||
ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
|
||||
bpl->addrHigh =
|
||||
le32_to_cpu(putPaddrHigh(dmabuf->phys +
|
||||
sizeof(*bpl)));
|
||||
bpl->addrLow =
|
||||
le32_to_cpu(putPaddrLow(dmabuf->phys +
|
||||
sizeof(*bpl)));
|
||||
bpl->tus.f.bdeFlags = 0;
|
||||
bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
|
||||
bpl->tus.w = le32_to_cpu(bpl->tus.w);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmdiocbq == NULL || rspiocbq == NULL ||
|
||||
dmabuf == NULL || bpl == NULL || ctreq == NULL) {
|
||||
dmabuf == NULL || bpl == NULL || ctreq == NULL ||
|
||||
dmabuf->virt == NULL) {
|
||||
ret_val = ENOMEM;
|
||||
goto err_get_xri_exit;
|
||||
}
|
||||
|
@ -1918,9 +1929,11 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
|
|||
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (rxbmp != NULL) {
|
||||
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
|
||||
if (rxbmp->virt) {
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
|
||||
|
@ -2174,14 +2187,16 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
|
|||
|
||||
if (txbmp) {
|
||||
txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
|
||||
INIT_LIST_HEAD(&txbmp->list);
|
||||
txbpl = (struct ulp_bde64 *) txbmp->virt;
|
||||
if (txbpl)
|
||||
if (txbmp->virt) {
|
||||
INIT_LIST_HEAD(&txbmp->list);
|
||||
txbpl = (struct ulp_bde64 *) txbmp->virt;
|
||||
txbuffer = diag_cmd_data_alloc(phba,
|
||||
txbpl, full_size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) {
|
||||
if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
|
||||
!txbmp->virt) {
|
||||
rc = -ENOMEM;
|
||||
goto err_loopback_test_exit;
|
||||
}
|
||||
|
@ -2377,35 +2392,90 @@ void
|
|||
lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
|
||||
{
|
||||
struct bsg_job_data *dd_data;
|
||||
MAILBOX_t *pmb;
|
||||
MAILBOX_t *mb;
|
||||
struct fc_bsg_job *job;
|
||||
uint32_t size;
|
||||
unsigned long flags;
|
||||
uint8_t *to;
|
||||
uint8_t *from;
|
||||
|
||||
spin_lock_irqsave(&phba->ct_ev_lock, flags);
|
||||
dd_data = pmboxq->context1;
|
||||
/* job already timed out? */
|
||||
if (!dd_data) {
|
||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
pmb = &dd_data->context_un.mbox.pmboxq->u.mb;
|
||||
mb = dd_data->context_un.mbox.mb;
|
||||
/* build the outgoing buffer to do an sg copy
|
||||
* the format is the response mailbox followed by any extended
|
||||
* mailbox data
|
||||
*/
|
||||
from = (uint8_t *)&pmboxq->u.mb;
|
||||
to = (uint8_t *)dd_data->context_un.mbox.mb;
|
||||
memcpy(to, from, sizeof(MAILBOX_t));
|
||||
if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) {
|
||||
/* copy the extended data if any, count is in words */
|
||||
if (dd_data->context_un.mbox.outExtWLen) {
|
||||
from = (uint8_t *)dd_data->context_un.mbox.ext;
|
||||
to += sizeof(MAILBOX_t);
|
||||
size = dd_data->context_un.mbox.outExtWLen *
|
||||
sizeof(uint32_t);
|
||||
memcpy(to, from, size);
|
||||
} else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) {
|
||||
from = (uint8_t *)dd_data->context_un.mbox.
|
||||
dmp->dma.virt;
|
||||
to += sizeof(MAILBOX_t);
|
||||
size = dd_data->context_un.mbox.dmp->size;
|
||||
memcpy(to, from, size);
|
||||
} else if ((phba->sli_rev == LPFC_SLI_REV4) &&
|
||||
(pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) {
|
||||
from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
|
||||
virt;
|
||||
to += sizeof(MAILBOX_t);
|
||||
size = pmboxq->u.mb.un.varWords[5];
|
||||
memcpy(to, from, size);
|
||||
} else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) {
|
||||
from = (uint8_t *)dd_data->context_un.
|
||||
mbox.dmp->dma.virt;
|
||||
to += sizeof(MAILBOX_t);
|
||||
size = dd_data->context_un.mbox.dmp->size;
|
||||
memcpy(to, from, size);
|
||||
}
|
||||
}
|
||||
|
||||
from = (uint8_t *)dd_data->context_un.mbox.mb;
|
||||
job = dd_data->context_un.mbox.set_job;
|
||||
memcpy(mb, pmb, sizeof(*pmb));
|
||||
size = job->request_payload.payload_len;
|
||||
size = job->reply_payload.payload_len;
|
||||
job->reply->reply_payload_rcv_len =
|
||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
||||
job->reply_payload.sg_cnt,
|
||||
mb, size);
|
||||
from, size);
|
||||
job->reply->result = 0;
|
||||
|
||||
dd_data->context_un.mbox.set_job = NULL;
|
||||
job->dd_data = NULL;
|
||||
job->job_done(job);
|
||||
/* need to hold the lock until we call job done to hold off
|
||||
* the timeout handler returning to the midlayer while
|
||||
* we are stillprocessing the job
|
||||
*/
|
||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||
|
||||
kfree(dd_data->context_un.mbox.mb);
|
||||
mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
|
||||
kfree(mb);
|
||||
kfree(dd_data->context_un.mbox.ext);
|
||||
if (dd_data->context_un.mbox.dmp) {
|
||||
dma_free_coherent(&phba->pcidev->dev,
|
||||
dd_data->context_un.mbox.dmp->size,
|
||||
dd_data->context_un.mbox.dmp->dma.virt,
|
||||
dd_data->context_un.mbox.dmp->dma.phys);
|
||||
kfree(dd_data->context_un.mbox.dmp);
|
||||
}
|
||||
if (dd_data->context_un.mbox.rxbmp) {
|
||||
lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt,
|
||||
dd_data->context_un.mbox.rxbmp->phys);
|
||||
kfree(dd_data->context_un.mbox.rxbmp);
|
||||
}
|
||||
kfree(dd_data);
|
||||
return;
|
||||
}
|
||||
|
@ -2464,10 +2534,12 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
|
|||
case MBX_SET_DEBUG:
|
||||
case MBX_WRITE_WWN:
|
||||
case MBX_SLI4_CONFIG:
|
||||
case MBX_READ_EVENT_LOG:
|
||||
case MBX_READ_EVENT_LOG_STATUS:
|
||||
case MBX_WRITE_EVENT_LOG:
|
||||
case MBX_PORT_CAPABILITIES:
|
||||
case MBX_PORT_IOV_CONTROL:
|
||||
case MBX_RUN_BIU_DIAG64:
|
||||
break;
|
||||
case MBX_SET_VARIABLE:
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||
|
@ -2482,8 +2554,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
|
|||
phba->fc_topology = TOPOLOGY_PT_PT;
|
||||
}
|
||||
break;
|
||||
case MBX_RUN_BIU_DIAG64:
|
||||
case MBX_READ_EVENT_LOG:
|
||||
case MBX_READ_SPARM64:
|
||||
case MBX_READ_LA:
|
||||
case MBX_READ_LA64:
|
||||
|
@ -2518,97 +2588,365 @@ static uint32_t
|
|||
lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
||||
struct lpfc_vport *vport)
|
||||
{
|
||||
LPFC_MBOXQ_t *pmboxq;
|
||||
MAILBOX_t *pmb;
|
||||
MAILBOX_t *mb;
|
||||
struct bsg_job_data *dd_data;
|
||||
LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
|
||||
MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
|
||||
/* a 4k buffer to hold the mb and extended data from/to the bsg */
|
||||
MAILBOX_t *mb = NULL;
|
||||
struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
|
||||
uint32_t size;
|
||||
struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */
|
||||
struct lpfc_dmabufext *dmp = NULL; /* for biu diag */
|
||||
struct ulp_bde64 *rxbpl = NULL;
|
||||
struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *)
|
||||
job->request->rqst_data.h_vendor.vendor_cmd;
|
||||
uint8_t *ext = NULL;
|
||||
int rc = 0;
|
||||
uint8_t *from;
|
||||
|
||||
/* in case no data is transferred */
|
||||
job->reply->reply_payload_rcv_len = 0;
|
||||
|
||||
/* check if requested extended data lengths are valid */
|
||||
if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) ||
|
||||
(mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) {
|
||||
rc = -ERANGE;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
/* allocate our bsg tracking structure */
|
||||
dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
|
||||
if (!dd_data) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
|
||||
"2727 Failed allocation of dd_data\n");
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL);
|
||||
if (!mb) {
|
||||
kfree(dd_data);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!pmboxq) {
|
||||
kfree(dd_data);
|
||||
kfree(mb);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
|
||||
|
||||
size = job->request_payload.payload_len;
|
||||
job->reply->reply_payload_rcv_len =
|
||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
mb, size);
|
||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
mb, size);
|
||||
|
||||
rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
|
||||
if (rc != 0) {
|
||||
kfree(dd_data);
|
||||
kfree(mb);
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return rc; /* must be negative */
|
||||
}
|
||||
if (rc != 0)
|
||||
goto job_done; /* must be negative */
|
||||
|
||||
memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
|
||||
pmb = &pmboxq->u.mb;
|
||||
memcpy(pmb, mb, sizeof(*pmb));
|
||||
pmb->mbxOwner = OWN_HOST;
|
||||
pmboxq->context1 = NULL;
|
||||
pmboxq->vport = vport;
|
||||
|
||||
if ((vport->fc_flag & FC_OFFLINE_MODE) ||
|
||||
(!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
|
||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
|
||||
if (rc != MBX_SUCCESS) {
|
||||
if (rc != MBX_TIMEOUT) {
|
||||
kfree(dd_data);
|
||||
kfree(mb);
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
}
|
||||
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
|
||||
/* If HBA encountered an error attention, allow only DUMP
|
||||
* or RESTART mailbox commands until the HBA is restarted.
|
||||
*/
|
||||
if (phba->pport->stopped &&
|
||||
pmb->mbxCommand != MBX_DUMP_MEMORY &&
|
||||
pmb->mbxCommand != MBX_RESTART &&
|
||||
pmb->mbxCommand != MBX_WRITE_VPARMS &&
|
||||
pmb->mbxCommand != MBX_WRITE_WWN)
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
|
||||
"2797 mbox: Issued mailbox cmd "
|
||||
"0x%x while in stopped state.\n",
|
||||
pmb->mbxCommand);
|
||||
|
||||
/* Don't allow mailbox commands to be sent when blocked
|
||||
* or when in the middle of discovery
|
||||
*/
|
||||
if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
|
||||
rc = -EAGAIN;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
/* extended mailbox commands will need an extended buffer */
|
||||
if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
|
||||
ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL);
|
||||
if (!ext) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
memcpy(mb, pmb, sizeof(*pmb));
|
||||
job->reply->reply_payload_rcv_len =
|
||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
||||
job->reply_payload.sg_cnt,
|
||||
mb, size);
|
||||
kfree(dd_data);
|
||||
kfree(mb);
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
/* not waiting mbox already done */
|
||||
return 0;
|
||||
/* any data for the device? */
|
||||
if (mbox_req->inExtWLen) {
|
||||
from = (uint8_t *)mb;
|
||||
from += sizeof(MAILBOX_t);
|
||||
memcpy((uint8_t *)ext, from,
|
||||
mbox_req->inExtWLen * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
pmboxq->context2 = ext;
|
||||
pmboxq->in_ext_byte_len =
|
||||
mbox_req->inExtWLen *
|
||||
sizeof(uint32_t);
|
||||
pmboxq->out_ext_byte_len =
|
||||
mbox_req->outExtWLen *
|
||||
sizeof(uint32_t);
|
||||
pmboxq->mbox_offset_word =
|
||||
mbox_req->mbOffset;
|
||||
pmboxq->context2 = ext;
|
||||
pmboxq->in_ext_byte_len =
|
||||
mbox_req->inExtWLen * sizeof(uint32_t);
|
||||
pmboxq->out_ext_byte_len =
|
||||
mbox_req->outExtWLen * sizeof(uint32_t);
|
||||
pmboxq->mbox_offset_word = mbox_req->mbOffset;
|
||||
}
|
||||
|
||||
/* biu diag will need a kernel buffer to transfer the data
|
||||
* allocate our own buffer and setup the mailbox command to
|
||||
* use ours
|
||||
*/
|
||||
if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) {
|
||||
uint32_t transmit_length = pmb->un.varWords[1];
|
||||
uint32_t receive_length = pmb->un.varWords[4];
|
||||
/* transmit length cannot be greater than receive length or
|
||||
* mailbox extension size
|
||||
*/
|
||||
if ((transmit_length > receive_length) ||
|
||||
(transmit_length > MAILBOX_EXT_SIZE)) {
|
||||
rc = -ERANGE;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!rxbmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||
if (!rxbmp->virt) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0);
|
||||
if (!dmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dmp->dma.list);
|
||||
pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
|
||||
putPaddrHigh(dmp->dma.phys);
|
||||
pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
|
||||
putPaddrLow(dmp->dma.phys);
|
||||
|
||||
pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
|
||||
putPaddrHigh(dmp->dma.phys +
|
||||
pmb->un.varBIUdiag.un.s2.
|
||||
xmit_bde64.tus.f.bdeSize);
|
||||
pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
|
||||
putPaddrLow(dmp->dma.phys +
|
||||
pmb->un.varBIUdiag.un.s2.
|
||||
xmit_bde64.tus.f.bdeSize);
|
||||
|
||||
/* copy the transmit data found in the mailbox extension area */
|
||||
from = (uint8_t *)mb;
|
||||
from += sizeof(MAILBOX_t);
|
||||
memcpy((uint8_t *)dmp->dma.virt, from, transmit_length);
|
||||
} else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) {
|
||||
struct READ_EVENT_LOG_VAR *rdEventLog =
|
||||
&pmb->un.varRdEventLog ;
|
||||
uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
|
||||
uint32_t mode = bf_get(lpfc_event_log, rdEventLog);
|
||||
|
||||
/* receive length cannot be greater than mailbox
|
||||
* extension size
|
||||
*/
|
||||
if (receive_length > MAILBOX_EXT_SIZE) {
|
||||
rc = -ERANGE;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
/* mode zero uses a bde like biu diags command */
|
||||
if (mode == 0) {
|
||||
|
||||
/* rebuild the command for sli4 using our own buffers
|
||||
* like we do for biu diags
|
||||
*/
|
||||
|
||||
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!rxbmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
if (rxbpl) {
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
dmp = diag_cmd_data_alloc(phba, rxbpl,
|
||||
receive_length, 0);
|
||||
}
|
||||
|
||||
if (!dmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dmp->dma.list);
|
||||
pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
|
||||
pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
|
||||
}
|
||||
} else if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
|
||||
/* rebuild the command for sli4 using our own buffers
|
||||
* like we do for biu diags
|
||||
*/
|
||||
uint32_t receive_length = pmb->un.varWords[2];
|
||||
/* receive length cannot be greater than mailbox
|
||||
* extension size
|
||||
*/
|
||||
if ((receive_length == 0) ||
|
||||
(receive_length > MAILBOX_EXT_SIZE)) {
|
||||
rc = -ERANGE;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!rxbmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||
if (!rxbmp->virt) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length,
|
||||
0);
|
||||
if (!dmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dmp->dma.list);
|
||||
pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
|
||||
pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
|
||||
} else if ((pmb->mbxCommand == MBX_UPDATE_CFG) &&
|
||||
pmb->un.varUpdateCfg.co) {
|
||||
struct ulp_bde64 *bde =
|
||||
(struct ulp_bde64 *)&pmb->un.varWords[4];
|
||||
|
||||
/* bde size cannot be greater than mailbox ext size */
|
||||
if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
|
||||
rc = -ERANGE;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
||||
if (!rxbmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
|
||||
if (!rxbmp->virt) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&rxbmp->list);
|
||||
rxbpl = (struct ulp_bde64 *) rxbmp->virt;
|
||||
dmp = diag_cmd_data_alloc(phba, rxbpl,
|
||||
bde->tus.f.bdeSize, 0);
|
||||
if (!dmp) {
|
||||
rc = -ENOMEM;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dmp->dma.list);
|
||||
bde->addrHigh = putPaddrHigh(dmp->dma.phys);
|
||||
bde->addrLow = putPaddrLow(dmp->dma.phys);
|
||||
|
||||
/* copy the transmit data found in the mailbox
|
||||
* extension area
|
||||
*/
|
||||
from = (uint8_t *)mb;
|
||||
from += sizeof(MAILBOX_t);
|
||||
memcpy((uint8_t *)dmp->dma.virt, from,
|
||||
bde->tus.f.bdeSize);
|
||||
}
|
||||
}
|
||||
|
||||
dd_data->context_un.mbox.rxbmp = rxbmp;
|
||||
dd_data->context_un.mbox.dmp = dmp;
|
||||
|
||||
/* setup wake call as IOCB callback */
|
||||
pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
|
||||
|
||||
/* setup context field to pass wait_queue pointer to wake function */
|
||||
pmboxq->context1 = dd_data;
|
||||
dd_data->type = TYPE_MBOX;
|
||||
dd_data->context_un.mbox.pmboxq = pmboxq;
|
||||
dd_data->context_un.mbox.mb = mb;
|
||||
dd_data->context_un.mbox.set_job = job;
|
||||
dd_data->context_un.mbox.ext = ext;
|
||||
dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
|
||||
dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
|
||||
dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen;
|
||||
job->dd_data = dd_data;
|
||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
|
||||
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
|
||||
kfree(dd_data);
|
||||
kfree(mb);
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
return -EIO;
|
||||
|
||||
if ((vport->fc_flag & FC_OFFLINE_MODE) ||
|
||||
(!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
|
||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
|
||||
if (rc != MBX_SUCCESS) {
|
||||
rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
/* job finished, copy the data */
|
||||
memcpy(mb, pmb, sizeof(*pmb));
|
||||
job->reply->reply_payload_rcv_len =
|
||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
||||
job->reply_payload.sg_cnt,
|
||||
mb, size);
|
||||
/* not waiting mbox already done */
|
||||
rc = 0;
|
||||
goto job_done;
|
||||
}
|
||||
|
||||
return 1;
|
||||
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
|
||||
if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY))
|
||||
return 1; /* job started */
|
||||
|
||||
job_done:
|
||||
/* common exit for error or job completed inline */
|
||||
kfree(mb);
|
||||
if (pmboxq)
|
||||
mempool_free(pmboxq, phba->mbox_mem_pool);
|
||||
kfree(ext);
|
||||
if (dmp) {
|
||||
dma_free_coherent(&phba->pcidev->dev,
|
||||
dmp->size, dmp->dma.virt,
|
||||
dmp->dma.phys);
|
||||
kfree(dmp);
|
||||
}
|
||||
if (rxbmp) {
|
||||
lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
|
||||
kfree(rxbmp);
|
||||
}
|
||||
kfree(dd_data);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2633,7 +2971,12 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
|
|||
goto job_error;
|
||||
}
|
||||
|
||||
if (job->request_payload.payload_len != PAGE_SIZE) {
|
||||
if (job->request_payload.payload_len != BSG_MBOX_SIZE) {
|
||||
rc = -EINVAL;
|
||||
goto job_error;
|
||||
}
|
||||
|
||||
if (job->reply_payload.payload_len != BSG_MBOX_SIZE) {
|
||||
rc = -EINVAL;
|
||||
goto job_error;
|
||||
}
|
||||
|
@ -3094,6 +3437,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
|
|||
job->dd_data = NULL;
|
||||
job->reply->reply_payload_rcv_len = 0;
|
||||
job->reply->result = -EAGAIN;
|
||||
/* the mbox completion handler can now be run */
|
||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||
job->job_done(job);
|
||||
break;
|
||||
|
|
|
@ -91,11 +91,12 @@ struct get_mgmt_rev_reply {
|
|||
struct MgmtRevInfo info;
|
||||
};
|
||||
|
||||
#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */
|
||||
struct dfc_mbox_req {
|
||||
uint32_t command;
|
||||
uint32_t mbOffset;
|
||||
uint32_t inExtWLen;
|
||||
uint32_t outExtWLen;
|
||||
uint8_t mbOffset;
|
||||
};
|
||||
|
||||
/* Used for menlo command or menlo data. The xri is only used for menlo data */
|
||||
|
|
|
@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|||
void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||
void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
|
||||
void lpfc_retry_pport_discovery(struct lpfc_hba *);
|
||||
void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
|
||||
|
||||
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
||||
|
|
|
@ -38,6 +38,7 @@ enum lpfc_work_type {
|
|||
LPFC_EVT_ELS_RETRY,
|
||||
LPFC_EVT_DEV_LOSS,
|
||||
LPFC_EVT_FASTPATH_MGMT_EVT,
|
||||
LPFC_EVT_RESET_HBA,
|
||||
};
|
||||
|
||||
/* structure used to queue event to the discovery tasklet */
|
||||
|
|
|
@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||
spin_unlock_irq(shost->host_lock);
|
||||
lpfc_unreg_rpi(vport, np);
|
||||
}
|
||||
lpfc_cleanup_pending_mbox(vport);
|
||||
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
|
||||
lpfc_mbx_unreg_vpi(vport);
|
||||
spin_lock_irq(shost->host_lock);
|
||||
|
@ -864,6 +865,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
}
|
||||
spin_lock_irq(shost->host_lock);
|
||||
vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
|
||||
vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
|
||||
/*
|
||||
|
@ -893,11 +895,14 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
|
||||
if (!rc) {
|
||||
/* Mark the FCF discovery process done */
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS,
|
||||
"2769 FLOGI successful on FCF record: "
|
||||
"current_fcf_index:x%x, terminate FCF "
|
||||
"round robin failover process\n",
|
||||
phba->fcf.current_rec.fcf_indx);
|
||||
if (phba->hba_flag & HBA_FIP_SUPPORT)
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
|
||||
LOG_ELS,
|
||||
"2769 FLOGI successful on FCF "
|
||||
"record: current_fcf_index:"
|
||||
"x%x, terminate FCF round "
|
||||
"robin failover process\n",
|
||||
phba->fcf.current_rec.fcf_indx);
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
@ -5366,7 +5371,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,
|
|||
sizeof(struct lpfc_name));
|
||||
pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
|
||||
cmdiocbp->context2)->virt);
|
||||
lsrjt_event.command = *pcmd;
|
||||
lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0;
|
||||
stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]);
|
||||
lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;
|
||||
lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp;
|
||||
|
@ -6050,7 +6055,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||
spin_lock_irq(shost->host_lock);
|
||||
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
if (vport->port_type == LPFC_PHYSICAL_PORT)
|
||||
if (vport->port_type == LPFC_PHYSICAL_PORT
|
||||
&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
|
||||
lpfc_initial_flogi(vport);
|
||||
else
|
||||
lpfc_initial_fdisc(vport);
|
||||
|
@ -6286,6 +6292,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
}
|
||||
spin_lock_irq(shost->host_lock);
|
||||
vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
|
||||
vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
|
||||
vport->fc_flag |= FC_FABRIC;
|
||||
if (vport->phba->fc_topology == TOPOLOGY_LOOP)
|
||||
vport->fc_flag |= FC_PUBLIC_LOOP;
|
||||
|
@ -6310,11 +6317,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
spin_unlock_irq(shost->host_lock);
|
||||
lpfc_unreg_rpi(vport, np);
|
||||
}
|
||||
lpfc_cleanup_pending_mbox(vport);
|
||||
lpfc_mbx_unreg_vpi(vport);
|
||||
spin_lock_irq(shost->host_lock);
|
||||
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
|
||||
else
|
||||
vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -475,6 +475,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
|
|||
lpfc_send_fastpath_evt(phba, evtp);
|
||||
free_evt = 0;
|
||||
break;
|
||||
case LPFC_EVT_RESET_HBA:
|
||||
if (!(phba->pport->load_flag & FC_UNLOADING))
|
||||
lpfc_reset_hba(phba);
|
||||
break;
|
||||
}
|
||||
if (free_evt)
|
||||
kfree(evtp);
|
||||
|
@ -1531,7 +1535,37 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
|
|||
}
|
||||
|
||||
/**
|
||||
* lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command
|
||||
* lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
* @fcf_cnt: number of eligible fcf record seen so far.
|
||||
*
|
||||
* This function makes an running random selection decision on FCF record to
|
||||
* use through a sequence of @fcf_cnt eligible FCF records with equal
|
||||
* probability. To perform integer manunipulation of random numbers with
|
||||
* size unit32_t, the lower 16 bits of the 32-bit random number returned
|
||||
* from random32() are taken as the random random number generated.
|
||||
*
|
||||
* Returns true when outcome is for the newly read FCF record should be
|
||||
* chosen; otherwise, return false when outcome is for keeping the previously
|
||||
* chosen FCF record.
|
||||
**/
|
||||
static bool
|
||||
lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
|
||||
{
|
||||
uint32_t rand_num;
|
||||
|
||||
/* Get 16-bit uniform random number */
|
||||
rand_num = (0xFFFF & random32());
|
||||
|
||||
/* Decision with probability 1/fcf_cnt */
|
||||
if ((fcf_cnt * rand_num) < 0xFFFF)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
* @mboxq: pointer to mailbox object.
|
||||
* @next_fcf_index: pointer to holder of next fcf index.
|
||||
|
@ -1592,7 +1626,9 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
|
|||
new_fcf_record = (struct fcf_record *)(virt_addr +
|
||||
sizeof(struct lpfc_mbx_read_fcf_tbl));
|
||||
lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
|
||||
sizeof(struct fcf_record));
|
||||
offsetof(struct fcf_record, vlan_bitmap));
|
||||
new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137);
|
||||
new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138);
|
||||
|
||||
return new_fcf_record;
|
||||
}
|
||||
|
@ -1679,6 +1715,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|||
uint16_t fcf_index, next_fcf_index;
|
||||
struct lpfc_fcf_rec *fcf_rec = NULL;
|
||||
uint16_t vlan_id;
|
||||
uint32_t seed;
|
||||
bool select_new_fcf;
|
||||
int rc;
|
||||
|
||||
/* If there is pending FCoE event restart FCF table scan */
|
||||
|
@ -1809,9 +1847,21 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|||
* than the driver FCF record, use the new record.
|
||||
*/
|
||||
if (new_fcf_record->fip_priority < fcf_rec->priority) {
|
||||
/* Choose this FCF record */
|
||||
/* Choose the new FCF record with lower priority */
|
||||
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
|
||||
addr_mode, vlan_id, 0);
|
||||
/* Reset running random FCF selection count */
|
||||
phba->fcf.eligible_fcf_cnt = 1;
|
||||
} else if (new_fcf_record->fip_priority == fcf_rec->priority) {
|
||||
/* Update running random FCF selection count */
|
||||
phba->fcf.eligible_fcf_cnt++;
|
||||
select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
|
||||
phba->fcf.eligible_fcf_cnt);
|
||||
if (select_new_fcf)
|
||||
/* Choose the new FCF by random selection */
|
||||
__lpfc_update_fcf_record(phba, fcf_rec,
|
||||
new_fcf_record,
|
||||
addr_mode, vlan_id, 0);
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
goto read_next_fcf;
|
||||
|
@ -1825,6 +1875,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
|||
addr_mode, vlan_id, (boot_flag ?
|
||||
BOOT_ENABLE : 0));
|
||||
phba->fcf.fcf_flag |= FCF_AVAILABLE;
|
||||
/* Setup initial running random FCF selection count */
|
||||
phba->fcf.eligible_fcf_cnt = 1;
|
||||
/* Seeding the random number generator for random selection */
|
||||
seed = (uint32_t)(0xFFFFFFFF & jiffies);
|
||||
srandom32(seed);
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
goto read_next_fcf;
|
||||
|
@ -2686,11 +2741,18 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||
switch (mb->mbxStatus) {
|
||||
case 0x0011:
|
||||
case 0x0020:
|
||||
case 0x9700:
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
|
||||
"0911 cmpl_unreg_vpi, mb status = 0x%x\n",
|
||||
mb->mbxStatus);
|
||||
break;
|
||||
/* If VPI is busy, reset the HBA */
|
||||
case 0x9700:
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
|
||||
"2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
|
||||
vport->vpi, mb->mbxStatus);
|
||||
if (!(phba->pport->load_flag & FC_UNLOADING))
|
||||
lpfc_workq_post_event(phba, NULL, NULL,
|
||||
LPFC_EVT_RESET_HBA);
|
||||
}
|
||||
spin_lock_irq(shost->host_lock);
|
||||
vport->vpi_state &= ~LPFC_VPI_REGISTERED;
|
||||
|
@ -2965,7 +3027,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
|
||||
|
||||
if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
|
||||
lpfc_start_fdiscs(phba);
|
||||
/* when physical port receive logo donot start
|
||||
* vport discovery */
|
||||
if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
|
||||
lpfc_start_fdiscs(phba);
|
||||
else
|
||||
vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;
|
||||
lpfc_do_scr_ns_plogi(phba, vport);
|
||||
}
|
||||
|
||||
|
@ -3177,7 +3244,6 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
||||
|
||||
if (new_state == NLP_STE_UNMAPPED_NODE) {
|
||||
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
|
||||
ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
|
||||
ndlp->nlp_type |= NLP_FC_NODE;
|
||||
}
|
||||
|
@ -4935,6 +5001,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
|
|||
ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
|
||||
if (ndlp)
|
||||
lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
|
||||
lpfc_cleanup_pending_mbox(vports[i]);
|
||||
lpfc_mbx_unreg_vpi(vports[i]);
|
||||
shost = lpfc_shost_from_vport(vports[i]);
|
||||
spin_lock_irq(shost->host_lock);
|
||||
|
|
|
@ -1565,95 +1565,83 @@ enum lpfc_protgrp_type {
|
|||
};
|
||||
|
||||
/* PDE Descriptors */
|
||||
#define LPFC_PDE1_DESCRIPTOR 0x81
|
||||
#define LPFC_PDE2_DESCRIPTOR 0x82
|
||||
#define LPFC_PDE3_DESCRIPTOR 0x83
|
||||
#define LPFC_PDE5_DESCRIPTOR 0x85
|
||||
#define LPFC_PDE6_DESCRIPTOR 0x86
|
||||
#define LPFC_PDE7_DESCRIPTOR 0x87
|
||||
|
||||
/* BlockGuard Profiles */
|
||||
enum lpfc_bg_prof_codes {
|
||||
LPFC_PROF_INVALID,
|
||||
LPFC_PROF_A1 = 128, /* Full Protection */
|
||||
LPFC_PROF_A2, /* Disabled Protection Checks:A2~A4 */
|
||||
LPFC_PROF_A3,
|
||||
LPFC_PROF_A4,
|
||||
LPFC_PROF_B1, /* Embedded DIFs: B1~B3 */
|
||||
LPFC_PROF_B2,
|
||||
LPFC_PROF_B3,
|
||||
LPFC_PROF_C1, /* Separate DIFs: C1~C3 */
|
||||
LPFC_PROF_C2,
|
||||
LPFC_PROF_C3,
|
||||
LPFC_PROF_D1, /* Full Protection */
|
||||
LPFC_PROF_D2, /* Partial Protection & Check Disabling */
|
||||
LPFC_PROF_D3,
|
||||
LPFC_PROF_E1, /* E1~E4:out - check-only, in - update apptag */
|
||||
LPFC_PROF_E2,
|
||||
LPFC_PROF_E3,
|
||||
LPFC_PROF_E4,
|
||||
LPFC_PROF_F1, /* Full Translation - F1 Prot Descriptor */
|
||||
/* F1 Translation BDE */
|
||||
LPFC_PROF_ANT1, /* TCP checksum, DIF inline with data buffers */
|
||||
LPFC_PROF_AST1, /* TCP checksum, DIF split from data buffer */
|
||||
LPFC_PROF_ANT2,
|
||||
LPFC_PROF_AST2
|
||||
/* BlockGuard Opcodes */
|
||||
#define BG_OP_IN_NODIF_OUT_CRC 0x0
|
||||
#define BG_OP_IN_CRC_OUT_NODIF 0x1
|
||||
#define BG_OP_IN_NODIF_OUT_CSUM 0x2
|
||||
#define BG_OP_IN_CSUM_OUT_NODIF 0x3
|
||||
#define BG_OP_IN_CRC_OUT_CRC 0x4
|
||||
#define BG_OP_IN_CSUM_OUT_CSUM 0x5
|
||||
#define BG_OP_IN_CRC_OUT_CSUM 0x6
|
||||
#define BG_OP_IN_CSUM_OUT_CRC 0x7
|
||||
|
||||
struct lpfc_pde5 {
|
||||
uint32_t word0;
|
||||
#define pde5_type_SHIFT 24
|
||||
#define pde5_type_MASK 0x000000ff
|
||||
#define pde5_type_WORD word0
|
||||
#define pde5_rsvd0_SHIFT 0
|
||||
#define pde5_rsvd0_MASK 0x00ffffff
|
||||
#define pde5_rsvd0_WORD word0
|
||||
uint32_t reftag; /* Reference Tag Value */
|
||||
uint32_t reftagtr; /* Reference Tag Translation Value */
|
||||
};
|
||||
|
||||
/* BlockGuard error-control defines */
|
||||
#define BG_EC_STOP_ERR 0x00
|
||||
#define BG_EC_CONT_ERR 0x01
|
||||
#define BG_EC_IGN_UNINIT_STOP_ERR 0x10
|
||||
#define BG_EC_IGN_UNINIT_CONT_ERR 0x11
|
||||
|
||||
/* PDE (Protection Descriptor Entry) word 0 bit masks and shifts */
|
||||
#define PDE_DESC_TYPE_MASK 0xff000000
|
||||
#define PDE_DESC_TYPE_SHIFT 24
|
||||
#define PDE_BG_PROFILE_MASK 0x00ff0000
|
||||
#define PDE_BG_PROFILE_SHIFT 16
|
||||
#define PDE_BLOCK_LEN_MASK 0x0000fffc
|
||||
#define PDE_BLOCK_LEN_SHIFT 2
|
||||
#define PDE_ERR_CTRL_MASK 0x00000003
|
||||
#define PDE_ERR_CTRL_SHIFT 0
|
||||
/* PDE word 1 bit masks and shifts */
|
||||
#define PDE_APPTAG_MASK_MASK 0xffff0000
|
||||
#define PDE_APPTAG_MASK_SHIFT 16
|
||||
#define PDE_APPTAG_VAL_MASK 0x0000ffff
|
||||
#define PDE_APPTAG_VAL_SHIFT 0
|
||||
struct lpfc_pde {
|
||||
uint32_t parms; /* bitfields of descriptor, prof, len, and ec */
|
||||
uint32_t apptag; /* bitfields of app tag maskand app tag value */
|
||||
uint32_t reftag; /* reference tag occupying all 32 bits */
|
||||
struct lpfc_pde6 {
|
||||
uint32_t word0;
|
||||
#define pde6_type_SHIFT 24
|
||||
#define pde6_type_MASK 0x000000ff
|
||||
#define pde6_type_WORD word0
|
||||
#define pde6_rsvd0_SHIFT 0
|
||||
#define pde6_rsvd0_MASK 0x00ffffff
|
||||
#define pde6_rsvd0_WORD word0
|
||||
uint32_t word1;
|
||||
#define pde6_rsvd1_SHIFT 26
|
||||
#define pde6_rsvd1_MASK 0x0000003f
|
||||
#define pde6_rsvd1_WORD word1
|
||||
#define pde6_na_SHIFT 25
|
||||
#define pde6_na_MASK 0x00000001
|
||||
#define pde6_na_WORD word1
|
||||
#define pde6_rsvd2_SHIFT 16
|
||||
#define pde6_rsvd2_MASK 0x000001FF
|
||||
#define pde6_rsvd2_WORD word1
|
||||
#define pde6_apptagtr_SHIFT 0
|
||||
#define pde6_apptagtr_MASK 0x0000ffff
|
||||
#define pde6_apptagtr_WORD word1
|
||||
uint32_t word2;
|
||||
#define pde6_optx_SHIFT 28
|
||||
#define pde6_optx_MASK 0x0000000f
|
||||
#define pde6_optx_WORD word2
|
||||
#define pde6_oprx_SHIFT 24
|
||||
#define pde6_oprx_MASK 0x0000000f
|
||||
#define pde6_oprx_WORD word2
|
||||
#define pde6_nr_SHIFT 23
|
||||
#define pde6_nr_MASK 0x00000001
|
||||
#define pde6_nr_WORD word2
|
||||
#define pde6_ce_SHIFT 22
|
||||
#define pde6_ce_MASK 0x00000001
|
||||
#define pde6_ce_WORD word2
|
||||
#define pde6_re_SHIFT 21
|
||||
#define pde6_re_MASK 0x00000001
|
||||
#define pde6_re_WORD word2
|
||||
#define pde6_ae_SHIFT 20
|
||||
#define pde6_ae_MASK 0x00000001
|
||||
#define pde6_ae_WORD word2
|
||||
#define pde6_ai_SHIFT 19
|
||||
#define pde6_ai_MASK 0x00000001
|
||||
#define pde6_ai_WORD word2
|
||||
#define pde6_bs_SHIFT 16
|
||||
#define pde6_bs_MASK 0x00000007
|
||||
#define pde6_bs_WORD word2
|
||||
#define pde6_apptagval_SHIFT 0
|
||||
#define pde6_apptagval_MASK 0x0000ffff
|
||||
#define pde6_apptagval_WORD word2
|
||||
};
|
||||
|
||||
/* inline function to set fields in parms of PDE */
|
||||
static inline void
|
||||
lpfc_pde_set_bg_parms(struct lpfc_pde *p, u8 desc, u8 prof, u16 len, u8 ec)
|
||||
{
|
||||
uint32_t *wp = &p->parms;
|
||||
|
||||
/* spec indicates that adapter appends two 0's to length field */
|
||||
len = len >> 2;
|
||||
|
||||
*wp &= 0;
|
||||
*wp |= ((desc << PDE_DESC_TYPE_SHIFT) & PDE_DESC_TYPE_MASK);
|
||||
*wp |= ((prof << PDE_BG_PROFILE_SHIFT) & PDE_BG_PROFILE_MASK);
|
||||
*wp |= ((len << PDE_BLOCK_LEN_SHIFT) & PDE_BLOCK_LEN_MASK);
|
||||
*wp |= ((ec << PDE_ERR_CTRL_SHIFT) & PDE_ERR_CTRL_MASK);
|
||||
*wp = le32_to_cpu(*wp);
|
||||
}
|
||||
|
||||
/* inline function to set apptag and reftag fields of PDE */
|
||||
static inline void
|
||||
lpfc_pde_set_dif_parms(struct lpfc_pde *p, u16 apptagmask, u16 apptagval,
|
||||
u32 reftag)
|
||||
{
|
||||
uint32_t *wp = &p->apptag;
|
||||
*wp &= 0;
|
||||
*wp |= ((apptagmask << PDE_APPTAG_MASK_SHIFT) & PDE_APPTAG_MASK_MASK);
|
||||
*wp |= ((apptagval << PDE_APPTAG_VAL_SHIFT) & PDE_APPTAG_VAL_MASK);
|
||||
*wp = le32_to_cpu(*wp);
|
||||
wp = &p->reftag;
|
||||
*wp = le32_to_cpu(reftag);
|
||||
}
|
||||
|
||||
|
||||
/* Structure for MB Command LOAD_SM and DOWN_LOAD */
|
||||
|
||||
|
@ -1744,6 +1732,17 @@ typedef struct {
|
|||
} un;
|
||||
} BIU_DIAG_VAR;
|
||||
|
||||
/* Structure for MB command READ_EVENT_LOG (0x38) */
|
||||
struct READ_EVENT_LOG_VAR {
|
||||
uint32_t word1;
|
||||
#define lpfc_event_log_SHIFT 29
|
||||
#define lpfc_event_log_MASK 0x00000001
|
||||
#define lpfc_event_log_WORD word1
|
||||
#define USE_MAILBOX_RESPONSE 1
|
||||
uint32_t offset;
|
||||
struct ulp_bde64 rcv_bde64;
|
||||
};
|
||||
|
||||
/* Structure for MB Command INIT_LINK (05) */
|
||||
|
||||
typedef struct {
|
||||
|
@ -2487,8 +2486,8 @@ typedef struct {
|
|||
#define DMP_VPORT_REGION_SIZE 0x200
|
||||
#define DMP_MBOX_OFFSET_WORD 0x5
|
||||
|
||||
#define DMP_REGION_23 0x17 /* fcoe param and port state region */
|
||||
#define DMP_RGN23_SIZE 0x400
|
||||
#define DMP_REGION_23 0x17 /* fcoe param and port state region */
|
||||
#define DMP_RGN23_SIZE 0x400
|
||||
|
||||
#define WAKE_UP_PARMS_REGION_ID 4
|
||||
#define WAKE_UP_PARMS_WORD_SIZE 15
|
||||
|
@ -2503,9 +2502,9 @@ struct vport_rec {
|
|||
#define VPORT_INFO_REV 0x1
|
||||
#define MAX_STATIC_VPORT_COUNT 16
|
||||
struct static_vport_info {
|
||||
uint32_t signature;
|
||||
uint32_t signature;
|
||||
uint32_t rev;
|
||||
struct vport_rec vport_list[MAX_STATIC_VPORT_COUNT];
|
||||
struct vport_rec vport_list[MAX_STATIC_VPORT_COUNT];
|
||||
uint32_t resvd[66];
|
||||
};
|
||||
|
||||
|
@ -2934,6 +2933,12 @@ typedef struct {
|
|||
/* Union of all Mailbox Command types */
|
||||
#define MAILBOX_CMD_WSIZE 32
|
||||
#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
|
||||
/* ext_wsize times 4 bytes should not be greater than max xmit size */
|
||||
#define MAILBOX_EXT_WSIZE 512
|
||||
#define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t))
|
||||
#define MAILBOX_HBA_EXT_OFFSET 0x100
|
||||
/* max mbox xmit size is a page size for sysfs IO operations */
|
||||
#define MAILBOX_MAX_XMIT_SIZE PAGE_SIZE
|
||||
|
||||
typedef union {
|
||||
uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
|
||||
|
@ -2972,6 +2977,9 @@ typedef union {
|
|||
REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */
|
||||
UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */
|
||||
ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
|
||||
struct READ_EVENT_LOG_VAR varRdEventLog; /* cmd = 0x38
|
||||
* (READ_EVENT_LOG)
|
||||
*/
|
||||
struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI) */
|
||||
} MAILVARIANTS;
|
||||
|
||||
|
@ -3652,7 +3660,8 @@ typedef struct _IOCB { /* IOCB structure */
|
|||
/* Maximum IOCBs that will fit in SLI2 slim */
|
||||
#define MAX_SLI2_IOCB 498
|
||||
#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
|
||||
(sizeof(MAILBOX_t) + sizeof(PCB_t)))
|
||||
(sizeof(MAILBOX_t) + sizeof(PCB_t) + \
|
||||
sizeof(uint32_t) * MAILBOX_EXT_WSIZE))
|
||||
|
||||
/* HBQ entries are 4 words each = 4k */
|
||||
#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \
|
||||
|
@ -3660,6 +3669,7 @@ typedef struct _IOCB { /* IOCB structure */
|
|||
|
||||
struct lpfc_sli2_slim {
|
||||
MAILBOX_t mbx;
|
||||
uint32_t mbx_ext_words[MAILBOX_EXT_WSIZE];
|
||||
PCB_t pcb;
|
||||
IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
|
||||
};
|
||||
|
|
|
@ -41,8 +41,14 @@
|
|||
* Or clear that bit field:
|
||||
* bf_set(example_bit_field, &t1, 0);
|
||||
*/
|
||||
#define bf_get_le32(name, ptr) \
|
||||
((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK)
|
||||
#define bf_get(name, ptr) \
|
||||
(((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK)
|
||||
#define bf_set_le32(name, ptr, value) \
|
||||
((ptr)->name##_WORD = cpu_to_le32(((((value) & \
|
||||
name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \
|
||||
~(name##_MASK << name##_SHIFT)))))
|
||||
#define bf_set(name, ptr, value) \
|
||||
((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
|
||||
((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
|
||||
|
@ -781,6 +787,7 @@ struct mbox_header {
|
|||
#define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37
|
||||
#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A
|
||||
#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D
|
||||
#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A
|
||||
|
||||
/* FCoE Opcodes */
|
||||
#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01
|
||||
|
@ -1102,6 +1109,39 @@ struct lpfc_mbx_mq_create {
|
|||
} u;
|
||||
};
|
||||
|
||||
struct lpfc_mbx_mq_create_ext {
|
||||
struct mbox_header header;
|
||||
union {
|
||||
struct {
|
||||
uint32_t word0;
|
||||
#define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0
|
||||
#define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF
|
||||
#define lpfc_mbx_mq_create_ext_num_pages_WORD word0
|
||||
uint32_t async_evt_bmap;
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_link_WORD async_evt_bmap
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT LPFC_TRAILER_CODE_FCOE
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK 0x00000001
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD async_evt_bmap
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT LPFC_TRAILER_CODE_GRP5
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK 0x00000001
|
||||
#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD async_evt_bmap
|
||||
struct mq_context context;
|
||||
struct dma_address page[LPFC_MAX_MQ_PAGE];
|
||||
} request;
|
||||
struct {
|
||||
uint32_t word0;
|
||||
#define lpfc_mbx_mq_create_q_id_SHIFT 0
|
||||
#define lpfc_mbx_mq_create_q_id_MASK 0x0000FFFF
|
||||
#define lpfc_mbx_mq_create_q_id_WORD word0
|
||||
} response;
|
||||
} u;
|
||||
#define LPFC_ASYNC_EVENT_LINK_STATE 0x2
|
||||
#define LPFC_ASYNC_EVENT_FCF_STATE 0x4
|
||||
#define LPFC_ASYNC_EVENT_GROUP5 0x20
|
||||
};
|
||||
|
||||
struct lpfc_mbx_mq_destroy {
|
||||
struct mbox_header header;
|
||||
union {
|
||||
|
@ -1428,8 +1468,8 @@ struct lpfc_mbx_reg_vfi {
|
|||
#define lpfc_reg_vfi_fcfi_WORD word2
|
||||
uint32_t wwn[2];
|
||||
struct ulp_bde64 bde;
|
||||
uint32_t word8_rsvd;
|
||||
uint32_t word9_rsvd;
|
||||
uint32_t e_d_tov;
|
||||
uint32_t r_a_tov;
|
||||
uint32_t word10;
|
||||
#define lpfc_reg_vfi_nport_id_SHIFT 0
|
||||
#define lpfc_reg_vfi_nport_id_MASK 0x00FFFFFF
|
||||
|
@ -1940,6 +1980,7 @@ struct lpfc_mbx_sli4_params {
|
|||
#define rdma_MASK 0x00000001
|
||||
#define rdma_WORD word3
|
||||
uint32_t sge_supp_len;
|
||||
#define SLI4_PAGE_SIZE 4096
|
||||
uint32_t word5;
|
||||
#define if_page_sz_SHIFT 0
|
||||
#define if_page_sz_MASK 0x0000ffff
|
||||
|
@ -2041,6 +2082,7 @@ struct lpfc_mqe {
|
|||
struct lpfc_mbx_reg_fcfi reg_fcfi;
|
||||
struct lpfc_mbx_unreg_fcfi unreg_fcfi;
|
||||
struct lpfc_mbx_mq_create mq_create;
|
||||
struct lpfc_mbx_mq_create_ext mq_create_ext;
|
||||
struct lpfc_mbx_eq_create eq_create;
|
||||
struct lpfc_mbx_cq_create cq_create;
|
||||
struct lpfc_mbx_wq_create wq_create;
|
||||
|
@ -2099,6 +2141,7 @@ struct lpfc_mcqe {
|
|||
#define LPFC_TRAILER_CODE_LINK 0x1
|
||||
#define LPFC_TRAILER_CODE_FCOE 0x2
|
||||
#define LPFC_TRAILER_CODE_DCBX 0x3
|
||||
#define LPFC_TRAILER_CODE_GRP5 0x5
|
||||
};
|
||||
|
||||
struct lpfc_acqe_link {
|
||||
|
@ -2168,6 +2211,19 @@ struct lpfc_acqe_dcbx {
|
|||
uint32_t trailer;
|
||||
};
|
||||
|
||||
struct lpfc_acqe_grp5 {
|
||||
uint32_t word0;
|
||||
#define lpfc_acqe_grp5_pport_SHIFT 0
|
||||
#define lpfc_acqe_grp5_pport_MASK 0x000000FF
|
||||
#define lpfc_acqe_grp5_pport_WORD word0
|
||||
uint32_t word1;
|
||||
#define lpfc_acqe_grp5_llink_spd_SHIFT 16
|
||||
#define lpfc_acqe_grp5_llink_spd_MASK 0x0000FFFF
|
||||
#define lpfc_acqe_grp5_llink_spd_WORD word1
|
||||
uint32_t event_tag;
|
||||
uint32_t trailer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Define the bootstrap mailbox (bmbx) region used to communicate
|
||||
* mailbox command between the host and port. The mailbox consists
|
||||
|
|
|
@ -2566,7 +2566,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
|
|||
shost->max_cmd_len = 16;
|
||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
shost->dma_boundary =
|
||||
phba->sli4_hba.pc_sli4_params.sge_supp_len;
|
||||
phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
|
||||
shost->sg_tablesize = phba->cfg_sg_seg_cnt;
|
||||
}
|
||||
|
||||
|
@ -2600,15 +2600,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
|
|||
init_timer(&vport->els_tmofunc);
|
||||
vport->els_tmofunc.function = lpfc_els_timeout;
|
||||
vport->els_tmofunc.data = (unsigned long)vport;
|
||||
if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
|
||||
phba->menlo_flag |= HBA_MENLO_SUPPORT;
|
||||
/* check for menlo minimum sg count */
|
||||
if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) {
|
||||
phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
|
||||
shost->sg_tablesize = phba->cfg_sg_seg_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
|
||||
if (error)
|
||||
goto out_put_shost;
|
||||
|
@ -3236,12 +3227,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
|
|||
|
||||
if (!vport)
|
||||
return NULL;
|
||||
ndlp = lpfc_findnode_did(vport, Fabric_DID);
|
||||
if (!ndlp)
|
||||
return NULL;
|
||||
phba = vport->phba;
|
||||
if (!phba)
|
||||
return NULL;
|
||||
ndlp = lpfc_findnode_did(vport, Fabric_DID);
|
||||
if (!ndlp) {
|
||||
/* Cannot find existing Fabric ndlp, so allocate a new one */
|
||||
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
|
||||
if (!ndlp)
|
||||
return 0;
|
||||
lpfc_nlp_init(vport, ndlp, Fabric_DID);
|
||||
/* Set the node type */
|
||||
ndlp->nlp_type |= NLP_FABRIC;
|
||||
/* Put ndlp onto node list */
|
||||
lpfc_enqueue_node(vport, ndlp);
|
||||
} else if (!NLP_CHK_NODE_ACT(ndlp)) {
|
||||
/* re-setup ndlp without removing from node list */
|
||||
ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
|
||||
if (!ndlp)
|
||||
return 0;
|
||||
}
|
||||
if (phba->pport->port_state <= LPFC_FLOGI)
|
||||
return NULL;
|
||||
/* If virtual link is not yet instantiated ignore CVL */
|
||||
|
@ -3304,11 +3309,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
|
|||
switch (event_type) {
|
||||
case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
|
||||
case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
|
||||
"2546 New FCF found/FCF parameter modified event: "
|
||||
"evt_tag:x%x, fcf_index:x%x\n",
|
||||
acqe_fcoe->event_tag, acqe_fcoe->index);
|
||||
|
||||
if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
|
||||
LOG_DISCOVERY,
|
||||
"2546 New FCF found event: "
|
||||
"evt_tag:x%x, fcf_index:x%x\n",
|
||||
acqe_fcoe->event_tag,
|
||||
acqe_fcoe->index);
|
||||
else
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
|
||||
LOG_DISCOVERY,
|
||||
"2788 FCF parameter modified event: "
|
||||
"evt_tag:x%x, fcf_index:x%x\n",
|
||||
acqe_fcoe->event_tag,
|
||||
acqe_fcoe->index);
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
|
||||
(phba->hba_flag & FCF_DISC_INPROGRESS)) {
|
||||
|
@ -3516,6 +3530,32 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
|
|||
"handled yet\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
* @acqe_link: pointer to the async grp5 completion queue entry.
|
||||
*
|
||||
* This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event
|
||||
* is an asynchronous notified of a logical link speed change. The Port
|
||||
* reports the logical link speed in units of 10Mbps.
|
||||
**/
|
||||
static void
|
||||
lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba,
|
||||
struct lpfc_acqe_grp5 *acqe_grp5)
|
||||
{
|
||||
uint16_t prev_ll_spd;
|
||||
|
||||
phba->fc_eventTag = acqe_grp5->event_tag;
|
||||
phba->fcoe_eventtag = acqe_grp5->event_tag;
|
||||
prev_ll_spd = phba->sli4_hba.link_state.logical_speed;
|
||||
phba->sli4_hba.link_state.logical_speed =
|
||||
(bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5));
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"2789 GRP5 Async Event: Updating logical link speed "
|
||||
"from %dMbps to %dMbps\n", (prev_ll_spd * 10),
|
||||
(phba->sli4_hba.link_state.logical_speed*10));
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_sli4_async_event_proc - Process all the pending asynchronous event
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
|
@ -3552,6 +3592,10 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
|
|||
lpfc_sli4_async_dcbx_evt(phba,
|
||||
&cq_event->cqe.acqe_dcbx);
|
||||
break;
|
||||
case LPFC_TRAILER_CODE_GRP5:
|
||||
lpfc_sli4_async_grp5_evt(phba,
|
||||
&cq_event->cqe.acqe_grp5);
|
||||
break;
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"1804 Invalid asynchrous event code: "
|
||||
|
@ -3813,6 +3857,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
|
|||
|
||||
/* Get all the module params for configuring this host */
|
||||
lpfc_get_cfgparam(phba);
|
||||
if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
|
||||
phba->menlo_flag |= HBA_MENLO_SUPPORT;
|
||||
/* check for menlo minimum sg count */
|
||||
if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT)
|
||||
phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the sg_tablesize is module parameter, the sg_dma_buf_size
|
||||
* used to create the sg_dma_buf_pool must be dynamically calculated.
|
||||
|
@ -4030,6 +4081,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
|||
if (unlikely(rc))
|
||||
goto out_free_bsmbx;
|
||||
|
||||
mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
|
||||
GFP_KERNEL);
|
||||
if (!mboxq) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_bsmbx;
|
||||
}
|
||||
|
||||
/* Get the Supported Pages. It is always available. */
|
||||
lpfc_supported_pages(mboxq);
|
||||
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
|
||||
if (unlikely(rc)) {
|
||||
rc = -EIO;
|
||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||
goto out_free_bsmbx;
|
||||
}
|
||||
|
||||
mqe = &mboxq->u.mqe;
|
||||
memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
|
||||
LPFC_MAX_SUPPORTED_PAGES);
|
||||
for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
|
||||
switch (pn_page[i]) {
|
||||
case LPFC_SLI4_PARAMETERS:
|
||||
phba->sli4_hba.pc_sli4_params.supported = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the port's SLI4 Parameters capabilities if supported. */
|
||||
if (phba->sli4_hba.pc_sli4_params.supported)
|
||||
rc = lpfc_pc_sli4_params_get(phba, mboxq);
|
||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||
if (rc) {
|
||||
rc = -EIO;
|
||||
goto out_free_bsmbx;
|
||||
}
|
||||
/* Create all the SLI4 queues */
|
||||
rc = lpfc_sli4_queue_create(phba);
|
||||
if (rc)
|
||||
|
@ -4090,43 +4178,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
|||
goto out_free_fcp_eq_hdl;
|
||||
}
|
||||
|
||||
mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
|
||||
GFP_KERNEL);
|
||||
if (!mboxq) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_fcp_eq_hdl;
|
||||
}
|
||||
|
||||
/* Get the Supported Pages. It is always available. */
|
||||
lpfc_supported_pages(mboxq);
|
||||
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
|
||||
if (unlikely(rc)) {
|
||||
rc = -EIO;
|
||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||
goto out_free_fcp_eq_hdl;
|
||||
}
|
||||
|
||||
mqe = &mboxq->u.mqe;
|
||||
memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
|
||||
LPFC_MAX_SUPPORTED_PAGES);
|
||||
for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
|
||||
switch (pn_page[i]) {
|
||||
case LPFC_SLI4_PARAMETERS:
|
||||
phba->sli4_hba.pc_sli4_params.supported = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the port's SLI4 Parameters capabilities if supported. */
|
||||
if (phba->sli4_hba.pc_sli4_params.supported)
|
||||
rc = lpfc_pc_sli4_params_get(phba, mboxq);
|
||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||
if (rc) {
|
||||
rc = -EIO;
|
||||
goto out_free_fcp_eq_hdl;
|
||||
}
|
||||
return rc;
|
||||
|
||||
out_free_fcp_eq_hdl:
|
||||
|
@ -5050,6 +5101,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
|
|||
|
||||
memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
|
||||
phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
|
||||
phba->mbox_ext = (phba->slim2p.virt +
|
||||
offsetof(struct lpfc_sli2_slim, mbx_ext_words));
|
||||
phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
|
||||
phba->IOCBs = (phba->slim2p.virt +
|
||||
offsetof(struct lpfc_sli2_slim, IOCBs));
|
||||
|
@ -7753,21 +7806,23 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
|
|||
* @phba: pointer to lpfc hba data structure.
|
||||
*
|
||||
* This routine is called to prepare the SLI3 device for PCI slot recover. It
|
||||
* aborts and stops all the on-going I/Os on the pci device.
|
||||
* aborts all the outstanding SCSI I/Os to the pci device.
|
||||
**/
|
||||
static void
|
||||
lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
|
||||
{
|
||||
struct lpfc_sli *psli = &phba->sli;
|
||||
struct lpfc_sli_ring *pring;
|
||||
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||
"2723 PCI channel I/O abort preparing for recovery\n");
|
||||
/* Prepare for bringing HBA offline */
|
||||
lpfc_offline_prep(phba);
|
||||
/* Clear sli active flag to prevent sysfs access to HBA */
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
/* Stop and flush all I/Os and bring HBA offline */
|
||||
lpfc_offline(phba);
|
||||
|
||||
/*
|
||||
* There may be errored I/Os through HBA, abort all I/Os on txcmplq
|
||||
* and let the SCSI mid-layer to retry them to recover.
|
||||
*/
|
||||
pring = &psli->ring[psli->fcp_ring];
|
||||
lpfc_sli_abort_iocb_ring(phba, pring);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7781,21 +7836,20 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
|
|||
static void
|
||||
lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
|
||||
{
|
||||
struct lpfc_sli *psli = &phba->sli;
|
||||
struct lpfc_sli_ring *pring;
|
||||
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||
"2710 PCI channel disable preparing for reset\n");
|
||||
|
||||
/* Block all SCSI devices' I/Os on the host */
|
||||
lpfc_scsi_dev_block(phba);
|
||||
|
||||
/* stop all timers */
|
||||
lpfc_stop_hba_timers(phba);
|
||||
|
||||
/* Disable interrupt and pci device */
|
||||
lpfc_sli_disable_intr(phba);
|
||||
pci_disable_device(phba->pcidev);
|
||||
/*
|
||||
* There may be I/Os dropped by the firmware.
|
||||
* Error iocb (I/O) on txcmplq and let the SCSI layer
|
||||
* retry it after re-establishing link.
|
||||
*/
|
||||
pring = &psli->ring[psli->fcp_ring];
|
||||
lpfc_sli_abort_iocb_ring(phba, pring);
|
||||
/* Flush all driver's outstanding SCSI I/Os as we are to reset */
|
||||
lpfc_sli_flush_fcp_rings(phba);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7811,6 +7865,12 @@ lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
|
|||
{
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||
"2711 PCI channel permanent disable for failure\n");
|
||||
/* Block all SCSI devices' I/Os on the host */
|
||||
lpfc_scsi_dev_block(phba);
|
||||
|
||||
/* stop all timers */
|
||||
lpfc_stop_hba_timers(phba);
|
||||
|
||||
/* Clean up all driver's outstanding SCSI I/Os */
|
||||
lpfc_sli_flush_fcp_rings(phba);
|
||||
}
|
||||
|
@ -7839,9 +7899,6 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
|
|||
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
||||
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
||||
|
||||
/* Block all SCSI devices' I/Os on the host */
|
||||
lpfc_scsi_dev_block(phba);
|
||||
|
||||
switch (state) {
|
||||
case pci_channel_io_normal:
|
||||
/* Non-fatal error, prepare for recovery */
|
||||
|
@ -7948,7 +8005,7 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
|
|||
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
||||
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
||||
|
||||
/* Bring the device online */
|
||||
/* Bring device online, it will be no-op for non-fatal error resume */
|
||||
lpfc_online(phba);
|
||||
|
||||
/* Clean up Advanced Error Reporting (AER) if needed */
|
||||
|
|
|
@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||
phba->pcb->feature = FEATURE_INITIAL_SLI2;
|
||||
|
||||
/* Setup Mailbox pointers */
|
||||
phba->pcb->mailBoxSize = sizeof(MAILBOX_t);
|
||||
phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE;
|
||||
offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;
|
||||
pdma_addr = phba->slim2p.phys + offset;
|
||||
phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr);
|
||||
|
@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|||
*
|
||||
*/
|
||||
|
||||
if (phba->sli_rev == 3) {
|
||||
phba->host_gp = &mb_slim->us.s3.host[0];
|
||||
phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
|
||||
} else {
|
||||
phba->host_gp = &mb_slim->us.s2.host[0];
|
||||
if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) {
|
||||
phba->host_gp = &phba->mbox->us.s2.host[0];
|
||||
phba->hbq_put = NULL;
|
||||
}
|
||||
offset = (uint8_t *)&phba->mbox->us.s2.host -
|
||||
(uint8_t *)phba->slim2p.virt;
|
||||
pdma_addr = phba->slim2p.phys + offset;
|
||||
phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr);
|
||||
phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr);
|
||||
} else {
|
||||
/* Always Host Group Pointer is in SLIM */
|
||||
mb->un.varCfgPort.hps = 1;
|
||||
|
||||
/* mask off BAR0's flag bits 0 - 3 */
|
||||
phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
|
||||
(void __iomem *)phba->host_gp -
|
||||
(void __iomem *)phba->MBslimaddr;
|
||||
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
phba->pcb->hgpAddrHigh = bar_high;
|
||||
else
|
||||
phba->pcb->hgpAddrHigh = 0;
|
||||
/* write HGP data to SLIM at the required longword offset */
|
||||
memset(&hgp, 0, sizeof(struct lpfc_hgp));
|
||||
if (phba->sli_rev == 3) {
|
||||
phba->host_gp = &mb_slim->us.s3.host[0];
|
||||
phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
|
||||
} else {
|
||||
phba->host_gp = &mb_slim->us.s2.host[0];
|
||||
phba->hbq_put = NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < phba->sli.num_rings; i++) {
|
||||
lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
|
||||
/* mask off BAR0's flag bits 0 - 3 */
|
||||
phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
|
||||
(void __iomem *)phba->host_gp -
|
||||
(void __iomem *)phba->MBslimaddr;
|
||||
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
phba->pcb->hgpAddrHigh = bar_high;
|
||||
else
|
||||
phba->pcb->hgpAddrHigh = 0;
|
||||
/* write HGP data to SLIM at the required longword offset */
|
||||
memset(&hgp, 0, sizeof(struct lpfc_hgp));
|
||||
|
||||
for (i = 0; i < phba->sli.num_rings; i++) {
|
||||
lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
|
||||
sizeof(*phba->host_gp));
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup Port Group offset */
|
||||
|
@ -1598,7 +1611,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
|
|||
for (sgentry = 0; sgentry < sgecount; sgentry++) {
|
||||
lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);
|
||||
phyaddr = getPaddr(sge.pa_hi, sge.pa_lo);
|
||||
dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE,
|
||||
dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
|
||||
mbox->sge_array->addr[sgentry], phyaddr);
|
||||
}
|
||||
/* Free the sge address array memory */
|
||||
|
@ -1656,7 +1669,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
|
|||
}
|
||||
|
||||
/* Setup for the none-embedded mbox command */
|
||||
pcount = (PAGE_ALIGN(length))/PAGE_SIZE;
|
||||
pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE;
|
||||
pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
|
||||
LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
|
||||
/* Allocate record for keeping SGE virtual addresses */
|
||||
|
@ -1671,24 +1684,24 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
|
|||
for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
|
||||
/* The DMA memory is always allocated in the length of a
|
||||
* page even though the last SGE might not fill up to a
|
||||
* page, this is used as a priori size of PAGE_SIZE for
|
||||
* page, this is used as a priori size of SLI4_PAGE_SIZE for
|
||||
* the later DMA memory free.
|
||||
*/
|
||||
viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE,
|
||||
viraddr = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
|
||||
&phyaddr, GFP_KERNEL);
|
||||
/* In case of malloc fails, proceed with whatever we have */
|
||||
if (!viraddr)
|
||||
break;
|
||||
memset(viraddr, 0, PAGE_SIZE);
|
||||
memset(viraddr, 0, SLI4_PAGE_SIZE);
|
||||
mbox->sge_array->addr[pagen] = viraddr;
|
||||
/* Keep the first page for later sub-header construction */
|
||||
if (pagen == 0)
|
||||
cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;
|
||||
resid_len = length - alloc_len;
|
||||
if (resid_len > PAGE_SIZE) {
|
||||
if (resid_len > SLI4_PAGE_SIZE) {
|
||||
lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
|
||||
PAGE_SIZE);
|
||||
alloc_len += PAGE_SIZE;
|
||||
SLI4_PAGE_SIZE);
|
||||
alloc_len += SLI4_PAGE_SIZE;
|
||||
} else {
|
||||
lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
|
||||
resid_len);
|
||||
|
@ -1886,6 +1899,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
|
|||
memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
|
||||
reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
|
||||
reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
|
||||
reg_vfi->e_d_tov = vport->phba->fc_edtov;
|
||||
reg_vfi->r_a_tov = vport->phba->fc_ratov;
|
||||
reg_vfi->bde.addrHigh = putPaddrHigh(phys);
|
||||
reg_vfi->bde.addrLow = putPaddrLow(phys);
|
||||
reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
|
||||
|
|
|
@ -493,6 +493,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||
struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
|
||||
{
|
||||
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_vport **vports;
|
||||
int i, active_vlink_present = 0 ;
|
||||
|
||||
/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
|
||||
/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
|
||||
|
@ -505,15 +508,44 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||
lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
|
||||
else
|
||||
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
|
||||
if ((ndlp->nlp_DID == Fabric_DID) &&
|
||||
vport->port_type == LPFC_NPIV_PORT) {
|
||||
if (ndlp->nlp_DID == Fabric_DID) {
|
||||
if (vport->port_state <= LPFC_FDISC)
|
||||
goto out;
|
||||
lpfc_linkdown_port(vport);
|
||||
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
|
||||
spin_lock_irq(shost->host_lock);
|
||||
ndlp->nlp_flag |= NLP_DELAY_TMO;
|
||||
vport->fc_flag |= FC_VPORT_LOGO_RCVD;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
vports = lpfc_create_vport_work_array(phba);
|
||||
if (vports) {
|
||||
for (i = 0; i <= phba->max_vports && vports[i] != NULL;
|
||||
i++) {
|
||||
if ((!(vports[i]->fc_flag &
|
||||
FC_VPORT_LOGO_RCVD)) &&
|
||||
(vports[i]->port_state > LPFC_FDISC)) {
|
||||
active_vlink_present = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lpfc_destroy_vport_work_array(phba, vports);
|
||||
}
|
||||
|
||||
ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
|
||||
if (active_vlink_present) {
|
||||
/*
|
||||
* If there are other active VLinks present,
|
||||
* re-instantiate the Vlink using FDISC.
|
||||
*/
|
||||
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
|
||||
spin_lock_irq(shost->host_lock);
|
||||
ndlp->nlp_flag |= NLP_DELAY_TMO;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
|
||||
vport->port_state = LPFC_FDISC;
|
||||
} else {
|
||||
spin_lock_irq(shost->host_lock);
|
||||
phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
lpfc_retry_pport_discovery(phba);
|
||||
}
|
||||
} else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
|
||||
((ndlp->nlp_type & NLP_FCP_TARGET) ||
|
||||
!(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
|
||||
|
@ -526,6 +558,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||
|
||||
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
|
||||
}
|
||||
out:
|
||||
ndlp->nlp_prev_state = ndlp->nlp_state;
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
|
||||
|
||||
|
@ -604,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
|||
lpfc_unreg_rpi(vport, ndlp);
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd.
|
||||
* @phba : Pointer to lpfc_hba structure.
|
||||
* @vport: Pointer to lpfc_vport structure.
|
||||
* @rpi : rpi to be release.
|
||||
*
|
||||
* This function will send a unreg_login mailbox command to the firmware
|
||||
* to release a rpi.
|
||||
**/
|
||||
void
|
||||
lpfc_release_rpi(struct lpfc_hba *phba,
|
||||
struct lpfc_vport *vport,
|
||||
uint16_t rpi)
|
||||
{
|
||||
LPFC_MBOXQ_t *pmb;
|
||||
int rc;
|
||||
|
||||
pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
|
||||
GFP_KERNEL);
|
||||
if (!pmb)
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
|
||||
"2796 mailbox memory allocation failed \n");
|
||||
else {
|
||||
lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
|
||||
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
|
||||
if (rc == MBX_NOT_FINISHED)
|
||||
mempool_free(pmb, phba->mbox_mem_pool);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
void *arg, uint32_t evt)
|
||||
{
|
||||
struct lpfc_hba *phba;
|
||||
LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
|
||||
MAILBOX_t *mb;
|
||||
uint16_t rpi;
|
||||
|
||||
phba = vport->phba;
|
||||
/* Release the RPI if reglogin completing */
|
||||
if (!(phba->pport->load_flag & FC_UNLOADING) &&
|
||||
(evt == NLP_EVT_CMPL_REG_LOGIN) &&
|
||||
(!pmb->u.mb.mbxStatus)) {
|
||||
mb = &pmb->u.mb;
|
||||
rpi = pmb->u.mb.un.varWords[0];
|
||||
lpfc_release_rpi(phba, vport, rpi);
|
||||
}
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
||||
"0271 Illegal State Transition: node x%x "
|
||||
"event x%x, state x%x Data: x%x x%x\n",
|
||||
|
@ -944,6 +1021,18 @@ static uint32_t
|
|||
lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
|
||||
struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
|
||||
{
|
||||
struct lpfc_hba *phba;
|
||||
LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
|
||||
MAILBOX_t *mb = &pmb->u.mb;
|
||||
uint16_t rpi;
|
||||
|
||||
phba = vport->phba;
|
||||
/* Release the RPI */
|
||||
if (!(phba->pport->load_flag & FC_UNLOADING) &&
|
||||
!mb->mbxStatus) {
|
||||
rpi = pmb->u.mb.un.varWords[0];
|
||||
lpfc_release_rpi(phba, vport, rpi);
|
||||
}
|
||||
return ndlp->nlp_state;
|
||||
}
|
||||
|
||||
|
|
|
@ -1141,37 +1141,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;
|
||||
|
||||
}
|
||||
|
@ -1179,12 +1189,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:
|
||||
|
@ -1194,6 +1206,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 {
|
||||
|
@ -1201,7 +1214,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
|
|||
BUG();
|
||||
}
|
||||
|
||||
return ret_prof;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct scsi_dif_tuple {
|
||||
|
@ -1266,7 +1279,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 |
|
||||
* +-------------------------+
|
||||
|
@ -1284,30 +1299,49 @@ 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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* advance bpl and increment bde count */
|
||||
num_bde++;
|
||||
bpl++;
|
||||
|
||||
|
@ -1342,15 +1376,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 |
|
||||
* +-------------------------+
|
||||
* | ... |
|
||||
* +-------------------------+
|
||||
|
@ -1369,19 +1405,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);
|
||||
|
@ -1394,31 +1432,47 @@ 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);
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
||||
|
@ -1429,10 +1483,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++;
|
||||
|
@ -1484,6 +1535,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 ? */
|
||||
|
@ -1506,7 +1558,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
|
|||
|
||||
out:
|
||||
|
||||
|
||||
return num_bde;
|
||||
}
|
||||
/*
|
||||
|
@ -1828,8 +1879,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)
|
||||
|
@ -1937,8 +1988,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)
|
||||
|
|
|
@ -212,7 +212,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
|
|||
struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
|
||||
|
||||
/* If the next EQE is not valid then we are done */
|
||||
if (!bf_get(lpfc_eqe_valid, eqe))
|
||||
if (!bf_get_le32(lpfc_eqe_valid, eqe))
|
||||
return NULL;
|
||||
/* If the host has not yet processed the next entry then we are done */
|
||||
if (((q->hba_index + 1) % q->entry_count) == q->host_index)
|
||||
|
@ -247,7 +247,7 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
|
|||
/* while there are valid entries */
|
||||
while (q->hba_index != q->host_index) {
|
||||
temp_eqe = q->qe[q->host_index].eqe;
|
||||
bf_set(lpfc_eqe_valid, temp_eqe, 0);
|
||||
bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
|
||||
released++;
|
||||
q->host_index = ((q->host_index + 1) % q->entry_count);
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q)
|
|||
struct lpfc_cqe *cqe;
|
||||
|
||||
/* If the next CQE is not valid then we are done */
|
||||
if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
|
||||
if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
|
||||
return NULL;
|
||||
/* If the host has not yet processed the next entry then we are done */
|
||||
if (((q->hba_index + 1) % q->entry_count) == q->host_index)
|
||||
|
@ -321,7 +321,7 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
|
|||
/* while there are valid entries */
|
||||
while (q->hba_index != q->host_index) {
|
||||
temp_qe = q->qe[q->host_index].cqe;
|
||||
bf_set(lpfc_cqe_valid, temp_qe, 0);
|
||||
bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
|
||||
released++;
|
||||
q->host_index = ((q->host_index + 1) % q->entry_count);
|
||||
}
|
||||
|
@ -1659,6 +1659,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
|
|||
case MBX_INIT_VPI:
|
||||
case MBX_INIT_VFI:
|
||||
case MBX_RESUME_RPI:
|
||||
case MBX_READ_EVENT_LOG_STATUS:
|
||||
case MBX_READ_EVENT_LOG:
|
||||
ret = mbxCommand;
|
||||
break;
|
||||
default:
|
||||
|
@ -4296,7 +4298,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
|
|||
"2570 Failed to read FCoE parameters\n");
|
||||
|
||||
/* Issue READ_REV to collect vpd and FW information. */
|
||||
vpd_size = PAGE_SIZE;
|
||||
vpd_size = SLI4_PAGE_SIZE;
|
||||
vpd = kzalloc(vpd_size, GFP_KERNEL);
|
||||
if (!vpd) {
|
||||
rc = -ENOMEM;
|
||||
|
@ -4891,9 +4893,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
|
|||
mb->mbxOwner = OWN_CHIP;
|
||||
|
||||
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
||||
/* First copy command data to host SLIM area */
|
||||
/* Populate mbox extension offset word. */
|
||||
if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) {
|
||||
*(((uint32_t *)mb) + pmbox->mbox_offset_word)
|
||||
= (uint8_t *)phba->mbox_ext
|
||||
- (uint8_t *)phba->mbox;
|
||||
}
|
||||
|
||||
/* Copy the mailbox extension data */
|
||||
if (pmbox->in_ext_byte_len && pmbox->context2) {
|
||||
lpfc_sli_pcimem_bcopy(pmbox->context2,
|
||||
(uint8_t *)phba->mbox_ext,
|
||||
pmbox->in_ext_byte_len);
|
||||
}
|
||||
/* Copy command data to host SLIM area */
|
||||
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
||||
} else {
|
||||
/* Populate mbox extension offset word. */
|
||||
if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len)
|
||||
*(((uint32_t *)mb) + pmbox->mbox_offset_word)
|
||||
= MAILBOX_HBA_EXT_OFFSET;
|
||||
|
||||
/* Copy the mailbox extension data */
|
||||
if (pmbox->in_ext_byte_len && pmbox->context2) {
|
||||
lpfc_memcpy_to_slim(phba->MBslimaddr +
|
||||
MAILBOX_HBA_EXT_OFFSET,
|
||||
pmbox->context2, pmbox->in_ext_byte_len);
|
||||
|
||||
}
|
||||
if (mb->mbxCommand == MBX_CONFIG_PORT) {
|
||||
/* copy command data into host mbox for cmpl */
|
||||
lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
|
||||
|
@ -5003,15 +5030,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
|
|||
if (psli->sli_flag & LPFC_SLI_ACTIVE) {
|
||||
/* copy results back to user */
|
||||
lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
|
||||
/* Copy the mailbox extension data */
|
||||
if (pmbox->out_ext_byte_len && pmbox->context2) {
|
||||
lpfc_sli_pcimem_bcopy(phba->mbox_ext,
|
||||
pmbox->context2,
|
||||
pmbox->out_ext_byte_len);
|
||||
}
|
||||
} else {
|
||||
/* First copy command data */
|
||||
lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
|
||||
MAILBOX_CMD_SIZE);
|
||||
if ((mb->mbxCommand == MBX_DUMP_MEMORY) &&
|
||||
pmbox->context2) {
|
||||
lpfc_memcpy_from_slim((void *)pmbox->context2,
|
||||
phba->MBslimaddr + DMP_RSP_OFFSET,
|
||||
mb->un.varDmp.word_cnt);
|
||||
/* Copy the mailbox extension data */
|
||||
if (pmbox->out_ext_byte_len && pmbox->context2) {
|
||||
lpfc_memcpy_from_slim(pmbox->context2,
|
||||
phba->MBslimaddr +
|
||||
MAILBOX_HBA_EXT_OFFSET,
|
||||
pmbox->out_ext_byte_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7104,13 +7138,11 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
*/
|
||||
list_del_init(&abort_iocb->list);
|
||||
pring->txcmplq_cnt--;
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
/* Firmware could still be in progress of DMAing
|
||||
* payload, so don't free data buffer till after
|
||||
* a hbeat.
|
||||
*/
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
|
||||
abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
@ -7118,7 +7150,8 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||
abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
|
||||
abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
|
||||
(abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
|
||||
}
|
||||
} else
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
}
|
||||
|
||||
lpfc_sli_release_iocbq(phba, cmdiocb);
|
||||
|
@ -8133,6 +8166,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
|
|||
if (pmb->mbox_cmpl) {
|
||||
lpfc_sli_pcimem_bcopy(mbox, pmbox,
|
||||
MAILBOX_CMD_SIZE);
|
||||
if (pmb->out_ext_byte_len &&
|
||||
pmb->context2)
|
||||
lpfc_sli_pcimem_bcopy(
|
||||
phba->mbox_ext,
|
||||
pmb->context2,
|
||||
pmb->out_ext_byte_len);
|
||||
}
|
||||
if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
|
||||
pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
|
||||
|
@ -8983,17 +9022,17 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
|
|||
int ecount = 0;
|
||||
uint16_t cqid;
|
||||
|
||||
if (bf_get(lpfc_eqe_major_code, eqe) != 0) {
|
||||
if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"0359 Not a valid slow-path completion "
|
||||
"event: majorcode=x%x, minorcode=x%x\n",
|
||||
bf_get(lpfc_eqe_major_code, eqe),
|
||||
bf_get(lpfc_eqe_minor_code, eqe));
|
||||
bf_get_le32(lpfc_eqe_major_code, eqe),
|
||||
bf_get_le32(lpfc_eqe_minor_code, eqe));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the reference to the corresponding CQ */
|
||||
cqid = bf_get(lpfc_eqe_resource_id, eqe);
|
||||
cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
|
||||
|
||||
/* Search for completion queue pointer matching this cqid */
|
||||
speq = phba->sli4_hba.sp_eq;
|
||||
|
@ -9221,12 +9260,12 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
|
|||
uint16_t cqid;
|
||||
int ecount = 0;
|
||||
|
||||
if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0)) {
|
||||
if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"0366 Not a valid fast-path completion "
|
||||
"event: majorcode=x%x, minorcode=x%x\n",
|
||||
bf_get(lpfc_eqe_major_code, eqe),
|
||||
bf_get(lpfc_eqe_minor_code, eqe));
|
||||
bf_get_le32(lpfc_eqe_major_code, eqe),
|
||||
bf_get_le32(lpfc_eqe_minor_code, eqe));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -9239,7 +9278,7 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
|
|||
}
|
||||
|
||||
/* Get the reference to the corresponding CQ */
|
||||
cqid = bf_get(lpfc_eqe_resource_id, eqe);
|
||||
cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
|
||||
if (unlikely(cqid != cq->queue_id)) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"0368 Miss-matched fast-path completion "
|
||||
|
@ -9506,7 +9545,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
|
|||
while (!list_empty(&queue->page_list)) {
|
||||
list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
|
||||
list);
|
||||
dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE,
|
||||
dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE,
|
||||
dmabuf->virt, dmabuf->phys);
|
||||
kfree(dmabuf);
|
||||
}
|
||||
|
@ -9532,13 +9571,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
|
|||
struct lpfc_dmabuf *dmabuf;
|
||||
int x, total_qe_count;
|
||||
void *dma_pointer;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
queue = kzalloc(sizeof(struct lpfc_queue) +
|
||||
(sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
|
||||
if (!queue)
|
||||
return NULL;
|
||||
queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE;
|
||||
queue->page_count = (ALIGN(entry_size * entry_count,
|
||||
hw_page_size))/hw_page_size;
|
||||
INIT_LIST_HEAD(&queue->list);
|
||||
INIT_LIST_HEAD(&queue->page_list);
|
||||
INIT_LIST_HEAD(&queue->child_list);
|
||||
|
@ -9547,19 +9590,19 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
|
|||
if (!dmabuf)
|
||||
goto out_fail;
|
||||
dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
|
||||
PAGE_SIZE, &dmabuf->phys,
|
||||
hw_page_size, &dmabuf->phys,
|
||||
GFP_KERNEL);
|
||||
if (!dmabuf->virt) {
|
||||
kfree(dmabuf);
|
||||
goto out_fail;
|
||||
}
|
||||
memset(dmabuf->virt, 0, PAGE_SIZE);
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
dmabuf->buffer_tag = x;
|
||||
list_add_tail(&dmabuf->list, &queue->page_list);
|
||||
/* initialize queue's entry array */
|
||||
dma_pointer = dmabuf->virt;
|
||||
for (; total_qe_count < entry_count &&
|
||||
dma_pointer < (PAGE_SIZE + dmabuf->virt);
|
||||
dma_pointer < (hw_page_size + dmabuf->virt);
|
||||
total_qe_count++, dma_pointer += entry_size) {
|
||||
queue->qe[total_qe_count].address = dma_pointer;
|
||||
}
|
||||
|
@ -9604,6 +9647,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
|
|||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
uint16_t dmult;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!mbox)
|
||||
|
@ -9653,6 +9700,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
|
|||
break;
|
||||
}
|
||||
list_for_each_entry(dmabuf, &eq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
|
@ -9715,6 +9763,11 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
|||
int rc, length, status = 0;
|
||||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
|
||||
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!mbox)
|
||||
|
@ -9752,6 +9805,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
|||
break;
|
||||
}
|
||||
list_for_each_entry(dmabuf, &cq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
|
@ -9791,38 +9845,27 @@ out:
|
|||
}
|
||||
|
||||
/**
|
||||
* lpfc_mq_create - Create a mailbox Queue on the HBA
|
||||
* lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration
|
||||
* @phba: HBA structure that indicates port to create a queue on.
|
||||
* @mq: The queue structure to use to create the mailbox queue.
|
||||
* @mbox: An allocated pointer to type LPFC_MBOXQ_t
|
||||
* @cq: The completion queue to associate with this cq.
|
||||
*
|
||||
* This function creates a mailbox queue, as detailed in @mq, on a port,
|
||||
* described by @phba by sending a MQ_CREATE mailbox command to the HBA.
|
||||
* This function provides failback (fb) functionality when the
|
||||
* mq_create_ext fails on older FW generations. It's purpose is identical
|
||||
* to mq_create_ext otherwise.
|
||||
*
|
||||
* The @phba struct is used to send mailbox command to HBA. The @cq struct
|
||||
* is used to get the entry count and entry size that are necessary to
|
||||
* determine the number of pages to allocate and use for this queue. This
|
||||
* function will send the MQ_CREATE mailbox command to the HBA to setup the
|
||||
* mailbox queue. This function is asynchronous and will wait for the mailbox
|
||||
* command to finish before continuing.
|
||||
*
|
||||
* On success this function will return a zero. If unable to allocate enough
|
||||
* memory this function will return ENOMEM. If the queue create mailbox command
|
||||
* fails this function will return ENXIO.
|
||||
* This routine cannot fail as all attributes were previously accessed and
|
||||
* initialized in mq_create_ext.
|
||||
**/
|
||||
uint32_t
|
||||
lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
||||
struct lpfc_queue *cq, uint32_t subtype)
|
||||
static void
|
||||
lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
||||
LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq)
|
||||
{
|
||||
struct lpfc_mbx_mq_create *mq_create;
|
||||
struct lpfc_dmabuf *dmabuf;
|
||||
LPFC_MBOXQ_t *mbox;
|
||||
int rc, length, status = 0;
|
||||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
int length;
|
||||
|
||||
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!mbox)
|
||||
return -ENOMEM;
|
||||
length = (sizeof(struct lpfc_mbx_mq_create) -
|
||||
sizeof(struct lpfc_sli4_cfg_mhdr));
|
||||
lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
|
||||
|
@ -9830,18 +9873,11 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
|||
length, LPFC_SLI4_MBX_EMBED);
|
||||
mq_create = &mbox->u.mqe.un.mq_create;
|
||||
bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
|
||||
mq->page_count);
|
||||
mq->page_count);
|
||||
bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
|
||||
cq->queue_id);
|
||||
cq->queue_id);
|
||||
bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
|
||||
switch (mq->entry_count) {
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"0362 Unsupported MQ count. (%d)\n",
|
||||
mq->entry_count);
|
||||
if (mq->entry_count < 16)
|
||||
return -EINVAL;
|
||||
/* otherwise default to smallest count (drop through) */
|
||||
case 16:
|
||||
bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
|
||||
LPFC_MQ_CNT_16);
|
||||
|
@ -9861,13 +9897,120 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
|||
}
|
||||
list_for_each_entry(dmabuf, &mq->page_list, list) {
|
||||
mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
putPaddrLow(dmabuf->phys);
|
||||
mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
putPaddrHigh(dmabuf->phys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_mq_create - Create a mailbox Queue on the HBA
|
||||
* @phba: HBA structure that indicates port to create a queue on.
|
||||
* @mq: The queue structure to use to create the mailbox queue.
|
||||
* @cq: The completion queue to associate with this cq.
|
||||
* @subtype: The queue's subtype.
|
||||
*
|
||||
* This function creates a mailbox queue, as detailed in @mq, on a port,
|
||||
* described by @phba by sending a MQ_CREATE mailbox command to the HBA.
|
||||
*
|
||||
* The @phba struct is used to send mailbox command to HBA. The @cq struct
|
||||
* is used to get the entry count and entry size that are necessary to
|
||||
* determine the number of pages to allocate and use for this queue. This
|
||||
* function will send the MQ_CREATE mailbox command to the HBA to setup the
|
||||
* mailbox queue. This function is asynchronous and will wait for the mailbox
|
||||
* command to finish before continuing.
|
||||
*
|
||||
* On success this function will return a zero. If unable to allocate enough
|
||||
* memory this function will return ENOMEM. If the queue create mailbox command
|
||||
* fails this function will return ENXIO.
|
||||
**/
|
||||
int32_t
|
||||
lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
||||
struct lpfc_queue *cq, uint32_t subtype)
|
||||
{
|
||||
struct lpfc_mbx_mq_create *mq_create;
|
||||
struct lpfc_mbx_mq_create_ext *mq_create_ext;
|
||||
struct lpfc_dmabuf *dmabuf;
|
||||
LPFC_MBOXQ_t *mbox;
|
||||
int rc, length, status = 0;
|
||||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!mbox)
|
||||
return -ENOMEM;
|
||||
length = (sizeof(struct lpfc_mbx_mq_create_ext) -
|
||||
sizeof(struct lpfc_sli4_cfg_mhdr));
|
||||
lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
|
||||
LPFC_MBOX_OPCODE_MQ_CREATE_EXT,
|
||||
length, LPFC_SLI4_MBX_EMBED);
|
||||
|
||||
mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
|
||||
bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,
|
||||
mq->page_count);
|
||||
bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request,
|
||||
1);
|
||||
bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste,
|
||||
&mq_create_ext->u.request, 1);
|
||||
bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
|
||||
&mq_create_ext->u.request, 1);
|
||||
bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
|
||||
cq->queue_id);
|
||||
bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
|
||||
switch (mq->entry_count) {
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"0362 Unsupported MQ count. (%d)\n",
|
||||
mq->entry_count);
|
||||
if (mq->entry_count < 16)
|
||||
return -EINVAL;
|
||||
/* otherwise default to smallest count (drop through) */
|
||||
case 16:
|
||||
bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
|
||||
LPFC_MQ_CNT_16);
|
||||
break;
|
||||
case 32:
|
||||
bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
|
||||
LPFC_MQ_CNT_32);
|
||||
break;
|
||||
case 64:
|
||||
bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
|
||||
LPFC_MQ_CNT_64);
|
||||
break;
|
||||
case 128:
|
||||
bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
|
||||
LPFC_MQ_CNT_128);
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(dmabuf, &mq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
putPaddrHigh(dmabuf->phys);
|
||||
}
|
||||
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
|
||||
shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr;
|
||||
mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
|
||||
&mq_create_ext->u.response);
|
||||
if (rc != MBX_SUCCESS) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||
"2795 MQ_CREATE_EXT failed with "
|
||||
"status x%x. Failback to MQ_CREATE.\n",
|
||||
rc);
|
||||
lpfc_mq_create_fb_init(phba, mq, mbox, cq);
|
||||
mq_create = &mbox->u.mqe.un.mq_create;
|
||||
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
|
||||
shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
|
||||
mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
|
||||
&mq_create->u.response);
|
||||
}
|
||||
|
||||
/* The IOCTL status is embedded in the mailbox subheader. */
|
||||
shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
|
||||
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
|
||||
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
|
||||
if (shdr_status || shdr_add_status || rc) {
|
||||
|
@ -9878,7 +10021,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
|
|||
status = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);
|
||||
if (mq->queue_id == 0xFFFF) {
|
||||
status = -ENXIO;
|
||||
goto out;
|
||||
|
@ -9927,6 +10069,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
|
|||
int rc, length, status = 0;
|
||||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!mbox)
|
||||
|
@ -9942,6 +10088,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
|
|||
bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
|
||||
cq->queue_id);
|
||||
list_for_each_entry(dmabuf, &wq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
wq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
|
@ -10010,6 +10157,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
|
|||
int rc, length, status = 0;
|
||||
uint32_t shdr_status, shdr_add_status;
|
||||
union lpfc_sli4_cfg_shdr *shdr;
|
||||
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
|
||||
|
||||
if (!phba->sli4_hba.pc_sli4_params.supported)
|
||||
hw_page_size = SLI4_PAGE_SIZE;
|
||||
|
||||
if (hrq->entry_count != drq->entry_count)
|
||||
return -EINVAL;
|
||||
|
@ -10054,6 +10205,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
|
|||
bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
|
||||
LPFC_HDR_BUF_SIZE);
|
||||
list_for_each_entry(dmabuf, &hrq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
|
||||
putPaddrLow(dmabuf->phys);
|
||||
rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
|
||||
|
@ -10626,7 +10778,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
|
|||
|
||||
reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
|
||||
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
|
||||
if (reqlen > PAGE_SIZE) {
|
||||
if (reqlen > SLI4_PAGE_SIZE) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"2559 Block sgl registration required DMA "
|
||||
"size (%d) great than a page\n", reqlen);
|
||||
|
@ -10732,7 +10884,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
|
|||
/* Calculate the requested length of the dma memory */
|
||||
reqlen = cnt * sizeof(struct sgl_page_pairs) +
|
||||
sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
|
||||
if (reqlen > PAGE_SIZE) {
|
||||
if (reqlen > SLI4_PAGE_SIZE) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"0217 Block sgl registration required DMA "
|
||||
"size (%d) great than a page\n", reqlen);
|
||||
|
@ -11568,8 +11720,8 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
|
|||
*
|
||||
* This routine is invoked to post rpi header templates to the
|
||||
* HBA consistent with the SLI-4 interface spec. This routine
|
||||
* posts a PAGE_SIZE memory region to the port to hold up to
|
||||
* PAGE_SIZE modulo 64 rpi context headers.
|
||||
* posts a SLI4_PAGE_SIZE memory region to the port to hold up to
|
||||
* SLI4_PAGE_SIZE modulo 64 rpi context headers.
|
||||
*
|
||||
* This routine does not require any locks. It's usage is expected
|
||||
* to be driver load or reset recovery when the driver is
|
||||
|
@ -11672,8 +11824,8 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
|
|||
*
|
||||
* This routine is invoked to post rpi header templates to the
|
||||
* HBA consistent with the SLI-4 interface spec. This routine
|
||||
* posts a PAGE_SIZE memory region to the port to hold up to
|
||||
* PAGE_SIZE modulo 64 rpi context headers.
|
||||
* posts a SLI4_PAGE_SIZE memory region to the port to hold up to
|
||||
* SLI4_PAGE_SIZE modulo 64 rpi context headers.
|
||||
*
|
||||
* Returns
|
||||
* A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
|
||||
|
@ -12040,9 +12192,11 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
|
|||
phba->hba_flag |= FCF_DISC_INPROGRESS;
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
/* Reset FCF round robin index bmask for new scan */
|
||||
if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
|
||||
if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) {
|
||||
memset(phba->fcf.fcf_rr_bmask, 0,
|
||||
sizeof(*phba->fcf.fcf_rr_bmask));
|
||||
phba->fcf.eligible_fcf_cnt = 0;
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
fail_fcf_scan:
|
||||
|
@ -12507,6 +12661,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
|
|||
struct lpfc_hba *phba = vport->phba;
|
||||
LPFC_MBOXQ_t *mb, *nextmb;
|
||||
struct lpfc_dmabuf *mp;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
|
||||
|
@ -12523,6 +12678,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
|
|||
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
||||
kfree(mp);
|
||||
}
|
||||
ndlp = (struct lpfc_nodelist *) mb->context2;
|
||||
if (ndlp) {
|
||||
lpfc_nlp_put(ndlp);
|
||||
mb->context2 = NULL;
|
||||
}
|
||||
}
|
||||
list_del(&mb->list);
|
||||
mempool_free(mb, phba->mbox_mem_pool);
|
||||
|
@ -12532,6 +12692,15 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
|
|||
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
|
||||
(mb->u.mb.mbxCommand == MBX_REG_VPI))
|
||||
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
|
||||
ndlp = (struct lpfc_nodelist *) mb->context2;
|
||||
if (ndlp) {
|
||||
lpfc_nlp_put(ndlp);
|
||||
mb->context2 = NULL;
|
||||
}
|
||||
/* Unregister the RPI when mailbox complete */
|
||||
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ struct lpfc_cq_event {
|
|||
struct lpfc_acqe_link acqe_link;
|
||||
struct lpfc_acqe_fcoe acqe_fcoe;
|
||||
struct lpfc_acqe_dcbx acqe_dcbx;
|
||||
struct lpfc_acqe_grp5 acqe_grp5;
|
||||
struct lpfc_rcqe rcqe_cmpl;
|
||||
struct sli4_wcqe_xri_aborted wcqe_axri;
|
||||
struct lpfc_wcqe_complete wcqe_cmpl;
|
||||
|
@ -110,6 +111,9 @@ typedef struct lpfcMboxq {
|
|||
|
||||
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
|
||||
uint8_t mbox_flag;
|
||||
uint16_t in_ext_byte_len;
|
||||
uint16_t out_ext_byte_len;
|
||||
uint8_t mbox_offset_word;
|
||||
struct lpfc_mcqe mcqe;
|
||||
struct lpfc_mbx_nembed_sge_virt *sge_array;
|
||||
} LPFC_MBOXQ_t;
|
||||
|
|
|
@ -162,6 +162,7 @@ struct lpfc_fcf {
|
|||
#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
|
||||
uint32_t addr_mode;
|
||||
uint16_t fcf_rr_init_indx;
|
||||
uint32_t eligible_fcf_cnt;
|
||||
struct lpfc_fcf_rec current_rec;
|
||||
struct lpfc_fcf_rec failover_rec;
|
||||
struct timer_list redisc_wait;
|
||||
|
@ -492,8 +493,8 @@ void lpfc_sli4_queue_free(struct lpfc_queue *);
|
|||
uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
|
||||
uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
|
||||
struct lpfc_queue *, uint32_t, uint32_t);
|
||||
uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
|
||||
struct lpfc_queue *, uint32_t);
|
||||
int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
|
||||
struct lpfc_queue *, uint32_t);
|
||||
uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,
|
||||
struct lpfc_queue *, uint32_t);
|
||||
uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* included with this package. *
|
||||
*******************************************************************/
|
||||
|
||||
#define LPFC_DRIVER_VERSION "8.3.10"
|
||||
#define LPFC_DRIVER_VERSION "8.3.12"
|
||||
#define LPFC_DRIVER_NAME "lpfc"
|
||||
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
|
||||
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
|
||||
|
|
|
@ -763,7 +763,9 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
|
|||
spin_lock_irq(&phba->hbalock);
|
||||
list_for_each_entry(port_iterator, &phba->port_list, listentry) {
|
||||
if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
|
||||
lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT,
|
||||
if (!(port_iterator->load_flag & FC_UNLOADING))
|
||||
lpfc_printf_vlog(port_iterator, KERN_ERR,
|
||||
LOG_VPORT,
|
||||
"1801 Create vport work array FAILED: "
|
||||
"cannot do scsi_host_get\n");
|
||||
continue;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Kernel configuration file for the MPT2SAS
|
||||
#
|
||||
# This code is based on drivers/scsi/mpt2sas/Kconfig
|
||||
# Copyright (C) 2007-2009 LSI Corporation
|
||||
# Copyright (C) 2007-2010 LSI Corporation
|
||||
# (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2009 LSI Corporation.
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2.h
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2009 LSI Corporation.
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_cnfg.h
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Fusion-MPT MPI 2.0 Header File Change History
|
||||
==============================
|
||||
|
||||
Copyright (c) 2000-2009 LSI Corporation.
|
||||
Copyright (c) 2000-2010 LSI Corporation.
|
||||
|
||||
---------------------------------------
|
||||
Header Set Release Version: 02.00.14
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2009 LSI Corporation.
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_init.h
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2009 LSI Corporation.
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_ioc.h
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2009 LSI Corporation.
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_tool.h
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* for access to MPT (Message Passing Technology) firmware.
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -58,6 +58,7 @@
|
|||
#include <linux/sort.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/aer.h>
|
||||
|
||||
#include "mpt2sas_base.h"
|
||||
|
||||
|
@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
|
|||
request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
|
||||
return;
|
||||
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
return;
|
||||
|
||||
switch (ioc_status) {
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
|
|||
desc = "IR Operation Status";
|
||||
break;
|
||||
case MPI2_EVENT_SAS_DISCOVERY:
|
||||
desc = "Discovery";
|
||||
break;
|
||||
{
|
||||
Mpi2EventDataSasDiscovery_t *event_data =
|
||||
(Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
|
||||
printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name,
|
||||
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
|
||||
"start" : "stop");
|
||||
if (event_data->DiscoveryStatus)
|
||||
printk("discovery_status(0x%08x)",
|
||||
le32_to_cpu(event_data->DiscoveryStatus));
|
||||
printk("\n");
|
||||
return;
|
||||
}
|
||||
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
|
||||
desc = "SAS Broadcast Primitive";
|
||||
break;
|
||||
|
@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
goto out_fail;
|
||||
}
|
||||
|
||||
/* AER (Advanced Error Reporting) hooks */
|
||||
pci_enable_pcie_error_reporting(pdev);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (_base_config_dma_addressing(ioc, pdev) != 0) {
|
||||
|
@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
}
|
||||
|
||||
for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
|
||||
if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
|
||||
if (pio_sz)
|
||||
continue;
|
||||
pio_chip = (u64)pci_resource_start(pdev, i);
|
||||
|
@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
} else {
|
||||
if (memap_sz)
|
||||
continue;
|
||||
ioc->chip_phys = pci_resource_start(pdev, i);
|
||||
chip_phys = (u64)ioc->chip_phys;
|
||||
memap_sz = pci_resource_len(pdev, i);
|
||||
ioc->chip = ioremap(ioc->chip_phys, memap_sz);
|
||||
if (ioc->chip == NULL) {
|
||||
printk(MPT2SAS_ERR_FMT "unable to map adapter "
|
||||
"memory!\n", ioc->name);
|
||||
r = -EINVAL;
|
||||
goto out_fail;
|
||||
/* verify memory resource is valid before using */
|
||||
if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
|
||||
ioc->chip_phys = pci_resource_start(pdev, i);
|
||||
chip_phys = (u64)ioc->chip_phys;
|
||||
memap_sz = pci_resource_len(pdev, i);
|
||||
ioc->chip = ioremap(ioc->chip_phys, memap_sz);
|
||||
if (ioc->chip == NULL) {
|
||||
printk(MPT2SAS_ERR_FMT "unable to map "
|
||||
"adapter memory!\n", ioc->name);
|
||||
r = -EINVAL;
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
ioc->chip_phys = 0;
|
||||
ioc->pci_irq = -1;
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return r;
|
||||
}
|
||||
|
@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
|
|||
ioc->config_page, ioc->config_page_dma);
|
||||
}
|
||||
|
||||
kfree(ioc->scsi_lookup);
|
||||
if (ioc->scsi_lookup) {
|
||||
free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages);
|
||||
ioc->scsi_lookup = NULL;
|
||||
}
|
||||
kfree(ioc->hpr_lookup);
|
||||
kfree(ioc->internal_lookup);
|
||||
}
|
||||
|
@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||
ioc->name, (unsigned long long) ioc->request_dma));
|
||||
total_sz += sz;
|
||||
|
||||
ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,
|
||||
sizeof(struct request_tracker), GFP_KERNEL);
|
||||
sz = ioc->scsiio_depth * sizeof(struct request_tracker);
|
||||
ioc->scsi_lookup_pages = get_order(sz);
|
||||
ioc->scsi_lookup = (struct request_tracker *)__get_free_pages(
|
||||
GFP_KERNEL, ioc->scsi_lookup_pages);
|
||||
if (!ioc->scsi_lookup) {
|
||||
printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
|
||||
ioc->name);
|
||||
printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
|
||||
"sz(%d)\n", ioc->name, (int)sz);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||
* since epoch ~ midnight January 1, 1970.
|
||||
*/
|
||||
do_gettimeofday(¤t_time);
|
||||
mpi_request.TimeStamp = (current_time.tv_sec * 1000) +
|
||||
(current_time.tv_usec >> 3);
|
||||
mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 +
|
||||
(current_time.tv_usec / 1000));
|
||||
|
||||
if (ioc->logging_level & MPT_DEBUG_INIT) {
|
||||
u32 *mfp;
|
||||
|
@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|||
mpi_request->VP_ID = 0;
|
||||
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
|
||||
mpi_request->EventMasks[i] =
|
||||
le32_to_cpu(ioc->event_masks[i]);
|
||||
cpu_to_le32(ioc->event_masks[i]);
|
||||
mpt2sas_base_put_smid_default(ioc, smid);
|
||||
init_completion(&ioc->base_cmds.done);
|
||||
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
|
||||
|
@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
__func__));
|
||||
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
||||
ioc->shost_recovery = 0;
|
||||
if (ioc->pci_irq) {
|
||||
synchronize_irq(pdev->irq);
|
||||
free_irq(ioc->pci_irq, ioc);
|
||||
|
@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
|||
ioc->pci_irq = -1;
|
||||
ioc->chip_phys = 0;
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return;
|
||||
}
|
||||
|
@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
|
||||
ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
|
||||
sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
|
||||
if (!ioc->pfacts)
|
||||
if (!ioc->pfacts) {
|
||||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
|
||||
r = _base_get_port_facts(ioc, i, CAN_SLEEP);
|
||||
|
@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
|
||||
mutex_init(&ioc->ctl_cmds.mutex);
|
||||
|
||||
if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
|
||||
!ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
|
||||
!ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
|
||||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
|
||||
init_completion(&ioc->shost_recovery_done);
|
||||
|
||||
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
|
||||
ioc->event_masks[i] = -1;
|
||||
|
||||
|
@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
pci_set_drvdata(ioc->pdev, NULL);
|
||||
kfree(ioc->tm_cmds.reply);
|
||||
kfree(ioc->transport_cmds.reply);
|
||||
kfree(ioc->scsih_cmds.reply);
|
||||
kfree(ioc->config_cmds.reply);
|
||||
kfree(ioc->base_cmds.reply);
|
||||
kfree(ioc->ctl_cmds.reply);
|
||||
|
@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|||
ioc->ctl_cmds.reply = NULL;
|
||||
ioc->base_cmds.reply = NULL;
|
||||
ioc->tm_cmds.reply = NULL;
|
||||
ioc->scsih_cmds.reply = NULL;
|
||||
ioc->transport_cmds.reply = NULL;
|
||||
ioc->config_cmds.reply = NULL;
|
||||
ioc->pfacts = NULL;
|
||||
|
@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
|
|||
kfree(ioc->base_cmds.reply);
|
||||
kfree(ioc->tm_cmds.reply);
|
||||
kfree(ioc->transport_cmds.reply);
|
||||
kfree(ioc->scsih_cmds.reply);
|
||||
kfree(ioc->config_cmds.reply);
|
||||
}
|
||||
|
||||
|
@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
|
|||
|
||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
ioc->shost_recovery = 0;
|
||||
complete(&ioc->shost_recovery_done);
|
||||
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
|
||||
if (!r)
|
||||
_base_reset_handler(ioc, MPT2_IOC_RUNNING);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* for access to MPT (Message Passing Technology) firmware.
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -69,11 +69,11 @@
|
|||
#define MPT2SAS_DRIVER_NAME "mpt2sas"
|
||||
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
|
||||
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
|
||||
#define MPT2SAS_DRIVER_VERSION "04.100.01.00"
|
||||
#define MPT2SAS_MAJOR_VERSION 04
|
||||
#define MPT2SAS_DRIVER_VERSION "05.100.00.02"
|
||||
#define MPT2SAS_MAJOR_VERSION 05
|
||||
#define MPT2SAS_MINOR_VERSION 100
|
||||
#define MPT2SAS_BUILD_VERSION 01
|
||||
#define MPT2SAS_RELEASE_VERSION 00
|
||||
#define MPT2SAS_BUILD_VERSION 00
|
||||
#define MPT2SAS_RELEASE_VERSION 02
|
||||
|
||||
/*
|
||||
* Set MPT2SAS_SG_DEPTH value based on user input.
|
||||
|
@ -119,7 +119,6 @@
|
|||
#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
|
||||
#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
|
||||
#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
|
||||
#define MPT2_IOC_RUNNING 4 /* shost running */
|
||||
|
||||
/*
|
||||
* logging format
|
||||
|
@ -260,16 +259,6 @@ struct _internal_cmd {
|
|||
u16 smid;
|
||||
};
|
||||
|
||||
/*
|
||||
* SAS Topology Structures
|
||||
*/
|
||||
|
||||
#define MPTSAS_STATE_TR_SEND 0x0001
|
||||
#define MPTSAS_STATE_TR_COMPLETE 0x0002
|
||||
#define MPTSAS_STATE_CNTRL_SEND 0x0004
|
||||
#define MPTSAS_STATE_CNTRL_COMPLETE 0x0008
|
||||
|
||||
#define MPT2SAS_REQ_SAS_CNTRL 0x0010
|
||||
|
||||
/**
|
||||
* struct _sas_device - attached device information
|
||||
|
@ -307,7 +296,6 @@ struct _sas_device {
|
|||
u16 slot;
|
||||
u8 hidden_raid_component;
|
||||
u8 responding;
|
||||
u16 state;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -378,6 +366,7 @@ struct _sas_port {
|
|||
* @phy_id: unique phy id
|
||||
* @handle: device handle for this phy
|
||||
* @attached_handle: device handle for attached device
|
||||
* @phy_belongs_to_port: port has been created for this phy
|
||||
*/
|
||||
struct _sas_phy {
|
||||
struct list_head port_siblings;
|
||||
|
@ -387,6 +376,7 @@ struct _sas_phy {
|
|||
u8 phy_id;
|
||||
u16 handle;
|
||||
u16 attached_handle;
|
||||
u8 phy_belongs_to_port;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER {
|
|||
/* fw event handler */
|
||||
char firmware_event_name[20];
|
||||
struct workqueue_struct *firmware_event_thread;
|
||||
u8 fw_events_off;
|
||||
spinlock_t fw_event_lock;
|
||||
struct list_head fw_event_list;
|
||||
|
||||
|
@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER {
|
|||
int aen_event_read_flag;
|
||||
u8 broadcast_aen_busy;
|
||||
u8 shost_recovery;
|
||||
struct completion shost_recovery_done;
|
||||
spinlock_t ioc_reset_in_progress_lock;
|
||||
u8 ioc_link_reset_in_progress;
|
||||
u8 ignore_loginfos;
|
||||
|
@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER {
|
|||
dma_addr_t request_dma;
|
||||
u32 request_dma_sz;
|
||||
struct request_tracker *scsi_lookup;
|
||||
spinlock_t scsi_lookup_lock;
|
||||
ulong scsi_lookup_pages;
|
||||
spinlock_t scsi_lookup_lock;
|
||||
struct list_head free_list;
|
||||
int pending_io_count;
|
||||
wait_queue_head_t reset_wq;
|
||||
|
@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER {
|
|||
u16 max_sges_in_chain_message;
|
||||
u16 chains_needed_per_io;
|
||||
u16 chain_offset_value_for_main_message;
|
||||
u16 chain_depth;
|
||||
u32 chain_depth;
|
||||
|
||||
/* hi-priority queue */
|
||||
u16 hi_priority_smid;
|
||||
|
@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
|
|||
/* scsih shared API */
|
||||
u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply);
|
||||
void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
|
||||
u8 type, u16 smid_task, ulong timeout);
|
||||
int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
|
||||
uint channel, uint id, uint lun, u8 type, u16 smid_task,
|
||||
ulong timeout, struct scsi_cmnd *scmd);
|
||||
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
|
||||
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This module provides common API for accessing firmware configuration pages
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
|
|||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
goto out;
|
||||
for (i = 0; i < config_page->NumElements; i++) {
|
||||
if ((config_page->ConfigElement[i].ElementFlags &
|
||||
if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) &
|
||||
MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=
|
||||
MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
|
||||
continue;
|
||||
if (config_page->ConfigElement[i].PhysDiskDevHandle ==
|
||||
pd_handle) {
|
||||
if (le16_to_cpu(config_page->ConfigElement[i].
|
||||
PhysDiskDevHandle) == pd_handle) {
|
||||
*volume_handle = le16_to_cpu(config_page->
|
||||
ConfigElement[i].VolDevHandle);
|
||||
r = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
|
|||
if (!found) {
|
||||
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
||||
"handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
|
||||
desc, tm_request->DevHandle, lun));
|
||||
desc, le16_to_cpu(tm_request->DevHandle), lun));
|
||||
tm_reply = ioc->ctl_cmds.reply;
|
||||
tm_reply->DevHandle = tm_request->DevHandle;
|
||||
tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
|
||||
|
@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
|
|||
|
||||
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
|
||||
"handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
|
||||
desc, tm_request->DevHandle, lun, tm_request->TaskMID));
|
||||
desc, le16_to_cpu(tm_request->DevHandle), lun,
|
||||
le16_to_cpu(tm_request->TaskMID)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
|
||||
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
|
||||
mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
|
||||
if (!mpi_request->FunctionDependent1 ||
|
||||
mpi_request->FunctionDependent1 >
|
||||
cpu_to_le16(ioc->facts.MaxDevHandle)) {
|
||||
if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
|
||||
le16_to_cpu(mpi_request->FunctionDependent1) >
|
||||
ioc->facts.MaxDevHandle) {
|
||||
ret = -EINVAL;
|
||||
mpt2sas_base_free_smid(ioc, smid);
|
||||
goto out;
|
||||
|
@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
mpt2sas_base_get_sense_buffer_dma(ioc, smid);
|
||||
priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
|
||||
memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
mpt2sas_base_put_smid_scsi_io(ioc, smid,
|
||||
le16_to_cpu(mpi_request->FunctionDependent1));
|
||||
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
|
||||
mpt2sas_base_put_smid_scsi_io(ioc, smid,
|
||||
le16_to_cpu(mpi_request->FunctionDependent1));
|
||||
else
|
||||
mpt2sas_base_put_smid_default(ioc, smid);
|
||||
break;
|
||||
}
|
||||
case MPI2_FUNCTION_SCSI_TASK_MGMT:
|
||||
|
@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
Mpi2SCSITaskManagementRequest_t *tm_request =
|
||||
(Mpi2SCSITaskManagementRequest_t *)mpi_request;
|
||||
|
||||
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
|
||||
"handle(0x%04x), task_type(0x%02x)\n", ioc->name,
|
||||
le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
|
||||
|
||||
if (tm_request->TaskType ==
|
||||
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
|
||||
tm_request->TaskType ==
|
||||
|
@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
}
|
||||
}
|
||||
|
||||
mutex_lock(&ioc->tm_cmds.mutex);
|
||||
mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
|
||||
tm_request->DevHandle));
|
||||
mpt2sas_base_put_smid_hi_priority(ioc, smid);
|
||||
|
@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
|
||||
Mpi2SCSITaskManagementRequest_t *tm_request =
|
||||
(Mpi2SCSITaskManagementRequest_t *)mpi_request;
|
||||
mutex_unlock(&ioc->tm_cmds.mutex);
|
||||
mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
|
||||
tm_request->DevHandle));
|
||||
} else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
|
||||
|
@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
|
|||
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
|
||||
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
|
||||
"= (0x%04x)\n", ioc->name,
|
||||
mpi_request->FunctionDependent1);
|
||||
le16_to_cpu(mpi_request->FunctionDependent1));
|
||||
mpt2sas_halt_firmware(ioc);
|
||||
mutex_lock(&ioc->tm_cmds.mutex);
|
||||
mpt2sas_scsih_issue_tm(ioc,
|
||||
mpi_request->FunctionDependent1, 0,
|
||||
MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
|
||||
le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
|
||||
0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10,
|
||||
NULL);
|
||||
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
|
||||
mutex_unlock(&ioc->tm_cmds.mutex);
|
||||
} else
|
||||
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
|
||||
FORCE_BIG_HAMMER);
|
||||
|
@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
|
|||
|
||||
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
|
||||
"dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
|
||||
(unsigned long long)request_data_dma, mpi_request->BufferLength));
|
||||
(unsigned long long)request_data_dma,
|
||||
le32_to_cpu(mpi_request->BufferLength)));
|
||||
|
||||
for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
|
||||
mpi_request->ProductSpecific[i] =
|
||||
|
@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
|
|||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%02xh\n",
|
||||
le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
|
||||
return snprintf(buf, PAGE_SIZE, "%08xh\n",
|
||||
le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
|
||||
}
|
||||
static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
|
||||
_ctl_version_nvdata_persistent_show, NULL);
|
||||
|
@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev,
|
|||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%02xh\n",
|
||||
le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
|
||||
return snprintf(buf, PAGE_SIZE, "%08xh\n",
|
||||
le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
|
||||
}
|
||||
static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
|
||||
_ctl_version_nvdata_default_show, NULL);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Logging Support for MPT (Message Passing Technology) based controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
|
||||
* Copyright (C) 2007-2009 LSI Corporation
|
||||
* Copyright (C) 2007-2010 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue