提交 39695224 编写于 作者: 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: (209 commits)
  [SCSI] fix oops during scsi scanning
  [SCSI] libsrp: fix memory leak in srp_ring_free()
  [SCSI] libiscsi, bnx2i: make bound ep check common
  [SCSI] libiscsi: add completion function for drivers that do not need pdu processing
  [SCSI] scsi_dh_rdac: changes for rdac debug logging
  [SCSI] scsi_dh_rdac: changes to collect the rdac debug information during the initialization
  [SCSI] scsi_dh_rdac: move the init code from rdac_activate to rdac_bus_attach
  [SCSI] sg: fix oops in the error path in sg_build_indirect()
  [SCSI] mptsas : Bump version to 3.04.12
  [SCSI] mptsas : FW event thread and scsi mid layer deadlock in SYNCHRONIZE CACHE command
  [SCSI] mptsas : Send DID_NO_CONNECT for pending IOs of removed device
  [SCSI] mptsas : PAE Kernel more than 4 GB kernel panic
  [SCSI] mptsas : NULL pointer on big endian systems causing Expander not to tear off
  [SCSI] mptsas : Sanity check for phyinfo is added
  [SCSI] scsi_dh_rdac: Add support for Sun StorageTek ST2500, ST2510 and ST2530
  [SCSI] pmcraid: PMC-Sierra MaxRAID driver to support 6Gb/s SAS RAID controller
  [SCSI] qla2xxx: Update version number to 8.03.01-k6.
  [SCSI] qla2xxx: Properly delete rports attached to a vport.
  [SCSI] qla2xxx: Correct various NPIV issues.
  [SCSI] qla2xxx: Correct qla2x00_eh_wait_on_command() to wait correctly.
  ...
...@@ -4009,6 +4009,14 @@ S: Maintained ...@@ -4009,6 +4009,14 @@ S: Maintained
F: drivers/block/pktcdvd.c F: drivers/block/pktcdvd.c
F: include/linux/pktcdvd.h F: include/linux/pktcdvd.h
PMC SIERRA MaxRAID DRIVER
P: Anil Ravindranath
M: anil_ravindranath@pmc-sierra.com
L: linux-scsi@vger.kernel.org
W: http://www.pmc-sierra.com/
S: Supported
F: drivers/scsi/pmcraid.*
POSIX CLOCKS and TIMERS POSIX CLOCKS and TIMERS
M: Thomas Gleixner <tglx@linutronix.de> M: Thomas Gleixner <tglx@linutronix.de>
S: Supported S: Supported
...@@ -4447,7 +4455,7 @@ F: drivers/scsi/sg.c ...@@ -4447,7 +4455,7 @@ F: drivers/scsi/sg.c
F: include/scsi/sg.h F: include/scsi/sg.h
SCSI SUBSYSTEM SCSI SUBSYSTEM
M: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com> M: "James E.J. Bottomley" <James.Bottomley@suse.de>
L: linux-scsi@vger.kernel.org L: linux-scsi@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6.git
......
...@@ -88,6 +88,14 @@ int get_sync_clock(unsigned long long *clock); ...@@ -88,6 +88,14 @@ int get_sync_clock(unsigned long long *clock);
void init_cpu_timer(void); void init_cpu_timer(void);
unsigned long long monotonic_clock(void); unsigned long long monotonic_clock(void);
void tod_to_timeval(__u64, struct timespec *);
static inline
void stck_to_timespec(unsigned long long stck, struct timespec *ts)
{
tod_to_timeval(stck - TOD_UNIX_EPOCH, ts);
}
extern u64 sched_clock_base_cc; extern u64 sched_clock_base_cc;
/** /**
......
...@@ -63,8 +63,6 @@ typedef struct ...@@ -63,8 +63,6 @@ typedef struct
} debug_sprintf_entry_t; } debug_sprintf_entry_t;
extern void tod_to_timeval(uint64_t todval, struct timespec *xtime);
/* internal function prototyes */ /* internal function prototyes */
static int debug_init(void); static int debug_init(void);
...@@ -1450,17 +1448,13 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, ...@@ -1450,17 +1448,13 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
int area, debug_entry_t * entry, char *out_buf) int area, debug_entry_t * entry, char *out_buf)
{ {
struct timespec time_spec; struct timespec time_spec;
unsigned long long time;
char *except_str; char *except_str;
unsigned long caller; unsigned long caller;
int rc = 0; int rc = 0;
unsigned int level; unsigned int level;
level = entry->id.fields.level; level = entry->id.fields.level;
time = entry->id.stck; stck_to_timespec(entry->id.stck, &time_spec);
/* adjust todclock to 1970 */
time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
tod_to_timeval(time, &time_spec);
if (entry->id.fields.exception) if (entry->id.fields.exception)
except_str = "*"; except_str = "*";
......
...@@ -91,6 +91,7 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) ...@@ -91,6 +91,7 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
todval -= (sec * 1000000) << 12; todval -= (sec * 1000000) << 12;
xtime->tv_nsec = ((todval * 1000) >> 12); xtime->tv_nsec = ((todval * 1000) >> 12);
} }
EXPORT_SYMBOL(tod_to_timeval);
void clock_comparator_work(void) void clock_comparator_work(void)
{ {
......
...@@ -64,6 +64,7 @@ struct multipath { ...@@ -64,6 +64,7 @@ struct multipath {
spinlock_t lock; spinlock_t lock;
const char *hw_handler_name; const char *hw_handler_name;
char *hw_handler_params;
unsigned nr_priority_groups; unsigned nr_priority_groups;
struct list_head priority_groups; struct list_head priority_groups;
unsigned pg_init_required; /* pg_init needs calling? */ unsigned pg_init_required; /* pg_init needs calling? */
...@@ -219,6 +220,7 @@ static void free_multipath(struct multipath *m) ...@@ -219,6 +220,7 @@ static void free_multipath(struct multipath *m)
} }
kfree(m->hw_handler_name); kfree(m->hw_handler_name);
kfree(m->hw_handler_params);
mempool_destroy(m->mpio_pool); mempool_destroy(m->mpio_pool);
kfree(m); kfree(m);
} }
...@@ -615,6 +617,17 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps, ...@@ -615,6 +617,17 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
dm_put_device(ti, p->path.dev); dm_put_device(ti, p->path.dev);
goto bad; goto bad;
} }
if (m->hw_handler_params) {
r = scsi_dh_set_params(q, m->hw_handler_params);
if (r < 0) {
ti->error = "unable to set hardware "
"handler parameters";
scsi_dh_detach(q);
dm_put_device(ti, p->path.dev);
goto bad;
}
}
} }
r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error); r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
...@@ -705,6 +718,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as, ...@@ -705,6 +718,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
static int parse_hw_handler(struct arg_set *as, struct multipath *m) static int parse_hw_handler(struct arg_set *as, struct multipath *m)
{ {
unsigned hw_argc; unsigned hw_argc;
int ret;
struct dm_target *ti = m->ti; struct dm_target *ti = m->ti;
static struct param _params[] = { static struct param _params[] = {
...@@ -726,17 +740,33 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m) ...@@ -726,17 +740,33 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
request_module("scsi_dh_%s", m->hw_handler_name); request_module("scsi_dh_%s", m->hw_handler_name);
if (scsi_dh_handler_exist(m->hw_handler_name) == 0) { if (scsi_dh_handler_exist(m->hw_handler_name) == 0) {
ti->error = "unknown hardware handler type"; ti->error = "unknown hardware handler type";
kfree(m->hw_handler_name); ret = -EINVAL;
m->hw_handler_name = NULL; goto fail;
return -EINVAL;
} }
if (hw_argc > 1) if (hw_argc > 1) {
DMWARN("Ignoring user-specified arguments for " char *p;
"hardware handler \"%s\"", m->hw_handler_name); int i, j, len = 4;
for (i = 0; i <= hw_argc - 2; i++)
len += strlen(as->argv[i]) + 1;
p = m->hw_handler_params = kzalloc(len, GFP_KERNEL);
if (!p) {
ti->error = "memory allocation failed";
ret = -ENOMEM;
goto fail;
}
j = sprintf(p, "%d", hw_argc - 1);
for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1)
j = sprintf(p, "%s", as->argv[i]);
}
consume(as, hw_argc - 1); consume(as, hw_argc - 1);
return 0; return 0;
fail:
kfree(m->hw_handler_name);
m->hw_handler_name = NULL;
return ret;
} }
static int parse_features(struct arg_set *as, struct multipath *m) static int parse_features(struct arg_set *as, struct multipath *m)
......
...@@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) ...@@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
{ {
SGESimple64_t *pSge = (SGESimple64_t *) pAddr; SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
pSge->Address.Low = cpu_to_le32 pSge->Address.Low = cpu_to_le32
(lower_32_bits((unsigned long)(dma_addr))); (lower_32_bits(dma_addr));
pSge->Address.High = cpu_to_le32 pSge->Address.High = cpu_to_le32
(upper_32_bits((unsigned long)dma_addr)); (upper_32_bits(dma_addr));
pSge->FlagsLength = cpu_to_le32 pSge->FlagsLength = cpu_to_le32
((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
} }
...@@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) ...@@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
u32 tmp; u32 tmp;
pSge->Address.Low = cpu_to_le32 pSge->Address.Low = cpu_to_le32
(lower_32_bits((unsigned long)(dma_addr))); (lower_32_bits(dma_addr));
tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); tmp = (u32)(upper_32_bits(dma_addr));
/* /*
* 1078 errata workaround for the 36GB limitation * 1078 errata workaround for the 36GB limitation
...@@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) ...@@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
pChain->NextChainOffset = next; pChain->NextChainOffset = next;
pChain->Address.Low = cpu_to_le32(tmp); pChain->Address.Low = cpu_to_le32(tmp);
tmp = (u32)(upper_32_bits((unsigned long)dma_addr)); tmp = (u32)(upper_32_bits(dma_addr));
pChain->Address.High = cpu_to_le32(tmp); pChain->Address.High = cpu_to_le32(tmp);
} }
...@@ -1297,12 +1297,8 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) ...@@ -1297,12 +1297,8 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
psge = (char *)&ioc_init->HostPageBufferSGE; psge = (char *)&ioc_init->HostPageBufferSGE;
flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_SYSTEM_ADDRESS | MPI_SGE_FLAGS_SYSTEM_ADDRESS |
MPI_SGE_FLAGS_32_BIT_ADDRESSING |
MPI_SGE_FLAGS_HOST_TO_IOC | MPI_SGE_FLAGS_HOST_TO_IOC |
MPI_SGE_FLAGS_END_OF_BUFFER; MPI_SGE_FLAGS_END_OF_BUFFER;
if (sizeof(dma_addr_t) == sizeof(u64)) {
flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
}
flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
flags_length |= ioc->HostPageBuffer_sz; flags_length |= ioc->HostPageBuffer_sz;
ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
...@@ -2224,8 +2220,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ...@@ -2224,8 +2220,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
int hard; int hard;
int rc=0; int rc=0;
int ii; int ii;
u8 cb_idx;
int handlers;
int ret = 0; int ret = 0;
int reset_alt_ioc_active = 0; int reset_alt_ioc_active = 0;
int irq_allocated = 0; int irq_allocated = 0;
...@@ -2548,34 +2542,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ...@@ -2548,34 +2542,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
mpt_get_manufacturing_pg_0(ioc); mpt_get_manufacturing_pg_0(ioc);
} }
/*
* Call each currently registered protocol IOC reset handler
* with post-reset indication.
* NOTE: If we're doing _IOC_BRINGUP, there can be no
* MptResetHandlers[] registered yet.
*/
if (hard_reset_done) {
rc = handlers = 0;
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
if ((ret == 0) && MptResetHandlers[cb_idx]) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling IOC post_reset handler #%d\n",
ioc->name, cb_idx));
rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
handlers++;
}
if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling IOC post_reset handler #%d\n",
ioc->alt_ioc->name, cb_idx));
rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
}
}
/* FIXME? Examine results here? */
}
out: out:
if ((ret != 0) && irq_allocated) { if ((ret != 0) && irq_allocated) {
free_irq(ioc->pci_irq, ioc); free_irq(ioc->pci_irq, ioc);
...@@ -3938,6 +3904,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) ...@@ -3938,6 +3904,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
int count = 0; int count = 0;
u32 diag1val = 0; u32 diag1val = 0;
MpiFwHeader_t *cached_fw; /* Pointer to FW */ MpiFwHeader_t *cached_fw; /* Pointer to FW */
u8 cb_idx;
/* Clear any existing interrupts */ /* Clear any existing interrupts */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
...@@ -3956,6 +3923,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) ...@@ -3956,6 +3923,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
else else
mdelay(1); mdelay(1);
/*
* Call each currently registered protocol IOC reset handler
* with pre-reset indication.
* NOTE: If we're doing _IOC_BRINGUP, there can be no
* MptResetHandlers[] registered yet.
*/
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
if (MptResetHandlers[cb_idx])
(*(MptResetHandlers[cb_idx]))(ioc,
MPT_IOC_PRE_RESET);
}
for (count = 0; count < 60; count ++) { for (count = 0; count < 60; count ++) {
doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
doorbell &= MPI_IOC_STATE_MASK; doorbell &= MPI_IOC_STATE_MASK;
...@@ -4052,25 +4031,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) ...@@ -4052,25 +4031,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
* NOTE: If we're doing _IOC_BRINGUP, there can be no * NOTE: If we're doing _IOC_BRINGUP, there can be no
* MptResetHandlers[] registered yet. * MptResetHandlers[] registered yet.
*/ */
{ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
u8 cb_idx; if (MptResetHandlers[cb_idx]) {
int r = 0; mpt_signal_reset(cb_idx,
ioc, MPT_IOC_PRE_RESET);
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if (ioc->alt_ioc) {
if (MptResetHandlers[cb_idx]) { mpt_signal_reset(cb_idx,
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ioc->alt_ioc, MPT_IOC_PRE_RESET);
"Calling IOC pre_reset handler #%d\n",
ioc->name, cb_idx));
r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
if (ioc->alt_ioc) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling alt-%s pre_reset handler #%d\n",
ioc->name, ioc->alt_ioc->name, cb_idx));
r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
} }
} }
/* FIXME? Examine results here? */
} }
if (ioc->cached_fw) if (ioc->cached_fw)
...@@ -6956,7 +6925,7 @@ EXPORT_SYMBOL(mpt_halt_firmware); ...@@ -6956,7 +6925,7 @@ EXPORT_SYMBOL(mpt_halt_firmware);
int int
mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
{ {
int rc; int rc;
u8 cb_idx; u8 cb_idx;
unsigned long flags; unsigned long flags;
unsigned long time_count; unsigned long time_count;
...@@ -6982,8 +6951,6 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ...@@ -6982,8 +6951,6 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
ioc->alt_ioc->ioc_reset_in_progress = 1; ioc->alt_ioc->ioc_reset_in_progress = 1;
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
/* FIXME: If do_ioc_recovery fails, repeat....
*/
/* The SCSI driver needs to adjust timeouts on all current /* The SCSI driver needs to adjust timeouts on all current
* commands prior to the diagnostic reset being issued. * commands prior to the diagnostic reset being issued.
...@@ -7020,6 +6987,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ...@@ -7020,6 +6987,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
} }
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
if (MptResetHandlers[cb_idx]) {
mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
if (ioc->alt_ioc)
mpt_signal_reset(cb_idx,
ioc->alt_ioc, MPT_IOC_POST_RESET);
}
}
dtmprintk(ioc, dtmprintk(ioc,
printk(MYIOC_s_DEBUG_FMT printk(MYIOC_s_DEBUG_FMT
"HardResetHandler: completed (%d seconds): %s\n", ioc->name, "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
......
...@@ -76,8 +76,8 @@ ...@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif #endif
#define MPT_LINUX_VERSION_COMMON "3.04.10" #define MPT_LINUX_VERSION_COMMON "3.04.12"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.09" #define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.12"
#define WHAT_MAGIC_STRING "@" "(" "#" ")" #define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \ #define show_mptmod_ver(s,ver) \
...@@ -157,8 +157,9 @@ ...@@ -157,8 +157,9 @@
/* /*
* Try to keep these at 2^N-1 * Try to keep these at 2^N-1
*/ */
#define MPT_FC_CAN_QUEUE 127 #define MPT_FC_CAN_QUEUE 1024
#define MPT_SCSI_CAN_QUEUE 127 #define MPT_SCSI_CAN_QUEUE 127
#define MPT_SAS_CAN_QUEUE 127
/* /*
* Set the MAX_SGE value based on user input. * Set the MAX_SGE value based on user input.
...@@ -879,23 +880,9 @@ typedef enum { ...@@ -879,23 +880,9 @@ typedef enum {
typedef struct _MPT_SCSI_HOST { typedef struct _MPT_SCSI_HOST {
MPT_ADAPTER *ioc; MPT_ADAPTER *ioc;
int port;
u32 pad0;
MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
struct timer_list timer;
/* Pool of memory for holding SCpnts before doing
* OS callbacks. freeQ is the free pool.
*/
u8 negoNvram; /* DV disabled, nego NVRAM */
u8 pad1;
u8 rsvd[2];
MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */
struct scsi_cmnd *abortSCpnt;
MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */
ushort sel_timeout[MPT_MAX_FC_DEVICES]; ushort sel_timeout[MPT_MAX_FC_DEVICES];
char *info_kbuf; char *info_kbuf;
long last_queue_full; long last_queue_full;
u16 tm_iocstatus;
u16 spi_pending; u16 spi_pending;
struct list_head target_reset_list; struct list_head target_reset_list;
} MPT_SCSI_HOST; } MPT_SCSI_HOST;
......
...@@ -1288,25 +1288,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1288,25 +1288,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup)); ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
hd->abortSCpnt = NULL;
/* Clear the pointer used to store
* single-threaded commands, i.e., those
* issued during a bus scan, dv and
* configuration pages.
*/
hd->cmdPtr = NULL;
/* Initialize this SCSI Hosts' timers
* To use, set the timer expires field
* and add_timer
*/
init_timer(&hd->timer);
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
hd->last_queue_full = 0; hd->last_queue_full = 0;
sh->transportt = mptfc_transport_template; sh->transportt = mptfc_transport_template;
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
*/ */
#define MPTSAS_RAID_CHANNEL 1 #define MPTSAS_RAID_CHANNEL 1
#define SAS_CONFIG_PAGE_TIMEOUT 30
MODULE_AUTHOR(MODULEAUTHOR); MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME); MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -324,7 +325,6 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) ...@@ -324,7 +325,6 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
{ {
struct fw_event_work *fw_event, *next; struct fw_event_work *fw_event, *next;
struct mptsas_target_reset_event *target_reset_list, *n; struct mptsas_target_reset_event *target_reset_list, *n;
u8 flush_q;
MPT_SCSI_HOST *hd = shost_priv(ioc->sh); MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
/* flush the target_reset_list */ /* flush the target_reset_list */
...@@ -344,15 +344,10 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) ...@@ -344,15 +344,10 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
!ioc->fw_event_q || in_interrupt()) !ioc->fw_event_q || in_interrupt())
return; return;
flush_q = 0;
list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
if (cancel_delayed_work(&fw_event->work)) if (cancel_delayed_work(&fw_event->work))
mptsas_free_fw_event(ioc, fw_event); mptsas_free_fw_event(ioc, fw_event);
else
flush_q = 1;
} }
if (flush_q)
flush_workqueue(ioc->fw_event_q);
} }
...@@ -661,7 +656,7 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, ...@@ -661,7 +656,7 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
cfg.pageAddr = starget->id; cfg.pageAddr = starget->id;
cfg.cfghdr.hdr = &hdr; cfg.cfghdr.hdr = &hdr;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
if (mpt_config(ioc, &cfg) != 0) if (mpt_config(ioc, &cfg) != 0)
goto out; goto out;
...@@ -851,7 +846,13 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) ...@@ -851,7 +846,13 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details->num_phys--; port_details->num_phys--;
port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
sas_port_delete_phy(port_details->port, phy_info->phy); if (phy_info->phy) {
devtprintk(ioc, dev_printk(KERN_DEBUG,
&phy_info->phy->dev, MYIOC_s_FMT
"delete phy %d, phy-obj (0x%p)\n", ioc->name,
phy_info->phy_id, phy_info->phy));
sas_port_delete_phy(port_details->port, phy_info->phy);
}
phy_info->port_details = NULL; phy_info->port_details = NULL;
} }
...@@ -1272,7 +1273,6 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) ...@@ -1272,7 +1273,6 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
} }
mptsas_cleanup_fw_event_q(ioc); mptsas_cleanup_fw_event_q(ioc);
mptsas_queue_rescan(ioc); mptsas_queue_rescan(ioc);
mptsas_fw_event_on(ioc);
break; break;
default: default:
break; break;
...@@ -1318,7 +1318,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, ...@@ -1318,7 +1318,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
cfg.pageAddr = form + form_specific; cfg.pageAddr = form + form_specific;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
if (error) if (error)
...@@ -1592,6 +1592,7 @@ mptsas_firmware_event_work(struct work_struct *work) ...@@ -1592,6 +1592,7 @@ mptsas_firmware_event_work(struct work_struct *work)
mptsas_scan_sas_topology(ioc); mptsas_scan_sas_topology(ioc);
ioc->in_rescan = 0; ioc->in_rescan = 0;
mptsas_free_fw_event(ioc, fw_event); mptsas_free_fw_event(ioc, fw_event);
mptsas_fw_event_on(ioc);
return; return;
} }
...@@ -1891,7 +1892,7 @@ static struct scsi_host_template mptsas_driver_template = { ...@@ -1891,7 +1892,7 @@ static struct scsi_host_template mptsas_driver_template = {
.eh_bus_reset_handler = mptscsih_bus_reset, .eh_bus_reset_handler = mptscsih_bus_reset,
.eh_host_reset_handler = mptscsih_host_reset, .eh_host_reset_handler = mptscsih_host_reset,
.bios_param = mptscsih_bios_param, .bios_param = mptscsih_bios_param,
.can_queue = MPT_FC_CAN_QUEUE, .can_queue = MPT_SAS_CAN_QUEUE,
.this_id = -1, .this_id = -1,
.sg_tablesize = MPT_SCSI_SG_DEPTH, .sg_tablesize = MPT_SCSI_SG_DEPTH,
.max_sectors = 8192, .max_sectors = 8192,
...@@ -1926,7 +1927,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) ...@@ -1926,7 +1927,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
cfg.pageAddr = phy->identify.phy_identifier; cfg.pageAddr = phy->identify.phy_identifier;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
if (error) if (error)
...@@ -2278,7 +2279,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) ...@@ -2278,7 +2279,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
cfg.pageAddr = 0; cfg.pageAddr = 0;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
if (error) if (error)
...@@ -2349,7 +2350,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) ...@@ -2349,7 +2350,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
cfg.cfghdr.ehdr = &hdr; cfg.cfghdr.ehdr = &hdr;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
...@@ -2411,7 +2412,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, ...@@ -2411,7 +2412,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
cfg.cfghdr.ehdr = &hdr; cfg.cfghdr.ehdr = &hdr;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
/* Get Phy Pg 0 for each Phy. */ /* Get Phy Pg 0 for each Phy. */
cfg.physAddr = -1; cfg.physAddr = -1;
...@@ -2479,7 +2480,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, ...@@ -2479,7 +2480,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
cfg.physAddr = -1; cfg.physAddr = -1;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
memset(device_info, 0, sizeof(struct mptsas_devinfo)); memset(device_info, 0, sizeof(struct mptsas_devinfo));
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
...@@ -2554,7 +2555,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, ...@@ -2554,7 +2555,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
cfg.pageAddr = form + form_specific; cfg.pageAddr = form + form_specific;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
memset(port_info, 0, sizeof(struct mptsas_portinfo)); memset(port_info, 0, sizeof(struct mptsas_portinfo));
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
...@@ -2635,7 +2636,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, ...@@ -2635,7 +2636,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
cfg.pageAddr = form + form_specific; cfg.pageAddr = form + form_specific;
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
cfg.dir = 0; /* read */ cfg.dir = 0; /* read */
cfg.timeout = 10; cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
error = mpt_config(ioc, &cfg); error = mpt_config(ioc, &cfg);
if (error) if (error)
...@@ -3307,6 +3308,7 @@ mptsas_send_expander_event(struct fw_event_work *fw_event) ...@@ -3307,6 +3308,7 @@ mptsas_send_expander_event(struct fw_event_work *fw_event)
expander_data = (MpiEventDataSasExpanderStatusChange_t *) expander_data = (MpiEventDataSasExpanderStatusChange_t *)
fw_event->event_data; fw_event->event_data;
memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
sas_address = le64_to_cpu(sas_address);
port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
...@@ -4760,10 +4762,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -4760,10 +4762,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* set 16 byte cdb's */ /* set 16 byte cdb's */
sh->max_cmd_len = 16; sh->max_cmd_len = 16;
sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
sh->max_id = ioc->pfacts[0].PortSCSIID; sh->max_id = -1;
sh->max_lun = max_lun; sh->max_lun = max_lun;
sh->transportt = mptsas_transport_template; sh->transportt = mptsas_transport_template;
/* Required entry. /* Required entry.
...@@ -4821,25 +4822,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -4821,25 +4822,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup)); ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
hd->abortSCpnt = NULL;
/* Clear the pointer used to store
* single-threaded commands, i.e., those
* issued during a bus scan, dv and
* configuration pages.
*/
hd->cmdPtr = NULL;
/* Initialize this SCSI Hosts' timers
* To use, set the timer expires field
* and add_timer
*/
init_timer(&hd->timer);
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
ioc->sas_data.ptClear = mpt_pt_clear; ioc->sas_data.ptClear = mpt_pt_clear;
hd->last_queue_full = 0; hd->last_queue_full = 0;
......
...@@ -628,6 +628,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -628,6 +628,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
return 1; return 1;
} }
if (ioc->bus_type == SAS) {
VirtDevice *vdevice = sc->device->hostdata;
if (!vdevice || !vdevice->vtarget ||
vdevice->vtarget->deleted) {
sc->result = DID_NO_CONNECT << 16;
goto out;
}
}
sc->host_scribble = NULL; sc->host_scribble = NULL;
sc->result = DID_OK << 16; /* Set default reply as OK */ sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf; pScsiReq = (SCSIIORequest_t *) mf;
...@@ -689,6 +699,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -689,6 +699,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
switch(status) { switch(status) {
case MPI_IOCSTATUS_BUSY: /* 0x0002 */ case MPI_IOCSTATUS_BUSY: /* 0x0002 */
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
/* CHECKME! /* CHECKME!
* Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)
* But not: DID_BUS_BUSY lest one risk * But not: DID_BUS_BUSY lest one risk
...@@ -872,7 +883,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -872,7 +883,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
...@@ -892,7 +902,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -892,7 +902,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
#endif #endif
} /* end of address reply case */ } /* end of address reply case */
out:
/* Unmap the DMA buffers, if any. */ /* Unmap the DMA buffers, if any. */
scsi_dma_unmap(sc); scsi_dma_unmap(sc);
...@@ -1729,9 +1739,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) ...@@ -1729,9 +1739,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
*/ */
mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
hd->abortSCpnt = SCpnt;
retval = mptscsih_IssueTaskMgmt(hd, retval = mptscsih_IssueTaskMgmt(hd,
MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
vdevice->vtarget->channel, vdevice->vtarget->channel,
...@@ -2293,7 +2300,10 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) ...@@ -2293,7 +2300,10 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
else else
max_depth = MPT_SCSI_CMD_PER_DEV_LOW; max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
} else } else
max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; max_depth = ioc->sh->can_queue;
if (!sdev->tagged_supported)
max_depth = 1;
if (qdepth > max_depth) if (qdepth > max_depth)
qdepth = max_depth; qdepth = max_depth;
...@@ -2627,50 +2637,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, ...@@ -2627,50 +2637,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
return 1; return 1;
} }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* mptscsih_timer_expired - Call back for timer process.
* Used only for dv functionality.
* @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
*
*/
void
mptscsih_timer_expired(unsigned long data)
{
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
MPT_ADAPTER *ioc = hd->ioc;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
if (hd->cmdPtr) {
MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
/* Desire to issue a task management request here.
* TM requests MUST be single threaded.
* If old eh code and no TM current, issue request.
* If new eh code, do nothing. Wait for OS cmd timeout
* for bus reset.
*/
} else {
/* Perform a FW reload */
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
}
}
} else {
/* This should NEVER happen */
printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
}
/* No more processing.
* TM call will generate an interrupt for SCSI TM Management.
* The FW will reply to all outstanding commands, callback will finish cleanup.
* Hard reset clean-up will free all resources.
*/
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
return;
}
/** /**
* mptscsih_get_completion_code - * mptscsih_get_completion_code -
...@@ -3265,6 +3231,5 @@ EXPORT_SYMBOL(mptscsih_scandv_complete); ...@@ -3265,6 +3231,5 @@ EXPORT_SYMBOL(mptscsih_scandv_complete);
EXPORT_SYMBOL(mptscsih_event_process); EXPORT_SYMBOL(mptscsih_event_process);
EXPORT_SYMBOL(mptscsih_ioc_reset); EXPORT_SYMBOL(mptscsih_ioc_reset);
EXPORT_SYMBOL(mptscsih_change_queue_depth); EXPORT_SYMBOL(mptscsih_change_queue_depth);
EXPORT_SYMBOL(mptscsih_timer_expired);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
...@@ -129,7 +129,6 @@ extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRA ...@@ -129,7 +129,6 @@ extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRA
extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
extern void mptscsih_timer_expired(unsigned long data);
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern struct device_attribute *mptscsih_host_attrs[]; extern struct device_attribute *mptscsih_host_attrs[];
......
...@@ -1472,28 +1472,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1472,28 +1472,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup)); ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
hd->abortSCpnt = NULL;
/* Clear the pointer used to store
* single-threaded commands, i.e., those
* issued during a bus scan, dv and
* configuration pages.
*/
hd->cmdPtr = NULL;
/* Initialize this SCSI Hosts' timers
* To use, set the timer expires field
* and add_timer
*/
init_timer(&hd->timer);
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
ioc->spi_data.Saf_Te = mpt_saf_te; ioc->spi_data.Saf_Te = mpt_saf_te;
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"saf_te %x\n", "saf_te %x\n",
ioc->name, ioc->name,
......
...@@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock); ...@@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock);
static struct class enclosure_class; static struct class enclosure_class;
/** /**
* enclosure_find - find an enclosure given a device * enclosure_find - find an enclosure given a parent device
* @dev: the device to find for * @dev: the parent to match against
* @start: Optional enclosure device to start from (NULL if none)
* *
* Looks through the list of registered enclosures to see * Looks through the list of registered enclosures to find all those
* if it can find a match for a device. Returns NULL if no * with @dev as a parent. Returns NULL if no enclosure is
* enclosure is found. Obtains a reference to the enclosure class * found. @start can be used as a starting point to obtain multiple
* device which must be released with device_put(). * enclosures per parent (should begin with NULL and then be set to
* each returned enclosure device). Obtains a reference to the
* enclosure class device which must be released with device_put().
* If @start is not NULL, a reference must be taken on it which is
* released before returning (this allows a loop through all
* enclosures to exit with only the reference on the enclosure of
* interest held). Note that the @dev may correspond to the actual
* device housing the enclosure, in which case no iteration via @start
* is required.
*/ */
struct enclosure_device *enclosure_find(struct device *dev) struct enclosure_device *enclosure_find(struct device *dev,
struct enclosure_device *start)
{ {
struct enclosure_device *edev; struct enclosure_device *edev;
mutex_lock(&container_list_lock); mutex_lock(&container_list_lock);
list_for_each_entry(edev, &container_list, node) { edev = list_prepare_entry(start, &container_list, node);
if (edev->edev.parent == dev) { if (start)
get_device(&edev->edev); put_device(&start->edev);
mutex_unlock(&container_list_lock);
return edev; list_for_each_entry_continue(edev, &container_list, node) {
struct device *parent = edev->edev.parent;
/* parent might not be immediate, so iterate up to
* the root of the tree if necessary */
while (parent) {
if (parent == dev) {
get_device(&edev->edev);
mutex_unlock(&container_list_lock);
return edev;
}
parent = parent->parent;
} }
} }
mutex_unlock(&container_list_lock); mutex_unlock(&container_list_lock);
...@@ -295,6 +315,9 @@ int enclosure_add_device(struct enclosure_device *edev, int component, ...@@ -295,6 +315,9 @@ int enclosure_add_device(struct enclosure_device *edev, int component,
cdev = &edev->component[component]; cdev = &edev->component[component];
if (cdev->dev == dev)
return -EEXIST;
if (cdev->dev) if (cdev->dev)
enclosure_remove_links(cdev); enclosure_remove_links(cdev);
...@@ -312,19 +335,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); ...@@ -312,19 +335,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device);
* Returns zero on success or an error. * Returns zero on success or an error.
* *
*/ */
int enclosure_remove_device(struct enclosure_device *edev, int component) int enclosure_remove_device(struct enclosure_device *edev, struct device *dev)
{ {
struct enclosure_component *cdev; struct enclosure_component *cdev;
int i;
if (!edev || component >= edev->components) if (!edev || !dev)
return -EINVAL; return -EINVAL;
cdev = &edev->component[component]; for (i = 0; i < edev->components; i++) {
cdev = &edev->component[i];
device_del(&cdev->cdev); if (cdev->dev == dev) {
put_device(cdev->dev); enclosure_remove_links(cdev);
cdev->dev = NULL; device_del(&cdev->cdev);
return device_add(&cdev->cdev); put_device(dev);
cdev->dev = NULL;
return device_add(&cdev->cdev);
}
}
return -ENODEV;
} }
EXPORT_SYMBOL_GPL(enclosure_remove_device); EXPORT_SYMBOL_GPL(enclosure_remove_device);
......
...@@ -42,6 +42,12 @@ static char *init_device; ...@@ -42,6 +42,12 @@ static char *init_device;
module_param_named(device, init_device, charp, 0400); module_param_named(device, init_device, charp, 0400);
MODULE_PARM_DESC(device, "specify initial device"); MODULE_PARM_DESC(device, "specify initial device");
static struct kmem_cache *zfcp_cache_hw_align(const char *name,
unsigned long size)
{
return kmem_cache_create(name, size, roundup_pow_of_two(size), 0, NULL);
}
static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
{ {
int idx; int idx;
...@@ -78,7 +84,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) ...@@ -78,7 +84,7 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
struct zfcp_port *port; struct zfcp_port *port;
struct zfcp_unit *unit; struct zfcp_unit *unit;
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
read_lock_irq(&zfcp_data.config_lock); read_lock_irq(&zfcp_data.config_lock);
adapter = zfcp_get_adapter_by_busid(busid); adapter = zfcp_get_adapter_by_busid(busid);
if (adapter) if (adapter)
...@@ -93,31 +99,23 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) ...@@ -93,31 +99,23 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
unit = zfcp_unit_enqueue(port, lun); unit = zfcp_unit_enqueue(port, lun);
if (IS_ERR(unit)) if (IS_ERR(unit))
goto out_unit; goto out_unit;
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
ccw_device_set_online(adapter->ccw_device); ccw_device_set_online(adapter->ccw_device);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
flush_work(&unit->scsi_work); flush_work(&unit->scsi_work);
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
zfcp_unit_put(unit); zfcp_unit_put(unit);
out_unit: out_unit:
zfcp_port_put(port); zfcp_port_put(port);
out_port: out_port:
zfcp_adapter_put(adapter); zfcp_adapter_put(adapter);
out_adapter: out_adapter:
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return; return;
} }
static struct kmem_cache *zfcp_cache_create(int size, char *name)
{
int align = 1;
while ((size - align) > 0)
align <<= 1;
return kmem_cache_create(name , size, align, 0, NULL);
}
static void __init zfcp_init_device_setup(char *devstr) static void __init zfcp_init_device_setup(char *devstr)
{ {
char *token; char *token;
...@@ -158,24 +156,27 @@ static int __init zfcp_module_init(void) ...@@ -158,24 +156,27 @@ static int __init zfcp_module_init(void)
{ {
int retval = -ENOMEM; int retval = -ENOMEM;
zfcp_data.fsf_req_qtcb_cache = zfcp_cache_create( zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn",
sizeof(struct zfcp_fsf_req_qtcb), "zfcp_fsf"); sizeof(struct ct_iu_gpn_ft_req));
if (!zfcp_data.fsf_req_qtcb_cache) if (!zfcp_data.gpn_ft_cache)
goto out; goto out;
zfcp_data.sr_buffer_cache = zfcp_cache_create( zfcp_data.qtcb_cache = zfcp_cache_hw_align("zfcp_qtcb",
sizeof(struct fsf_status_read_buffer), "zfcp_sr"); sizeof(struct fsf_qtcb));
if (!zfcp_data.qtcb_cache)
goto out_qtcb_cache;
zfcp_data.sr_buffer_cache = zfcp_cache_hw_align("zfcp_sr",
sizeof(struct fsf_status_read_buffer));
if (!zfcp_data.sr_buffer_cache) if (!zfcp_data.sr_buffer_cache)
goto out_sr_cache; goto out_sr_cache;
zfcp_data.gid_pn_cache = zfcp_cache_create( zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid",
sizeof(struct zfcp_gid_pn_data), "zfcp_gid"); sizeof(struct zfcp_gid_pn_data));
if (!zfcp_data.gid_pn_cache) if (!zfcp_data.gid_pn_cache)
goto out_gid_cache; goto out_gid_cache;
zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq"); mutex_init(&zfcp_data.config_mutex);
sema_init(&zfcp_data.config_sema, 1);
rwlock_init(&zfcp_data.config_lock); rwlock_init(&zfcp_data.config_lock);
zfcp_data.scsi_transport_template = zfcp_data.scsi_transport_template =
...@@ -209,7 +210,9 @@ static int __init zfcp_module_init(void) ...@@ -209,7 +210,9 @@ static int __init zfcp_module_init(void)
out_gid_cache: out_gid_cache:
kmem_cache_destroy(zfcp_data.sr_buffer_cache); kmem_cache_destroy(zfcp_data.sr_buffer_cache);
out_sr_cache: out_sr_cache:
kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache); kmem_cache_destroy(zfcp_data.qtcb_cache);
out_qtcb_cache:
kmem_cache_destroy(zfcp_data.gpn_ft_cache);
out: out:
return retval; return retval;
} }
...@@ -263,7 +266,7 @@ static void zfcp_sysfs_unit_release(struct device *dev) ...@@ -263,7 +266,7 @@ static void zfcp_sysfs_unit_release(struct device *dev)
* @port: pointer to port where unit is added * @port: pointer to port where unit is added
* @fcp_lun: FCP LUN of unit to be enqueued * @fcp_lun: FCP LUN of unit to be enqueued
* Returns: pointer to enqueued unit on success, ERR_PTR on error * Returns: pointer to enqueued unit on success, ERR_PTR on error
* Locks: config_sema must be held to serialize changes to the unit list * Locks: config_mutex must be held to serialize changes to the unit list
* *
* Sets up some unit internal structures and creates sysfs entry. * Sets up some unit internal structures and creates sysfs entry.
*/ */
...@@ -271,6 +274,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -271,6 +274,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
{ {
struct zfcp_unit *unit; struct zfcp_unit *unit;
read_lock_irq(&zfcp_data.config_lock);
if (zfcp_get_unit_by_lun(port, fcp_lun)) {
read_unlock_irq(&zfcp_data.config_lock);
return ERR_PTR(-EINVAL);
}
read_unlock_irq(&zfcp_data.config_lock);
unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
if (!unit) if (!unit)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -282,8 +292,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -282,8 +292,11 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
unit->port = port; unit->port = port;
unit->fcp_lun = fcp_lun; unit->fcp_lun = fcp_lun;
dev_set_name(&unit->sysfs_device, "0x%016llx", if (dev_set_name(&unit->sysfs_device, "0x%016llx",
(unsigned long long) fcp_lun); (unsigned long long) fcp_lun)) {
kfree(unit);
return ERR_PTR(-ENOMEM);
}
unit->sysfs_device.parent = &port->sysfs_device; unit->sysfs_device.parent = &port->sysfs_device;
unit->sysfs_device.release = zfcp_sysfs_unit_release; unit->sysfs_device.release = zfcp_sysfs_unit_release;
dev_set_drvdata(&unit->sysfs_device, unit); dev_set_drvdata(&unit->sysfs_device, unit);
...@@ -299,20 +312,15 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -299,20 +312,15 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
unit->latencies.cmd.channel.min = 0xFFFFFFFF; unit->latencies.cmd.channel.min = 0xFFFFFFFF;
unit->latencies.cmd.fabric.min = 0xFFFFFFFF; unit->latencies.cmd.fabric.min = 0xFFFFFFFF;
read_lock_irq(&zfcp_data.config_lock); if (device_register(&unit->sysfs_device)) {
if (zfcp_get_unit_by_lun(port, fcp_lun)) { put_device(&unit->sysfs_device);
read_unlock_irq(&zfcp_data.config_lock); return ERR_PTR(-EINVAL);
goto err_out_free;
} }
read_unlock_irq(&zfcp_data.config_lock);
if (device_register(&unit->sysfs_device))
goto err_out_free;
if (sysfs_create_group(&unit->sysfs_device.kobj, if (sysfs_create_group(&unit->sysfs_device.kobj,
&zfcp_sysfs_unit_attrs)) { &zfcp_sysfs_unit_attrs)) {
device_unregister(&unit->sysfs_device); device_unregister(&unit->sysfs_device);
return ERR_PTR(-EIO); return ERR_PTR(-EINVAL);
} }
zfcp_unit_get(unit); zfcp_unit_get(unit);
...@@ -327,10 +335,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) ...@@ -327,10 +335,6 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun)
zfcp_port_get(port); zfcp_port_get(port);
return unit; return unit;
err_out_free:
kfree(unit);
return ERR_PTR(-EINVAL);
} }
/** /**
...@@ -353,37 +357,47 @@ void zfcp_unit_dequeue(struct zfcp_unit *unit) ...@@ -353,37 +357,47 @@ void zfcp_unit_dequeue(struct zfcp_unit *unit)
static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{ {
/* must only be called with zfcp_data.config_sema taken */ /* must only be called with zfcp_data.config_mutex taken */
adapter->pool.fsf_req_erp = adapter->pool.erp_req =
mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
if (!adapter->pool.fsf_req_erp) if (!adapter->pool.erp_req)
return -ENOMEM;
adapter->pool.gid_pn_req =
mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
if (!adapter->pool.gid_pn_req)
return -ENOMEM; return -ENOMEM;
adapter->pool.fsf_req_scsi = adapter->pool.scsi_req =
mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
if (!adapter->pool.fsf_req_scsi) if (!adapter->pool.scsi_req)
return -ENOMEM; return -ENOMEM;
adapter->pool.fsf_req_abort = adapter->pool.scsi_abort =
mempool_create_slab_pool(1, zfcp_data.fsf_req_qtcb_cache); mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
if (!adapter->pool.fsf_req_abort) if (!adapter->pool.scsi_abort)
return -ENOMEM; return -ENOMEM;
adapter->pool.fsf_req_status_read = adapter->pool.status_read_req =
mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM, mempool_create_kmalloc_pool(FSF_STATUS_READS_RECOM,
sizeof(struct zfcp_fsf_req)); sizeof(struct zfcp_fsf_req));
if (!adapter->pool.fsf_req_status_read) if (!adapter->pool.status_read_req)
return -ENOMEM; return -ENOMEM;
adapter->pool.data_status_read = adapter->pool.qtcb_pool =
mempool_create_slab_pool(4, zfcp_data.qtcb_cache);
if (!adapter->pool.qtcb_pool)
return -ENOMEM;
adapter->pool.status_read_data =
mempool_create_slab_pool(FSF_STATUS_READS_RECOM, mempool_create_slab_pool(FSF_STATUS_READS_RECOM,
zfcp_data.sr_buffer_cache); zfcp_data.sr_buffer_cache);
if (!adapter->pool.data_status_read) if (!adapter->pool.status_read_data)
return -ENOMEM; return -ENOMEM;
adapter->pool.data_gid_pn = adapter->pool.gid_pn_data =
mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); mempool_create_slab_pool(1, zfcp_data.gid_pn_cache);
if (!adapter->pool.data_gid_pn) if (!adapter->pool.gid_pn_data)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
...@@ -391,19 +405,21 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) ...@@ -391,19 +405,21 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{ {
/* zfcp_data.config_sema must be held */ /* zfcp_data.config_mutex must be held */
if (adapter->pool.fsf_req_erp) if (adapter->pool.erp_req)
mempool_destroy(adapter->pool.fsf_req_erp); mempool_destroy(adapter->pool.erp_req);
if (adapter->pool.fsf_req_scsi) if (adapter->pool.scsi_req)
mempool_destroy(adapter->pool.fsf_req_scsi); mempool_destroy(adapter->pool.scsi_req);
if (adapter->pool.fsf_req_abort) if (adapter->pool.scsi_abort)
mempool_destroy(adapter->pool.fsf_req_abort); mempool_destroy(adapter->pool.scsi_abort);
if (adapter->pool.fsf_req_status_read) if (adapter->pool.qtcb_pool)
mempool_destroy(adapter->pool.fsf_req_status_read); mempool_destroy(adapter->pool.qtcb_pool);
if (adapter->pool.data_status_read) if (adapter->pool.status_read_req)
mempool_destroy(adapter->pool.data_status_read); mempool_destroy(adapter->pool.status_read_req);
if (adapter->pool.data_gid_pn) if (adapter->pool.status_read_data)
mempool_destroy(adapter->pool.data_gid_pn); mempool_destroy(adapter->pool.status_read_data);
if (adapter->pool.gid_pn_data)
mempool_destroy(adapter->pool.gid_pn_data);
} }
/** /**
...@@ -418,7 +434,7 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) ...@@ -418,7 +434,7 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
int zfcp_status_read_refill(struct zfcp_adapter *adapter) int zfcp_status_read_refill(struct zfcp_adapter *adapter)
{ {
while (atomic_read(&adapter->stat_miss) > 0) while (atomic_read(&adapter->stat_miss) > 0)
if (zfcp_fsf_status_read(adapter)) { if (zfcp_fsf_status_read(adapter->qdio)) {
if (atomic_read(&adapter->stat_miss) >= 16) { if (atomic_read(&adapter->stat_miss) >= 16) {
zfcp_erp_adapter_reopen(adapter, 0, "axsref1", zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
NULL); NULL);
...@@ -446,6 +462,27 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) ...@@ -446,6 +462,27 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl)
adapter->fsf_lic_version); adapter->fsf_lic_version);
} }
static int zfcp_setup_adapter_work_queue(struct zfcp_adapter *adapter)
{
char name[TASK_COMM_LEN];
snprintf(name, sizeof(name), "zfcp_q_%s",
dev_name(&adapter->ccw_device->dev));
adapter->work_queue = create_singlethread_workqueue(name);
if (adapter->work_queue)
return 0;
return -ENOMEM;
}
static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter)
{
if (adapter->work_queue)
destroy_workqueue(adapter->work_queue);
adapter->work_queue = NULL;
}
/** /**
* zfcp_adapter_enqueue - enqueue a new adapter to the list * zfcp_adapter_enqueue - enqueue a new adapter to the list
* @ccw_device: pointer to the struct cc_device * @ccw_device: pointer to the struct cc_device
...@@ -455,7 +492,7 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) ...@@ -455,7 +492,7 @@ static void zfcp_print_sl(struct seq_file *m, struct service_level *sl)
* Enqueues an adapter at the end of the adapter list in the driver data. * Enqueues an adapter at the end of the adapter list in the driver data.
* All adapter internal structures are set up. * All adapter internal structures are set up.
* Proc-fs entries are also created. * Proc-fs entries are also created.
* locks: config_sema must be held to serialise changes to the adapter list * locks: config_mutex must be held to serialize changes to the adapter list
*/ */
int zfcp_adapter_enqueue(struct ccw_device *ccw_device) int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
{ {
...@@ -463,37 +500,37 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -463,37 +500,37 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* /*
* Note: It is safe to release the list_lock, as any list changes * Note: It is safe to release the list_lock, as any list changes
* are protected by the config_sema, which must be held to get here * are protected by the config_mutex, which must be held to get here
*/ */
adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL);
if (!adapter) if (!adapter)
return -ENOMEM; return -ENOMEM;
adapter->gs = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL);
if (!adapter->gs) {
kfree(adapter);
return -ENOMEM;
}
ccw_device->handler = NULL; ccw_device->handler = NULL;
adapter->ccw_device = ccw_device; adapter->ccw_device = ccw_device;
atomic_set(&adapter->refcount, 0); atomic_set(&adapter->refcount, 0);
if (zfcp_qdio_allocate(adapter)) if (zfcp_qdio_setup(adapter))
goto qdio_allocate_failed; goto qdio_failed;
if (zfcp_allocate_low_mem_buffers(adapter)) if (zfcp_allocate_low_mem_buffers(adapter))
goto failed_low_mem_buffers; goto low_mem_buffers_failed;
if (zfcp_reqlist_alloc(adapter)) if (zfcp_reqlist_alloc(adapter))
goto failed_low_mem_buffers; goto low_mem_buffers_failed;
if (zfcp_adapter_debug_register(adapter)) if (zfcp_dbf_adapter_register(adapter))
goto debug_register_failed; goto debug_register_failed;
if (zfcp_setup_adapter_work_queue(adapter))
goto work_queue_failed;
if (zfcp_fc_gs_setup(adapter))
goto generic_services_failed;
init_waitqueue_head(&adapter->remove_wq); init_waitqueue_head(&adapter->remove_wq);
init_waitqueue_head(&adapter->erp_thread_wqh); init_waitqueue_head(&adapter->erp_ready_wq);
init_waitqueue_head(&adapter->erp_done_wqh); init_waitqueue_head(&adapter->erp_done_wqh);
INIT_LIST_HEAD(&adapter->port_list_head); INIT_LIST_HEAD(&adapter->port_list_head);
...@@ -502,20 +539,14 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -502,20 +539,14 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
spin_lock_init(&adapter->req_list_lock); spin_lock_init(&adapter->req_list_lock);
spin_lock_init(&adapter->hba_dbf_lock);
spin_lock_init(&adapter->san_dbf_lock);
spin_lock_init(&adapter->scsi_dbf_lock);
spin_lock_init(&adapter->rec_dbf_lock);
spin_lock_init(&adapter->req_q_lock);
spin_lock_init(&adapter->qdio_stat_lock);
rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->erp_lock);
rwlock_init(&adapter->abort_lock); rwlock_init(&adapter->abort_lock);
sema_init(&adapter->erp_ready_sem, 0); if (zfcp_erp_thread_setup(adapter))
goto erp_thread_failed;
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later);
adapter->service_level.seq_print = zfcp_print_sl; adapter->service_level.seq_print = zfcp_print_sl;
...@@ -529,20 +560,25 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -529,20 +560,25 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
goto sysfs_failed; goto sysfs_failed;
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
zfcp_fc_wka_ports_init(adapter);
if (!zfcp_adapter_scsi_register(adapter)) if (!zfcp_adapter_scsi_register(adapter))
return 0; return 0;
sysfs_failed: sysfs_failed:
zfcp_adapter_debug_unregister(adapter); zfcp_erp_thread_kill(adapter);
erp_thread_failed:
zfcp_fc_gs_destroy(adapter);
generic_services_failed:
zfcp_destroy_adapter_work_queue(adapter);
work_queue_failed:
zfcp_dbf_adapter_unregister(adapter->dbf);
debug_register_failed: debug_register_failed:
dev_set_drvdata(&ccw_device->dev, NULL); dev_set_drvdata(&ccw_device->dev, NULL);
kfree(adapter->req_list); kfree(adapter->req_list);
failed_low_mem_buffers: low_mem_buffers_failed:
zfcp_free_low_mem_buffers(adapter); zfcp_free_low_mem_buffers(adapter);
qdio_allocate_failed: qdio_failed:
zfcp_qdio_free(adapter); zfcp_qdio_destroy(adapter->qdio);
kfree(adapter); kfree(adapter);
return -ENOMEM; return -ENOMEM;
} }
...@@ -559,6 +595,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) ...@@ -559,6 +595,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
cancel_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work); cancel_work_sync(&adapter->stat_work);
zfcp_fc_wka_ports_force_offline(adapter->gs);
zfcp_adapter_scsi_unregister(adapter); zfcp_adapter_scsi_unregister(adapter);
sysfs_remove_group(&adapter->ccw_device->dev.kobj, sysfs_remove_group(&adapter->ccw_device->dev.kobj,
&zfcp_sysfs_adapter_attrs); &zfcp_sysfs_adapter_attrs);
...@@ -570,13 +607,15 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) ...@@ -570,13 +607,15 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
if (!retval) if (!retval)
return; return;
zfcp_adapter_debug_unregister(adapter); zfcp_fc_gs_destroy(adapter);
zfcp_qdio_free(adapter); zfcp_erp_thread_kill(adapter);
zfcp_destroy_adapter_work_queue(adapter);
zfcp_dbf_adapter_unregister(adapter->dbf);
zfcp_free_low_mem_buffers(adapter); zfcp_free_low_mem_buffers(adapter);
zfcp_qdio_destroy(adapter->qdio);
kfree(adapter->req_list); kfree(adapter->req_list);
kfree(adapter->fc_stats); kfree(adapter->fc_stats);
kfree(adapter->stats_reset_data); kfree(adapter->stats_reset_data);
kfree(adapter->gs);
kfree(adapter); kfree(adapter);
} }
...@@ -592,7 +631,7 @@ static void zfcp_sysfs_port_release(struct device *dev) ...@@ -592,7 +631,7 @@ static void zfcp_sysfs_port_release(struct device *dev)
* @status: initial status for the port * @status: initial status for the port
* @d_id: destination id of the remote port to be enqueued * @d_id: destination id of the remote port to be enqueued
* Returns: pointer to enqueued port on success, ERR_PTR on error * Returns: pointer to enqueued port on success, ERR_PTR on error
* Locks: config_sema must be held to serialize changes to the port list * Locks: config_mutex must be held to serialize changes to the port list
* *
* All port internal structures are set up and the sysfs entry is generated. * All port internal structures are set up and the sysfs entry is generated.
* d_id is used to enqueue ports with a well known address like the Directory * d_id is used to enqueue ports with a well known address like the Directory
...@@ -602,7 +641,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -602,7 +641,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
u32 status, u32 d_id) u32 status, u32 d_id)
{ {
struct zfcp_port *port; struct zfcp_port *port;
int retval;
read_lock_irq(&zfcp_data.config_lock);
if (zfcp_get_port_by_wwpn(adapter, wwpn)) {
read_unlock_irq(&zfcp_data.config_lock);
return ERR_PTR(-EINVAL);
}
read_unlock_irq(&zfcp_data.config_lock);
port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL);
if (!port) if (!port)
...@@ -610,7 +655,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -610,7 +655,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
init_waitqueue_head(&port->remove_wq); init_waitqueue_head(&port->remove_wq);
INIT_LIST_HEAD(&port->unit_list_head); INIT_LIST_HEAD(&port->unit_list_head);
INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); INIT_WORK(&port->rport_work, zfcp_scsi_rport_work);
...@@ -623,29 +668,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -623,29 +668,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set(&port->refcount, 0); atomic_set(&port->refcount, 0);
dev_set_name(&port->sysfs_device, "0x%016llx", if (dev_set_name(&port->sysfs_device, "0x%016llx",
(unsigned long long)wwpn); (unsigned long long)wwpn)) {
kfree(port);
return ERR_PTR(-ENOMEM);
}
port->sysfs_device.parent = &adapter->ccw_device->dev; port->sysfs_device.parent = &adapter->ccw_device->dev;
port->sysfs_device.release = zfcp_sysfs_port_release; port->sysfs_device.release = zfcp_sysfs_port_release;
dev_set_drvdata(&port->sysfs_device, port); dev_set_drvdata(&port->sysfs_device, port);
read_lock_irq(&zfcp_data.config_lock); if (device_register(&port->sysfs_device)) {
if (zfcp_get_port_by_wwpn(adapter, wwpn)) { put_device(&port->sysfs_device);
read_unlock_irq(&zfcp_data.config_lock); return ERR_PTR(-EINVAL);
goto err_out_free;
} }
read_unlock_irq(&zfcp_data.config_lock);
if (device_register(&port->sysfs_device)) if (sysfs_create_group(&port->sysfs_device.kobj,
goto err_out_free; &zfcp_sysfs_port_attrs)) {
retval = sysfs_create_group(&port->sysfs_device.kobj,
&zfcp_sysfs_port_attrs);
if (retval) {
device_unregister(&port->sysfs_device); device_unregister(&port->sysfs_device);
goto err_out; return ERR_PTR(-EINVAL);
} }
zfcp_port_get(port); zfcp_port_get(port);
...@@ -659,11 +699,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -659,11 +699,6 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
zfcp_adapter_get(adapter); zfcp_adapter_get(adapter);
return port; return port;
err_out_free:
kfree(port);
err_out:
return ERR_PTR(-EINVAL);
} }
/** /**
...@@ -672,12 +707,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, ...@@ -672,12 +707,11 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
*/ */
void zfcp_port_dequeue(struct zfcp_port *port) void zfcp_port_dequeue(struct zfcp_port *port)
{ {
wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
list_del(&port->list); list_del(&port->list);
write_unlock_irq(&zfcp_data.config_lock); write_unlock_irq(&zfcp_data.config_lock);
if (port->rport) wait_event(port->remove_wq, atomic_read(&port->refcount) == 0);
port->rport->dd_data = NULL; cancel_work_sync(&port->rport_work); /* usually not necessary */
zfcp_adapter_put(port->adapter); zfcp_adapter_put(port->adapter);
sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs);
device_unregister(&port->sysfs_device); device_unregister(&port->sysfs_device);
......
...@@ -18,12 +18,15 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev) ...@@ -18,12 +18,15 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev)
{ {
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
down(&zfcp_data.config_sema); if (!adapter)
return 0;
mutex_lock(&zfcp_data.config_mutex);
zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return 0; return 0;
} }
...@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) ...@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
{ {
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
if (!adapter)
return 0;
zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
...@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) ...@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
* zfcp_ccw_probe - probe function of zfcp driver * zfcp_ccw_probe - probe function of zfcp driver
* @ccw_device: pointer to belonging ccw device * @ccw_device: pointer to belonging ccw device
* *
* This function gets called by the common i/o layer and sets up the initial * This function gets called by the common i/o layer for each FCP
* data structures for each fcp adapter, which was detected by the system. * device found on the current system. This is only a stub to make cio
* Also the sysfs files for this adapter will be created by this function. * work: To only allocate adapter resources for devices actually used,
* In addition the nameserver port will be added to the ports of the adapter * the allocation is deferred to the first call to ccw_set_online.
* and its sysfs representation will be created too.
*/ */
static int zfcp_ccw_probe(struct ccw_device *ccw_device) static int zfcp_ccw_probe(struct ccw_device *ccw_device)
{ {
int retval = 0; return 0;
down(&zfcp_data.config_sema);
if (zfcp_adapter_enqueue(ccw_device)) {
dev_err(&ccw_device->dev,
"Setting up data structures for the "
"FCP adapter failed\n");
retval = -EINVAL;
}
up(&zfcp_data.config_sema);
return retval;
} }
/** /**
...@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
LIST_HEAD(port_remove_lh); LIST_HEAD(port_remove_lh);
ccw_device_set_offline(ccw_device); ccw_device_set_offline(ccw_device);
down(&zfcp_data.config_sema);
mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
...@@ -129,29 +127,41 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -129,29 +127,41 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
zfcp_adapter_dequeue(adapter); zfcp_adapter_dequeue(adapter);
up(&zfcp_data.config_sema); out:
mutex_unlock(&zfcp_data.config_mutex);
} }
/** /**
* zfcp_ccw_set_online - set_online function of zfcp driver * zfcp_ccw_set_online - set_online function of zfcp driver
* @ccw_device: pointer to belonging ccw device * @ccw_device: pointer to belonging ccw device
* *
* This function gets called by the common i/o layer and sets an adapter * This function gets called by the common i/o layer and sets an
* into state online. Setting an fcp device online means that it will be * adapter into state online. The first call will allocate all
* registered with the SCSI stack, that the QDIO queues will be set up * adapter resources that will be retained until the device is removed
* and that the adapter will be opened (asynchronously). * via zfcp_ccw_remove.
*
* Setting an fcp device online means that it will be registered with
* the SCSI stack, that the QDIO queues will be set up and that the
* adapter will be opened.
*/ */
static int zfcp_ccw_set_online(struct ccw_device *ccw_device) static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
int retval; int ret = 0;
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
retval = zfcp_erp_thread_setup(adapter); if (!adapter) {
if (retval) ret = zfcp_adapter_enqueue(ccw_device);
goto out; if (ret) {
dev_err(&ccw_device->dev,
"Setting up data structures for the "
"FCP adapter failed\n");
goto out;
}
adapter = dev_get_drvdata(&ccw_device->dev);
}
/* initialize request counter */ /* initialize request counter */
BUG_ON(!zfcp_reqlist_isempty(adapter)); BUG_ON(!zfcp_reqlist_isempty(adapter));
...@@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) ...@@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"ccsonl2", NULL); "ccsonl2", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema); out:
flush_work(&adapter->scan_work); mutex_unlock(&zfcp_data.config_mutex);
return 0; if (!ret)
flush_work(&adapter->scan_work);
out: return ret;
up(&zfcp_data.config_sema);
return retval;
} }
/** /**
...@@ -182,12 +190,15 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) ...@@ -182,12 +190,15 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter); mutex_unlock(&zfcp_data.config_mutex);
up(&zfcp_data.config_sema); out:
return 0; return 0;
} }
...@@ -240,11 +251,12 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) ...@@ -240,11 +251,12 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&cdev->dev); adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema); zfcp_erp_thread_kill(adapter);
mutex_unlock(&zfcp_data.config_mutex);
} }
static struct ccw_driver zfcp_ccw_driver = { static struct ccw_driver zfcp_ccw_driver = {
......
此差异已折叠。
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* This file is part of the zfcp device driver for * This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries. * FCP adapters for IBM System z9 and zSeries.
* *
* Copyright IBM Corp. 2008, 2008 * Copyright IBM Corp. 2008, 2009
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -22,7 +22,9 @@ ...@@ -22,7 +22,9 @@
#ifndef ZFCP_DBF_H #ifndef ZFCP_DBF_H
#define ZFCP_DBF_H #define ZFCP_DBF_H
#include "zfcp_ext.h"
#include "zfcp_fsf.h" #include "zfcp_fsf.h"
#include "zfcp_def.h"
#define ZFCP_DBF_TAG_SIZE 4 #define ZFCP_DBF_TAG_SIZE 4
#define ZFCP_DBF_ID_SIZE 7 #define ZFCP_DBF_ID_SIZE 7
...@@ -35,13 +37,13 @@ struct zfcp_dbf_dump { ...@@ -35,13 +37,13 @@ struct zfcp_dbf_dump {
u8 data[]; /* dump data */ u8 data[]; /* dump data */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_rec_dbf_record_thread { struct zfcp_dbf_rec_record_thread {
u32 total; u32 total;
u32 ready; u32 ready;
u32 running; u32 running;
}; };
struct zfcp_rec_dbf_record_target { struct zfcp_dbf_rec_record_target {
u64 ref; u64 ref;
u32 status; u32 status;
u32 d_id; u32 d_id;
...@@ -50,7 +52,7 @@ struct zfcp_rec_dbf_record_target { ...@@ -50,7 +52,7 @@ struct zfcp_rec_dbf_record_target {
u32 erp_count; u32 erp_count;
}; };
struct zfcp_rec_dbf_record_trigger { struct zfcp_dbf_rec_record_trigger {
u8 want; u8 want;
u8 need; u8 need;
u32 as; u32 as;
...@@ -62,21 +64,21 @@ struct zfcp_rec_dbf_record_trigger { ...@@ -62,21 +64,21 @@ struct zfcp_rec_dbf_record_trigger {
u64 fcp_lun; u64 fcp_lun;
}; };
struct zfcp_rec_dbf_record_action { struct zfcp_dbf_rec_record_action {
u32 status; u32 status;
u32 step; u32 step;
u64 action; u64 action;
u64 fsf_req; u64 fsf_req;
}; };
struct zfcp_rec_dbf_record { struct zfcp_dbf_rec_record {
u8 id; u8 id;
char id2[7]; char id2[7];
union { union {
struct zfcp_rec_dbf_record_action action; struct zfcp_dbf_rec_record_action action;
struct zfcp_rec_dbf_record_thread thread; struct zfcp_dbf_rec_record_thread thread;
struct zfcp_rec_dbf_record_target target; struct zfcp_dbf_rec_record_target target;
struct zfcp_rec_dbf_record_trigger trigger; struct zfcp_dbf_rec_record_trigger trigger;
} u; } u;
}; };
...@@ -87,7 +89,7 @@ enum { ...@@ -87,7 +89,7 @@ enum {
ZFCP_REC_DBF_ID_TRIGGER, ZFCP_REC_DBF_ID_TRIGGER,
}; };
struct zfcp_hba_dbf_record_response { struct zfcp_dbf_hba_record_response {
u32 fsf_command; u32 fsf_command;
u64 fsf_reqid; u64 fsf_reqid;
u32 fsf_seqno; u32 fsf_seqno;
...@@ -125,7 +127,7 @@ struct zfcp_hba_dbf_record_response { ...@@ -125,7 +127,7 @@ struct zfcp_hba_dbf_record_response {
} u; } u;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_hba_dbf_record_status { struct zfcp_dbf_hba_record_status {
u8 failed; u8 failed;
u32 status_type; u32 status_type;
u32 status_subtype; u32 status_subtype;
...@@ -139,24 +141,24 @@ struct zfcp_hba_dbf_record_status { ...@@ -139,24 +141,24 @@ struct zfcp_hba_dbf_record_status {
u8 payload[ZFCP_DBF_UNSOL_PAYLOAD]; u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_hba_dbf_record_qdio { struct zfcp_dbf_hba_record_qdio {
u32 qdio_error; u32 qdio_error;
u8 sbal_index; u8 sbal_index;
u8 sbal_count; u8 sbal_count;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_hba_dbf_record { struct zfcp_dbf_hba_record {
u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag[ZFCP_DBF_TAG_SIZE];
u8 tag2[ZFCP_DBF_TAG_SIZE]; u8 tag2[ZFCP_DBF_TAG_SIZE];
union { union {
struct zfcp_hba_dbf_record_response response; struct zfcp_dbf_hba_record_response response;
struct zfcp_hba_dbf_record_status status; struct zfcp_dbf_hba_record_status status;
struct zfcp_hba_dbf_record_qdio qdio; struct zfcp_dbf_hba_record_qdio qdio;
struct fsf_bit_error_payload berr; struct fsf_bit_error_payload berr;
} u; } u;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_san_dbf_record_ct_request { struct zfcp_dbf_san_record_ct_request {
u16 cmd_req_code; u16 cmd_req_code;
u8 revision; u8 revision;
u8 gs_type; u8 gs_type;
...@@ -166,7 +168,7 @@ struct zfcp_san_dbf_record_ct_request { ...@@ -166,7 +168,7 @@ struct zfcp_san_dbf_record_ct_request {
u32 len; u32 len;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_san_dbf_record_ct_response { struct zfcp_dbf_san_record_ct_response {
u16 cmd_rsp_code; u16 cmd_rsp_code;
u8 revision; u8 revision;
u8 reason_code; u8 reason_code;
...@@ -176,27 +178,27 @@ struct zfcp_san_dbf_record_ct_response { ...@@ -176,27 +178,27 @@ struct zfcp_san_dbf_record_ct_response {
u32 len; u32 len;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_san_dbf_record_els { struct zfcp_dbf_san_record_els {
u8 ls_code; u8 ls_code;
u32 len; u32 len;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_san_dbf_record { struct zfcp_dbf_san_record {
u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag[ZFCP_DBF_TAG_SIZE];
u64 fsf_reqid; u64 fsf_reqid;
u32 fsf_seqno; u32 fsf_seqno;
u32 s_id; u32 s_id;
u32 d_id; u32 d_id;
union { union {
struct zfcp_san_dbf_record_ct_request ct_req; struct zfcp_dbf_san_record_ct_request ct_req;
struct zfcp_san_dbf_record_ct_response ct_resp; struct zfcp_dbf_san_record_ct_response ct_resp;
struct zfcp_san_dbf_record_els els; struct zfcp_dbf_san_record_els els;
} u; } u;
#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 #define ZFCP_DBF_SAN_MAX_PAYLOAD 1024
u8 payload[32]; u8 payload[32];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_scsi_dbf_record { struct zfcp_dbf_scsi_record {
u8 tag[ZFCP_DBF_TAG_SIZE]; u8 tag[ZFCP_DBF_TAG_SIZE];
u8 tag2[ZFCP_DBF_TAG_SIZE]; u8 tag2[ZFCP_DBF_TAG_SIZE];
u32 scsi_id; u32 scsi_id;
...@@ -222,4 +224,127 @@ struct zfcp_scsi_dbf_record { ...@@ -222,4 +224,127 @@ struct zfcp_scsi_dbf_record {
u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO]; u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct zfcp_dbf {
debug_info_t *rec;
debug_info_t *hba;
debug_info_t *san;
debug_info_t *scsi;
spinlock_t rec_lock;
spinlock_t hba_lock;
spinlock_t san_lock;
spinlock_t scsi_lock;
struct zfcp_dbf_rec_record rec_buf;
struct zfcp_dbf_hba_record hba_buf;
struct zfcp_dbf_san_record san_buf;
struct zfcp_dbf_scsi_record scsi_buf;
struct zfcp_adapter *adapter;
};
static inline
void zfcp_dbf_hba_fsf_resp(const char *tag2, int level,
struct zfcp_fsf_req *req, struct zfcp_dbf *dbf)
{
if (level <= dbf->hba->level)
_zfcp_dbf_hba_fsf_response(tag2, level, req, dbf);
}
/**
* zfcp_dbf_hba_fsf_response - trace event for request completion
* @fsf_req: request that has been completed
*/
static inline void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
{
struct zfcp_dbf *dbf = req->adapter->dbf;
struct fsf_qtcb *qtcb = req->qtcb;
if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
(qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
zfcp_dbf_hba_fsf_resp("perr", 1, req, dbf);
} else if (qtcb->header.fsf_status != FSF_GOOD) {
zfcp_dbf_hba_fsf_resp("ferr", 1, req, dbf);
} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
(req->fsf_command == FSF_QTCB_OPEN_LUN)) {
zfcp_dbf_hba_fsf_resp("open", 4, req, dbf);
} else if (qtcb->header.log_length) {
zfcp_dbf_hba_fsf_resp("qtcb", 5, req, dbf);
} else {
zfcp_dbf_hba_fsf_resp("norm", 6, req, dbf);
}
}
/**
* zfcp_dbf_hba_fsf_unsol - trace event for an unsolicited status buffer
* @tag: tag indicating which kind of unsolicited status has been received
* @dbf: reference to dbf structure
* @status_buffer: buffer containing payload of unsolicited status
*/
static inline
void zfcp_dbf_hba_fsf_unsol(const char *tag, struct zfcp_dbf *dbf,
struct fsf_status_read_buffer *buf)
{
int level = 2;
if (level <= dbf->hba->level)
_zfcp_dbf_hba_fsf_unsol(tag, level, dbf, buf);
}
static inline
void zfcp_dbf_scsi(const char *tag, const char *tag2, int level,
struct zfcp_dbf *dbf, struct scsi_cmnd *scmd,
struct zfcp_fsf_req *req, unsigned long old_id)
{
if (level <= dbf->scsi->level)
_zfcp_dbf_scsi(tag, tag2, level, dbf, scmd, req, old_id);
}
/**
* zfcp_dbf_scsi_result - trace event for SCSI command completion
* @tag: tag indicating success or failure of SCSI command
* @level: trace level applicable for this event
* @adapter: adapter that has been used to issue the SCSI command
* @scmd: SCSI command pointer
* @fsf_req: request used to issue SCSI command (might be NULL)
*/
static inline
void zfcp_dbf_scsi_result(const char *tag, int level, struct zfcp_dbf *dbf,
struct scsi_cmnd *scmd, struct zfcp_fsf_req *fsf_req)
{
zfcp_dbf_scsi("rslt", tag, level, dbf, scmd, fsf_req, 0);
}
/**
* zfcp_dbf_scsi_abort - trace event for SCSI command abort
* @tag: tag indicating success or failure of abort operation
* @adapter: adapter thas has been used to issue SCSI command to be aborted
* @scmd: SCSI command to be aborted
* @new_req: request containing abort (might be NULL)
* @old_id: identifier of request containg SCSI command to be aborted
*/
static inline
void zfcp_dbf_scsi_abort(const char *tag, struct zfcp_dbf *dbf,
struct scsi_cmnd *scmd, struct zfcp_fsf_req *new_req,
unsigned long old_id)
{
zfcp_dbf_scsi("abrt", tag, 1, dbf, scmd, new_req, old_id);
}
/**
* zfcp_dbf_scsi_devreset - trace event for Logical Unit or Target Reset
* @tag: tag indicating success or failure of reset operation
* @flag: indicates type of reset (Target Reset, Logical Unit Reset)
* @unit: unit that needs reset
* @scsi_cmnd: SCSI command which caused this error recovery
*/
static inline
void zfcp_dbf_scsi_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
zfcp_dbf_scsi(flag == FCP_TARGET_RESET ? "trst" : "lrst", tag, 1,
unit->port->adapter->dbf, scsi_cmnd, NULL, 0);
}
#endif /* ZFCP_DBF_H */ #endif /* ZFCP_DBF_H */
...@@ -37,10 +37,8 @@ ...@@ -37,10 +37,8 @@
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/sysinfo.h> #include <asm/sysinfo.h>
#include "zfcp_dbf.h"
#include "zfcp_fsf.h" #include "zfcp_fsf.h"
/********************* GENERAL DEFINES *********************************/ /********************* GENERAL DEFINES *********************************/
#define REQUEST_LIST_SIZE 128 #define REQUEST_LIST_SIZE 128
...@@ -75,9 +73,6 @@ ...@@ -75,9 +73,6 @@
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
/* timeout for name-server lookup (in seconds) */
#define ZFCP_NS_GID_PN_TIMEOUT 10
/* task attribute values in FCP-2 FCP_CMND IU */ /* task attribute values in FCP-2 FCP_CMND IU */
#define SIMPLE_Q 0 #define SIMPLE_Q 0
#define HEAD_OF_Q 1 #define HEAD_OF_Q 1
...@@ -224,8 +219,6 @@ struct zfcp_ls_adisc { ...@@ -224,8 +219,6 @@ struct zfcp_ls_adisc {
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
#define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_UP 0x00000020
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
...@@ -234,6 +227,7 @@ struct zfcp_ls_adisc { ...@@ -234,6 +227,7 @@ struct zfcp_ls_adisc {
/* remote port status */ /* remote port status */
#define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001
#define ZFCP_STATUS_PORT_LINK_TEST 0x00000002
/* well known address (WKA) port status*/ /* well known address (WKA) port status*/
enum zfcp_wka_status { enum zfcp_wka_status {
...@@ -249,7 +243,6 @@ enum zfcp_wka_status { ...@@ -249,7 +243,6 @@ enum zfcp_wka_status {
/* FSF request status (this does not have a common part) */ /* FSF request status (this does not have a common part) */
#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002
#define ZFCP_STATUS_FSFREQ_COMPLETED 0x00000004
#define ZFCP_STATUS_FSFREQ_ERROR 0x00000008 #define ZFCP_STATUS_FSFREQ_ERROR 0x00000008
#define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010 #define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010
#define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040 #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040
...@@ -266,12 +259,14 @@ struct zfcp_fsf_req; ...@@ -266,12 +259,14 @@ struct zfcp_fsf_req;
/* holds various memory pools of an adapter */ /* holds various memory pools of an adapter */
struct zfcp_adapter_mempool { struct zfcp_adapter_mempool {
mempool_t *fsf_req_erp; mempool_t *erp_req;
mempool_t *fsf_req_scsi; mempool_t *gid_pn_req;
mempool_t *fsf_req_abort; mempool_t *scsi_req;
mempool_t *fsf_req_status_read; mempool_t *scsi_abort;
mempool_t *data_status_read; mempool_t *status_read_req;
mempool_t *data_gid_pn; mempool_t *status_read_data;
mempool_t *gid_pn_data;
mempool_t *qtcb_pool;
}; };
/* /*
...@@ -305,6 +300,15 @@ struct ct_iu_gid_pn_resp { ...@@ -305,6 +300,15 @@ struct ct_iu_gid_pn_resp {
u32 d_id; u32 d_id;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct ct_iu_gpn_ft_req {
struct ct_hdr header;
u8 flags;
u8 domain_id_scope;
u8 area_id_scope;
u8 fc4_type;
} __attribute__ ((packed));
/** /**
* struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
* @wka_port: port where the request is sent to * @wka_port: port where the request is sent to
...@@ -312,7 +316,6 @@ struct ct_iu_gid_pn_resp { ...@@ -312,7 +316,6 @@ struct ct_iu_gid_pn_resp {
* @resp: scatter-gather list for response * @resp: scatter-gather list for response
* @handler: handler function (called for response to the request) * @handler: handler function (called for response to the request)
* @handler_data: data passed to handler function * @handler_data: data passed to handler function
* @timeout: FSF timeout for this request
* @completion: completion for synchronization purposes * @completion: completion for synchronization purposes
* @status: used to pass error status to calling function * @status: used to pass error status to calling function
*/ */
...@@ -322,7 +325,6 @@ struct zfcp_send_ct { ...@@ -322,7 +325,6 @@ struct zfcp_send_ct {
struct scatterlist *resp; struct scatterlist *resp;
void (*handler)(unsigned long); void (*handler)(unsigned long);
unsigned long handler_data; unsigned long handler_data;
int timeout;
struct completion *completion; struct completion *completion;
int status; int status;
}; };
...@@ -420,6 +422,29 @@ struct zfcp_latencies { ...@@ -420,6 +422,29 @@ struct zfcp_latencies {
spinlock_t lock; spinlock_t lock;
}; };
/** struct zfcp_qdio - basic QDIO data structure
* @resp_q: response queue
* @req_q: request 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
* @req_q_util: used for accounting
* @req_q_full: queue full incidents
* @req_q_wq: used to wait for SBAL availability
* @adapter: adapter used in conjunction with this QDIO structure
*/
struct zfcp_qdio {
struct zfcp_qdio_queue resp_q;
struct zfcp_qdio_queue req_q;
spinlock_t stat_lock;
spinlock_t req_q_lock;
unsigned long long req_q_time;
u64 req_q_util;
atomic_t req_q_full;
wait_queue_head_t req_q_wq;
struct zfcp_adapter *adapter;
};
struct zfcp_adapter { struct zfcp_adapter {
atomic_t refcount; /* reference count */ atomic_t refcount; /* reference count */
wait_queue_head_t remove_wq; /* can be used to wait for wait_queue_head_t remove_wq; /* can be used to wait for
...@@ -428,6 +453,7 @@ struct zfcp_adapter { ...@@ -428,6 +453,7 @@ struct zfcp_adapter {
u64 peer_wwpn; /* P2P peer WWPN */ u64 peer_wwpn; /* P2P peer WWPN */
u32 peer_d_id; /* P2P peer D_ID */ u32 peer_d_id; /* P2P peer D_ID */
struct ccw_device *ccw_device; /* S/390 ccw device */ struct ccw_device *ccw_device; /* S/390 ccw device */
struct zfcp_qdio *qdio;
u32 hydra_version; /* Hydra version */ u32 hydra_version; /* Hydra version */
u32 fsf_lic_version; u32 fsf_lic_version;
u32 adapter_features; /* FCP channel features */ u32 adapter_features; /* FCP channel features */
...@@ -439,15 +465,7 @@ struct zfcp_adapter { ...@@ -439,15 +465,7 @@ struct zfcp_adapter {
unsigned long req_no; /* unique FSF req number */ unsigned long req_no; /* unique FSF req number */
struct list_head *req_list; /* list of pending reqs */ struct list_head *req_list; /* list of pending reqs */
spinlock_t req_list_lock; /* request list lock */ spinlock_t req_list_lock; /* request list lock */
struct zfcp_qdio_queue req_q; /* request queue */
spinlock_t req_q_lock; /* for operations on queue */
ktime_t req_q_time; /* time of last fill level change */
u64 req_q_util; /* for accounting */
spinlock_t qdio_stat_lock;
u32 fsf_req_seq_no; /* FSF cmnd seq number */ u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for
more avaliable SBALs */
struct zfcp_qdio_queue resp_q; /* response queue */
rwlock_t abort_lock; /* Protects against SCSI rwlock_t abort_lock; /* Protects against SCSI
stack abort/command stack abort/command
completion races */ completion races */
...@@ -456,10 +474,9 @@ struct zfcp_adapter { ...@@ -456,10 +474,9 @@ struct zfcp_adapter {
atomic_t status; /* status of this adapter */ atomic_t status; /* status of this adapter */
struct list_head erp_ready_head; /* error recovery for this struct list_head erp_ready_head; /* error recovery for this
adapter/devices */ adapter/devices */
wait_queue_head_t erp_ready_wq;
struct list_head erp_running_head; struct list_head erp_running_head;
rwlock_t erp_lock; rwlock_t erp_lock;
struct semaphore erp_ready_sem;
wait_queue_head_t erp_thread_wqh;
wait_queue_head_t erp_done_wqh; wait_queue_head_t erp_done_wqh;
struct zfcp_erp_action erp_action; /* pending error recovery */ struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter; atomic_t erp_counter;
...@@ -467,27 +484,16 @@ struct zfcp_adapter { ...@@ -467,27 +484,16 @@ struct zfcp_adapter {
actions */ actions */
u32 erp_low_mem_count; /* nr of erp actions waiting u32 erp_low_mem_count; /* nr of erp actions waiting
for memory */ for memory */
struct task_struct *erp_thread;
struct zfcp_wka_ports *gs; /* generic services */ struct zfcp_wka_ports *gs; /* generic services */
debug_info_t *rec_dbf; struct zfcp_dbf *dbf; /* debug traces */
debug_info_t *hba_dbf;
debug_info_t *san_dbf; /* debug feature areas */
debug_info_t *scsi_dbf;
spinlock_t rec_dbf_lock;
spinlock_t hba_dbf_lock;
spinlock_t san_dbf_lock;
spinlock_t scsi_dbf_lock;
struct zfcp_rec_dbf_record rec_dbf_buf;
struct zfcp_hba_dbf_record hba_dbf_buf;
struct zfcp_san_dbf_record san_dbf_buf;
struct zfcp_scsi_dbf_record scsi_dbf_buf;
struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct zfcp_adapter_mempool pool; /* Adapter memory pools */
struct qdio_initialize qdio_init_data; /* for qdio_establish */
struct fc_host_statistics *fc_stats; struct fc_host_statistics *fc_stats;
struct fsf_qtcb_bottom_port *stats_reset_data; struct fsf_qtcb_bottom_port *stats_reset_data;
unsigned long stats_reset; unsigned long stats_reset;
struct work_struct scan_work; struct work_struct scan_work;
struct service_level service_level; struct service_level service_level;
atomic_t qdio_outb_full; /* queue full incidents */ struct workqueue_struct *work_queue;
}; };
struct zfcp_port { struct zfcp_port {
...@@ -531,36 +537,64 @@ struct zfcp_unit { ...@@ -531,36 +537,64 @@ struct zfcp_unit {
struct work_struct scsi_work; struct work_struct scsi_work;
}; };
/* FSF request */ /**
* struct zfcp_queue_req - queue related values for a request
* @sbal_number: number of free SBALs
* @sbal_first: first SBAL for this request
* @sbal_last: last SBAL for this request
* @sbal_limit: last possible SBAL for this request
* @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_queue_req {
u8 sbal_number;
u8 sbal_first;
u8 sbal_last;
u8 sbal_limit;
u8 sbale_curr;
u8 sbal_response;
u16 qdio_outb_usage;
u16 qdio_inb_usage;
};
/**
* struct zfcp_fsf_req - basic FSF request structure
* @list: list of FSF requests
* @req_id: unique request ID
* @adapter: adapter this request belongs to
* @queue_req: queue related values
* @completion: used to signal the completion of the request
* @status: status of the request
* @fsf_command: FSF command issued
* @qtcb: associated QTCB
* @seq_no: sequence number of this request
* @data: private data
* @timer: timer data of this request
* @erp_action: reference to erp action if request issued on behalf of ERP
* @pool: reference to memory pool if used for this request
* @issued: time when request was send (STCK)
* @unit: reference to unit if this request is a SCSI request
* @handler: handler which should be called to process response
*/
struct zfcp_fsf_req { struct zfcp_fsf_req {
struct list_head list; /* list of FSF requests */ struct list_head list;
unsigned long req_id; /* unique request ID */ unsigned long req_id;
struct zfcp_adapter *adapter; /* adapter request belongs to */ struct zfcp_adapter *adapter;
u8 sbal_number; /* nr of SBALs free for use */ struct zfcp_queue_req queue_req;
u8 sbal_first; /* first SBAL for this request */ struct completion completion;
u8 sbal_last; /* last SBAL for this request */ u32 status;
u8 sbal_limit; /* last possible SBAL for u32 fsf_command;
this reuest */ struct fsf_qtcb *qtcb;
u8 sbale_curr; /* current SBALE during creation u32 seq_no;
of request */ void *data;
u8 sbal_response; /* SBAL used in interrupt */ struct timer_list timer;
wait_queue_head_t completion_wq; /* can be used by a routine struct zfcp_erp_action *erp_action;
to wait for completion */ mempool_t *pool;
u32 status; /* status of this request */ unsigned long long issued;
u32 fsf_command; /* FSF Command copy */ struct zfcp_unit *unit;
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
void *data; /* private data of request */
struct timer_list timer; /* used for erp or scsi er */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
mempool_t *pool; /* used if request was alloacted
from emergency pool */
unsigned long long issued; /* request sent time (STCK) */
struct zfcp_unit *unit;
void (*handler)(struct zfcp_fsf_req *); void (*handler)(struct zfcp_fsf_req *);
u16 qdio_outb_usage;/* usage of outbound queue */
u16 qdio_inb_usage; /* usage of inbound queue */
}; };
/* driver data */ /* driver data */
...@@ -570,18 +604,11 @@ struct zfcp_data { ...@@ -570,18 +604,11 @@ struct zfcp_data {
rwlock_t config_lock; /* serialises changes rwlock_t config_lock; /* serialises changes
to adapter/port/unit to adapter/port/unit
lists */ lists */
struct semaphore config_sema; /* serialises configuration struct mutex config_mutex;
changes */ struct kmem_cache *gpn_ft_cache;
struct kmem_cache *fsf_req_qtcb_cache; struct kmem_cache *qtcb_cache;
struct kmem_cache *sr_buffer_cache; struct kmem_cache *sr_buffer_cache;
struct kmem_cache *gid_pn_cache; struct kmem_cache *gid_pn_cache;
struct workqueue_struct *work_queue;
};
/* struct used by memory pools for fsf_requests */
struct zfcp_fsf_req_qtcb {
struct zfcp_fsf_req fsf_req;
struct fsf_qtcb qtcb;
}; };
/********************** ZFCP SPECIFIC DEFINES ********************************/ /********************** ZFCP SPECIFIC DEFINES ********************************/
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define KMSG_COMPONENT "zfcp" #define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/kthread.h>
#include "zfcp_ext.h" #include "zfcp_ext.h"
#define ZFCP_MAX_ERPS 3 #define ZFCP_MAX_ERPS 3
...@@ -26,7 +27,6 @@ enum zfcp_erp_steps { ...@@ -26,7 +27,6 @@ enum zfcp_erp_steps {
ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400,
ZFCP_ERP_STEP_PORT_OPENING = 0x0800, ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
...@@ -75,9 +75,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act) ...@@ -75,9 +75,9 @@ static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
struct zfcp_adapter *adapter = act->adapter; struct zfcp_adapter *adapter = act->adapter;
list_move(&act->list, &act->adapter->erp_ready_head); list_move(&act->list, &act->adapter->erp_ready_head);
zfcp_rec_dbf_event_action("erardy1", act); zfcp_dbf_rec_action("erardy1", act);
up(&adapter->erp_ready_sem); wake_up(&adapter->erp_ready_wq);
zfcp_rec_dbf_event_thread("erardy2", adapter); zfcp_dbf_rec_thread("erardy2", adapter->dbf);
} }
static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
...@@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, ...@@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
a_status = atomic_read(&adapter->status); a_status = atomic_read(&adapter->status);
if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0; return 0;
if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
!(a_status & ZFCP_STATUS_COMMON_OPEN))
return 0; /* shutdown requested for closed adapter */
} }
return need; return need;
...@@ -213,8 +216,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, ...@@ -213,8 +216,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
int retval = 1, need; int retval = 1, need;
struct zfcp_erp_action *act = NULL; struct zfcp_erp_action *act = NULL;
if (!(atomic_read(&adapter->status) & if (!adapter->erp_thread)
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
return -EIO; return -EIO;
need = zfcp_erp_required_act(want, adapter, port, unit); need = zfcp_erp_required_act(want, adapter, port, unit);
...@@ -227,12 +229,11 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, ...@@ -227,12 +229,11 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
goto out; goto out;
++adapter->erp_total_count; ++adapter->erp_total_count;
list_add_tail(&act->list, &adapter->erp_ready_head); list_add_tail(&act->list, &adapter->erp_ready_head);
up(&adapter->erp_ready_sem); wake_up(&adapter->erp_ready_wq);
zfcp_rec_dbf_event_thread("eracte1", adapter); zfcp_dbf_rec_thread("eracte1", adapter->dbf);
retval = 0; retval = 0;
out: out:
zfcp_rec_dbf_event_trigger(id, ref, want, need, act, zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit);
adapter, port, unit);
return retval; return retval;
} }
...@@ -443,28 +444,28 @@ static int status_change_clear(unsigned long mask, atomic_t *status) ...@@ -443,28 +444,28 @@ static int status_change_clear(unsigned long mask, atomic_t *status)
static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
{ {
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
} }
static void zfcp_erp_port_unblock(struct zfcp_port *port) static void zfcp_erp_port_unblock(struct zfcp_port *port)
{ {
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
zfcp_rec_dbf_event_port("erpubl1", NULL, port); zfcp_dbf_rec_port("erpubl1", NULL, port);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
} }
static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
{ {
if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); zfcp_dbf_rec_unit("eruubl1", NULL, unit);
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
} }
static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{ {
list_move(&erp_action->list, &erp_action->adapter->erp_running_head); list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
zfcp_rec_dbf_event_action("erator1", erp_action); zfcp_dbf_rec_action("erator1", erp_action);
} }
static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
...@@ -480,13 +481,12 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) ...@@ -480,13 +481,12 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
if (act->status & (ZFCP_STATUS_ERP_DISMISSED | if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) { ZFCP_STATUS_ERP_TIMEDOUT)) {
act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
zfcp_rec_dbf_event_action("erscf_1", act); zfcp_dbf_rec_action("erscf_1", act);
act->fsf_req->erp_action = NULL; act->fsf_req->erp_action = NULL;
} }
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
zfcp_rec_dbf_event_action("erscf_2", act); zfcp_dbf_rec_action("erscf_2", act);
if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
ZFCP_STATUS_FSFREQ_DISMISSED))
act->fsf_req = NULL; act->fsf_req = NULL;
} else } else
act->fsf_req = NULL; act->fsf_req = NULL;
...@@ -604,9 +604,11 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) ...@@ -604,9 +604,11 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
{ {
if (zfcp_qdio_open(act->adapter)) struct zfcp_qdio *qdio = act->adapter->qdio;
if (zfcp_qdio_open(qdio))
return ZFCP_ERP_FAILED; return ZFCP_ERP_FAILED;
init_waitqueue_head(&act->adapter->request_wq); init_waitqueue_head(&qdio->req_q_wq);
atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
return ZFCP_ERP_SUCCEEDED; return ZFCP_ERP_SUCCEEDED;
} }
...@@ -641,9 +643,10 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) ...@@ -641,9 +643,10 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
return ZFCP_ERP_FAILED; return ZFCP_ERP_FAILED;
} }
zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
down(&adapter->erp_ready_sem); wait_event(adapter->erp_ready_wq,
zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); !list_empty(&adapter->erp_ready_head));
zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
break; break;
...@@ -682,9 +685,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) ...@@ -682,9 +685,10 @@ static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
if (ret) if (ret)
return ZFCP_ERP_FAILED; return ZFCP_ERP_FAILED;
zfcp_rec_dbf_event_thread_lock("erasox1", adapter); zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
down(&adapter->erp_ready_sem); wait_event(adapter->erp_ready_wq,
zfcp_rec_dbf_event_thread_lock("erasox2", adapter); !list_empty(&adapter->erp_ready_head));
zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
return ZFCP_ERP_FAILED; return ZFCP_ERP_FAILED;
...@@ -711,10 +715,10 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) ...@@ -711,10 +715,10 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
struct zfcp_adapter *adapter = act->adapter; struct zfcp_adapter *adapter = act->adapter;
/* close queues to ensure that buffers are not accessed by adapter */ /* close queues to ensure that buffers are not accessed by adapter */
zfcp_qdio_close(adapter); zfcp_qdio_close(adapter->qdio);
zfcp_fsf_req_dismiss_all(adapter); zfcp_fsf_req_dismiss_all(adapter);
adapter->fsf_req_seq_no = 0; adapter->fsf_req_seq_no = 0;
zfcp_fc_wka_port_force_offline(&adapter->gs->ds); zfcp_fc_wka_ports_force_offline(adapter->gs);
/* all ports and units are closed */ /* all ports and units are closed */
zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
...@@ -841,27 +845,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) ...@@ -841,27 +845,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
return zfcp_erp_port_strategy_open_port(act); return zfcp_erp_port_strategy_open_port(act);
} }
void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
{
int retval;
struct zfcp_port *port = container_of(work, struct zfcp_port,
gid_pn_work);
retval = zfcp_fc_ns_gid_pn(&port->erp_action);
if (!retval) {
port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
goto out;
}
if (retval == -ENOMEM) {
zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM);
goto out;
}
/* all other error condtions */
zfcp_erp_notify(&port->erp_action, 0);
out:
zfcp_port_put(port);
}
static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
{ {
struct zfcp_adapter *adapter = act->adapter; struct zfcp_adapter *adapter = act->adapter;
...@@ -876,15 +859,11 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) ...@@ -876,15 +859,11 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
return zfcp_erp_open_ptp_port(act); return zfcp_erp_open_ptp_port(act);
if (!port->d_id) { if (!port->d_id) {
zfcp_port_get(port); zfcp_port_get(port);
if (!queue_work(zfcp_data.work_queue, if (!queue_work(adapter->work_queue,
&port->gid_pn_work)) &port->gid_pn_work))
zfcp_port_put(port); zfcp_port_put(port);
return ZFCP_ERP_CONTINUES; return ZFCP_ERP_EXIT;
} }
/* fall through */
case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
if (!port->d_id)
return ZFCP_ERP_FAILED;
return zfcp_erp_port_strategy_open_port(act); return zfcp_erp_port_strategy_open_port(act);
case ZFCP_ERP_STEP_PORT_OPENING: case ZFCP_ERP_STEP_PORT_OPENING:
...@@ -1163,7 +1142,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) ...@@ -1163,7 +1142,7 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
} }
list_del(&erp_action->list); list_del(&erp_action->list);
zfcp_rec_dbf_event_action("eractd1", erp_action); zfcp_dbf_rec_action("eractd1", erp_action);
switch (erp_action->action) { switch (erp_action->action) {
case ZFCP_ERP_ACTION_REOPEN_UNIT: case ZFCP_ERP_ACTION_REOPEN_UNIT:
...@@ -1311,20 +1290,16 @@ static int zfcp_erp_thread(void *data) ...@@ -1311,20 +1290,16 @@ static int zfcp_erp_thread(void *data)
struct list_head *next; struct list_head *next;
struct zfcp_erp_action *act; struct zfcp_erp_action *act;
unsigned long flags; unsigned long flags;
int ignore;
daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
/* Block all signals */
siginitsetinv(&current->blocked, 0);
atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
wake_up(&adapter->erp_thread_wqh);
while (!(atomic_read(&adapter->status) & for (;;) {
ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
wait_event_interruptible(adapter->erp_ready_wq,
!list_empty(&adapter->erp_ready_head) ||
kthread_should_stop());
zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); if (kthread_should_stop())
ignore = down_interruptible(&adapter->erp_ready_sem); break;
zfcp_rec_dbf_event_thread_lock("erthrd2", adapter);
write_lock_irqsave(&adapter->erp_lock, flags); write_lock_irqsave(&adapter->erp_lock, flags);
next = adapter->erp_ready_head.next; next = adapter->erp_ready_head.next;
...@@ -1339,9 +1314,6 @@ static int zfcp_erp_thread(void *data) ...@@ -1339,9 +1314,6 @@ static int zfcp_erp_thread(void *data)
} }
} }
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
wake_up(&adapter->erp_thread_wqh);
return 0; return 0;
} }
...@@ -1353,18 +1325,17 @@ static int zfcp_erp_thread(void *data) ...@@ -1353,18 +1325,17 @@ static int zfcp_erp_thread(void *data)
*/ */
int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
{ {
int retval; struct task_struct *thread;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); dev_name(&adapter->ccw_device->dev));
if (retval < 0) { if (IS_ERR(thread)) {
dev_err(&adapter->ccw_device->dev, dev_err(&adapter->ccw_device->dev,
"Creating an ERP thread for the FCP device failed.\n"); "Creating an ERP thread for the FCP device failed.\n");
return retval; return PTR_ERR(thread);
} }
wait_event(adapter->erp_thread_wqh,
atomic_read(&adapter->status) & adapter->erp_thread = thread;
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP);
return 0; return 0;
} }
...@@ -1379,16 +1350,10 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) ...@@ -1379,16 +1350,10 @@ int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
*/ */
void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
{ {
atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); kthread_stop(adapter->erp_thread);
up(&adapter->erp_ready_sem); adapter->erp_thread = NULL;
zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); WARN_ON(!list_empty(&adapter->erp_ready_head));
WARN_ON(!list_empty(&adapter->erp_running_head));
wait_event(adapter->erp_thread_wqh,
!(atomic_read(&adapter->status) &
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP));
atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL,
&adapter->status);
} }
/** /**
...@@ -1456,11 +1421,11 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, ...@@ -1456,11 +1421,11 @@ void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
if (set_or_clear == ZFCP_SET) { if (set_or_clear == ZFCP_SET) {
if (status_change_set(mask, &adapter->status)) if (status_change_set(mask, &adapter->status))
zfcp_rec_dbf_event_adapter(id, ref, adapter); zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
atomic_set_mask(mask, &adapter->status); atomic_set_mask(mask, &adapter->status);
} else { } else {
if (status_change_clear(mask, &adapter->status)) if (status_change_clear(mask, &adapter->status))
zfcp_rec_dbf_event_adapter(id, ref, adapter); zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
atomic_clear_mask(mask, &adapter->status); atomic_clear_mask(mask, &adapter->status);
if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
atomic_set(&adapter->erp_counter, 0); atomic_set(&adapter->erp_counter, 0);
...@@ -1490,11 +1455,11 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, ...@@ -1490,11 +1455,11 @@ void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
if (set_or_clear == ZFCP_SET) { if (set_or_clear == ZFCP_SET) {
if (status_change_set(mask, &port->status)) if (status_change_set(mask, &port->status))
zfcp_rec_dbf_event_port(id, ref, port); zfcp_dbf_rec_port(id, ref, port);
atomic_set_mask(mask, &port->status); atomic_set_mask(mask, &port->status);
} else { } else {
if (status_change_clear(mask, &port->status)) if (status_change_clear(mask, &port->status))
zfcp_rec_dbf_event_port(id, ref, port); zfcp_dbf_rec_port(id, ref, port);
atomic_clear_mask(mask, &port->status); atomic_clear_mask(mask, &port->status);
if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
atomic_set(&port->erp_counter, 0); atomic_set(&port->erp_counter, 0);
...@@ -1519,11 +1484,11 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, ...@@ -1519,11 +1484,11 @@ void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
{ {
if (set_or_clear == ZFCP_SET) { if (set_or_clear == ZFCP_SET) {
if (status_change_set(mask, &unit->status)) if (status_change_set(mask, &unit->status))
zfcp_rec_dbf_event_unit(id, ref, unit); zfcp_dbf_rec_unit(id, ref, unit);
atomic_set_mask(mask, &unit->status); atomic_set_mask(mask, &unit->status);
} else { } else {
if (status_change_clear(mask, &unit->status)) if (status_change_clear(mask, &unit->status))
zfcp_rec_dbf_event_unit(id, ref, unit); zfcp_dbf_rec_unit(id, ref, unit);
atomic_clear_mask(mask, &unit->status); atomic_clear_mask(mask, &unit->status);
if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
atomic_set(&unit->erp_counter, 0); atomic_set(&unit->erp_counter, 0);
......
...@@ -34,37 +34,31 @@ extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); ...@@ -34,37 +34,31 @@ extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
extern struct miscdevice zfcp_cfdc_misc; extern struct miscdevice zfcp_cfdc_misc;
/* zfcp_dbf.c */ /* zfcp_dbf.c */
extern int zfcp_adapter_debug_register(struct zfcp_adapter *); extern int zfcp_dbf_adapter_register(struct zfcp_adapter *);
extern void zfcp_adapter_debug_unregister(struct zfcp_adapter *); extern void zfcp_dbf_adapter_unregister(struct zfcp_dbf *);
extern void zfcp_rec_dbf_event_thread(char *, struct zfcp_adapter *); extern void zfcp_dbf_rec_thread(char *, struct zfcp_dbf *);
extern void zfcp_rec_dbf_event_thread_lock(char *, struct zfcp_adapter *); extern void zfcp_dbf_rec_thread_lock(char *, struct zfcp_dbf *);
extern void zfcp_rec_dbf_event_adapter(char *, void *, struct zfcp_adapter *); extern void zfcp_dbf_rec_adapter(char *, void *, struct zfcp_dbf *);
extern void zfcp_rec_dbf_event_port(char *, void *, struct zfcp_port *); extern void zfcp_dbf_rec_port(char *, void *, struct zfcp_port *);
extern void zfcp_rec_dbf_event_unit(char *, void *, struct zfcp_unit *); extern void zfcp_dbf_rec_unit(char *, void *, struct zfcp_unit *);
extern void zfcp_rec_dbf_event_trigger(char *, void *, u8, u8, void *, extern void zfcp_dbf_rec_trigger(char *, void *, u8, u8, void *,
struct zfcp_adapter *, struct zfcp_adapter *, struct zfcp_port *,
struct zfcp_port *, struct zfcp_unit *); struct zfcp_unit *);
extern void zfcp_rec_dbf_event_action(char *, struct zfcp_erp_action *); extern void zfcp_dbf_rec_action(char *, struct zfcp_erp_action *);
extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); extern void _zfcp_dbf_hba_fsf_response(const char *, int, struct zfcp_fsf_req *,
extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, struct zfcp_dbf *);
struct fsf_status_read_buffer *); extern void _zfcp_dbf_hba_fsf_unsol(const char *, int level, struct zfcp_dbf *,
extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int, struct fsf_status_read_buffer *);
int); extern void zfcp_dbf_hba_qdio(struct zfcp_dbf *, unsigned int, int, int);
extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *, extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
struct zfcp_fsf_req *); extern void zfcp_dbf_san_ct_request(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); extern void zfcp_dbf_san_ct_response(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); extern void zfcp_dbf_san_els_request(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); extern void zfcp_dbf_san_els_response(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); extern void zfcp_dbf_san_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); extern void _zfcp_dbf_scsi(const char *, const char *, int, struct zfcp_dbf *,
extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, struct scsi_cmnd *, struct zfcp_fsf_req *,
struct scsi_cmnd *, unsigned long);
struct zfcp_fsf_req *);
extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
struct scsi_cmnd *, struct zfcp_fsf_req *,
unsigned long);
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
struct scsi_cmnd *);
/* zfcp_erp.c */ /* zfcp_erp.c */
extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *, extern void zfcp_erp_modify_adapter_status(struct zfcp_adapter *, char *,
...@@ -96,22 +90,20 @@ extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *); ...@@ -96,22 +90,20 @@ extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, char *, void *);
extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *,
void *); void *);
extern void zfcp_erp_timeout_handler(unsigned long); extern void zfcp_erp_timeout_handler(unsigned long);
extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *);
/* zfcp_fc.c */ /* zfcp_fc.c */
extern int zfcp_scan_ports(struct zfcp_adapter *); extern int zfcp_fc_scan_ports(struct zfcp_adapter *);
extern void _zfcp_scan_ports_later(struct work_struct *); extern void _zfcp_fc_scan_ports_later(struct work_struct *);
extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *);
extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); extern void zfcp_fc_port_did_lookup(struct work_struct *);
extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *);
extern void zfcp_test_link(struct zfcp_port *); extern void zfcp_fc_test_link(struct zfcp_port *);
extern void zfcp_fc_link_test_work(struct work_struct *); extern void zfcp_fc_link_test_work(struct work_struct *);
extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); extern void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *);
extern void zfcp_fc_wka_ports_init(struct zfcp_adapter *); extern int zfcp_fc_gs_setup(struct zfcp_adapter *);
extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *); extern int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *);
extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *); extern int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *);
extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *);
/* zfcp_fsf.c */ /* zfcp_fsf.c */
extern int zfcp_fsf_open_port(struct zfcp_erp_action *); extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
...@@ -122,37 +114,39 @@ extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); ...@@ -122,37 +114,39 @@ extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *);
extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *, extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *,
struct fsf_qtcb_bottom_config *); struct fsf_qtcb_bottom_config *);
extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *, extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *,
struct fsf_qtcb_bottom_port *); struct fsf_qtcb_bottom_port *);
extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *, extern struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *,
struct zfcp_fsf_cfdc *); struct zfcp_fsf_cfdc *);
extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *); extern int zfcp_fsf_status_read(struct zfcp_qdio *);
extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); extern int zfcp_status_read_refill(struct zfcp_adapter *adapter);
extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *);
struct zfcp_erp_action *);
extern int zfcp_fsf_send_els(struct zfcp_send_els *); extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *,
struct scsi_cmnd *); struct scsi_cmnd *);
extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8);
extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long,
struct zfcp_unit *); struct zfcp_unit *);
extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
/* zfcp_qdio.c */ /* zfcp_qdio.c */
extern int zfcp_qdio_allocate(struct zfcp_adapter *); extern int zfcp_qdio_setup(struct zfcp_adapter *);
extern void zfcp_qdio_free(struct zfcp_adapter *); extern void zfcp_qdio_destroy(struct zfcp_qdio *);
extern int zfcp_qdio_send(struct zfcp_fsf_req *); extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_queue_req *);
extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *); extern struct qdio_buffer_element
extern struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *); *zfcp_qdio_sbale_req(struct zfcp_qdio *, struct zfcp_queue_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, extern struct qdio_buffer_element
*zfcp_qdio_sbale_curr(struct zfcp_qdio *, struct zfcp_queue_req *);
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *,
struct zfcp_queue_req *, unsigned long,
struct scatterlist *, int); struct scatterlist *, int);
extern int zfcp_qdio_open(struct zfcp_adapter *); extern int zfcp_qdio_open(struct zfcp_qdio *);
extern void zfcp_qdio_close(struct zfcp_adapter *); extern void zfcp_qdio_close(struct zfcp_qdio *);
/* zfcp_scsi.c */ /* zfcp_scsi.c */
extern struct zfcp_data zfcp_data; extern struct zfcp_data zfcp_data;
......
...@@ -25,14 +25,6 @@ static u32 rscn_range_mask[] = { ...@@ -25,14 +25,6 @@ static u32 rscn_range_mask[] = {
[RSCN_FABRIC_ADDRESS] = 0x000000, [RSCN_FABRIC_ADDRESS] = 0x000000,
}; };
struct ct_iu_gpn_ft_req {
struct ct_hdr header;
u8 flags;
u8 domain_id_scope;
u8 area_id_scope;
u8 fc4_type;
} __attribute__ ((packed));
struct gpn_ft_resp_acc { struct gpn_ft_resp_acc {
u8 control; u8 control;
u8 port_id[3]; u8 port_id[3];
...@@ -65,7 +57,7 @@ struct zfcp_fc_ns_handler_data { ...@@ -65,7 +57,7 @@ struct zfcp_fc_ns_handler_data {
unsigned long handler_data; unsigned long handler_data;
}; };
static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) static int zfcp_fc_wka_port_get(struct zfcp_wka_port *wka_port)
{ {
if (mutex_lock_interruptible(&wka_port->mutex)) if (mutex_lock_interruptible(&wka_port->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -90,7 +82,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) ...@@ -90,7 +82,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port)
return -EIO; return -EIO;
} }
static void zfcp_wka_port_offline(struct work_struct *work) static void zfcp_fc_wka_port_offline(struct work_struct *work)
{ {
struct delayed_work *dw = to_delayed_work(work); struct delayed_work *dw = to_delayed_work(work);
struct zfcp_wka_port *wka_port = struct zfcp_wka_port *wka_port =
...@@ -110,7 +102,7 @@ static void zfcp_wka_port_offline(struct work_struct *work) ...@@ -110,7 +102,7 @@ static void zfcp_wka_port_offline(struct work_struct *work)
mutex_unlock(&wka_port->mutex); mutex_unlock(&wka_port->mutex);
} }
static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) static void zfcp_fc_wka_port_put(struct zfcp_wka_port *wka_port)
{ {
if (atomic_dec_return(&wka_port->refcount) != 0) if (atomic_dec_return(&wka_port->refcount) != 0)
return; return;
...@@ -129,10 +121,10 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id, ...@@ -129,10 +121,10 @@ static void zfcp_fc_wka_port_init(struct zfcp_wka_port *wka_port, u32 d_id,
wka_port->status = ZFCP_WKA_PORT_OFFLINE; wka_port->status = ZFCP_WKA_PORT_OFFLINE;
atomic_set(&wka_port->refcount, 0); atomic_set(&wka_port->refcount, 0);
mutex_init(&wka_port->mutex); mutex_init(&wka_port->mutex);
INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline); INIT_DELAYED_WORK(&wka_port->work, zfcp_fc_wka_port_offline);
} }
void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
{ {
cancel_delayed_work_sync(&wka->work); cancel_delayed_work_sync(&wka->work);
mutex_lock(&wka->mutex); mutex_lock(&wka->mutex);
...@@ -140,15 +132,13 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) ...@@ -140,15 +132,13 @@ void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka)
mutex_unlock(&wka->mutex); mutex_unlock(&wka->mutex);
} }
void zfcp_fc_wka_ports_init(struct zfcp_adapter *adapter) void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs)
{ {
struct zfcp_wka_ports *gs = adapter->gs; zfcp_fc_wka_port_force_offline(&gs->ms);
zfcp_fc_wka_port_force_offline(&gs->ts);
zfcp_fc_wka_port_init(&gs->ms, FC_FID_MGMT_SERV, adapter); zfcp_fc_wka_port_force_offline(&gs->ds);
zfcp_fc_wka_port_init(&gs->ts, FC_FID_TIME_SERV, adapter); zfcp_fc_wka_port_force_offline(&gs->as);
zfcp_fc_wka_port_init(&gs->ds, FC_FID_DIR_SERV, adapter); zfcp_fc_wka_port_force_offline(&gs->ks);
zfcp_fc_wka_port_init(&gs->as, FC_FID_ALIASES, adapter);
zfcp_fc_wka_port_init(&gs->ks, FC_FID_SEC_KEY, adapter);
} }
static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
...@@ -160,7 +150,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, ...@@ -160,7 +150,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range,
read_lock_irqsave(&zfcp_data.config_lock, flags); read_lock_irqsave(&zfcp_data.config_lock, flags);
list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) {
if ((port->d_id & range) == (elem->nport_did & range)) if ((port->d_id & range) == (elem->nport_did & range))
zfcp_test_link(port); zfcp_fc_test_link(port);
if (!port->d_id) if (!port->d_id)
zfcp_erp_port_reopen(port, zfcp_erp_port_reopen(port,
ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_STATUS_COMMON_ERP_FAILED,
...@@ -241,7 +231,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req) ...@@ -241,7 +231,7 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
(struct fsf_status_read_buffer *) fsf_req->data; (struct fsf_status_read_buffer *) fsf_req->data;
unsigned int els_type = status_buffer->payload.data[0]; unsigned int els_type = status_buffer->payload.data[0];
zfcp_san_dbf_event_incoming_els(fsf_req); zfcp_dbf_san_incoming_els(fsf_req);
if (els_type == LS_PLOGI) if (els_type == LS_PLOGI)
zfcp_fc_incoming_plogi(fsf_req); zfcp_fc_incoming_plogi(fsf_req);
else if (els_type == LS_LOGO) else if (els_type == LS_LOGO)
...@@ -281,19 +271,18 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) ...@@ -281,19 +271,18 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data)
port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
} }
int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
struct zfcp_gid_pn_data *gid_pn) struct zfcp_gid_pn_data *gid_pn)
{ {
struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_adapter *adapter = port->adapter;
struct zfcp_fc_ns_handler_data compl_rec; struct zfcp_fc_ns_handler_data compl_rec;
int ret; int ret;
/* setup parameters for send generic command */ /* setup parameters for send generic command */
gid_pn->port = erp_action->port; gid_pn->port = port;
gid_pn->ct.wka_port = &adapter->gs->ds; gid_pn->ct.wka_port = &adapter->gs->ds;
gid_pn->ct.handler = zfcp_fc_ns_handler; gid_pn->ct.handler = zfcp_fc_ns_handler;
gid_pn->ct.handler_data = (unsigned long) &compl_rec; gid_pn->ct.handler_data = (unsigned long) &compl_rec;
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
gid_pn->ct.req = &gid_pn->req; gid_pn->ct.req = &gid_pn->req;
gid_pn->ct.resp = &gid_pn->resp; gid_pn->ct.resp = &gid_pn->resp;
sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req,
...@@ -308,13 +297,12 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, ...@@ -308,13 +297,12 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS;
gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN;
gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4;
gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; gid_pn->ct_iu_req.wwpn = port->wwpn;
init_completion(&compl_rec.done); init_completion(&compl_rec.done);
compl_rec.handler = zfcp_fc_ns_gid_pn_eval; compl_rec.handler = zfcp_fc_ns_gid_pn_eval;
compl_rec.handler_data = (unsigned long) gid_pn; compl_rec.handler_data = (unsigned long) gid_pn;
ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.gid_pn_req);
erp_action);
if (!ret) if (!ret)
wait_for_completion(&compl_rec.done); wait_for_completion(&compl_rec.done);
return ret; return ret;
...@@ -322,33 +310,56 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, ...@@ -322,33 +310,56 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action,
/** /**
* zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
* @erp_action: pointer to zfcp_erp_action where GID_PN request is needed * @port: port where GID_PN request is needed
* return: -ENOMEM on error, 0 otherwise * return: -ENOMEM on error, 0 otherwise
*/ */
int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)
{ {
int ret; int ret;
struct zfcp_gid_pn_data *gid_pn; struct zfcp_gid_pn_data *gid_pn;
struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_adapter *adapter = port->adapter;
gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); gid_pn = mempool_alloc(adapter->pool.gid_pn_data, GFP_ATOMIC);
if (!gid_pn) if (!gid_pn)
return -ENOMEM; return -ENOMEM;
memset(gid_pn, 0, sizeof(*gid_pn)); memset(gid_pn, 0, sizeof(*gid_pn));
ret = zfcp_wka_port_get(&adapter->gs->ds); ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
if (ret) if (ret)
goto out; goto out;
ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); ret = zfcp_fc_ns_gid_pn_request(port, gid_pn);
zfcp_wka_port_put(&adapter->gs->ds); zfcp_fc_wka_port_put(&adapter->gs->ds);
out: out:
mempool_free(gid_pn, adapter->pool.data_gid_pn); mempool_free(gid_pn, adapter->pool.gid_pn_data);
return ret; return ret;
} }
void zfcp_fc_port_did_lookup(struct work_struct *work)
{
int ret;
struct zfcp_port *port = container_of(work, struct zfcp_port,
gid_pn_work);
ret = zfcp_fc_ns_gid_pn(port);
if (ret) {
/* could not issue gid_pn for some reason */
zfcp_erp_adapter_reopen(port->adapter, 0, "fcgpn_1", NULL);
goto out;
}
if (!port->d_id) {
zfcp_erp_port_failed(port, "fcgpn_2", NULL);
goto out;
}
zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL);
out:
zfcp_port_put(port);
}
/** /**
* zfcp_fc_plogi_evaluate - evaluate PLOGI playload * zfcp_fc_plogi_evaluate - evaluate PLOGI playload
* @port: zfcp_port structure * @port: zfcp_port structure
...@@ -404,6 +415,7 @@ static void zfcp_fc_adisc_handler(unsigned long data) ...@@ -404,6 +415,7 @@ static void zfcp_fc_adisc_handler(unsigned long data)
/* port is good, unblock rport without going through erp */ /* port is good, unblock rport without going through erp */
zfcp_scsi_schedule_rport_register(port); zfcp_scsi_schedule_rport_register(port);
out: out:
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
zfcp_port_put(port); zfcp_port_put(port);
kfree(adisc); kfree(adisc);
} }
...@@ -450,28 +462,36 @@ void zfcp_fc_link_test_work(struct work_struct *work) ...@@ -450,28 +462,36 @@ void zfcp_fc_link_test_work(struct work_struct *work)
port->rport_task = RPORT_DEL; port->rport_task = RPORT_DEL;
zfcp_scsi_rport_work(&port->rport_work); zfcp_scsi_rport_work(&port->rport_work);
/* only issue one test command at one time per port */
if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST)
goto out;
atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
retval = zfcp_fc_adisc(port); retval = zfcp_fc_adisc(port);
if (retval == 0) if (retval == 0)
return; return;
/* send of ADISC was not possible */ /* send of ADISC was not possible */
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL);
out:
zfcp_port_put(port); zfcp_port_put(port);
} }
/** /**
* zfcp_test_link - lightweight link test procedure * zfcp_fc_test_link - lightweight link test procedure
* @port: port to be tested * @port: port to be tested
* *
* Test status of a link to a remote port using the ELS command ADISC. * Test status of a link to a remote port using the ELS command ADISC.
* If there is a problem with the remote port, error recovery steps * If there is a problem with the remote port, error recovery steps
* will be triggered. * will be triggered.
*/ */
void zfcp_test_link(struct zfcp_port *port) void zfcp_fc_test_link(struct zfcp_port *port)
{ {
zfcp_port_get(port); zfcp_port_get(port);
if (!queue_work(zfcp_data.work_queue, &port->test_link_work)) if (!queue_work(port->adapter->work_queue, &port->test_link_work))
zfcp_port_put(port); zfcp_port_put(port);
} }
...@@ -479,7 +499,7 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) ...@@ -479,7 +499,7 @@ static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
{ {
struct scatterlist *sg = &gpn_ft->sg_req; struct scatterlist *sg = &gpn_ft->sg_req;
kfree(sg_virt(sg)); /* free request buffer */ kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg));
zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
kfree(gpn_ft); kfree(gpn_ft);
...@@ -494,7 +514,7 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) ...@@ -494,7 +514,7 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num)
if (!gpn_ft) if (!gpn_ft)
return NULL; return NULL;
req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL); req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
if (!req) { if (!req) {
kfree(gpn_ft); kfree(gpn_ft);
gpn_ft = NULL; gpn_ft = NULL;
...@@ -511,9 +531,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) ...@@ -511,9 +531,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num)
} }
static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
struct zfcp_adapter *adapter, struct zfcp_adapter *adapter, int max_bytes)
int max_bytes)
{ {
struct zfcp_send_ct *ct = &gpn_ft->ct; struct zfcp_send_ct *ct = &gpn_ft->ct;
struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
...@@ -536,19 +555,18 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, ...@@ -536,19 +555,18 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
ct->wka_port = &adapter->gs->ds; ct->wka_port = &adapter->gs->ds;
ct->handler = zfcp_fc_ns_handler; ct->handler = zfcp_fc_ns_handler;
ct->handler_data = (unsigned long)&compl_rec; ct->handler_data = (unsigned long)&compl_rec;
ct->timeout = 10;
ct->req = &gpn_ft->sg_req; ct->req = &gpn_ft->sg_req;
ct->resp = gpn_ft->sg_resp; ct->resp = gpn_ft->sg_resp;
init_completion(&compl_rec.done); init_completion(&compl_rec.done);
compl_rec.handler = NULL; compl_rec.handler = NULL;
ret = zfcp_fsf_send_ct(ct, NULL, NULL); ret = zfcp_fsf_send_ct(ct, NULL);
if (!ret) if (!ret)
wait_for_completion(&compl_rec.done); wait_for_completion(&compl_rec.done);
return ret; return ret;
} }
static void zfcp_validate_port(struct zfcp_port *port) static void zfcp_fc_validate_port(struct zfcp_port *port)
{ {
struct zfcp_adapter *adapter = port->adapter; struct zfcp_adapter *adapter = port->adapter;
...@@ -568,7 +586,7 @@ static void zfcp_validate_port(struct zfcp_port *port) ...@@ -568,7 +586,7 @@ static void zfcp_validate_port(struct zfcp_port *port)
zfcp_port_dequeue(port); zfcp_port_dequeue(port);
} }
static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
{ {
struct zfcp_send_ct *ct = &gpn_ft->ct; struct zfcp_send_ct *ct = &gpn_ft->ct;
struct scatterlist *sg = gpn_ft->sg_resp; struct scatterlist *sg = gpn_ft->sg_resp;
...@@ -595,7 +613,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) ...@@ -595,7 +613,7 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
return -E2BIG; return -E2BIG;
} }
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
/* first entry is the header */ /* first entry is the header */
for (x = 1; x < max_entries && !last; x++) { for (x = 1; x < max_entries && !last; x++) {
...@@ -628,16 +646,16 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) ...@@ -628,16 +646,16 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list) list_for_each_entry_safe(port, tmp, &adapter->port_list_head, list)
zfcp_validate_port(port); zfcp_fc_validate_port(port);
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return ret; return ret;
} }
/** /**
* zfcp_scan_ports - scan remote ports and attach new ports * zfcp_fc_scan_ports - scan remote ports and attach new ports
* @adapter: pointer to struct zfcp_adapter * @adapter: pointer to struct zfcp_adapter
*/ */
int zfcp_scan_ports(struct zfcp_adapter *adapter) int zfcp_fc_scan_ports(struct zfcp_adapter *adapter)
{ {
int ret, i; int ret, i;
struct zfcp_gpn_ft *gpn_ft; struct zfcp_gpn_ft *gpn_ft;
...@@ -652,7 +670,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) ...@@ -652,7 +670,7 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV) fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
return 0; return 0;
ret = zfcp_wka_port_get(&adapter->gs->ds); ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
if (ret) if (ret)
return ret; return ret;
...@@ -663,9 +681,9 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) ...@@ -663,9 +681,9 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes);
if (!ret) { if (!ret) {
ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); ret = zfcp_fc_eval_gpn_ft(gpn_ft, max_entries);
if (ret == -EAGAIN) if (ret == -EAGAIN)
ssleep(1); ssleep(1);
else else
...@@ -674,14 +692,14 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) ...@@ -674,14 +692,14 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter)
} }
zfcp_free_sg_env(gpn_ft, buf_num); zfcp_free_sg_env(gpn_ft, buf_num);
out: out:
zfcp_wka_port_put(&adapter->gs->ds); zfcp_fc_wka_port_put(&adapter->gs->ds);
return ret; return ret;
} }
void _zfcp_scan_ports_later(struct work_struct *work) void _zfcp_fc_scan_ports_later(struct work_struct *work)
{ {
zfcp_scan_ports(container_of(work, struct zfcp_adapter, scan_work)); zfcp_fc_scan_ports(container_of(work, struct zfcp_adapter, scan_work));
} }
struct zfcp_els_fc_job { struct zfcp_els_fc_job {
...@@ -732,7 +750,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) ...@@ -732,7 +750,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job)
els_fc_job->els.adapter = adapter; els_fc_job->els.adapter = adapter;
if (rport) { if (rport) {
read_lock_irq(&zfcp_data.config_lock); read_lock_irq(&zfcp_data.config_lock);
port = rport->dd_data; port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) if (port)
els_fc_job->els.d_id = port->d_id; els_fc_job->els.d_id = port->d_id;
read_unlock_irq(&zfcp_data.config_lock); read_unlock_irq(&zfcp_data.config_lock);
...@@ -771,7 +789,7 @@ static void zfcp_fc_generic_ct_handler(unsigned long data) ...@@ -771,7 +789,7 @@ static void zfcp_fc_generic_ct_handler(unsigned long data)
job->state_flags = FC_RQST_STATE_DONE; job->state_flags = FC_RQST_STATE_DONE;
job->job_done(job); job->job_done(job);
zfcp_wka_port_put(ct_fc_job->ct.wka_port); zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
kfree(ct_fc_job); kfree(ct_fc_job);
} }
...@@ -817,7 +835,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) ...@@ -817,7 +835,7 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
return -EINVAL; /* no such service */ return -EINVAL; /* no such service */
} }
ret = zfcp_wka_port_get(ct_fc_job->ct.wka_port); ret = zfcp_fc_wka_port_get(ct_fc_job->ct.wka_port);
if (ret) { if (ret) {
kfree(ct_fc_job); kfree(ct_fc_job);
return ret; return ret;
...@@ -825,16 +843,40 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job) ...@@ -825,16 +843,40 @@ int zfcp_fc_execute_ct_fc_job(struct fc_bsg_job *job)
ct_fc_job->ct.req = job->request_payload.sg_list; ct_fc_job->ct.req = job->request_payload.sg_list;
ct_fc_job->ct.resp = job->reply_payload.sg_list; ct_fc_job->ct.resp = job->reply_payload.sg_list;
ct_fc_job->ct.timeout = ZFCP_FSF_REQUEST_TIMEOUT;
ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler; ct_fc_job->ct.handler = zfcp_fc_generic_ct_handler;
ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job; ct_fc_job->ct.handler_data = (unsigned long) ct_fc_job;
ct_fc_job->ct.completion = NULL; ct_fc_job->ct.completion = NULL;
ct_fc_job->job = job; ct_fc_job->job = job;
ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL, NULL); ret = zfcp_fsf_send_ct(&ct_fc_job->ct, NULL);
if (ret) { if (ret) {
kfree(ct_fc_job); kfree(ct_fc_job);
zfcp_wka_port_put(ct_fc_job->ct.wka_port); zfcp_fc_wka_port_put(ct_fc_job->ct.wka_port);
} }
return ret; return ret;
} }
int zfcp_fc_gs_setup(struct zfcp_adapter *adapter)
{
struct zfcp_wka_ports *wka_ports;
wka_ports = kzalloc(sizeof(struct zfcp_wka_ports), GFP_KERNEL);
if (!wka_ports)
return -ENOMEM;
adapter->gs = wka_ports;
zfcp_fc_wka_port_init(&wka_ports->ms, FC_FID_MGMT_SERV, adapter);
zfcp_fc_wka_port_init(&wka_ports->ts, FC_FID_TIME_SERV, adapter);
zfcp_fc_wka_port_init(&wka_ports->ds, FC_FID_DIR_SERV, adapter);
zfcp_fc_wka_port_init(&wka_ports->as, FC_FID_ALIASES, adapter);
zfcp_fc_wka_port_init(&wka_ports->ks, FC_FID_SEC_KEY, adapter);
return 0;
}
void zfcp_fc_gs_destroy(struct zfcp_adapter *adapter)
{
kfree(adapter->gs);
adapter->gs = NULL;
}
此差异已折叠。
...@@ -3,13 +3,14 @@ ...@@ -3,13 +3,14 @@
* *
* Interface to the FSF support functions. * Interface to the FSF support functions.
* *
* Copyright IBM Corporation 2002, 2008 * Copyright IBM Corporation 2002, 2009
*/ */
#ifndef FSF_H #ifndef FSF_H
#define FSF_H #define FSF_H
#include <linux/pfn.h> #include <linux/pfn.h>
#include <linux/scatterlist.h>
#define FSF_QTCB_CURRENT_VERSION 0x00000001 #define FSF_QTCB_CURRENT_VERSION 0x00000001
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Setup and helper functions to access QDIO. * Setup and helper functions to access QDIO.
* *
* Copyright IBM Corporation 2002, 2008 * Copyright IBM Corporation 2002, 2009
*/ */
#define KMSG_COMPONENT "zfcp" #define KMSG_COMPONENT "zfcp"
...@@ -34,29 +34,10 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) ...@@ -34,29 +34,10 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
return &q->sbal[sbal_idx]->element[sbale_idx]; return &q->sbal[sbal_idx]->element[sbale_idx];
} }
/** static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
* zfcp_qdio_free - free memory used by request- and resposne queue
* @adapter: pointer to the zfcp_adapter structure
*/
void zfcp_qdio_free(struct zfcp_adapter *adapter)
{ {
struct qdio_buffer **sbal_req, **sbal_resp; struct zfcp_adapter *adapter = qdio->adapter;
int p;
if (adapter->ccw_device)
qdio_free(adapter->ccw_device);
sbal_req = adapter->req_q.sbal;
sbal_resp = adapter->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]);
}
}
static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, char *id)
{
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
zfcp_erp_adapter_reopen(adapter, zfcp_erp_adapter_reopen(adapter,
...@@ -75,72 +56,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) ...@@ -75,72 +56,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
} }
/* this needs to be called prior to updating the queue fill level */ /* this needs to be called prior to updating the queue fill level */
static void zfcp_qdio_account(struct zfcp_adapter *adapter) static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
{ {
ktime_t now; unsigned long long now, span;
s64 span;
int free, used; int free, used;
spin_lock(&adapter->qdio_stat_lock); spin_lock(&qdio->stat_lock);
now = ktime_get(); now = get_clock_monotonic();
span = ktime_us_delta(now, adapter->req_q_time); span = (now - qdio->req_q_time) >> 12;
free = max(0, atomic_read(&adapter->req_q.count)); free = atomic_read(&qdio->req_q.count);
used = QDIO_MAX_BUFFERS_PER_Q - free; used = QDIO_MAX_BUFFERS_PER_Q - free;
adapter->req_q_util += used * span; qdio->req_q_util += used * span;
adapter->req_q_time = now; qdio->req_q_time = now;
spin_unlock(&adapter->qdio_stat_lock); spin_unlock(&qdio->stat_lock);
} }
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, 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 first, int count,
unsigned long parm) unsigned long parm)
{ {
struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
struct zfcp_qdio_queue *queue = &adapter->req_q; struct zfcp_qdio_queue *queue = &qdio->req_q;
if (unlikely(qdio_err)) { if (unlikely(qdio_err)) {
zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count); zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
zfcp_qdio_handler_error(adapter, "qdireq1"); count);
zfcp_qdio_handler_error(qdio, "qdireq1");
return; return;
} }
/* cleanup all SBALs being program-owned now */ /* cleanup all SBALs being program-owned now */
zfcp_qdio_zero_sbals(queue->sbal, first, count); zfcp_qdio_zero_sbals(queue->sbal, first, count);
zfcp_qdio_account(adapter); zfcp_qdio_account(qdio);
atomic_add(count, &queue->count); atomic_add(count, &queue->count);
wake_up(&adapter->request_wq); wake_up(&qdio->req_q_wq);
}
static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
unsigned long req_id, int sbal_idx)
{
struct zfcp_fsf_req *fsf_req;
unsigned long flags;
spin_lock_irqsave(&adapter->req_list_lock, flags);
fsf_req = zfcp_reqlist_find(adapter, req_id);
if (!fsf_req)
/*
* Unknown request means that we have potentially memory
* corruption and must stop the machine immediatly.
*/
panic("error: unknown request id (%lx) on adapter %s.\n",
req_id, dev_name(&adapter->ccw_device->dev));
zfcp_reqlist_remove(adapter, fsf_req);
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
fsf_req->sbal_response = sbal_idx;
fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count);
zfcp_fsf_req_complete(fsf_req);
} }
static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed) static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
{ {
struct zfcp_qdio_queue *queue = &adapter->resp_q; struct zfcp_qdio_queue *queue = &qdio->resp_q;
struct ccw_device *cdev = adapter->ccw_device; struct ccw_device *cdev = qdio->adapter->ccw_device;
u8 count, start = queue->first; u8 count, start = queue->first;
unsigned int retval; unsigned int retval;
...@@ -162,14 +118,13 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, ...@@ -162,14 +118,13 @@ 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 first, int count,
unsigned long parm) unsigned long parm)
{ {
struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
struct zfcp_qdio_queue *queue = &adapter->resp_q; int sbal_idx, sbal_no;
struct qdio_buffer_element *sbale;
int sbal_idx, sbale_idx, sbal_no;
if (unlikely(qdio_err)) { if (unlikely(qdio_err)) {
zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count); zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
zfcp_qdio_handler_error(adapter, "qdires1"); count);
zfcp_qdio_handler_error(qdio, "qdires1");
return; return;
} }
...@@ -179,39 +134,27 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, ...@@ -179,39 +134,27 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
*/ */
for (sbal_no = 0; sbal_no < count; sbal_no++) { for (sbal_no = 0; sbal_no < count; sbal_no++) {
sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
/* go through all SBALEs of SBAL */ /* go through all SBALEs of SBAL */
for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER; zfcp_fsf_reqid_check(qdio, sbal_idx);
sbale_idx++) {
sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx);
zfcp_qdio_reqid_check(adapter,
(unsigned long) sbale->addr,
sbal_idx);
if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
break;
};
if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY)))
dev_warn(&adapter->ccw_device->dev,
"A QDIO protocol error occurred, "
"operations continue\n");
} }
/* /*
* put range of SBALs back to response queue * put range of SBALs back to response queue
* (including SBALs which have already been free before) * (including SBALs which have already been free before)
*/ */
zfcp_qdio_resp_put_back(adapter, count); zfcp_qdio_resp_put_back(qdio, count);
} }
/** /**
* zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req
* @fsf_req: pointer to struct fsf_req * @qdio: pointer to struct zfcp_qdio
* @q_rec: pointer to struct zfcp_queue_rec
* Returns: pointer to qdio_buffer_element (SBALE) structure * Returns: pointer to qdio_buffer_element (SBALE) structure
*/ */
struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_qdio *qdio,
struct zfcp_queue_req *q_req)
{ {
return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
} }
/** /**
...@@ -219,74 +162,80 @@ struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) ...@@ -219,74 +162,80 @@ struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
* @fsf_req: pointer to struct fsf_req * @fsf_req: pointer to struct fsf_req
* Returns: pointer to qdio_buffer_element (SBALE) structure * Returns: pointer to qdio_buffer_element (SBALE) structure
*/ */
struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio,
struct zfcp_queue_req *q_req)
{ {
return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
req->sbale_curr); q_req->sbale_curr);
} }
static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
struct zfcp_queue_req *q_req, int max_sbals)
{ {
int count = atomic_read(&fsf_req->adapter->req_q.count); int count = atomic_read(&qdio->req_q.count);
count = min(count, max_sbals); count = min(count, max_sbals);
fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1) q_req->sbal_limit = (q_req->sbal_first + count - 1)
% QDIO_MAX_BUFFERS_PER_Q; % QDIO_MAX_BUFFERS_PER_Q;
} }
static struct qdio_buffer_element * static struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
unsigned long sbtype)
{ {
struct qdio_buffer_element *sbale; struct qdio_buffer_element *sbale;
/* set last entry flag in current SBALE of current SBAL */ /* set last entry flag in current SBALE of current SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req); sbale = zfcp_qdio_sbale_curr(qdio, q_req);
sbale->flags |= SBAL_FLAGS_LAST_ENTRY; sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
/* don't exceed last allowed SBAL */ /* don't exceed last allowed SBAL */
if (fsf_req->sbal_last == fsf_req->sbal_limit) if (q_req->sbal_last == q_req->sbal_limit)
return NULL; return NULL;
/* set chaining flag in first SBALE of current SBAL */ /* set chaining flag in first SBALE of current SBAL */
sbale = zfcp_qdio_sbale_req(fsf_req); sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->flags |= SBAL_FLAGS0_MORE_SBALS; sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
/* calculate index of next SBAL */ /* calculate index of next SBAL */
fsf_req->sbal_last++; q_req->sbal_last++;
fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
/* keep this requests number of SBALs up-to-date */ /* keep this requests number of SBALs up-to-date */
fsf_req->sbal_number++; q_req->sbal_number++;
/* start at first SBALE of new SBAL */ /* start at first SBALE of new SBAL */
fsf_req->sbale_curr = 0; q_req->sbale_curr = 0;
/* set storage-block type for new SBAL */ /* set storage-block type for new SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req); sbale = zfcp_qdio_sbale_curr(qdio, q_req);
sbale->flags |= sbtype; sbale->flags |= sbtype;
return sbale; return sbale;
} }
static struct qdio_buffer_element * static struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req,
unsigned int sbtype)
{ {
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
return zfcp_qdio_sbal_chain(fsf_req, sbtype); return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
fsf_req->sbale_curr++; q_req->sbale_curr++;
return zfcp_qdio_sbale_curr(fsf_req); return zfcp_qdio_sbale_curr(qdio, q_req);
} }
static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req) static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
struct zfcp_queue_req *q_req)
{ {
struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal; struct qdio_buffer **sbal = qdio->req_q.sbal;
int first = fsf_req->sbal_first; int first = q_req->sbal_first;
int last = fsf_req->sbal_last; int last = q_req->sbal_last;
int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
QDIO_MAX_BUFFERS_PER_Q + 1; QDIO_MAX_BUFFERS_PER_Q + 1;
zfcp_qdio_zero_sbals(sbal, first, count); zfcp_qdio_zero_sbals(sbal, first, count);
} }
static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
struct zfcp_queue_req *q_req,
unsigned int sbtype, void *start_addr, unsigned int sbtype, void *start_addr,
unsigned int total_length) unsigned int total_length)
{ {
...@@ -297,10 +246,10 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, ...@@ -297,10 +246,10 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
/* split segment up */ /* split segment up */
for (addr = start_addr, remaining = total_length; remaining > 0; for (addr = start_addr, remaining = total_length; remaining > 0;
addr += length, remaining -= length) { addr += length, remaining -= length) {
sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
if (!sbale) { if (!sbale) {
atomic_inc(&fsf_req->adapter->qdio_outb_full); atomic_inc(&qdio->req_q_full);
zfcp_qdio_undo_sbals(fsf_req); zfcp_qdio_undo_sbals(qdio, q_req);
return -EINVAL; return -EINVAL;
} }
...@@ -322,29 +271,31 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req, ...@@ -322,29 +271,31 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
* @max_sbals: upper bound for number of SBALs to be used * @max_sbals: upper bound for number of SBALs to be used
* Returns: number of bytes, or error (negativ) * Returns: number of bytes, or error (negativ)
*/ */
int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio,
struct scatterlist *sg, int max_sbals) struct zfcp_queue_req *q_req,
unsigned long sbtype, struct scatterlist *sg,
int max_sbals)
{ {
struct qdio_buffer_element *sbale; struct qdio_buffer_element *sbale;
int retval, bytes = 0; int retval, bytes = 0;
/* figure out last allowed SBAL */ /* figure out last allowed SBAL */
zfcp_qdio_sbal_limit(fsf_req, max_sbals); zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
/* set storage-block type for this request */ /* set storage-block type for this request */
sbale = zfcp_qdio_sbale_req(fsf_req); sbale = zfcp_qdio_sbale_req(qdio, q_req);
sbale->flags |= sbtype; sbale->flags |= sbtype;
for (; sg; sg = sg_next(sg)) { for (; sg; sg = sg_next(sg)) {
retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg), retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
sg->length); sg_virt(sg), sg->length);
if (retval < 0) if (retval < 0)
return retval; return retval;
bytes += sg->length; bytes += sg->length;
} }
/* assume that no other SBALEs are to follow in the same SBAL */ /* assume that no other SBALEs are to follow in the same SBAL */
sbale = zfcp_qdio_sbale_curr(fsf_req); sbale = zfcp_qdio_sbale_curr(qdio, q_req);
sbale->flags |= SBAL_FLAGS_LAST_ENTRY; sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
return bytes; return bytes;
...@@ -352,21 +303,22 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, ...@@ -352,21 +303,22 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
/** /**
* zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
* @fsf_req: pointer to struct zfcp_fsf_req * @qdio: pointer to struct zfcp_qdio
* @q_req: pointer to struct zfcp_queue_req
* Returns: 0 on success, error otherwise * Returns: 0 on success, error otherwise
*/ */
int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_queue_req *q_req)
{ {
struct zfcp_adapter *adapter = fsf_req->adapter; struct zfcp_qdio_queue *req_q = &qdio->req_q;
struct zfcp_qdio_queue *req_q = &adapter->req_q; int first = q_req->sbal_first;
int first = fsf_req->sbal_first; int count = q_req->sbal_number;
int count = fsf_req->sbal_number;
int retval; int retval;
unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
zfcp_qdio_account(adapter); zfcp_qdio_account(qdio);
retval = do_QDIO(adapter->ccw_device, qdio_flags, 0, first, count); retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
count);
if (unlikely(retval)) { if (unlikely(retval)) {
zfcp_qdio_zero_sbals(req_q->sbal, first, count); zfcp_qdio_zero_sbals(req_q->sbal, first, count);
return retval; return retval;
...@@ -379,63 +331,69 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req) ...@@ -379,63 +331,69 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
return 0; return 0;
} }
static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
struct zfcp_qdio *qdio)
{
id->cdev = qdio->adapter->ccw_device;
id->q_format = QDIO_ZFCP_QFMT;
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
ASCEBC(id->adapter_name, 8);
id->qib_param_field_format = 0;
id->qib_param_field = NULL;
id->input_slib_elements = NULL;
id->output_slib_elements = NULL;
id->no_input_qs = 1;
id->no_output_qs = 1;
id->input_handler = zfcp_qdio_int_resp;
id->output_handler = zfcp_qdio_int_req;
id->int_parm = (unsigned long) qdio;
id->flags = QDIO_INBOUND_0COPY_SBALS |
QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
}
/** /**
* zfcp_qdio_allocate - allocate queue memory and initialize QDIO data * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
* @adapter: pointer to struct zfcp_adapter * @adapter: pointer to struct zfcp_adapter
* Returns: -ENOMEM on memory allocation error or return value from * Returns: -ENOMEM on memory allocation error or return value from
* qdio_allocate * qdio_allocate
*/ */
int zfcp_qdio_allocate(struct zfcp_adapter *adapter) static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
{ {
struct qdio_initialize *init_data; struct qdio_initialize init_data;
if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) || if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal)) zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
return -ENOMEM; return -ENOMEM;
init_data = &adapter->qdio_init_data; zfcp_qdio_setup_init_data(&init_data, qdio);
init_data->cdev = adapter->ccw_device; return qdio_allocate(&init_data);
init_data->q_format = QDIO_ZFCP_QFMT;
memcpy(init_data->adapter_name, dev_name(&adapter->ccw_device->dev), 8);
ASCEBC(init_data->adapter_name, 8);
init_data->qib_param_field_format = 0;
init_data->qib_param_field = NULL;
init_data->input_slib_elements = NULL;
init_data->output_slib_elements = NULL;
init_data->no_input_qs = 1;
init_data->no_output_qs = 1;
init_data->input_handler = zfcp_qdio_int_resp;
init_data->output_handler = zfcp_qdio_int_req;
init_data->int_parm = (unsigned long) adapter;
init_data->flags = QDIO_INBOUND_0COPY_SBALS |
QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
init_data->input_sbal_addr_array =
(void **) (adapter->resp_q.sbal);
init_data->output_sbal_addr_array =
(void **) (adapter->req_q.sbal);
return qdio_allocate(init_data);
} }
/** /**
* zfcp_close_qdio - close qdio queues for an adapter * zfcp_close_qdio - close qdio queues for an adapter
* @qdio: pointer to structure zfcp_qdio
*/ */
void zfcp_qdio_close(struct zfcp_adapter *adapter) void zfcp_qdio_close(struct zfcp_qdio *qdio)
{ {
struct zfcp_qdio_queue *req_q; struct zfcp_qdio_queue *req_q;
int first, count; int first, count;
if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
return; return;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
req_q = &adapter->req_q; req_q = &qdio->req_q;
spin_lock_bh(&adapter->req_q_lock); spin_lock_bh(&qdio->req_q_lock);
atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
spin_unlock_bh(&adapter->req_q_lock); spin_unlock_bh(&qdio->req_q_lock);
qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); qdio_shutdown(qdio->adapter->ccw_device,
QDIO_FLAG_CLEANUP_USING_CLEAR);
/* cleanup used outbound sbals */ /* cleanup used outbound sbals */
count = atomic_read(&req_q->count); count = atomic_read(&req_q->count);
...@@ -446,50 +404,99 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter) ...@@ -446,50 +404,99 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
} }
req_q->first = 0; req_q->first = 0;
atomic_set(&req_q->count, 0); atomic_set(&req_q->count, 0);
adapter->resp_q.first = 0; qdio->resp_q.first = 0;
atomic_set(&adapter->resp_q.count, 0); atomic_set(&qdio->resp_q.count, 0);
} }
/** /**
* zfcp_qdio_open - prepare and initialize response queue * zfcp_qdio_open - prepare and initialize response queue
* @adapter: pointer to struct zfcp_adapter * @qdio: pointer to struct zfcp_qdio
* Returns: 0 on success, otherwise -EIO * Returns: 0 on success, otherwise -EIO
*/ */
int zfcp_qdio_open(struct zfcp_adapter *adapter) int zfcp_qdio_open(struct zfcp_qdio *qdio)
{ {
struct qdio_buffer_element *sbale; struct qdio_buffer_element *sbale;
struct qdio_initialize init_data;
struct ccw_device *cdev = qdio->adapter->ccw_device;
int cc; int cc;
if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
return -EIO; return -EIO;
if (qdio_establish(&adapter->qdio_init_data)) zfcp_qdio_setup_init_data(&init_data, qdio);
if (qdio_establish(&init_data))
goto failed_establish; goto failed_establish;
if (qdio_activate(adapter->ccw_device)) if (qdio_activate(cdev))
goto failed_qdio; goto failed_qdio;
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
sbale = &(adapter->resp_q.sbal[cc]->element[0]); sbale = &(qdio->resp_q.sbal[cc]->element[0]);
sbale->length = 0; sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY; sbale->flags = SBAL_FLAGS_LAST_ENTRY;
sbale->addr = NULL; sbale->addr = NULL;
} }
if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
QDIO_MAX_BUFFERS_PER_Q)) QDIO_MAX_BUFFERS_PER_Q))
goto failed_qdio; goto failed_qdio;
/* set index of first avalable SBALS / number of available SBALS */ /* set index of first avalable SBALS / number of available SBALS */
adapter->req_q.first = 0; qdio->req_q.first = 0;
atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
return 0; return 0;
failed_qdio: failed_qdio:
qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
failed_establish: failed_establish:
dev_err(&adapter->ccw_device->dev, dev_err(&cdev->dev,
"Setting up the QDIO connection to the FCP adapter failed\n"); "Setting up the QDIO connection to the FCP adapter failed\n");
return -EIO; return -EIO;
} }
void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
{
struct qdio_buffer **sbal_req, **sbal_resp;
int p;
if (!qdio)
return;
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]);
}
kfree(qdio);
}
int zfcp_qdio_setup(struct zfcp_adapter *adapter)
{
struct zfcp_qdio *qdio;
qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL);
if (!qdio)
return -ENOMEM;
qdio->adapter = adapter;
if (zfcp_qdio_allocate(qdio)) {
zfcp_qdio_destroy(qdio);
return -ENOMEM;
}
spin_lock_init(&qdio->req_q_lock);
spin_lock_init(&qdio->stat_lock);
adapter->qdio = qdio;
return 0;
}
...@@ -9,8 +9,9 @@ ...@@ -9,8 +9,9 @@
#define KMSG_COMPONENT "zfcp" #define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include "zfcp_ext.h"
#include <asm/atomic.h> #include <asm/atomic.h>
#include "zfcp_ext.h"
#include "zfcp_dbf.h"
static unsigned int default_depth = 32; static unsigned int default_depth = 32;
module_param_named(queue_depth, default_depth, uint, 0600); module_param_named(queue_depth, default_depth, uint, 0600);
...@@ -52,11 +53,11 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp) ...@@ -52,11 +53,11 @@ static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
{ {
struct zfcp_adapter *adapter =
(struct zfcp_adapter *) scpnt->device->host->hostdata[0];
set_host_byte(scpnt, result); set_host_byte(scpnt, result);
if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) if ((scpnt->device != NULL) && (scpnt->device->host != NULL))
zfcp_scsi_dbf_event_result("fail", 4, zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL);
(struct zfcp_adapter*) scpnt->device->host->hostdata[0],
scpnt, NULL);
/* return directly */ /* return directly */
scpnt->scsi_done(scpnt); scpnt->scsi_done(scpnt);
} }
...@@ -92,7 +93,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, ...@@ -92,7 +93,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
scsi_result = fc_remote_port_chkready(rport); scsi_result = fc_remote_port_chkready(rport);
if (unlikely(scsi_result)) { if (unlikely(scsi_result)) {
scpnt->result = scsi_result; scpnt->result = scsi_result;
zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); zfcp_dbf_scsi_result("fail", 4, adapter->dbf, scpnt, NULL);
scpnt->scsi_done(scpnt); scpnt->scsi_done(scpnt);
return 0; return 0;
} }
...@@ -180,8 +181,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) ...@@ -180,8 +181,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
spin_unlock(&adapter->req_list_lock); spin_unlock(&adapter->req_list_lock);
if (!old_req) { if (!old_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags); write_unlock_irqrestore(&adapter->abort_lock, flags);
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, zfcp_dbf_scsi_abort("lte1", adapter->dbf, scpnt, NULL,
old_reqid); old_reqid);
return FAILED; /* completion could be in progress */ return FAILED; /* completion could be in progress */
} }
old_req->data = NULL; old_req->data = NULL;
...@@ -197,16 +198,15 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) ...@@ -197,16 +198,15 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) & if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) { ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
old_reqid); old_reqid);
return SUCCESS; return SUCCESS;
} }
} }
if (!abrt_req) if (!abrt_req)
return FAILED; return FAILED;
wait_event(abrt_req->completion_wq, wait_for_completion(&abrt_req->completion);
abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
dbf_tag = "okay"; dbf_tag = "okay";
...@@ -216,7 +216,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) ...@@ -216,7 +216,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
dbf_tag = "fail"; dbf_tag = "fail";
retval = FAILED; retval = FAILED;
} }
zfcp_scsi_dbf_event_abort(dbf_tag, adapter, scpnt, abrt_req, old_reqid); zfcp_dbf_scsi_abort(dbf_tag, adapter->dbf, scpnt, abrt_req, old_reqid);
zfcp_fsf_req_free(abrt_req); zfcp_fsf_req_free(abrt_req);
return retval; return retval;
} }
...@@ -225,7 +225,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) ...@@ -225,7 +225,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
{ {
struct zfcp_unit *unit = scpnt->device->hostdata; struct zfcp_unit *unit = scpnt->device->hostdata;
struct zfcp_adapter *adapter = unit->port->adapter; struct zfcp_adapter *adapter = unit->port->adapter;
struct zfcp_fsf_req *fsf_req; struct zfcp_fsf_req *fsf_req = NULL;
int retval = SUCCESS; int retval = SUCCESS;
int retry = 3; int retry = 3;
...@@ -237,25 +237,23 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) ...@@ -237,25 +237,23 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
if (!(atomic_read(&adapter->status) & if (!(atomic_read(&adapter->status) &
ZFCP_STATUS_COMMON_RUNNING)) { ZFCP_STATUS_COMMON_RUNNING)) {
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
scpnt);
return SUCCESS; return SUCCESS;
} }
} }
if (!fsf_req) if (!fsf_req)
return FAILED; return FAILED;
wait_event(fsf_req->completion_wq, wait_for_completion(&fsf_req->completion);
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); zfcp_dbf_scsi_devreset("fail", tm_flags, unit, scpnt);
retval = FAILED; retval = FAILED;
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); zfcp_dbf_scsi_devreset("nsup", tm_flags, unit, scpnt);
retval = FAILED; retval = FAILED;
} else } else
zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); zfcp_dbf_scsi_devreset("okay", tm_flags, unit, scpnt);
zfcp_fsf_req_free(fsf_req); zfcp_fsf_req_free(fsf_req);
return retval; return retval;
...@@ -430,7 +428,7 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host) ...@@ -430,7 +428,7 @@ static struct fc_host_statistics *zfcp_get_fc_host_stats(struct Scsi_Host *host)
if (!data) if (!data)
return NULL; return NULL;
ret = zfcp_fsf_exchange_port_data_sync(adapter, data); ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
if (ret) { if (ret) {
kfree(data); kfree(data);
return NULL; return NULL;
...@@ -459,7 +457,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) ...@@ -459,7 +457,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
if (!data) if (!data)
return; return;
ret = zfcp_fsf_exchange_port_data_sync(adapter, data); ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data);
if (ret) if (ret)
kfree(data); kfree(data);
else { else {
...@@ -492,21 +490,6 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) ...@@ -492,21 +490,6 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
rport->dev_loss_tmo = timeout; rport->dev_loss_tmo = timeout;
} }
/**
* zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport
* @rport: The rport that is about to be deleted.
*/
static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
{
struct zfcp_port *port;
write_lock_irq(&zfcp_data.config_lock);
port = rport->dd_data;
if (port)
port->rport = NULL;
write_unlock_irq(&zfcp_data.config_lock);
}
/** /**
* zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport
* @rport: The FC rport where to teminate I/O * @rport: The FC rport where to teminate I/O
...@@ -518,9 +501,12 @@ static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) ...@@ -518,9 +501,12 @@ static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport)
static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
{ {
struct zfcp_port *port; struct zfcp_port *port;
struct Scsi_Host *shost = rport_to_shost(rport);
struct zfcp_adapter *adapter =
(struct zfcp_adapter *)shost->hostdata[0];
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
port = rport->dd_data; port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
if (port) if (port)
zfcp_port_get(port); zfcp_port_get(port);
write_unlock_irq(&zfcp_data.config_lock); write_unlock_irq(&zfcp_data.config_lock);
...@@ -552,7 +538,6 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) ...@@ -552,7 +538,6 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port)
return; return;
} }
rport->dd_data = port;
rport->maxframe_size = port->maxframe_size; rport->maxframe_size = port->maxframe_size;
rport->supported_classes = port->supported_classes; rport->supported_classes = port->supported_classes;
port->rport = rport; port->rport = rport;
...@@ -573,7 +558,7 @@ void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) ...@@ -573,7 +558,7 @@ void zfcp_scsi_schedule_rport_register(struct zfcp_port *port)
zfcp_port_get(port); zfcp_port_get(port);
port->rport_task = RPORT_ADD; port->rport_task = RPORT_ADD;
if (!queue_work(zfcp_data.work_queue, &port->rport_work)) if (!queue_work(port->adapter->work_queue, &port->rport_work))
zfcp_port_put(port); zfcp_port_put(port);
} }
...@@ -582,8 +567,11 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) ...@@ -582,8 +567,11 @@ void zfcp_scsi_schedule_rport_block(struct zfcp_port *port)
zfcp_port_get(port); zfcp_port_get(port);
port->rport_task = RPORT_DEL; port->rport_task = RPORT_DEL;
if (!queue_work(zfcp_data.work_queue, &port->rport_work)) if (port->rport && queue_work(port->adapter->work_queue,
zfcp_port_put(port); &port->rport_work))
return;
zfcp_port_put(port);
} }
void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter)
...@@ -662,7 +650,6 @@ struct fc_function_template zfcp_transport_functions = { ...@@ -662,7 +650,6 @@ struct fc_function_template zfcp_transport_functions = {
.reset_fc_host_stats = zfcp_reset_fc_host_stats, .reset_fc_host_stats = zfcp_reset_fc_host_stats,
.set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo,
.get_host_port_state = zfcp_get_host_port_state, .get_host_port_state = zfcp_get_host_port_state,
.dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk,
.terminate_rport_io = zfcp_scsi_terminate_rport_io, .terminate_rport_io = zfcp_scsi_terminate_rport_io,
.show_host_port_state = 1, .show_host_port_state = 1,
.bsg_request = zfcp_execute_fc_job, .bsg_request = zfcp_execute_fc_job,
......
...@@ -88,7 +88,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ ...@@ -88,7 +88,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
unsigned long val; \ unsigned long val; \
int retval = 0; \ int retval = 0; \
\ \
down(&zfcp_data.config_sema); \ mutex_lock(&zfcp_data.config_mutex); \
if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \ if (atomic_read(&_feat->status) & ZFCP_STATUS_COMMON_REMOVE) { \
retval = -EBUSY; \ retval = -EBUSY; \
goto out; \ goto out; \
...@@ -105,7 +105,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \ ...@@ -105,7 +105,7 @@ static ssize_t zfcp_sysfs_##_feat##_failed_store(struct device *dev, \
_reopen_id, NULL); \ _reopen_id, NULL); \
zfcp_erp_wait(_adapter); \ zfcp_erp_wait(_adapter); \
out: \ out: \
up(&zfcp_data.config_sema); \ mutex_unlock(&zfcp_data.config_mutex); \
return retval ? retval : (ssize_t) count; \ return retval ? retval : (ssize_t) count; \
} \ } \
static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \ static ZFCP_DEV_ATTR(_feat, failed, S_IWUSR | S_IRUGO, \
...@@ -126,7 +126,7 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev, ...@@ -126,7 +126,7 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE)
return -EBUSY; return -EBUSY;
ret = zfcp_scan_ports(adapter); ret = zfcp_fc_scan_ports(adapter);
return ret ? ret : (ssize_t) count; return ret ? ret : (ssize_t) count;
} }
static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
...@@ -142,7 +142,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, ...@@ -142,7 +142,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
int retval = 0; int retval = 0;
LIST_HEAD(port_remove_lh); LIST_HEAD(port_remove_lh);
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) {
retval = -EBUSY; retval = -EBUSY;
goto out; goto out;
...@@ -173,7 +173,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, ...@@ -173,7 +173,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
zfcp_port_put(port); zfcp_port_put(port);
zfcp_port_dequeue(port); zfcp_port_dequeue(port);
out: out:
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return retval ? retval : (ssize_t) count; return retval ? retval : (ssize_t) count;
} }
static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL,
...@@ -207,7 +207,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, ...@@ -207,7 +207,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
u64 fcp_lun; u64 fcp_lun;
int retval = -EINVAL; int retval = -EINVAL;
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
retval = -EBUSY; retval = -EBUSY;
goto out; goto out;
...@@ -226,7 +226,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, ...@@ -226,7 +226,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
zfcp_erp_wait(unit->port->adapter); zfcp_erp_wait(unit->port->adapter);
zfcp_unit_put(unit); zfcp_unit_put(unit);
out: out:
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return retval ? retval : (ssize_t) count; return retval ? retval : (ssize_t) count;
} }
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store); static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
...@@ -241,7 +241,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, ...@@ -241,7 +241,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
int retval = 0; int retval = 0;
LIST_HEAD(unit_remove_lh); LIST_HEAD(unit_remove_lh);
down(&zfcp_data.config_sema); mutex_lock(&zfcp_data.config_mutex);
if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) {
retval = -EBUSY; retval = -EBUSY;
goto out; goto out;
...@@ -282,7 +282,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, ...@@ -282,7 +282,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
zfcp_unit_put(unit); zfcp_unit_put(unit);
zfcp_unit_dequeue(unit); zfcp_unit_dequeue(unit);
out: out:
up(&zfcp_data.config_sema); mutex_unlock(&zfcp_data.config_mutex);
return retval ? retval : (ssize_t) count; return retval ? retval : (ssize_t) count;
} }
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
...@@ -425,7 +425,7 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, ...@@ -425,7 +425,7 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev,
if (!qtcb_port) if (!qtcb_port)
return -ENOMEM; return -ENOMEM;
retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port);
if (!retval) if (!retval)
retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util,
qtcb_port->cb_util, qtcb_port->a_util); qtcb_port->cb_util, qtcb_port->a_util);
...@@ -451,7 +451,7 @@ static int zfcp_sysfs_adapter_ex_config(struct device *dev, ...@@ -451,7 +451,7 @@ static int zfcp_sysfs_adapter_ex_config(struct device *dev,
if (!qtcb_config) if (!qtcb_config)
return -ENOMEM; return -ENOMEM;
retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config);
if (!retval) if (!retval)
*stat_inf = qtcb_config->stat_info; *stat_inf = qtcb_config->stat_info;
...@@ -492,15 +492,15 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev, ...@@ -492,15 +492,15 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev,
char *buf) char *buf)
{ {
struct Scsi_Host *scsi_host = class_to_shost(dev); struct Scsi_Host *scsi_host = class_to_shost(dev);
struct zfcp_adapter *adapter = struct zfcp_qdio *qdio =
(struct zfcp_adapter *) scsi_host->hostdata[0]; ((struct zfcp_adapter *) scsi_host->hostdata[0])->qdio;
u64 util; u64 util;
spin_lock_bh(&adapter->qdio_stat_lock); spin_lock_bh(&qdio->stat_lock);
util = adapter->req_q_util; util = qdio->req_q_util;
spin_unlock_bh(&adapter->qdio_stat_lock); spin_unlock_bh(&qdio->stat_lock);
return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full), return sprintf(buf, "%d %llu\n", atomic_read(&qdio->req_q_full),
(unsigned long long)util); (unsigned long long)util);
} }
static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL); static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL);
......
...@@ -1811,6 +1811,12 @@ config ZFCP ...@@ -1811,6 +1811,12 @@ config ZFCP
called zfcp. If you want to compile it as a module, say M here called zfcp. If you want to compile it as a module, say M here
and read <file:Documentation/kbuild/modules.txt>. and read <file:Documentation/kbuild/modules.txt>.
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
depends on PCI && SCSI
---help---
This driver supports the PMC SIERRA MaxRAID adapters.
config SCSI_SRP config SCSI_SRP
tristate "SCSI RDMA Protocol helper library" tristate "SCSI RDMA Protocol helper library"
depends on SCSI && PCI depends on SCSI && PCI
......
...@@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/ ...@@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/
obj-$(CONFIG_PS3_ROM) += ps3rom.o obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_ARM) += arm/
......
此差异已折叠。
...@@ -387,6 +387,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) ...@@ -387,6 +387,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
bnx2i_ep = ep->dd_data; bnx2i_ep = ep->dd_data;
INIT_LIST_HEAD(&bnx2i_ep->link); INIT_LIST_HEAD(&bnx2i_ep->link);
bnx2i_ep->state = EP_STATE_IDLE; bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
bnx2i_ep->hba = hba; bnx2i_ep->hba = hba;
bnx2i_ep->hba_age = hba->age; bnx2i_ep->hba_age = hba->age;
hba->ofld_conns_active++; hba->ofld_conns_active++;
...@@ -1160,9 +1161,6 @@ static int bnx2i_task_xmit(struct iscsi_task *task) ...@@ -1160,9 +1161,6 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
struct bnx2i_cmd *cmd = task->dd_data; struct bnx2i_cmd *cmd = task->dd_data;
struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
return -ENOTCONN;
if (!bnx2i_conn->is_bound) if (!bnx2i_conn->is_bound)
return -ENOTCONN; return -ENOTCONN;
...@@ -1653,15 +1651,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, ...@@ -1653,15 +1651,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
struct iscsi_endpoint *ep; struct iscsi_endpoint *ep;
int rc = 0; int rc = 0;
if (shost) if (shost) {
/* driver is given scsi host to work with */ /* driver is given scsi host to work with */
hba = iscsi_host_priv(shost); hba = iscsi_host_priv(shost);
else /* Register the device with cnic if not already done so */
bnx2i_register_device(hba);
} else
/* /*
* check if the given destination can be reached through * check if the given destination can be reached through
* a iscsi capable NetXtreme2 device * a iscsi capable NetXtreme2 device
*/ */
hba = bnx2i_check_route(dst_addr); hba = bnx2i_check_route(dst_addr);
if (!hba) { if (!hba) {
rc = -ENOMEM; rc = -ENOMEM;
goto check_busy; goto check_busy;
...@@ -1681,8 +1682,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, ...@@ -1681,8 +1682,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
goto net_if_down; goto net_if_down;
} }
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
bnx2i_ep->num_active_cmds = 0; bnx2i_ep->num_active_cmds = 0;
iscsi_cid = bnx2i_alloc_iscsi_cid(hba); iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
if (iscsi_cid == -1) { if (iscsi_cid == -1) {
......
...@@ -353,6 +353,12 @@ ch_readconfig(scsi_changer *ch) ...@@ -353,6 +353,12 @@ ch_readconfig(scsi_changer *ch)
/* look up the devices of the data transfer elements */ /* look up the devices of the data transfer elements */
ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device), ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device),
GFP_KERNEL); GFP_KERNEL);
if (!ch->dt) {
kfree(buffer);
return -ENOMEM;
}
for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
id = -1; id = -1;
lun = 0; lun = 0;
......
此差异已折叠。
...@@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev) ...@@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev)
goto out; goto out;
} }
if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
out: out:
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work) ...@@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work)
} }
spin_unlock_irqrestore(&fnic->fnic_lock, flags); spin_unlock_irqrestore(&fnic->fnic_lock, flags);
fc_exch_recv(lp, lp->emp, fp); fc_exch_recv(lp, fp);
} }
} }
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -124,6 +124,7 @@ static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max, ...@@ -124,6 +124,7 @@ static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
kfree(ring[i]); kfree(ring[i]);
} }
kfree(ring);
} }
int srp_target_alloc(struct srp_target *target, struct device *dev, int srp_target_alloc(struct srp_target *target, struct device *dev,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册