提交 03da3098 编写于 作者: 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: (276 commits)
  [SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions
  [SCSI] zfcp: Introduce experimental support for DIF/DIX
  [SCSI] zfcp: Enable data division support for FCP devices
  [SCSI] zfcp: Prevent access on uninitialized memory.
  [SCSI] zfcp: Post events through FC transport class
  [SCSI] zfcp: Cleanup QDIO attachment and improve processing.
  [SCSI] zfcp: Cleanup function parameters for sbal value.
  [SCSI] zfcp: Use correct width for timer_interval field
  [SCSI] zfcp: Remove SCSI device when removing unit
  [SCSI] zfcp: Use memdup_user and kstrdup
  [SCSI] zfcp: Fix retry after failed "open port" erp action
  [SCSI] zfcp: Fail erp after timeout
  [SCSI] zfcp: Use forced_reopen in terminate_rport_io callback
  [SCSI] zfcp: Register SCSI devices after successful fc_remote_port_add
  [SCSI] zfcp: Do not try "forced close" when port is already closed
  [SCSI] zfcp: Do not unblock rport from REOPEN_PORT_FORCED
  [SCSI] sd: add support for runtime PM
  [SCSI] implement runtime Power Management
  [SCSI] convert to the new PM framework
  [SCSI] Unify SAM_ and SAM_STAT_ macros
  ...
HPSA - Hewlett Packard Smart Array driver
-----------------------------------------
This file describes the hpsa SCSI driver for HP Smart Array controllers.
The hpsa driver is intended to supplant the cciss driver for newer
Smart Array controllers. The hpsa driver is a SCSI driver, while the
cciss driver is a "block" driver. Actually cciss is both a block
driver (for logical drives) AND a SCSI driver (for tape drives). This
"split-brained" design of the cciss driver is a source of excess
complexity and eliminating that complexity is one of the reasons
for hpsa to exist.
Supported devices:
------------------
Smart Array P212
Smart Array P410
Smart Array P410i
Smart Array P411
Smart Array P812
Smart Array P712m
Smart Array P711m
StorageWorks P1210m
Additionally, older Smart Arrays may work with the hpsa driver if the kernel
boot parameter "hpsa_allow_any=1" is specified, however these are not tested
nor supported by HP with this driver. For older Smart Arrays, the cciss
driver should still be used.
HPSA specific entries in /sys
-----------------------------
In addition to the generic SCSI attributes available in /sys, hpsa supports
the following attributes:
HPSA specific host attributes:
------------------------------
/sys/class/scsi_host/host*/rescan
/sys/class/scsi_host/host*/firmware_revision
the host "rescan" attribute is a write only attribute. Writing to this
attribute will cause the driver to scan for new, changed, or removed devices
(e.g. hot-plugged tape drives, or newly configured or deleted logical drives,
etc.) and notify the SCSI midlayer of any changes detected. Normally this is
triggered automatically by HP's Array Configuration Utility (either the GUI or
command line variety) so for logical drive changes, the user should not
normally have to use this. It may be useful when hot plugging devices like
tape drives, or entire storage boxes containing pre-configured logical drives.
The "firmware_revision" attribute contains the firmware version of the Smart Array.
For example:
root@host:/sys/class/scsi_host/host4# cat firmware_revision
7.14
HPSA specific disk attributes:
------------------------------
/sys/class/scsi_disk/c:b:t:l/device/unique_id
/sys/class/scsi_disk/c:b:t:l/device/raid_level
/sys/class/scsi_disk/c:b:t:l/device/lunid
(where c:b:t:l are the controller, bus, target and lun of the device)
For example:
root@host:/sys/class/scsi_disk/4:0:0:0/device# cat unique_id
600508B1001044395355323037570F77
root@host:/sys/class/scsi_disk/4:0:0:0/device# cat lunid
0x0000004000000000
root@host:/sys/class/scsi_disk/4:0:0:0/device# cat raid_level
RAID 0
HPSA specific ioctls:
---------------------
For compatibility with applications written for the cciss driver, many, but
not all of the ioctls supported by the cciss driver are also supported by the
hpsa driver. The data structures used by these are described in
include/linux/cciss_ioctl.h
CCISS_DEREGDISK
CCISS_REGNEWDISK
CCISS_REGNEWD
The above three ioctls all do exactly the same thing, which is to cause the driver
to rescan for new devices. This does exactly the same thing as writing to the
hpsa specific host "rescan" attribute.
CCISS_GETPCIINFO
Returns PCI domain, bus, device and function and "board ID" (PCI subsystem ID).
CCISS_GETDRIVVER
Returns driver version in three bytes encoded as:
(major_version << 16) | (minor_version << 8) | (subminor_version)
CCISS_PASSTHRU
CCISS_BIG_PASSTHRU
Allows "BMIC" and "CISS" commands to be passed through to the Smart Array.
These are used extensively by the HP Array Configuration Utility, SNMP storage
agents, etc. See cciss_vol_status at http://cciss.sf.net for some examples.
......@@ -2625,6 +2625,14 @@ S: Maintained
F: Documentation/blockdev/cpqarray.txt
F: drivers/block/cpqarray.*
HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa)
M: Stephen M. Cameron <scameron@beardog.cce.hp.com>
L: iss_storagedev@hp.com
S: Supported
F: Documentation/scsi/hpsa.txt
F: drivers/scsi/hpsa*.[ch]
F: include/linux/cciss*.h
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
M: Mike Miller <mike.miller@hp.com>
L: iss_storagedev@hp.com
......
......@@ -84,6 +84,7 @@ struct qdr {
#define QIB_AC_OUTBOUND_PCI_SUPPORTED 0x40
#define QIB_RFLAGS_ENABLE_QEBSM 0x80
#define QIB_RFLAGS_ENABLE_DATA_DIV 0x02
/**
* struct qib - queue information block (QIB)
......@@ -284,6 +285,9 @@ struct slsb {
u8 val[QDIO_MAX_BUFFERS_PER_Q];
} __attribute__ ((packed, aligned(256)));
#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
struct qdio_ssqd_desc {
u8 flags;
u8:8;
......@@ -332,6 +336,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
* @adapter_name: name for the adapter
* @qib_param_field_format: format for qib_parm_field
* @qib_param_field: pointer to 128 bytes or NULL, if no param field
* @qib_rflags: rflags to set
* @input_slib_elements: pointer to no_input_qs * 128 words of data or NULL
* @output_slib_elements: pointer to no_output_qs * 128 words of data or NULL
* @no_input_qs: number of input queues
......@@ -348,6 +353,7 @@ struct qdio_initialize {
unsigned char adapter_name[8];
unsigned int qib_param_field_format;
unsigned char *qib_param_field;
unsigned char qib_rflags;
unsigned long *input_slib_elements;
unsigned long *output_slib_elements;
unsigned int no_input_qs;
......
......@@ -115,6 +115,7 @@ MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
" and halt Firmware on fault - (default=0)");
static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
#ifdef MFCNT
static int mfcounter = 0;
......@@ -213,7 +214,7 @@ static int ProcessEventNotification(MPT_ADAPTER *ioc,
static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
......@@ -490,7 +491,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
else if (ioc->bus_type == SPI)
mpt_spi_log_info(ioc, log_info);
else if (ioc->bus_type == SAS)
mpt_sas_log_info(ioc, log_info);
mpt_sas_log_info(ioc, log_info, cb_idx);
}
if (ioc_stat & MPI_IOCSTATUS_MASK)
......@@ -644,7 +645,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
* considered an error by the caller.
*/
u8
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
{
u8 cb_idx;
last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
......@@ -659,6 +660,8 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
MptDriverClass[cb_idx] = dclass;
MptEvHandlers[cb_idx] = NULL;
last_drv_idx = cb_idx;
memcpy(MptCallbacksName[cb_idx], func_name,
strlen(func_name) > 50 ? 50 : strlen(func_name));
break;
}
}
......@@ -1632,6 +1635,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
} else {
printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
ioc->name, pci_name(pdev));
pci_release_selected_regions(pdev, ioc->bars);
return r;
}
} else {
......@@ -1645,6 +1649,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
} else {
printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
ioc->name, pci_name(pdev));
pci_release_selected_regions(pdev, ioc->bars);
return r;
}
}
......@@ -1675,6 +1680,7 @@ mpt_mapresources(MPT_ADAPTER *ioc)
if (mem == NULL) {
printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
" memory!\n", ioc->name);
pci_release_selected_regions(pdev, ioc->bars);
return -EINVAL;
}
ioc->memmap = mem;
......@@ -1770,7 +1776,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
ioc->pcidev = pdev;
spin_lock_init(&ioc->taskmgmt_lock);
mutex_init(&ioc->internal_cmds.mutex);
......@@ -1913,6 +1918,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->msi_enable = 0;
break;
}
ioc->fw_events_off = 1;
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
......@@ -2051,7 +2059,6 @@ mpt_detach(struct pci_dev *pdev)
mpt_adapter_dispose(ioc);
pci_set_drvdata(pdev, NULL);
}
/**************************************************************************
......@@ -5062,8 +5069,9 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
goto out;
if (!timeleft) {
printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
ioc->name, __func__);
printk(MYIOC_s_WARN_FMT
"Issuing Reset from %s!!, doorbell=0x%08x\n",
ioc->name, __func__, mpt_GetIocState(ioc, 0));
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
......@@ -6454,8 +6462,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
mutex_unlock(&ioc->mptbase_cmds.mutex);
if (issue_hard_reset) {
issue_hard_reset = 0;
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
ioc->name, __func__);
printk(MYIOC_s_WARN_FMT
"Issuing Reset from %s!!, doorbell=0x%08x\n",
ioc->name, __func__, mpt_GetIocState(ioc, 0));
if (retry_count == 0) {
if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
retry_count++;
......@@ -6971,6 +6980,7 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
if (ioc->taskmgmt_in_progress) {
ioc->ioc_reset_in_progress = 0;
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
return -1;
}
......@@ -7144,7 +7154,8 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
if (rc != 0) {
printk(KERN_WARNING MYNAM
": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
rc, ioc->name, mpt_GetIocState(ioc, 0));
} else {
if (ioc->hard_resets < -1)
ioc->hard_resets++;
......@@ -7997,7 +8008,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
* Refer to lsi/mpi_log_sas.h.
**/
static void
mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
{
union loginfo_type {
u32 loginfo;
......@@ -8051,21 +8062,22 @@ union loginfo_type {
if (sub_code_desc != NULL)
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code={%s},"
" SubCode={%s}\n",
" SubCode={%s} cb_idx %s\n",
ioc->name, log_info, originator_desc, code_desc,
sub_code_desc);
sub_code_desc, MptCallbacksName[cb_idx]);
else if (code_desc != NULL)
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code={%s},"
" SubCode(0x%04x)\n",
" SubCode(0x%04x) cb_idx %s\n",
ioc->name, log_info, originator_desc, code_desc,
sas_loginfo.dw.subcode);
sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
else
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
" SubCode(0x%04x)\n",
" SubCode(0x%04x) cb_idx %s\n",
ioc->name, log_info, originator_desc,
sas_loginfo.dw.code, sas_loginfo.dw.subcode);
sas_loginfo.dw.code, sas_loginfo.dw.subcode,
MptCallbacksName[cb_idx]);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
......@@ -8430,7 +8442,8 @@ fusion_init(void)
/* Register ourselves (mptbase) in order to facilitate
* EventNotification handling.
*/
mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
"mptbase_reply");
/* Register for hard reset handling callbacks.
*/
......
......@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
#define MPT_LINUX_VERSION_COMMON "3.04.15"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.15"
#define MPT_LINUX_VERSION_COMMON "3.04.17"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.17"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
......@@ -396,6 +396,8 @@ typedef struct _VirtTarget {
u8 raidVolume; /* set, if RAID Volume */
u8 type; /* byte 0 of Inquiry data */
u8 deleted; /* target in process of being removed */
u8 inDMD; /* currently in the device
removal delay timer */
u32 num_luns;
} VirtTarget;
......@@ -580,6 +582,7 @@ struct mptfc_rport_info
typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
dma_addr_t dma_addr);
typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc);
/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
......@@ -601,7 +604,7 @@ typedef struct _MPT_ADAPTER
u16 nvdata_version_default;
int debug_level;
u8 io_missing_delay;
u8 device_missing_delay;
u16 device_missing_delay;
SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
u8 bus_type;
......@@ -738,6 +741,7 @@ typedef struct _MPT_ADAPTER
int taskmgmt_in_progress;
u8 taskmgmt_quiesce_io;
u8 ioc_reset_in_progress;
MPT_SCHEDULE_TARGET_RESET schedule_target_reset;
struct work_struct sas_persist_task;
struct work_struct fc_setup_reset_work;
......@@ -922,7 +926,8 @@ extern void mpt_detach(struct pci_dev *pdev);
extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mpt_resume(struct pci_dev *pdev);
#endif
extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass,
char *func_name);
extern void mpt_deregister(u8 cb_idx);
extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
extern void mpt_event_deregister(u8 cb_idx);
......
......@@ -261,10 +261,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
/* We are done, issue wake up
*/
if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->ioctl_cmds.done);
ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->ioctl_cmds.done);
if (ioc->bus_type == SAS)
ioc->schedule_target_reset(ioc);
} else {
ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->ioctl_cmds.done);
}
}
out_continuation:
......@@ -298,6 +304,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
if (ioc->bus_type == SAS)
ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
......@@ -946,9 +954,12 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
mpt_free_msg_frame(iocp, mf);
goto fwdl_out;
}
if (!timeleft)
if (!timeleft) {
printk(MYIOC_s_WARN_FMT
"FW download timeout, doorbell=0x%08x\n",
iocp->name, mpt_GetIocState(iocp, 0));
mptctl_timeout_expired(iocp, mf);
else
} else
goto retry_wait;
goto fwdl_out;
}
......@@ -2293,6 +2304,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
goto done_free_mem;
}
if (!timeleft) {
printk(MYIOC_s_WARN_FMT
"mpt cmd timeout, doorbell=0x%08x"
" function=0x%x\n",
ioc->name, mpt_GetIocState(ioc, 0), function);
if (function == MPI_FUNCTION_SCSI_TASK_MGMT)
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
mptctl_timeout_expired(ioc, mf);
......@@ -2600,9 +2615,12 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
mpt_free_msg_frame(ioc, mf);
goto out;
}
if (!timeleft)
if (!timeleft) {
printk(MYIOC_s_WARN_FMT
"HOST INFO command timeout, doorbell=0x%08x\n",
ioc->name, mpt_GetIocState(ioc, 0));
mptctl_timeout_expired(ioc, mf);
else
} else
goto retry_wait;
goto out;
}
......@@ -3000,7 +3018,8 @@ static int __init mptctl_init(void)
* Install our handler
*/
++where;
mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER,
"mptctl_reply");
if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
misc_deregister(&mptctl_miscdev);
......@@ -3008,7 +3027,8 @@ static int __init mptctl_init(void)
goto out_fail;
}
mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER,
"mptctl_taskmgmt_reply");
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);
......
......@@ -1472,9 +1472,12 @@ mptfc_init(void)
if (!mptfc_transport_template)
return -ENODEV;
mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER,
"mptscsih_scandv_complete");
mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER,
"mptscsih_scandv_complete");
mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER,
"mptscsih_scandv_complete");
mpt_event_register(mptfcDoneCtx, mptfc_event_process);
mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
......
......@@ -1452,7 +1452,9 @@ static int __init mpt_lan_init (void)
{
show_mptmod_ver(LANAME, LANVER);
if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) {
LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER,
"lan_reply");
if (LanCtx <= 0) {
printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n");
return -EBUSY;
}
......
......@@ -57,6 +57,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_dbg.h>
#include "mptbase.h"
......@@ -126,6 +127,7 @@ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
void mptsas_schedule_target_reset(void *ioc);
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
......@@ -1138,6 +1140,44 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
}
}
/**
* mptsas_schedule_target_reset- send pending target reset
* @iocp: per adapter object
*
* This function will delete scheduled target reset from the list and
* try to send next target reset. This will be called from completion
* context of any Task managment command.
*/
void
mptsas_schedule_target_reset(void *iocp)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
struct list_head *head = &hd->target_reset_list;
struct mptsas_target_reset_event *target_reset_list;
u8 id, channel;
/*
* issue target reset to next device in the queue
*/
head = &hd->target_reset_list;
if (list_empty(head))
return;
target_reset_list = list_entry(head->next,
struct mptsas_target_reset_event, list);
id = target_reset_list->sas_event_data.TargetID;
channel = target_reset_list->sas_event_data.Bus;
target_reset_list->time_count = jiffies;
if (mptsas_target_reset(ioc, channel, id))
target_reset_list->target_reset_issued = 1;
return;
}
/**
* mptsas_taskmgmt_complete - complete SAS task management function
* @ioc: Pointer to MPT_ADAPTER structure
......@@ -1222,28 +1262,12 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* enable work queue to remove device from upper layers
*/
list_del(&target_reset_list->list);
if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
if (!ioc->fw_events_off)
mptsas_queue_device_delete(ioc,
&target_reset_list->sas_event_data);
/*
* issue target reset to next device in the queue
*/
head = &hd->target_reset_list;
if (list_empty(head))
return 1;
target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
list);
id = target_reset_list->sas_event_data.TargetID;
channel = target_reset_list->sas_event_data.Bus;
target_reset_list->time_count = jiffies;
if (mptsas_target_reset(ioc, channel, id))
target_reset_list->target_reset_issued = 1;
ioc->schedule_target_reset(ioc);
return 1;
}
......@@ -1889,6 +1913,48 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return mptscsih_qcmd(SCpnt,done);
}
/**
* mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
* if the device under question is currently in the
* device removal delay.
* @sc: scsi command that the midlayer is about to time out
*
**/
static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
{
MPT_SCSI_HOST *hd;
MPT_ADAPTER *ioc;
VirtDevice *vdevice;
enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
hd = shost_priv(sc->device->host);
if (hd == NULL) {
printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
__func__, sc);
goto done;
}
ioc = hd->ioc;
if (ioc->bus_type != SAS) {
printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
__func__, sc);
goto done;
}
vdevice = sc->device->hostdata;
if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
|| vdevice->vtarget->deleted)) {
dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
"or in device removal delay (sc=%p)\n",
ioc->name, __func__, sc));
rc = BLK_EH_RESET_TIMER;
goto done;
}
done:
return rc;
}
static struct scsi_host_template mptsas_driver_template = {
.module = THIS_MODULE,
......@@ -2364,7 +2430,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
SasIOUnitPage1_t *buffer;
dma_addr_t dma_handle;
int error;
u16 device_missing_delay;
u8 device_missing_delay;
memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
memset(&cfg, 0, sizeof(CONFIGPARMS));
......@@ -2401,7 +2467,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
ioc->io_missing_delay =
le16_to_cpu(buffer->IODeviceMissingDelay);
device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
device_missing_delay = buffer->ReportDeviceMissingDelay;
ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
(device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
......@@ -2549,6 +2615,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
device_info->sas_address = le64_to_cpu(sas_address);
device_info->device_info =
le32_to_cpu(buffer->DeviceInfo);
device_info->flags = le16_to_cpu(buffer->Flags);
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
......@@ -2960,6 +3027,7 @@ static int mptsas_probe_one_phy(struct device *dev,
struct sas_phy *phy;
struct sas_port *port;
int error = 0;
VirtTarget *vtarget;
if (!dev) {
error = -ENODEV;
......@@ -3182,6 +3250,16 @@ static int mptsas_probe_one_phy(struct device *dev,
rphy_to_expander_device(rphy));
}
/* If the device exists,verify it wasn't previously flagged
as a missing device. If so, clear it */
vtarget = mptsas_find_vtarget(ioc,
phy_info->attached.channel,
phy_info->attached.id);
if (vtarget && vtarget->inDMD) {
printk(KERN_INFO "Device returned, unsetting inDMD\n");
vtarget->inDMD = 0;
}
out:
return error;
}
......@@ -3635,9 +3713,42 @@ mptsas_send_link_status_event(struct fw_event_work *fw_event)
MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
phy_info->phy->negotiated_linkrate =
SAS_LINK_RATE_FAILED;
else
else {
phy_info->phy->negotiated_linkrate =
SAS_LINK_RATE_UNKNOWN;
if (ioc->device_missing_delay &&
mptsas_is_end_device(&phy_info->attached)) {
struct scsi_device *sdev;
VirtDevice *vdevice;
u8 channel, id;
id = phy_info->attached.id;
channel = phy_info->attached.channel;
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Link down for fw_id %d:fw_channel %d\n",
ioc->name, phy_info->attached.id,
phy_info->attached.channel));
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 ||
vdevice->vtarget->raidVolume))
continue;
if (vdevice->vtarget->id == id &&
vdevice->vtarget->channel ==
channel)
devtprintk(ioc,
printk(MYIOC_s_DEBUG_FMT
"SDEV OUTSTANDING CMDS"
"%d\n", ioc->name,
sdev->device_busy));
}
}
}
}
out:
mptsas_free_fw_event(ioc, fw_event);
......@@ -3840,6 +3951,13 @@ mptsas_probe_devices(MPT_ADAPTER *ioc)
MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
continue;
/* If there is no FW B_T mapping for this device then continue
* */
if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
|| !(sas_device.flags &
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
continue;
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
if (!phy_info)
continue;
......@@ -4149,6 +4267,14 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
phys_disk.PhysDiskID))
continue;
/* If there is no FW B_T mapping for this device then continue
* */
if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
|| !(sas_device.flags &
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
continue;
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
mptsas_add_end_device(ioc, phy_info);
......@@ -4171,6 +4297,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
struct mptsas_devinfo sas_device;
VirtTarget *vtarget;
int i;
struct mptsas_portinfo *port_info;
switch (hot_plug_info->event_type) {
......@@ -4199,12 +4326,47 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
(hot_plug_info->channel << 8) +
hot_plug_info->id);
/* If there is no FW B_T mapping for this device then break
* */
if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
|| !(sas_device.flags &
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
break;
if (!sas_device.handle)
return;
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
if (!phy_info)
/* Only For SATA Device ADD */
if (!phy_info && (sas_device.device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s %d SATA HOT PLUG: "
"parent handle of device %x\n", ioc->name,
__func__, __LINE__, sas_device.handle_parent));
port_info = mptsas_find_portinfo_by_handle(ioc,
sas_device.handle_parent);
if (port_info == ioc->hba_port_info)
mptsas_probe_hba_phys(ioc);
else if (port_info)
mptsas_expander_refresh(ioc, port_info);
else {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s %d port info is NULL\n",
ioc->name, __func__, __LINE__));
break;
}
phy_info = mptsas_refreshing_device_handles
(ioc, &sas_device);
}
if (!phy_info) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s %d phy info is NULL\n",
ioc->name, __func__, __LINE__));
break;
}
if (mptsas_get_rphy(phy_info))
break;
......@@ -4241,6 +4403,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
/* If there is no FW B_T mapping for this device then break
* */
if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
|| !(sas_device.flags &
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
break;
phy_info = mptsas_find_phyinfo_by_sas_address(
ioc, sas_device.sas_address);
......@@ -4294,6 +4463,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
/* If there is no FW B_T mapping for this device then break
* */
if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
|| !(sas_device.flags &
MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
break;
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
if (!phy_info) {
......@@ -4727,8 +4903,9 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
mutex_unlock(&ioc->taskmgmt_cmds.mutex);
if (issue_reset) {
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
ioc->name, __func__);
printk(MYIOC_s_WARN_FMT
"Issuing Reset from %s!! doorbell=0x%08x\n",
ioc->name, __func__, mpt_GetIocState(ioc, 0));
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
}
mptsas_free_fw_event(ioc, fw_event);
......@@ -4816,12 +4993,47 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
u16 ioc_stat;
ioc_stat = le16_to_cpu(reply->IOCStatus);
if (sas_event_data->ReasonCode ==
MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
mptsas_target_reset_queue(ioc, sas_event_data);
return 0;
}
if (sas_event_data->ReasonCode ==
MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
ioc->device_missing_delay &&
(ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
VirtTarget *vtarget = NULL;
u8 id, channel;
u32 log_info = le32_to_cpu(reply->IOCLogInfo);
id = sas_event_data->TargetID;
channel = sas_event_data->Bus;
vtarget = mptsas_find_vtarget(ioc, channel, id);
if (vtarget) {
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"LogInfo (0x%x) available for "
"INTERNAL_DEVICE_RESET"
"fw_id %d fw_channel %d\n", ioc->name,
log_info, id, channel));
if (vtarget->raidVolume) {
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Skipping Raid Volume for inDMD\n",
ioc->name));
} else {
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Setting device flag inDMD\n",
ioc->name));
vtarget->inDMD = 1;
}
}
}
break;
}
case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
......@@ -4924,7 +5136,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->DoneCtx = mptsasDoneCtx;
ioc->TaskCtx = mptsasTaskCtx;
ioc->InternalCtx = mptsasInternalCtx;
ioc->schedule_target_reset = &mptsas_schedule_target_reset;
/* Added sanity check on readiness of the MPT adapter.
*/
if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
......@@ -5154,14 +5366,20 @@ mptsas_init(void)
sas_attach_transport(&mptsas_transport_functions);
if (!mptsas_transport_template)
return -ENODEV;
mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
"mptscsih_io_done");
mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
"mptscsih_taskmgmt_complete");
mptsasInternalCtx =
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
"mptscsih_scandv_complete");
mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
"mptsas_mgmt_done");
mptsasDeviceResetCtx =
mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
"mptsas_taskmgmt_complete");
mpt_event_register(mptsasDoneCtx, mptsas_event_process);
mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
......
......@@ -140,6 +140,7 @@ struct mptsas_devinfo {
u64 sas_address; /* WWN of this device,
SATA is assigned by HBA,expander */
u32 device_info; /* bitfield detailed info about this device */
u16 flags; /* sas device pg0 flags */
};
/*
......
......@@ -664,6 +664,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
u32 log_info;
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
......@@ -738,13 +739,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
if ( ioc->bus_type == SAS ) {
u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
if ((log_info & SAS_LOGINFO_MASK)
== SAS_LOGINFO_NEXUS_LOSS) {
sc->result = (DID_BUS_BUSY << 16);
break;
}
u16 ioc_status =
le16_to_cpu(pScsiReply->IOCStatus);
if ((ioc_status &
MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
&&
((log_info & SAS_LOGINFO_MASK) ==
SAS_LOGINFO_NEXUS_LOSS)) {
VirtDevice *vdevice =
sc->device->hostdata;
/* flag the device as being in
* device removal delay so we can
* notify the midlayer to hold off
* on timeout eh */
if (vdevice && vdevice->
vtarget &&
vdevice->vtarget->
raidVolume)
printk(KERN_INFO
"Skipping Raid Volume"
"for inDMD\n");
else if (vdevice &&
vdevice->vtarget)
vdevice->vtarget->
inDMD = 1;
sc->result =
(DID_TRANSPORT_DISRUPTED
<< 16);
break;
}
} else if (ioc->bus_type == FC) {
/*
......@@ -1704,8 +1728,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
if (issue_hard_reset) {
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
ioc->name, __func__);
printk(MYIOC_s_WARN_FMT
"Issuing Reset from %s!! doorbell=0x%08x\n",
ioc->name, __func__, mpt_GetIocState(ioc, 0));
retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
......@@ -2132,6 +2157,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
if (ioc->bus_type == SAS)
ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
......@@ -2459,6 +2486,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
return 0;
}
......@@ -3045,8 +3074,11 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
goto out;
}
if (!timeleft) {
printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
ioc->name, __func__);
printk(MYIOC_s_WARN_FMT
"Issuing Reset from %s!! doorbell=0x%08xh"
" cmd=0x%02x\n",
ioc->name, __func__, mpt_GetIocState(ioc, 0),
cmd);
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
mpt_free_msg_frame(ioc, mf);
}
......
......@@ -1551,9 +1551,12 @@ mptspi_init(void)
if (!mptspi_transport_template)
return -ENODEV;
mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
"mptscsih_io_done");
mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
"mptscsih_taskmgmt_complete");
mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
MPTSPI_DRIVER, "mptscsih_scandv_complete");
mpt_event_register(mptspiDoneCtx, mptspi_event_process);
mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
......
......@@ -285,8 +285,11 @@ enclosure_component_register(struct enclosure_device *edev,
cdev->groups = enclosure_groups;
err = device_register(cdev);
if (err)
ERR_PTR(err);
if (err) {
ecomp->number = -1;
put_device(cdev);
return ERR_PTR(err);
}
return ecomp;
}
......
......@@ -368,6 +368,8 @@ static void setup_qib(struct qdio_irq *irq_ptr,
if (qebsm_possible())
irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM;
irq_ptr->qib.rflags |= init_data->qib_rflags;
irq_ptr->qib.qfmt = init_data->q_format;
if (init_data->no_input_qs)
irq_ptr->qib.isliba =
......
......@@ -98,13 +98,11 @@ static void __init zfcp_init_device_setup(char *devstr)
u64 wwpn, lun;
/* duplicate devstr and keep the original for sysfs presentation*/
str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL);
str_saved = kstrdup(devstr, GFP_KERNEL);
str = str_saved;
if (!str)
return;
strcpy(str, devstr);
token = strsep(&str, ",");
if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE)
goto err_out;
......@@ -314,7 +312,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
}
retval = -EINVAL;
INIT_WORK(&unit->scsi_work, zfcp_scsi_scan);
INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work);
spin_lock_init(&unit->latencies.lock);
unit->latencies.write.channel.min = 0xFFFFFFFF;
......@@ -526,6 +524,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
rwlock_init(&adapter->port_list_lock);
INIT_LIST_HEAD(&adapter->port_list);
INIT_LIST_HEAD(&adapter->events.list);
INIT_WORK(&adapter->events.work, zfcp_fc_post_event);
spin_lock_init(&adapter->events.list_lock);
init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh);
......
......@@ -189,18 +189,12 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
if (!fsf_cfdc)
return -ENOMEM;
data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL);
if (!data) {
retval = -ENOMEM;
data = memdup_user(data_user, sizeof(*data_user));
if (IS_ERR(data)) {
retval = PTR_ERR(data);
goto no_mem_sense;
}
retval = copy_from_user(data, data_user, sizeof(*data));
if (retval) {
retval = -EFAULT;
goto free_buffer;
}
if (data->signature != 0xCFDCACDF) {
retval = -EINVAL;
goto free_buffer;
......
......@@ -155,6 +155,8 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
if (scsi_cmnd) {
response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
response->u.fcp.serial = scsi_cmnd->serial_number;
response->u.fcp.data_dir =
qtcb->bottom.io.data_direction;
}
break;
......@@ -326,6 +328,7 @@ static void zfcp_dbf_hba_view_response(char **p,
case FSF_QTCB_FCP_CMND:
if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
break;
zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
*p += sprintf(*p, "\n");
......@@ -1005,7 +1008,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter)
char dbf_name[DEBUG_MAX_NAME_LEN];
struct zfcp_dbf *dbf;
dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL);
if (!dbf)
return -ENOMEM;
......
......@@ -111,6 +111,7 @@ struct zfcp_dbf_hba_record_response {
struct {
u64 cmnd;
u64 serial;
u32 data_dir;
} fcp;
struct {
u64 wwpn;
......
......@@ -37,6 +37,7 @@
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
#include "zfcp_fsf.h"
#include "zfcp_fc.h"
#include "zfcp_qdio.h"
struct zfcp_reqlist;
......@@ -72,10 +73,12 @@ struct zfcp_reqlist;
/* adapter status */
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400
/* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
......@@ -190,6 +193,7 @@ struct zfcp_adapter {
struct service_level service_level;
struct workqueue_struct *work_queue;
struct device_dma_parameters dma_parms;
struct zfcp_fc_events events;
};
struct zfcp_port {
......@@ -212,6 +216,7 @@ struct zfcp_port {
struct work_struct test_link_work;
struct work_struct rport_work;
enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task;
unsigned int starget_id;
};
struct zfcp_unit {
......
......@@ -141,8 +141,12 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
need = ZFCP_ERP_ACTION_REOPEN_PORT;
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_PORT:
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
p_status = atomic_read(&port->status);
if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
need = ZFCP_ERP_ACTION_REOPEN_PORT;
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_PORT:
p_status = atomic_read(&port->status);
if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0;
......@@ -893,8 +897,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
}
if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
port->d_id = 0;
_zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
return ZFCP_ERP_EXIT;
return ZFCP_ERP_FAILED;
}
/* fall through otherwise */
}
......@@ -1188,19 +1191,14 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
switch (act->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT:
if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
get_device(&unit->dev);
if (scsi_queue_work(unit->port->adapter->scsi_host,
&unit->scsi_work) <= 0)
put_device(&unit->dev);
}
put_device(&unit->dev);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
if (result == ZFCP_ERP_SUCCEEDED)
zfcp_scsi_schedule_rport_register(port);
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
put_device(&port->dev);
break;
......@@ -1247,6 +1245,11 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
retval = ZFCP_ERP_FAILED;
goto check_target;
}
zfcp_erp_action_to_running(erp_action);
/* no lock to allow for blocking operations */
......@@ -1279,6 +1282,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
goto unlock;
}
check_target:
retval = zfcp_erp_strategy_check_target(erp_action, retval);
zfcp_erp_action_dequeue(erp_action);
retval = zfcp_erp_strategy_statechange(erp_action, retval);
......
......@@ -96,6 +96,9 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
extern void zfcp_erp_timeout_handler(unsigned long);
/* zfcp_fc.c */
extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,
enum fc_host_event_code event_code, u32);
extern void zfcp_fc_post_event(struct work_struct *);
extern void zfcp_fc_scan_ports(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fc_port_did_lookup(struct work_struct *);
......@@ -146,9 +149,10 @@ 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 *,
struct scatterlist *, int);
struct scatterlist *);
extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_qdio *);
extern void zfcp_qdio_siosl(struct zfcp_adapter *);
/* zfcp_scsi.c */
extern struct zfcp_data zfcp_data;
......@@ -159,7 +163,10 @@ extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
extern void zfcp_scsi_scan(struct work_struct *);
extern void zfcp_scsi_scan(struct zfcp_unit *);
extern void zfcp_scsi_scan_work(struct work_struct *);
extern void zfcp_scsi_set_prot(struct zfcp_adapter *);
extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
/* zfcp_sysfs.c */
extern struct attribute_group zfcp_sysfs_unit_attrs;
......
......@@ -23,6 +23,58 @@ static u32 zfcp_fc_rscn_range_mask[] = {
[ELS_ADDR_FMT_FAB] = 0x000000,
};
/**
* zfcp_fc_post_event - post event to userspace via fc_transport
* @work: work struct with enqueued events
*/
void zfcp_fc_post_event(struct work_struct *work)
{
struct zfcp_fc_event *event = NULL, *tmp = NULL;
LIST_HEAD(tmp_lh);
struct zfcp_fc_events *events = container_of(work,
struct zfcp_fc_events, work);
struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter,
events);
spin_lock_bh(&events->list_lock);
list_splice_init(&events->list, &tmp_lh);
spin_unlock_bh(&events->list_lock);
list_for_each_entry_safe(event, tmp, &tmp_lh, list) {
fc_host_post_event(adapter->scsi_host, fc_get_event_number(),
event->code, event->data);
list_del(&event->list);
kfree(event);
}
}
/**
* zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context
* @adapter: The adapter where to enqueue the event
* @event_code: The event code (as defined in fc_host_event_code in
* scsi_transport_fc.h)
* @event_data: The event data (e.g. n_port page in case of els)
*/
void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter,
enum fc_host_event_code event_code, u32 event_data)
{
struct zfcp_fc_event *event;
event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC);
if (!event)
return;
event->code = event_code;
event->data = event_data;
spin_lock(&adapter->events.list_lock);
list_add_tail(&event->list, &adapter->events.list);
spin_unlock(&adapter->events.list_lock);
queue_work(adapter->work_queue, &adapter->events.work);
}
static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port)
{
if (mutex_lock_interruptible(&wka_port->mutex))
......@@ -148,6 +200,8 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK;
_zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt],
page);
zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,
*(u32 *)page);
}
queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
}
......
......@@ -29,6 +29,30 @@
#define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000)
/**
* struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context
* @code: Event code
* @data: Event data
* @list: list_head for zfcp_fc_events list
*/
struct zfcp_fc_event {
enum fc_host_event_code code;
u32 data;
struct list_head list;
};
/**
* struct zfcp_fc_events - Infrastructure for posting FC events from irq context
* @list: List for queueing of events from irq context to workqueue
* @list_lock: Lock for event list
* @work: work_struct for forwarding events in workqueue
*/
struct zfcp_fc_events {
struct list_head list;
spinlock_t list_lock;
struct work_struct work;
};
/**
* struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request
* @ct_hdr: FC GS common transport header
......@@ -196,6 +220,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
fcp->fc_dl = scsi_bufflen(scsi);
if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
}
/**
......
......@@ -21,6 +21,7 @@
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"fsrth_1", NULL);
}
......@@ -274,6 +275,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
break;
case FSF_STATUS_READ_LINK_DOWN:
zfcp_fsf_status_read_link_down(req);
zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0);
break;
case FSF_STATUS_READ_LINK_UP:
dev_info(&adapter->ccw_device->dev,
......@@ -286,6 +288,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED,
"fssrh_2", req);
zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0);
break;
case FSF_STATUS_READ_NOTIFICATION_LOST:
if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
......@@ -323,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
dev_err(&req->adapter->ccw_device->dev,
"The FCP adapter reported a problem "
"that cannot be recovered\n");
zfcp_qdio_siosl(req->adapter);
zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
break;
}
......@@ -413,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
dev_err(&adapter->ccw_device->dev,
"0x%x is not a valid transfer protocol status\n",
qtcb->prefix.prot_status);
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
}
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
......@@ -495,7 +501,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
adapter->hydra_version = bottom->adapter_type;
adapter->timer_ticks = bottom->timer_interval;
adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK;
adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
(u16)FSF_STATUS_READS_RECOM);
......@@ -523,6 +529,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
return -EIO;
}
zfcp_scsi_set_prot(adapter);
return 0;
}
......@@ -732,7 +740,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req)
zfcp_reqlist_add(adapter->req_list, req);
req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count);
req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free);
req->issued = get_clock();
if (zfcp_qdio_send(qdio, &req->qdio_req)) {
del_timer(&req->timer);
......@@ -959,8 +967,7 @@ static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
int max_sbals)
struct scatterlist *sg_resp)
{
struct zfcp_adapter *adapter = req->adapter;
u32 feat = adapter->adapter_features;
......@@ -983,18 +990,19 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
return 0;
}
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
sg_req, max_sbals);
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
if (bytes <= 0)
return -EIO;
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
req->qtcb->bottom.support.req_buf_length = bytes;
zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
sg_resp, max_sbals);
sg_resp);
req->qtcb->bottom.support.resp_buf_length = bytes;
if (bytes <= 0)
return -EIO;
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
return 0;
}
......@@ -1002,11 +1010,11 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
struct scatterlist *sg_req,
struct scatterlist *sg_resp,
int max_sbals, unsigned int timeout)
unsigned int timeout)
{
int ret;
ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp);
if (ret)
return ret;
......@@ -1046,8 +1054,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout);
if (ret)
goto failed_send;
......@@ -1143,7 +1150,10 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout);
zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
if (ret)
goto failed_send;
......@@ -2025,7 +2035,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC;
if (req->status & ZFCP_STATUS_FSFREQ_ERROR)
blktrc.flags |= ZFCP_BLK_REQ_ERROR;
blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
blktrc.inb_usage = 0;
blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
......@@ -2035,9 +2045,13 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
blktrc.fabric_lat = lat_in->fabric_lat * ticks;
switch (req->qtcb->bottom.io.data_direction) {
case FSF_DATADIR_DIF_READ_STRIP:
case FSF_DATADIR_DIF_READ_CONVERT:
case FSF_DATADIR_READ:
lat = &unit->latencies.read;
break;
case FSF_DATADIR_DIF_WRITE_INSERT:
case FSF_DATADIR_DIF_WRITE_CONVERT:
case FSF_DATADIR_WRITE:
lat = &unit->latencies.write;
break;
......@@ -2078,6 +2092,21 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
goto skip_fsfstatus;
}
switch (req->qtcb->header.fsf_status) {
case FSF_INCONSISTENT_PROT_DATA:
case FSF_INVALID_PROT_PARM:
set_host_byte(scpnt, DID_ERROR);
goto skip_fsfstatus;
case FSF_BLOCK_GUARD_CHECK_FAILURE:
zfcp_scsi_dif_sense_error(scpnt, 0x1);
goto skip_fsfstatus;
case FSF_APP_TAG_CHECK_FAILURE:
zfcp_scsi_dif_sense_error(scpnt, 0x2);
goto skip_fsfstatus;
case FSF_REF_TAG_CHECK_FAILURE:
zfcp_scsi_dif_sense_error(scpnt, 0x3);
goto skip_fsfstatus;
}
fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
......@@ -2187,6 +2216,44 @@ static void zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *req)
}
}
static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
{
switch (scsi_get_prot_op(scsi_cmnd)) {
case SCSI_PROT_NORMAL:
switch (scsi_cmnd->sc_data_direction) {
case DMA_NONE:
*data_dir = FSF_DATADIR_CMND;
break;
case DMA_FROM_DEVICE:
*data_dir = FSF_DATADIR_READ;
break;
case DMA_TO_DEVICE:
*data_dir = FSF_DATADIR_WRITE;
break;
case DMA_BIDIRECTIONAL:
return -EINVAL;
}
break;
case SCSI_PROT_READ_STRIP:
*data_dir = FSF_DATADIR_DIF_READ_STRIP;
break;
case SCSI_PROT_WRITE_INSERT:
*data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
break;
case SCSI_PROT_READ_PASS:
*data_dir = FSF_DATADIR_DIF_READ_CONVERT;
break;
case SCSI_PROT_WRITE_PASS:
*data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
break;
default:
return -EINVAL;
}
return 0;
}
/**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
* @unit: unit where command is sent to
......@@ -2198,16 +2265,17 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
struct zfcp_fsf_req *req;
struct fcp_cmnd *fcp_cmnd;
unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
int real_bytes, retval = -EIO;
int real_bytes, retval = -EIO, dix_bytes = 0;
struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_qdio *qdio = adapter->qdio;
struct fsf_qtcb_bottom_io *io;
if (unlikely(!(atomic_read(&unit->status) &
ZFCP_STATUS_COMMON_UNBLOCKED)))
return -EBUSY;
spin_lock(&qdio->req_q_lock);
if (atomic_read(&qdio->req_q.count) <= 0) {
if (atomic_read(&qdio->req_q_free) <= 0) {
atomic_inc(&qdio->req_q_full);
goto out;
}
......@@ -2223,56 +2291,45 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
goto out;
}
scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
io = &req->qtcb->bottom.io;
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
req->unit = unit;
req->data = scsi_cmnd;
req->handler = zfcp_fsf_send_fcp_command_handler;
req->qtcb->header.lun_handle = unit->handle;
req->qtcb->header.port_handle = unit->port->handle;
req->qtcb->bottom.io.service_class = FSF_CLASS_3;
req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
io->service_class = FSF_CLASS_3;
io->fcp_cmnd_length = FCP_CMND_LEN;
scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
/*
* set depending on data direction:
* data direction bits in SBALE (SB Type)
* data direction bits in QTCB
*/
switch (scsi_cmnd->sc_data_direction) {
case DMA_NONE:
req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
break;
case DMA_FROM_DEVICE:
req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
break;
case DMA_TO_DEVICE:
req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
break;
case DMA_BIDIRECTIONAL:
goto failed_scsi_cmnd;
if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
io->data_block_length = scsi_cmnd->device->sector_size;
io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
}
zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
get_device(&unit->dev);
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
if (scsi_prot_sg_count(scsi_cmnd)) {
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
scsi_prot_sg_count(scsi_cmnd));
dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
scsi_prot_sglist(scsi_cmnd));
io->prot_data_length = dix_bytes;
}
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
scsi_sglist(scsi_cmnd),
ZFCP_FSF_MAX_SBALS_PER_REQ);
if (unlikely(real_bytes < 0)) {
if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
dev_err(&adapter->ccw_device->dev,
"Oversize data package, unit 0x%016Lx "
"on port 0x%016Lx closed\n",
(unsigned long long)unit->fcp_lun,
(unsigned long long)unit->port->wwpn);
zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req);
retval = -EINVAL;
}
scsi_sglist(scsi_cmnd));
if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
goto failed_scsi_cmnd;
}
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
retval = zfcp_fsf_req_send(req);
if (unlikely(retval))
......@@ -2391,13 +2448,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
bottom->option = fsf_cfdc->option;
bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
fsf_cfdc->sg,
ZFCP_FSF_MAX_SBALS_PER_REQ);
bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
if (bytes != ZFCP_CFDC_MAX_SIZE) {
zfcp_fsf_req_free(req);
goto out;
}
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
retval = zfcp_fsf_req_send(req);
......@@ -2419,7 +2476,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
{
struct zfcp_adapter *adapter = qdio->adapter;
struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx];
struct qdio_buffer *sbal = qdio->res_q[sbal_idx];
struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
unsigned long req_id;
......@@ -2431,17 +2488,17 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
req_id = (unsigned long) sbale->addr;
fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
if (!fsf_req)
if (!fsf_req) {
/*
* Unknown request means that we have potentially memory
* corruption and must stop the machine immediately.
*/
zfcp_qdio_siosl(adapter);
panic("error: unknown req_id (%lx) on adapter %s.\n",
req_id, dev_name(&adapter->ccw_device->dev));
}
fsf_req->qdio_req.sbal_response = sbal_idx;
fsf_req->qdio_req.qdio_inb_usage =
atomic_read(&qdio->resp_q.count);
zfcp_fsf_req_complete(fsf_req);
if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
......
......@@ -80,11 +80,15 @@
#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
#define FSF_SBAL_MISMATCH 0x00000063
#define FSF_INCONSISTENT_PROT_DATA 0x00000070
#define FSF_INVALID_PROT_PARM 0x00000071
#define FSF_BLOCK_GUARD_CHECK_FAILURE 0x00000081
#define FSF_APP_TAG_CHECK_FAILURE 0x00000082
#define FSF_REF_TAG_CHECK_FAILURE 0x00000083
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
#define FSF_UNKNOWN_COMMAND 0x000000E2
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
/* #define FSF_ERROR 0x000000FF */
#define FSF_PROT_STATUS_QUAL_SIZE 16
#define FSF_STATUS_QUALIFIER_SIZE 16
......@@ -147,18 +151,17 @@
#define FSF_DATADIR_WRITE 0x00000001
#define FSF_DATADIR_READ 0x00000002
#define FSF_DATADIR_CMND 0x00000004
#define FSF_DATADIR_DIF_WRITE_INSERT 0x00000009
#define FSF_DATADIR_DIF_READ_STRIP 0x0000000a
#define FSF_DATADIR_DIF_WRITE_CONVERT 0x0000000b
#define FSF_DATADIR_DIF_READ_CONVERT 0X0000000c
/* data protection control flags */
#define FSF_APP_TAG_CHECK_ENABLE 0x10
/* fc service class */
#define FSF_CLASS_3 0x00000003
/* SBAL chaining */
#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
......@@ -170,6 +173,8 @@
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
#define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000
#define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000
/* host connection features */
#define FSF_FEATURE_NPIV_MODE 0x00000001
......@@ -324,9 +329,14 @@ struct fsf_qtcb_header {
struct fsf_qtcb_bottom_io {
u32 data_direction;
u32 service_class;
u8 res1[8];
u8 res1;
u8 data_prot_flags;
u16 app_tag_value;
u32 ref_tag_value;
u32 fcp_cmnd_length;
u8 res2[12];
u32 data_block_length;
u32 prot_data_length;
u8 res2[4];
u8 fcp_cmnd[FSF_FCP_CMND_SIZE];
u8 fcp_rsp[FSF_FCP_RSP_SIZE];
u8 res3[64];
......@@ -352,6 +362,8 @@ struct fsf_qtcb_bottom_support {
u8 els[256];
} __attribute__ ((packed));
#define ZFCP_FSF_TIMER_INT_MASK 0x3FFF
struct fsf_qtcb_bottom_config {
u32 lic_version;
u32 feature_selection;
......
......@@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
return 0;
}
static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
unsigned int qdio_err)
{
struct zfcp_adapter *adapter = qdio->adapter;
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
if (qdio_err & QDIO_ERROR_SLSB_STATE)
zfcp_qdio_siosl(adapter);
zfcp_erp_adapter_reopen(adapter,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
......@@ -55,72 +58,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
{
unsigned long long now, span;
int free, used;
int used;
spin_lock(&qdio->stat_lock);
now = get_clock_monotonic();
span = (now - qdio->req_q_time) >> 12;
free = atomic_read(&qdio->req_q.count);
used = QDIO_MAX_BUFFERS_PER_Q - free;
used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
qdio->req_q_util += used * span;
qdio->req_q_time = now;
spin_unlock(&qdio->stat_lock);
}
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
int queue_no, int first, int count,
int queue_no, int idx, int count,
unsigned long parm)
{
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
struct zfcp_qdio_queue *queue = &qdio->req_q;
if (unlikely(qdio_err)) {
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
count);
zfcp_qdio_handler_error(qdio, "qdireq1");
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
return;
}
/* cleanup all SBALs being program-owned now */
zfcp_qdio_zero_sbals(queue->sbal, first, count);
zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
zfcp_qdio_account(qdio);
atomic_add(count, &queue->count);
atomic_add(count, &qdio->req_q_free);
wake_up(&qdio->req_q_wq);
}
static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
{
struct zfcp_qdio_queue *queue = &qdio->resp_q;
struct ccw_device *cdev = qdio->adapter->ccw_device;
u8 count, start = queue->first;
unsigned int retval;
count = atomic_read(&queue->count) + processed;
retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
if (unlikely(retval)) {
atomic_set(&queue->count, count);
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
} else {
queue->first += count;
queue->first %= QDIO_MAX_BUFFERS_PER_Q;
atomic_set(&queue->count, 0);
}
}
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
int queue_no, int first, int count,
int queue_no, int idx, int count,
unsigned long parm)
{
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
int sbal_idx, sbal_no;
if (unlikely(qdio_err)) {
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
count);
zfcp_qdio_handler_error(qdio, "qdires1");
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
return;
}
......@@ -129,25 +107,16 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
* returned by QDIO layer
*/
for (sbal_no = 0; sbal_no < count; sbal_no++) {
sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
/* go through all SBALEs of SBAL */
zfcp_fsf_reqid_check(qdio, sbal_idx);
}
/*
* put range of SBALs back to response queue
* (including SBALs which have already been free before)
* put SBALs back to response queue
*/
zfcp_qdio_resp_put_back(qdio, count);
}
static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
struct zfcp_qdio_req *q_req, int max_sbals)
{
int count = atomic_read(&qdio->req_q.count);
count = min(count, max_sbals);
q_req->sbal_limit = (q_req->sbal_first + count - 1)
% QDIO_MAX_BUFFERS_PER_Q;
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
}
static struct qdio_buffer_element *
......@@ -173,6 +142,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
/* keep this requests number of SBALs up-to-date */
q_req->sbal_number++;
BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ);
/* start at first SBALE of new SBAL */
q_req->sbale_curr = 0;
......@@ -193,17 +163,6 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
return zfcp_qdio_sbale_curr(qdio, q_req);
}
static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
struct zfcp_qdio_req *q_req)
{
struct qdio_buffer **sbal = qdio->req_q.sbal;
int first = q_req->sbal_first;
int last = q_req->sbal_last;
int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
QDIO_MAX_BUFFERS_PER_Q + 1;
zfcp_qdio_zero_sbals(sbal, first, count);
}
/**
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
* @qdio: pointer to struct zfcp_qdio
......@@ -213,14 +172,11 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
* Returns: number of bytes, or error (negativ)
*/
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
struct scatterlist *sg, int max_sbals)
struct scatterlist *sg)
{
struct qdio_buffer_element *sbale;
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 |= q_req->sbtype;
......@@ -229,7 +185,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
sbale = zfcp_qdio_sbale_next(qdio, q_req);
if (!sbale) {
atomic_inc(&qdio->req_q_full);
zfcp_qdio_undo_sbals(qdio, q_req);
zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
q_req->sbal_number);
return -EINVAL;
}
......@@ -239,19 +196,13 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
bytes += sg->length;
}
/* assume that no other SBALEs are to follow in the same SBAL */
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
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) ||
if (atomic_read(&qdio->req_q_free) ||
!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return 1;
spin_unlock_bh(&qdio->req_q_lock);
......@@ -300,25 +251,25 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
*/
int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
struct zfcp_qdio_queue *req_q = &qdio->req_q;
int first = q_req->sbal_first;
int count = q_req->sbal_number;
int retval;
unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
u8 sbal_number = q_req->sbal_number;
zfcp_qdio_account(qdio);
retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
count);
retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
q_req->sbal_first, sbal_number);
if (unlikely(retval)) {
zfcp_qdio_zero_sbals(req_q->sbal, first, count);
zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
sbal_number);
return retval;
}
/* account for transferred buffers */
atomic_sub(count, &req_q->count);
req_q->first += count;
req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
atomic_sub(sbal_number, &qdio->req_q_free);
qdio->req_q_idx += sbal_number;
qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
return 0;
}
......@@ -331,6 +282,7 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->q_format = QDIO_ZFCP_QFMT;
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
ASCEBC(id->adapter_name, 8);
id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
id->qib_param_field_format = 0;
id->qib_param_field = NULL;
id->input_slib_elements = NULL;
......@@ -340,10 +292,10 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
id->input_handler = zfcp_qdio_int_resp;
id->output_handler = zfcp_qdio_int_req;
id->int_parm = (unsigned long) qdio;
id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
id->input_sbal_addr_array = (void **) (qdio->res_q);
id->output_sbal_addr_array = (void **) (qdio->req_q);
}
/**
* zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
* @adapter: pointer to struct zfcp_adapter
......@@ -354,8 +306,8 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
{
struct qdio_initialize init_data;
if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
if (zfcp_qdio_buffers_enqueue(qdio->req_q) ||
zfcp_qdio_buffers_enqueue(qdio->res_q))
return -ENOMEM;
zfcp_qdio_setup_init_data(&init_data, qdio);
......@@ -369,34 +321,30 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
*/
void zfcp_qdio_close(struct zfcp_qdio *qdio)
{
struct zfcp_qdio_queue *req_q;
int first, count;
struct zfcp_adapter *adapter = qdio->adapter;
int idx, count;
if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
req_q = &qdio->req_q;
spin_lock_bh(&qdio->req_q_lock);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
spin_unlock_bh(&qdio->req_q_lock);
wake_up(&qdio->req_q_wq);
qdio_shutdown(qdio->adapter->ccw_device,
QDIO_FLAG_CLEANUP_USING_CLEAR);
qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
/* cleanup used outbound sbals */
count = atomic_read(&req_q->count);
count = atomic_read(&qdio->req_q_free);
if (count < QDIO_MAX_BUFFERS_PER_Q) {
first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q;
idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
count = QDIO_MAX_BUFFERS_PER_Q - count;
zfcp_qdio_zero_sbals(req_q->sbal, first, count);
zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
}
req_q->first = 0;
atomic_set(&req_q->count, 0);
qdio->resp_q.first = 0;
atomic_set(&qdio->resp_q.count, 0);
qdio->req_q_idx = 0;
atomic_set(&qdio->req_q_free, 0);
}
/**
......@@ -408,34 +356,45 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
{
struct qdio_buffer_element *sbale;
struct qdio_initialize init_data;
struct ccw_device *cdev = qdio->adapter->ccw_device;
struct zfcp_adapter *adapter = qdio->adapter;
struct ccw_device *cdev = adapter->ccw_device;
struct qdio_ssqd_desc ssqd;
int cc;
if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
return -EIO;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
&qdio->adapter->status);
zfcp_qdio_setup_init_data(&init_data, qdio);
if (qdio_establish(&init_data))
goto failed_establish;
if (qdio_get_ssqd_desc(init_data.cdev, &ssqd))
goto failed_qdio;
if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED)
atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
&qdio->adapter->status);
if (qdio_activate(cdev))
goto failed_qdio;
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
sbale = &(qdio->resp_q.sbal[cc]->element[0]);
sbale = &(qdio->res_q[cc]->element[0]);
sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
sbale->addr = NULL;
}
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
QDIO_MAX_BUFFERS_PER_Q))
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q))
goto failed_qdio;
/* set index of first avalable SBALS / number of available SBALS */
qdio->req_q.first = 0;
atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
qdio->req_q_idx = 0;
atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
return 0;
......@@ -449,7 +408,6 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
{
struct qdio_buffer **sbal_req, **sbal_resp;
int p;
if (!qdio)
......@@ -458,12 +416,9 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
if (qdio->adapter->ccw_device)
qdio_free(qdio->adapter->ccw_device);
sbal_req = qdio->req_q.sbal;
sbal_resp = qdio->resp_q.sbal;
for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
free_page((unsigned long) sbal_req[p]);
free_page((unsigned long) sbal_resp[p]);
free_page((unsigned long) qdio->req_q[p]);
free_page((unsigned long) qdio->res_q[p]);
}
kfree(qdio);
......@@ -491,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter)
return 0;
}
/**
* zfcp_qdio_siosl - Trigger logging in FCP channel
* @adapter: The zfcp_adapter where to trigger logging
*
* Call the cio siosl function to trigger hardware logging. This
* wrapper function sets a flag to ensure hardware logging is only
* triggered once before going through qdio shutdown.
*
* The triggers are always run from qdio tasklet context, so no
* additional synchronization is necessary.
*/
void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
{
int rc;
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
return;
rc = ccw_device_siosl(adapter->ccw_device);
if (!rc)
atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
&adapter->status);
}
......@@ -19,22 +19,20 @@
/* 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
* @first: index of next free buffer in queue
* @count: number of free buffers in queue
*/
struct zfcp_qdio_queue {
struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q];
u8 first;
atomic_t count;
};
/* Max SBALS for chaining */
#define ZFCP_QDIO_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_QDIO_MAX_SBALES_PER_REQ \
(ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
/**
* struct zfcp_qdio - basic qdio data structure
* @resp_q: response queue
* @res_q: response queue
* @req_q: request queue
* @req_q_idx: index of next free buffer
* @req_q_free: number of free buffers in queue
* @stat_lock: lock to protect req_q_util and req_q_time
* @req_q_lock: lock to serialize access to request queue
* @req_q_time: time of last fill level change
......@@ -44,8 +42,10 @@ struct zfcp_qdio_queue {
* @adapter: adapter used in conjunction with this qdio structure
*/
struct zfcp_qdio {
struct zfcp_qdio_queue resp_q;
struct zfcp_qdio_queue req_q;
struct qdio_buffer *res_q[QDIO_MAX_BUFFERS_PER_Q];
struct qdio_buffer *req_q[QDIO_MAX_BUFFERS_PER_Q];
u8 req_q_idx;
atomic_t req_q_free;
spinlock_t stat_lock;
spinlock_t req_q_lock;
unsigned long long req_q_time;
......@@ -65,7 +65,6 @@ struct zfcp_qdio {
* @sbale_curr: current sbale at creation of this request
* @sbal_response: sbal used in interrupt
* @qdio_outb_usage: usage of outbound queue
* @qdio_inb_usage: usage of inbound queue
*/
struct zfcp_qdio_req {
u32 sbtype;
......@@ -76,21 +75,8 @@ struct zfcp_qdio_req {
u8 sbale_curr;
u8 sbal_response;
u16 qdio_outb_usage;
u16 qdio_inb_usage;
};
/**
* zfcp_qdio_sbale - return pointer to sbale in qdio queue
* @q: queue where to find sbal
* @sbal_idx: sbal index in queue
* @sbale_idx: sbale index in sbal
*/
static inline struct qdio_buffer_element *
zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
{
return &q->sbal[sbal_idx]->element[sbale_idx];
}
/**
* zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request
* @qdio: pointer to struct zfcp_qdio
......@@ -100,7 +86,7 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
return &qdio->req_q[q_req->sbal_last]->element[0];
}
/**
......@@ -112,8 +98,7 @@ zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
static inline struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
{
return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
q_req->sbale_curr);
return &qdio->req_q[q_req->sbal_last]->element[q_req->sbale_curr];
}
/**
......@@ -134,21 +119,25 @@ 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;
int count = min(atomic_read(&qdio->req_q_free),
ZFCP_QDIO_MAX_SBALS_PER_REQ);
q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
q_req->sbal_first = q_req->sbal_last = qdio->req_q_idx;
q_req->sbal_number = 1;
q_req->sbtype = sbtype;
q_req->sbale_curr = 1;
q_req->sbal_limit = (q_req->sbal_first + count - 1)
% QDIO_MAX_BUFFERS_PER_Q;
sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->addr = (void *) req_id;
sbale->flags |= SBAL_FLAGS0_COMMAND;
sbale->flags |= sbtype;
sbale->flags = SBAL_FLAGS0_COMMAND | sbtype;
q_req->sbale_curr = 1;
if (unlikely(!data))
return;
sbale++;
sbale->addr = data;
if (likely(data))
sbale->length = len;
sbale->length = len;
}
/**
......@@ -210,4 +199,36 @@ void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
}
/**
* zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req
* @qdio: pointer to struct zfcp_qdio
* @q_req: The current zfcp_qdio_req
* @max_sbals: maximum number of SBALs allowed
*/
static inline
void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
struct zfcp_qdio_req *q_req, int max_sbals)
{
int count = min(atomic_read(&qdio->req_q_free), max_sbals);
q_req->sbal_limit = (q_req->sbal_first + count - 1) %
QDIO_MAX_BUFFERS_PER_Q;
}
/**
* zfcp_qdio_set_data_div - set data division count
* @qdio: pointer to struct zfcp_qdio
* @q_req: The current zfcp_qdio_req
* @count: The data division count
*/
static inline
void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
struct zfcp_qdio_req *q_req, u32 count)
{
struct qdio_buffer_element *sbale;
sbale = &qdio->req_q[q_req->sbal_first]->element[0];
sbale->length = count;
}
#endif /* ZFCP_QDIO_H */
......@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <scsi/fc/fc_fcp.h>
#include <scsi/scsi_eh.h>
#include <asm/atomic.h>
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
......@@ -22,6 +23,13 @@ static unsigned int default_depth = 32;
module_param_named(queue_depth, default_depth, uint, 0600);
MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
static bool enable_dif;
#ifdef CONFIG_ZFCP_DIF
module_param_named(dif, enable_dif, bool, 0600);
MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
#endif
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
int reason)
{
......@@ -506,8 +514,10 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
* @rport: The FC rport where to teminate I/O
*
* Abort all pending SCSI commands for a port by closing the
* port. Using a reopen avoiding a conflict with a shutdown
* overwriting a reopen.
* port. Using a reopen avoids a conflict with a shutdown
* overwriting a reopen. The "forced" ensures that a disappeared port
* is not opened again as valid due to the cached plogi data in
* non-NPIV mode.
*/
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
{
......@@ -519,11 +529,25 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) {
zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL);
zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL);
put_device(&port->dev);
}
}
static void zfcp_scsi_queue_unit_register(struct zfcp_port *port)
{
struct zfcp_unit *unit;
read_lock_irq(&port->unit_list_lock);
list_for_each_entry(unit, &port->unit_list, list) {
get_device(&unit->dev);
if (scsi_queue_work(port->adapter->scsi_host,
&unit->scsi_work) <= 0)
put_device(&unit->dev);
}
read_unlock_irq(&port->unit_list_lock);
}
static void zfcp_scsi_rport_register(struct zfcp_port *port)
{
struct fc_rport_identifiers ids;
......@@ -548,6 +572,9 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
rport->maxframe_size = port->maxframe_size;
rport->supported_classes = port->supported_classes;
port->rport = rport;
port->starget_id = rport->scsi_target_id;
zfcp_scsi_queue_unit_register(port);
}
static void zfcp_scsi_rport_block(struct zfcp_port *port)
......@@ -610,24 +637,74 @@ void zfcp_scsi_rport_work(struct work_struct *work)
put_device(&port->dev);
}
void zfcp_scsi_scan(struct work_struct *work)
/**
* zfcp_scsi_scan - Register LUN with SCSI midlayer
* @unit: The LUN/unit to register
*/
void zfcp_scsi_scan(struct zfcp_unit *unit)
{
struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
scsi_work);
struct fc_rport *rport;
flush_work(&unit->port->rport_work);
rport = unit->port->rport;
struct fc_rport *rport = unit->port->rport;
if (rport && rport->port_state == FC_PORTSTATE_ONLINE)
scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
scsilun_to_int((struct scsi_lun *)
&unit->fcp_lun), 0);
}
void zfcp_scsi_scan_work(struct work_struct *work)
{
struct zfcp_unit *unit = container_of(work, struct zfcp_unit,
scsi_work);
zfcp_scsi_scan(unit);
put_device(&unit->dev);
}
/**
* zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
* @adapter: The adapter where to configure DIF/DIX for the SCSI host
*/
void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
{
unsigned int mask = 0;
unsigned int data_div;
struct Scsi_Host *shost = adapter->scsi_host;
data_div = atomic_read(&adapter->status) &
ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED;
if (enable_dif &&
adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1)
mask |= SHOST_DIF_TYPE1_PROTECTION;
if (enable_dif && data_div &&
adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
mask |= SHOST_DIX_TYPE1_PROTECTION;
scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
}
scsi_host_set_prot(shost, mask);
}
/**
* zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error
* @scmd: The SCSI command to report the error for
* @ascq: The ASCQ to put in the sense buffer
*
* See the error handling in sd_done for the sense codes used here.
* Set DID_SOFT_ERROR to retry the request, if possible.
*/
void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
{
scsi_build_sense_buffer(1, scmd->sense_buffer,
ILLEGAL_REQUEST, 0x10, ascq);
set_driver_byte(scmd, DRIVER_SENSE);
scmd->result |= SAM_STAT_CHECK_CONDITION;
set_host_byte(scmd, DID_SOFT_ERROR);
}
struct fc_function_template zfcp_transport_functions = {
.show_starget_port_id = 1,
.show_starget_port_name = 1,
......@@ -677,11 +754,11 @@ struct zfcp_data zfcp_data = {
.eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
.can_queue = 4096,
.this_id = -1,
.sg_tablesize = ZFCP_FSF_MAX_SBALES_PER_REQ,
.sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ,
.cmd_per_lun = 1,
.use_clustering = 1,
.sdev_attrs = zfcp_sysfs_sdev_attrs,
.max_sectors = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
.max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
.dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
.shost_attrs = zfcp_sysfs_shost_attrs,
},
......
......@@ -275,7 +275,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL);
zfcp_erp_wait(unit->port->adapter);
flush_work(&unit->scsi_work);
zfcp_scsi_scan(unit);
out:
put_device(&port->dev);
return retval ? retval : (ssize_t) count;
......@@ -290,6 +290,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
struct zfcp_unit *unit;
u64 fcp_lun;
int retval = -EINVAL;
struct scsi_device *sdev;
if (!(port && get_device(&port->dev)))
return -EBUSY;
......@@ -303,8 +304,13 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
else
retval = 0;
/* wait for possible timeout during SCSI probe */
flush_work(&unit->scsi_work);
sdev = scsi_device_lookup(port->adapter->scsi_host, 0,
port->starget_id,
scsilun_to_int((struct scsi_lun *)&fcp_lun));
if (sdev) {
scsi_remove_device(sdev);
scsi_device_put(sdev);
}
write_lock_irq(&port->unit_list_lock);
list_del(&unit->list);
......
......@@ -1847,6 +1847,10 @@ config ZFCP
called zfcp. If you want to compile it as a module, say M here
and read <file:Documentation/kbuild/modules.txt>.
config ZFCP_DIF
tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)"
depends on ZFCP && EXPERIMENTAL
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
depends on PCI && SCSI
......
......@@ -163,6 +163,7 @@ 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_mod-$(CONFIG_PM_OPS) += scsi_pm.o
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
......
......@@ -1091,6 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
struct list_head *insert = &aac_devices;
int error = -ENODEV;
int unique_id = 0;
u64 dmamask;
list_for_each_entry(aac, &aac_devices, entry) {
if (aac->id > unique_id)
......@@ -1104,17 +1105,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
goto out;
error = -ENODEV;
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
goto out_disable_pdev;
/*
* If the quirk31 bit is set, the adapter needs adapter
* to driver communication memory to be allocated below 2gig
*/
if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(31)) ||
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(31)))
goto out_disable_pdev;
dmamask = DMA_BIT_MASK(31);
else
dmamask = DMA_BIT_MASK(32);
if (pci_set_dma_mask(pdev, dmamask) ||
pci_set_consistent_dma_mask(pdev, dmamask))
goto out_disable_pdev;
pci_set_master(pdev);
......
......@@ -170,7 +170,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
case 15:
break;
default:
printf("aic7770_config: invalid irq setting %d\n", intdef);
printk("aic7770_config: invalid irq setting %d\n", intdef);
return (ENXIO);
}
......@@ -221,7 +221,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
break;
}
if (have_seeprom == 0) {
free(ahc->seep_config, M_DEVBUF);
kfree(ahc->seep_config);
ahc->seep_config = NULL;
}
......@@ -293,7 +293,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
sc = ahc->seep_config;
if (bootverbose)
printf("%s: Reading SEEPROM...", ahc_name(ahc));
printk("%s: Reading SEEPROM...", ahc_name(ahc));
have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
/*start_addr*/0, sizeof(*sc)/2);
......@@ -301,16 +301,16 @@ aha2840_load_seeprom(struct ahc_softc *ahc)
if (ahc_verify_cksum(sc) == 0) {
if(bootverbose)
printf ("checksum error\n");
printk ("checksum error\n");
have_seeprom = 0;
} else if (bootverbose) {
printf("done.\n");
printk("done.\n");
}
}
if (!have_seeprom) {
if (bootverbose)
printf("%s: No SEEPROM available\n", ahc_name(ahc));
printk("%s: No SEEPROM available\n", ahc_name(ahc));
ahc->flags |= AHC_USEDEFAULTS;
} else {
/*
......
......@@ -85,7 +85,7 @@ aic7770_probe(struct device *dev)
int error;
sprintf(buf, "ahc_eisa:%d", eisaBase >> 12);
name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (name == NULL)
return (ENOMEM);
strcpy(name, buf);
......
此差异已折叠。
此差异已折叠。
......@@ -363,13 +363,6 @@ struct ahd_platform_data {
resource_size_t mem_busaddr; /* Mem Base Addr */
};
/************************** OS Utility Wrappers *******************************/
#define printf printk
#define M_NOWAIT GFP_ATOMIC
#define M_WAITOK 0
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
void ahd_delay(long);
/***************************** Low Level I/O **********************************/
......
......@@ -178,7 +178,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ahd_get_pci_bus(pci),
ahd_get_pci_slot(pci),
ahd_get_pci_function(pci));
name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
name = kmalloc(strlen(buf) + 1, GFP_ATOMIC);
if (name == NULL)
return (-ENOMEM);
strcpy(name, buf);
......@@ -333,7 +333,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
if (ahd_pci_test_register_access(ahd) != 0) {
printf("aic79xx: PCI Device %d:%d:%d "
printk("aic79xx: PCI Device %d:%d:%d "
"failed memory mapped test. Using PIO.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
......@@ -346,7 +346,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
} else
command |= PCIM_CMD_MEMEN;
} else if (bootverbose) {
printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
printk("aic79xx: PCI%d:%d:%d MEM region 0x%llx "
"unavailable. Cannot memory map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
......@@ -365,7 +365,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
ahd->bshs[1].ioport = (u_long)base2;
command |= PCIM_CMD_PORTEN;
} else {
printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
printk("aic79xx: PCI%d:%d:%d IO regions 0x%llx and "
"0x%llx unavailable. Cannot map device.\n",
ahd_get_pci_bus(ahd->dev_softc),
ahd_get_pci_slot(ahd->dev_softc),
......
......@@ -338,7 +338,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
*/
if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
if (bootverbose)
printf("%s: Enabling 39Bit Addressing\n",
printk("%s: Enabling 39Bit Addressing\n",
ahd_name(ahd));
devconfig = ahd_pci_read_config(ahd->dev_softc,
DEVCONFIG, /*bytes*/4);
......@@ -528,7 +528,7 @@ ahd_check_extport(struct ahd_softc *ahd)
* Fetch VPD for this function and parse it.
*/
if (bootverbose)
printf("%s: Reading VPD from SEEPROM...",
printk("%s: Reading VPD from SEEPROM...",
ahd_name(ahd));
/* Address is always in units of 16bit words */
......@@ -541,12 +541,12 @@ ahd_check_extport(struct ahd_softc *ahd)
if (error == 0)
error = ahd_parse_vpddata(ahd, &vpd);
if (bootverbose)
printf("%s: VPD parsing %s\n",
printk("%s: VPD parsing %s\n",
ahd_name(ahd),
error == 0 ? "successful" : "failed");
if (bootverbose)
printf("%s: Reading SEEPROM...", ahd_name(ahd));
printk("%s: Reading SEEPROM...", ahd_name(ahd));
/* Address is always in units of 16bit words */
start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
......@@ -556,16 +556,16 @@ ahd_check_extport(struct ahd_softc *ahd)
/*bytestream*/FALSE);
if (error != 0) {
printf("Unable to read SEEPROM\n");
printk("Unable to read SEEPROM\n");
have_seeprom = 0;
} else {
have_seeprom = ahd_verify_cksum(sc);
if (bootverbose) {
if (have_seeprom == 0)
printf ("checksum error\n");
printk ("checksum error\n");
else
printf ("done.\n");
printk ("done.\n");
}
}
ahd_release_seeprom(ahd);
......@@ -615,21 +615,21 @@ ahd_check_extport(struct ahd_softc *ahd)
uint16_t *sc_data;
int i;
printf("%s: Seeprom Contents:", ahd_name(ahd));
printk("%s: Seeprom Contents:", ahd_name(ahd));
sc_data = (uint16_t *)sc;
for (i = 0; i < (sizeof(*sc)); i += 2)
printf("\n\t0x%.4x", sc_data[i]);
printf("\n");
printk("\n\t0x%.4x", sc_data[i]);
printk("\n");
}
#endif
if (!have_seeprom) {
if (bootverbose)
printf("%s: No SEEPROM available.\n", ahd_name(ahd));
printk("%s: No SEEPROM available.\n", ahd_name(ahd));
ahd->flags |= AHD_USEDEFAULTS;
error = ahd_default_config(ahd);
adapter_control = CFAUTOTERM|CFSEAUTOTERM;
free(ahd->seep_config, M_DEVBUF);
kfree(ahd->seep_config);
ahd->seep_config = NULL;
} else {
error = ahd_parse_cfgdata(ahd, sc);
......@@ -656,7 +656,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((ahd->flags & AHD_STPWLEVEL_A) != 0)
devconfig |= STPWLEVEL;
if (bootverbose)
printf("%s: STPWLEVEL is %s\n",
printk("%s: STPWLEVEL is %s\n",
ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off");
ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
......@@ -671,7 +671,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
if ((adapter_control & CFAUTOTERM) == 0) {
if (bootverbose)
printf("%s: Manual Primary Termination\n",
printk("%s: Manual Primary Termination\n",
ahd_name(ahd));
termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
if ((adapter_control & CFSTERM) != 0)
......@@ -679,14 +679,14 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((adapter_control & CFWSTERM) != 0)
termctl |= FLX_TERMCTL_ENPRIHIGH;
} else if (error != 0) {
printf("%s: Primary Auto-Term Sensing failed! "
printk("%s: Primary Auto-Term Sensing failed! "
"Using Defaults.\n", ahd_name(ahd));
termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
}
if ((adapter_control & CFSEAUTOTERM) == 0) {
if (bootverbose)
printf("%s: Manual Secondary Termination\n",
printk("%s: Manual Secondary Termination\n",
ahd_name(ahd));
termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
if ((adapter_control & CFSELOWTERM) != 0)
......@@ -694,7 +694,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
if ((adapter_control & CFSEHIGHTERM) != 0)
termctl |= FLX_TERMCTL_ENSECHIGH;
} else if (error != 0) {
printf("%s: Secondary Auto-Term Sensing failed! "
printk("%s: Secondary Auto-Term Sensing failed! "
"Using Defaults.\n", ahd_name(ahd));
termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
}
......@@ -714,22 +714,22 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
if (error != 0) {
printf("%s: Unable to set termination settings!\n",
printk("%s: Unable to set termination settings!\n",
ahd_name(ahd));
} else if (bootverbose) {
printf("%s: Primary High byte termination %sabled\n",
printk("%s: Primary High byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
printf("%s: Primary Low byte termination %sabled\n",
printk("%s: Primary Low byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
printf("%s: Secondary High byte termination %sabled\n",
printk("%s: Secondary High byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
printf("%s: Secondary Low byte termination %sabled\n",
printk("%s: Secondary Low byte termination %sabled\n",
ahd_name(ahd),
(termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
}
......@@ -805,7 +805,7 @@ ahd_pci_intr(struct ahd_softc *ahd)
if ((intstat & PCIINT) == 0)
return;
printf("%s: PCI error Interrupt\n", ahd_name(ahd));
printk("%s: PCI error Interrupt\n", ahd_name(ahd));
saved_modes = ahd_save_modes(ahd);
ahd_dump_card_state(ahd);
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
......@@ -832,7 +832,7 @@ ahd_pci_intr(struct ahd_softc *ahd)
s = pci_status_strings[bit];
if (i == 7/*TARG*/ && bit == 3)
s = "%s: Signaled Target Abort\n";
printf(s, ahd_name(ahd), pci_status_source[i]);
printk(s, ahd_name(ahd), pci_status_source[i]);
}
}
}
......@@ -862,7 +862,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
*/
pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS,
/*bytes*/2);
printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
ahd_name(ahd), pcix_status);
saved_modes = ahd_save_modes(ahd);
for (i = 0; i < 4; i++) {
......@@ -891,7 +891,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
static const char *s;
s = split_status_strings[bit];
printf(s, ahd_name(ahd),
printk(s, ahd_name(ahd),
split_status_source[i]);
}
......@@ -902,7 +902,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
static const char *s;
s = split_status_strings[bit];
printf(s, ahd_name(ahd), "SG");
printk(s, ahd_name(ahd), "SG");
}
}
}
......@@ -950,7 +950,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
pci = ahd->dev_softc;
rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
if (rev < ID_AIC7902_PCI_REV_A4) {
printf("%s: Unable to attach to unsupported chip revision %d\n",
printk("%s: Unable to attach to unsupported chip revision %d\n",
ahd_name(ahd), rev);
ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
return (ENXIO);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -368,13 +368,6 @@ struct ahc_platform_data {
resource_size_t mem_busaddr; /* Mem Base Addr */
};
/************************** OS Utility Wrappers *******************************/
#define printf printk
#define M_NOWAIT GFP_ATOMIC
#define M_WAITOK 0
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
void ahc_delay(long);
......
此差异已折叠。
此差异已折叠。
......@@ -223,7 +223,7 @@ static void asd_task_tasklet_complete(struct asd_ascb *ascb,
switch (opcode) {
case TC_NO_ERROR:
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAM_GOOD;
ts->stat = SAM_STAT_GOOD;
break;
case TC_UNDERRUN:
ts->resp = SAS_TASK_COMPLETE;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册