提交 33cf23b0 编写于 作者: L Linus Torvalds

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.
  ...
......@@ -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 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
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;
......
此差异已折叠。
......@@ -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,
},
};
/*
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,
......
/*
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
......
/*
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,
......
/*
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;
status = DMA(instance)->ISTR;
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;
struct Scsi_Host *instance = data;
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
unsigned int status = regs->ISTR;
unsigned long flags;
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;
}
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;
/* 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);
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);
/* 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;
/* setup dma direction */
if (!dir_in)
cntr |= CNTR_DDIR;
/* remember direction */
hdata->dma_dir = dir_in;
/* remember direction */
HDATA(cmd->device->host)->dma_dir = dir_in;
regs->CNTR = cntr;
DMA(cmd->device->host)->CNTR = cntr;
/* setup DMA *physical* address */
regs->ACR = addr;
/* 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;
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;
/* 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;
if (!HDATA(instance)->dma_dir)
cntr |= CNTR_DDIR;
/* disable SCSI interrupts */
DMA(instance)->CNTR = cntr;
/* flush if we were reading */
if (HDATA(instance)->dma_dir) {
DMA(instance)->FLUSH = 1;
while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
;
}
/* clear a possible interrupt */
DMA(instance)->CINT = 1;
/* stop DMA */
DMA(instance)->SP_DMA = 1;
/* restore the CONTROL bits (minus the direction flag) */
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
/* 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;
}
struct WD33C93_hostdata *hdata = shost_priv(instance);
a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD;
if (!hdata->dma_dir)
cntr |= CNTR_DDIR;
/* disable SCSI interrupts */
regs->CNTR = cntr;
/* flush if we were reading */
if (hdata->dma_dir) {
regs->FLUSH = 1;
while (!(regs->ISTR & ISTR_FE_FLG))
;
}
/* clear a possible interrupt */
regs->CINT = 1;
/* stop DMA */
regs->SP_DMA = 1;
/* 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;
if (!MACH_IS_AMIGA || called)
return 0;
called = 1;
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;
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;
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;
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;
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 = &regs->SASR;
wdregs.SCMD = &regs->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);
/*
* 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 (!dir_in) {
/* copy to bounce buffer for a write */
memcpy (HDATA(a3000_host)->dma_bounce_buffer,
cmd->SCp.ptr, cmd->SCp.this_residual);
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->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);
}
addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
}
/* setup dma direction */
if (!dir_in)
cntr |= CNTR_DDIR;
/* setup dma direction */
if (!dir_in)
cntr |= CNTR_DDIR;
/* remember direction */
hdata->dma_dir = dir_in;
/* remember direction */
HDATA(a3000_host)->dma_dir = dir_in;
DMA(a3000_host)->CNTR = cntr;
DMA(a3000_host)->CNTR = cntr;
/* setup DMA *physical* address */
DMA(a3000_host)->ACR = addr;
/* 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);
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 */
/* 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;
if (!HDATA(instance)->dma_dir)
cntr |= CNTR_DDIR;
DMA(instance)->CNTR = cntr;
mb(); /* make sure CNTR is updated before next IO */
/* 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 */
}
/* 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;
struct WD33C93_hostdata *hdata = shost_priv(instance);
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD;
if (!hdata->dma_dir)
cntr |= CNTR_DDIR;
DMA(instance)->CNTR = cntr;
mb(); /* make sure CNTR is updated before next IO */
/* 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;
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;
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;
return 1;
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;
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->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;
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 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
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 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
"array deleted" :
"enclosure services event");
}
#endif
break;
case ADD:
if (!scsi_device_online(device)) {
......@@ -1145,12 +1159,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
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 @@ bfad_hal_mem_alloc(struct bfad_s *bfad)
*/
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 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
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 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
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 @@ static inline int fcoe_em_config(struct fc_lport *lport)
/**
* 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 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
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++;
}
......
此差异已折叠。
......@@ -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);
......
此差异已折叠。
此差异已折叠。
......@@ -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))
......
此差异已折叠。
......@@ -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;
}
......
此差异已折叠。
......@@ -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)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -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 *);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册