forked from Minki/linux
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-for-linus-2.6
This commit is contained in:
commit
9600c11ba3
@ -35,6 +35,23 @@ config FUSION_FC
|
||||
LSIFC929X
|
||||
LSIFC929XL
|
||||
|
||||
config FUSION_SAS
|
||||
tristate "Fusion MPT ScsiHost drivers for SAS"
|
||||
depends on PCI && SCSI
|
||||
select FUSION
|
||||
select SCSI_SAS_ATTRS
|
||||
---help---
|
||||
SCSI HOST support for a SAS host adapters.
|
||||
|
||||
List of supported controllers:
|
||||
|
||||
LSISAS1064
|
||||
LSISAS1066
|
||||
LSISAS1068
|
||||
LSISAS1064E
|
||||
LSISAS1066E
|
||||
LSISAS1068E
|
||||
|
||||
config FUSION_MAX_SGE
|
||||
int "Maximum number of scatter gather entries (16 - 128)"
|
||||
depends on FUSION
|
||||
|
@ -34,5 +34,6 @@
|
||||
|
||||
obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o
|
||||
obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o
|
||||
obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o
|
||||
obj-$(CONFIG_FUSION_CTL) += mptctl.o
|
||||
obj-$(CONFIG_FUSION_LAN) += mptlan.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -65,6 +65,7 @@
|
||||
#include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */
|
||||
#include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */
|
||||
#include "lsi/mpi_tool.h" /* Tools support */
|
||||
#include "lsi/mpi_sas.h" /* SAS support */
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
|
||||
@ -76,8 +77,8 @@
|
||||
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
|
||||
#endif
|
||||
|
||||
#define MPT_LINUX_VERSION_COMMON "3.03.02"
|
||||
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.02"
|
||||
#define MPT_LINUX_VERSION_COMMON "3.03.03"
|
||||
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.03"
|
||||
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
|
||||
|
||||
#define show_mptmod_ver(s,ver) \
|
||||
@ -423,7 +424,7 @@ typedef struct _MPT_IOCTL {
|
||||
/*
|
||||
* Event Structure and define
|
||||
*/
|
||||
#define MPTCTL_EVENT_LOG_SIZE (0x0000000A)
|
||||
#define MPTCTL_EVENT_LOG_SIZE (0x000000032)
|
||||
typedef struct _mpt_ioctl_events {
|
||||
u32 event; /* Specified by define above */
|
||||
u32 eventContext; /* Index or counter */
|
||||
@ -451,16 +452,13 @@ typedef struct _mpt_ioctl_events {
|
||||
#define MPT_SCSICFG_ALL_IDS 0x02 /* WriteSDP1 to all IDS */
|
||||
/* #define MPT_SCSICFG_BLK_NEGO 0x10 WriteSDP1 with WDTR and SDTR disabled */
|
||||
|
||||
typedef struct _ScsiCfgData {
|
||||
typedef struct _SpiCfgData {
|
||||
u32 PortFlags;
|
||||
int *nvram; /* table of device NVRAM values */
|
||||
IOCPage2_t *pIocPg2; /* table of Raid Volumes */
|
||||
IOCPage3_t *pIocPg3; /* table of physical disks */
|
||||
IOCPage4_t *pIocPg4; /* SEP devices addressing */
|
||||
dma_addr_t IocPg4_dma; /* Phys Addr of IOCPage4 data */
|
||||
int IocPg4Sz; /* IOCPage4 size */
|
||||
u8 dvStatus[MPT_MAX_SCSI_DEVICES];
|
||||
int isRaid; /* bit field, 1 if RAID */
|
||||
u8 minSyncFactor; /* 0xFF if async */
|
||||
u8 maxSyncOffset; /* 0 if async */
|
||||
u8 maxBusWidth; /* 0 if narrow, 1 if wide */
|
||||
@ -472,10 +470,28 @@ typedef struct _ScsiCfgData {
|
||||
u8 dvScheduled; /* 1 if scheduled */
|
||||
u8 forceDv; /* 1 to force DV scheduling */
|
||||
u8 noQas; /* Disable QAS for this adapter */
|
||||
u8 Saf_Te; /* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */
|
||||
u8 Saf_Te; /* 1 to force all Processors as
|
||||
* SAF-TE if Inquiry data length
|
||||
* is too short to check for SAF-TE
|
||||
*/
|
||||
u8 mpt_dv; /* command line option: enhanced=1, basic=0 */
|
||||
u8 bus_reset; /* 1 to allow bus reset */
|
||||
u8 rsvd[1];
|
||||
} ScsiCfgData;
|
||||
}SpiCfgData;
|
||||
|
||||
typedef struct _SasCfgData {
|
||||
u8 ptClear; /* 1 to automatically clear the
|
||||
* persistent table.
|
||||
* 0 to disable
|
||||
* automatic clearing.
|
||||
*/
|
||||
}SasCfgData;
|
||||
|
||||
typedef struct _RaidCfgData {
|
||||
IOCPage2_t *pIocPg2; /* table of Raid Volumes */
|
||||
IOCPage3_t *pIocPg3; /* table of physical disks */
|
||||
int isRaid; /* bit field, 1 if RAID */
|
||||
}RaidCfgData;
|
||||
|
||||
/*
|
||||
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
|
||||
@ -530,11 +546,16 @@ typedef struct _MPT_ADAPTER
|
||||
u8 *sense_buf_pool;
|
||||
dma_addr_t sense_buf_pool_dma;
|
||||
u32 sense_buf_low_dma;
|
||||
u8 *HostPageBuffer; /* SAS - host page buffer support */
|
||||
u32 HostPageBuffer_sz;
|
||||
dma_addr_t HostPageBuffer_dma;
|
||||
int mtrr_reg;
|
||||
struct pci_dev *pcidev; /* struct pci_dev pointer */
|
||||
u8 __iomem *memmap; /* mmap address */
|
||||
struct Scsi_Host *sh; /* Scsi Host pointer */
|
||||
ScsiCfgData spi_data; /* Scsi config. data */
|
||||
SpiCfgData spi_data; /* Scsi config. data */
|
||||
RaidCfgData raid_data; /* Raid config. data */
|
||||
SasCfgData sas_data; /* Sas config. data */
|
||||
MPT_IOCTL *ioctl; /* ioctl data pointer */
|
||||
struct proc_dir_entry *ioc_dentry;
|
||||
struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */
|
||||
@ -554,31 +575,35 @@ typedef struct _MPT_ADAPTER
|
||||
#else
|
||||
u32 mfcnt;
|
||||
#endif
|
||||
u32 NB_for_64_byte_frame;
|
||||
u32 NB_for_64_byte_frame;
|
||||
u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)];
|
||||
u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)];
|
||||
IOCFactsReply_t facts;
|
||||
PortFactsReply_t pfacts[2];
|
||||
FCPortPage0_t fc_port_page0[2];
|
||||
struct timer_list persist_timer; /* persist table timer */
|
||||
int persist_wait_done; /* persist completion flag */
|
||||
u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
|
||||
LANPage0_t lan_cnfg_page0;
|
||||
LANPage1_t lan_cnfg_page1;
|
||||
/*
|
||||
/*
|
||||
* Description: errata_flag_1064
|
||||
* If a PCIX read occurs within 1 or 2 cycles after the chip receives
|
||||
* a split completion for a read data, an internal address pointer incorrectly
|
||||
* increments by 32 bytes
|
||||
*/
|
||||
int errata_flag_1064;
|
||||
int errata_flag_1064;
|
||||
u8 FirstWhoInit;
|
||||
u8 upload_fw; /* If set, do a fw upload */
|
||||
u8 reload_fw; /* Force a FW Reload on next reset */
|
||||
u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
|
||||
u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
|
||||
u8 pad1[4];
|
||||
int DoneCtx;
|
||||
int TaskCtx;
|
||||
int InternalCtx;
|
||||
struct list_head list;
|
||||
struct list_head list;
|
||||
struct net_device *netdev;
|
||||
struct list_head sas_topology;
|
||||
} MPT_ADAPTER;
|
||||
|
||||
/*
|
||||
@ -964,6 +989,7 @@ extern void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
|
||||
extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
|
||||
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
|
||||
extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
|
||||
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
|
||||
|
||||
/*
|
||||
* Public data decl's...
|
||||
|
@ -1326,7 +1326,7 @@ mptctl_gettargetinfo (unsigned long arg)
|
||||
*/
|
||||
if (hd && hd->Targets) {
|
||||
mpt_findImVolumes(ioc);
|
||||
pIoc2 = ioc->spi_data.pIocPg2;
|
||||
pIoc2 = ioc->raid_data.pIocPg2;
|
||||
for ( id = 0; id <= max_id; ) {
|
||||
if ( pIoc2 && pIoc2->NumActiveVolumes ) {
|
||||
if ( id == pIoc2->RaidVolume[0].VolumeID ) {
|
||||
@ -1348,7 +1348,7 @@ mptctl_gettargetinfo (unsigned long arg)
|
||||
--maxWordsLeft;
|
||||
goto next_id;
|
||||
} else {
|
||||
pIoc3 = ioc->spi_data.pIocPg3;
|
||||
pIoc3 = ioc->raid_data.pIocPg3;
|
||||
for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) {
|
||||
if ( pIoc3->PhysDisk[jj].PhysDiskID == id )
|
||||
goto next_id;
|
||||
|
@ -189,7 +189,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
printk(MYIOC_s_WARN_FMT
|
||||
"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
|
||||
ioc->name, ioc);
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
|
||||
|
@ -312,7 +312,12 @@ static int
|
||||
mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
||||
{
|
||||
struct net_device *dev = ioc->netdev;
|
||||
struct mpt_lan_priv *priv = netdev_priv(dev);
|
||||
struct mpt_lan_priv *priv;
|
||||
|
||||
if (dev == NULL)
|
||||
return(1);
|
||||
else
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n",
|
||||
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
|
||||
|
1235
drivers/message/fusion/mptsas.c
Normal file
1235
drivers/message/fusion/mptsas.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -62,6 +62,7 @@
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi_dbg.h>
|
||||
|
||||
#include "mptbase.h"
|
||||
#include "mptscsih.h"
|
||||
@ -93,8 +94,9 @@ typedef struct _BIG_SENSE_BUF {
|
||||
|
||||
#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
|
||||
#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
|
||||
#define MPT_ICFLAG_PHYS_DISK 0x04 /* Any SCSI IO but do Phys Disk Format */
|
||||
#define MPT_ICFLAG_TAGGED_CMD 0x08 /* Do tagged IO */
|
||||
#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
|
||||
#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
|
||||
#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
|
||||
#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
|
||||
#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
|
||||
|
||||
@ -159,6 +161,8 @@ int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR
|
||||
static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
|
||||
static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
|
||||
|
||||
static struct work_struct mptscsih_persistTask;
|
||||
|
||||
#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
|
||||
static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
|
||||
static void mptscsih_domainValidation(void *hd);
|
||||
@ -167,6 +171,7 @@ static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
|
||||
static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
|
||||
static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
|
||||
static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
|
||||
static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
|
||||
#endif
|
||||
|
||||
void mptscsih_remove(struct pci_dev *);
|
||||
@ -606,11 +611,24 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
|
||||
sc->resid = sc->request_bufflen - xfer_cnt;
|
||||
|
||||
/*
|
||||
* if we get a data underrun indication, yet no data was
|
||||
* transferred and the SCSI status indicates that the
|
||||
* command was never started, change the data underrun
|
||||
* to success
|
||||
*/
|
||||
if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
|
||||
(scsi_status == MPI_SCSI_STATUS_BUSY ||
|
||||
scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||
|
||||
scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {
|
||||
status = MPI_IOCSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
|
||||
"IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
|
||||
"resid=%d bufflen=%d xfer_cnt=%d\n",
|
||||
ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
|
||||
status, scsi_state, scsi_status, sc->resid,
|
||||
status, scsi_state, scsi_status, sc->resid,
|
||||
sc->request_bufflen, xfer_cnt));
|
||||
|
||||
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
|
||||
@ -619,8 +637,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
/*
|
||||
* Look for + dump FCP ResponseInfo[]!
|
||||
*/
|
||||
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) {
|
||||
printk(KERN_NOTICE " FCP_ResponseInfo=%08xh\n",
|
||||
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
|
||||
pScsiReply->ResponseInfo) {
|
||||
printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
|
||||
"FCP_ResponseInfo=%08xh\n",
|
||||
ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],
|
||||
le32_to_cpu(pScsiReply->ResponseInfo));
|
||||
}
|
||||
|
||||
@ -661,23 +682,13 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
break;
|
||||
|
||||
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
|
||||
if ( xfer_cnt >= sc->underflow ) {
|
||||
/* Sufficient data transfer occurred */
|
||||
sc->resid = sc->request_bufflen - xfer_cnt;
|
||||
if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
|
||||
sc->result=DID_SOFT_ERROR << 16;
|
||||
else /* Sufficient data transfer occurred */
|
||||
sc->result = (DID_OK << 16) | scsi_status;
|
||||
} else if ( xfer_cnt == 0 ) {
|
||||
/* A CRC Error causes this condition; retry */
|
||||
sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
|
||||
(CHECK_CONDITION << 1);
|
||||
sc->sense_buffer[0] = 0x70;
|
||||
sc->sense_buffer[2] = NO_SENSE;
|
||||
sc->sense_buffer[12] = 0;
|
||||
sc->sense_buffer[13] = 0;
|
||||
} else {
|
||||
sc->result = DID_SOFT_ERROR << 16;
|
||||
}
|
||||
dreplyprintk((KERN_NOTICE
|
||||
"RESIDUAL_MISMATCH: result=%x on id=%d\n",
|
||||
sc->result, sc->device->id));
|
||||
dreplyprintk((KERN_NOTICE
|
||||
"RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
|
||||
break;
|
||||
|
||||
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
|
||||
@ -692,7 +703,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
;
|
||||
} else {
|
||||
if (xfer_cnt < sc->underflow) {
|
||||
sc->result = DID_SOFT_ERROR << 16;
|
||||
if (scsi_status == SAM_STAT_BUSY)
|
||||
sc->result = SAM_STAT_BUSY;
|
||||
else
|
||||
sc->result = DID_SOFT_ERROR << 16;
|
||||
}
|
||||
if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
|
||||
/* What to do?
|
||||
@ -717,8 +731,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
|
||||
|
||||
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
|
||||
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
|
||||
scsi_status = pScsiReply->SCSIStatus;
|
||||
sc->result = (DID_OK << 16) | scsi_status;
|
||||
if (scsi_status == MPI_SCSI_STATUS_BUSY)
|
||||
sc->result = (DID_BUS_BUSY << 16) | scsi_status;
|
||||
else
|
||||
sc->result = (DID_OK << 16) | scsi_status;
|
||||
if (scsi_state == 0) {
|
||||
;
|
||||
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
|
||||
@ -890,12 +906,13 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun)
|
||||
SCSIIORequest_t *mf = NULL;
|
||||
int ii;
|
||||
int max = hd->ioc->req_depth;
|
||||
struct scsi_cmnd *sc;
|
||||
|
||||
dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
|
||||
target, lun, max));
|
||||
|
||||
for (ii=0; ii < max; ii++) {
|
||||
if (hd->ScsiLookup[ii] != NULL) {
|
||||
if ((sc = hd->ScsiLookup[ii]) != NULL) {
|
||||
|
||||
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
|
||||
|
||||
@ -910,9 +927,22 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun)
|
||||
hd->ScsiLookup[ii] = NULL;
|
||||
mptscsih_freeChainBuffers(hd->ioc, ii);
|
||||
mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
|
||||
if (sc->use_sg) {
|
||||
pci_unmap_sg(hd->ioc->pcidev,
|
||||
(struct scatterlist *) sc->request_buffer,
|
||||
sc->use_sg,
|
||||
sc->sc_data_direction);
|
||||
} else if (sc->request_bufflen) {
|
||||
pci_unmap_single(hd->ioc->pcidev,
|
||||
sc->SCp.dma_handle,
|
||||
sc->request_bufflen,
|
||||
sc->sc_data_direction);
|
||||
}
|
||||
sc->host_scribble = NULL;
|
||||
sc->result = DID_NO_CONNECT << 16;
|
||||
sc->scsi_done(sc);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -967,8 +997,10 @@ mptscsih_remove(struct pci_dev *pdev)
|
||||
unsigned long flags;
|
||||
int sz1;
|
||||
|
||||
if(!host)
|
||||
if(!host) {
|
||||
mpt_detach(pdev);
|
||||
return;
|
||||
}
|
||||
|
||||
scsi_remove_host(host);
|
||||
|
||||
@ -1256,8 +1288,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
MPT_SCSI_HOST *hd;
|
||||
MPT_FRAME_HDR *mf;
|
||||
SCSIIORequest_t *pScsiReq;
|
||||
VirtDevice *pTarget;
|
||||
int target;
|
||||
VirtDevice *pTarget = SCpnt->device->hostdata;
|
||||
int lun;
|
||||
u32 datalen;
|
||||
u32 scsictl;
|
||||
@ -1267,12 +1298,9 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
int ii;
|
||||
|
||||
hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
|
||||
target = SCpnt->device->id;
|
||||
lun = SCpnt->device->lun;
|
||||
SCpnt->scsi_done = done;
|
||||
|
||||
pTarget = hd->Targets[target];
|
||||
|
||||
dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
|
||||
(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
|
||||
|
||||
@ -1315,7 +1343,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
/* Default to untagged. Once a target structure has been allocated,
|
||||
* use the Inquiry data to determine if device supports tagged.
|
||||
*/
|
||||
if ( pTarget
|
||||
if (pTarget
|
||||
&& (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
|
||||
&& (SCpnt->device->tagged_supported)) {
|
||||
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
|
||||
@ -1325,8 +1353,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
|
||||
/* Use the above information to set up the message frame
|
||||
*/
|
||||
pScsiReq->TargetID = (u8) target;
|
||||
pScsiReq->Bus = (u8) SCpnt->device->channel;
|
||||
pScsiReq->TargetID = (u8) pTarget->target_id;
|
||||
pScsiReq->Bus = pTarget->bus_id;
|
||||
pScsiReq->ChainOffset = 0;
|
||||
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
|
||||
pScsiReq->CDBLength = SCpnt->cmd_len;
|
||||
@ -1378,7 +1406,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
|
||||
#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
|
||||
if (hd->ioc->bus_type == SCSI) {
|
||||
int dvStatus = hd->ioc->spi_data.dvStatus[target];
|
||||
int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id];
|
||||
int issueCmd = 1;
|
||||
|
||||
if (dvStatus || hd->ioc->spi_data.forceDv) {
|
||||
@ -1426,6 +1454,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hd->ScsiLookup[my_idx] = NULL;
|
||||
mptscsih_freeChainBuffers(hd->ioc, my_idx);
|
||||
mpt_free_msg_frame(hd->ioc, mf);
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
@ -1713,24 +1742,23 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
|
||||
MPT_FRAME_HDR *mf;
|
||||
u32 ctx2abort;
|
||||
int scpnt_idx;
|
||||
int retval;
|
||||
|
||||
/* If we can't locate our host adapter structure, return FAILED status.
|
||||
*/
|
||||
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
|
||||
SCpnt->result = DID_RESET << 16;
|
||||
SCpnt->scsi_done(SCpnt);
|
||||
dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: "
|
||||
dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
|
||||
"Can't locate host! (sc=%p)\n",
|
||||
SCpnt));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
ioc = hd->ioc;
|
||||
if (hd->resetPending)
|
||||
if (hd->resetPending) {
|
||||
return FAILED;
|
||||
|
||||
printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
}
|
||||
|
||||
if (hd->timeouts < -1)
|
||||
hd->timeouts++;
|
||||
@ -1738,16 +1766,20 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
|
||||
/* Find this command
|
||||
*/
|
||||
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
|
||||
/* Cmd not found in ScsiLookup.
|
||||
/* Cmd not found in ScsiLookup.
|
||||
* Do OS callback.
|
||||
*/
|
||||
SCpnt->result = DID_RESET << 16;
|
||||
dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: "
|
||||
dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
|
||||
"Command not in the active list! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt));
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
scsi_print_command(SCpnt);
|
||||
|
||||
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
|
||||
* (the IO to be ABORT'd)
|
||||
*
|
||||
@ -1760,38 +1792,22 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
|
||||
|
||||
hd->abortSCpnt = SCpnt;
|
||||
|
||||
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
|
||||
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
|
||||
SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
|
||||
ctx2abort, 2 /* 2 second timeout */)
|
||||
< 0) {
|
||||
ctx2abort, 2 /* 2 second timeout */);
|
||||
|
||||
/* The TM request failed and the subsequent FW-reload failed!
|
||||
* Fatal error case.
|
||||
*/
|
||||
printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
|
||||
hd->ioc->name,
|
||||
((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
||||
|
||||
/* We must clear our pending flag before clearing our state.
|
||||
*/
|
||||
if (retval == 0)
|
||||
return SUCCESS;
|
||||
|
||||
if(retval != FAILED ) {
|
||||
hd->tmPending = 0;
|
||||
hd->tmState = TM_STATE_NONE;
|
||||
|
||||
/* Unmap the DMA buffers, if any. */
|
||||
if (SCpnt->use_sg) {
|
||||
pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer,
|
||||
SCpnt->use_sg, SCpnt->sc_data_direction);
|
||||
} else if (SCpnt->request_bufflen) {
|
||||
pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle,
|
||||
SCpnt->request_bufflen, SCpnt->sc_data_direction);
|
||||
}
|
||||
hd->ScsiLookup[scpnt_idx] = NULL;
|
||||
SCpnt->result = DID_RESET << 16;
|
||||
SCpnt->scsi_done(SCpnt); /* Issue the command callback */
|
||||
mptscsih_freeChainBuffers(ioc, scpnt_idx);
|
||||
mpt_free_msg_frame(ioc, mf);
|
||||
return FAILED;
|
||||
}
|
||||
return SUCCESS;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
@ -1807,11 +1823,12 @@ int
|
||||
mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
|
||||
{
|
||||
MPT_SCSI_HOST *hd;
|
||||
int retval;
|
||||
|
||||
/* If we can't locate our host adapter structure, return FAILED status.
|
||||
*/
|
||||
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
|
||||
dtmprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: "
|
||||
dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
|
||||
"Can't locate host! (sc=%p)\n",
|
||||
SCpnt));
|
||||
return FAILED;
|
||||
@ -1820,24 +1837,26 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
|
||||
if (hd->resetPending)
|
||||
return FAILED;
|
||||
|
||||
printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
|
||||
printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
scsi_print_command(SCpnt);
|
||||
|
||||
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
|
||||
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
|
||||
SCpnt->device->channel, SCpnt->device->id,
|
||||
0, 0, 5 /* 5 second timeout */)
|
||||
< 0){
|
||||
/* The TM request failed and the subsequent FW-reload failed!
|
||||
* Fatal error case.
|
||||
*/
|
||||
printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
0, 0, 5 /* 5 second timeout */);
|
||||
|
||||
printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
|
||||
hd->ioc->name,
|
||||
((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
||||
|
||||
if (retval == 0)
|
||||
return SUCCESS;
|
||||
|
||||
if(retval != FAILED ) {
|
||||
hd->tmPending = 0;
|
||||
hd->tmState = TM_STATE_NONE;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
@ -1853,41 +1872,39 @@ int
|
||||
mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
|
||||
{
|
||||
MPT_SCSI_HOST *hd;
|
||||
spinlock_t *host_lock = SCpnt->device->host->host_lock;
|
||||
int retval;
|
||||
|
||||
/* If we can't locate our host adapter structure, return FAILED status.
|
||||
*/
|
||||
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
|
||||
dtmprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: "
|
||||
dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
|
||||
"Can't locate host! (sc=%p)\n",
|
||||
SCpnt ) );
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n",
|
||||
printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
scsi_print_command(SCpnt);
|
||||
|
||||
if (hd->timeouts < -1)
|
||||
hd->timeouts++;
|
||||
|
||||
/* We are now ready to execute the task management request. */
|
||||
if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
||||
SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */)
|
||||
< 0){
|
||||
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
|
||||
SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */);
|
||||
|
||||
/* The TM request failed and the subsequent FW-reload failed!
|
||||
* Fatal error case.
|
||||
*/
|
||||
printk(MYIOC_s_WARN_FMT
|
||||
"Error processing TaskMgmt request (sc=%p)\n",
|
||||
hd->ioc->name, SCpnt);
|
||||
printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
|
||||
hd->ioc->name,
|
||||
((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
|
||||
|
||||
if (retval == 0)
|
||||
return SUCCESS;
|
||||
|
||||
if(retval != FAILED ) {
|
||||
hd->tmPending = 0;
|
||||
hd->tmState = TM_STATE_NONE;
|
||||
spin_lock_irq(host_lock);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
@ -2169,7 +2186,7 @@ mptscsih_slave_alloc(struct scsi_device *device)
|
||||
vdev->raidVolume = 0;
|
||||
hd->Targets[device->id] = vdev;
|
||||
if (hd->ioc->bus_type == SCSI) {
|
||||
if (hd->ioc->spi_data.isRaid & (1 << device->id)) {
|
||||
if (hd->ioc->raid_data.isRaid & (1 << device->id)) {
|
||||
vdev->raidVolume = 1;
|
||||
ddvtprintk((KERN_INFO
|
||||
"RAID Volume @ id %d\n", device->id));
|
||||
@ -2180,22 +2197,7 @@ mptscsih_slave_alloc(struct scsi_device *device)
|
||||
|
||||
out:
|
||||
vdev->num_luns++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) {
|
||||
if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID)
|
||||
return 1;
|
||||
}
|
||||
|
||||
device->hostdata = vdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2226,7 +2228,7 @@ mptscsih_slave_destroy(struct scsi_device *device)
|
||||
hd->Targets[target] = NULL;
|
||||
|
||||
if (hd->ioc->bus_type == SCSI) {
|
||||
if (mptscsih_is_raid_volume(hd, target)) {
|
||||
if (mptscsih_is_phys_disk(hd->ioc, target)) {
|
||||
hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
|
||||
} else {
|
||||
hd->ioc->spi_data.dvStatus[target] =
|
||||
@ -2439,6 +2441,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
||||
{
|
||||
MPT_SCSI_HOST *hd;
|
||||
unsigned long flags;
|
||||
int ii;
|
||||
|
||||
dtmprintk((KERN_WARNING MYNAM
|
||||
": IOC %s_reset routed to SCSI host driver!\n",
|
||||
@ -2496,11 +2499,8 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
||||
|
||||
/* ScsiLookup initialization
|
||||
*/
|
||||
{
|
||||
int ii;
|
||||
for (ii=0; ii < hd->ioc->req_depth; ii++)
|
||||
hd->ScsiLookup[ii] = NULL;
|
||||
}
|
||||
for (ii=0; ii < hd->ioc->req_depth; ii++)
|
||||
hd->ScsiLookup[ii] = NULL;
|
||||
|
||||
/* 2. Chain Buffer initialization
|
||||
*/
|
||||
@ -2548,6 +2548,16 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
|
||||
return 1; /* currently means nothing really */
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/* work queue thread to clear the persitency table */
|
||||
static void
|
||||
mptscsih_sas_persist_clear_table(void * arg)
|
||||
{
|
||||
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
|
||||
|
||||
mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
int
|
||||
mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
||||
@ -2558,18 +2568,18 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
||||
devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
|
||||
ioc->name, event));
|
||||
|
||||
if (ioc->sh == NULL ||
|
||||
((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
|
||||
return 1;
|
||||
|
||||
switch (event) {
|
||||
case MPI_EVENT_UNIT_ATTENTION: /* 03 */
|
||||
/* FIXME! */
|
||||
break;
|
||||
case MPI_EVENT_IOC_BUS_RESET: /* 04 */
|
||||
case MPI_EVENT_EXT_BUS_RESET: /* 05 */
|
||||
hd = NULL;
|
||||
if (ioc->sh) {
|
||||
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
||||
if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
|
||||
hd->soft_resets++;
|
||||
}
|
||||
if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1))
|
||||
hd->soft_resets++;
|
||||
break;
|
||||
case MPI_EVENT_LOGOUT: /* 09 */
|
||||
/* FIXME! */
|
||||
@ -2588,69 +2598,24 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
|
||||
break;
|
||||
|
||||
case MPI_EVENT_INTEGRATED_RAID: /* 0B */
|
||||
{
|
||||
pMpiEventDataRaid_t pRaidEventData =
|
||||
(pMpiEventDataRaid_t) pEvReply->Data;
|
||||
#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
|
||||
/* negoNvram set to 0 if DV enabled and to USE_NVRAM if
|
||||
* if DV disabled. Need to check for target mode.
|
||||
*/
|
||||
hd = NULL;
|
||||
if (ioc->sh)
|
||||
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
|
||||
|
||||
if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) {
|
||||
ScsiCfgData *pSpi;
|
||||
Ioc3PhysDisk_t *pPDisk;
|
||||
int numPDisk;
|
||||
u8 reason;
|
||||
u8 physDiskNum;
|
||||
|
||||
reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
|
||||
if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
|
||||
/* New or replaced disk.
|
||||
* Set DV flag and schedule DV.
|
||||
*/
|
||||
pSpi = &ioc->spi_data;
|
||||
physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24;
|
||||
ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum));
|
||||
if (pSpi->pIocPg3) {
|
||||
pPDisk = pSpi->pIocPg3->PhysDisk;
|
||||
numPDisk =pSpi->pIocPg3->NumPhysDisks;
|
||||
|
||||
while (numPDisk) {
|
||||
if (physDiskNum == pPDisk->PhysDiskNum) {
|
||||
pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
|
||||
pSpi->forceDv = MPT_SCSICFG_NEED_DV;
|
||||
ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
|
||||
break;
|
||||
}
|
||||
pPDisk++;
|
||||
numPDisk--;
|
||||
}
|
||||
|
||||
if (numPDisk == 0) {
|
||||
/* The physical disk that needs DV was not found
|
||||
* in the stored IOC Page 3. The driver must reload
|
||||
* this page. DV routine will set the NEED_DV flag for
|
||||
* all phys disks that have DV_NOT_DONE set.
|
||||
*/
|
||||
pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
|
||||
ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Domain Validation Needed */
|
||||
if (ioc->bus_type == SCSI &&
|
||||
pRaidEventData->ReasonCode ==
|
||||
MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
|
||||
mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
|
||||
printk("Raid Event RF: ");
|
||||
{
|
||||
u32 *m = (u32 *)pEvReply;
|
||||
int ii;
|
||||
int n = (int)pEvReply->MsgLength;
|
||||
for (ii=6; ii < n; ii++)
|
||||
printk(" %08x", le32_to_cpu(m[ii]));
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
/* Persistent table is full. */
|
||||
case MPI_EVENT_PERSISTENT_TABLE_FULL:
|
||||
INIT_WORK(&mptscsih_persistTask,
|
||||
mptscsih_sas_persist_clear_table,(void *)ioc);
|
||||
schedule_work(&mptscsih_persistTask);
|
||||
break;
|
||||
|
||||
case MPI_EVENT_NONE: /* 00 */
|
||||
@ -2687,7 +2652,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *
|
||||
{
|
||||
int indexed_lun, lun_index;
|
||||
VirtDevice *vdev;
|
||||
ScsiCfgData *pSpi;
|
||||
SpiCfgData *pSpi;
|
||||
char data_56;
|
||||
|
||||
dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
|
||||
@ -2794,7 +2759,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *
|
||||
static void
|
||||
mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
|
||||
{
|
||||
ScsiCfgData *pspi_data = &hd->ioc->spi_data;
|
||||
SpiCfgData *pspi_data = &hd->ioc->spi_data;
|
||||
int id = (int) target->target_id;
|
||||
int nvram;
|
||||
VirtDevice *vdev;
|
||||
@ -2973,11 +2938,13 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56)
|
||||
static void
|
||||
mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
|
||||
{
|
||||
MPT_ADAPTER *ioc = hd->ioc;
|
||||
u8 cmd;
|
||||
ScsiCfgData *pSpi;
|
||||
SpiCfgData *pSpi;
|
||||
|
||||
ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
|
||||
pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
|
||||
ddvtprintk((MYIOC_s_NOTE_FMT
|
||||
" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
|
||||
hd->ioc->name, pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0]));
|
||||
|
||||
if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0))
|
||||
return;
|
||||
@ -2985,12 +2952,12 @@ mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
|
||||
cmd = pReq->CDB[0];
|
||||
|
||||
if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
|
||||
pSpi = &hd->ioc->spi_data;
|
||||
if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) {
|
||||
pSpi = &ioc->spi_data;
|
||||
if ((ioc->raid_data.isRaid & (1 << pReq->TargetID)) && ioc->raid_data.pIocPg3) {
|
||||
/* Set NEED_DV for all hidden disks
|
||||
*/
|
||||
Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk;
|
||||
int numPDisk = pSpi->pIocPg3->NumPhysDisks;
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
|
||||
|
||||
while (numPDisk) {
|
||||
pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
|
||||
@ -3004,6 +2971,50 @@ mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq)
|
||||
}
|
||||
}
|
||||
|
||||
/* mptscsih_raid_set_dv_flags()
|
||||
*
|
||||
* New or replaced disk. Set DV flag and schedule DV.
|
||||
*/
|
||||
static void
|
||||
mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
|
||||
{
|
||||
MPT_ADAPTER *ioc = hd->ioc;
|
||||
SpiCfgData *pSpi = &ioc->spi_data;
|
||||
Ioc3PhysDisk_t *pPDisk;
|
||||
int numPDisk;
|
||||
|
||||
if (hd->negoNvram != 0)
|
||||
return;
|
||||
|
||||
ddvtprintk(("DV requested for phys disk id %d\n", id));
|
||||
if (ioc->raid_data.pIocPg3) {
|
||||
pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
|
||||
numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
|
||||
while (numPDisk) {
|
||||
if (id == pPDisk->PhysDiskNum) {
|
||||
pSpi->dvStatus[pPDisk->PhysDiskID] =
|
||||
(MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
|
||||
pSpi->forceDv = MPT_SCSICFG_NEED_DV;
|
||||
ddvtprintk(("NEED_DV set for phys disk id %d\n",
|
||||
pPDisk->PhysDiskID));
|
||||
break;
|
||||
}
|
||||
pPDisk++;
|
||||
numPDisk--;
|
||||
}
|
||||
|
||||
if (numPDisk == 0) {
|
||||
/* The physical disk that needs DV was not found
|
||||
* in the stored IOC Page 3. The driver must reload
|
||||
* this page. DV routine will set the NEED_DV flag for
|
||||
* all phys disks that have DV_NOT_DONE set.
|
||||
*/
|
||||
pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
|
||||
ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/*
|
||||
* If no Target, bus reset on 1st I/O. Set the flag to
|
||||
@ -3091,7 +3102,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
|
||||
MPT_ADAPTER *ioc = hd->ioc;
|
||||
Config_t *pReq;
|
||||
SCSIDevicePage1_t *pData;
|
||||
VirtDevice *pTarget;
|
||||
VirtDevice *pTarget=NULL;
|
||||
MPT_FRAME_HDR *mf;
|
||||
dma_addr_t dataDma;
|
||||
u16 req_idx;
|
||||
@ -3190,7 +3201,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
|
||||
#endif
|
||||
|
||||
if (flags & MPT_SCSICFG_BLK_NEGO)
|
||||
negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
|
||||
negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
|
||||
|
||||
mptscsih_setDevicePage1Flags(width, factor, offset,
|
||||
&requested, &configuration, negoFlags);
|
||||
@ -4011,7 +4022,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum)
|
||||
|
||||
/* If target Ptr NULL or if this target is NOT a disk, skip.
|
||||
*/
|
||||
if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
|
||||
if ((pTarget) && (pTarget->inq_data[0] == TYPE_DISK)){
|
||||
for (lun=0; lun <= MPT_LAST_LUN; lun++) {
|
||||
/* If LUN present, issue the command
|
||||
*/
|
||||
@ -4106,9 +4117,9 @@ mptscsih_domainValidation(void *arg)
|
||||
|
||||
if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
|
||||
mpt_read_ioc_pg_3(ioc);
|
||||
if (ioc->spi_data.pIocPg3) {
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
||||
if (ioc->raid_data.pIocPg3) {
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
|
||||
|
||||
while (numPDisk) {
|
||||
if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
|
||||
@ -4147,7 +4158,7 @@ mptscsih_domainValidation(void *arg)
|
||||
isPhysDisk = mptscsih_is_phys_disk(ioc, id);
|
||||
if (isPhysDisk) {
|
||||
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
||||
if (hd->ioc->spi_data.isRaid & (1 << ii)) {
|
||||
if (hd->ioc->raid_data.isRaid & (1 << ii)) {
|
||||
hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
|
||||
}
|
||||
}
|
||||
@ -4166,7 +4177,7 @@ mptscsih_domainValidation(void *arg)
|
||||
|
||||
if (isPhysDisk) {
|
||||
for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
|
||||
if (hd->ioc->spi_data.isRaid & (1 << ii)) {
|
||||
if (hd->ioc->raid_data.isRaid & (1 << ii)) {
|
||||
hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
|
||||
}
|
||||
}
|
||||
@ -4188,21 +4199,21 @@ mptscsih_domainValidation(void *arg)
|
||||
|
||||
/* Search IOC page 3 to determine if this is hidden physical disk
|
||||
*/
|
||||
static int
|
||||
/* Search IOC page 3 to determine if this is hidden physical disk
|
||||
*/
|
||||
static int
|
||||
mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
|
||||
{
|
||||
if (ioc->spi_data.pIocPg3) {
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
||||
int i;
|
||||
|
||||
while (numPDisk) {
|
||||
if (pPDisk->PhysDiskID == id) {
|
||||
return 1;
|
||||
}
|
||||
pPDisk++;
|
||||
numPDisk--;
|
||||
}
|
||||
if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
||||
if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4408,7 +4419,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
/* Skip this ID? Set cfg.cfghdr.hdr to force config page write
|
||||
*/
|
||||
{
|
||||
ScsiCfgData *pspi_data = &hd->ioc->spi_data;
|
||||
SpiCfgData *pspi_data = &hd->ioc->spi_data;
|
||||
if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
||||
/* Set the factor from nvram */
|
||||
nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
|
||||
@ -4438,11 +4449,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
}
|
||||
|
||||
/* Finish iocmd inititialization - hidden or visible disk? */
|
||||
if (ioc->spi_data.pIocPg3) {
|
||||
if (ioc->raid_data.pIocPg3) {
|
||||
/* Search IOC page 3 for matching id
|
||||
*/
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks;
|
||||
Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
|
||||
int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
|
||||
|
||||
while (numPDisk) {
|
||||
if (pPDisk->PhysDiskID == id) {
|
||||
@ -4466,7 +4477,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
/* RAID Volume ID's may double for a physical device. If RAID but
|
||||
* not a physical ID as well, skip DV.
|
||||
*/
|
||||
if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
|
||||
if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
|
||||
goto target_done;
|
||||
|
||||
|
||||
@ -4815,6 +4826,8 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
notDone = 0;
|
||||
if (iocmd.flags & MPT_ICFLAG_ECHO) {
|
||||
bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
|
||||
if (pbuf1[0] & 0x01)
|
||||
iocmd.flags |= MPT_ICFLAG_EBOS;
|
||||
} else {
|
||||
bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
|
||||
}
|
||||
@ -4911,6 +4924,9 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
}
|
||||
iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
|
||||
|
||||
if (iocmd.flags & MPT_ICFLAG_EBOS)
|
||||
goto skip_Reserve;
|
||||
|
||||
repeat = 5;
|
||||
while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
|
||||
iocmd.cmd = RESERVE;
|
||||
@ -4954,6 +4970,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
|
||||
}
|
||||
}
|
||||
|
||||
skip_Reserve:
|
||||
mptscsih_fillbuf(pbuf1, sz, patt, 1);
|
||||
iocmd.cmd = WRITE_BUFFER;
|
||||
iocmd.data_dma = buf1_dma;
|
||||
@ -5198,11 +5215,12 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
|
||||
* If not an LVD bus, the adapter minSyncFactor has been
|
||||
* already throttled back.
|
||||
*/
|
||||
negoFlags = hd->ioc->spi_data.noQas;
|
||||
if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) {
|
||||
width = pTarget->maxWidth;
|
||||
offset = pTarget->maxOffset;
|
||||
factor = pTarget->minSyncFactor;
|
||||
negoFlags = pTarget->negoFlags;
|
||||
negoFlags |= pTarget->negoFlags;
|
||||
} else {
|
||||
if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
|
||||
data = hd->ioc->spi_data.nvram[id];
|
||||
@ -5223,7 +5241,6 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
|
||||
}
|
||||
|
||||
/* Set the negotiation flags */
|
||||
negoFlags = hd->ioc->spi_data.noQas;
|
||||
if (!width)
|
||||
negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/drivers/message/fusion/mptscsi.h
|
||||
* linux/drivers/message/fusion/mptscsih.h
|
||||
* High performance SCSI / Fibre Channel SCSI Host device driver.
|
||||
* For use with PCI chip/adapter(s):
|
||||
* LSIFC9xx/LSI409xx Fibre Channel
|
||||
@ -53,8 +53,8 @@
|
||||
* SCSI Public stuff...
|
||||
*/
|
||||
|
||||
#define MPT_SCSI_CMD_PER_DEV_HIGH 31
|
||||
#define MPT_SCSI_CMD_PER_DEV_LOW 7
|
||||
#define MPT_SCSI_CMD_PER_DEV_HIGH 64
|
||||
#define MPT_SCSI_CMD_PER_DEV_LOW 32
|
||||
|
||||
#define MPT_SCSI_CMD_PER_LUN 7
|
||||
|
||||
@ -77,6 +77,7 @@
|
||||
#define MPTSCSIH_MAX_WIDTH 1
|
||||
#define MPTSCSIH_MIN_SYNC 0x08
|
||||
#define MPTSCSIH_SAF_TE 0
|
||||
#define MPTSCSIH_PT_CLEAR 0
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -199,7 +199,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
printk(MYIOC_s_WARN_FMT
|
||||
"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
|
||||
ioc->name, ioc);
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST));
|
||||
|
@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \
|
||||
zfcp_fsf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \
|
||||
zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \
|
||||
zfcp_sysfs_unit.o zfcp_sysfs_driver.o
|
||||
|
||||
obj-$(CONFIG_ZFCP) += zfcp.o
|
||||
|
@ -122,95 +122,6 @@ _zfcp_hex_dump(char *addr, int count)
|
||||
|
||||
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
|
||||
|
||||
static inline int
|
||||
zfcp_fsf_req_is_scsi_cmnd(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
return ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) &&
|
||||
!(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT));
|
||||
}
|
||||
|
||||
void
|
||||
zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
|
||||
void *add_data, int add_length)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
struct scsi_cmnd *scsi_cmnd;
|
||||
int level = 3;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->dbf_lock, flags);
|
||||
if (zfcp_fsf_req_is_scsi_cmnd(fsf_req)) {
|
||||
scsi_cmnd = fsf_req->data.send_fcp_command_task.scsi_cmnd;
|
||||
debug_text_event(adapter->cmd_dbf, level, "fsferror");
|
||||
debug_text_event(adapter->cmd_dbf, level, text);
|
||||
debug_event(adapter->cmd_dbf, level, &fsf_req,
|
||||
sizeof (unsigned long));
|
||||
debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,
|
||||
sizeof (u32));
|
||||
debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
|
||||
sizeof (unsigned long));
|
||||
debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
|
||||
min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
|
||||
for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH)
|
||||
debug_event(adapter->cmd_dbf,
|
||||
level,
|
||||
(char *) add_data + i,
|
||||
min(ZFCP_CMD_DBF_LENGTH, add_length - i));
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->dbf_lock, flags);
|
||||
}
|
||||
|
||||
/* XXX additionally log unit if available */
|
||||
/* ---> introduce new parameter for unit, see 2.4 code */
|
||||
void
|
||||
zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
union zfcp_req_data *req_data;
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
int level = ((host_byte(scsi_cmnd->result) != 0) ? 1 : 5);
|
||||
unsigned long flags;
|
||||
|
||||
adapter = (struct zfcp_adapter *) scsi_cmnd->device->host->hostdata[0];
|
||||
req_data = (union zfcp_req_data *) scsi_cmnd->host_scribble;
|
||||
fsf_req = (req_data ? req_data->send_fcp_command_task.fsf_req : NULL);
|
||||
spin_lock_irqsave(&adapter->dbf_lock, flags);
|
||||
debug_text_event(adapter->cmd_dbf, level, "hostbyte");
|
||||
debug_text_event(adapter->cmd_dbf, level, text);
|
||||
debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32));
|
||||
debug_event(adapter->cmd_dbf, level, &scsi_cmnd,
|
||||
sizeof (unsigned long));
|
||||
debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd,
|
||||
min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len));
|
||||
if (likely(fsf_req)) {
|
||||
debug_event(adapter->cmd_dbf, level, &fsf_req,
|
||||
sizeof (unsigned long));
|
||||
debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no,
|
||||
sizeof (u32));
|
||||
} else {
|
||||
debug_text_event(adapter->cmd_dbf, level, "");
|
||||
debug_text_event(adapter->cmd_dbf, level, "");
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->dbf_lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
|
||||
struct fsf_status_read_buffer *status_buffer, int length)
|
||||
{
|
||||
int level = 1;
|
||||
int i;
|
||||
|
||||
debug_text_event(adapter->in_els_dbf, level, text);
|
||||
debug_event(adapter->in_els_dbf, level, &status_buffer->d_id, 8);
|
||||
for (i = 0; i < length; i += ZFCP_IN_ELS_DBF_LENGTH)
|
||||
debug_event(adapter->in_els_dbf,
|
||||
level,
|
||||
(char *) status_buffer->payload + i,
|
||||
min(ZFCP_IN_ELS_DBF_LENGTH, length - i));
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_device_setup - setup function
|
||||
* @str: pointer to parameter string
|
||||
@ -1017,81 +928,6 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
|
||||
mempool_destroy(adapter->pool.data_gid_pn);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_adapter_debug_register - registers debug feature for an adapter
|
||||
* @adapter: pointer to adapter for which debug features should be registered
|
||||
* return: -ENOMEM on error, 0 otherwise
|
||||
*/
|
||||
int
|
||||
zfcp_adapter_debug_register(struct zfcp_adapter *adapter)
|
||||
{
|
||||
char dbf_name[20];
|
||||
|
||||
/* debug feature area which records SCSI command failures (hostbyte) */
|
||||
spin_lock_init(&adapter->dbf_lock);
|
||||
|
||||
sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->cmd_dbf = debug_register(dbf_name, ZFCP_CMD_DBF_INDEX,
|
||||
ZFCP_CMD_DBF_AREAS,
|
||||
ZFCP_CMD_DBF_LENGTH);
|
||||
debug_register_view(adapter->cmd_dbf, &debug_hex_ascii_view);
|
||||
debug_set_level(adapter->cmd_dbf, ZFCP_CMD_DBF_LEVEL);
|
||||
|
||||
/* debug feature area which records SCSI command aborts */
|
||||
sprintf(dbf_name, ZFCP_ABORT_DBF_NAME "%s",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->abort_dbf = debug_register(dbf_name, ZFCP_ABORT_DBF_INDEX,
|
||||
ZFCP_ABORT_DBF_AREAS,
|
||||
ZFCP_ABORT_DBF_LENGTH);
|
||||
debug_register_view(adapter->abort_dbf, &debug_hex_ascii_view);
|
||||
debug_set_level(adapter->abort_dbf, ZFCP_ABORT_DBF_LEVEL);
|
||||
|
||||
/* debug feature area which records incoming ELS commands */
|
||||
sprintf(dbf_name, ZFCP_IN_ELS_DBF_NAME "%s",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->in_els_dbf = debug_register(dbf_name, ZFCP_IN_ELS_DBF_INDEX,
|
||||
ZFCP_IN_ELS_DBF_AREAS,
|
||||
ZFCP_IN_ELS_DBF_LENGTH);
|
||||
debug_register_view(adapter->in_els_dbf, &debug_hex_ascii_view);
|
||||
debug_set_level(adapter->in_els_dbf, ZFCP_IN_ELS_DBF_LEVEL);
|
||||
|
||||
/* debug feature area which records erp events */
|
||||
sprintf(dbf_name, ZFCP_ERP_DBF_NAME "%s",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->erp_dbf = debug_register(dbf_name, ZFCP_ERP_DBF_INDEX,
|
||||
ZFCP_ERP_DBF_AREAS,
|
||||
ZFCP_ERP_DBF_LENGTH);
|
||||
debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
|
||||
debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
|
||||
|
||||
if (!(adapter->cmd_dbf && adapter->abort_dbf &&
|
||||
adapter->in_els_dbf && adapter->erp_dbf)) {
|
||||
zfcp_adapter_debug_unregister(adapter);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
|
||||
* @adapter: pointer to adapter for which debug features should be unregistered
|
||||
*/
|
||||
void
|
||||
zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter)
|
||||
{
|
||||
debug_unregister(adapter->abort_dbf);
|
||||
debug_unregister(adapter->cmd_dbf);
|
||||
debug_unregister(adapter->erp_dbf);
|
||||
debug_unregister(adapter->in_els_dbf);
|
||||
adapter->abort_dbf = NULL;
|
||||
adapter->cmd_dbf = NULL;
|
||||
adapter->erp_dbf = NULL;
|
||||
adapter->in_els_dbf = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
zfcp_dummy_release(struct device *dev)
|
||||
{
|
||||
@ -1462,10 +1298,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
|
||||
/* see FC-FS */
|
||||
no_entries = (fcp_rscn_head->payload_len / 4);
|
||||
|
||||
zfcp_in_els_dbf_event(adapter, "##rscn", status_buffer,
|
||||
fcp_rscn_head->payload_len);
|
||||
|
||||
debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:");
|
||||
for (i = 1; i < no_entries; i++) {
|
||||
/* skip head and start with 1st element */
|
||||
fcp_rscn_element++;
|
||||
@ -1497,8 +1329,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
|
||||
(ZFCP_STATUS_PORT_DID_DID, &port->status)) {
|
||||
ZFCP_LOG_INFO("incoming RSCN, trying to open "
|
||||
"port 0x%016Lx\n", port->wwpn);
|
||||
debug_text_event(adapter->erp_dbf, 1,
|
||||
"unsol_els_rscnu:");
|
||||
zfcp_erp_port_reopen(port,
|
||||
ZFCP_STATUS_COMMON_ERP_FAILED);
|
||||
continue;
|
||||
@ -1524,8 +1354,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
|
||||
*/
|
||||
ZFCP_LOG_INFO("incoming RSCN, trying to open "
|
||||
"port 0x%016Lx\n", port->wwpn);
|
||||
debug_text_event(adapter->erp_dbf, 1,
|
||||
"unsol_els_rscnk:");
|
||||
zfcp_test_link(port);
|
||||
}
|
||||
}
|
||||
@ -1541,8 +1369,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
|
||||
struct zfcp_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
zfcp_in_els_dbf_event(adapter, "##plogi", status_buffer, 28);
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list) {
|
||||
if (port->wwpn == (*(wwn_t *) & els_logi->nport_wwn))
|
||||
@ -1556,8 +1382,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
|
||||
status_buffer->d_id,
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
} else {
|
||||
debug_text_event(adapter->erp_dbf, 1, "unsol_els_plogi:");
|
||||
debug_event(adapter->erp_dbf, 1, &els_logi->nport_wwn, 8);
|
||||
zfcp_erp_port_forced_reopen(port, 0);
|
||||
}
|
||||
}
|
||||
@ -1570,8 +1394,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
|
||||
struct zfcp_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
zfcp_in_els_dbf_event(adapter, "##logo", status_buffer, 16);
|
||||
|
||||
read_lock_irqsave(&zfcp_data.config_lock, flags);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list) {
|
||||
if (port->wwpn == els_logo->nport_wwpn)
|
||||
@ -1585,8 +1407,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
|
||||
status_buffer->d_id,
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
} else {
|
||||
debug_text_event(adapter->erp_dbf, 1, "unsol_els_logo:");
|
||||
debug_event(adapter->erp_dbf, 1, &els_logo->nport_wwpn, 8);
|
||||
zfcp_erp_port_forced_reopen(port, 0);
|
||||
}
|
||||
}
|
||||
@ -1595,7 +1415,6 @@ static void
|
||||
zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter,
|
||||
struct fsf_status_read_buffer *status_buffer)
|
||||
{
|
||||
zfcp_in_els_dbf_event(adapter, "##undef", status_buffer, 24);
|
||||
ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x "
|
||||
"for adapter %s\n", *(u32 *) (status_buffer->payload),
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
@ -1609,10 +1428,11 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req)
|
||||
u32 els_type;
|
||||
struct zfcp_adapter *adapter;
|
||||
|
||||
status_buffer = fsf_req->data.status_read.buffer;
|
||||
status_buffer = (struct fsf_status_read_buffer *) fsf_req->data;
|
||||
els_type = *(u32 *) (status_buffer->payload);
|
||||
adapter = fsf_req->adapter;
|
||||
|
||||
zfcp_san_dbf_event_incoming_els(fsf_req);
|
||||
if (els_type == LS_PLOGI)
|
||||
zfcp_fsf_incoming_els_plogi(adapter, status_buffer);
|
||||
else if (els_type == LS_LOGO)
|
||||
|
@ -202,19 +202,9 @@ static int
|
||||
zfcp_ccw_set_offline(struct ccw_device *ccw_device)
|
||||
{
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_port *port;
|
||||
struct fc_rport *rport;
|
||||
|
||||
down(&zfcp_data.config_sema);
|
||||
adapter = dev_get_drvdata(&ccw_device->dev);
|
||||
/* might be racy, but we cannot take config_lock due to the fact that
|
||||
fc_remote_port_delete might sleep */
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
if (port->rport) {
|
||||
rport = port->rport;
|
||||
port->rport = NULL;
|
||||
fc_remote_port_delete(rport);
|
||||
}
|
||||
zfcp_erp_adapter_shutdown(adapter, 0);
|
||||
zfcp_erp_wait(adapter);
|
||||
zfcp_adapter_scsi_unregister(adapter);
|
||||
|
995
drivers/s390/scsi/zfcp_dbf.c
Normal file
995
drivers/s390/scsi/zfcp_dbf.c
Normal file
@ -0,0 +1,995 @@
|
||||
/*
|
||||
*
|
||||
* linux/drivers/s390/scsi/zfcp_dbf.c
|
||||
*
|
||||
* FCP adapter driver for IBM eServer zSeries
|
||||
*
|
||||
* Debugging facilities
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2005
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define ZFCP_DBF_REVISION "$Revision$"
|
||||
|
||||
#include <asm/debug.h>
|
||||
#include <linux/ctype.h>
|
||||
#include "zfcp_ext.h"
|
||||
|
||||
static u32 dbfsize = 4;
|
||||
|
||||
module_param(dbfsize, uint, 0400);
|
||||
MODULE_PARM_DESC(dbfsize,
|
||||
"number of pages for each debug feature area (default 4)");
|
||||
|
||||
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
|
||||
|
||||
static inline int
|
||||
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
|
||||
{
|
||||
unsigned long long sec;
|
||||
struct timespec xtime;
|
||||
int len = 0;
|
||||
|
||||
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
|
||||
sec = stck >> 12;
|
||||
do_div(sec, 1000000);
|
||||
xtime.tv_sec = sec;
|
||||
stck -= (sec * 1000000) << 12;
|
||||
xtime.tv_nsec = ((stck * 1000) >> 12);
|
||||
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
|
||||
label, xtime.tv_sec, xtime.tv_nsec);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int zfcp_dbf_tag(char *out_buf, const char *label, const char *tag)
|
||||
{
|
||||
int len = 0, i;
|
||||
|
||||
len += sprintf(out_buf + len, "%-24s", label);
|
||||
for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++)
|
||||
len += sprintf(out_buf + len, "%c", tag[i]);
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_dbf_view(char *out_buf, const char *label, const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int len = 0;
|
||||
|
||||
len += sprintf(out_buf + len, "%-24s", label);
|
||||
va_start(arg, format);
|
||||
len += vsprintf(out_buf + len, format, arg);
|
||||
va_end(arg);
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_dbf_view_dump(char *out_buf, const char *label,
|
||||
char *buffer, int buflen, int offset, int total_size)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (offset == 0)
|
||||
len += sprintf(out_buf + len, "%-24s ", label);
|
||||
|
||||
while (buflen--) {
|
||||
if (offset > 0) {
|
||||
if ((offset % 32) == 0)
|
||||
len += sprintf(out_buf + len, "\n%-24c ", ' ');
|
||||
else if ((offset % 4) == 0)
|
||||
len += sprintf(out_buf + len, " ");
|
||||
}
|
||||
len += sprintf(out_buf + len, "%02x", *buffer++);
|
||||
if (++offset == total_size) {
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (total_size == 0)
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
|
||||
debug_entry_t * entry, char *out_buf)
|
||||
{
|
||||
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry);
|
||||
int len = 0;
|
||||
|
||||
if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) {
|
||||
len += zfcp_dbf_stck(out_buf + len, "timestamp",
|
||||
entry->id.stck);
|
||||
len += zfcp_dbf_view(out_buf + len, "cpu", "%02i",
|
||||
entry->id.fields.cpuid);
|
||||
} else {
|
||||
len += zfcp_dbf_view_dump(out_buf + len, NULL,
|
||||
dump->data,
|
||||
dump->size,
|
||||
dump->offset, dump->total_size);
|
||||
if ((dump->offset + dump->size) == dump->total_size)
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
struct fsf_qtcb *qtcb = fsf_req->qtcb;
|
||||
union fsf_prot_status_qual *prot_status_qual =
|
||||
&qtcb->prefix.prot_status_qual;
|
||||
union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual;
|
||||
struct scsi_cmnd *scsi_cmnd;
|
||||
struct zfcp_port *port;
|
||||
struct zfcp_unit *unit;
|
||||
struct zfcp_send_els *send_els;
|
||||
struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
|
||||
struct zfcp_hba_dbf_record_response *response = &rec->type.response;
|
||||
int level;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
|
||||
memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
|
||||
strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE);
|
||||
|
||||
if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
|
||||
(qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
|
||||
strncpy(rec->tag2, "perr", ZFCP_DBF_TAG_SIZE);
|
||||
level = 1;
|
||||
} else if (qtcb->header.fsf_status != FSF_GOOD) {
|
||||
strncpy(rec->tag2, "ferr", ZFCP_DBF_TAG_SIZE);
|
||||
level = 1;
|
||||
} else if ((fsf_req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
|
||||
(fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
|
||||
strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
|
||||
level = 4;
|
||||
} else if ((prot_status_qual->doubleword[0] != 0) ||
|
||||
(prot_status_qual->doubleword[1] != 0) ||
|
||||
(fsf_status_qual->doubleword[0] != 0) ||
|
||||
(fsf_status_qual->doubleword[1] != 0)) {
|
||||
strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
|
||||
level = 3;
|
||||
} else {
|
||||
strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
|
||||
level = 6;
|
||||
}
|
||||
|
||||
response->fsf_command = fsf_req->fsf_command;
|
||||
response->fsf_reqid = (unsigned long)fsf_req;
|
||||
response->fsf_seqno = fsf_req->seq_no;
|
||||
response->fsf_issued = fsf_req->issued;
|
||||
response->fsf_prot_status = qtcb->prefix.prot_status;
|
||||
response->fsf_status = qtcb->header.fsf_status;
|
||||
memcpy(response->fsf_prot_status_qual,
|
||||
prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE);
|
||||
memcpy(response->fsf_status_qual,
|
||||
fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE);
|
||||
response->fsf_req_status = fsf_req->status;
|
||||
response->sbal_first = fsf_req->sbal_first;
|
||||
response->sbal_curr = fsf_req->sbal_curr;
|
||||
response->sbal_last = fsf_req->sbal_last;
|
||||
response->pool = fsf_req->pool != NULL;
|
||||
response->erp_action = (unsigned long)fsf_req->erp_action;
|
||||
|
||||
switch (fsf_req->fsf_command) {
|
||||
case FSF_QTCB_FCP_CMND:
|
||||
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
|
||||
break;
|
||||
scsi_cmnd = (struct scsi_cmnd *)fsf_req->data;
|
||||
if (scsi_cmnd != NULL) {
|
||||
response->data.send_fcp.scsi_cmnd
|
||||
= (unsigned long)scsi_cmnd;
|
||||
response->data.send_fcp.scsi_serial
|
||||
= scsi_cmnd->serial_number;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSF_QTCB_OPEN_PORT_WITH_DID:
|
||||
case FSF_QTCB_CLOSE_PORT:
|
||||
case FSF_QTCB_CLOSE_PHYSICAL_PORT:
|
||||
port = (struct zfcp_port *)fsf_req->data;
|
||||
response->data.port.wwpn = port->wwpn;
|
||||
response->data.port.d_id = port->d_id;
|
||||
response->data.port.port_handle = qtcb->header.port_handle;
|
||||
break;
|
||||
|
||||
case FSF_QTCB_OPEN_LUN:
|
||||
case FSF_QTCB_CLOSE_LUN:
|
||||
unit = (struct zfcp_unit *)fsf_req->data;
|
||||
port = unit->port;
|
||||
response->data.unit.wwpn = port->wwpn;
|
||||
response->data.unit.fcp_lun = unit->fcp_lun;
|
||||
response->data.unit.port_handle = qtcb->header.port_handle;
|
||||
response->data.unit.lun_handle = qtcb->header.lun_handle;
|
||||
break;
|
||||
|
||||
case FSF_QTCB_SEND_ELS:
|
||||
send_els = (struct zfcp_send_els *)fsf_req->data;
|
||||
response->data.send_els.d_id = qtcb->bottom.support.d_id;
|
||||
response->data.send_els.ls_code = send_els->ls_code >> 24;
|
||||
break;
|
||||
|
||||
case FSF_QTCB_ABORT_FCP_CMND:
|
||||
case FSF_QTCB_SEND_GENERIC:
|
||||
case FSF_QTCB_EXCHANGE_CONFIG_DATA:
|
||||
case FSF_QTCB_EXCHANGE_PORT_DATA:
|
||||
case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
|
||||
case FSF_QTCB_UPLOAD_CONTROL_FILE:
|
||||
break;
|
||||
}
|
||||
|
||||
debug_event(adapter->hba_dbf, level,
|
||||
rec, sizeof(struct zfcp_hba_dbf_record));
|
||||
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
|
||||
}
|
||||
|
||||
inline void
|
||||
zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
|
||||
struct fsf_status_read_buffer *status_buffer)
|
||||
{
|
||||
struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
|
||||
memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
|
||||
strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE);
|
||||
strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE);
|
||||
|
||||
rec->type.status.failed = adapter->status_read_failed;
|
||||
if (status_buffer != NULL) {
|
||||
rec->type.status.status_type = status_buffer->status_type;
|
||||
rec->type.status.status_subtype = status_buffer->status_subtype;
|
||||
memcpy(&rec->type.status.queue_designator,
|
||||
&status_buffer->queue_designator,
|
||||
sizeof(struct fsf_queue_designator));
|
||||
|
||||
switch (status_buffer->status_type) {
|
||||
case FSF_STATUS_READ_SENSE_DATA_AVAIL:
|
||||
rec->type.status.payload_size =
|
||||
ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL;
|
||||
break;
|
||||
|
||||
case FSF_STATUS_READ_BIT_ERROR_THRESHOLD:
|
||||
rec->type.status.payload_size =
|
||||
ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD;
|
||||
break;
|
||||
|
||||
case FSF_STATUS_READ_LINK_DOWN:
|
||||
switch (status_buffer->status_subtype) {
|
||||
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK:
|
||||
case FSF_STATUS_READ_SUB_FDISC_FAILED:
|
||||
rec->type.status.payload_size =
|
||||
sizeof(struct fsf_link_down_info);
|
||||
}
|
||||
break;
|
||||
|
||||
case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
|
||||
rec->type.status.payload_size =
|
||||
ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT;
|
||||
break;
|
||||
}
|
||||
memcpy(&rec->type.status.payload,
|
||||
&status_buffer->payload, rec->type.status.payload_size);
|
||||
}
|
||||
|
||||
debug_event(adapter->hba_dbf, 2,
|
||||
rec, sizeof(struct zfcp_hba_dbf_record));
|
||||
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
|
||||
}
|
||||
|
||||
inline void
|
||||
zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
|
||||
unsigned int qdio_error, unsigned int siga_error,
|
||||
int sbal_index, int sbal_count)
|
||||
{
|
||||
struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->hba_dbf_lock, flags);
|
||||
memset(rec, 0, sizeof(struct zfcp_hba_dbf_record));
|
||||
strncpy(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE);
|
||||
rec->type.qdio.status = status;
|
||||
rec->type.qdio.qdio_error = qdio_error;
|
||||
rec->type.qdio.siga_error = siga_error;
|
||||
rec->type.qdio.sbal_index = sbal_index;
|
||||
rec->type.qdio.sbal_count = sbal_count;
|
||||
debug_event(adapter->hba_dbf, 0,
|
||||
rec, sizeof(struct zfcp_hba_dbf_record));
|
||||
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
|
||||
}
|
||||
|
||||
static inline int
|
||||
zfcp_hba_dbf_view_response(char *out_buf,
|
||||
struct zfcp_hba_dbf_record_response *rec)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_command", "0x%08x",
|
||||
rec->fsf_command);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
|
||||
rec->fsf_reqid);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
|
||||
rec->fsf_seqno);
|
||||
len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_prot_status", "0x%08x",
|
||||
rec->fsf_prot_status);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_status", "0x%08x",
|
||||
rec->fsf_status);
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "fsf_prot_status_qual",
|
||||
rec->fsf_prot_status_qual,
|
||||
FSF_PROT_STATUS_QUAL_SIZE,
|
||||
0, FSF_PROT_STATUS_QUAL_SIZE);
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "fsf_status_qual",
|
||||
rec->fsf_status_qual,
|
||||
FSF_STATUS_QUALIFIER_SIZE,
|
||||
0, FSF_STATUS_QUALIFIER_SIZE);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_req_status", "0x%08x",
|
||||
rec->fsf_req_status);
|
||||
len += zfcp_dbf_view(out_buf + len, "sbal_first", "0x%02x",
|
||||
rec->sbal_first);
|
||||
len += zfcp_dbf_view(out_buf + len, "sbal_curr", "0x%02x",
|
||||
rec->sbal_curr);
|
||||
len += zfcp_dbf_view(out_buf + len, "sbal_last", "0x%02x",
|
||||
rec->sbal_last);
|
||||
len += zfcp_dbf_view(out_buf + len, "pool", "0x%02x", rec->pool);
|
||||
|
||||
switch (rec->fsf_command) {
|
||||
case FSF_QTCB_FCP_CMND:
|
||||
if (rec->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
|
||||
break;
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx",
|
||||
rec->data.send_fcp.scsi_cmnd);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx",
|
||||
rec->data.send_fcp.scsi_serial);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_OPEN_PORT_WITH_DID:
|
||||
case FSF_QTCB_CLOSE_PORT:
|
||||
case FSF_QTCB_CLOSE_PHYSICAL_PORT:
|
||||
len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx",
|
||||
rec->data.port.wwpn);
|
||||
len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x",
|
||||
rec->data.port.d_id);
|
||||
len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x",
|
||||
rec->data.port.port_handle);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_OPEN_LUN:
|
||||
case FSF_QTCB_CLOSE_LUN:
|
||||
len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx",
|
||||
rec->data.unit.wwpn);
|
||||
len += zfcp_dbf_view(out_buf + len, "fcp_lun", "0x%016Lx",
|
||||
rec->data.unit.fcp_lun);
|
||||
len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x",
|
||||
rec->data.unit.port_handle);
|
||||
len += zfcp_dbf_view(out_buf + len, "lun_handle", "0x%08x",
|
||||
rec->data.unit.lun_handle);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_SEND_ELS:
|
||||
len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x",
|
||||
rec->data.send_els.d_id);
|
||||
len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x",
|
||||
rec->data.send_els.ls_code);
|
||||
break;
|
||||
|
||||
case FSF_QTCB_ABORT_FCP_CMND:
|
||||
case FSF_QTCB_SEND_GENERIC:
|
||||
case FSF_QTCB_EXCHANGE_CONFIG_DATA:
|
||||
case FSF_QTCB_EXCHANGE_PORT_DATA:
|
||||
case FSF_QTCB_DOWNLOAD_CONTROL_FILE:
|
||||
case FSF_QTCB_UPLOAD_CONTROL_FILE:
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += zfcp_dbf_view(out_buf + len, "failed", "0x%02x", rec->failed);
|
||||
len += zfcp_dbf_view(out_buf + len, "status_type", "0x%08x",
|
||||
rec->status_type);
|
||||
len += zfcp_dbf_view(out_buf + len, "status_subtype", "0x%08x",
|
||||
rec->status_subtype);
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "queue_designator",
|
||||
(char *)&rec->queue_designator,
|
||||
sizeof(struct fsf_queue_designator),
|
||||
0, sizeof(struct fsf_queue_designator));
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "payload",
|
||||
(char *)&rec->payload,
|
||||
rec->payload_size, 0, rec->payload_size);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += zfcp_dbf_view(out_buf + len, "status", "0x%08x", rec->status);
|
||||
len += zfcp_dbf_view(out_buf + len, "qdio_error", "0x%08x",
|
||||
rec->qdio_error);
|
||||
len += zfcp_dbf_view(out_buf + len, "siga_error", "0x%08x",
|
||||
rec->siga_error);
|
||||
len += zfcp_dbf_view(out_buf + len, "sbal_index", "0x%02x",
|
||||
rec->sbal_index);
|
||||
len += zfcp_dbf_view(out_buf + len, "sbal_count", "0x%02x",
|
||||
rec->sbal_count);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
|
||||
char *out_buf, const char *in_buf)
|
||||
{
|
||||
struct zfcp_hba_dbf_record *rec = (struct zfcp_hba_dbf_record *)in_buf;
|
||||
int len = 0;
|
||||
|
||||
if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
return 0;
|
||||
|
||||
len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
|
||||
if (isalpha(rec->tag2[0]))
|
||||
len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2);
|
||||
if (strncmp(rec->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
len += zfcp_hba_dbf_view_response(out_buf + len,
|
||||
&rec->type.response);
|
||||
else if (strncmp(rec->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
len += zfcp_hba_dbf_view_status(out_buf + len,
|
||||
&rec->type.status);
|
||||
else if (strncmp(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
len += zfcp_hba_dbf_view_qdio(out_buf + len, &rec->type.qdio);
|
||||
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct debug_view zfcp_hba_dbf_view = {
|
||||
"structured",
|
||||
NULL,
|
||||
&zfcp_dbf_view_header,
|
||||
&zfcp_hba_dbf_view_format,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
inline void
|
||||
_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
|
||||
u32 s_id, u32 d_id, void *buffer, int buflen)
|
||||
{
|
||||
struct zfcp_send_ct *send_ct = (struct zfcp_send_ct *)fsf_req->data;
|
||||
struct zfcp_port *port = send_ct->port;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
struct ct_hdr *header = (struct ct_hdr *)buffer;
|
||||
struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf;
|
||||
struct zfcp_san_dbf_record_ct *ct = &rec->type.ct;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&adapter->san_dbf_lock, flags);
|
||||
memset(rec, 0, sizeof(struct zfcp_san_dbf_record));
|
||||
strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
|
||||
rec->fsf_reqid = (unsigned long)fsf_req;
|
||||
rec->fsf_seqno = fsf_req->seq_no;
|
||||
rec->s_id = s_id;
|
||||
rec->d_id = d_id;
|
||||
if (strncmp(tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
ct->type.request.cmd_req_code = header->cmd_rsp_code;
|
||||
ct->type.request.revision = header->revision;
|
||||
ct->type.request.gs_type = header->gs_type;
|
||||
ct->type.request.gs_subtype = header->gs_subtype;
|
||||
ct->type.request.options = header->options;
|
||||
ct->type.request.max_res_size = header->max_res_size;
|
||||
} else if (strncmp(tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
ct->type.response.cmd_rsp_code = header->cmd_rsp_code;
|
||||
ct->type.response.revision = header->revision;
|
||||
ct->type.response.reason_code = header->reason_code;
|
||||
ct->type.response.reason_code_expl = header->reason_code_expl;
|
||||
ct->type.response.vendor_unique = header->vendor_unique;
|
||||
}
|
||||
ct->payload_size =
|
||||
min(buflen - (int)sizeof(struct ct_hdr), ZFCP_DBF_CT_PAYLOAD);
|
||||
memcpy(ct->payload, buffer + sizeof(struct ct_hdr), ct->payload_size);
|
||||
debug_event(adapter->san_dbf, 3,
|
||||
rec, sizeof(struct zfcp_san_dbf_record));
|
||||
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
|
||||
}
|
||||
|
||||
inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
|
||||
struct zfcp_port *port = ct->port;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
|
||||
_zfcp_san_dbf_event_common_ct("octc", fsf_req,
|
||||
fc_host_port_id(adapter->scsi_host),
|
||||
port->d_id, zfcp_sg_to_address(ct->req),
|
||||
ct->req->length);
|
||||
}
|
||||
|
||||
inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
|
||||
struct zfcp_port *port = ct->port;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
|
||||
_zfcp_san_dbf_event_common_ct("rctc", fsf_req, port->d_id,
|
||||
fc_host_port_id(adapter->scsi_host),
|
||||
zfcp_sg_to_address(ct->resp),
|
||||
ct->resp->length);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_zfcp_san_dbf_event_common_els(const char *tag, int level,
|
||||
struct zfcp_fsf_req *fsf_req, u32 s_id,
|
||||
u32 d_id, u8 ls_code, void *buffer, int buflen)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf;
|
||||
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
|
||||
unsigned long flags;
|
||||
int offset = 0;
|
||||
|
||||
spin_lock_irqsave(&adapter->san_dbf_lock, flags);
|
||||
do {
|
||||
memset(rec, 0, sizeof(struct zfcp_san_dbf_record));
|
||||
if (offset == 0) {
|
||||
strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
|
||||
rec->fsf_reqid = (unsigned long)fsf_req;
|
||||
rec->fsf_seqno = fsf_req->seq_no;
|
||||
rec->s_id = s_id;
|
||||
rec->d_id = d_id;
|
||||
rec->type.els.ls_code = ls_code;
|
||||
buflen = min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD);
|
||||
rec->type.els.payload_size = buflen;
|
||||
memcpy(rec->type.els.payload,
|
||||
buffer, min(buflen, ZFCP_DBF_ELS_PAYLOAD));
|
||||
offset += min(buflen, ZFCP_DBF_ELS_PAYLOAD);
|
||||
} else {
|
||||
strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
|
||||
dump->total_size = buflen;
|
||||
dump->offset = offset;
|
||||
dump->size = min(buflen - offset,
|
||||
(int)sizeof(struct zfcp_san_dbf_record)
|
||||
- (int)sizeof(struct zfcp_dbf_dump));
|
||||
memcpy(dump->data, buffer + offset, dump->size);
|
||||
offset += dump->size;
|
||||
}
|
||||
debug_event(adapter->san_dbf, level,
|
||||
rec, sizeof(struct zfcp_san_dbf_record));
|
||||
} while (offset < buflen);
|
||||
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
|
||||
}
|
||||
|
||||
inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
|
||||
|
||||
_zfcp_san_dbf_event_common_els("oels", 2, fsf_req,
|
||||
fc_host_port_id(els->adapter->scsi_host),
|
||||
els->d_id,
|
||||
*(u8 *) zfcp_sg_to_address(els->req),
|
||||
zfcp_sg_to_address(els->req),
|
||||
els->req->length);
|
||||
}
|
||||
|
||||
inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
|
||||
|
||||
_zfcp_san_dbf_event_common_els("rels", 2, fsf_req, els->d_id,
|
||||
fc_host_port_id(els->adapter->scsi_host),
|
||||
*(u8 *) zfcp_sg_to_address(els->req),
|
||||
zfcp_sg_to_address(els->resp),
|
||||
els->resp->length);
|
||||
}
|
||||
|
||||
inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
|
||||
{
|
||||
struct zfcp_adapter *adapter = fsf_req->adapter;
|
||||
struct fsf_status_read_buffer *status_buffer =
|
||||
(struct fsf_status_read_buffer *)fsf_req->data;
|
||||
int length = (int)status_buffer->length -
|
||||
(int)((void *)&status_buffer->payload - (void *)status_buffer);
|
||||
|
||||
_zfcp_san_dbf_event_common_els("iels", 1, fsf_req, status_buffer->d_id,
|
||||
fc_host_port_id(adapter->scsi_host),
|
||||
*(u8 *) status_buffer->payload,
|
||||
(void *)status_buffer->payload, length);
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
|
||||
char *out_buf, const char *in_buf)
|
||||
{
|
||||
struct zfcp_san_dbf_record *rec = (struct zfcp_san_dbf_record *)in_buf;
|
||||
char *buffer = NULL;
|
||||
int buflen = 0, total = 0;
|
||||
int len = 0;
|
||||
|
||||
if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
return 0;
|
||||
|
||||
len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
|
||||
rec->fsf_reqid);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
|
||||
rec->fsf_seqno);
|
||||
len += zfcp_dbf_view(out_buf + len, "s_id", "0x%06x", rec->s_id);
|
||||
len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x", rec->d_id);
|
||||
|
||||
if (strncmp(rec->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
len += zfcp_dbf_view(out_buf + len, "cmd_req_code", "0x%04x",
|
||||
rec->type.ct.type.request.cmd_req_code);
|
||||
len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x",
|
||||
rec->type.ct.type.request.revision);
|
||||
len += zfcp_dbf_view(out_buf + len, "gs_type", "0x%02x",
|
||||
rec->type.ct.type.request.gs_type);
|
||||
len += zfcp_dbf_view(out_buf + len, "gs_subtype", "0x%02x",
|
||||
rec->type.ct.type.request.gs_subtype);
|
||||
len += zfcp_dbf_view(out_buf + len, "options", "0x%02x",
|
||||
rec->type.ct.type.request.options);
|
||||
len += zfcp_dbf_view(out_buf + len, "max_res_size", "0x%04x",
|
||||
rec->type.ct.type.request.max_res_size);
|
||||
total = rec->type.ct.payload_size;
|
||||
buffer = rec->type.ct.payload;
|
||||
buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
|
||||
} else if (strncmp(rec->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
len += zfcp_dbf_view(out_buf + len, "cmd_rsp_code", "0x%04x",
|
||||
rec->type.ct.type.response.cmd_rsp_code);
|
||||
len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x",
|
||||
rec->type.ct.type.response.revision);
|
||||
len += zfcp_dbf_view(out_buf + len, "reason_code", "0x%02x",
|
||||
rec->type.ct.type.response.reason_code);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "reason_code_expl", "0x%02x",
|
||||
rec->type.ct.type.response.reason_code_expl);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "vendor_unique", "0x%02x",
|
||||
rec->type.ct.type.response.vendor_unique);
|
||||
total = rec->type.ct.payload_size;
|
||||
buffer = rec->type.ct.payload;
|
||||
buflen = min(total, ZFCP_DBF_CT_PAYLOAD);
|
||||
} else if (strncmp(rec->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
|
||||
strncmp(rec->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
|
||||
strncmp(rec->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x",
|
||||
rec->type.els.ls_code);
|
||||
total = rec->type.els.payload_size;
|
||||
buffer = rec->type.els.payload;
|
||||
buflen = min(total, ZFCP_DBF_ELS_PAYLOAD);
|
||||
}
|
||||
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "payload",
|
||||
buffer, buflen, 0, total);
|
||||
|
||||
if (buflen == total)
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct debug_view zfcp_san_dbf_view = {
|
||||
"structured",
|
||||
NULL,
|
||||
&zfcp_dbf_view_header,
|
||||
&zfcp_san_dbf_view_format,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static inline void
|
||||
_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
|
||||
struct zfcp_adapter *adapter,
|
||||
struct scsi_cmnd *scsi_cmnd,
|
||||
struct zfcp_fsf_req *new_fsf_req)
|
||||
{
|
||||
struct zfcp_fsf_req *fsf_req =
|
||||
(struct zfcp_fsf_req *)scsi_cmnd->host_scribble;
|
||||
struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf;
|
||||
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
|
||||
unsigned long flags;
|
||||
struct fcp_rsp_iu *fcp_rsp;
|
||||
char *fcp_rsp_info = NULL, *fcp_sns_info = NULL;
|
||||
int offset = 0, buflen = 0;
|
||||
|
||||
spin_lock_irqsave(&adapter->scsi_dbf_lock, flags);
|
||||
do {
|
||||
memset(rec, 0, sizeof(struct zfcp_scsi_dbf_record));
|
||||
if (offset == 0) {
|
||||
strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE);
|
||||
strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE);
|
||||
if (scsi_cmnd->device) {
|
||||
rec->scsi_id = scsi_cmnd->device->id;
|
||||
rec->scsi_lun = scsi_cmnd->device->lun;
|
||||
}
|
||||
rec->scsi_result = scsi_cmnd->result;
|
||||
rec->scsi_cmnd = (unsigned long)scsi_cmnd;
|
||||
rec->scsi_serial = scsi_cmnd->serial_number;
|
||||
memcpy(rec->scsi_opcode,
|
||||
&scsi_cmnd->cmnd,
|
||||
min((int)scsi_cmnd->cmd_len,
|
||||
ZFCP_DBF_SCSI_OPCODE));
|
||||
rec->scsi_retries = scsi_cmnd->retries;
|
||||
rec->scsi_allowed = scsi_cmnd->allowed;
|
||||
if (fsf_req != NULL) {
|
||||
fcp_rsp = (struct fcp_rsp_iu *)
|
||||
&(fsf_req->qtcb->bottom.io.fcp_rsp);
|
||||
fcp_rsp_info =
|
||||
zfcp_get_fcp_rsp_info_ptr(fcp_rsp);
|
||||
fcp_sns_info =
|
||||
zfcp_get_fcp_sns_info_ptr(fcp_rsp);
|
||||
|
||||
rec->type.fcp.rsp_validity =
|
||||
fcp_rsp->validity.value;
|
||||
rec->type.fcp.rsp_scsi_status =
|
||||
fcp_rsp->scsi_status;
|
||||
rec->type.fcp.rsp_resid = fcp_rsp->fcp_resid;
|
||||
if (fcp_rsp->validity.bits.fcp_rsp_len_valid)
|
||||
rec->type.fcp.rsp_code =
|
||||
*(fcp_rsp_info + 3);
|
||||
if (fcp_rsp->validity.bits.fcp_sns_len_valid) {
|
||||
buflen = min((int)fcp_rsp->fcp_sns_len,
|
||||
ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO);
|
||||
rec->type.fcp.sns_info_len = buflen;
|
||||
memcpy(rec->type.fcp.sns_info,
|
||||
fcp_sns_info,
|
||||
min(buflen,
|
||||
ZFCP_DBF_SCSI_FCP_SNS_INFO));
|
||||
offset += min(buflen,
|
||||
ZFCP_DBF_SCSI_FCP_SNS_INFO);
|
||||
}
|
||||
|
||||
rec->fsf_reqid = (unsigned long)fsf_req;
|
||||
rec->fsf_seqno = fsf_req->seq_no;
|
||||
rec->fsf_issued = fsf_req->issued;
|
||||
}
|
||||
if (new_fsf_req != NULL) {
|
||||
rec->type.new_fsf_req.fsf_reqid =
|
||||
(unsigned long)
|
||||
new_fsf_req;
|
||||
rec->type.new_fsf_req.fsf_seqno =
|
||||
new_fsf_req->seq_no;
|
||||
rec->type.new_fsf_req.fsf_issued =
|
||||
new_fsf_req->issued;
|
||||
}
|
||||
} else {
|
||||
strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
|
||||
dump->total_size = buflen;
|
||||
dump->offset = offset;
|
||||
dump->size = min(buflen - offset,
|
||||
(int)sizeof(struct
|
||||
zfcp_scsi_dbf_record) -
|
||||
(int)sizeof(struct zfcp_dbf_dump));
|
||||
memcpy(dump->data, fcp_sns_info + offset, dump->size);
|
||||
offset += dump->size;
|
||||
}
|
||||
debug_event(adapter->scsi_dbf, level,
|
||||
rec, sizeof(struct zfcp_scsi_dbf_record));
|
||||
} while (offset < buflen);
|
||||
spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
|
||||
}
|
||||
|
||||
inline void
|
||||
zfcp_scsi_dbf_event_result(const char *tag, int level,
|
||||
struct zfcp_adapter *adapter,
|
||||
struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
_zfcp_scsi_dbf_event_common("rslt",
|
||||
tag, level, adapter, scsi_cmnd, NULL);
|
||||
}
|
||||
|
||||
inline void
|
||||
zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
|
||||
struct scsi_cmnd *scsi_cmnd,
|
||||
struct zfcp_fsf_req *new_fsf_req)
|
||||
{
|
||||
_zfcp_scsi_dbf_event_common("abrt",
|
||||
tag, 1, adapter, scsi_cmnd, new_fsf_req);
|
||||
}
|
||||
|
||||
inline void
|
||||
zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
|
||||
struct scsi_cmnd *scsi_cmnd)
|
||||
{
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
_zfcp_scsi_dbf_event_common(flag == FCP_TARGET_RESET ? "trst" : "lrst",
|
||||
tag, 1, adapter, scsi_cmnd, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
|
||||
char *out_buf, const char *in_buf)
|
||||
{
|
||||
struct zfcp_scsi_dbf_record *rec =
|
||||
(struct zfcp_scsi_dbf_record *)in_buf;
|
||||
int len = 0;
|
||||
|
||||
if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0)
|
||||
return 0;
|
||||
|
||||
len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag);
|
||||
len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_id", "0x%08x", rec->scsi_id);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_lun", "0x%08x",
|
||||
rec->scsi_lun);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_result", "0x%08x",
|
||||
rec->scsi_result);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx",
|
||||
rec->scsi_cmnd);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx",
|
||||
rec->scsi_serial);
|
||||
len += zfcp_dbf_view_dump(out_buf + len, "scsi_opcode",
|
||||
rec->scsi_opcode,
|
||||
ZFCP_DBF_SCSI_OPCODE,
|
||||
0, ZFCP_DBF_SCSI_OPCODE);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_retries", "0x%02x",
|
||||
rec->scsi_retries);
|
||||
len += zfcp_dbf_view(out_buf + len, "scsi_allowed", "0x%02x",
|
||||
rec->scsi_allowed);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx",
|
||||
rec->fsf_reqid);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x",
|
||||
rec->fsf_seqno);
|
||||
len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued);
|
||||
if (strncmp(rec->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "fcp_rsp_validity", "0x%02x",
|
||||
rec->type.fcp.rsp_validity);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "fcp_rsp_scsi_status",
|
||||
"0x%02x", rec->type.fcp.rsp_scsi_status);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "fcp_rsp_resid", "0x%08x",
|
||||
rec->type.fcp.rsp_resid);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "fcp_rsp_code", "0x%08x",
|
||||
rec->type.fcp.rsp_code);
|
||||
len +=
|
||||
zfcp_dbf_view(out_buf + len, "fcp_sns_info_len", "0x%08x",
|
||||
rec->type.fcp.sns_info_len);
|
||||
len +=
|
||||
zfcp_dbf_view_dump(out_buf + len, "fcp_sns_info",
|
||||
rec->type.fcp.sns_info,
|
||||
min((int)rec->type.fcp.sns_info_len,
|
||||
ZFCP_DBF_SCSI_FCP_SNS_INFO), 0,
|
||||
rec->type.fcp.sns_info_len);
|
||||
} else if (strncmp(rec->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_reqid_abort", "0x%0Lx",
|
||||
rec->type.new_fsf_req.fsf_reqid);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_seqno_abort", "0x%08x",
|
||||
rec->type.new_fsf_req.fsf_seqno);
|
||||
len += zfcp_dbf_stck(out_buf + len, "fsf_issued",
|
||||
rec->type.new_fsf_req.fsf_issued);
|
||||
} else if ((strncmp(rec->tag, "trst", ZFCP_DBF_TAG_SIZE) == 0) ||
|
||||
(strncmp(rec->tag, "lrst", ZFCP_DBF_TAG_SIZE) == 0)) {
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_reqid_reset", "0x%0Lx",
|
||||
rec->type.new_fsf_req.fsf_reqid);
|
||||
len += zfcp_dbf_view(out_buf + len, "fsf_seqno_reset", "0x%08x",
|
||||
rec->type.new_fsf_req.fsf_seqno);
|
||||
len += zfcp_dbf_stck(out_buf + len, "fsf_issued",
|
||||
rec->type.new_fsf_req.fsf_issued);
|
||||
}
|
||||
|
||||
len += sprintf(out_buf + len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct debug_view zfcp_scsi_dbf_view = {
|
||||
"structured",
|
||||
NULL,
|
||||
&zfcp_dbf_view_header,
|
||||
&zfcp_scsi_dbf_view_format,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* zfcp_adapter_debug_register - registers debug feature for an adapter
|
||||
* @adapter: pointer to adapter for which debug features should be registered
|
||||
* return: -ENOMEM on error, 0 otherwise
|
||||
*/
|
||||
int zfcp_adapter_debug_register(struct zfcp_adapter *adapter)
|
||||
{
|
||||
char dbf_name[DEBUG_MAX_NAME_LEN];
|
||||
|
||||
/* debug feature area which records recovery activity */
|
||||
spin_lock_init(&adapter->erp_dbf_lock);
|
||||
sprintf(dbf_name, "zfcp_%s_erp", zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->erp_dbf = debug_register(dbf_name, dbfsize, 2,
|
||||
sizeof(struct zfcp_erp_dbf_record));
|
||||
if (!adapter->erp_dbf)
|
||||
goto failed;
|
||||
debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
|
||||
debug_set_level(adapter->erp_dbf, 3);
|
||||
|
||||
/* debug feature area which records HBA (FSF and QDIO) conditions */
|
||||
spin_lock_init(&adapter->hba_dbf_lock);
|
||||
sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1,
|
||||
sizeof(struct zfcp_hba_dbf_record));
|
||||
if (!adapter->hba_dbf)
|
||||
goto failed;
|
||||
debug_register_view(adapter->hba_dbf, &debug_hex_ascii_view);
|
||||
debug_register_view(adapter->hba_dbf, &zfcp_hba_dbf_view);
|
||||
debug_set_level(adapter->hba_dbf, 3);
|
||||
|
||||
/* debug feature area which records SAN command failures and recovery */
|
||||
spin_lock_init(&adapter->san_dbf_lock);
|
||||
sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->san_dbf = debug_register(dbf_name, dbfsize, 1,
|
||||
sizeof(struct zfcp_san_dbf_record));
|
||||
if (!adapter->san_dbf)
|
||||
goto failed;
|
||||
debug_register_view(adapter->san_dbf, &debug_hex_ascii_view);
|
||||
debug_register_view(adapter->san_dbf, &zfcp_san_dbf_view);
|
||||
debug_set_level(adapter->san_dbf, 6);
|
||||
|
||||
/* debug feature area which records SCSI command failures and recovery */
|
||||
spin_lock_init(&adapter->scsi_dbf_lock);
|
||||
sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter));
|
||||
adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1,
|
||||
sizeof(struct zfcp_scsi_dbf_record));
|
||||
if (!adapter->scsi_dbf)
|
||||
goto failed;
|
||||
debug_register_view(adapter->scsi_dbf, &debug_hex_ascii_view);
|
||||
debug_register_view(adapter->scsi_dbf, &zfcp_scsi_dbf_view);
|
||||
debug_set_level(adapter->scsi_dbf, 3);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
zfcp_adapter_debug_unregister(adapter);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
|
||||
* @adapter: pointer to adapter for which debug features should be unregistered
|
||||
*/
|
||||
void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter)
|
||||
{
|
||||
debug_unregister(adapter->scsi_dbf);
|
||||
debug_unregister(adapter->san_dbf);
|
||||
debug_unregister(adapter->hba_dbf);
|
||||
debug_unregister(adapter->erp_dbf);
|
||||
adapter->scsi_dbf = NULL;
|
||||
adapter->san_dbf = NULL;
|
||||
adapter->hba_dbf = NULL;
|
||||
adapter->erp_dbf = NULL;
|
||||
}
|
||||
|
||||
#undef ZFCP_LOG_AREA
|
@ -66,7 +66,7 @@
|
||||
/********************* GENERAL DEFINES *********************************/
|
||||
|
||||
/* zfcp version number, it consists of major, minor, and patch-level number */
|
||||
#define ZFCP_VERSION "4.3.0"
|
||||
#define ZFCP_VERSION "4.5.0"
|
||||
|
||||
/**
|
||||
* zfcp_sg_to_address - determine kernel address from struct scatterlist
|
||||
@ -154,13 +154,17 @@ typedef u32 scsi_lun_t;
|
||||
#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 100
|
||||
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7
|
||||
|
||||
/* Retry 5 times every 2 second, then every minute */
|
||||
#define ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES 5
|
||||
#define ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP 200
|
||||
#define ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP 6000
|
||||
|
||||
/* timeout value for "default timer" for fsf requests */
|
||||
#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ);
|
||||
|
||||
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
|
||||
|
||||
typedef unsigned long long wwn_t;
|
||||
typedef unsigned int fc_id_t;
|
||||
typedef unsigned long long fcp_lun_t;
|
||||
/* data length field may be at variable position in FCP-2 FCP_CMND IU */
|
||||
typedef unsigned int fcp_dl_t;
|
||||
@ -280,6 +284,171 @@ struct fcp_logo {
|
||||
wwn_t nport_wwpn;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* DBF stuff
|
||||
*/
|
||||
#define ZFCP_DBF_TAG_SIZE 4
|
||||
|
||||
struct zfcp_dbf_dump {
|
||||
u8 tag[ZFCP_DBF_TAG_SIZE];
|
||||
u32 total_size; /* size of total dump data */
|
||||
u32 offset; /* how much data has being already dumped */
|
||||
u32 size; /* how much data comes with this record */
|
||||
u8 data[]; /* dump data */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* FIXME: to be inflated when reworking the erp dbf */
|
||||
struct zfcp_erp_dbf_record {
|
||||
u8 dummy[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_hba_dbf_record_response {
|
||||
u32 fsf_command;
|
||||
u64 fsf_reqid;
|
||||
u32 fsf_seqno;
|
||||
u64 fsf_issued;
|
||||
u32 fsf_prot_status;
|
||||
u32 fsf_status;
|
||||
u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE];
|
||||
u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
|
||||
u32 fsf_req_status;
|
||||
u8 sbal_first;
|
||||
u8 sbal_curr;
|
||||
u8 sbal_last;
|
||||
u8 pool;
|
||||
u64 erp_action;
|
||||
union {
|
||||
struct {
|
||||
u64 scsi_cmnd;
|
||||
u64 scsi_serial;
|
||||
} send_fcp;
|
||||
struct {
|
||||
u64 wwpn;
|
||||
u32 d_id;
|
||||
u32 port_handle;
|
||||
} port;
|
||||
struct {
|
||||
u64 wwpn;
|
||||
u64 fcp_lun;
|
||||
u32 port_handle;
|
||||
u32 lun_handle;
|
||||
} unit;
|
||||
struct {
|
||||
u32 d_id;
|
||||
u8 ls_code;
|
||||
} send_els;
|
||||
} data;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_hba_dbf_record_status {
|
||||
u8 failed;
|
||||
u32 status_type;
|
||||
u32 status_subtype;
|
||||
struct fsf_queue_designator
|
||||
queue_designator;
|
||||
u32 payload_size;
|
||||
#define ZFCP_DBF_UNSOL_PAYLOAD 80
|
||||
#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32
|
||||
#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56
|
||||
#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32)
|
||||
u8 payload[ZFCP_DBF_UNSOL_PAYLOAD];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_hba_dbf_record_qdio {
|
||||
u32 status;
|
||||
u32 qdio_error;
|
||||
u32 siga_error;
|
||||
u8 sbal_index;
|
||||
u8 sbal_count;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_hba_dbf_record {
|
||||
u8 tag[ZFCP_DBF_TAG_SIZE];
|
||||
u8 tag2[ZFCP_DBF_TAG_SIZE];
|
||||
union {
|
||||
struct zfcp_hba_dbf_record_response response;
|
||||
struct zfcp_hba_dbf_record_status status;
|
||||
struct zfcp_hba_dbf_record_qdio qdio;
|
||||
} type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_san_dbf_record_ct {
|
||||
union {
|
||||
struct {
|
||||
u16 cmd_req_code;
|
||||
u8 revision;
|
||||
u8 gs_type;
|
||||
u8 gs_subtype;
|
||||
u8 options;
|
||||
u16 max_res_size;
|
||||
} request;
|
||||
struct {
|
||||
u16 cmd_rsp_code;
|
||||
u8 revision;
|
||||
u8 reason_code;
|
||||
u8 reason_code_expl;
|
||||
u8 vendor_unique;
|
||||
} response;
|
||||
} type;
|
||||
u32 payload_size;
|
||||
#define ZFCP_DBF_CT_PAYLOAD 24
|
||||
u8 payload[ZFCP_DBF_CT_PAYLOAD];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_san_dbf_record_els {
|
||||
u8 ls_code;
|
||||
u32 payload_size;
|
||||
#define ZFCP_DBF_ELS_PAYLOAD 32
|
||||
#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024
|
||||
u8 payload[ZFCP_DBF_ELS_PAYLOAD];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_san_dbf_record {
|
||||
u8 tag[ZFCP_DBF_TAG_SIZE];
|
||||
u64 fsf_reqid;
|
||||
u32 fsf_seqno;
|
||||
u32 s_id;
|
||||
u32 d_id;
|
||||
union {
|
||||
struct zfcp_san_dbf_record_ct ct;
|
||||
struct zfcp_san_dbf_record_els els;
|
||||
} type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct zfcp_scsi_dbf_record {
|
||||
u8 tag[ZFCP_DBF_TAG_SIZE];
|
||||
u8 tag2[ZFCP_DBF_TAG_SIZE];
|
||||
u32 scsi_id;
|
||||
u32 scsi_lun;
|
||||
u32 scsi_result;
|
||||
u64 scsi_cmnd;
|
||||
u64 scsi_serial;
|
||||
#define ZFCP_DBF_SCSI_OPCODE 16
|
||||
u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE];
|
||||
u8 scsi_retries;
|
||||
u8 scsi_allowed;
|
||||
u64 fsf_reqid;
|
||||
u32 fsf_seqno;
|
||||
u64 fsf_issued;
|
||||
union {
|
||||
struct {
|
||||
u64 fsf_reqid;
|
||||
u32 fsf_seqno;
|
||||
u64 fsf_issued;
|
||||
} new_fsf_req;
|
||||
struct {
|
||||
u8 rsp_validity;
|
||||
u8 rsp_scsi_status;
|
||||
u32 rsp_resid;
|
||||
u8 rsp_code;
|
||||
#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16
|
||||
#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256
|
||||
u32 sns_info_len;
|
||||
u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO];
|
||||
} fcp;
|
||||
} type;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* FC-FS stuff
|
||||
*/
|
||||
@ -339,34 +508,6 @@ struct zfcp_rc_entry {
|
||||
*/
|
||||
#define ZFCP_CT_TIMEOUT (3 * R_A_TOV)
|
||||
|
||||
|
||||
/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/
|
||||
|
||||
/* debug feature entries per adapter */
|
||||
#define ZFCP_ERP_DBF_INDEX 1
|
||||
#define ZFCP_ERP_DBF_AREAS 2
|
||||
#define ZFCP_ERP_DBF_LENGTH 16
|
||||
#define ZFCP_ERP_DBF_LEVEL 3
|
||||
#define ZFCP_ERP_DBF_NAME "zfcperp"
|
||||
|
||||
#define ZFCP_CMD_DBF_INDEX 2
|
||||
#define ZFCP_CMD_DBF_AREAS 1
|
||||
#define ZFCP_CMD_DBF_LENGTH 8
|
||||
#define ZFCP_CMD_DBF_LEVEL 3
|
||||
#define ZFCP_CMD_DBF_NAME "zfcpcmd"
|
||||
|
||||
#define ZFCP_ABORT_DBF_INDEX 2
|
||||
#define ZFCP_ABORT_DBF_AREAS 1
|
||||
#define ZFCP_ABORT_DBF_LENGTH 8
|
||||
#define ZFCP_ABORT_DBF_LEVEL 6
|
||||
#define ZFCP_ABORT_DBF_NAME "zfcpabt"
|
||||
|
||||
#define ZFCP_IN_ELS_DBF_INDEX 2
|
||||
#define ZFCP_IN_ELS_DBF_AREAS 1
|
||||
#define ZFCP_IN_ELS_DBF_LENGTH 8
|
||||
#define ZFCP_IN_ELS_DBF_LEVEL 6
|
||||
#define ZFCP_IN_ELS_DBF_NAME "zfcpels"
|
||||
|
||||
/******************** LOGGING MACROS AND DEFINES *****************************/
|
||||
|
||||
/*
|
||||
@ -501,6 +642,7 @@ do { \
|
||||
#define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080
|
||||
#define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100
|
||||
#define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200
|
||||
#define ZFCP_STATUS_ADAPTER_XPORT_OK 0x00000800
|
||||
|
||||
#define ZFCP_STATUS_ADAPTER_SCSI_UP \
|
||||
(ZFCP_STATUS_COMMON_UNBLOCKED | \
|
||||
@ -635,45 +777,6 @@ struct zfcp_adapter_mempool {
|
||||
mempool_t *data_gid_pn;
|
||||
};
|
||||
|
||||
struct zfcp_exchange_config_data{
|
||||
};
|
||||
|
||||
struct zfcp_open_port {
|
||||
struct zfcp_port *port;
|
||||
};
|
||||
|
||||
struct zfcp_close_port {
|
||||
struct zfcp_port *port;
|
||||
};
|
||||
|
||||
struct zfcp_open_unit {
|
||||
struct zfcp_unit *unit;
|
||||
};
|
||||
|
||||
struct zfcp_close_unit {
|
||||
struct zfcp_unit *unit;
|
||||
};
|
||||
|
||||
struct zfcp_close_physical_port {
|
||||
struct zfcp_port *port;
|
||||
};
|
||||
|
||||
struct zfcp_send_fcp_command_task {
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
struct zfcp_unit *unit;
|
||||
struct scsi_cmnd *scsi_cmnd;
|
||||
unsigned long start_jiffies;
|
||||
};
|
||||
|
||||
struct zfcp_send_fcp_command_task_management {
|
||||
struct zfcp_unit *unit;
|
||||
};
|
||||
|
||||
struct zfcp_abort_fcp_command {
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
struct zfcp_unit *unit;
|
||||
};
|
||||
|
||||
/*
|
||||
* header for CT_IU
|
||||
*/
|
||||
@ -702,7 +805,7 @@ struct ct_iu_gid_pn_req {
|
||||
/* FS_ACC IU and data unit for GID_PN nameserver request */
|
||||
struct ct_iu_gid_pn_resp {
|
||||
struct ct_hdr header;
|
||||
fc_id_t d_id;
|
||||
u32 d_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef void (*zfcp_send_ct_handler_t)(unsigned long);
|
||||
@ -768,7 +871,7 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long);
|
||||
struct zfcp_send_els {
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_port *port;
|
||||
fc_id_t d_id;
|
||||
u32 d_id;
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
unsigned int req_count;
|
||||
@ -781,33 +884,6 @@ struct zfcp_send_els {
|
||||
int status;
|
||||
};
|
||||
|
||||
struct zfcp_status_read {
|
||||
struct fsf_status_read_buffer *buffer;
|
||||
};
|
||||
|
||||
struct zfcp_fsf_done {
|
||||
struct completion *complete;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* request specific data */
|
||||
union zfcp_req_data {
|
||||
struct zfcp_exchange_config_data exchange_config_data;
|
||||
struct zfcp_open_port open_port;
|
||||
struct zfcp_close_port close_port;
|
||||
struct zfcp_open_unit open_unit;
|
||||
struct zfcp_close_unit close_unit;
|
||||
struct zfcp_close_physical_port close_physical_port;
|
||||
struct zfcp_send_fcp_command_task send_fcp_command_task;
|
||||
struct zfcp_send_fcp_command_task_management
|
||||
send_fcp_command_task_management;
|
||||
struct zfcp_abort_fcp_command abort_fcp_command;
|
||||
struct zfcp_send_ct *send_ct;
|
||||
struct zfcp_send_els *send_els;
|
||||
struct zfcp_status_read status_read;
|
||||
struct fsf_qtcb_bottom_port *port_data;
|
||||
};
|
||||
|
||||
struct zfcp_qdio_queue {
|
||||
struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */
|
||||
u8 free_index; /* index of next free bfr
|
||||
@ -838,21 +914,19 @@ struct zfcp_adapter {
|
||||
atomic_t refcount; /* reference count */
|
||||
wait_queue_head_t remove_wq; /* can be used to wait for
|
||||
refcount drop to zero */
|
||||
wwn_t wwnn; /* WWNN */
|
||||
wwn_t wwpn; /* WWPN */
|
||||
fc_id_t s_id; /* N_Port ID */
|
||||
wwn_t peer_wwnn; /* P2P peer WWNN */
|
||||
wwn_t peer_wwpn; /* P2P peer WWPN */
|
||||
fc_id_t peer_d_id; /* P2P peer D_ID */
|
||||
u32 peer_d_id; /* P2P peer D_ID */
|
||||
wwn_t physical_wwpn; /* WWPN of physical port */
|
||||
u32 physical_s_id; /* local FC port ID */
|
||||
struct ccw_device *ccw_device; /* S/390 ccw device */
|
||||
u8 fc_service_class;
|
||||
u32 fc_topology; /* FC topology */
|
||||
u32 fc_link_speed; /* FC interface speed */
|
||||
u32 hydra_version; /* Hydra version */
|
||||
u32 fsf_lic_version;
|
||||
u32 supported_features;/* of FCP channel */
|
||||
u32 adapter_features; /* FCP channel features */
|
||||
u32 connection_features; /* host connection features */
|
||||
u32 hardware_version; /* of FCP channel */
|
||||
u8 serial_number[32]; /* of hardware */
|
||||
struct Scsi_Host *scsi_host; /* Pointer to mid-layer */
|
||||
unsigned short scsi_host_no; /* Assigned host number */
|
||||
unsigned char name[9];
|
||||
@ -889,11 +963,18 @@ struct zfcp_adapter {
|
||||
u32 erp_low_mem_count; /* nr of erp actions waiting
|
||||
for memory */
|
||||
struct zfcp_port *nameserver_port; /* adapter's nameserver */
|
||||
debug_info_t *erp_dbf; /* S/390 debug features */
|
||||
debug_info_t *abort_dbf;
|
||||
debug_info_t *in_els_dbf;
|
||||
debug_info_t *cmd_dbf;
|
||||
spinlock_t dbf_lock;
|
||||
debug_info_t *erp_dbf;
|
||||
debug_info_t *hba_dbf;
|
||||
debug_info_t *san_dbf; /* debug feature areas */
|
||||
debug_info_t *scsi_dbf;
|
||||
spinlock_t erp_dbf_lock;
|
||||
spinlock_t hba_dbf_lock;
|
||||
spinlock_t san_dbf_lock;
|
||||
spinlock_t scsi_dbf_lock;
|
||||
struct zfcp_erp_dbf_record erp_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 qdio_initialize qdio_init_data; /* for qdio_establish */
|
||||
struct device generic_services; /* directory for WKA ports */
|
||||
@ -919,7 +1000,7 @@ struct zfcp_port {
|
||||
atomic_t status; /* status of this remote port */
|
||||
wwn_t wwnn; /* WWNN if known */
|
||||
wwn_t wwpn; /* WWPN */
|
||||
fc_id_t d_id; /* D_ID */
|
||||
u32 d_id; /* D_ID */
|
||||
u32 handle; /* handle assigned by FSF */
|
||||
struct zfcp_erp_action erp_action; /* pending error recovery */
|
||||
atomic_t erp_counter;
|
||||
@ -963,11 +1044,13 @@ struct zfcp_fsf_req {
|
||||
u32 fsf_command; /* FSF Command copy */
|
||||
struct fsf_qtcb *qtcb; /* address of associated QTCB */
|
||||
u32 seq_no; /* Sequence number of request */
|
||||
union zfcp_req_data data; /* Info fields of request */
|
||||
unsigned long data; /* private data of request */
|
||||
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;
|
||||
};
|
||||
|
||||
typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
|
||||
|
@ -82,6 +82,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *);
|
||||
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *);
|
||||
static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *);
|
||||
static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *);
|
||||
static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *);
|
||||
static int zfcp_erp_adapter_strategy_open_fsf_statusread(
|
||||
struct zfcp_erp_action *);
|
||||
|
||||
@ -345,13 +346,13 @@ zfcp_erp_adisc(struct zfcp_port *port)
|
||||
|
||||
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
|
||||
without FC-AL-2 capability, so we don't set it */
|
||||
adisc->wwpn = adapter->wwpn;
|
||||
adisc->wwnn = adapter->wwnn;
|
||||
adisc->nport_id = adapter->s_id;
|
||||
adisc->wwpn = fc_host_port_name(adapter->scsi_host);
|
||||
adisc->wwnn = fc_host_node_name(adapter->scsi_host);
|
||||
adisc->nport_id = fc_host_port_id(adapter->scsi_host);
|
||||
ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
|
||||
"(wwpn=0x%016Lx, wwnn=0x%016Lx, "
|
||||
"hard_nport_id=0x%08x, nport_id=0x%08x)\n",
|
||||
adapter->s_id, send_els->d_id, (wwn_t) adisc->wwpn,
|
||||
adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
|
||||
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
|
||||
adisc->nport_id);
|
||||
|
||||
@ -404,7 +405,7 @@ zfcp_erp_adisc_handler(unsigned long data)
|
||||
struct zfcp_send_els *send_els;
|
||||
struct zfcp_port *port;
|
||||
struct zfcp_adapter *adapter;
|
||||
fc_id_t d_id;
|
||||
u32 d_id;
|
||||
struct zfcp_ls_adisc_acc *adisc;
|
||||
|
||||
send_els = (struct zfcp_send_els *) data;
|
||||
@ -435,9 +436,9 @@ zfcp_erp_adisc_handler(unsigned long data)
|
||||
ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
|
||||
"0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
|
||||
"hard_nport_id=0x%08x, nport_id=0x%08x)\n",
|
||||
d_id, adapter->s_id, (wwn_t) adisc->wwpn,
|
||||
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
|
||||
adisc->nport_id);
|
||||
d_id, fc_host_port_id(adapter->scsi_host),
|
||||
(wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
|
||||
adisc->hard_nport_id, adisc->nport_id);
|
||||
|
||||
/* set wwnn for port */
|
||||
if (port->wwnn == 0)
|
||||
@ -886,7 +887,7 @@ static int
|
||||
zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
int retval = 0;
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
struct zfcp_fsf_req *fsf_req = NULL;
|
||||
struct zfcp_adapter *adapter = erp_action->adapter;
|
||||
|
||||
if (erp_action->fsf_req) {
|
||||
@ -896,7 +897,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
|
||||
list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
|
||||
if (fsf_req == erp_action->fsf_req)
|
||||
break;
|
||||
if (fsf_req == erp_action->fsf_req) {
|
||||
if (fsf_req && (fsf_req->erp_action == erp_action)) {
|
||||
/* fsf_req still exists */
|
||||
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
|
||||
debug_event(adapter->erp_dbf, 3, &fsf_req,
|
||||
@ -2258,16 +2259,21 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
|
||||
static int
|
||||
zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
int retval;
|
||||
int xconfig, xport;
|
||||
|
||||
/* do 'exchange configuration data' */
|
||||
retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action);
|
||||
if (retval == ZFCP_ERP_FAILED)
|
||||
return retval;
|
||||
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
||||
&erp_action->adapter->status)) {
|
||||
zfcp_erp_adapter_strategy_open_fsf_xport(erp_action);
|
||||
atomic_set(&erp_action->adapter->erp_counter, 0);
|
||||
return ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
/* start the desired number of Status Reads */
|
||||
retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
|
||||
return retval;
|
||||
xconfig = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action);
|
||||
xport = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action);
|
||||
if ((xconfig == ZFCP_ERP_FAILED) || (xport == ZFCP_ERP_FAILED))
|
||||
return ZFCP_ERP_FAILED;
|
||||
|
||||
return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2291,7 +2297,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
|
||||
&adapter->status);
|
||||
ZFCP_LOG_DEBUG("Doing exchange config data\n");
|
||||
write_lock(&adapter->erp_lock);
|
||||
zfcp_erp_action_to_running(erp_action);
|
||||
write_unlock(&adapter->erp_lock);
|
||||
zfcp_erp_timeout_init(erp_action);
|
||||
if (zfcp_fsf_exchange_config_data(erp_action)) {
|
||||
retval = ZFCP_ERP_FAILED;
|
||||
@ -2348,6 +2356,76 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
int retval = ZFCP_ERP_SUCCEEDED;
|
||||
int retries;
|
||||
int sleep;
|
||||
struct zfcp_adapter *adapter = erp_action->adapter;
|
||||
|
||||
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
|
||||
|
||||
for (retries = 0; ; retries++) {
|
||||
ZFCP_LOG_DEBUG("Doing exchange port data\n");
|
||||
zfcp_erp_action_to_running(erp_action);
|
||||
zfcp_erp_timeout_init(erp_action);
|
||||
if (zfcp_fsf_exchange_port_data(erp_action, adapter, NULL)) {
|
||||
retval = ZFCP_ERP_FAILED;
|
||||
debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
|
||||
ZFCP_LOG_INFO("error: initiation of exchange of "
|
||||
"port data failed for adapter %s\n",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
break;
|
||||
}
|
||||
debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok");
|
||||
ZFCP_LOG_DEBUG("Xchange underway\n");
|
||||
|
||||
/*
|
||||
* Why this works:
|
||||
* Both the normal completion handler as well as the timeout
|
||||
* handler will do an 'up' when the 'exchange port data'
|
||||
* request completes or times out. Thus, the signal to go on
|
||||
* won't be lost utilizing this semaphore.
|
||||
* Furthermore, this 'adapter_reopen' action is
|
||||
* guaranteed to be the only action being there (highest action
|
||||
* which prevents other actions from being created).
|
||||
* Resulting from that, the wake signal recognized here
|
||||
* _must_ be the one belonging to the 'exchange port
|
||||
* data' request.
|
||||
*/
|
||||
down(&adapter->erp_ready_sem);
|
||||
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
|
||||
ZFCP_LOG_INFO("error: exchange of port data "
|
||||
"for adapter %s timed out\n",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
||||
&adapter->status))
|
||||
break;
|
||||
|
||||
ZFCP_LOG_DEBUG("host connection still initialising... "
|
||||
"waiting and retrying...\n");
|
||||
/* sleep a little bit before retry */
|
||||
sleep = retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES ?
|
||||
ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP :
|
||||
ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP;
|
||||
msleep(jiffies_to_msecs(sleep));
|
||||
}
|
||||
|
||||
if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
|
||||
&adapter->status)) {
|
||||
ZFCP_LOG_INFO("error: exchange of port data for "
|
||||
"adapter %s failed\n",
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
retval = ZFCP_ERP_FAILED;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* function:
|
||||
*
|
||||
@ -3194,11 +3272,19 @@ zfcp_erp_action_enqueue(int action,
|
||||
/* fall through !!! */
|
||||
|
||||
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||||
if (atomic_test_mask
|
||||
(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)
|
||||
&& port->erp_action.action ==
|
||||
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
|
||||
debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp");
|
||||
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
|
||||
&port->status)) {
|
||||
if (port->erp_action.action !=
|
||||
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
|
||||
ZFCP_LOG_INFO("dropped erp action %i (port "
|
||||
"0x%016Lx, action in use: %i)\n",
|
||||
action, port->wwpn,
|
||||
port->erp_action.action);
|
||||
debug_text_event(adapter->erp_dbf, 4,
|
||||
"pf_actenq_drp");
|
||||
} else
|
||||
debug_text_event(adapter->erp_dbf, 4,
|
||||
"pf_actenq_drpcp");
|
||||
debug_event(adapter->erp_dbf, 4, &port->wwpn,
|
||||
sizeof (wwn_t));
|
||||
goto out;
|
||||
@ -3589,6 +3675,9 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter)
|
||||
struct zfcp_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
|
||||
return;
|
||||
|
||||
debug_text_event(adapter->erp_dbf, 3, "a_access_recover");
|
||||
debug_event(adapter->erp_dbf, 3, &adapter->name, 8);
|
||||
|
||||
|
@ -96,7 +96,8 @@ extern int zfcp_fsf_open_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_port_data(struct zfcp_adapter *,
|
||||
extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
|
||||
struct zfcp_adapter *,
|
||||
struct fsf_qtcb_bottom_port *);
|
||||
extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
|
||||
u32, u32, struct zfcp_sg_list *);
|
||||
@ -109,7 +110,6 @@ extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, 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_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *);
|
||||
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
|
||||
struct zfcp_unit *,
|
||||
struct scsi_cmnd *,
|
||||
@ -182,9 +182,25 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *);
|
||||
extern void zfcp_erp_unit_access_changed(struct zfcp_unit *);
|
||||
|
||||
/******************************** AUX ****************************************/
|
||||
extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *,
|
||||
void *, int);
|
||||
extern void zfcp_cmd_dbf_event_scsi(const char *, struct scsi_cmnd *);
|
||||
extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *,
|
||||
struct fsf_status_read_buffer *, int);
|
||||
extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *);
|
||||
extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *,
|
||||
struct fsf_status_read_buffer *);
|
||||
extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *,
|
||||
unsigned int, unsigned int, unsigned int,
|
||||
int, int);
|
||||
|
||||
extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *);
|
||||
extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *);
|
||||
extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *);
|
||||
extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *);
|
||||
extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *);
|
||||
|
||||
extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *,
|
||||
struct scsi_cmnd *);
|
||||
extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
|
||||
struct scsi_cmnd *,
|
||||
struct zfcp_fsf_req *);
|
||||
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
|
||||
struct scsi_cmnd *);
|
||||
|
||||
#endif /* ZFCP_EXT_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -116,6 +116,7 @@
|
||||
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
|
||||
/* #define FSF_ERROR 0x000000FF */
|
||||
|
||||
#define FSF_PROT_STATUS_QUAL_SIZE 16
|
||||
#define FSF_STATUS_QUALIFIER_SIZE 16
|
||||
|
||||
/* FSF status qualifier, recommendations */
|
||||
@ -139,9 +140,18 @@
|
||||
#define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004
|
||||
|
||||
/* FSF status qualifier (most significant 4 bytes), local link down */
|
||||
#define FSF_PSQ_LINK_NOLIGHT 0x00000004
|
||||
#define FSF_PSQ_LINK_WRAPPLUG 0x00000008
|
||||
#define FSF_PSQ_LINK_NOFCP 0x00000010
|
||||
#define FSF_PSQ_LINK_NO_LIGHT 0x00000004
|
||||
#define FSF_PSQ_LINK_WRAP_PLUG 0x00000008
|
||||
#define FSF_PSQ_LINK_NO_FCP 0x00000010
|
||||
#define FSF_PSQ_LINK_FIRMWARE_UPDATE 0x00000020
|
||||
#define FSF_PSQ_LINK_INVALID_WWPN 0x00000100
|
||||
#define FSF_PSQ_LINK_NO_NPIV_SUPPORT 0x00000200
|
||||
#define FSF_PSQ_LINK_NO_FCP_RESOURCES 0x00000400
|
||||
#define FSF_PSQ_LINK_NO_FABRIC_RESOURCES 0x00000800
|
||||
#define FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE 0x00001000
|
||||
#define FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED 0x00002000
|
||||
#define FSF_PSQ_LINK_MODE_TABLE_CURRUPTED 0x00004000
|
||||
#define FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT 0x00008000
|
||||
|
||||
/* payload size in status read buffer */
|
||||
#define FSF_STATUS_READ_PAYLOAD_SIZE 4032
|
||||
@ -154,15 +164,21 @@
|
||||
#define FSF_STATUS_READ_INCOMING_ELS 0x00000002
|
||||
#define FSF_STATUS_READ_SENSE_DATA_AVAIL 0x00000003
|
||||
#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004
|
||||
#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */
|
||||
#define FSF_STATUS_READ_LINK_DOWN 0x00000005
|
||||
#define FSF_STATUS_READ_LINK_UP 0x00000006
|
||||
#define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A
|
||||
#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B
|
||||
#define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C
|
||||
|
||||
/* status subtypes in status read buffer */
|
||||
#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001
|
||||
#define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002
|
||||
|
||||
/* status subtypes for link down */
|
||||
#define FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK 0x00000000
|
||||
#define FSF_STATUS_READ_SUB_FDISC_FAILED 0x00000001
|
||||
#define FSF_STATUS_READ_SUB_FIRMWARE_UPDATE 0x00000002
|
||||
|
||||
/* status subtypes for CFDC */
|
||||
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002
|
||||
#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
|
||||
@ -193,11 +209,15 @@
|
||||
#define FSF_QTCB_LOG_SIZE 1024
|
||||
|
||||
/* channel features */
|
||||
#define FSF_FEATURE_QTCB_SUPPRESSION 0x00000001
|
||||
#define FSF_FEATURE_CFDC 0x00000002
|
||||
#define FSF_FEATURE_LUN_SHARING 0x00000004
|
||||
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
|
||||
#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
|
||||
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
|
||||
|
||||
/* host connection features */
|
||||
#define FSF_FEATURE_NPIV_MODE 0x00000001
|
||||
#define FSF_FEATURE_VM_ASSIGNED_WWPN 0x00000002
|
||||
|
||||
/* option */
|
||||
#define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001
|
||||
@ -305,15 +325,23 @@ struct fsf_qual_sequence_error {
|
||||
u32 res1[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_qual_locallink_error {
|
||||
u32 code;
|
||||
u32 res1[3];
|
||||
struct fsf_link_down_info {
|
||||
u32 error_code;
|
||||
u32 res1;
|
||||
u8 res2[2];
|
||||
u8 primary_status;
|
||||
u8 ioerr_code;
|
||||
u8 action_code;
|
||||
u8 reason_code;
|
||||
u8 explanation_code;
|
||||
u8 vendor_specific_code;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union fsf_prot_status_qual {
|
||||
u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)];
|
||||
struct fsf_qual_version_error version_error;
|
||||
struct fsf_qual_sequence_error sequence_error;
|
||||
struct fsf_qual_locallink_error locallink_error;
|
||||
struct fsf_link_down_info link_down_info;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_qtcb_prefix {
|
||||
@ -331,7 +359,9 @@ union fsf_status_qual {
|
||||
u8 byte[FSF_STATUS_QUALIFIER_SIZE];
|
||||
u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)];
|
||||
u32 word[FSF_STATUS_QUALIFIER_SIZE / sizeof (u32)];
|
||||
u64 doubleword[FSF_STATUS_QUALIFIER_SIZE / sizeof(u64)];
|
||||
struct fsf_queue_designator fsf_queue_designator;
|
||||
struct fsf_link_down_info link_down_info;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_qtcb_header {
|
||||
@ -406,8 +436,8 @@ struct fsf_qtcb_bottom_config {
|
||||
u32 low_qtcb_version;
|
||||
u32 max_qtcb_size;
|
||||
u32 max_data_transfer_size;
|
||||
u32 supported_features;
|
||||
u8 res1[4];
|
||||
u32 adapter_features;
|
||||
u32 connection_features;
|
||||
u32 fc_topology;
|
||||
u32 fc_link_speed;
|
||||
u32 adapter_type;
|
||||
@ -425,7 +455,7 @@ struct fsf_qtcb_bottom_config {
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct fsf_qtcb_bottom_port {
|
||||
u8 res1[8];
|
||||
u64 wwpn;
|
||||
u32 fc_port_id;
|
||||
u32 port_type;
|
||||
u32 port_state;
|
||||
|
@ -54,8 +54,7 @@ static inline int zfcp_qdio_sbals_from_buffer
|
||||
static qdio_handler_t zfcp_qdio_request_handler;
|
||||
static qdio_handler_t zfcp_qdio_response_handler;
|
||||
static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
|
||||
unsigned int,
|
||||
unsigned int, unsigned int);
|
||||
unsigned int, unsigned int, unsigned int, int, int);
|
||||
|
||||
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
|
||||
|
||||
@ -214,22 +213,12 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
|
||||
*
|
||||
*/
|
||||
static inline int
|
||||
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
|
||||
unsigned int status,
|
||||
unsigned int qdio_error, unsigned int siga_error)
|
||||
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
|
||||
unsigned int qdio_error, unsigned int siga_error,
|
||||
int first_element, int elements_processed)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) {
|
||||
if (status & QDIO_STATUS_INBOUND_INT) {
|
||||
ZFCP_LOG_TRACE("status is"
|
||||
" QDIO_STATUS_INBOUND_INT \n");
|
||||
}
|
||||
if (status & QDIO_STATUS_OUTBOUND_INT) {
|
||||
ZFCP_LOG_TRACE("status is"
|
||||
" QDIO_STATUS_OUTBOUND_INT \n");
|
||||
}
|
||||
}
|
||||
if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) {
|
||||
retval = -EIO;
|
||||
|
||||
@ -237,9 +226,10 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter,
|
||||
"qdio_error=0x%x, siga_error=0x%x)\n",
|
||||
status, qdio_error, siga_error);
|
||||
|
||||
/* Restarting IO on the failed adapter from scratch */
|
||||
debug_text_event(adapter->erp_dbf, 1, "qdio_err");
|
||||
zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error,
|
||||
first_element, elements_processed);
|
||||
/*
|
||||
* Restarting IO on the failed adapter from scratch.
|
||||
* Since we have been using this adapter, it is save to assume
|
||||
* that it is not failed but recoverable. The card seems to
|
||||
* report link-up events by self-initiated queue shutdown.
|
||||
@ -282,7 +272,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
|
||||
first_element, elements_processed);
|
||||
|
||||
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
|
||||
siga_error)))
|
||||
siga_error, first_element,
|
||||
elements_processed)))
|
||||
goto out;
|
||||
/*
|
||||
* we stored address of struct zfcp_adapter data structure
|
||||
@ -334,7 +325,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
|
||||
queue = &adapter->response_queue;
|
||||
|
||||
if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error,
|
||||
siga_error)))
|
||||
siga_error, first_element,
|
||||
elements_processed)))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
|
@ -44,7 +44,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
|
||||
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
|
||||
static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
|
||||
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
|
||||
static int zfcp_task_management_function(struct zfcp_unit *, u8);
|
||||
static int zfcp_task_management_function(struct zfcp_unit *, u8,
|
||||
struct scsi_cmnd *);
|
||||
|
||||
static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
|
||||
scsi_lun_t);
|
||||
@ -242,7 +243,10 @@ static void
|
||||
zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
|
||||
{
|
||||
set_host_byte(&scpnt->result, result);
|
||||
zfcp_cmd_dbf_event_scsi("failing", scpnt);
|
||||
if ((scpnt->device != NULL) && (scpnt->device->host != NULL))
|
||||
zfcp_scsi_dbf_event_result("fail", 4,
|
||||
(struct zfcp_adapter*) scpnt->device->host->hostdata[0],
|
||||
scpnt);
|
||||
/* return directly */
|
||||
scpnt->scsi_done(scpnt);
|
||||
}
|
||||
@ -414,67 +418,38 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
|
||||
return (struct zfcp_port *) NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* function: zfcp_scsi_eh_abort_handler
|
||||
/**
|
||||
* zfcp_scsi_eh_abort_handler - abort the specified SCSI command
|
||||
* @scpnt: pointer to scsi_cmnd to be aborted
|
||||
* Return: SUCCESS - command has been aborted and cleaned up in internal
|
||||
* bookkeeping, SCSI stack won't be called for aborted command
|
||||
* FAILED - otherwise
|
||||
*
|
||||
* purpose: tries to abort the specified (timed out) SCSI command
|
||||
*
|
||||
* note: We do not need to care for a SCSI command which completes
|
||||
* normally but late during this abort routine runs.
|
||||
* We are allowed to return late commands to the SCSI stack.
|
||||
* It tracks the state of commands and will handle late commands.
|
||||
* (Usually, the normal completion of late commands is ignored with
|
||||
* respect to the running abort operation. Grep for 'done_late'
|
||||
* in the SCSI stacks sources.)
|
||||
*
|
||||
* returns: SUCCESS - command has been aborted and cleaned up in internal
|
||||
* bookkeeping,
|
||||
* SCSI stack won't be called for aborted command
|
||||
* FAILED - otherwise
|
||||
* We do not need to care for a SCSI command which completes normally
|
||||
* but late during this abort routine runs. We are allowed to return
|
||||
* late commands to the SCSI stack. It tracks the state of commands and
|
||||
* will handle late commands. (Usually, the normal completion of late
|
||||
* commands is ignored with respect to the running abort operation.)
|
||||
*/
|
||||
int
|
||||
__zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||
zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
struct Scsi_Host *scsi_host;
|
||||
struct zfcp_adapter *adapter;
|
||||
struct zfcp_unit *unit;
|
||||
int retval = SUCCESS;
|
||||
struct zfcp_fsf_req *new_fsf_req, *old_fsf_req;
|
||||
struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
|
||||
struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
|
||||
struct zfcp_port *port = unit->port;
|
||||
struct Scsi_Host *scsi_host = scpnt->device->host;
|
||||
union zfcp_req_data *req_data = NULL;
|
||||
struct zfcp_fsf_req *new_fsf_req = NULL;
|
||||
struct zfcp_fsf_req *old_fsf_req;
|
||||
unsigned long flags;
|
||||
u32 status = 0;
|
||||
|
||||
/* the components of a abort_dbf record (fixed size record) */
|
||||
u64 dbf_scsi_cmnd = (unsigned long) scpnt;
|
||||
char dbf_opcode[ZFCP_ABORT_DBF_LENGTH];
|
||||
wwn_t dbf_wwn = port->wwpn;
|
||||
fcp_lun_t dbf_fcp_lun = unit->fcp_lun;
|
||||
u64 dbf_retries = scpnt->retries;
|
||||
u64 dbf_allowed = scpnt->allowed;
|
||||
u64 dbf_timeout = 0;
|
||||
u64 dbf_fsf_req = 0;
|
||||
u64 dbf_fsf_status = 0;
|
||||
u64 dbf_fsf_qual[2] = { 0, 0 };
|
||||
char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef";
|
||||
|
||||
memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH);
|
||||
memcpy(dbf_opcode,
|
||||
scpnt->cmnd,
|
||||
min(scpnt->cmd_len, (unsigned char) ZFCP_ABORT_DBF_LENGTH));
|
||||
scsi_host = scpnt->device->host;
|
||||
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
|
||||
unit = (struct zfcp_unit *) scpnt->device->hostdata;
|
||||
|
||||
ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n",
|
||||
scpnt, zfcp_get_busid_by_adapter(adapter));
|
||||
|
||||
spin_unlock_irq(scsi_host->host_lock);
|
||||
|
||||
/*
|
||||
* Race condition between normal (late) completion and abort has
|
||||
* to be avoided.
|
||||
* The entirity of all accesses to scsi_req have to be atomic.
|
||||
* scsi_req is usually part of the fsf_req and thus we block the
|
||||
* release of fsf_req as long as we need to access scsi_req.
|
||||
*/
|
||||
/* avoid race condition between late normal completion and abort */
|
||||
write_lock_irqsave(&adapter->abort_lock, flags);
|
||||
|
||||
/*
|
||||
@ -484,144 +459,47 @@ __zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||
* this routine returns. (scpnt is parameter passed to this routine
|
||||
* and must not disappear during abort even on late completion.)
|
||||
*/
|
||||
req_data = (union zfcp_req_data *) scpnt->host_scribble;
|
||||
/* DEBUG */
|
||||
ZFCP_LOG_DEBUG("req_data=%p\n", req_data);
|
||||
if (!req_data) {
|
||||
ZFCP_LOG_DEBUG("late command completion overtook abort\n");
|
||||
/*
|
||||
* That's it.
|
||||
* Do not initiate abort but return SUCCESS.
|
||||
*/
|
||||
write_unlock_irqrestore(&adapter->abort_lock, flags);
|
||||
retval = SUCCESS;
|
||||
strncpy(dbf_result, "##late1", ZFCP_ABORT_DBF_LENGTH);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Figure out which fsf_req needs to be aborted. */
|
||||
old_fsf_req = req_data->send_fcp_command_task.fsf_req;
|
||||
|
||||
dbf_fsf_req = (unsigned long) old_fsf_req;
|
||||
dbf_timeout =
|
||||
(jiffies - req_data->send_fcp_command_task.start_jiffies) / HZ;
|
||||
|
||||
ZFCP_LOG_DEBUG("old_fsf_req=%p\n", old_fsf_req);
|
||||
old_fsf_req = (struct zfcp_fsf_req *) scpnt->host_scribble;
|
||||
if (!old_fsf_req) {
|
||||
write_unlock_irqrestore(&adapter->abort_lock, flags);
|
||||
ZFCP_LOG_NORMAL("bug: no old fsf request found\n");
|
||||
ZFCP_LOG_NORMAL("req_data:\n");
|
||||
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
|
||||
(char *) req_data, sizeof (union zfcp_req_data));
|
||||
ZFCP_LOG_NORMAL("scsi_cmnd:\n");
|
||||
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
|
||||
(char *) scpnt, sizeof (struct scsi_cmnd));
|
||||
retval = FAILED;
|
||||
strncpy(dbf_result, "##bug:r", ZFCP_ABORT_DBF_LENGTH);
|
||||
zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, new_fsf_req);
|
||||
retval = SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
old_fsf_req->data.send_fcp_command_task.scsi_cmnd = NULL;
|
||||
/* mark old request as being aborted */
|
||||
old_fsf_req->data = 0;
|
||||
old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
|
||||
/*
|
||||
* We have to collect all information (e.g. unit) needed by
|
||||
* zfcp_fsf_abort_fcp_command before calling that routine
|
||||
* since that routine is not allowed to access
|
||||
* fsf_req which it is going to abort.
|
||||
* This is because of we need to release fsf_req_list_lock
|
||||
* before calling zfcp_fsf_abort_fcp_command.
|
||||
* Since this lock will not be held, fsf_req may complete
|
||||
* late and may be released meanwhile.
|
||||
*/
|
||||
ZFCP_LOG_DEBUG("unit 0x%016Lx (%p)\n", unit->fcp_lun, unit);
|
||||
|
||||
/*
|
||||
* We block (call schedule)
|
||||
* That's why we must release the lock and enable the
|
||||
* interrupts before.
|
||||
* On the other hand we do not need the lock anymore since
|
||||
* all critical accesses to scsi_req are done.
|
||||
*/
|
||||
/* don't access old_fsf_req after releasing the abort_lock */
|
||||
write_unlock_irqrestore(&adapter->abort_lock, flags);
|
||||
/* call FSF routine which does the abort */
|
||||
new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req,
|
||||
adapter, unit, 0);
|
||||
ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req);
|
||||
if (!new_fsf_req) {
|
||||
ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n");
|
||||
retval = FAILED;
|
||||
ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd "
|
||||
"failed\n");
|
||||
strncpy(dbf_result, "##nores", ZFCP_ABORT_DBF_LENGTH);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* wait for completion of abort */
|
||||
ZFCP_LOG_DEBUG("waiting for cleanup...\n");
|
||||
#if 1
|
||||
/*
|
||||
* FIXME:
|
||||
* copying zfcp_fsf_req_wait_and_cleanup code is not really nice
|
||||
*/
|
||||
__wait_event(new_fsf_req->completion_wq,
|
||||
new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
|
||||
status = new_fsf_req->status;
|
||||
dbf_fsf_status = new_fsf_req->qtcb->header.fsf_status;
|
||||
/*
|
||||
* Ralphs special debug load provides timestamps in the FSF
|
||||
* status qualifier. This might be specified later if being
|
||||
* useful for debugging aborts.
|
||||
*/
|
||||
dbf_fsf_qual[0] =
|
||||
*(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0];
|
||||
dbf_fsf_qual[1] =
|
||||
*(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2];
|
||||
zfcp_fsf_req_free(new_fsf_req);
|
||||
#else
|
||||
retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req,
|
||||
ZFCP_UNINTERRUPTIBLE, &status);
|
||||
#endif
|
||||
ZFCP_LOG_DEBUG("Waiting for cleanup complete, status=0x%x\n", status);
|
||||
|
||||
/* status should be valid since signals were not permitted */
|
||||
if (status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
|
||||
if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
|
||||
zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, new_fsf_req);
|
||||
retval = SUCCESS;
|
||||
strncpy(dbf_result, "##succ", ZFCP_ABORT_DBF_LENGTH);
|
||||
} else if (status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
|
||||
} else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
|
||||
zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, new_fsf_req);
|
||||
retval = SUCCESS;
|
||||
strncpy(dbf_result, "##late2", ZFCP_ABORT_DBF_LENGTH);
|
||||
} else {
|
||||
zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, new_fsf_req);
|
||||
retval = FAILED;
|
||||
strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH);
|
||||
}
|
||||
|
||||
zfcp_fsf_req_free(new_fsf_req);
|
||||
out:
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_scsi_cmnd, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_opcode, ZFCP_ABORT_DBF_LENGTH);
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_wwn, sizeof (wwn_t));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_fcp_lun, sizeof (fcp_lun_t));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_retries, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_allowed, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_timeout, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_fsf_req, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_fsf_status, sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[0], sizeof (u64));
|
||||
debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[1], sizeof (u64));
|
||||
debug_text_event(adapter->abort_dbf, 1, dbf_result);
|
||||
|
||||
spin_lock_irq(scsi_host->host_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
int rc;
|
||||
struct Scsi_Host *scsi_host = scpnt->device->host;
|
||||
spin_lock_irq(scsi_host->host_lock);
|
||||
rc = __zfcp_scsi_eh_abort_handler(scpnt);
|
||||
spin_unlock_irq(scsi_host->host_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* function: zfcp_scsi_eh_device_reset_handler
|
||||
*
|
||||
@ -651,8 +529,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
|
||||
*/
|
||||
if (!atomic_test_mask(ZFCP_STATUS_UNIT_NOTSUPPUNITRESET,
|
||||
&unit->status)) {
|
||||
retval =
|
||||
zfcp_task_management_function(unit, FCP_LOGICAL_UNIT_RESET);
|
||||
retval = zfcp_task_management_function(unit,
|
||||
FCP_LOGICAL_UNIT_RESET,
|
||||
scpnt);
|
||||
if (retval) {
|
||||
ZFCP_LOG_DEBUG("unit reset failed (unit=%p)\n", unit);
|
||||
if (retval == -ENOTSUPP)
|
||||
@ -668,7 +547,7 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
retval = zfcp_task_management_function(unit, FCP_TARGET_RESET);
|
||||
retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt);
|
||||
if (retval) {
|
||||
ZFCP_LOG_DEBUG("target reset failed (unit=%p)\n", unit);
|
||||
retval = FAILED;
|
||||
@ -681,12 +560,12 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
|
||||
}
|
||||
|
||||
static int
|
||||
zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
|
||||
zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
|
||||
struct scsi_cmnd *scpnt)
|
||||
{
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
int retval;
|
||||
int status;
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
int retval = 0;
|
||||
|
||||
/* issue task management function */
|
||||
fsf_req = zfcp_fsf_send_fcp_command_task_management
|
||||
@ -696,70 +575,63 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags)
|
||||
"failed for unit 0x%016Lx on port 0x%016Lx on "
|
||||
"adapter %s\n", unit->fcp_lun, unit->port->wwpn,
|
||||
zfcp_get_busid_by_adapter(adapter));
|
||||
zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt);
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = zfcp_fsf_req_wait_and_cleanup(fsf_req,
|
||||
ZFCP_UNINTERRUPTIBLE, &status);
|
||||
__wait_event(fsf_req->completion_wq,
|
||||
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
|
||||
|
||||
/*
|
||||
* check completion status of task management function
|
||||
* (status should always be valid since no signals permitted)
|
||||
*/
|
||||
if (status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED)
|
||||
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
|
||||
zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
|
||||
retval = -EIO;
|
||||
else if (status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP)
|
||||
} else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) {
|
||||
zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt);
|
||||
retval = -ENOTSUPP;
|
||||
else
|
||||
retval = 0;
|
||||
} else
|
||||
zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
|
||||
|
||||
zfcp_fsf_req_free(fsf_req);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* function: zfcp_scsi_eh_bus_reset_handler
|
||||
*
|
||||
* purpose:
|
||||
*
|
||||
* returns:
|
||||
/**
|
||||
* zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter)
|
||||
*/
|
||||
int
|
||||
zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
int retval = 0;
|
||||
struct zfcp_unit *unit;
|
||||
struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
unit = (struct zfcp_unit *) scpnt->device->hostdata;
|
||||
ZFCP_LOG_NORMAL("bus reset because of problems with "
|
||||
"unit 0x%016Lx\n", unit->fcp_lun);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
|
||||
zfcp_erp_wait(unit->port->adapter);
|
||||
retval = SUCCESS;
|
||||
zfcp_erp_adapter_reopen(adapter, 0);
|
||||
zfcp_erp_wait(adapter);
|
||||
|
||||
return retval;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* function: zfcp_scsi_eh_host_reset_handler
|
||||
*
|
||||
* purpose:
|
||||
*
|
||||
* returns:
|
||||
/**
|
||||
* zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter)
|
||||
*/
|
||||
int
|
||||
zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
|
||||
{
|
||||
int retval = 0;
|
||||
struct zfcp_unit *unit;
|
||||
struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
|
||||
struct zfcp_adapter *adapter = unit->port->adapter;
|
||||
|
||||
unit = (struct zfcp_unit *) scpnt->device->hostdata;
|
||||
ZFCP_LOG_NORMAL("host reset because of problems with "
|
||||
"unit 0x%016Lx\n", unit->fcp_lun);
|
||||
zfcp_erp_adapter_reopen(unit->port->adapter, 0);
|
||||
zfcp_erp_wait(unit->port->adapter);
|
||||
retval = SUCCESS;
|
||||
zfcp_erp_adapter_reopen(adapter, 0);
|
||||
zfcp_erp_wait(adapter);
|
||||
|
||||
return retval;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -826,10 +698,16 @@ void
|
||||
zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct Scsi_Host *shost;
|
||||
struct zfcp_port *port;
|
||||
|
||||
shost = adapter->scsi_host;
|
||||
if (!shost)
|
||||
return;
|
||||
read_lock_irq(&zfcp_data.config_lock);
|
||||
list_for_each_entry(port, &adapter->port_list_head, list)
|
||||
if (port->rport)
|
||||
port->rport = NULL;
|
||||
read_unlock_irq(&zfcp_data.config_lock);
|
||||
fc_remove_host(shost);
|
||||
scsi_remove_host(shost);
|
||||
scsi_host_put(shost);
|
||||
@ -904,18 +782,6 @@ zfcp_get_node_name(struct scsi_target *starget)
|
||||
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
zfcp_set_fc_host_attrs(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct Scsi_Host *shost = adapter->scsi_host;
|
||||
|
||||
fc_host_node_name(shost) = adapter->wwnn;
|
||||
fc_host_port_name(shost) = adapter->wwpn;
|
||||
strncpy(fc_host_serial_number(shost), adapter->serial_number,
|
||||
min(FC_SERIAL_NUMBER_SIZE, 32));
|
||||
fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
|
||||
}
|
||||
|
||||
struct fc_function_template zfcp_transport_functions = {
|
||||
.get_starget_port_id = zfcp_get_port_id,
|
||||
.get_starget_port_name = zfcp_get_port_name,
|
||||
@ -927,7 +793,10 @@ struct fc_function_template zfcp_transport_functions = {
|
||||
.show_host_node_name = 1,
|
||||
.show_host_port_name = 1,
|
||||
.show_host_supported_classes = 1,
|
||||
.show_host_maxframe_size = 1,
|
||||
.show_host_serial_number = 1,
|
||||
.show_host_speed = 1,
|
||||
.show_host_port_id = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,21 +62,18 @@ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct devi
|
||||
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL);
|
||||
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status));
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(physical_wwpn, "0x%016llx\n", adapter->physical_wwpn);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
|
||||
fc_topologies[adapter->fc_topology]);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
|
||||
adapter->hardware_version);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no);
|
||||
ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
|
||||
(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
|
||||
@ -255,21 +252,18 @@ static struct attribute *zfcp_adapter_attrs[] = {
|
||||
&dev_attr_in_recovery.attr,
|
||||
&dev_attr_port_remove.attr,
|
||||
&dev_attr_port_add.attr,
|
||||
&dev_attr_wwnn.attr,
|
||||
&dev_attr_wwpn.attr,
|
||||
&dev_attr_s_id.attr,
|
||||
&dev_attr_peer_wwnn.attr,
|
||||
&dev_attr_peer_wwpn.attr,
|
||||
&dev_attr_peer_d_id.attr,
|
||||
&dev_attr_physical_wwpn.attr,
|
||||
&dev_attr_physical_s_id.attr,
|
||||
&dev_attr_card_version.attr,
|
||||
&dev_attr_lic_version.attr,
|
||||
&dev_attr_fc_link_speed.attr,
|
||||
&dev_attr_fc_service_class.attr,
|
||||
&dev_attr_fc_topology.attr,
|
||||
&dev_attr_scsi_host_no.attr,
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_hardware_version.attr,
|
||||
&dev_attr_serial_number.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -1109,15 +1109,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ahc_linux_get_memsize(void)
|
||||
{
|
||||
struct sysinfo si;
|
||||
|
||||
si_meminfo(&si);
|
||||
return ((uint64_t)si.totalram << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Place the SCSI bus into a known state by either resetting it,
|
||||
* or forcing transfer negotiations on the next command to any
|
||||
|
@ -494,8 +494,6 @@ ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
|
||||
int ahc_linux_register_host(struct ahc_softc *,
|
||||
struct scsi_host_template *);
|
||||
|
||||
uint64_t ahc_linux_get_memsize(void);
|
||||
|
||||
/*************************** Pretty Printing **********************************/
|
||||
struct info_str {
|
||||
char *buffer;
|
||||
|
@ -180,6 +180,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
struct ahc_pci_identity *entry;
|
||||
char *name;
|
||||
int error;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pci = pdev;
|
||||
entry = ahc_find_pci_device(pci);
|
||||
@ -209,11 +210,12 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (sizeof(dma_addr_t) > 4
|
||||
&& ahc_linux_get_memsize() > 0x80000000
|
||||
&& pci_set_dma_mask(pdev, mask_39bit) == 0) {
|
||||
&& ahc->features & AHC_LARGE_SCBS
|
||||
&& dma_set_mask(dev, mask_39bit) == 0
|
||||
&& dma_get_required_mask(dev) > DMA_32BIT_MASK) {
|
||||
ahc->flags |= AHC_39BIT_ADDRESSING;
|
||||
} else {
|
||||
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
|
||||
if (dma_set_mask(dev, DMA_32BIT_MASK)) {
|
||||
printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
@ -996,6 +996,7 @@ oktosend:
|
||||
#ifdef ED_DBGP
|
||||
printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
|
||||
#endif
|
||||
dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
|
||||
outl(dev->id[c][target_id].prdaddr, tmpcip);
|
||||
tmpcip = tmpcip - 2;
|
||||
outb(0x06, tmpcip);
|
||||
@ -2572,7 +2573,7 @@ static void atp870u_free_tables(struct Scsi_Host *host)
|
||||
for (k = 0; k < 16; k++) {
|
||||
if (!atp_dev->id[j][k].prd_table)
|
||||
continue;
|
||||
pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prdaddr);
|
||||
pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus);
|
||||
atp_dev->id[j][k].prd_table = NULL;
|
||||
}
|
||||
}
|
||||
@ -2584,12 +2585,13 @@ static int atp870u_init_tables(struct Scsi_Host *host)
|
||||
int c,k;
|
||||
for(c=0;c < 2;c++) {
|
||||
for(k=0;k<16;k++) {
|
||||
atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prdaddr));
|
||||
atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus));
|
||||
if (!atp_dev->id[c][k].prd_table) {
|
||||
printk("atp870u_init_tables fail\n");
|
||||
atp870u_free_tables(host);
|
||||
return -ENOMEM;
|
||||
}
|
||||
atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus;
|
||||
atp_dev->id[c][k].devsp=0x20;
|
||||
atp_dev->id[c][k].devtype = 0x7f;
|
||||
atp_dev->id[c][k].curr_req = NULL;
|
||||
|
@ -54,8 +54,9 @@ struct atp_unit
|
||||
unsigned long tran_len;
|
||||
unsigned long last_len;
|
||||
unsigned char *prd_pos;
|
||||
unsigned char *prd_table;
|
||||
dma_addr_t prdaddr;
|
||||
unsigned char *prd_table; /* Kernel address of PRD table */
|
||||
dma_addr_t prd_bus; /* Bus address of PRD */
|
||||
dma_addr_t prdaddr; /* Dynamically updated in driver */
|
||||
struct scsi_cmnd *curr_req;
|
||||
} id[2][16];
|
||||
struct Scsi_Host *host;
|
||||
|
@ -1360,3 +1360,5 @@ static Scsi_Host_Template driver_template = {
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
};
|
||||
#include "scsi_module.c"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -98,6 +98,7 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
|
||||
switch (oldstate) {
|
||||
case SHOST_CREATED:
|
||||
case SHOST_RUNNING:
|
||||
case SHOST_CANCEL_RECOVERY:
|
||||
break;
|
||||
default:
|
||||
goto illegal;
|
||||
@ -107,12 +108,31 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
|
||||
case SHOST_DEL:
|
||||
switch (oldstate) {
|
||||
case SHOST_CANCEL:
|
||||
case SHOST_DEL_RECOVERY:
|
||||
break;
|
||||
default:
|
||||
goto illegal;
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOST_CANCEL_RECOVERY:
|
||||
switch (oldstate) {
|
||||
case SHOST_CANCEL:
|
||||
case SHOST_RECOVERY:
|
||||
break;
|
||||
default:
|
||||
goto illegal;
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOST_DEL_RECOVERY:
|
||||
switch (oldstate) {
|
||||
case SHOST_CANCEL_RECOVERY:
|
||||
break;
|
||||
default:
|
||||
goto illegal;
|
||||
}
|
||||
break;
|
||||
}
|
||||
shost->shost_state = state;
|
||||
return 0;
|
||||
@ -134,13 +154,24 @@ EXPORT_SYMBOL(scsi_host_set_state);
|
||||
**/
|
||||
void scsi_remove_host(struct Scsi_Host *shost)
|
||||
{
|
||||
unsigned long flags;
|
||||
down(&shost->scan_mutex);
|
||||
scsi_host_set_state(shost, SHOST_CANCEL);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL))
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
up(&shost->scan_mutex);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
up(&shost->scan_mutex);
|
||||
scsi_forget_host(shost);
|
||||
scsi_proc_host_rm(shost);
|
||||
|
||||
scsi_host_set_state(shost, SHOST_DEL);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_DEL))
|
||||
BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
transport_unregister_device(&shost->shost_gendev);
|
||||
class_device_unregister(&shost->shost_classdev);
|
||||
|
@ -460,6 +460,8 @@ MODULE_PARM(adisplay, "1i");
|
||||
MODULE_PARM(normal, "1i");
|
||||
MODULE_PARM(ansi, "1i");
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
/*counter of concurrent disk read/writes, to turn on/off disk led */
|
||||
static int disk_rw_in_progress = 0;
|
||||
|
@ -727,6 +727,16 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
|
||||
if (hostdata->madapter_info.port_max_txu[0])
|
||||
hostdata->host->max_sectors =
|
||||
hostdata->madapter_info.port_max_txu[0] >> 9;
|
||||
|
||||
if (hostdata->madapter_info.os_type == 3 &&
|
||||
strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
|
||||
printk("ibmvscsi: host (Ver. %s) doesn't support large"
|
||||
"transfers\n",
|
||||
hostdata->madapter_info.srp_version);
|
||||
printk("ibmvscsi: limiting scatterlists to %d\n",
|
||||
MAX_INDIRECT_BUFS);
|
||||
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1265,9 +1265,8 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
|
||||
list_for_each_safe(lh, lh_sf, &active_list) {
|
||||
scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
|
||||
list_del_init(lh);
|
||||
if (recovery) {
|
||||
scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
|
||||
} else {
|
||||
if (recovery &&
|
||||
!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)) {
|
||||
scmd->result = (DID_ABORT << 16);
|
||||
scsi_finish_command(scmd);
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ static struct {
|
||||
{"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */
|
||||
{"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */
|
||||
{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
|
||||
{"transtec", "T5008", "0001", BLIST_NOREPORTLUN },
|
||||
{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */
|
||||
{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */
|
||||
{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */
|
||||
|
@ -50,7 +50,7 @@
|
||||
void scsi_eh_wakeup(struct Scsi_Host *shost)
|
||||
{
|
||||
if (shost->host_busy == shost->host_failed) {
|
||||
up(shost->eh_wait);
|
||||
wake_up_process(shost->ehandler);
|
||||
SCSI_LOG_ERROR_RECOVERY(5,
|
||||
printk("Waking error handler thread\n"));
|
||||
}
|
||||
@ -68,19 +68,24 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
|
||||
{
|
||||
struct Scsi_Host *shost = scmd->device->host;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (shost->eh_wait == NULL)
|
||||
if (!shost->ehandler)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_RECOVERY))
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY))
|
||||
goto out_unlock;
|
||||
|
||||
ret = 1;
|
||||
scmd->eh_eflags |= eh_flag;
|
||||
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
|
||||
scsi_host_set_state(shost, SHOST_RECOVERY);
|
||||
shost->host_failed++;
|
||||
scsi_eh_wakeup(shost);
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,8 +181,8 @@ void scsi_times_out(struct scsi_cmnd *scmd)
|
||||
}
|
||||
|
||||
if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
|
||||
panic("Error handler thread not present at %p %p %s %d",
|
||||
scmd, scmd->device->host, __FILE__, __LINE__);
|
||||
scmd->result |= DID_TIME_OUT << 16;
|
||||
__scsi_done(scmd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,8 +201,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev)
|
||||
{
|
||||
int online;
|
||||
|
||||
wait_event(sdev->host->host_wait, (sdev->host->shost_state !=
|
||||
SHOST_RECOVERY));
|
||||
wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host));
|
||||
|
||||
online = scsi_device_online(sdev);
|
||||
|
||||
@ -1441,6 +1445,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
|
||||
static void scsi_restart_operations(struct Scsi_Host *shost)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* If the door was locked, we need to insert a door lock request
|
||||
@ -1460,7 +1465,11 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
|
||||
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
|
||||
__FUNCTION__));
|
||||
|
||||
scsi_host_set_state(shost, SHOST_RUNNING);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
if (scsi_host_set_state(shost, SHOST_RUNNING))
|
||||
if (scsi_host_set_state(shost, SHOST_CANCEL))
|
||||
BUG_ON(scsi_host_set_state(shost, SHOST_DEL));
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
wake_up(&shost->host_wait);
|
||||
|
||||
@ -1582,40 +1591,31 @@ int scsi_error_handler(void *data)
|
||||
{
|
||||
struct Scsi_Host *shost = (struct Scsi_Host *) data;
|
||||
int rtn;
|
||||
DECLARE_MUTEX_LOCKED(sem);
|
||||
|
||||
current->flags |= PF_NOFREEZE;
|
||||
shost->eh_wait = &sem;
|
||||
|
||||
|
||||
/*
|
||||
* Wake up the thread that created us.
|
||||
* Note - we always use TASK_INTERRUPTIBLE even if the module
|
||||
* was loaded as part of the kernel. The reason is that
|
||||
* UNINTERRUPTIBLE would cause this thread to be counted in
|
||||
* the load average as a running process, and an interruptible
|
||||
* wait doesn't.
|
||||
*/
|
||||
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of"
|
||||
" scsi_eh_%d\n",shost->host_no));
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* If we get a signal, it means we are supposed to go
|
||||
* away and die. This typically happens if the user is
|
||||
* trying to unload a module.
|
||||
*/
|
||||
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
|
||||
" scsi_eh_%d"
|
||||
" sleeping\n",shost->host_no));
|
||||
|
||||
/*
|
||||
* Note - we always use down_interruptible with the semaphore
|
||||
* even if the module was loaded as part of the kernel. The
|
||||
* reason is that down() will cause this thread to be counted
|
||||
* in the load average as a running process, and down
|
||||
* interruptible doesn't. Given that we need to allow this
|
||||
* thread to die if the driver was loaded as a module, using
|
||||
* semaphores isn't unreasonable.
|
||||
*/
|
||||
down_interruptible(&sem);
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (!kthread_should_stop()) {
|
||||
if (shost->host_failed == 0 ||
|
||||
shost->host_failed != shost->host_busy) {
|
||||
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
|
||||
" scsi_eh_%d"
|
||||
" sleeping\n",
|
||||
shost->host_no));
|
||||
schedule();
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
continue;
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
|
||||
" scsi_eh_%d waking"
|
||||
" up\n",shost->host_no));
|
||||
@ -1642,7 +1642,7 @@ int scsi_error_handler(void *data)
|
||||
* which are still online.
|
||||
*/
|
||||
scsi_restart_operations(shost);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d"
|
||||
@ -1651,7 +1651,7 @@ int scsi_error_handler(void *data)
|
||||
/*
|
||||
* Make sure that nobody tries to wake us up again.
|
||||
*/
|
||||
shost->eh_wait = NULL;
|
||||
shost->ehandler = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -458,7 +458,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
|
||||
* error processing, as long as the device was opened
|
||||
* non-blocking */
|
||||
if (filp && filp->f_flags & O_NONBLOCK) {
|
||||
if (sdev->host->shost_state == SHOST_RECOVERY)
|
||||
if (scsi_host_in_recovery(sdev->host))
|
||||
return -ENODEV;
|
||||
} else if (!scsi_block_when_processing_errors(sdev))
|
||||
return -ENODEV;
|
||||
|
@ -118,7 +118,6 @@ static void scsi_unprep_request(struct request *req)
|
||||
req->flags &= ~REQ_DONTPREP;
|
||||
req->special = (req->flags & REQ_SPECIAL) ? cmd->sc_request : NULL;
|
||||
|
||||
scsi_release_buffers(cmd);
|
||||
scsi_put_command(cmd);
|
||||
}
|
||||
|
||||
@ -140,14 +139,12 @@ static void scsi_unprep_request(struct request *req)
|
||||
* commands.
|
||||
* Notes: This could be called either from an interrupt context or a
|
||||
* normal process context.
|
||||
* Notes: Upon return, cmd is a stale pointer.
|
||||
*/
|
||||
int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
|
||||
{
|
||||
struct Scsi_Host *host = cmd->device->host;
|
||||
struct scsi_device *device = cmd->device;
|
||||
struct request_queue *q = device->request_queue;
|
||||
struct request *req = cmd->request;
|
||||
unsigned long flags;
|
||||
|
||||
SCSI_LOG_MLQUEUE(1,
|
||||
@ -188,9 +185,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
|
||||
* function. The SCSI request function detects the blocked condition
|
||||
* and plugs the queue appropriately.
|
||||
*/
|
||||
scsi_unprep_request(req);
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
blk_requeue_request(q, req);
|
||||
blk_requeue_request(q, cmd->request);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
scsi_run_queue(q);
|
||||
@ -451,7 +447,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
shost->host_busy--;
|
||||
if (unlikely((shost->shost_state == SHOST_RECOVERY) &&
|
||||
if (unlikely(scsi_host_in_recovery(shost) &&
|
||||
shost->host_failed))
|
||||
scsi_eh_wakeup(shost);
|
||||
spin_unlock(shost->host_lock);
|
||||
@ -1268,6 +1264,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
|
||||
}
|
||||
} else {
|
||||
memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
|
||||
cmd->cmd_len = req->cmd_len;
|
||||
if (rq_data_dir(req) == WRITE)
|
||||
cmd->sc_data_direction = DMA_TO_DEVICE;
|
||||
else if (req->data_len)
|
||||
@ -1342,7 +1339,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
|
||||
struct Scsi_Host *shost,
|
||||
struct scsi_device *sdev)
|
||||
{
|
||||
if (shost->shost_state == SHOST_RECOVERY)
|
||||
if (scsi_host_in_recovery(shost))
|
||||
return 0;
|
||||
if (shost->host_busy == 0 && shost->host_blocked) {
|
||||
/*
|
||||
@ -1514,7 +1511,6 @@ static void scsi_request_fn(struct request_queue *q)
|
||||
* cases (host limits or settings) should run the queue at some
|
||||
* later time.
|
||||
*/
|
||||
scsi_unprep_request(req);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
blk_requeue_request(q, req);
|
||||
sdev->device_busy--;
|
||||
|
@ -1466,23 +1466,17 @@ EXPORT_SYMBOL(scsi_scan_single_target);
|
||||
|
||||
void scsi_forget_host(struct Scsi_Host *shost)
|
||||
{
|
||||
struct scsi_target *starget, *tmp;
|
||||
struct scsi_device *sdev;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Ok, this look a bit strange. We always look for the first device
|
||||
* on the list as scsi_remove_device removes them from it - thus we
|
||||
* also have to release the lock.
|
||||
* We don't need to get another reference to the device before
|
||||
* releasing the lock as we already own the reference from
|
||||
* scsi_register_device that's release in scsi_remove_device. And
|
||||
* after that we don't look at sdev anymore.
|
||||
*/
|
||||
restart:
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
|
||||
list_for_each_entry(sdev, &shost->__devices, siblings) {
|
||||
if (sdev->sdev_state == SDEV_DEL)
|
||||
continue;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
scsi_remove_target(&starget->dev);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
__scsi_remove_device(sdev);
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ static struct {
|
||||
{ SHOST_CANCEL, "cancel" },
|
||||
{ SHOST_DEL, "deleted" },
|
||||
{ SHOST_RECOVERY, "recovery" },
|
||||
{ SHOST_CANCEL_RECOVERY, "cancel/recovery" },
|
||||
{ SHOST_DEL_RECOVERY, "deleted/recovery", },
|
||||
};
|
||||
const char *scsi_host_state_name(enum scsi_host_state state)
|
||||
{
|
||||
@ -707,9 +709,11 @@ void __scsi_remove_device(struct scsi_device *sdev)
|
||||
**/
|
||||
void scsi_remove_device(struct scsi_device *sdev)
|
||||
{
|
||||
down(&sdev->host->scan_mutex);
|
||||
struct Scsi_Host *shost = sdev->host;
|
||||
|
||||
down(&shost->scan_mutex);
|
||||
__scsi_remove_device(sdev);
|
||||
up(&sdev->host->scan_mutex);
|
||||
up(&shost->scan_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_remove_device);
|
||||
|
||||
@ -717,17 +721,20 @@ void __scsi_remove_target(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
unsigned long flags;
|
||||
struct scsi_device *sdev, *tmp;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
starget->reap_ref++;
|
||||
list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
|
||||
restart:
|
||||
list_for_each_entry(sdev, &shost->__devices, siblings) {
|
||||
if (sdev->channel != starget->channel ||
|
||||
sdev->id != starget->id)
|
||||
sdev->id != starget->id ||
|
||||
sdev->sdev_state == SDEV_DEL)
|
||||
continue;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
scsi_remove_device(sdev);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
scsi_target_reap(starget);
|
||||
|
@ -235,6 +235,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
|
||||
return 0;
|
||||
|
||||
memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
|
||||
SCpnt->cmd_len = rq->cmd_len;
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
SCpnt->sc_data_direction = DMA_TO_DEVICE;
|
||||
else if (rq->data_len)
|
||||
|
@ -1027,7 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
|
||||
if (sdp->detached)
|
||||
return -ENODEV;
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
if (sdp->device->host->shost_state == SHOST_RECOVERY)
|
||||
if (scsi_host_in_recovery(sdp->device->host))
|
||||
return -EBUSY;
|
||||
} else if (!scsi_block_when_processing_errors(sdp->device))
|
||||
return -EBUSY;
|
||||
|
@ -326,6 +326,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
|
||||
return 0;
|
||||
|
||||
memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
|
||||
SCpnt->cmd_len = rq->cmd_len;
|
||||
if (!rq->data_len)
|
||||
SCpnt->sc_data_direction = DMA_NONE;
|
||||
else if (rq_data_dir(rq) == WRITE)
|
||||
|
@ -4206,6 +4206,7 @@ static int st_init_command(struct scsi_cmnd *SCpnt)
|
||||
return 0;
|
||||
|
||||
memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
|
||||
SCpnt->cmd_len = rq->cmd_len;
|
||||
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
SCpnt->sc_data_direction = DMA_TO_DEVICE;
|
||||
|
@ -439,6 +439,8 @@ enum scsi_host_state {
|
||||
SHOST_CANCEL,
|
||||
SHOST_DEL,
|
||||
SHOST_RECOVERY,
|
||||
SHOST_CANCEL_RECOVERY,
|
||||
SHOST_DEL_RECOVERY,
|
||||
};
|
||||
|
||||
struct Scsi_Host {
|
||||
@ -465,8 +467,6 @@ struct Scsi_Host {
|
||||
|
||||
struct list_head eh_cmd_q;
|
||||
struct task_struct * ehandler; /* Error recovery thread. */
|
||||
struct semaphore * eh_wait; /* The error recovery thread waits
|
||||
on this. */
|
||||
struct semaphore * eh_action; /* Wait for specific actions on the
|
||||
host. */
|
||||
unsigned int eh_active:1; /* Indicates the eh thread is awake and active if
|
||||
@ -621,6 +621,13 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev)
|
||||
return container_of(dev, struct Scsi_Host, shost_gendev);
|
||||
}
|
||||
|
||||
static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
|
||||
{
|
||||
return shost->shost_state == SHOST_RECOVERY ||
|
||||
shost->shost_state == SHOST_CANCEL_RECOVERY ||
|
||||
shost->shost_state == SHOST_DEL_RECOVERY;
|
||||
}
|
||||
|
||||
extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
|
||||
extern void scsi_flush_work(struct Scsi_Host *);
|
||||
|
||||
|
@ -103,8 +103,8 @@ enum fc_port_state {
|
||||
incapable of reporting */
|
||||
#define FC_PORTSPEED_1GBIT 1
|
||||
#define FC_PORTSPEED_2GBIT 2
|
||||
#define FC_PORTSPEED_10GBIT 4
|
||||
#define FC_PORTSPEED_4GBIT 8
|
||||
#define FC_PORTSPEED_4GBIT 4
|
||||
#define FC_PORTSPEED_10GBIT 8
|
||||
#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user