summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/BusLogic.c83
-rw-r--r--drivers/scsi/BusLogic.h1
-rw-r--r--drivers/scsi/NCR5380.c61
-rw-r--r--drivers/scsi/NCR5380.h6
-rw-r--r--drivers/scsi/a2091.c3
-rw-r--r--drivers/scsi/a3000.c3
-rw-r--r--drivers/scsi/aacraid/aacraid.h6
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/src.c26
-rw-r--r--drivers/scsi/advansys.c1164
-rw-r--r--drivers/scsi/aha152x.c61
-rw-r--r--drivers/scsi/aha1740.c29
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c9
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h12
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c163
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c9
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h12
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c153
-rw-r--r--drivers/scsi/aic7xxx_old.c2
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx_proc.c221
-rw-r--r--drivers/scsi/arm/acornscsi.c58
-rw-r--r--drivers/scsi/arm/arxescsi.c40
-rw-r--r--drivers/scsi/arm/cumana_1.c1
-rw-r--r--drivers/scsi/arm/cumana_2.c43
-rw-r--r--drivers/scsi/arm/eesox.c42
-rw-r--r--drivers/scsi/arm/fas216.c31
-rw-r--r--drivers/scsi/arm/fas216.h6
-rw-r--r--drivers/scsi/arm/oak.c6
-rw-r--r--drivers/scsi/arm/powertec.c29
-rw-r--r--drivers/scsi/atari_NCR5380.c145
-rw-r--r--drivers/scsi/atari_scsi.c2
-rw-r--r--drivers/scsi/atari_scsi.h2
-rw-r--r--drivers/scsi/atp870u.c40
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c2
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h23
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c41
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c22
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c9
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h12
-rw-r--r--drivers/scsi/csiostor/Makefile3
-rw-r--r--drivers/scsi/csiostor/csio_hw.c564
-rw-r--r--drivers/scsi/csiostor/csio_hw.h47
-rw-r--r--drivers/scsi/csiostor/csio_hw_chip.h175
-rw-r--r--drivers/scsi/csiostor/csio_hw_t4.c403
-rw-r--r--drivers/scsi/csiostor/csio_hw_t5.c397
-rw-r--r--drivers/scsi/csiostor/csio_init.c48
-rw-r--r--drivers/scsi/csiostor/csio_init.h29
-rw-r--r--drivers/scsi/csiostor/csio_lnode.h2
-rw-r--r--drivers/scsi/csiostor/csio_mb.c12
-rw-r--r--drivers/scsi/csiostor/csio_rnode.c10
-rw-r--r--drivers/scsi/csiostor/csio_rnode.h2
-rw-r--r--drivers/scsi/csiostor/csio_wr.c60
-rw-r--r--drivers/scsi/dc395x.c20
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c17
-rw-r--r--drivers/scsi/dpt_i2o.c102
-rw-r--r--drivers/scsi/dtc.c3
-rw-r--r--drivers/scsi/dtc.h3
-rw-r--r--drivers/scsi/eata_pio.c56
-rw-r--r--drivers/scsi/fcoe/fcoe.c17
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c64
-rw-r--r--drivers/scsi/g_NCR5380.c51
-rw-r--r--drivers/scsi/gdth.c3
-rw-r--r--drivers/scsi/gdth.h3
-rw-r--r--drivers/scsi/gdth_proc.c211
-rw-r--r--drivers/scsi/gdth_proc.h5
-rw-r--r--drivers/scsi/gvp11.c3
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/imm.c40
-rw-r--r--drivers/scsi/in2000.c178
-rw-r--r--drivers/scsi/ipr.c13
-rw-r--r--drivers/scsi/ips.c238
-rw-r--r--drivers/scsi/ips.h9
-rw-r--r--drivers/scsi/isci/init.c6
-rw-r--r--drivers/scsi/iscsi_tcp.c18
-rw-r--r--drivers/scsi/libfc/fc_disc.c26
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/libsas/sas_expander.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c1109
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c21
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c74
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c139
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c24
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c1
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c118
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac_scsi.c3
-rw-r--r--drivers/scsi/mac_scsi.h3
-rw-r--r--drivers/scsi/megaraid.c1040
-rw-r--r--drivers/scsi/megaraid.h17
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c4
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c14
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c14
-rw-r--r--drivers/scsi/mvme147.c3
-rw-r--r--drivers/scsi/mvsas/mv_init.c6
-rw-r--r--drivers/scsi/mvumi.c4
-rw-r--r--drivers/scsi/mvumi.h1
-rw-r--r--drivers/scsi/nsp32.c39
-rw-r--r--drivers/scsi/osd/osd_initiator.c2
-rw-r--r--drivers/scsi/pas16.c3
-rw-r--r--drivers/scsi/pas16.h3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c36
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h9
-rw-r--r--drivers/scsi/pmcraid.c14
-rw-r--r--drivers/scsi/ppa.c36
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c154
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c30
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h237
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h50
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c56
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h41
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c67
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c20
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c68
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c3476
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h510
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c214
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c28
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.h10
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h19
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h38
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h9
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c47
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c120
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c21
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c1731
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi_debug.c53
-rw-r--r--drivers/scsi/scsi_netlink.c4
-rw-r--r--drivers/scsi/scsi_proc.c74
-rw-r--r--drivers/scsi/scsi_transport_fc.c21
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c1072
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/sg.c1
-rw-r--r--drivers/scsi/sr.c3
-rw-r--r--drivers/scsi/st.c8
-rw-r--r--drivers/scsi/sun3_NCR5380.c183
-rw-r--r--drivers/scsi/sun3_scsi.c1
-rw-r--r--drivers/scsi/sun3_scsi.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c115
-rw-r--r--drivers/scsi/t128.c3
-rw-r--r--drivers/scsi/t128.h3
-rw-r--r--drivers/scsi/virtio_scsi.c487
-rw-r--r--drivers/scsi/wd33c93.c194
-rw-r--r--drivers/scsi/wd33c93.h3
-rw-r--r--drivers/scsi/wd7000.c31
160 files changed, 12142 insertions, 5365 deletions
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index d7ca247efa35..344d87599cd2 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -3201,26 +3201,30 @@ static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_de
BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>.
*/
-static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, int WriteFlag)
+static int BusLogic_write_info(struct Scsi_Host *shost, char *ProcBuffer, int BytesAvailable)
{
struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) shost->hostdata;
struct BusLogic_TargetStatistics *TargetStatistics;
- int TargetID, Length;
- char *Buffer;
TargetStatistics = HostAdapter->TargetStatistics;
- if (WriteFlag) {
- HostAdapter->ExternalHostAdapterResets = 0;
- HostAdapter->HostAdapterInternalErrors = 0;
- memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics));
- return 0;
- }
- Buffer = HostAdapter->MessageBuffer;
- Length = HostAdapter->MessageBufferLength;
- Length += sprintf(&Buffer[Length], "\n\
+ HostAdapter->ExternalHostAdapterResets = 0;
+ HostAdapter->HostAdapterInternalErrors = 0;
+ memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics));
+ return 0;
+}
+
+static int BusLogic_show_info(struct seq_file *m, struct Scsi_Host *shost)
+{
+ struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) shost->hostdata;
+ struct BusLogic_TargetStatistics *TargetStatistics;
+ int TargetID;
+
+ TargetStatistics = HostAdapter->TargetStatistics;
+ seq_write(m, HostAdapter->MessageBuffer, HostAdapter->MessageBufferLength);
+ seq_printf(m, "\n\
Current Driver Queue Depth: %d\n\
Currently Allocated CCBs: %d\n", HostAdapter->DriverQueueDepth, HostAdapter->AllocatedCCBs);
- Length += sprintf(&Buffer[Length], "\n\n\
+ seq_printf(m, "\n\n\
DATA TRANSFER STATISTICS\n\
\n\
Target Tagged Queuing Queue Depth Active Attempted Completed\n\
@@ -3229,66 +3233,62 @@ Target Tagged Queuing Queue Depth Active Attempted Completed\n\
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (!TargetFlags->TargetExists)
continue;
- Length += sprintf(&Buffer[Length], " %2d %s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? " Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
+ seq_printf(m, " %2d %s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? " Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
? " Permitted" : " Disabled"))
: "Not Supported"));
- Length += sprintf(&Buffer[Length],
+ seq_printf(m,
" %3d %3u %9u %9u\n", HostAdapter->QueueDepth[TargetID], HostAdapter->ActiveCommands[TargetID], TargetStatistics[TargetID].CommandsAttempted, TargetStatistics[TargetID].CommandsCompleted);
}
- Length += sprintf(&Buffer[Length], "\n\
+ seq_printf(m, "\n\
Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\
====== ============= ============== =================== ===================\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (!TargetFlags->TargetExists)
continue;
- Length += sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands);
+ seq_printf(m, " %2d %9u %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands);
if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0)
- Length += sprintf(&Buffer[Length], " %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units);
+ seq_printf(m, " %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units);
else
- Length += sprintf(&Buffer[Length], " %9u", TargetStatistics[TargetID].TotalBytesRead.Units);
+ seq_printf(m, " %9u", TargetStatistics[TargetID].TotalBytesRead.Units);
if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0)
- Length += sprintf(&Buffer[Length], " %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units);
+ seq_printf(m, " %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units);
else
- Length += sprintf(&Buffer[Length], " %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units);
+ seq_printf(m, " %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units);
}
- Length += sprintf(&Buffer[Length], "\n\
+ seq_printf(m, "\n\
Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\
====== ======= ========= ========= ========= ========= =========\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (!TargetFlags->TargetExists)
continue;
- Length +=
- sprintf(&Buffer[Length],
+ seq_printf(m,
" %2d Read %9u %9u %9u %9u %9u\n", TargetID,
TargetStatistics[TargetID].ReadCommandSizeBuckets[0],
TargetStatistics[TargetID].ReadCommandSizeBuckets[1], TargetStatistics[TargetID].ReadCommandSizeBuckets[2], TargetStatistics[TargetID].ReadCommandSizeBuckets[3], TargetStatistics[TargetID].ReadCommandSizeBuckets[4]);
- Length +=
- sprintf(&Buffer[Length],
+ seq_printf(m,
" %2d Write %9u %9u %9u %9u %9u\n", TargetID,
TargetStatistics[TargetID].WriteCommandSizeBuckets[0],
TargetStatistics[TargetID].WriteCommandSizeBuckets[1], TargetStatistics[TargetID].WriteCommandSizeBuckets[2], TargetStatistics[TargetID].WriteCommandSizeBuckets[3], TargetStatistics[TargetID].WriteCommandSizeBuckets[4]);
}
- Length += sprintf(&Buffer[Length], "\n\
+ seq_printf(m, "\n\
Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\
====== ======= ========= ========= ========= ========= =========\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (!TargetFlags->TargetExists)
continue;
- Length +=
- sprintf(&Buffer[Length],
+ seq_printf(m,
" %2d Read %9u %9u %9u %9u %9u\n", TargetID,
TargetStatistics[TargetID].ReadCommandSizeBuckets[5],
TargetStatistics[TargetID].ReadCommandSizeBuckets[6], TargetStatistics[TargetID].ReadCommandSizeBuckets[7], TargetStatistics[TargetID].ReadCommandSizeBuckets[8], TargetStatistics[TargetID].ReadCommandSizeBuckets[9]);
- Length +=
- sprintf(&Buffer[Length],
+ seq_printf(m,
" %2d Write %9u %9u %9u %9u %9u\n", TargetID,
TargetStatistics[TargetID].WriteCommandSizeBuckets[5],
TargetStatistics[TargetID].WriteCommandSizeBuckets[6], TargetStatistics[TargetID].WriteCommandSizeBuckets[7], TargetStatistics[TargetID].WriteCommandSizeBuckets[8], TargetStatistics[TargetID].WriteCommandSizeBuckets[9]);
}
- Length += sprintf(&Buffer[Length], "\n\n\
+ seq_printf(m, "\n\n\
ERROR RECOVERY STATISTICS\n\
\n\
Command Aborts Bus Device Resets Host Adapter Resets\n\
@@ -3299,20 +3299,12 @@ Target Requested Completed Requested Completed Requested Completed\n\
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (!TargetFlags->TargetExists)
continue;
- Length += sprintf(&Buffer[Length], "\
+ seq_printf(m, "\
%2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, TargetStatistics[TargetID].CommandAbortsRequested, TargetStatistics[TargetID].CommandAbortsAttempted, TargetStatistics[TargetID].CommandAbortsCompleted, TargetStatistics[TargetID].BusDeviceResetsRequested, TargetStatistics[TargetID].BusDeviceResetsAttempted, TargetStatistics[TargetID].BusDeviceResetsCompleted, TargetStatistics[TargetID].HostAdapterResetsRequested, TargetStatistics[TargetID].HostAdapterResetsAttempted, TargetStatistics[TargetID].HostAdapterResetsCompleted);
}
- Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets);
- Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors);
- if (Length >= BusLogic_MessageBufferSize)
- BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize);
- if ((Length -= Offset) <= 0)
- return 0;
- if (Length >= BytesAvailable)
- Length = BytesAvailable;
- memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length);
- *StartPointer = ProcBuffer;
- return Length;
+ seq_printf(m, "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets);
+ seq_printf(m, "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors);
+ return 0;
}
@@ -3566,7 +3558,8 @@ static int __init BusLogic_ParseDriverOptions(char *OptionsString)
static struct scsi_host_template Bus_Logic_template = {
.module = THIS_MODULE,
.proc_name = "BusLogic",
- .proc_info = BusLogic_ProcDirectoryInfo,
+ .write_info = BusLogic_write_info,
+ .show_info = BusLogic_show_info,
.name = "BusLogic",
.info = BusLogic_DriverInfo,
.queuecommand = BusLogic_QueueCommand,
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 649fcb31f26d..6c6c13c3be1b 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -1321,7 +1321,6 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T Co
static const char *BusLogic_DriverInfo(struct Scsi_Host *);
static int BusLogic_QueueCommand(struct Scsi_Host *h, struct scsi_cmnd *);
static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
-static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
static int BusLogic_SlaveConfigure(struct scsi_device *);
static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *);
static irqreturn_t BusLogic_InterruptHandler(int, void *);
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 450353e04dde..1e9d6ad9302b 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -695,33 +695,35 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
* Return the number of bytes read from or written
*/
+static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
+ char *buffer, int length)
+{
+#ifdef DTC_PUBLIC_RELEASE
+ dtc_wmaxi = dtc_maxi = 0;
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+ pas_wmaxi = pas_maxi = 0;
+#endif
+ return (-ENOSYS); /* Currently this is a no-op */
+}
+
#undef SPRINTF
-#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)
+#define SPRINTF(args...) seq_printf(m, ## args)
static
-char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length);
+void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m);
static
-char *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len);
+void lprint_command(unsigned char *cmd, struct seq_file *m);
static
-char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
+void lprint_opcode(int opcode, struct seq_file *m);
-static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
- char *buffer, char **start, off_t offset, int length, int inout)
+static int __maybe_unused NCR5380_show_info(struct seq_file *m,
+ struct Scsi_Host *instance)
{
- char *pos = buffer;
struct NCR5380_hostdata *hostdata;
Scsi_Cmnd *ptr;
hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- if (inout) { /* Has data been written to the file ? */
-#ifdef DTC_PUBLIC_RELEASE
- dtc_wmaxi = dtc_maxi = 0;
-#endif
-#ifdef PAS16_PUBLIC_RELEASE
- pas_wmaxi = pas_maxi = 0;
-#endif
- return (-ENOSYS); /* Currently this is a no-op */
- }
SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE);
if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400)
SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE);
@@ -755,46 +757,37 @@ static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
if (!hostdata->connected)
SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
else
- pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length);
+ lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
SPRINTF("scsi%d: issue_queue\n", instance->host_no);
for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ lprint_Scsi_Cmnd(ptr, m);
SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ lprint_Scsi_Cmnd(ptr, m);
spin_unlock_irq(instance->host_lock);
-
- *start = buffer;
- if (pos - buffer < offset)
- return 0;
- else if (pos - buffer - offset < length)
- return pos - buffer - offset;
- return length;
+ return 0;
}
-static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length)
+static void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m)
{
SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
SPRINTF(" command = ");
- pos = lprint_command(cmd->cmnd, pos, buffer, length);
- return (pos);
+ lprint_command(cmd->cmnd, m);
}
-static char *lprint_command(unsigned char *command, char *pos, char *buffer, int length)
+static void lprint_command(unsigned char *command, struct seq_file *m)
{
int i, s;
- pos = lprint_opcode(command[0], pos, buffer, length);
+ lprint_opcode(command[0], m);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
SPRINTF("%02x ", command[i]);
SPRINTF("\n");
- return (pos);
}
-static char *lprint_opcode(int opcode, char *pos, char *buffer, int length)
+static void lprint_opcode(int opcode, struct seq_file *m)
{
SPRINTF("%2d (0x%02x)", opcode, opcode);
- return (pos);
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index fd40a32b1f6f..14964d0a0e9d 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -314,8 +314,10 @@ static void NCR5380_print(struct Scsi_Host *instance);
static int NCR5380_abort(Scsi_Cmnd * cmd);
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
- char *buffer, char **start, off_t offset, int length, int inout);
+static int __maybe_unused NCR5380_show_info(struct seq_file *,
+ struct Scsi_Host *);
+static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
+ char *buffer, int length);
static void NCR5380_reselect(struct Scsi_Host *instance);
static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 3e09aa21c1ca..30fa38a0ad39 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -166,7 +166,8 @@ static int a2091_bus_reset(struct scsi_cmnd *cmd)
static struct scsi_host_template a2091_scsi_template = {
.module = THIS_MODULE,
.name = "Commodore A2091/A590 SCSI",
- .proc_info = wd33c93_proc_info,
+ .show_info = wd33c93_show_info,
+ .write_info = wd33c93_write_info,
.proc_name = "A2901",
.queuecommand = wd33c93_queuecommand,
.eh_abort_handler = wd33c93_abort,
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index e29fe0e708f8..c487916a9d45 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -181,7 +181,8 @@ static int a3000_bus_reset(struct scsi_cmnd *cmd)
static struct scsi_host_template amiga_a3000_scsi_template = {
.module = THIS_MODULE,
.name = "Amiga 3000 built-in SCSI",
- .proc_info = wd33c93_proc_info,
+ .show_info = wd33c93_show_info,
+ .write_info = wd33c93_write_info,
.proc_name = "A3000",
.queuecommand = wd33c93_queuecommand,
.eh_abort_handler = wd33c93_abort,
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index a6f7190c09a4..9323d058706b 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 30000
+# define AAC_DRIVER_BUILD 30200
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -1918,6 +1918,10 @@ extern struct aac_common aac_config;
#define MONITOR_PANIC 0x00000020
#define KERNEL_UP_AND_RUNNING 0x00000080
#define KERNEL_PANIC 0x00000100
+#define FLASH_UPD_PENDING 0x00002000
+#define FLASH_UPD_SUCCESS 0x00004000
+#define FLASH_UPD_FAILED 0x00008000
+#define FWUPD_TIMEOUT (5 * 60)
/*
* Doorbell bit defines
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 3f759957f4b4..177b094c7792 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -214,7 +214,7 @@ int aac_send_shutdown(struct aac_dev * dev)
cmd = (struct aac_close *) fib_data(fibctx);
cmd->command = cpu_to_le32(VM_CloseAll);
- cmd->cid = cpu_to_le32(0xffffffff);
+ cmd->cid = cpu_to_le32(0xfffffffe);
status = aac_fib_send(ContainerCommand,
fibctx,
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index e2e349204e7d..0f56d8d7524f 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -703,6 +703,28 @@ int aac_srcv_init(struct aac_dev *dev)
!aac_src_restart_adapter(dev, 0))
++restart;
/*
+ * Check to see if flash update is running.
+ * Wait for the adapter to be up and running. Wait up to 5 minutes
+ */
+ status = src_readl(dev, MUnit.OMR);
+ if (status & FLASH_UPD_PENDING) {
+ start = jiffies;
+ do {
+ status = src_readl(dev, MUnit.OMR);
+ if (time_after(jiffies, start+HZ*FWUPD_TIMEOUT)) {
+ printk(KERN_ERR "%s%d: adapter flash update failed.\n",
+ dev->name, instance);
+ goto error_iounmap;
+ }
+ } while (!(status & FLASH_UPD_SUCCESS) &&
+ !(status & FLASH_UPD_FAILED));
+ /* Delay 10 seconds.
+ * Because right now FW is doing a soft reset,
+ * do not read scratch pad register at this time
+ */
+ ssleep(10);
+ }
+ /*
* Check to see if the board panic'd while booting.
*/
status = src_readl(dev, MUnit.OMR);
@@ -730,7 +752,9 @@ int aac_srcv_init(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
*/
- while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) {
+ while (!((status = src_readl(dev, MUnit.OMR)) &
+ KERNEL_UP_AND_RUNNING) ||
+ status == 0xffffffff) {
if ((restart &&
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
time_after(jiffies, start+HZ*startup_timeout)) {
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index dcfaee66a8b9..c67e401954c5 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -2178,22 +2178,6 @@ do { \
#define ASC_INFO_SIZE 128 /* advansys_info() line size */
-#ifdef CONFIG_PROC_FS
-/* /proc/scsi/advansys/[0...] related definitions */
-#define ASC_PRTBUF_SIZE 2048
-#define ASC_PRTLINE_SIZE 160
-
-#define ASC_PRT_NEXT() \
- if (cp) { \
- totlen += len; \
- leftlen -= len; \
- if (leftlen == 0) { \
- return totlen; \
- } \
- cp += len; \
- }
-#endif /* CONFIG_PROC_FS */
-
/* Asc Library return codes */
#define ASC_TRUE 1
#define ASC_FALSE 0
@@ -2384,7 +2368,6 @@ struct asc_board {
} eep_config;
ulong last_reset; /* Saved last reset time */
/* /proc/scsi/advansys/[0...] */
- char *prtbuf; /* /proc print buffer */
#ifdef ADVANSYS_STATS
struct asc_stats asc_stats; /* Board statistics */
#endif /* ADVANSYS_STATS */
@@ -2875,64 +2858,21 @@ static const char *advansys_info(struct Scsi_Host *shost)
}
#ifdef CONFIG_PROC_FS
-/*
- * asc_prt_line()
- *
- * If 'cp' is NULL print to the console, otherwise print to a buffer.
- *
- * Return 0 if printing to the console, otherwise return the number of
- * bytes written to the buffer.
- *
- * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
- * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
- */
-static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
-{
- va_list args;
- int ret;
- char s[ASC_PRTLINE_SIZE];
-
- va_start(args, fmt);
- ret = vsprintf(s, fmt, args);
- BUG_ON(ret >= ASC_PRTLINE_SIZE);
- if (buf == NULL) {
- (void)printk(s);
- ret = 0;
- } else {
- ret = min(buflen, ret);
- memcpy(buf, s, ret);
- }
- va_end(args);
- return ret;
-}
/*
* asc_prt_board_devices()
*
* Print driver information for devices attached to the board.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_board_devices(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
- int leftlen;
- int totlen;
- int len;
int chip_scsi_id;
int i;
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
- "\nDevice Information for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "\nDevice Information for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
if (ASC_NARROW_BOARD(boardp)) {
chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
@@ -2940,60 +2880,42 @@ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
}
- len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
- ASC_PRT_NEXT();
+ seq_printf(m, "Target IDs Detected:");
for (i = 0; i <= ADV_MAX_TID; i++) {
- if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X,", i);
- ASC_PRT_NEXT();
- }
+ if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i))
+ seq_printf(m, " %X,", i);
}
- len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
- ASC_PRT_NEXT();
-
- return totlen;
+ seq_printf(m, " (%X=Host Adapter)\n", chip_scsi_id);
}
/*
* Display Wide Board BIOS Information.
*/
-static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_adv_bios(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
- int leftlen;
- int totlen;
- int len;
ushort major, minor, letter;
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
- ASC_PRT_NEXT();
+ seq_printf(m, "\nROM BIOS Version: ");
/*
* If the BIOS saved a valid signature, then fill in
* the BIOS code segment base address.
*/
if (boardp->bios_signature != 0x55AA) {
- len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "Disabled or Pre-3.1\n");
+ seq_printf(m,
+ "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+ seq_printf(m,
+ "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
} else {
major = (boardp->bios_version >> 12) & 0xF;
minor = (boardp->bios_version >> 8) & 0xF;
letter = (boardp->bios_version & 0xFF);
- len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+ seq_printf(m, "%d.%d%c\n",
major, minor,
letter >= 26 ? '?' : letter + 'A');
- ASC_PRT_NEXT();
-
/*
* Current available ROM BIOS release is 3.1I for UW
* and 3.2I for U2W. This code doesn't differentiate
@@ -3001,16 +2923,12 @@ static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
*/
if (major < 3 || (major <= 3 && minor < 1) ||
(major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
- len = asc_prt_line(cp, leftlen,
- "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- "ftp://ftp.connectcom.net/pub\n");
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
+ seq_printf(m,
+ "ftp://ftp.connectcom.net/pub\n");
}
}
-
- return totlen;
}
/*
@@ -3115,20 +3033,11 @@ static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
* asc_prt_asc_board_eeprom()
*
* Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp;
- int leftlen;
- int totlen;
- int len;
ASCEEP_CONFIG *ep;
int i;
#ifdef CONFIG_ISA
@@ -3139,129 +3048,75 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
ep = &boardp->eep_config.asc_eep;
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
- "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
- == ASC_TRUE) {
- len =
- asc_prt_line(cp, leftlen, " Serial Number: %s\n",
- serialstr);
- ASC_PRT_NEXT();
- } else {
- if (ep->adapter_info[5] == 0xBB) {
- len = asc_prt_line(cp, leftlen,
- " Default Settings Used for EEPROM-less Adapter.\n");
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.\n");
- ASC_PRT_NEXT();
- }
- }
-
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
- ep->max_tag_qng);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
- " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->
- disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->
- use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->
- start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep->
- init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ == ASC_TRUE)
+ seq_printf(m, " Serial Number: %s\n", serialstr);
+ else if (ep->adapter_info[5] == 0xBB)
+ seq_printf(m,
+ " Default Settings Used for EEPROM-less Adapter.\n");
+ else
+ seq_printf(m,
+ " Serial Number Signature Not Present.\n");
+
+ seq_printf(m,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
+ ep->max_tag_qng);
+
+ seq_printf(m,
+ " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
+
+ seq_printf(m, " Target ID: ");
+ for (i = 0; i <= ASC_MAX_TID; i++)
+ seq_printf(m, " %d", i);
+ seq_printf(m, "\n");
+
+ seq_printf(m, " Disconnects: ");
+ for (i = 0; i <= ASC_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
+
+ seq_printf(m, " Command Queuing: ");
+ for (i = 0; i <= ASC_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
+
+ seq_printf(m, " Start Motor: ");
+ for (i = 0; i <= ASC_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
+
+ seq_printf(m, " Synchronous Transfer:");
+ for (i = 0; i <= ASC_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
#ifdef CONFIG_ISA
if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- len = asc_prt_line(cp, leftlen,
- " Host ISA DMA speed: %d MB/S\n",
- isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " Host ISA DMA speed: %d MB/S\n",
+ isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
}
#endif /* CONFIG_ISA */
-
- return totlen;
}
/*
* asc_prt_adv_board_eeprom()
*
* Print board EEPROM configuration.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
ADV_DVC_VAR *adv_dvc_varp;
- int leftlen;
- int totlen;
- int len;
int i;
char *termstr;
uchar serialstr[13];
@@ -3281,13 +3136,9 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
}
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
- "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
wordp = &ep_3550->serial_number_word1;
@@ -3297,38 +3148,28 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
wordp = &ep_38C1600->serial_number_word1;
}
- if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
- len =
- asc_prt_line(cp, leftlen, " Serial Number: %s\n",
- serialstr);
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Serial Number Signature Not Present.\n");
- ASC_PRT_NEXT();
- }
+ if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE)
+ seq_printf(m, " Serial Number: %s\n", serialstr);
+ else
+ seq_printf(m, " Serial Number Signature Not Present.\n");
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_3550->adapter_scsi_id,
- ep_3550->max_host_qng, ep_3550->max_dvc_qng);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_38C0800->adapter_scsi_id,
- ep_38C0800->max_host_qng,
- ep_38C0800->max_dvc_qng);
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
- ep_38C1600->adapter_scsi_id,
- ep_38C1600->max_host_qng,
- ep_38C1600->max_dvc_qng);
- ASC_PRT_NEXT();
- }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ seq_printf(m,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_3550->adapter_scsi_id,
+ ep_3550->max_host_qng, ep_3550->max_dvc_qng);
+ else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+ seq_printf(m,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_38C0800->adapter_scsi_id,
+ ep_38C0800->max_host_qng,
+ ep_38C0800->max_dvc_qng);
+ else
+ seq_printf(m,
+ " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep_38C1600->adapter_scsi_id,
+ ep_38C1600->max_host_qng,
+ ep_38C1600->max_dvc_qng);
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->termination;
} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
@@ -3352,34 +3193,26 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
break;
}
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_3550->termination, termstr,
- ep_3550->bios_ctrl);
- ASC_PRT_NEXT();
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_38C0800->termination_lvd, termstr,
- ep_38C0800->bios_ctrl);
- ASC_PRT_NEXT();
- } else {
- len = asc_prt_line(cp, leftlen,
- " termination: %u (%s), bios_ctrl: 0x%x\n",
- ep_38C1600->termination_lvd, termstr,
- ep_38C1600->bios_ctrl);
- ASC_PRT_NEXT();
- }
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+ seq_printf(m,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_3550->termination, termstr,
+ ep_3550->bios_ctrl);
+ else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+ seq_printf(m,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_38C0800->termination_lvd, termstr,
+ ep_38C0800->bios_ctrl);
+ else
+ seq_printf(m,
+ " termination: %u (%s), bios_ctrl: 0x%x\n",
+ ep_38C1600->termination_lvd, termstr,
+ ep_38C1600->bios_ctrl);
- len = asc_prt_line(cp, leftlen, " Target ID: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %X", i);
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Target ID: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %X", i);
+ seq_printf(m, "\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->disc_enable;
@@ -3388,15 +3221,11 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
} else {
word = ep_38C1600->disc_enable;
}
- len = asc_prt_line(cp, leftlen, " Disconnects: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Disconnects: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->tagqng_able;
@@ -3405,15 +3234,11 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
} else {
word = ep_38C1600->tagqng_able;
}
- len = asc_prt_line(cp, leftlen, " Command Queuing: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Queuing: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->start_motor;
@@ -3422,42 +3247,28 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
} else {
word = ep_38C1600->start_motor;
}
- len = asc_prt_line(cp, leftlen, " Start Motor: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Start Motor: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->
- sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
- 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Synchronous Transfer:");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
+ 'Y' : 'N');
+ seq_printf(m, "\n");
}
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (ep_3550->
- ultra_able & ADV_TID_TO_TIDMASK(i))
- ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Ultra Transfer: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i))
+ ? 'Y' : 'N');
+ seq_printf(m, "\n");
}
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
@@ -3467,21 +3278,16 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
} else {
word = ep_38C1600->wdtr_able;
}
- len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ADV_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %c",
- (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, " Wide Transfer: ");
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ seq_printf(m, " %c",
+ (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ seq_printf(m, "\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
- len = asc_prt_line(cp, leftlen,
- " Synchronous Transfer Speed (Mhz):\n ");
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " Synchronous Transfer Speed (Mhz):\n ");
for (i = 0; i <= ADV_MAX_TID; i++) {
char *speed_str;
@@ -3517,99 +3323,64 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
speed_str = "Unk";
break;
}
- len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
- ASC_PRT_NEXT();
- if (i == 7) {
- len = asc_prt_line(cp, leftlen, "\n ");
- ASC_PRT_NEXT();
- }
+ seq_printf(m, "%X:%s ", i, speed_str);
+ if (i == 7)
+ seq_printf(m, "\n ");
sdtr_speed >>= 4;
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
}
-
- return totlen;
}
/*
* asc_prt_driver_conf()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_driver_conf(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
- int leftlen;
- int totlen;
- int len;
int chip_scsi_id;
- leftlen = cplen;
- totlen = len = 0;
+ seq_printf(m,
+ "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
- len = asc_prt_line(cp, leftlen,
- "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " host_busy %u, last_reset %lu, max_id %u, max_lun %u, max_channel %u\n",
+ shost->host_busy, shost->last_reset, shost->max_id,
+ shost->max_lun, shost->max_channel);
- len = asc_prt_line(cp, leftlen,
- " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
- shost->host_busy, shost->last_reset, shost->max_id,
- shost->max_lun, shost->max_channel);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+ shost->unique_id, shost->can_queue, shost->this_id,
+ shost->sg_tablesize, shost->cmd_per_lun);
- len = asc_prt_line(cp, leftlen,
- " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
- shost->unique_id, shost->can_queue, shost->this_id,
- shost->sg_tablesize, shost->cmd_per_lun);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " unchecked_isa_dma %d, use_clustering %d\n",
+ shost->unchecked_isa_dma, shost->use_clustering);
- len = asc_prt_line(cp, leftlen,
- " unchecked_isa_dma %d, use_clustering %d\n",
- shost->unchecked_isa_dma, shost->use_clustering);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " flags 0x%x, last_reset 0x%lx, jiffies 0x%lx, asc_n_io_port 0x%x\n",
+ boardp->flags, boardp->last_reset, jiffies,
+ boardp->asc_n_io_port);
- len = asc_prt_line(cp, leftlen,
- " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
- boardp->flags, boardp->last_reset, jiffies,
- boardp->asc_n_io_port);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
- ASC_PRT_NEXT();
+ seq_printf(m, " io_port 0x%lx\n", shost->io_port);
if (ASC_NARROW_BOARD(boardp)) {
chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
} else {
chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
}
-
- return totlen;
}
/*
* asc_prt_asc_board_info()
*
* Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
int chip_scsi_id;
- int leftlen;
- int totlen;
- int len;
ASC_DVC_VAR *v;
ASC_DVC_CFG *c;
int i;
@@ -3619,105 +3390,79 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
c = &boardp->dvc_cfg.asc_dvc_cfg;
chip_scsi_id = c->chip_scsi_id;
- leftlen = cplen;
- totlen = len = 0;
+ seq_printf(m,
+ "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
- len = asc_prt_line(cp, leftlen,
- "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
- "mcode_version 0x%x, err_code %u\n",
- c->chip_version, c->mcode_date, c->mcode_version,
- v->err_code);
- ASC_PRT_NEXT();
+ seq_printf(m, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x, err_code %u\n",
+ c->chip_version, c->mcode_date, c->mcode_version,
+ v->err_code);
/* Current number of commands waiting for the host. */
- len = asc_prt_line(cp, leftlen,
- " Total Command Pending: %d\n", v->cur_total_qng);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " Total Command Pending: %d\n", v->cur_total_qng);
- len = asc_prt_line(cp, leftlen, " Command Queuing:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Queuing:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i,
- (v->
- use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
- 'Y' : 'N');
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%c",
+ i,
+ (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
/* Current number of commands waiting for a device. */
- len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Queue Pending:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%u", i, v->cur_dvc_qng[i]);
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
/* Current limit on number of commands that can be sent to a device. */
- len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Queue Limit:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%u", i, v->max_dvc_qng[i]);
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
/* Indicate whether the device has returned queue full status. */
- len = asc_prt_line(cp, leftlen, " Command Queue Full:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Queue Full:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
- len = asc_prt_line(cp, leftlen, " %X:Y-%d",
- i, boardp->queue_full_cnt[i]);
- } else {
- len = asc_prt_line(cp, leftlen, " %X:N", i);
- }
- ASC_PRT_NEXT();
+ if (boardp->queue_full & ADV_TID_TO_TIDMASK(i))
+ seq_printf(m, " %X:Y-%d",
+ i, boardp->queue_full_cnt[i]);
+ else
+ seq_printf(m, " %X:N", i);
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
- len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Synchronous Transfer:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i,
- (v->
- sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%c",
+ i,
+ (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
for (i = 0; i <= ASC_MAX_TID; i++) {
uchar syn_period_ix;
@@ -3728,69 +3473,48 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:", i);
if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
+ seq_printf(m, " Asynchronous");
} else {
syn_period_ix =
(boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
1);
- len = asc_prt_line(cp, leftlen,
- " Transfer Period Factor: %d (%d.%d Mhz),",
- v->sdtr_period_tbl[syn_period_ix],
- 250 /
- v->sdtr_period_tbl[syn_period_ix],
- ASC_TENTHS(250,
- v->
- sdtr_period_tbl
- [syn_period_ix]));
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " Transfer Period Factor: %d (%d.%d Mhz),",
+ v->sdtr_period_tbl[syn_period_ix],
+ 250 / v->sdtr_period_tbl[syn_period_ix],
+ ASC_TENTHS(250,
+ v->sdtr_period_tbl[syn_period_ix]));
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- boardp->
- sdtr_data[i] & ASC_SYN_MAX_OFFSET);
- ASC_PRT_NEXT();
+ seq_printf(m, " REQ/ACK Offset: %d",
+ boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
}
if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*\n");
+ seq_printf(m, "*\n");
renegotiate = 1;
} else {
- len = asc_prt_line(cp, leftlen, "\n");
+ seq_printf(m, "\n");
}
- ASC_PRT_NEXT();
}
if (renegotiate) {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.\n");
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " * = Re-negotiation pending before next command.\n");
}
-
- return totlen;
}
/*
* asc_prt_adv_board_info()
*
* Print dynamic board configuration information.
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
- int leftlen;
- int totlen;
- int len;
int i;
ADV_DVC_VAR *v;
ADV_DVC_CFG *c;
@@ -3809,47 +3533,35 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
iop_base = v->iop_base;
chip_scsi_id = v->chip_scsi_id;
- leftlen = cplen;
- totlen = len = 0;
-
- len = asc_prt_line(cp, leftlen,
- "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
- len = asc_prt_line(cp, leftlen,
- " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
- v->iop_base,
- AdvReadWordRegister(iop_base,
- IOPW_SCSI_CFG1) & CABLE_DETECT,
- v->err_code);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+ (unsigned long)v->iop_base,
+ AdvReadWordRegister(iop_base,IOPW_SCSI_CFG1) & CABLE_DETECT,
+ v->err_code);
- len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
- "mcode_version 0x%x\n", c->chip_version,
- c->mcode_date, c->mcode_version);
- ASC_PRT_NEXT();
+ seq_printf(m, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x\n", c->chip_version,
+ c->mcode_date, c->mcode_version);
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Queuing Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i,
- (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%c",
+ i,
+ (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
- len = asc_prt_line(cp, leftlen, " Queue Limit:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Queue Limit:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3859,14 +3571,11 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
lrambyte);
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%d", i, lrambyte);
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
- len = asc_prt_line(cp, leftlen, " Command Pending:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Command Pending:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3876,33 +3585,26 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
lrambyte);
- len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%d", i, lrambyte);
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- len = asc_prt_line(cp, leftlen, " Wide Enabled:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Wide Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i,
- (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%c",
+ i,
+ (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
- len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Transfer Bit Width:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3913,37 +3615,30 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
lramword);
- len = asc_prt_line(cp, leftlen, " %X:%d",
- i, (lramword & 0x8000) ? 16 : 8);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%d",
+ i, (lramword & 0x8000) ? 16 : 8);
if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
(wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*");
- ASC_PRT_NEXT();
+ seq_printf(m, "*");
renegotiate = 1;
}
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
- ASC_PRT_NEXT();
+ seq_printf(m, " Synchronous Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:%c",
- i,
- (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
- 'N');
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:%c",
+ i,
+ (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
+ seq_printf(m, "\n");
AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
for (i = 0; i <= ADV_MAX_TID; i++) {
@@ -3959,358 +3654,170 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
continue;
}
- len = asc_prt_line(cp, leftlen, " %X:", i);
- ASC_PRT_NEXT();
+ seq_printf(m, " %X:", i);
if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
- len = asc_prt_line(cp, leftlen, " Asynchronous");
- ASC_PRT_NEXT();
+ seq_printf(m, " Asynchronous");
} else {
- len =
- asc_prt_line(cp, leftlen,
- " Transfer Period Factor: ");
- ASC_PRT_NEXT();
+ seq_printf(m, " Transfer Period Factor: ");
if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
- len =
- asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
- ASC_PRT_NEXT();
+ seq_printf(m, "9 (80.0 Mhz),");
} else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
- len =
- asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
- ASC_PRT_NEXT();
+ seq_printf(m, "10 (40.0 Mhz),");
} else { /* 20 Mhz or below. */
period = (((lramword >> 8) * 25) + 50) / 4;
if (period == 0) { /* Should never happen. */
- len =
- asc_prt_line(cp, leftlen,
- "%d (? Mhz), ");
- ASC_PRT_NEXT();
+ seq_printf(m, "%d (? Mhz), ", period);
} else {
- len = asc_prt_line(cp, leftlen,
- "%d (%d.%d Mhz),",
- period, 250 / period,
- ASC_TENTHS(250,
- period));
- ASC_PRT_NEXT();
+ seq_printf(m,
+ "%d (%d.%d Mhz),",
+ period, 250 / period,
+ ASC_TENTHS(250, period));
}
}
- len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
- lramword & 0x1F);
- ASC_PRT_NEXT();
+ seq_printf(m, " REQ/ACK Offset: %d",
+ lramword & 0x1F);
}
if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- len = asc_prt_line(cp, leftlen, "*\n");
+ seq_printf(m, "*\n");
renegotiate = 1;
} else {
- len = asc_prt_line(cp, leftlen, "\n");
+ seq_printf(m, "\n");
}
- ASC_PRT_NEXT();
}
if (renegotiate) {
- len = asc_prt_line(cp, leftlen,
- " * = Re-negotiation pending before next command.\n");
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " * = Re-negotiation pending before next command.\n");
}
-
- return totlen;
-}
-
-/*
- * asc_proc_copy()
- *
- * Copy proc information to a read buffer taking into account the current
- * read offset in the file and the remaining space in the read buffer.
- */
-static int
-asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
- char *cp, int cplen)
-{
- int cnt = 0;
-
- ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n",
- (unsigned)offset, (unsigned)advoffset, cplen);
- if (offset <= advoffset) {
- /* Read offset below current offset, copy everything. */
- cnt = min(cplen, leftlen);
- ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
- (ulong)curbuf, (ulong)cp, cnt);
- memcpy(curbuf, cp, cnt);
- } else if (offset < advoffset + cplen) {
- /* Read offset within current range, partial copy. */
- cnt = (advoffset + cplen) - offset;
- cp = (cp + cplen) - cnt;
- cnt = min(cnt, leftlen);
- ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
- (ulong)curbuf, (ulong)cp, cnt);
- memcpy(curbuf, cp, cnt);
- }
- return cnt;
}
#ifdef ADVANSYS_STATS
/*
* asc_prt_board_stats()
- *
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
- *
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
*/
-static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
+static void asc_prt_board_stats(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
struct asc_stats *s = &boardp->asc_stats;
- int leftlen = cplen;
- int len, totlen = 0;
+ seq_printf(m,
+ "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
- len = asc_prt_line(cp, leftlen,
- "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " queuecommand %u, reset %u, biosparam %u, interrupt %u\n",
+ s->queuecommand, s->reset, s->biosparam,
+ s->interrupt);
- len = asc_prt_line(cp, leftlen,
- " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
- s->queuecommand, s->reset, s->biosparam,
- s->interrupt);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " callback %u, done %u, build_error %u, build_noreq %u, build_nosg %u\n",
+ s->callback, s->done, s->build_error,
+ s->adv_build_noreq, s->adv_build_nosg);
- len = asc_prt_line(cp, leftlen,
- " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
- s->callback, s->done, s->build_error,
- s->adv_build_noreq, s->adv_build_nosg);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
- " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
- s->exe_noerror, s->exe_busy, s->exe_error,
- s->exe_unknown);
- ASC_PRT_NEXT();
+ seq_printf(m,
+ " exe_noerror %u, exe_busy %u, exe_error %u, exe_unknown %u\n",
+ s->exe_noerror, s->exe_busy, s->exe_error,
+ s->exe_unknown);
/*
* Display data transfer statistics.
*/
if (s->xfer_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ",
- s->xfer_cnt, s->xfer_elem);
- ASC_PRT_NEXT();
+ seq_printf(m, " xfer_cnt %u, xfer_elem %u, ",
+ s->xfer_cnt, s->xfer_elem);
- len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n",
- s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
- ASC_PRT_NEXT();
+ seq_printf(m, "xfer_bytes %u.%01u kb\n",
+ s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
/* Scatter gather transfer statistics */
- len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
- s->xfer_elem / s->xfer_cnt,
- ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
- ASC_PRT_NEXT();
+ seq_printf(m, " avg_num_elem %u.%01u, ",
+ s->xfer_elem / s->xfer_cnt,
+ ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
- len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
- (s->xfer_sect / 2) / s->xfer_elem,
- ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
- ASC_PRT_NEXT();
+ seq_printf(m, "avg_elem_size %u.%01u kb, ",
+ (s->xfer_sect / 2) / s->xfer_elem,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
- len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
- (s->xfer_sect / 2) / s->xfer_cnt,
- ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
- ASC_PRT_NEXT();
+ seq_printf(m, "avg_xfer_size %u.%01u kb\n",
+ (s->xfer_sect / 2) / s->xfer_cnt,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
}
-
- return totlen;
}
#endif /* ADVANSYS_STATS */
/*
- * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
+ * advansys_show_info() - /proc/scsi/advansys/{0,1,2,3,...}
*
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset into a /proc/scsi/advansys/[0...] file
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
+ * m: seq_file to print into
+ * shost: Scsi_Host
*
* Return the number of bytes read from or written to a
* /proc/scsi/advansys/[0...] file.
- *
- * Note: This function uses the per board buffer 'prtbuf' which is
- * allocated when the board is initialized in advansys_detect(). The
- * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
- * used to write to the buffer. The way asc_proc_copy() is written
- * if 'prtbuf' is too small it will not be overwritten. Instead the
- * user just won't get all the available statistics.
*/
static int
-advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+advansys_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct asc_board *boardp = shost_priv(shost);
- char *cp;
- int cplen;
- int cnt;
- int totcnt;
- int leftlen;
- char *curbuf;
- off_t advoffset;
ASC_DBG(1, "begin\n");
/*
- * User write not supported.
- */
- if (inout == TRUE)
- return -ENOSYS;
-
- /*
* User read of /proc/scsi/advansys/[0...] file.
*/
- /* Copy read data starting at the beginning of the buffer. */
- *start = buffer;
- curbuf = buffer;
- advoffset = 0;
- totcnt = 0;
- leftlen = length;
-
/*
* Get board configuration information.
*
* advansys_info() returns the board string from its own static buffer.
*/
- cp = (char *)advansys_info(shost);
- strcat(cp, "\n");
- cplen = strlen(cp);
/* Copy board information. */
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
+ seq_printf(m, "%s\n", (char *)advansys_info(shost));
/*
* Display Wide Board BIOS Information.
*/
- if (!ASC_NARROW_BOARD(boardp)) {
- cp = boardp->prtbuf;
- cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
+ if (!ASC_NARROW_BOARD(boardp))
+ asc_prt_adv_bios(m, shost);
/*
* Display driver information for each device attached to the board.
*/
- cp = boardp->prtbuf;
- cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ asc_prt_board_devices(m, shost);
/*
* Display EEPROM configuration for the board.
*/
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
- }
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ if (ASC_NARROW_BOARD(boardp))
+ asc_prt_asc_board_eeprom(m, shost);
+ else
+ asc_prt_adv_board_eeprom(m, shost);
/*
* Display driver configuration and information for the board.
*/
- cp = boardp->prtbuf;
- cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ asc_prt_driver_conf(m, shost);
#ifdef ADVANSYS_STATS
/*
* Display driver statistics for the board.
*/
- cp = boardp->prtbuf;
- cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ asc_prt_board_stats(m, shost);
#endif /* ADVANSYS_STATS */
/*
* Display Asc Library dynamic configuration information
* for the board.
*/
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
- }
- BUG_ON(cplen >= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG(1, "totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- ASC_DBG(1, "totcnt %d\n", totcnt);
-
- return totcnt;
+ if (ASC_NARROW_BOARD(boardp))
+ asc_prt_asc_board_info(m, shost);
+ else
+ asc_prt_adv_board_info(m, shost);
+ return 0;
}
#endif /* CONFIG_PROC_FS */
@@ -11743,7 +11250,7 @@ static int AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
static struct scsi_host_template advansys_template = {
.proc_name = DRV_NAME,
#ifdef CONFIG_PROC_FS
- .proc_info = advansys_proc_info,
+ .show_info = advansys_show_info,
#endif
.name = DRV_NAME,
.info = advansys_info,
@@ -11939,20 +11446,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
#endif /* CONFIG_PCI */
}
-#ifdef CONFIG_PROC_FS
- /*
- * Allocate buffer for printing information from
- * /proc/scsi/advansys/[0...].
- */
- boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
- if (!boardp->prtbuf) {
- shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n",
- ASC_PRTBUF_SIZE);
- ret = -ENOMEM;
- goto err_unmap;
- }
-#endif /* CONFIG_PROC_FS */
-
if (ASC_NARROW_BOARD(boardp)) {
/*
* Set the board bus type and PCI IRQ before
@@ -12010,7 +11503,7 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
}
if (ret)
- goto err_free_proc;
+ goto err_unmap;
/*
* Save the EEPROM configuration so that it can be displayed
@@ -12055,7 +11548,7 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
ASC_DBG(2, "AscInitSetConfig()\n");
ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0;
if (ret)
- goto err_free_proc;
+ goto err_unmap;
} else {
ADVEEP_3550_CONFIG *ep_3550;
ADVEEP_38C0800_CONFIG *ep_38C0800;
@@ -12290,7 +11783,7 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
shost_printk(KERN_ERR, shost, "request_dma() "
"%d failed %d\n",
shost->dma_channel, ret);
- goto err_free_proc;
+ goto err_unmap;
}
AscEnableIsaDma(shost->dma_channel);
}
@@ -12371,8 +11864,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
if (shost->dma_channel != NO_ISA_DMA)
free_dma(shost->dma_channel);
#endif
- err_free_proc:
- kfree(boardp->prtbuf);
err_unmap:
if (boardp->ioremap_addr)
iounmap(boardp->ioremap_addr);
@@ -12406,7 +11897,6 @@ static int advansys_release(struct Scsi_Host *shost)
iounmap(board->ioremap_addr);
advansys_wide_free_mem(board);
}
- kfree(board->prtbuf);
scsi_host_put(shost);
ASC_DBG(1, "end\n");
return 0;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index a284be17699f..3f7b6fee0a74 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -2977,11 +2977,10 @@ static void show_queues(struct Scsi_Host *shpnt)
}
#undef SPRINTF
-#define SPRINTF(args...) pos += sprintf(pos, ## args)
+#define SPRINTF(args...) seq_printf(m, ##args)
-static int get_command(char *pos, Scsi_Cmnd * ptr)
+static void get_command(struct seq_file *m, Scsi_Cmnd * ptr)
{
- char *start = pos;
int i;
SPRINTF("%p: target=%d; lun=%d; cmnd=( ",
@@ -3011,13 +3010,10 @@ static int get_command(char *pos, Scsi_Cmnd * ptr)
if (ptr->SCp.phase & syncneg)
SPRINTF("syncneg|");
SPRINTF("; next=0x%p\n", SCNEXT(ptr));
-
- return (pos - start);
}
-static int get_ports(struct Scsi_Host *shpnt, char *pos)
+static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
{
- char *start = pos;
int s;
SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
@@ -3273,11 +3269,9 @@ static int get_ports(struct Scsi_Host *shpnt, char *pos)
if (s & ENREQINIT)
SPRINTF("ENREQINIT ");
SPRINTF(")\n");
-
- return (pos - start);
}
-static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
{
if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
return -EINVAL;
@@ -3320,26 +3314,11 @@ static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
return length;
}
-#undef SPRINTF
-#define SPRINTF(args...) \
- do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
-
-static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start,
- off_t offset, int length, int inout)
+static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
{
int i;
- char *pos = buffer;
Scsi_Cmnd *ptr;
unsigned long flags;
- int thislength;
-
- DPRINTK(debug_procinfo,
- KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
- buffer, offset, length, shpnt->host_no, inout);
-
-
- if (inout)
- return aha152x_set_info(buffer, length, shpnt);
SPRINTF(AHA152X_REVID "\n");
@@ -3392,25 +3371,25 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
if (ISSUE_SC) {
SPRINTF("not yet issued commands:\n");
for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
- pos += get_command(pos, ptr);
+ get_command(m, ptr);
} else
SPRINTF("no not yet issued commands\n");
DO_UNLOCK(flags);
if (CURRENT_SC) {
SPRINTF("current command:\n");
- pos += get_command(pos, CURRENT_SC);
+ get_command(m, CURRENT_SC);
} else
SPRINTF("no current command\n");
if (DISCONNECTED_SC) {
SPRINTF("disconnected commands:\n");
for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
- pos += get_command(pos, ptr);
+ get_command(m, ptr);
} else
SPRINTF("no disconnected commands\n");
- pos += get_ports(shpnt, pos);
+ get_ports(m, shpnt);
#if defined(AHA152X_STAT)
SPRINTF("statistics:\n"
@@ -3440,24 +3419,7 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
HOSTDATA(shpnt)->time[i]);
}
#endif
-
- DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos);
-
- thislength = pos - (buffer + offset);
- DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength);
-
- if(thislength<0) {
- DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n");
- *start = NULL;
- return 0;
- }
-
- thislength = thislength<length ? thislength : length;
-
- DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength);
-
- *start = buffer + offset;
- return thislength < length ? thislength : length;
+ return 0;
}
static int aha152x_adjust_queue(struct scsi_device *device)
@@ -3470,7 +3432,8 @@ static struct scsi_host_template aha152x_driver_template = {
.module = THIS_MODULE,
.name = AHA152X_REVID,
.proc_name = "aha152x",
- .proc_info = aha152x_proc_info,
+ .show_info = aha152x_show_info,
+ .write_info = aha152x_set_info,
.queuecommand = aha152x_queue,
.eh_abort_handler = aha152x_abort,
.eh_device_reset_handler = aha152x_device_reset,
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index df775e6ba579..5f3101797c93 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -106,33 +106,14 @@ static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
return hdata->ecb_dma_addr + offset;
}
-static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer,
- char **start, off_t offset,
- int length, int inout)
+static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
{
- int len;
- struct aha1740_hostdata *host;
-
- if (inout)
- return-ENOSYS;
-
- host = HOSTDATA(shpnt);
-
- len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
+ struct aha1740_hostdata *host = HOSTDATA(shpnt);
+ seq_printf(m, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
"Extended translation %sabled.\n",
shpnt->io_port, shpnt->irq, host->edev->slot,
host->translation ? "en" : "dis");
-
- if (offset > len) {
- *start = buffer;
- return 0;
- }
-
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
- return len;
+ return 0;
}
static int aha1740_makecode(unchar *sense, unchar *status)
@@ -556,7 +537,7 @@ static int aha1740_eh_abort_handler (Scsi_Cmnd *dummy)
static struct scsi_host_template aha1740_template = {
.module = THIS_MODULE,
.proc_name = "aha1740",
- .proc_info = aha1740_proc_info,
+ .show_info = aha1740_show_info,
.name = "Adaptec 174x (EISA)",
.queuecommand = aha1740_queuecommand,
.bios_param = aha1740_biosparam,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 9328121804bb..69d5c43a65e5 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -906,7 +906,8 @@ struct scsi_host_template aic79xx_driver_template = {
.module = THIS_MODULE,
.name = "aic79xx",
.proc_name = "aic79xx",
- .proc_info = ahd_linux_proc_info,
+ .show_info = ahd_linux_show_info,
+ .write_info = ahd_proc_write_seeprom,
.info = ahd_linux_info,
.queuecommand = ahd_linux_queue,
.eh_abort_handler = ahd_linux_abort,
@@ -1702,19 +1703,13 @@ ahd_send_async(struct ahd_softc *ahd, char channel,
switch (code) {
case AC_TRANSFER_NEG:
{
- char buf[80];
struct scsi_target *starget;
- struct info_str info;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
unsigned int target_ppr_options;
BUG_ON(target == CAM_TARGET_WILDCARD);
- info.buffer = buf;
- info.length = sizeof(buf);
- info.offset = 0;
- info.pos = 0;
tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
target, &tstate);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 28e43498cdff..c58fa33c6592 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -379,14 +379,6 @@ void ahd_insb(struct ahd_softc * ahd, long port,
int ahd_linux_register_host(struct ahd_softc *,
struct scsi_host_template *);
-/*************************** Pretty Printing **********************************/
-struct info_str {
- char *buffer;
- int length;
- off_t offset;
- int pos;
-};
-
/******************************** Locking *************************************/
static inline void
ahd_lockinit(struct ahd_softc *ahd)
@@ -513,8 +505,8 @@ ahd_flush_device_writes(struct ahd_softc *ahd)
}
/**************************** Proc FS Support *********************************/
-int ahd_linux_proc_info(struct Scsi_Host *, char *, char **,
- off_t, int, int);
+int ahd_proc_write_seeprom(struct Scsi_Host *, char *, int);
+int ahd_linux_show_info(struct seq_file *,struct Scsi_Host *);
/*********************** Transaction Access Wrappers **************************/
static inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t);
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 59c85d5a153a..e9778b4f7e32 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -42,16 +42,12 @@
#include "aic79xx_osm.h"
#include "aic79xx_inline.h"
-static void copy_mem_info(struct info_str *info, char *data, int len);
-static int copy_info(struct info_str *info, char *fmt, ...);
static void ahd_dump_target_state(struct ahd_softc *ahd,
- struct info_str *info,
+ struct seq_file *m,
u_int our_id, char channel,
u_int target_id);
-static void ahd_dump_device_state(struct info_str *info,
+static void ahd_dump_device_state(struct seq_file *m,
struct scsi_device *sdev);
-static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
- char *buffer, int length);
/*
* Table of syncrates that don't follow the "divisible by 4"
@@ -93,58 +89,15 @@ ahd_calc_syncsrate(u_int period_factor)
return (10000000 / (period_factor * 4 * 10));
}
-
-static void
-copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->offset + info->length)
- len = info->offset + info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
-
- if (info->pos < info->offset) {
- off_t partial;
-
- partial = info->offset - info->pos;
- data += partial;
- info->pos += partial;
- len -= partial;
- }
-
- if (len > 0) {
- memcpy(info->buffer, data, len);
- info->pos += len;
- info->buffer += len;
- }
-}
-
-static int
-copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[256];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return (len);
-}
-
static void
-ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
+ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo)
{
u_int speed;
u_int freq;
u_int mb;
if (tinfo->period == AHD_PERIOD_UNKNOWN) {
- copy_info(info, "Renegotiation Pending\n");
+ seq_printf(m, "Renegotiation Pending\n");
return;
}
speed = 3300;
@@ -156,34 +109,34 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
speed *= (0x01 << tinfo->width);
mb = speed / 1000;
if (mb > 0)
- copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
+ seq_printf(m, "%d.%03dMB/s transfers", mb, speed % 1000);
else
- copy_info(info, "%dKB/s transfers", speed);
+ seq_printf(m, "%dKB/s transfers", speed);
if (freq != 0) {
int printed_options;
printed_options = 0;
- copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000);
+ seq_printf(m, " (%d.%03dMHz", freq / 1000, freq % 1000);
if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
- copy_info(info, " RDSTRM");
+ seq_printf(m, " RDSTRM");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
- copy_info(info, "%s", printed_options ? "|DT" : " DT");
+ seq_printf(m, "%s", printed_options ? "|DT" : " DT");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- copy_info(info, "%s", printed_options ? "|IU" : " IU");
+ seq_printf(m, "%s", printed_options ? "|IU" : " IU");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) {
- copy_info(info, "%s",
+ seq_printf(m, "%s",
printed_options ? "|RTI" : " RTI");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
- copy_info(info, "%s",
+ seq_printf(m, "%s",
printed_options ? "|QAS" : " QAS");
printed_options++;
}
@@ -191,19 +144,19 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
if (tinfo->width > 0) {
if (freq != 0) {
- copy_info(info, ", ");
+ seq_printf(m, ", ");
} else {
- copy_info(info, " (");
+ seq_printf(m, " (");
}
- copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
+ seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width));
} else if (freq != 0) {
- copy_info(info, ")");
+ seq_printf(m, ")");
}
- copy_info(info, "\n");
+ seq_printf(m, "\n");
}
static void
-ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
+ahd_dump_target_state(struct ahd_softc *ahd, struct seq_file *m,
u_int our_id, char channel, u_int target_id)
{
struct scsi_target *starget;
@@ -213,17 +166,17 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
target_id, &tstate);
- copy_info(info, "Target %d Negotiation Settings\n", target_id);
- copy_info(info, "\tUser: ");
- ahd_format_transinfo(info, &tinfo->user);
+ seq_printf(m, "Target %d Negotiation Settings\n", target_id);
+ seq_printf(m, "\tUser: ");
+ ahd_format_transinfo(m, &tinfo->user);
starget = ahd->platform_data->starget[target_id];
if (starget == NULL)
return;
- copy_info(info, "\tGoal: ");
- ahd_format_transinfo(info, &tinfo->goal);
- copy_info(info, "\tCurr: ");
- ahd_format_transinfo(info, &tinfo->curr);
+ seq_printf(m, "\tGoal: ");
+ ahd_format_transinfo(m, &tinfo->goal);
+ seq_printf(m, "\tCurr: ");
+ ahd_format_transinfo(m, &tinfo->curr);
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
struct scsi_device *dev;
@@ -233,29 +186,30 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
if (dev == NULL)
continue;
- ahd_dump_device_state(info, dev);
+ ahd_dump_device_state(m, dev);
}
}
static void
-ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev)
+ahd_dump_device_state(struct seq_file *m, struct scsi_device *sdev)
{
struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
- copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
+ seq_printf(m, "\tChannel %c Target %d Lun %d Settings\n",
sdev->sdev_target->channel + 'A',
sdev->sdev_target->id, sdev->lun);
- copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
- copy_info(info, "\t\tCommands Active %d\n", dev->active);
- copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
- copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
- copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
+ seq_printf(m, "\t\tCommands Queued %ld\n", dev->commands_issued);
+ seq_printf(m, "\t\tCommands Active %d\n", dev->active);
+ seq_printf(m, "\t\tCommand Openings %d\n", dev->openings);
+ seq_printf(m, "\t\tMax Tagged Openings %d\n", dev->maxtags);
+ seq_printf(m, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
}
-static int
-ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
+int
+ahd_proc_write_seeprom(struct Scsi_Host *shost, char *buffer, int length)
{
+ struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
ahd_mode_state saved_modes;
int have_seeprom;
u_long s;
@@ -319,64 +273,45 @@ done:
* Return information to handle /proc support for the driver.
*/
int
-ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+ahd_linux_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
- struct info_str info;
char ahd_info[256];
u_int max_targ;
u_int i;
- int retval;
- /* Has data been written to the file? */
- if (inout == TRUE) {
- retval = ahd_proc_write_seeprom(ahd, buffer, length);
- goto done;
- }
-
- if (start)
- *start = buffer;
-
- info.buffer = buffer;
- info.length = length;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, "Adaptec AIC79xx driver version: %s\n",
+ seq_printf(m, "Adaptec AIC79xx driver version: %s\n",
AIC79XX_DRIVER_VERSION);
- copy_info(&info, "%s\n", ahd->description);
+ seq_printf(m, "%s\n", ahd->description);
ahd_controller_info(ahd, ahd_info);
- copy_info(&info, "%s\n", ahd_info);
- copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+ seq_printf(m, "%s\n", ahd_info);
+ seq_printf(m, "Allocated SCBs: %d, SG List Length: %d\n\n",
ahd->scb_data.numscbs, AHD_NSEG);
max_targ = 16;
if (ahd->seep_config == NULL)
- copy_info(&info, "No Serial EEPROM\n");
+ seq_printf(m, "No Serial EEPROM\n");
else {
- copy_info(&info, "Serial EEPROM:\n");
+ seq_printf(m, "Serial EEPROM:\n");
for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) {
if (((i % 8) == 0) && (i != 0)) {
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
}
- copy_info(&info, "0x%.4x ",
+ seq_printf(m, "0x%.4x ",
((uint16_t*)ahd->seep_config)[i]);
}
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
}
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
if ((ahd->features & AHD_WIDE) == 0)
max_targ = 8;
for (i = 0; i < max_targ; i++) {
- ahd_dump_target_state(ahd, &info, ahd->our_id, 'A',
+ ahd_dump_target_state(ahd, m, ahd->our_id, 'A',
/*target_id*/i);
}
- retval = info.pos > info.offset ? info.pos - info.offset : 0;
-done:
- return (retval);
+ return 0;
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 5a477cdc780d..c0c62583b542 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -803,7 +803,8 @@ struct scsi_host_template aic7xxx_driver_template = {
.module = THIS_MODULE,
.name = "aic7xxx",
.proc_name = "aic7xxx",
- .proc_info = ahc_linux_proc_info,
+ .show_info = ahc_linux_show_info,
+ .write_info = ahc_proc_write_seeprom,
.info = ahc_linux_info,
.queuecommand = ahc_linux_queue,
.eh_abort_handler = ahc_linux_abort,
@@ -1631,10 +1632,8 @@ ahc_send_async(struct ahc_softc *ahc, char channel,
switch (code) {
case AC_TRANSFER_NEG:
{
- char buf[80];
struct scsi_target *starget;
struct ahc_linux_target *targ;
- struct info_str info;
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
int target_offset;
@@ -1642,10 +1641,6 @@ ahc_send_async(struct ahc_softc *ahc, char channel,
BUG_ON(target == CAM_TARGET_WILDCARD);
- info.buffer = buf;
- info.length = sizeof(buf);
- info.offset = 0;
- info.pos = 0;
tinfo = ahc_fetch_transinfo(ahc, channel,
channel == 'A' ? ahc->our_id
: ahc->our_id_b,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index bca0fb83f553..bc4cca92ff04 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -383,14 +383,6 @@ void ahc_insb(struct ahc_softc * ahc, long port,
int ahc_linux_register_host(struct ahc_softc *,
struct scsi_host_template *);
-/*************************** Pretty Printing **********************************/
-struct info_str {
- char *buffer;
- int length;
- off_t offset;
- int pos;
-};
-
/******************************** Locking *************************************/
/* Lock protecting internal data structures */
@@ -523,8 +515,8 @@ ahc_flush_device_writes(struct ahc_softc *ahc)
}
/**************************** Proc FS Support *********************************/
-int ahc_linux_proc_info(struct Scsi_Host *, char *, char **,
- off_t, int, int);
+int ahc_proc_write_seeprom(struct Scsi_Host *, char *, int);
+int ahc_linux_show_info(struct seq_file *, struct Scsi_Host *);
/*************************** Domain Validation ********************************/
/*********************** Transaction Access Wrappers *************************/
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index f2525f8ed1c7..383a3d11652d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -43,16 +43,12 @@
#include "aic7xxx_inline.h"
#include "aic7xxx_93cx6.h"
-static void copy_mem_info(struct info_str *info, char *data, int len);
-static int copy_info(struct info_str *info, char *fmt, ...);
static void ahc_dump_target_state(struct ahc_softc *ahc,
- struct info_str *info,
+ struct seq_file *m,
u_int our_id, char channel,
u_int target_id, u_int target_offset);
-static void ahc_dump_device_state(struct info_str *info,
+static void ahc_dump_device_state(struct seq_file *m,
struct scsi_device *dev);
-static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
- char *buffer, int length);
/*
* Table of syncrates that don't follow the "divisible by 4"
@@ -94,51 +90,8 @@ ahc_calc_syncsrate(u_int period_factor)
return (10000000 / (period_factor * 4 * 10));
}
-
-static void
-copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->offset + info->length)
- len = info->offset + info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
-
- if (info->pos < info->offset) {
- off_t partial;
-
- partial = info->offset - info->pos;
- data += partial;
- info->pos += partial;
- len -= partial;
- }
-
- if (len > 0) {
- memcpy(info->buffer, data, len);
- info->pos += len;
- info->buffer += len;
- }
-}
-
-static int
-copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[256];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return (len);
-}
-
static void
-ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
+ahc_format_transinfo(struct seq_file *m, struct ahc_transinfo *tinfo)
{
u_int speed;
u_int freq;
@@ -153,12 +106,12 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
speed *= (0x01 << tinfo->width);
mb = speed / 1000;
if (mb > 0)
- copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
+ seq_printf(m, "%d.%03dMB/s transfers", mb, speed % 1000);
else
- copy_info(info, "%dKB/s transfers", speed);
+ seq_printf(m, "%dKB/s transfers", speed);
if (freq != 0) {
- copy_info(info, " (%d.%03dMHz%s, offset %d",
+ seq_printf(m, " (%d.%03dMHz%s, offset %d",
freq / 1000, freq % 1000,
(tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
? " DT" : "", tinfo->offset);
@@ -166,19 +119,19 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
if (tinfo->width > 0) {
if (freq != 0) {
- copy_info(info, ", ");
+ seq_printf(m, ", ");
} else {
- copy_info(info, " (");
+ seq_printf(m, " (");
}
- copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
+ seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width));
} else if (freq != 0) {
- copy_info(info, ")");
+ seq_printf(m, ")");
}
- copy_info(info, "\n");
+ seq_printf(m, "\n");
}
static void
-ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
+ahc_dump_target_state(struct ahc_softc *ahc, struct seq_file *m,
u_int our_id, char channel, u_int target_id,
u_int target_offset)
{
@@ -190,18 +143,18 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
target_id, &tstate);
if ((ahc->features & AHC_TWIN) != 0)
- copy_info(info, "Channel %c ", channel);
- copy_info(info, "Target %d Negotiation Settings\n", target_id);
- copy_info(info, "\tUser: ");
- ahc_format_transinfo(info, &tinfo->user);
+ seq_printf(m, "Channel %c ", channel);
+ seq_printf(m, "Target %d Negotiation Settings\n", target_id);
+ seq_printf(m, "\tUser: ");
+ ahc_format_transinfo(m, &tinfo->user);
starget = ahc->platform_data->starget[target_offset];
if (!starget)
return;
- copy_info(info, "\tGoal: ");
- ahc_format_transinfo(info, &tinfo->goal);
- copy_info(info, "\tCurr: ");
- ahc_format_transinfo(info, &tinfo->curr);
+ seq_printf(m, "\tGoal: ");
+ ahc_format_transinfo(m, &tinfo->goal);
+ seq_printf(m, "\tCurr: ");
+ ahc_format_transinfo(m, &tinfo->curr);
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
struct scsi_device *sdev;
@@ -211,29 +164,30 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
if (sdev == NULL)
continue;
- ahc_dump_device_state(info, sdev);
+ ahc_dump_device_state(m, sdev);
}
}
static void
-ahc_dump_device_state(struct info_str *info, struct scsi_device *sdev)
+ahc_dump_device_state(struct seq_file *m, struct scsi_device *sdev)
{
struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
- copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
+ seq_printf(m, "\tChannel %c Target %d Lun %d Settings\n",
sdev->sdev_target->channel + 'A',
sdev->sdev_target->id, sdev->lun);
- copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
- copy_info(info, "\t\tCommands Active %d\n", dev->active);
- copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
- copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
- copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
+ seq_printf(m, "\t\tCommands Queued %ld\n", dev->commands_issued);
+ seq_printf(m, "\t\tCommands Active %d\n", dev->active);
+ seq_printf(m, "\t\tCommand Openings %d\n", dev->openings);
+ seq_printf(m, "\t\tMax Tagged Openings %d\n", dev->maxtags);
+ seq_printf(m, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
}
-static int
-ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
+int
+ahc_proc_write_seeprom(struct Scsi_Host *shost, char *buffer, int length)
{
+ struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata;
struct seeprom_descriptor sd;
int have_seeprom;
u_long s;
@@ -332,53 +286,36 @@ done:
* Return information to handle /proc support for the driver.
*/
int
-ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+ahc_linux_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata;
- struct info_str info;
char ahc_info[256];
u_int max_targ;
u_int i;
- int retval;
- /* Has data been written to the file? */
- if (inout == TRUE) {
- retval = ahc_proc_write_seeprom(ahc, buffer, length);
- goto done;
- }
-
- if (start)
- *start = buffer;
-
- info.buffer = buffer;
- info.length = length;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
+ seq_printf(m, "Adaptec AIC7xxx driver version: %s\n",
AIC7XXX_DRIVER_VERSION);
- copy_info(&info, "%s\n", ahc->description);
+ seq_printf(m, "%s\n", ahc->description);
ahc_controller_info(ahc, ahc_info);
- copy_info(&info, "%s\n", ahc_info);
- copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+ seq_printf(m, "%s\n", ahc_info);
+ seq_printf(m, "Allocated SCBs: %d, SG List Length: %d\n\n",
ahc->scb_data->numscbs, AHC_NSEG);
if (ahc->seep_config == NULL)
- copy_info(&info, "No Serial EEPROM\n");
+ seq_printf(m, "No Serial EEPROM\n");
else {
- copy_info(&info, "Serial EEPROM:\n");
+ seq_printf(m, "Serial EEPROM:\n");
for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
if (((i % 8) == 0) && (i != 0)) {
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
}
- copy_info(&info, "0x%.4x ",
+ seq_printf(m, "0x%.4x ",
((uint16_t*)ahc->seep_config)[i]);
}
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
}
- copy_info(&info, "\n");
+ seq_printf(m, "\n");
max_targ = 16;
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
@@ -398,10 +335,8 @@ ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
target_id = i % 8;
}
- ahc_dump_target_state(ahc, &info, our_id,
+ ahc_dump_target_state(ahc, m, our_id,
channel, target_id, i);
}
- retval = info.pos > info.offset ? info.pos - info.offset : 0;
-done:
- return (retval);
+ return 0;
}
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 5b212f0df898..33ec9c643400 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -11108,7 +11108,7 @@ MODULE_VERSION(AIC7XXX_H_VERSION);
static struct scsi_host_template driver_template = {
- .proc_info = aic7xxx_proc_info,
+ .show_info = aic7xxx_show_info,
.detect = aic7xxx_detect,
.release = aic7xxx_release,
.info = aic7xxx_info,
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
index b07e4f04fd00..976f45ccf2cf 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
@@ -30,62 +30,23 @@
*-M*************************************************************************/
-#define BLS (&aic7xxx_buffer[size])
#define HDRB \
" 0 - 4K 4 - 16K 16 - 64K 64 - 256K 256K - 1M 1M+"
-#ifdef PROC_DEBUG
-extern int vsprintf(char *, const char *, va_list);
-
-static void
-proc_debug(const char *fmt, ...)
-{
- va_list ap;
- char buf[256];
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- printk(buf);
- va_end(ap);
-}
-#else /* PROC_DEBUG */
-# define proc_debug(fmt, args...)
-#endif /* PROC_DEBUG */
-
-static int aic7xxx_buffer_size = 0;
-static char *aic7xxx_buffer = NULL;
-
/*+F*************************************************************************
* Function:
- * aic7xxx_set_info
- *
- * Description:
- * Set parameters for the driver from the /proc filesystem.
- *-F*************************************************************************/
-static int
-aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
-{
- proc_debug("aic7xxx_set_info(): %s\n", buffer);
- return (-ENOSYS); /* Currently this is a no-op */
-}
-
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_proc_info
+ * aic7xxx_show_info
*
* Description:
* Return information to handle /proc support for the driver.
*-F*************************************************************************/
int
-aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length,
- int inout)
+aic7xxx_show_info(struct seq_file *m, struct Scsi_Host *HBAptr)
{
struct aic7xxx_host *p;
struct aic_dev_data *aic_dev;
struct scsi_device *sdptr;
- int size = 0;
unsigned char i;
unsigned char tindex;
@@ -94,66 +55,21 @@ aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t
if (!p)
{
- size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no);
- if (size > length)
- {
- return (size);
- }
- else
- {
- return (length);
- }
- }
-
- if (inout == TRUE) /* Has data been written to the file? */
- {
- return (aic7xxx_set_info(buffer, length, HBAptr));
+ seq_printf(m, "Can't find adapter for host number %d\n", HBAptr->host_no);
+ return 0;
}
p = (struct aic7xxx_host *) HBAptr->hostdata;
- /*
- * It takes roughly 1K of space to hold all relevant card info, not
- * counting any proc stats, so we start out with a 1.5k buffer size and
- * if proc_stats is defined, then we sweep the stats structure to see
- * how many drives we will be printing out for and add 384 bytes per
- * device with active stats.
- *
- * Hmmmm...that 1.5k seems to keep growing as items get added so they
- * can be easily viewed for debugging purposes. So, we bumped that
- * 1.5k to 4k so we can quit having to bump it all the time.
- */
-
- size = 4096;
- list_for_each_entry(aic_dev, &p->aic_devs, list)
- size += 512;
- if (aic7xxx_buffer_size != size)
- {
- if (aic7xxx_buffer != NULL)
- {
- kfree(aic7xxx_buffer);
- aic7xxx_buffer_size = 0;
- }
- aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
- }
- if (aic7xxx_buffer == NULL)
- {
- size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
- __LINE__);
- return size;
- }
- aic7xxx_buffer_size = size;
-
- size = 0;
- size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
- size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
- size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " SCSI Adapter: %s\n",
+ seq_printf(m, "Adaptec AIC7xxx driver version: ");
+ seq_printf(m, "%s/", AIC7XXX_C_VERSION);
+ seq_printf(m, "%s", AIC7XXX_H_VERSION);
+ seq_printf(m, "\n");
+ seq_printf(m, "Adapter Configuration:\n");
+ seq_printf(m, " SCSI Adapter: %s\n",
board_names[p->board_name_index]);
if (p->flags & AHC_TWIN)
- size += sprintf(BLS, " Twin Channel Controller ");
+ seq_printf(m, " Twin Channel Controller ");
else
{
char *channel = "";
@@ -184,86 +100,86 @@ aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t
ultra = "Ultra-2 LVD/SE ";
else if (p->features & AHC_ULTRA)
ultra = "Ultra ";
- size += sprintf(BLS, " %s%sController%s ",
+ seq_printf(m, " %s%sController%s ",
ultra, wide, channel);
}
switch(p->chip & ~AHC_CHIPID_MASK)
{
case AHC_VL:
- size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+ seq_printf(m, "at VLB slot %d\n", p->pci_device_fn);
break;
case AHC_EISA:
- size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+ seq_printf(m, "at EISA slot %d\n", p->pci_device_fn);
break;
default:
- size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+ seq_printf(m, "at PCI %d/%d/%d\n", p->pci_bus,
PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
break;
}
if( !(p->maddr) )
{
- size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base);
+ seq_printf(m, " Programmed I/O Base: %lx\n", p->base);
}
else
{
- size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+ seq_printf(m, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
}
if( (p->chip & (AHC_VL | AHC_EISA)) )
{
- size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address);
+ seq_printf(m, " BIOS Memory Address: 0x%08x\n", p->bios_address);
}
- size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
+ seq_printf(m, " Adapter SEEPROM Config: %s\n",
(p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
"SEEPROM not found, using leftover BIOS values.") );
- size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n",
+ seq_printf(m, " Adaptec SCSI BIOS: %s\n",
(p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
- size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
- size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n",
+ seq_printf(m, " IRQ: %d\n", HBAptr->irq);
+ seq_printf(m, " SCBs: Active %d, Max Active %d,\n",
p->activescbs, p->max_activescbs);
- size += sprintf(BLS, " Allocated %d, HW %d, "
+ seq_printf(m, " Allocated %d, HW %d, "
"Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
p->scb_data->maxscbs);
if (p->flags & AHC_EXTERNAL_SRAM)
- size += sprintf(BLS, " Using External SCB SRAM\n");
- size += sprintf(BLS, " Interrupts: %ld", p->isr_count);
+ seq_printf(m, " Using External SCB SRAM\n");
+ seq_printf(m, " Interrupts: %ld", p->isr_count);
if (p->chip & AHC_EISA)
{
- size += sprintf(BLS, " %s\n",
+ seq_printf(m, " %s\n",
(p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
}
else
{
- size += sprintf(BLS, "\n");
+ seq_printf(m, "\n");
}
- size += sprintf(BLS, " BIOS Control Word: 0x%04x\n",
+ seq_printf(m, " BIOS Control Word: 0x%04x\n",
p->bios_control);
- size += sprintf(BLS, " Adapter Control Word: 0x%04x\n",
+ seq_printf(m, " Adapter Control Word: 0x%04x\n",
p->adapter_control);
- size += sprintf(BLS, " Extended Translation: %sabled\n",
+ seq_printf(m, " Extended Translation: %sabled\n",
(p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
- size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+ seq_printf(m, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
if (p->features & (AHC_ULTRA | AHC_ULTRA2))
{
- size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+ seq_printf(m, " Ultra Enable Flags: 0x%04x\n", p->ultraenb);
}
- size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
- size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
+ seq_printf(m, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
+ seq_printf(m, " Tagged Queue By Device array for aic7xxx host "
"instance %d:\n", p->instance);
- size += sprintf(BLS, " {");
+ seq_printf(m, " {");
for(i=0; i < (MAX_TARGETS - 1); i++)
- size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
- size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+ seq_printf(m, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+ seq_printf(m, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Statistics:\n\n");
+ seq_printf(m, "\n");
+ seq_printf(m, "Statistics:\n\n");
list_for_each_entry(aic_dev, &p->aic_devs, list)
{
sdptr = aic_dev->SDptr;
tindex = sdptr->channel << 3 | sdptr->id;
- size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+ seq_printf(m, "(scsi%d:%d:%d:%d)\n",
p->host_no, sdptr->channel, sdptr->id, sdptr->lun);
- size += sprintf(BLS, " Device using %s/%s",
+ seq_printf(m, " Device using %s/%s",
(aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ?
"Wide" : "Narrow",
(aic_dev->cur.offset != 0) ?
@@ -279,78 +195,59 @@ aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t
sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
if (sync_rate != NULL)
{
- size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+ seq_printf(m, "%s MByte/sec, offset %d\n",
sync_rate->rate[rate],
aic_dev->cur.offset );
}
else
{
- size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+ seq_printf(m, "3.3 MByte/sec, offset %d\n",
aic_dev->cur.offset );
}
}
- size += sprintf(BLS, " Transinfo settings: ");
- size += sprintf(BLS, "current(%d/%d/%d/%d), ",
+ seq_printf(m, " Transinfo settings: ");
+ seq_printf(m, "current(%d/%d/%d/%d), ",
aic_dev->cur.period,
aic_dev->cur.offset,
aic_dev->cur.width,
aic_dev->cur.options);
- size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
+ seq_printf(m, "goal(%d/%d/%d/%d), ",
aic_dev->goal.period,
aic_dev->goal.offset,
aic_dev->goal.width,
aic_dev->goal.options);
- size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
+ seq_printf(m, "user(%d/%d/%d/%d)\n",
p->user[tindex].period,
p->user[tindex].offset,
p->user[tindex].width,
p->user[tindex].options);
if(sdptr->simple_tags)
{
- size += sprintf(BLS, " Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth);
+ seq_printf(m, " Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth);
}
if(aic_dev->barrier_total)
- size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
+ seq_printf(m, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total,
aic_dev->barrier_total, aic_dev->ordered_total);
else
- size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld reads/writes)\n",
+ seq_printf(m, " Total transfers %ld:\n (%ld/%ld reads/writes)\n",
aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
- size += sprintf(BLS, "%s\n", HDRB);
- size += sprintf(BLS, " Reads:");
+ seq_printf(m, "%s\n", HDRB);
+ seq_printf(m, " Reads:");
for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++)
{
- size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]);
+ seq_printf(m, " %10ld", aic_dev->r_bins[i]);
}
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, " Writes:");
+ seq_printf(m, "\n");
+ seq_printf(m, " Writes:");
for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++)
{
- size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]);
+ seq_printf(m, " %10ld", aic_dev->w_bins[i]);
}
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "\n\n");
- }
- if (size >= aic7xxx_buffer_size)
- {
- printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
- }
-
- if (offset > size - 1)
- {
- kfree(aic7xxx_buffer);
- aic7xxx_buffer = NULL;
- aic7xxx_buffer_size = length = 0;
- *start = NULL;
+ seq_printf(m, "\n");
+ seq_printf(m, "\n\n");
}
- else
- {
- *start = buffer;
- length = min_t(int, length, size - offset);
- memcpy(buffer, &aic7xxx_buffer[offset], length);
- }
-
- return (length);
+ return 0;
}
/*
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 3e1172adb37b..09ba1869d366 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -2836,20 +2836,15 @@ char *acornscsi_info(struct Scsi_Host *host)
return string;
}
-int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int acornscsi_show_info(struct seq_file *m, struct Scsi_Host *instance)
{
- int pos, begin = 0, devidx;
+ int devidx;
struct scsi_device *scd;
AS_Host *host;
- char *p = buffer;
-
- if (inout == 1)
- return -EINVAL;
host = (AS_Host *)instance->hostdata;
- p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
+ seq_printf(m, "AcornSCSI driver v%d.%d.%d"
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
" SYNC"
#endif
@@ -2864,14 +2859,14 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
#endif
"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
- p += sprintf(p, "SBIC: WD33C93A Address: %p IRQ : %d\n",
+ seq_printf(m, "SBIC: WD33C93A Address: %p IRQ : %d\n",
host->base + SBIC_REGIDX, host->scsi.irq);
#ifdef USE_DMAC
- p += sprintf(p, "DMAC: uPC71071 Address: %p IRQ : %d\n\n",
+ seq_printf(m, "DMAC: uPC71071 Address: %p IRQ : %d\n\n",
host->base + DMAC_OFFSET, host->scsi.irq);
#endif
- p += sprintf(p, "Statistics:\n"
+ seq_printf(m, "Statistics:\n"
"Queued commands: %-10u Issued commands: %-10u\n"
"Done commands : %-10u Reads : %-10u\n"
"Writes : %-10u Others : %-10u\n"
@@ -2886,7 +2881,7 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
for (devidx = 0; devidx < 9; devidx ++) {
unsigned int statptr, prev;
- p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
+ seq_printf(m, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
statptr = host->status_ptr[devidx] - 10;
if ((signed int)statptr < 0)
@@ -2896,7 +2891,7 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
if (host->status[devidx][statptr].when) {
- p += sprintf(p, "%c%02X:%02X+%2ld",
+ seq_printf(m, "%c%02X:%02X+%2ld",
host->status[devidx][statptr].irq ? '-' : ' ',
host->status[devidx][statptr].ph,
host->status[devidx][statptr].ssr,
@@ -2907,51 +2902,32 @@ int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
}
}
- p += sprintf(p, "\nAttached devices:\n");
+ seq_printf(m, "\nAttached devices:\n");
shost_for_each_device(scd, instance) {
- p += sprintf(p, "Device/Lun TaggedQ Sync\n");
- p += sprintf(p, " %d/%d ", scd->id, scd->lun);
+ seq_printf(m, "Device/Lun TaggedQ Sync\n");
+ seq_printf(m, " %d/%d ", scd->id, scd->lun);
if (scd->tagged_supported)
- p += sprintf(p, "%3sabled(%3d) ",
+ seq_printf(m, "%3sabled(%3d) ",
scd->simple_tags ? "en" : "dis",
scd->current_tag);
else
- p += sprintf(p, "unsupported ");
+ seq_printf(m, "unsupported ");
if (host->device[scd->id].sync_xfer & 15)
- p += sprintf(p, "offset %d, %d ns\n",
+ seq_printf(m, "offset %d, %d ns\n",
host->device[scd->id].sync_xfer & 15,
acornscsi_getperiod(host->device[scd->id].sync_xfer));
else
- p += sprintf(p, "async\n");
+ seq_printf(m, "async\n");
- pos = p - buffer;
- if (pos + begin < offset) {
- begin += pos;
- p = buffer;
- }
- pos = p - buffer;
- if (pos + begin > offset + length) {
- scsi_device_put(scd);
- break;
- }
}
-
- pos = p - buffer;
-
- *start = buffer + (offset - begin);
- pos -= offset - begin;
-
- if (pos > length)
- pos = length;
-
- return pos;
+ return 0;
}
static struct scsi_host_template acornscsi_template = {
.module = THIS_MODULE,
- .proc_info = acornscsi_proc_info,
+ .show_info = acornscsi_show_info,
.name = "AcornSCSI",
.info = acornscsi_info,
.queuecommand = acornscsi_queuecmd,
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index 9274510294ac..32d23212de48 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -220,47 +220,21 @@ static const char *arxescsi_info(struct Scsi_Host *host)
return string;
}
-/*
- * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
- * int length, int host_no, int inout)
- * Purpose : Return information about the driver to a user process accessing
- * the /proc filesystem.
- * Params : buffer - a buffer to write information to
- * start - a pointer into this buffer set by this routine to the start
- * of the required information.
- * offset - offset into information that we have read up to.
- * length - length of buffer
- * host_no - host number to return information for
- * inout - 0 for reading, 1 for writing.
- * Returns : length of data written to buffer.
- */
static int
-arxescsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
- int inout)
+arxescsi_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct arxescsi_info *info;
- char *p = buffer;
- int pos;
-
info = (struct arxescsi_info *)host->hostdata;
- if (inout == 1)
- return -EINVAL;
-
- p += sprintf(p, "ARXE 16-bit SCSI driver v%s\n", VERSION);
- p += fas216_print_host(&info->info, p);
- p += fas216_print_stats(&info->info, p);
- p += fas216_print_devices(&info->info, p);
-
- *start = buffer + offset;
- pos = p - buffer - offset;
- if (pos > length)
- pos = length;
- return pos;
+ seq_printf(m, "ARXE 16-bit SCSI driver v%s\n", VERSION);
+ fas216_print_host(&info->info, m);
+ fas216_print_stats(&info->info, m);
+ fas216_print_devices(&info->info, m);
+ return 0;
}
static struct scsi_host_template arxescsi_template = {
- .proc_info = arxescsi_proc_info,
+ .show_info = arxescsi_show_info,
.name = "ARXE SCSI card",
.info = arxescsi_info,
.queuecommand = fas216_noqueue_command,
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index c93938b246d5..b679778376c5 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -30,7 +30,6 @@
#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
#define NCR5380_intr cumanascsi_intr
#define NCR5380_queue_command cumanascsi_queue_command
-#define NCR5380_proc_info cumanascsi_proc_info
#define NCR5380_implementation_fields \
unsigned ctrl; \
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index e3bae93c3c22..58915f29055b 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -337,50 +337,25 @@ cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
return ret;
}
-/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset,
- * int length, int host_no, int inout)
- * Purpose : Return information about the driver to a user process accessing
- * the /proc filesystem.
- * Params : buffer - a buffer to write information to
- * start - a pointer into this buffer set by this routine to the start
- * of the required information.
- * offset - offset into information that we have read up to.
- * length - length of buffer
- * host_no - host number to return information for
- * inout - 0 for reading, 1 for writing.
- * Returns : length of data written to buffer.
- */
-int cumanascsi_2_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int cumanascsi_2_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct cumanascsi2_info *info;
- char *p = buffer;
- int pos;
-
- if (inout == 1)
- return cumanascsi_2_set_proc_info(host, buffer, length);
-
info = (struct cumanascsi2_info *)host->hostdata;
- p += sprintf(p, "Cumana SCSI II driver v%s\n", VERSION);
- p += fas216_print_host(&info->info, p);
- p += sprintf(p, "Term : o%s\n",
+ seq_printf(m, "Cumana SCSI II driver v%s\n", VERSION);
+ fas216_print_host(&info->info, m);
+ seq_printf(m, "Term : o%s\n",
info->terms ? "n" : "ff");
- p += fas216_print_stats(&info->info, p);
- p += fas216_print_devices(&info->info, p);
-
- *start = buffer + offset;
- pos = p - buffer - offset;
- if (pos > length)
- pos = length;
-
- return pos;
+ fas216_print_stats(&info->info, m);
+ fas216_print_devices(&info->info, m);
+ return 0;
}
static struct scsi_host_template cumanascsi2_template = {
.module = THIS_MODULE,
- .proc_info = cumanascsi_2_proc_info,
+ .show_info = cumanascsi_2_show_info,
+ .write_info = cumanascsi_2_set_proc_info,
.name = "Cumana SCSI II",
.info = cumanascsi_2_info,
.queuecommand = fas216_queue_command,
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index 8e36908415ec..5bf3c0d134b4 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -422,45 +422,20 @@ eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
return ret;
}
-/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
- * int length, int host_no, int inout)
- * Purpose : Return information about the driver to a user process accessing
- * the /proc filesystem.
- * Params : buffer - a buffer to write information to
- * start - a pointer into this buffer set by this routine to the start
- * of the required information.
- * offset - offset into information that we have read up to.
- * length - length of buffer
- * host_no - host number to return information for
- * inout - 0 for reading, 1 for writing.
- * Returns : length of data written to buffer.
- */
-int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int eesoxscsi_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct eesoxscsi_info *info;
- char *p = buffer;
- int pos;
-
- if (inout == 1)
- return eesoxscsi_set_proc_info(host, buffer, length);
info = (struct eesoxscsi_info *)host->hostdata;
- p += sprintf(p, "EESOX SCSI driver v%s\n", VERSION);
- p += fas216_print_host(&info->info, p);
- p += sprintf(p, "Term : o%s\n",
+ seq_printf(m, "EESOX SCSI driver v%s\n", VERSION);
+ fas216_print_host(&info->info, m);
+ seq_printf(m, "Term : o%s\n",
info->control & EESOX_TERM_ENABLE ? "n" : "ff");
- p += fas216_print_stats(&info->info, p);
- p += fas216_print_devices(&info->info, p);
-
- *start = buffer + offset;
- pos = p - buffer - offset;
- if (pos > length)
- pos = length;
-
- return pos;
+ fas216_print_stats(&info->info, m);
+ fas216_print_devices(&info->info, m);
+ return 0;
}
static ssize_t eesoxscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf)
@@ -498,7 +473,8 @@ static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
static struct scsi_host_template eesox_template = {
.module = THIS_MODULE,
- .proc_info = eesoxscsi_proc_info,
+ .show_info = eesoxscsi_show_info,
+ .write_info = eesoxscsi_set_proc_info,
.name = "EESOX SCSI",
.info = eesoxscsi_info,
.queuecommand = fas216_queue_command,
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 737554c37d9e..b46a6f6c0eb3 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2958,9 +2958,9 @@ void fas216_release(struct Scsi_Host *host)
queue_free(&info->queues.issue);
}
-int fas216_print_host(FAS216_Info *info, char *buffer)
+void fas216_print_host(FAS216_Info *info, struct seq_file *m)
{
- return sprintf(buffer,
+ seq_printf(m,
"\n"
"Chip : %s\n"
" Address: 0x%p\n"
@@ -2970,11 +2970,9 @@ int fas216_print_host(FAS216_Info *info, char *buffer)
info->scsi.irq, info->scsi.dma);
}
-int fas216_print_stats(FAS216_Info *info, char *buffer)
+void fas216_print_stats(FAS216_Info *info, struct seq_file *m)
{
- char *p = buffer;
-
- p += sprintf(p, "\n"
+ seq_printf(m, "\n"
"Command Statistics:\n"
" Queued : %u\n"
" Issued : %u\n"
@@ -2991,38 +2989,33 @@ int fas216_print_stats(FAS216_Info *info, char *buffer)
info->stats.writes, info->stats.miscs,
info->stats.disconnects, info->stats.aborts,
info->stats.bus_resets, info->stats.host_resets);
-
- return p - buffer;
}
-int fas216_print_devices(FAS216_Info *info, char *buffer)
+void fas216_print_devices(FAS216_Info *info, struct seq_file *m)
{
struct fas216_device *dev;
struct scsi_device *scd;
- char *p = buffer;
- p += sprintf(p, "Device/Lun TaggedQ Parity Sync\n");
+ seq_printf(m, "Device/Lun TaggedQ Parity Sync\n");
shost_for_each_device(scd, info->host) {
dev = &info->device[scd->id];
- p += sprintf(p, " %d/%d ", scd->id, scd->lun);
+ seq_printf(m, " %d/%d ", scd->id, scd->lun);
if (scd->tagged_supported)
- p += sprintf(p, "%3sabled(%3d) ",
+ seq_printf(m, "%3sabled(%3d) ",
scd->simple_tags ? "en" : "dis",
scd->current_tag);
else
- p += sprintf(p, "unsupported ");
+ seq_printf(m, "unsupported ");
- p += sprintf(p, "%3sabled ", dev->parity_enabled ? "en" : "dis");
+ seq_printf(m, "%3sabled ", dev->parity_enabled ? "en" : "dis");
if (dev->sof)
- p += sprintf(p, "offset %d, %d ns\n",
+ seq_printf(m, "offset %d, %d ns\n",
dev->sof, dev->period * 4);
else
- p += sprintf(p, "async\n");
+ seq_printf(m, "async\n");
}
-
- return p - buffer;
}
EXPORT_SYMBOL(fas216_init);
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index df2e1b3ddfe2..c57c16ef8193 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -358,9 +358,9 @@ extern void fas216_remove (struct Scsi_Host *instance);
*/
extern void fas216_release (struct Scsi_Host *instance);
-extern int fas216_print_host(FAS216_Info *info, char *buffer);
-extern int fas216_print_stats(FAS216_Info *info, char *buffer);
-extern int fas216_print_devices(FAS216_Info *info, char *buffer);
+extern void fas216_print_host(FAS216_Info *info, struct seq_file *m);
+extern void fas216_print_stats(FAS216_Info *info, struct seq_file *m);
+extern void fas216_print_devices(FAS216_Info *info, struct seq_file *m);
/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort this command
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 48facdc18002..4266eef8aca1 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -31,7 +31,8 @@
#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
#define NCR5380_intr oakscsi_intr
#define NCR5380_queue_command oakscsi_queue_command
-#define NCR5380_proc_info oakscsi_proc_info
+#define NCR5380_show_info oakscsi_show_info
+#define NCR5380_write_info oakscsi_write_info
#define NCR5380_implementation_fields \
void __iomem *base
@@ -115,7 +116,8 @@ printk("reading %p len %d\n", addr, len);
static struct scsi_host_template oakscsi_template = {
.module = THIS_MODULE,
- .proc_info = oakscsi_proc_info,
+ .show_info = oakscsi_show_info,
+ .write_info = oakscsi_write_info,
.name = "Oak 16-bit SCSI",
.info = oakscsi_info,
.queuecommand = oakscsi_queue_command,
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index 246600b93555..abc9593615e9 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -237,32 +237,20 @@ powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
* inout - 0 for reading, 1 for writing.
* Returns : length of data written to buffer.
*/
-int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int powertecscsi_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct powertec_info *info;
- char *p = buffer;
- int pos;
-
- if (inout == 1)
- return powertecscsi_set_proc_info(host, buffer, length);
info = (struct powertec_info *)host->hostdata;
- p += sprintf(p, "PowerTec SCSI driver v%s\n", VERSION);
- p += fas216_print_host(&info->info, p);
- p += sprintf(p, "Term : o%s\n",
+ seq_printf(m, "PowerTec SCSI driver v%s\n", VERSION);
+ fas216_print_host(&info->info, m);
+ seq_printf(m, "Term : o%s\n",
info->term_ctl ? "n" : "ff");
- p += fas216_print_stats(&info->info, p);
- p += fas216_print_devices(&info->info, p);
-
- *start = buffer + offset;
- pos = p - buffer - offset;
- if (pos > length)
- pos = length;
-
- return pos;
+ fas216_print_stats(&info->info, m);
+ fas216_print_devices(&info->info, m);
+ return 0;
}
static ssize_t powertecscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf)
@@ -291,7 +279,8 @@ static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
static struct scsi_host_template powertecscsi_template = {
.module = THIS_MODULE,
- .proc_info = powertecscsi_proc_info,
+ .show_info = powertecscsi_show_info,
+ .write_info = powertecscsi_set_proc_info,
.name = "PowerTec SCSI",
.info = powertecscsi_info,
.queuecommand = fas216_queue_command,
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 2db79b469d9e..0f3cdbc80ba6 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -719,119 +719,94 @@ static void __init NCR5380_print_options(struct Scsi_Host *instance)
* Inputs : instance, pointer to this instance.
*/
-static void NCR5380_print_status(struct Scsi_Host *instance)
+static void lprint_Scsi_Cmnd(Scsi_Cmnd *cmd)
{
- char *pr_bfr;
- char *start;
- int len;
-
- NCR_PRINT(NDEBUG_ANY);
- NCR_PRINT_PHASE(NDEBUG_ANY);
-
- pr_bfr = (char *)__get_free_page(GFP_ATOMIC);
- if (!pr_bfr) {
- printk("NCR5380_print_status: no memory for print buffer\n");
- return;
- }
- len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
- pr_bfr[len] = 0;
- printk("\n%s\n", pr_bfr);
- free_page((unsigned long)pr_bfr);
+ int i, s;
+ unsigned char *command;
+ printk("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ printk(KERN_CONT " command = ");
+ command = cmd->cmnd;
+ printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ printk(KERN_CONT " %02x", command[i]);
+ printk("\n");
}
-
-/******************************************/
-/*
- * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written
-*/
-
-#undef SPRINTF
-#define SPRINTF(fmt,args...) \
- do { \
- if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
- pos += sprintf(pos, fmt , ## args); \
- } while(0)
-static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
-
-static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
- char **start, off_t offset, int length, int inout)
+static void NCR5380_print_status(struct Scsi_Host *instance)
{
- char *pos = buffer;
struct NCR5380_hostdata *hostdata;
Scsi_Cmnd *ptr;
unsigned long flags;
- off_t begin = 0;
-#define check_offset() \
- do { \
- if (pos - buffer < offset - begin) { \
- begin += pos - buffer; \
- pos = buffer; \
- } \
- } while (0)
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
- if (inout) /* Has data been written to the file ? */
- return -ENOSYS; /* Currently this is a no-op */
- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- check_offset();
+ printk("\nNCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
local_irq_save(flags);
- SPRINTF("NCR5380: coroutine is%s running.\n",
+ printk("NCR5380: coroutine is%s running.\n",
main_running ? "" : "n't");
- check_offset();
if (!hostdata->connected)
- SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ printk("scsi%d: no currently connected command\n", HOSTNO);
else
- pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected,
- pos, buffer, length);
- SPRINTF("scsi%d: issue_queue\n", HOSTNO);
- check_offset();
- for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
- check_offset();
- }
+ lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected);
+ printk("scsi%d: issue_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ lprint_Scsi_Cmnd(ptr);
- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
- check_offset();
+ printk("scsi%d: disconnected_queue\n", HOSTNO);
for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
- check_offset();
- }
+ ptr = NEXT(ptr))
+ lprint_Scsi_Cmnd(ptr);
local_irq_restore(flags);
- *start = buffer + (offset - begin);
- if (pos - buffer < offset - begin)
- return 0;
- else if (pos - buffer - (offset - begin) < length)
- return pos - buffer - (offset - begin);
- return length;
+ printk("\n");
}
-static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+static void show_Scsi_Cmnd(Scsi_Cmnd *cmd, struct seq_file *m)
{
int i, s;
unsigned char *command;
- SPRINTF("scsi%d: destination target %d, lun %d\n",
+ seq_printf(m, "scsi%d: destination target %d, lun %d\n",
H_NO(cmd), cmd->device->id, cmd->device->lun);
- SPRINTF(" command = ");
+ seq_printf(m, " command = ");
command = cmd->cmnd;
- SPRINTF("%2d (0x%02x)", command[0], command[0]);
+ seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- SPRINTF(" %02x", command[i]);
- SPRINTF("\n");
- return pos;
+ seq_printf(m, " %02x", command[i]);
+ seq_printf(m, "\n");
}
+static int NCR5380_show_info(struct seq_file *m, struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ seq_printf(m, "NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ local_irq_save(flags);
+ seq_printf(m, "NCR5380: coroutine is%s running.\n",
+ main_running ? "" : "n't");
+ if (!hostdata->connected)
+ seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
+ else
+ show_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
+ seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ show_Scsi_Cmnd(ptr, m);
+
+ seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr))
+ show_Scsi_Cmnd(ptr, m);
+
+ local_irq_restore(flags);
+ return 0;
+}
/*
* Function : void NCR5380_init (struct Scsi_Host *instance)
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index df740cbbaef4..a3e6c8a3ff0f 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -1100,7 +1100,7 @@ static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
#include "atari_NCR5380.c"
static struct scsi_host_template driver_template = {
- .proc_info = atari_scsi_proc_info,
+ .show_info = atari_scsi_show_info,
.name = "Atari native SCSI",
.detect = atari_scsi_detect,
.release = atari_scsi_release,
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index bd52df78b209..11c624bb122d 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -47,7 +47,7 @@
#define NCR5380_intr atari_scsi_intr
#define NCR5380_queue_command atari_scsi_queue_command
#define NCR5380_abort atari_scsi_abort
-#define NCR5380_proc_info atari_scsi_proc_info
+#define NCR5380_show_info atari_scsi_show_info
#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0)
#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1)
#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst )
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index cfc73041f102..15a629d8ed08 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -3099,38 +3099,14 @@ static const char *atp870u_info(struct Scsi_Host *notused)
return buffer;
}
-#define BLS buffer + len + size
-static int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer,
- char **start, off_t offset, int length, int inout)
+static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr)
{
- static u8 buff[512];
- int size = 0;
- int len = 0;
- off_t begin = 0;
- off_t pos = 0;
-
- if (inout)
- return -EINVAL;
- if (offset == 0)
- memset(buff, 0, sizeof(buff));
- size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.6+ac\n");
- len += size;
- pos = begin + len;
- size = 0;
-
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port);
- size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
- len += size;
- pos = begin + len;
-
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length) {
- len = length; /* Ending slop */
- }
- return (len);
+ seq_printf(m, "ACARD AEC-671X Driver Version: 2.6+ac\n");
+ seq_printf(m, "\n");
+ seq_printf(m, "Adapter Configuration:\n");
+ seq_printf(m, " Base IO: %#.4lx\n", HBAptr->io_port);
+ seq_printf(m, " IRQ: %d\n", HBAptr->irq);
+ return 0;
}
@@ -3177,7 +3153,7 @@ static struct scsi_host_template atp870u_template = {
.module = THIS_MODULE,
.name = "atp870u" /* name */,
.proc_name = "atp870u",
- .proc_info = atp870u_proc_info,
+ .show_info = atp870u_show_info,
.info = atp870u_info /* info */,
.queuecommand = atp870u_queuecommand /* queuecommand */,
.eh_abort_handler = atp870u_abort /* abort */,
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 214d691adb53..9014690fe841 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -369,7 +369,7 @@ beiscsi_set_vlan_tag(struct Scsi_Host *shost,
break;
default:
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BS_%d : Unkown Param Type : %d\n",
+ "BS_%d : Unknown Param Type : %d\n",
iface_param->param);
return -ENOSYS;
}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index a6c2fe4b4d65..55cc9902263d 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1292,7 +1292,7 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
break;
default:
return snprintf(buf, PAGE_SIZE,
- "Unkown Adapter Family: 0x%x\n", dev_id);
+ "Unknown Adapter Family: 0x%x\n", dev_id);
break;
}
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 50fcd018d14b..11596b2c4702 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -88,9 +88,6 @@
#define BNX2FC_MAX_NPIV 256
-#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048
-#define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS
-#define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE
#define BNX2FC_MIN_PAYLOAD 256
#define BNX2FC_MAX_PAYLOAD 2048
#define BNX2FC_MFS \
@@ -108,11 +105,8 @@
#define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe))
#define BNX2FC_5771X_DB_PAGE_SIZE 128
-#define BNX2FC_MAX_TASKS \
- (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS)
#define BNX2FC_TASK_SIZE 128
#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE)
-#define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE)
#define BNX2FC_MAX_ROWS_IN_HASH_TBL 8
#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024)
@@ -125,12 +119,9 @@
#define BNX2FC_WRITE (1 << 0)
#define BNX2FC_MIN_XID 0
-#define BNX2FC_MAX_XID \
- (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1)
#define FCOE_MAX_NUM_XIDS 0x2000
-#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1)
-#define FCOE_MAX_XID (FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1)
-#define FCOE_XIDS_PER_CPU (FCOE_MIN_XID + (512 * nr_cpu_ids) - 1)
+#define FCOE_MAX_XID_OFFSET (FCOE_MAX_NUM_XIDS - 1)
+#define FCOE_XIDS_PER_CPU_OFFSET ((512 * nr_cpu_ids) - 1)
#define BNX2FC_MAX_LUN 0xFFFF
#define BNX2FC_MAX_FCP_TGT 256
#define BNX2FC_MAX_CMD_LEN 16
@@ -206,6 +197,13 @@ struct bnx2fc_hba {
#define BNX2FC_FLAG_FW_INIT_DONE 0
#define BNX2FC_FLAG_DESTROY_CMPL 1
u32 next_conn_id;
+
+ /* xid resources */
+ u16 max_xid;
+ u32 max_tasks;
+ u32 max_outstanding_cmds;
+ u32 elstm_xids;
+
struct fcoe_task_ctx_entry **task_ctx;
dma_addr_t *task_ctx_dma;
struct regpair *task_ctx_bd_tbl;
@@ -504,8 +502,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba);
void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba);
int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba);
void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba);
-struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
- u16 min_xid, u16 max_xid);
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba);
void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr);
void bnx2fc_get_link_state(struct bnx2fc_hba *hba);
char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 2daf4b0da434..7dffec1e5715 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -71,7 +71,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb);
static void bnx2fc_start_disc(struct bnx2fc_interface *interface);
static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev);
static int bnx2fc_lport_config(struct fc_lport *lport);
-static int bnx2fc_em_config(struct fc_lport *lport);
+static int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba);
static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba);
static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba);
static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
@@ -940,19 +940,21 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
fc_exch_init(lport);
fc_rport_init(lport);
fc_disc_init(lport);
+ fc_disc_config(lport, lport);
return 0;
}
-static int bnx2fc_em_config(struct fc_lport *lport)
+static int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba)
{
- int max_xid;
+ int fcoe_min_xid, fcoe_max_xid;
+ fcoe_min_xid = hba->max_xid + 1;
if (nr_cpu_ids <= 2)
- max_xid = FCOE_XIDS_PER_CPU;
+ fcoe_max_xid = hba->max_xid + FCOE_XIDS_PER_CPU_OFFSET;
else
- max_xid = FCOE_MAX_XID;
- if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
- max_xid, NULL)) {
+ fcoe_max_xid = hba->max_xid + FCOE_MAX_XID_OFFSET;
+ if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, fcoe_min_xid,
+ fcoe_max_xid, NULL)) {
printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
return -ENOMEM;
}
@@ -1299,6 +1301,12 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
mutex_init(&hba->hba_mutex);
hba->cnic = cnic;
+
+ hba->max_tasks = cnic->max_fcoe_exchanges;
+ hba->elstm_xids = (hba->max_tasks / 2);
+ hba->max_outstanding_cmds = hba->elstm_xids;
+ hba->max_xid = (hba->max_tasks - 1);
+
rc = bnx2fc_bind_pcidev(hba);
if (rc) {
printk(KERN_ERR PFX "create_adapter: bind error\n");
@@ -1317,8 +1325,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
hba->num_ofld_sess = 0;
- hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
- BNX2FC_MAX_XID);
+ hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba);
if (!hba->cmd_mgr) {
printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
goto cmgr_err;
@@ -1329,13 +1336,13 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
FCOE_IOS_PER_CONNECTION_SHIFT;
fcoe_cap->capability1 |= BNX2FC_NUM_MAX_SESS <<
FCOE_LOGINS_PER_PORT_SHIFT;
- fcoe_cap->capability2 = BNX2FC_MAX_OUTSTANDING_CMNDS <<
+ fcoe_cap->capability2 = hba->max_outstanding_cmds <<
FCOE_NUMBER_OF_EXCHANGES_SHIFT;
fcoe_cap->capability2 |= BNX2FC_MAX_NPIV <<
FCOE_NPIV_WWN_PER_PORT_SHIFT;
fcoe_cap->capability3 = BNX2FC_NUM_MAX_SESS <<
FCOE_TARGETS_SUPPORTED_SHIFT;
- fcoe_cap->capability3 |= BNX2FC_MAX_OUTSTANDING_CMNDS <<
+ fcoe_cap->capability3 |= hba->max_outstanding_cmds <<
FCOE_OUTSTANDING_COMMANDS_SHIFT;
fcoe_cap->capability4 = FCOE_CAPABILITY4_STATEFUL;
@@ -1415,7 +1422,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
struct Scsi_Host *shost;
struct fc_vport *vport = dev_to_vport(parent);
struct bnx2fc_lport *blport;
- struct bnx2fc_hba *hba;
+ struct bnx2fc_hba *hba = interface->hba;
int rc = 0;
blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
@@ -1425,6 +1432,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
}
/* Allocate Scsi_Host structure */
+ bnx2fc_shost_template.can_queue = hba->max_outstanding_cmds;
if (!npiv)
lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
else
@@ -1476,7 +1484,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
/* Allocate exchange manager */
if (!npiv)
- rc = bnx2fc_em_config(lport);
+ rc = bnx2fc_em_config(lport, hba);
else {
shost = vport_to_shost(vport);
n_port = shost_priv(shost);
@@ -1490,7 +1498,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
bnx2fc_interface_get(interface);
- hba = interface->hba;
spin_lock_bh(&hba->hba_lock);
blport->lport = lport;
list_add_tail(&blport->list, &hba->vports);
@@ -2133,6 +2140,7 @@ static int _bnx2fc_create(struct net_device *netdev,
}
ctlr = bnx2fc_to_ctlr(interface);
+ cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
interface->vlan_id = vlan_id;
interface->timer_work_queue =
@@ -2143,7 +2151,7 @@ static int _bnx2fc_create(struct net_device *netdev,
goto ifput_err;
}
- lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0);
+ lport = bnx2fc_if_create(interface, &cdev->dev, 0);
if (!lport) {
printk(KERN_ERR PFX "Failed to create interface (%s)\n",
netdev->name);
@@ -2159,8 +2167,6 @@ static int _bnx2fc_create(struct net_device *netdev,
/* Make this master N_port */
ctlr->lp = lport;
- cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
-
if (link_state == BNX2FC_CREATE_LINK_UP)
cdev->enabled = FCOE_CTLR_ENABLED;
else
@@ -2706,7 +2712,6 @@ static struct scsi_host_template bnx2fc_shost_template = {
.change_queue_type = fc_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
- .can_queue = BNX2FC_CAN_QUEUE,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
.max_sectors = 1024,
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 85ea98a80f40..50510ffe1bf5 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -77,7 +77,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
- fcoe_init1.num_tasks = BNX2FC_MAX_TASKS;
+ fcoe_init1.num_tasks = hba->max_tasks;
fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX;
fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX;
fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ;
@@ -697,7 +697,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
- if (xid > BNX2FC_MAX_XID) {
+ if (xid > hba->max_xid) {
BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
xid);
goto ret_err_rqe;
@@ -815,7 +815,7 @@ ret_err_rqe:
BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
- if (xid > BNX2FC_MAX_XID) {
+ if (xid > hba->max_xid) {
BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid);
goto ret_warn_rqe;
}
@@ -880,7 +880,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
spin_lock_bh(&tgt->tgt_lock);
xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
- if (xid >= BNX2FC_MAX_TASKS) {
+ if (xid >= hba->max_tasks) {
printk(KERN_ERR PFX "ERROR:xid out of range\n");
spin_unlock_bh(&tgt->tgt_lock);
return;
@@ -1842,6 +1842,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
int rc = 0;
struct regpair *task_ctx_bdt;
dma_addr_t addr;
+ int task_ctx_arr_sz;
int i;
/*
@@ -1865,7 +1866,8 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
* Allocate task_ctx which is an array of pointers pointing to
* a page containing 32 task contexts
*/
- hba->task_ctx = kzalloc((BNX2FC_TASK_CTX_ARR_SZ * sizeof(void *)),
+ task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE);
+ hba->task_ctx = kzalloc((task_ctx_arr_sz * sizeof(void *)),
GFP_KERNEL);
if (!hba->task_ctx) {
printk(KERN_ERR PFX "unable to allocate task context array\n");
@@ -1876,7 +1878,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
/*
* Allocate task_ctx_dma which is an array of dma addresses
*/
- hba->task_ctx_dma = kmalloc((BNX2FC_TASK_CTX_ARR_SZ *
+ hba->task_ctx_dma = kmalloc((task_ctx_arr_sz *
sizeof(dma_addr_t)), GFP_KERNEL);
if (!hba->task_ctx_dma) {
printk(KERN_ERR PFX "unable to alloc context mapping array\n");
@@ -1885,7 +1887,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
}
task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl;
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev,
PAGE_SIZE,
@@ -1905,7 +1907,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
return 0;
out3:
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
if (hba->task_ctx[i]) {
dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
@@ -1929,6 +1931,7 @@ out:
void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba)
{
+ int task_ctx_arr_sz;
int i;
if (hba->task_ctx_bd_tbl) {
@@ -1938,8 +1941,9 @@ void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba)
hba->task_ctx_bd_tbl = NULL;
}
+ task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE);
if (hba->task_ctx) {
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
if (hba->task_ctx[i]) {
dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
hba->task_ctx[i],
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 60798e829de6..723a9a8ba5ee 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -239,8 +239,7 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code)
sc_cmd->scsi_done(sc_cmd);
}
-struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
- u16 min_xid, u16 max_xid)
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba)
{
struct bnx2fc_cmd_mgr *cmgr;
struct io_bdt *bdt_info;
@@ -252,6 +251,8 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
int num_ios, num_pri_ios;
size_t bd_tbl_sz;
int arr_sz = num_possible_cpus() + 1;
+ u16 min_xid = BNX2FC_MIN_XID;
+ u16 max_xid = hba->max_xid;
if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) {
printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \
@@ -298,7 +299,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
* of slow path requests.
*/
xid = BNX2FC_MIN_XID;
- num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS;
+ num_pri_ios = num_ios - hba->elstm_xids;
for (i = 0; i < num_ios; i++) {
io_req = kzalloc(sizeof(*io_req), GFP_KERNEL);
@@ -367,7 +368,7 @@ void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr)
struct bnx2fc_hba *hba = cmgr->hba;
size_t bd_tbl_sz;
u16 min_xid = BNX2FC_MIN_XID;
- u16 max_xid = BNX2FC_MAX_XID;
+ u16 max_xid = hba->max_xid;
int num_ios;
int i;
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index b44d04e41b0d..f109e3b073c3 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -580,8 +580,8 @@ struct bnx2i_5771x_dbell {
* @sq_mem_size: SQ size
* @sq_prod_qe: SQ producer entry pointer
* @sq_cons_qe: SQ consumer entry pointer
- * @sq_first_qe: virtaul address of first entry in SQ
- * @sq_last_qe: virtaul address of last entry in SQ
+ * @sq_first_qe: virtual address of first entry in SQ
+ * @sq_last_qe: virtual address of last entry in SQ
* @sq_prod_idx: SQ producer index
* @sq_cons_idx: SQ consumer index
* @sqe_left: number sq entry left
@@ -593,8 +593,8 @@ struct bnx2i_5771x_dbell {
* @cq_mem_size: CQ size
* @cq_prod_qe: CQ producer entry pointer
* @cq_cons_qe: CQ consumer entry pointer
- * @cq_first_qe: virtaul address of first entry in CQ
- * @cq_last_qe: virtaul address of last entry in CQ
+ * @cq_first_qe: virtual address of first entry in CQ
+ * @cq_last_qe: virtual address of last entry in CQ
* @cq_prod_idx: CQ producer index
* @cq_cons_idx: CQ consumer index
* @cqe_left: number cq entry left
@@ -608,8 +608,8 @@ struct bnx2i_5771x_dbell {
* @rq_mem_size: RQ size
* @rq_prod_qe: RQ producer entry pointer
* @rq_cons_qe: RQ consumer entry pointer
- * @rq_first_qe: virtaul address of first entry in RQ
- * @rq_last_qe: virtaul address of last entry in RQ
+ * @rq_first_qe: virtual address of first entry in RQ
+ * @rq_last_qe: virtual address of last entry in RQ
* @rq_prod_idx: RQ producer index
* @rq_cons_idx: RQ consumer index
* @rqe_left: number rq entry left
diff --git a/drivers/scsi/csiostor/Makefile b/drivers/scsi/csiostor/Makefile
index b581966c88f9..913b9a92fb06 100644
--- a/drivers/scsi/csiostor/Makefile
+++ b/drivers/scsi/csiostor/Makefile
@@ -8,4 +8,5 @@ ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor.o
csiostor-objs := csio_attr.o csio_init.o csio_lnode.o csio_scsi.o \
- csio_hw.o csio_isr.o csio_mb.o csio_rnode.o csio_wr.o
+ csio_hw.o csio_hw_t4.o csio_hw_t5.o csio_isr.o \
+ csio_mb.o csio_rnode.o csio_wr.o
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index bdd78fb4fc70..193605519361 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -61,7 +61,7 @@ int csio_msi = 2;
static int dev_num;
/* FCoE Adapter types & its description */
-static const struct csio_adap_desc csio_fcoe_adapters[] = {
+static const struct csio_adap_desc csio_t4_fcoe_adapters[] = {
{"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"},
{"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"},
{"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"},
@@ -77,7 +77,38 @@ static const struct csio_adap_desc csio_fcoe_adapters[] = {
{"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"},
{"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"},
{"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"},
- {"T4 FPGA", "Chelsio T4 FPGA [FCoE]"}
+ {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"},
+ {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"},
+ {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"},
+ {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"},
+ {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"},
+ {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"},
+ {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"},
+ {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"},
+ {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"}
+};
+
+static const struct csio_adap_desc csio_t5_fcoe_adapters[] = {
+ {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"},
+ {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"},
+ {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"},
+ {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"},
+ {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"},
+ {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"},
+ {"T540-CH 10G", "Chelsio T540-CH 10G [FCoE]"},
+ {"T520-SO 10G", "Chelsio T520-SO 10G [FCoE]"},
+ {"T520-CX4 10G", "Chelsio T520-CX4 10G [FCoE]"},
+ {"T520-BT 10G", "Chelsio T520-BT 10G [FCoE]"},
+ {"T504-BT 1G", "Chelsio T504-BT 1G [FCoE]"},
+ {"B520-SR 10G", "Chelsio B520-SR 10G [FCoE]"},
+ {"B504-BT 1G", "Chelsio B504-BT 1G [FCoE]"},
+ {"T580-CR 10G", "Chelsio T580-CR 10G [FCoE]"},
+ {"T540-LP-CR 10G", "Chelsio T540-LP-CR 10G [FCoE]"},
+ {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"},
+ {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"},
+ {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"},
+ {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"},
+ {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"}
};
static void csio_mgmtm_cleanup(struct csio_mgmtm *);
@@ -124,7 +155,7 @@ int csio_is_hw_removing(struct csio_hw *hw)
* at the time it indicated completion is stored there. Returns 0 if the
* operation completes and -EAGAIN otherwise.
*/
-static int
+int
csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask,
int polarity, int attempts, int delay, uint32_t *valp)
{
@@ -145,6 +176,24 @@ csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask,
}
}
+/*
+ * csio_hw_tp_wr_bits_indirect - set/clear bits in an indirect TP register
+ * @hw: the adapter
+ * @addr: the indirect TP register address
+ * @mask: specifies the field within the register to modify
+ * @val: new value for the field
+ *
+ * Sets a field of an indirect TP register to the given value.
+ */
+void
+csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr,
+ unsigned int mask, unsigned int val)
+{
+ csio_wr_reg32(hw, addr, TP_PIO_ADDR);
+ val |= csio_rd_reg32(hw, TP_PIO_DATA) & ~mask;
+ csio_wr_reg32(hw, val, TP_PIO_DATA);
+}
+
void
csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask,
uint32_t value)
@@ -157,242 +206,22 @@ csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask,
}
-/*
- * csio_hw_mc_read - read from MC through backdoor accesses
- * @hw: the hw module
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from MC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int
-csio_hw_mc_read(struct csio_hw *hw, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
- csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
- csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
- csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
- MC_BIST_CMD);
- i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, MC_DATA(16));
-#undef MC_DATA
- return 0;
-}
-
-/*
- * csio_hw_edc_read - read from EDC through backdoor accesses
- * @hw: the hw module
- * @idx: which EDC to access
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int
-csio_hw_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- idx *= EDC_STRIDE;
- if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
- csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
- csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
- csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
- EDC_BIST_CMD + idx);
- i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, EDC_DATA(16));
-#undef EDC_DATA
- return 0;
-}
-
-/*
- * csio_mem_win_rw - read/write memory through PCIE memory window
- * @hw: the adapter
- * @addr: address of first byte requested
- * @data: MEMWIN0_APERTURE bytes of data containing the requested address
- * @dir: direction of transfer 1 => read, 0 => write
- *
- * Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
- * MEMWIN0_APERTURE-byte-aligned address that covers the requested
- * address @addr.
- */
-static int
-csio_mem_win_rw(struct csio_hw *hw, u32 addr, u32 *data, int dir)
-{
- int i;
-
- /*
- * Setup offset into PCIE memory window. Address must be a
- * MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to
- * ensure that changes propagate before we attempt to use the new
- * values.)
- */
- csio_wr_reg32(hw, addr & ~(MEMWIN0_APERTURE - 1),
- PCIE_MEM_ACCESS_OFFSET);
- csio_rd_reg32(hw, PCIE_MEM_ACCESS_OFFSET);
-
- /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
- for (i = 0; i < MEMWIN0_APERTURE; i = i + sizeof(__be32)) {
- if (dir)
- *data++ = csio_rd_reg32(hw, (MEMWIN0_BASE + i));
- else
- csio_wr_reg32(hw, *data++, (MEMWIN0_BASE + i));
- }
-
- return 0;
-}
-
-/*
- * csio_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
- * @hw: the csio_hw
- * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
- * @addr: address within indicated memory type
- * @len: amount of memory to transfer
- * @buf: host memory buffer
- * @dir: direction of transfer 1 => read, 0 => write
- *
- * Reads/writes an [almost] arbitrary memory region in the firmware: the
- * firmware memory address, length and host buffer must be aligned on
- * 32-bit boudaries. The memory is transferred as a raw byte sequence
- * from/to the firmware's memory. If this memory contains data
- * structures which contain multi-byte integers, it's the callers
- * responsibility to perform appropriate byte order conversions.
- */
-static int
-csio_memory_rw(struct csio_hw *hw, int mtype, u32 addr, u32 len,
- uint32_t *buf, int dir)
-{
- uint32_t pos, start, end, offset, memoffset;
- int ret;
- uint32_t *data;
-
- /*
- * Argument sanity checks ...
- */
- if ((addr & 0x3) || (len & 0x3))
- return -EINVAL;
-
- data = kzalloc(MEMWIN0_APERTURE, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- /* Offset into the region of memory which is being accessed
- * MEM_EDC0 = 0
- * MEM_EDC1 = 1
- * MEM_MC = 2
- */
- memoffset = (mtype * (5 * 1024 * 1024));
-
- /* Determine the PCIE_MEM_ACCESS_OFFSET */
- addr = addr + memoffset;
-
- /*
- * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
- * at a time so we need to round down the start and round up the end.
- * We'll start copying out of the first line at (addr - start) a word
- * at a time.
- */
- start = addr & ~(MEMWIN0_APERTURE-1);
- end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
- offset = (addr - start)/sizeof(__be32);
-
- for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
- /*
- * If we're writing, copy the data from the caller's memory
- * buffer
- */
- if (!dir) {
- /*
- * If we're doing a partial write, then we need to do
- * a read-modify-write ...
- */
- if (offset || len < MEMWIN0_APERTURE) {
- ret = csio_mem_win_rw(hw, pos, data, 1);
- if (ret) {
- kfree(data);
- return ret;
- }
- }
- while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
- len > 0) {
- data[offset++] = *buf++;
- len -= sizeof(__be32);
- }
- }
-
- /*
- * Transfer a block of memory and bail if there's an error.
- */
- ret = csio_mem_win_rw(hw, pos, data, dir);
- if (ret) {
- kfree(data);
- return ret;
- }
-
- /*
- * If we're reading, copy the data into the caller's memory
- * buffer.
- */
- if (dir)
- while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
- len > 0) {
- *buf++ = data[offset++];
- len -= sizeof(__be32);
- }
- }
-
- kfree(data);
-
- return 0;
-}
-
static int
csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf)
{
- return csio_memory_rw(hw, mtype, addr, len, buf, 0);
+ return hw->chip_ops->chip_memory_rw(hw, MEMWIN_CSIOSTOR, mtype,
+ addr, len, buf, 0);
}
/*
* EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
*/
-#define EEPROM_MAX_RD_POLL 40
-#define EEPROM_MAX_WR_POLL 6
-#define EEPROM_STAT_ADDR 0x7bfc
-#define VPD_BASE 0x400
-#define VPD_BASE_OLD 0
-#define VPD_LEN 512
+#define EEPROM_MAX_RD_POLL 40
+#define EEPROM_MAX_WR_POLL 6
+#define EEPROM_STAT_ADDR 0x7bfc
+#define VPD_BASE 0x400
+#define VPD_BASE_OLD 0
+#define VPD_LEN 1024
#define VPD_INFO_FLD_HDR_SIZE 3
/*
@@ -817,23 +646,6 @@ out:
return 0;
}
-/*
- * csio_hw_flash_cfg_addr - return the address of the flash
- * configuration file
- * @hw: the HW module
- *
- * Return the address within the flash where the Firmware Configuration
- * File is stored.
- */
-static unsigned int
-csio_hw_flash_cfg_addr(struct csio_hw *hw)
-{
- if (hw->params.sf_size == 0x100000)
- return FPGA_FLASH_CFG_OFFSET;
- else
- return FLASH_CFG_OFFSET;
-}
-
static void
csio_hw_print_fw_version(struct csio_hw *hw, char *str)
{
@@ -898,13 +710,13 @@ csio_hw_check_fw_version(struct csio_hw *hw)
minor = FW_HDR_FW_VER_MINOR_GET(hw->fwrev);
micro = FW_HDR_FW_VER_MICRO_GET(hw->fwrev);
- if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */
+ if (major != FW_VERSION_MAJOR(hw)) { /* major mismatch - fail */
csio_err(hw, "card FW has major version %u, driver wants %u\n",
- major, FW_VERSION_MAJOR);
+ major, FW_VERSION_MAJOR(hw));
return -EINVAL;
}
- if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO)
+ if (minor == FW_VERSION_MINOR(hw) && micro == FW_VERSION_MICRO(hw))
return 0; /* perfect match */
/* Minor/micro version mismatch */
@@ -1044,7 +856,7 @@ static void
csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
{
uint16_t val;
- uint32_t pcie_cap;
+ int pcie_cap;
if (!csio_pci_capability(hw->pdev, PCI_CAP_ID_EXP, &pcie_cap)) {
pci_read_config_word(hw->pdev,
@@ -1056,84 +868,6 @@ csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
}
}
-
-/*
- * Return the specified PCI-E Configuration Space register from our Physical
- * Function. We try first via a Firmware LDST Command since we prefer to let
- * the firmware own all of these registers, but if that fails we go for it
- * directly ourselves.
- */
-static uint32_t
-csio_read_pcie_cfg4(struct csio_hw *hw, int reg)
-{
- u32 val = 0;
- struct csio_mb *mbp;
- int rv;
- struct fw_ldst_cmd *ldst_cmd;
-
- mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
- if (!mbp) {
- CSIO_INC_STATS(hw, n_err_nomem);
- pci_read_config_dword(hw->pdev, reg, &val);
- return val;
- }
-
- csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
-
- rv = csio_mb_issue(hw, mbp);
-
- /*
- * If the LDST Command suucceeded, exctract the returned register
- * value. Otherwise read it directly ourself.
- */
- if (rv == 0) {
- ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
- val = ntohl(ldst_cmd->u.pcie.data[0]);
- } else
- pci_read_config_dword(hw->pdev, reg, &val);
-
- mempool_free(mbp, hw->mb_mempool);
-
- return val;
-} /* csio_read_pcie_cfg4 */
-
-static int
-csio_hw_set_mem_win(struct csio_hw *hw)
-{
- u32 bar0;
-
- /*
- * Truncation intentional: we only read the bottom 32-bits of the
- * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
- * read BAR0 instead of using pci_resource_start() because we could be
- * operating from within a Virtual Machine which is trapping our
- * accesses to our Configuration Space and we need to set up the PCI-E
- * Memory Window decoders with the actual addresses which will be
- * coming across the PCI-E link.
- */
- bar0 = csio_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
- bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
-
- /*
- * Set up memory window for accessing adapter memory ranges. (Read
- * back MA register to ensure that changes propagate before we attempt
- * to use the new values.)
- */
- csio_wr_reg32(hw, (bar0 + MEMWIN0_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN0_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0));
- csio_wr_reg32(hw, (bar0 + MEMWIN1_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN1_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1));
- csio_wr_reg32(hw, (bar0 + MEMWIN2_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN2_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
- csio_rd_reg32(hw, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
- return 0;
-} /* csio_hw_set_mem_win */
-
-
-
/*****************************************************************************/
/* HW State machine assists */
/*****************************************************************************/
@@ -1234,7 +968,9 @@ retry:
for (;;) {
uint32_t pcie_fw;
+ spin_unlock_irq(&hw->lock);
msleep(50);
+ spin_lock_irq(&hw->lock);
waiting -= 50;
/*
@@ -2121,9 +1857,9 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
uint32_t *cfg_data;
int value_to_add = 0;
- if (request_firmware(&cf, CSIO_CF_FNAME, dev) < 0) {
- csio_err(hw, "could not find config file " CSIO_CF_FNAME
- ",err: %d\n", ret);
+ if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) {
+ csio_err(hw, "could not find config file %s, err: %d\n",
+ CSIO_CF_FNAME(hw), ret);
return -ENOENT;
}
@@ -2147,9 +1883,24 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
ret = csio_memory_write(hw, mtype, maddr,
cf->size + value_to_add, cfg_data);
+
+ if ((ret == 0) && (value_to_add != 0)) {
+ union {
+ u32 word;
+ char buf[4];
+ } last;
+ size_t size = cf->size & ~0x3;
+ int i;
+
+ last.word = cfg_data[size >> 2];
+ for (i = value_to_add; i < 4; i++)
+ last.buf[i] = 0;
+ ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word);
+ }
if (ret == 0) {
- csio_info(hw, "config file upgraded to " CSIO_CF_FNAME "\n");
- strncpy(path, "/lib/firmware/" CSIO_CF_FNAME, 64);
+ csio_info(hw, "config file upgraded to %s\n",
+ CSIO_CF_FNAME(hw));
+ snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw));
}
leave:
@@ -2179,7 +1930,7 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
{
unsigned int mtype, maddr;
int rv;
- uint32_t finiver, finicsum, cfcsum;
+ uint32_t finiver = 0, finicsum = 0, cfcsum = 0;
int using_flash;
char path[64];
@@ -2207,7 +1958,7 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
* config file from flash.
*/
mtype = FW_MEMTYPE_CF_FLASH;
- maddr = csio_hw_flash_cfg_addr(hw);
+ maddr = hw->chip_ops->chip_flash_cfg_addr(hw);
using_flash = 1;
} else {
/*
@@ -2346,30 +2097,32 @@ csio_hw_flash_fw(struct csio_hw *hw)
struct pci_dev *pci_dev = hw->pdev;
struct device *dev = &pci_dev->dev ;
- if (request_firmware(&fw, CSIO_FW_FNAME, dev) < 0) {
- csio_err(hw, "could not find firmware image " CSIO_FW_FNAME
- ",err: %d\n", ret);
+ if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) {
+ csio_err(hw, "could not find firmware image %s, err: %d\n",
+ CSIO_FW_FNAME(hw), ret);
return -EINVAL;
}
hdr = (const struct fw_hdr *)fw->data;
fw_ver = ntohl(hdr->fw_ver);
- if (FW_HDR_FW_VER_MAJOR_GET(fw_ver) != FW_VERSION_MAJOR)
+ if (FW_HDR_FW_VER_MAJOR_GET(fw_ver) != FW_VERSION_MAJOR(hw))
return -EINVAL; /* wrong major version, won't do */
/*
* If the flash FW is unusable or we found something newer, load it.
*/
- if (FW_HDR_FW_VER_MAJOR_GET(hw->fwrev) != FW_VERSION_MAJOR ||
+ if (FW_HDR_FW_VER_MAJOR_GET(hw->fwrev) != FW_VERSION_MAJOR(hw) ||
fw_ver > hw->fwrev) {
ret = csio_hw_fw_upgrade(hw, hw->pfn, fw->data, fw->size,
/*force=*/false);
if (!ret)
- csio_info(hw, "firmware upgraded to version %pI4 from "
- CSIO_FW_FNAME "\n", &hdr->fw_ver);
+ csio_info(hw,
+ "firmware upgraded to version %pI4 from %s\n",
+ &hdr->fw_ver, CSIO_FW_FNAME(hw));
else
csio_err(hw, "firmware upgrade failed! err=%d\n", ret);
- }
+ } else
+ ret = -EINVAL;
release_firmware(fw);
@@ -2410,7 +2163,7 @@ csio_hw_configure(struct csio_hw *hw)
/* Set pci completion timeout value to 4 seconds. */
csio_set_pcie_completion_timeout(hw, 0xd);
- csio_hw_set_mem_win(hw);
+ hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR);
rv = csio_hw_get_fw_version(hw, &hw->fwrev);
if (rv != 0)
@@ -2478,6 +2231,8 @@ csio_hw_configure(struct csio_hw *hw)
} else {
if (hw->fw_state == CSIO_DEV_STATE_INIT) {
+ hw->flags |= CSIO_HWF_USING_SOFT_PARAMS;
+
/* device parameters */
rv = csio_get_device_params(hw);
if (rv != 0)
@@ -2651,7 +2406,7 @@ csio_hw_intr_disable(struct csio_hw *hw)
}
-static void
+void
csio_hw_fatal_err(struct csio_hw *hw)
{
csio_set_reg_field(hw, SGE_CONTROL, GLOBALENABLE, 0);
@@ -2990,14 +2745,6 @@ csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt)
/* END: HW SM */
/*****************************************************************************/
-/* Slow path handlers */
-struct intr_info {
- unsigned int mask; /* bits to check in interrupt status */
- const char *msg; /* message to print or NULL */
- short stat_idx; /* stat counter to increment or -1 */
- unsigned short fatal; /* whether the condition reported is fatal */
-};
-
/*
* csio_handle_intr_status - table driven interrupt handler
* @hw: HW instance
@@ -3011,7 +2758,7 @@ struct intr_info {
* by an entry specifying mask 0. Returns the number of fatal interrupt
* conditions.
*/
-static int
+int
csio_handle_intr_status(struct csio_hw *hw, unsigned int reg,
const struct intr_info *acts)
{
@@ -3038,80 +2785,6 @@ csio_handle_intr_status(struct csio_hw *hw, unsigned int reg,
}
/*
- * Interrupt handler for the PCIE module.
- */
-static void
-csio_pcie_intr_handler(struct csio_hw *hw)
-{
- static struct intr_info sysbus_intr_info[] = {
- { RNPP, "RXNP array parity error", -1, 1 },
- { RPCP, "RXPC array parity error", -1, 1 },
- { RCIP, "RXCIF array parity error", -1, 1 },
- { RCCP, "Rx completions control array parity error", -1, 1 },
- { RFTP, "RXFT array parity error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_port_intr_info[] = {
- { TPCP, "TXPC array parity error", -1, 1 },
- { TNPP, "TXNP array parity error", -1, 1 },
- { TFTP, "TXFT array parity error", -1, 1 },
- { TCAP, "TXCA array parity error", -1, 1 },
- { TCIP, "TXCIF array parity error", -1, 1 },
- { RCAP, "RXCA array parity error", -1, 1 },
- { OTDD, "outbound request TLP discarded", -1, 1 },
- { RDPE, "Rx data parity error", -1, 1 },
- { TDUE, "Tx uncorrectable data error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_intr_info[] = {
- { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
- { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
- { MSIDATAPERR, "MSI data parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
- { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
- { MATAGPERR, "PCI MA tag parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
- { RXWRPERR, "PCI Rx write parity error", -1, 1 },
- { RPLPERR, "PCI replay buffer parity error", -1, 1 },
- { PCIESINT, "PCI core secondary fault", -1, 1 },
- { PCIEPINT, "PCI core primary fault", -1, 1 },
- { UNXSPLCPLERR, "PCI unexpected split completion error", -1,
- 0 },
- { 0, NULL, 0, 0 }
- };
-
- int fat;
-
- fat = csio_handle_intr_status(hw,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
- sysbus_intr_info) +
- csio_handle_intr_status(hw,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
- pcie_port_intr_info) +
- csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
- if (fat)
- csio_hw_fatal_err(hw);
-}
-
-/*
* TP interrupt handler.
*/
static void csio_tp_intr_handler(struct csio_hw *hw)
@@ -3517,7 +3190,7 @@ static void csio_ncsi_intr_handler(struct csio_hw *hw)
*/
static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
{
- uint32_t v = csio_rd_reg32(hw, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
+ uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port));
v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
if (!v)
@@ -3527,7 +3200,7 @@ static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port);
if (v & RXFIFO_PRTY_ERR)
csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port);
- csio_wr_reg32(hw, v, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
+ csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port));
csio_hw_fatal_err(hw);
}
@@ -3596,7 +3269,7 @@ csio_hw_slow_intr_handler(struct csio_hw *hw)
csio_xgmac_intr_handler(hw, 3);
if (cause & PCIE)
- csio_pcie_intr_handler(hw);
+ hw->chip_ops->chip_pcie_intr_handler(hw);
if (cause & MC)
csio_mem_intr_handler(hw, MEM_MC);
@@ -3892,7 +3565,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
struct csio_fl_dma_buf *flb, void *priv)
{
__u8 op;
- __be64 *data;
void *msg = NULL;
uint32_t msg_len = 0;
bool msg_sg = 0;
@@ -3908,8 +3580,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
msg = (void *) flb;
msg_len = flb->totlen;
msg_sg = 1;
-
- data = (__be64 *) msg;
} else if (op == CPL_FW6_MSG || op == CPL_FW4_MSG) {
CSIO_INC_STATS(hw, n_cpl_fw6_msg);
@@ -3917,8 +3587,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
msg = (void *)((uintptr_t)wr + sizeof(__be64));
msg_len = (op == CPL_FW6_MSG) ? sizeof(struct cpl_fw6_msg) :
sizeof(struct cpl_fw4_msg);
-
- data = (__be64 *) msg;
} else {
csio_warn(hw, "unexpected CPL %#x on FW event queue\n", op);
CSIO_INC_STATS(hw, n_cpl_unexp);
@@ -4262,6 +3930,7 @@ csio_hw_get_device_id(struct csio_hw *hw)
&hw->params.pci.device_id);
csio_dev_id_cached(hw);
+ hw->chip_id = (hw->params.pci.device_id & CSIO_HW_CHIP_MASK);
} /* csio_hw_get_device_id */
@@ -4280,19 +3949,21 @@ csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id)
prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK);
adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK);
- if (prot_type == CSIO_FPGA) {
+ if (prot_type == CSIO_T4_FCOE_ASIC) {
+ memcpy(hw->hw_ver,
+ csio_t4_fcoe_adapters[adap_type].model_no, 16);
memcpy(hw->model_desc,
- csio_fcoe_adapters[13].description, 32);
- } else if (prot_type == CSIO_T4_FCOE_ASIC) {
+ csio_t4_fcoe_adapters[adap_type].description,
+ 32);
+ } else if (prot_type == CSIO_T5_FCOE_ASIC) {
memcpy(hw->hw_ver,
- csio_fcoe_adapters[adap_type].model_no, 16);
+ csio_t5_fcoe_adapters[adap_type].model_no, 16);
memcpy(hw->model_desc,
- csio_fcoe_adapters[adap_type].description, 32);
+ csio_t5_fcoe_adapters[adap_type].description,
+ 32);
} else {
char tempName[32] = "Chelsio FCoE Controller";
memcpy(hw->model_desc, tempName, 32);
-
- CSIO_DB_ASSERT(0);
}
}
} /* csio_hw_set_description */
@@ -4321,6 +3992,9 @@ csio_hw_init(struct csio_hw *hw)
strcpy(hw->name, CSIO_HW_NAME);
+ /* Initialize the HW chip ops with T4/T5 specific ops */
+ hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops;
+
/* Set the model & its description */
ven_id = hw->params.pci.vendor_id;
diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h
index 9edcca4c71af..489fc095cb03 100644
--- a/drivers/scsi/csiostor/csio_hw.h
+++ b/drivers/scsi/csiostor/csio_hw.h
@@ -48,6 +48,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_fc.h>
+#include "csio_hw_chip.h"
#include "csio_wr.h"
#include "csio_mb.h"
#include "csio_scsi.h"
@@ -60,13 +61,6 @@
*/
#define FW_HOSTERROR 255
-#define CSIO_FW_FNAME "cxgb4/t4fw.bin"
-#define CSIO_CF_FNAME "cxgb4/t4-config.txt"
-
-#define FW_VERSION_MAJOR 1
-#define FW_VERSION_MINOR 2
-#define FW_VERSION_MICRO 8
-
#define CSIO_HW_NAME "Chelsio FCoE Adapter"
#define CSIO_MAX_PFN 8
#define CSIO_MAX_PPORTS 4
@@ -123,8 +117,6 @@ extern int csio_msi;
#define CSIO_VENDOR_ID 0x1425
#define CSIO_ASIC_DEVID_PROTO_MASK 0xFF00
#define CSIO_ASIC_DEVID_TYPE_MASK 0x00FF
-#define CSIO_FPGA 0xA000
-#define CSIO_T4_FCOE_ASIC 0x4600
#define CSIO_GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
EDC1 | LE | TP | MA | PM_TX | PM_RX | \
@@ -207,17 +199,6 @@ enum {
SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */
};
-enum { MEM_EDC0, MEM_EDC1, MEM_MC };
-
-enum {
- MEMWIN0_APERTURE = 2048,
- MEMWIN0_BASE = 0x1b800,
- MEMWIN1_APERTURE = 32768,
- MEMWIN1_BASE = 0x28000,
- MEMWIN2_APERTURE = 65536,
- MEMWIN2_BASE = 0x30000,
-};
-
/* serial flash and firmware constants */
enum {
SF_ATTEMPTS = 10, /* max retries for SF operations */
@@ -239,9 +220,6 @@ enum {
FLASH_CFG_MAX_SIZE = 0x10000 , /* max size of the flash config file*/
FLASH_CFG_OFFSET = 0x1f0000,
FLASH_CFG_START_SEC = FLASH_CFG_OFFSET / SF_SEC_SIZE,
- FPGA_FLASH_CFG_OFFSET = 0xf0000 , /* if FPGA mode, then cfg file is
- * at 1MB - 64KB */
- FPGA_FLASH_CFG_START_SEC = FPGA_FLASH_CFG_OFFSET / SF_SEC_SIZE,
};
/*
@@ -259,6 +237,8 @@ enum {
FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
+ /* Location of Firmware Configuration File in FLASH. */
+ FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC),
};
#undef FLASH_START
@@ -310,7 +290,7 @@ struct csio_adap_desc {
struct pci_params {
uint16_t vendor_id;
uint16_t device_id;
- uint32_t vpd_cap_addr;
+ int vpd_cap_addr;
uint16_t speed;
uint8_t width;
};
@@ -513,6 +493,7 @@ struct csio_hw {
uint32_t fwrev;
uint32_t tp_vers;
char chip_ver;
+ uint16_t chip_id; /* Tells T4/T5 chip */
uint32_t cfg_finiver;
uint32_t cfg_finicsum;
uint32_t cfg_cfcsum;
@@ -556,6 +537,9 @@ struct csio_hw {
*/
struct csio_fcoe_res_info fres_info; /* Fcoe resource info */
+ struct csio_hw_chip_ops *chip_ops; /* T4/T5 Chip specific
+ * Operations
+ */
/* MSIX vectors */
struct csio_msix_entries msix_entries[CSIO_MAX_MSIX_VECS];
@@ -636,9 +620,16 @@ csio_us_to_core_ticks(struct csio_hw *hw, uint32_t us)
#define csio_dbg(__hw, __fmt, ...)
#endif
+int csio_hw_wait_op_done_val(struct csio_hw *, int, uint32_t, int,
+ int, int, uint32_t *);
+void csio_hw_tp_wr_bits_indirect(struct csio_hw *, unsigned int,
+ unsigned int, unsigned int);
int csio_mgmt_req_lookup(struct csio_mgmtm *, struct csio_ioreq *);
void csio_hw_intr_disable(struct csio_hw *);
-int csio_hw_slow_intr_handler(struct csio_hw *hw);
+int csio_hw_slow_intr_handler(struct csio_hw *);
+int csio_handle_intr_status(struct csio_hw *, unsigned int,
+ const struct intr_info *);
+
int csio_hw_start(struct csio_hw *);
int csio_hw_stop(struct csio_hw *);
int csio_hw_reset(struct csio_hw *);
@@ -647,19 +638,17 @@ int csio_is_hw_removing(struct csio_hw *);
int csio_fwevtq_handler(struct csio_hw *);
void csio_evtq_worker(struct work_struct *);
-int csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type,
- void *evt_msg, uint16_t len);
+int csio_enqueue_evt(struct csio_hw *, enum csio_evt, void *, uint16_t);
void csio_evtq_flush(struct csio_hw *hw);
int csio_request_irqs(struct csio_hw *);
void csio_intr_enable(struct csio_hw *);
void csio_intr_disable(struct csio_hw *, bool);
+void csio_hw_fatal_err(struct csio_hw *);
struct csio_lnode *csio_lnode_alloc(struct csio_hw *);
int csio_config_queues(struct csio_hw *);
-int csio_hw_mc_read(struct csio_hw *, uint32_t, __be32 *, uint64_t *);
-int csio_hw_edc_read(struct csio_hw *, int, uint32_t, __be32 *, uint64_t *);
int csio_hw_init(struct csio_hw *);
void csio_hw_exit(struct csio_hw *);
#endif /* ifndef __CSIO_HW_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw_chip.h b/drivers/scsi/csiostor/csio_hw_chip.h
new file mode 100644
index 000000000000..bca0de61ae80
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_chip.h
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_HW_CHIP_H__
+#define __CSIO_HW_CHIP_H__
+
+#include "csio_defs.h"
+
+/* FCoE device IDs for T4 */
+#define CSIO_DEVID_T440DBG_FCOE 0x4600
+#define CSIO_DEVID_T420CR_FCOE 0x4601
+#define CSIO_DEVID_T422CR_FCOE 0x4602
+#define CSIO_DEVID_T440CR_FCOE 0x4603
+#define CSIO_DEVID_T420BCH_FCOE 0x4604
+#define CSIO_DEVID_T440BCH_FCOE 0x4605
+#define CSIO_DEVID_T440CH_FCOE 0x4606
+#define CSIO_DEVID_T420SO_FCOE 0x4607
+#define CSIO_DEVID_T420CX_FCOE 0x4608
+#define CSIO_DEVID_T420BT_FCOE 0x4609
+#define CSIO_DEVID_T404BT_FCOE 0x460A
+#define CSIO_DEVID_B420_FCOE 0x460B
+#define CSIO_DEVID_B404_FCOE 0x460C
+#define CSIO_DEVID_T480CR_FCOE 0x460D
+#define CSIO_DEVID_T440LPCR_FCOE 0x460E
+#define CSIO_DEVID_AMSTERDAM_T4_FCOE 0x460F
+#define CSIO_DEVID_HUAWEI_T480_FCOE 0x4680
+#define CSIO_DEVID_HUAWEI_T440_FCOE 0x4681
+#define CSIO_DEVID_HUAWEI_STG310_FCOE 0x4682
+#define CSIO_DEVID_ACROMAG_XMC_XAUI 0x4683
+#define CSIO_DEVID_ACROMAG_XMC_SFP_FCOE 0x4684
+#define CSIO_DEVID_QUANTA_MEZZ_SFP_FCOE 0x4685
+#define CSIO_DEVID_HUAWEI_10GT_FCOE 0x4686
+#define CSIO_DEVID_HUAWEI_T440_TOE_FCOE 0x4687
+
+/* FCoE device IDs for T5 */
+#define CSIO_DEVID_T580DBG_FCOE 0x5600
+#define CSIO_DEVID_T520CR_FCOE 0x5601
+#define CSIO_DEVID_T522CR_FCOE 0x5602
+#define CSIO_DEVID_T540CR_FCOE 0x5603
+#define CSIO_DEVID_T520BCH_FCOE 0x5604
+#define CSIO_DEVID_T540BCH_FCOE 0x5605
+#define CSIO_DEVID_T540CH_FCOE 0x5606
+#define CSIO_DEVID_T520SO_FCOE 0x5607
+#define CSIO_DEVID_T520CX_FCOE 0x5608
+#define CSIO_DEVID_T520BT_FCOE 0x5609
+#define CSIO_DEVID_T504BT_FCOE 0x560A
+#define CSIO_DEVID_B520_FCOE 0x560B
+#define CSIO_DEVID_B504_FCOE 0x560C
+#define CSIO_DEVID_T580CR2_FCOE 0x560D
+#define CSIO_DEVID_T540LPCR_FCOE 0x560E
+#define CSIO_DEVID_AMSTERDAM_T5_FCOE 0x560F
+#define CSIO_DEVID_T580LPCR_FCOE 0x5610
+#define CSIO_DEVID_T520LLCR_FCOE 0x5611
+#define CSIO_DEVID_T560CR_FCOE 0x5612
+#define CSIO_DEVID_T580CR_FCOE 0x5613
+
+/* Define MACRO values */
+#define CSIO_HW_T4 0x4000
+#define CSIO_T4_FCOE_ASIC 0x4600
+#define CSIO_HW_T5 0x5000
+#define CSIO_T5_FCOE_ASIC 0x5600
+#define CSIO_HW_CHIP_MASK 0xF000
+#define T4_REGMAP_SIZE (160 * 1024)
+#define T5_REGMAP_SIZE (332 * 1024)
+#define FW_FNAME_T4 "cxgb4/t4fw.bin"
+#define FW_FNAME_T5 "cxgb4/t5fw.bin"
+#define FW_CFG_NAME_T4 "cxgb4/t4-config.txt"
+#define FW_CFG_NAME_T5 "cxgb4/t5-config.txt"
+
+/* Define static functions */
+static inline int csio_is_t4(uint16_t chip)
+{
+ return (chip == CSIO_HW_T4);
+}
+
+static inline int csio_is_t5(uint16_t chip)
+{
+ return (chip == CSIO_HW_T5);
+}
+
+/* Define MACRO DEFINITIONS */
+#define CSIO_DEVICE(devid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
+
+#define CSIO_HW_PIDX(hw, index) \
+ (csio_is_t4(hw->chip_id) ? (PIDX(index)) : \
+ (PIDX_T5(index) | DBTYPE(1U)))
+
+#define CSIO_HW_LP_INT_THRESH(hw, val) \
+ (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH(val)) : \
+ (V_LP_INT_THRESH_T5(val)))
+
+#define CSIO_HW_M_LP_INT_THRESH(hw) \
+ (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH_MASK) : (M_LP_INT_THRESH_T5))
+
+#define CSIO_MAC_INT_CAUSE_REG(hw, port) \
+ (csio_is_t4(hw->chip_id) ? (PORT_REG(port, XGMAC_PORT_INT_CAUSE)) : \
+ (T5_PORT_REG(port, MAC_PORT_INT_CAUSE)))
+
+#define FW_VERSION_MAJOR(hw) (csio_is_t4(hw->chip_id) ? 1 : 0)
+#define FW_VERSION_MINOR(hw) (csio_is_t4(hw->chip_id) ? 2 : 0)
+#define FW_VERSION_MICRO(hw) (csio_is_t4(hw->chip_id) ? 8 : 0)
+
+#define CSIO_FW_FNAME(hw) \
+ (csio_is_t4(hw->chip_id) ? FW_FNAME_T4 : FW_FNAME_T5)
+
+#define CSIO_CF_FNAME(hw) \
+ (csio_is_t4(hw->chip_id) ? FW_CFG_NAME_T4 : FW_CFG_NAME_T5)
+
+/* Declare ENUMS */
+enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 };
+
+enum {
+ MEMWIN_APERTURE = 2048,
+ MEMWIN_BASE = 0x1b800,
+ MEMWIN_CSIOSTOR = 6, /* PCI-e Memory Window access */
+};
+
+/* Slow path handlers */
+struct intr_info {
+ unsigned int mask; /* bits to check in interrupt status */
+ const char *msg; /* message to print or NULL */
+ short stat_idx; /* stat counter to increment or -1 */
+ unsigned short fatal; /* whether the condition reported is fatal */
+};
+
+/* T4/T5 Chip specific ops */
+struct csio_hw;
+struct csio_hw_chip_ops {
+ int (*chip_set_mem_win)(struct csio_hw *, uint32_t);
+ void (*chip_pcie_intr_handler)(struct csio_hw *);
+ uint32_t (*chip_flash_cfg_addr)(struct csio_hw *);
+ int (*chip_mc_read)(struct csio_hw *, int, uint32_t,
+ __be32 *, uint64_t *);
+ int (*chip_edc_read)(struct csio_hw *, int, uint32_t,
+ __be32 *, uint64_t *);
+ int (*chip_memory_rw)(struct csio_hw *, u32, int, u32,
+ u32, uint32_t *, int);
+ void (*chip_dfs_create_ext_mem)(struct csio_hw *);
+};
+
+extern struct csio_hw_chip_ops t4_ops;
+extern struct csio_hw_chip_ops t5_ops;
+
+#endif /* #ifndef __CSIO_HW_CHIP_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw_t4.c b/drivers/scsi/csiostor/csio_hw_t4.c
new file mode 100644
index 000000000000..89ecbac5478f
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_t4.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "csio_hw.h"
+#include "csio_init.h"
+
+/*
+ * Return the specified PCI-E Configuration Space register from our Physical
+ * Function. We try first via a Firmware LDST Command since we prefer to let
+ * the firmware own all of these registers, but if that fails we go for it
+ * directly ourselves.
+ */
+static uint32_t
+csio_t4_read_pcie_cfg4(struct csio_hw *hw, int reg)
+{
+ u32 val = 0;
+ struct csio_mb *mbp;
+ int rv;
+ struct fw_ldst_cmd *ldst_cmd;
+
+ mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+ if (!mbp) {
+ CSIO_INC_STATS(hw, n_err_nomem);
+ pci_read_config_dword(hw->pdev, reg, &val);
+ return val;
+ }
+
+ csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
+ rv = csio_mb_issue(hw, mbp);
+
+ /*
+ * If the LDST Command suucceeded, exctract the returned register
+ * value. Otherwise read it directly ourself.
+ */
+ if (rv == 0) {
+ ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
+ val = ntohl(ldst_cmd->u.pcie.data[0]);
+ } else
+ pci_read_config_dword(hw->pdev, reg, &val);
+
+ mempool_free(mbp, hw->mb_mempool);
+
+ return val;
+}
+
+static int
+csio_t4_set_mem_win(struct csio_hw *hw, uint32_t win)
+{
+ u32 bar0;
+ u32 mem_win_base;
+
+ /*
+ * Truncation intentional: we only read the bottom 32-bits of the
+ * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
+ * read BAR0 instead of using pci_resource_start() because we could be
+ * operating from within a Virtual Machine which is trapping our
+ * accesses to our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will be
+ * coming across the PCI-E link.
+ */
+ bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
+ bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ mem_win_base = bar0 + MEMWIN_BASE;
+
+ /*
+ * Set up memory window for accessing adapter memory ranges. (Read
+ * back MA register to ensure that changes propagate before we attempt
+ * to use the new values.)
+ */
+ csio_wr_reg32(hw, mem_win_base | BIR(0) |
+ WINDOW(ilog2(MEMWIN_APERTURE) - 10),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ return 0;
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void
+csio_t4_pcie_intr_handler(struct csio_hw *hw)
+{
+ static struct intr_info sysbus_intr_info[] = {
+ { RNPP, "RXNP array parity error", -1, 1 },
+ { RPCP, "RXPC array parity error", -1, 1 },
+ { RCIP, "RXCIF array parity error", -1, 1 },
+ { RCCP, "Rx completions control array parity error", -1, 1 },
+ { RFTP, "RXFT array parity error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+ static struct intr_info pcie_port_intr_info[] = {
+ { TPCP, "TXPC array parity error", -1, 1 },
+ { TNPP, "TXNP array parity error", -1, 1 },
+ { TFTP, "TXFT array parity error", -1, 1 },
+ { TCAP, "TXCA array parity error", -1, 1 },
+ { TCIP, "TXCIF array parity error", -1, 1 },
+ { RCAP, "RXCA array parity error", -1, 1 },
+ { OTDD, "outbound request TLP discarded", -1, 1 },
+ { RDPE, "Rx data parity error", -1, 1 },
+ { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+
+ static struct intr_info pcie_intr_info[] = {
+ { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
+ { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
+ { MSIDATAPERR, "MSI data parity error", -1, 1 },
+ { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
+ { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
+ { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
+ { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
+ { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
+ { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
+ { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR, "PCI FID parity error", -1, 1 },
+ { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
+ { MATAGPERR, "PCI MA tag parity error", -1, 1 },
+ { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
+ { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
+ { RXWRPERR, "PCI Rx write parity error", -1, 1 },
+ { RPLPERR, "PCI replay buffer parity error", -1, 1 },
+ { PCIESINT, "PCI core secondary fault", -1, 1 },
+ { PCIEPINT, "PCI core primary fault", -1, 1 },
+ { UNXSPLCPLERR, "PCI unexpected split completion error", -1,
+ 0 },
+ { 0, NULL, 0, 0 }
+ };
+
+ int fat;
+ fat = csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+ sysbus_intr_info) +
+ csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+ pcie_port_intr_info) +
+ csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
+ if (fat)
+ csio_hw_fatal_err(hw);
+}
+
+/*
+ * csio_t4_flash_cfg_addr - return the address of the flash configuration file
+ * @hw: the HW module
+ *
+ * Return the address within the flash where the Firmware Configuration
+ * File is stored.
+ */
+static unsigned int
+csio_t4_flash_cfg_addr(struct csio_hw *hw)
+{
+ return FLASH_CFG_OFFSET;
+}
+
+/*
+ * csio_t4_mc_read - read from MC through backdoor accesses
+ * @hw: the hw module
+ * @idx: not used for T4 adapter
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from MC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t4_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+
+ if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
+ csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
+ csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ MC_BIST_CMD);
+ i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, MC_DATA(16));
+#undef MC_DATA
+ return 0;
+}
+
+/*
+ * csio_t4_edc_read - read from EDC through backdoor accesses
+ * @hw: the hw module
+ * @idx: which EDC to access
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t4_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+
+ idx *= EDC_STRIDE;
+ if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
+ csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
+ csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
+ EDC_BIST_CMD + idx);
+ i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, EDC_DATA(16));
+#undef EDC_DATA
+ return 0;
+}
+
+/*
+ * csio_t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ * @hw: the csio_hw
+ * @win: PCI-E memory Window to use
+ * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
+ * @addr: address within indicated memory type
+ * @len: amount of memory to transfer
+ * @buf: host memory buffer
+ * @dir: direction of transfer 1 => read, 0 => write
+ *
+ * Reads/writes an [almost] arbitrary memory region in the firmware: the
+ * firmware memory address, length and host buffer must be aligned on
+ * 32-bit boudaries. The memory is transferred as a raw byte sequence
+ * from/to the firmware's memory. If this memory contains data
+ * structures which contain multi-byte integers, it's the callers
+ * responsibility to perform appropriate byte order conversions.
+ */
+static int
+csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
+ u32 len, uint32_t *buf, int dir)
+{
+ u32 pos, start, offset, memoffset, bar0;
+ u32 edc_size, mc_size, mem_reg, mem_aperture, mem_base;
+
+ /*
+ * Argument sanity checks ...
+ */
+ if ((addr & 0x3) || (len & 0x3))
+ return -EINVAL;
+
+ /* Offset into the region of memory which is being accessed
+ * MEM_EDC0 = 0
+ * MEM_EDC1 = 1
+ * MEM_MC = 2 -- T4
+ */
+ edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ if (mtype != MEM_MC1)
+ memoffset = (mtype * (edc_size * 1024 * 1024));
+ else {
+ mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR));
+ memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+ }
+
+ /* Determine the PCIE_MEM_ACCESS_OFFSET */
+ addr = addr + memoffset;
+
+ /*
+ * Each PCI-E Memory Window is programmed with a window size -- or
+ * "aperture" -- which controls the granularity of its mapping onto
+ * adapter memory. We need to grab that aperture in order to know
+ * how to use the specified window. The window is also programmed
+ * with the base address of the Memory Window in BAR0's address
+ * space. For T4 this is an absolute PCI-E Bus Address. For T5
+ * the address is relative to BAR0.
+ */
+ mem_reg = csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ mem_aperture = 1 << (WINDOW(mem_reg) + 10);
+ mem_base = GET_PCIEOFST(mem_reg) << 10;
+
+ bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
+ bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
+ mem_base -= bar0;
+
+ start = addr & ~(mem_aperture-1);
+ offset = addr - start;
+
+ csio_dbg(hw, "csio_t4_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
+ mem_reg, mem_aperture);
+ csio_dbg(hw, "csio_t4_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
+ mem_base, memoffset);
+ csio_dbg(hw, "csio_t4_memory_rw: bar0: 0x%x, start:0x%x, offset:0x%x\n",
+ bar0, start, offset);
+ csio_dbg(hw, "csio_t4_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
+ mtype, addr, len);
+
+ for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
+ /*
+ * Move PCI-E Memory Window to our current transfer
+ * position. Read it back to ensure that changes propagate
+ * before we attempt to use the new value.
+ */
+ csio_wr_reg32(hw, pos,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+
+ while (offset < mem_aperture && len > 0) {
+ if (dir)
+ *buf++ = csio_rd_reg32(hw, mem_base + offset);
+ else
+ csio_wr_reg32(hw, *buf++, mem_base + offset);
+
+ offset += sizeof(__be32);
+ len -= sizeof(__be32);
+ }
+ }
+ return 0;
+}
+
+/*
+ * csio_t4_dfs_create_ext_mem - setup debugfs for MC to read the values
+ * @hw: the csio_hw
+ *
+ * This function creates files in the debugfs with external memory region MC.
+ */
+static void
+csio_t4_dfs_create_ext_mem(struct csio_hw *hw)
+{
+ u32 size;
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
+ if (i & EXT_MEM_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ csio_add_debugfs_mem(hw, "mc", MEM_MC,
+ EXT_MEM_SIZE_GET(size));
+ }
+}
+
+/* T4 adapter specific function */
+struct csio_hw_chip_ops t4_ops = {
+ .chip_set_mem_win = csio_t4_set_mem_win,
+ .chip_pcie_intr_handler = csio_t4_pcie_intr_handler,
+ .chip_flash_cfg_addr = csio_t4_flash_cfg_addr,
+ .chip_mc_read = csio_t4_mc_read,
+ .chip_edc_read = csio_t4_edc_read,
+ .chip_memory_rw = csio_t4_memory_rw,
+ .chip_dfs_create_ext_mem = csio_t4_dfs_create_ext_mem,
+};
diff --git a/drivers/scsi/csiostor/csio_hw_t5.c b/drivers/scsi/csiostor/csio_hw_t5.c
new file mode 100644
index 000000000000..27745c170c24
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_t5.c
@@ -0,0 +1,397 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "csio_hw.h"
+#include "csio_init.h"
+
+static int
+csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win)
+{
+ u32 mem_win_base;
+ /*
+ * Truncation intentional: we only read the bottom 32-bits of the
+ * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
+ * read BAR0 instead of using pci_resource_start() because we could be
+ * operating from within a Virtual Machine which is trapping our
+ * accesses to our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will be
+ * coming across the PCI-E link.
+ */
+
+ /* For T5, only relative offset inside the PCIe BAR is passed */
+ mem_win_base = MEMWIN_BASE;
+
+ /*
+ * Set up memory window for accessing adapter memory ranges. (Read
+ * back MA register to ensure that changes propagate before we attempt
+ * to use the new values.)
+ */
+ csio_wr_reg32(hw, mem_win_base | BIR(0) |
+ WINDOW(ilog2(MEMWIN_APERTURE) - 10),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+
+ return 0;
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void
+csio_t5_pcie_intr_handler(struct csio_hw *hw)
+{
+ static struct intr_info sysbus_intr_info[] = {
+ { RNPP, "RXNP array parity error", -1, 1 },
+ { RPCP, "RXPC array parity error", -1, 1 },
+ { RCIP, "RXCIF array parity error", -1, 1 },
+ { RCCP, "Rx completions control array parity error", -1, 1 },
+ { RFTP, "RXFT array parity error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+ static struct intr_info pcie_port_intr_info[] = {
+ { TPCP, "TXPC array parity error", -1, 1 },
+ { TNPP, "TXNP array parity error", -1, 1 },
+ { TFTP, "TXFT array parity error", -1, 1 },
+ { TCAP, "TXCA array parity error", -1, 1 },
+ { TCIP, "TXCIF array parity error", -1, 1 },
+ { RCAP, "RXCA array parity error", -1, 1 },
+ { OTDD, "outbound request TLP discarded", -1, 1 },
+ { RDPE, "Rx data parity error", -1, 1 },
+ { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+
+ static struct intr_info pcie_intr_info[] = {
+ { MSTGRPPERR, "Master Response Read Queue parity error",
+ -1, 1 },
+ { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
+ { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
+ { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
+ -1, 1 },
+ { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
+ -1, 1 },
+ { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
+ { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
+ { DREQWRPERR, "PCI DMA channel write request parity error",
+ -1, 1 },
+ { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
+ { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR, "PCI FID parity error", -1, 1 },
+ { VFIDPERR, "PCI INTx clear parity error", -1, 1 },
+ { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
+ { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
+ { IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
+ -1, 1 },
+ { IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
+ -1, 1 },
+ { RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
+ { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
+ { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
+ { READRSPERR, "Outbound read error", -1, 0 },
+ { 0, NULL, 0, 0 }
+ };
+
+ int fat;
+ fat = csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+ sysbus_intr_info) +
+ csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+ pcie_port_intr_info) +
+ csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
+ if (fat)
+ csio_hw_fatal_err(hw);
+}
+
+/*
+ * csio_t5_flash_cfg_addr - return the address of the flash configuration file
+ * @hw: the HW module
+ *
+ * Return the address within the flash where the Firmware Configuration
+ * File is stored.
+ */
+static unsigned int
+csio_t5_flash_cfg_addr(struct csio_hw *hw)
+{
+ return FLASH_CFG_START;
+}
+
+/*
+ * csio_t5_mc_read - read from MC through backdoor accesses
+ * @hw: the hw module
+ * @idx: index to the register
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from MC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t5_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+ uint32_t mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg;
+ uint32_t mc_bist_status_rdata_reg, mc_bist_data_pattern_reg;
+
+ mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD, idx);
+ mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR, idx);
+ mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN, idx);
+ mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA, idx);
+ mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN, idx);
+
+ if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, mc_bist_cmd_addr_reg);
+ csio_wr_reg32(hw, 64, mc_bist_cmd_len_reg);
+ csio_wr_reg32(hw, 0xc, mc_bist_data_pattern_reg);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ mc_bist_cmd_reg);
+ i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, MC_DATA(16));
+#undef MC_DATA
+ return 0;
+}
+
+/*
+ * csio_t5_edc_read - read from EDC through backdoor accesses
+ * @hw: the hw module
+ * @idx: which EDC to access
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t5_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+ uint32_t edc_bist_cmd_reg, edc_bist_cmd_addr_reg, edc_bist_cmd_len_reg;
+ uint32_t edc_bist_cmd_data_pattern, edc_bist_status_rdata_reg;
+
+/*
+ * These macro are missing in t4_regs.h file.
+ */
+#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
+#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
+
+ edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD, idx);
+ edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx);
+ edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx);
+ edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx);
+ edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx);
+#undef EDC_REG_T5
+#undef EDC_STRIDE_T5
+
+ if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, edc_bist_cmd_addr_reg);
+ csio_wr_reg32(hw, 64, edc_bist_cmd_len_reg);
+ csio_wr_reg32(hw, 0xc, edc_bist_cmd_data_pattern);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ edc_bist_cmd_reg);
+ i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, EDC_DATA(16));
+#undef EDC_DATA
+ return 0;
+}
+
+/*
+ * csio_t5_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ * @hw: the csio_hw
+ * @win: PCI-E memory Window to use
+ * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
+ * @addr: address within indicated memory type
+ * @len: amount of memory to transfer
+ * @buf: host memory buffer
+ * @dir: direction of transfer 1 => read, 0 => write
+ *
+ * Reads/writes an [almost] arbitrary memory region in the firmware: the
+ * firmware memory address, length and host buffer must be aligned on
+ * 32-bit boudaries. The memory is transferred as a raw byte sequence
+ * from/to the firmware's memory. If this memory contains data
+ * structures which contain multi-byte integers, it's the callers
+ * responsibility to perform appropriate byte order conversions.
+ */
+static int
+csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
+ u32 len, uint32_t *buf, int dir)
+{
+ u32 pos, start, offset, memoffset;
+ u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;
+
+ /*
+ * Argument sanity checks ...
+ */
+ if ((addr & 0x3) || (len & 0x3))
+ return -EINVAL;
+
+ /* Offset into the region of memory which is being accessed
+ * MEM_EDC0 = 0
+ * MEM_EDC1 = 1
+ * MEM_MC = 2 -- T4
+ * MEM_MC0 = 2 -- For T5
+ * MEM_MC1 = 3 -- For T5
+ */
+ edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ if (mtype != MEM_MC1)
+ memoffset = (mtype * (edc_size * 1024 * 1024));
+ else {
+ mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR));
+ memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+ }
+
+ /* Determine the PCIE_MEM_ACCESS_OFFSET */
+ addr = addr + memoffset;
+
+ /*
+ * Each PCI-E Memory Window is programmed with a window size -- or
+ * "aperture" -- which controls the granularity of its mapping onto
+ * adapter memory. We need to grab that aperture in order to know
+ * how to use the specified window. The window is also programmed
+ * with the base address of the Memory Window in BAR0's address
+ * space. For T4 this is an absolute PCI-E Bus Address. For T5
+ * the address is relative to BAR0.
+ */
+ mem_reg = csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ mem_aperture = 1 << (WINDOW(mem_reg) + 10);
+ mem_base = GET_PCIEOFST(mem_reg) << 10;
+
+ start = addr & ~(mem_aperture-1);
+ offset = addr - start;
+ win_pf = V_PFNUM(hw->pfn);
+
+ csio_dbg(hw, "csio_t5_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
+ mem_reg, mem_aperture);
+ csio_dbg(hw, "csio_t5_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
+ mem_base, memoffset);
+ csio_dbg(hw, "csio_t5_memory_rw: start:0x%x, offset:0x%x, win_pf:%d\n",
+ start, offset, win_pf);
+ csio_dbg(hw, "csio_t5_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
+ mtype, addr, len);
+
+ for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
+ /*
+ * Move PCI-E Memory Window to our current transfer
+ * position. Read it back to ensure that changes propagate
+ * before we attempt to use the new value.
+ */
+ csio_wr_reg32(hw, pos | win_pf,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+
+ while (offset < mem_aperture && len > 0) {
+ if (dir)
+ *buf++ = csio_rd_reg32(hw, mem_base + offset);
+ else
+ csio_wr_reg32(hw, *buf++, mem_base + offset);
+
+ offset += sizeof(__be32);
+ len -= sizeof(__be32);
+ }
+ }
+ return 0;
+}
+
+/*
+ * csio_t5_dfs_create_ext_mem - setup debugfs for MC0 or MC1 to read the values
+ * @hw: the csio_hw
+ *
+ * This function creates files in the debugfs with external memory region
+ * MC0 & MC1.
+ */
+static void
+csio_t5_dfs_create_ext_mem(struct csio_hw *hw)
+{
+ u32 size;
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
+ if (i & EXT_MEM_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ csio_add_debugfs_mem(hw, "mc0", MEM_MC0,
+ EXT_MEM_SIZE_GET(size));
+ }
+ if (i & EXT_MEM1_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR);
+ csio_add_debugfs_mem(hw, "mc1", MEM_MC1,
+ EXT_MEM_SIZE_GET(size));
+ }
+}
+
+/* T5 adapter specific function */
+struct csio_hw_chip_ops t5_ops = {
+ .chip_set_mem_win = csio_t5_set_mem_win,
+ .chip_pcie_intr_handler = csio_t5_pcie_intr_handler,
+ .chip_flash_cfg_addr = csio_t5_flash_cfg_addr,
+ .chip_mc_read = csio_t5_mc_read,
+ .chip_edc_read = csio_t5_edc_read,
+ .chip_memory_rw = csio_t5_memory_rw,
+ .chip_dfs_create_ext_mem = csio_t5_dfs_create_ext_mem,
+};
diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c
index 0604b5ff3638..00346fe939d5 100644
--- a/drivers/scsi/csiostor/csio_init.c
+++ b/drivers/scsi/csiostor/csio_init.c
@@ -81,9 +81,11 @@ csio_mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
__be32 data[16];
if (mem == MEM_MC)
- ret = csio_hw_mc_read(hw, pos, data, NULL);
+ ret = hw->chip_ops->chip_mc_read(hw, 0, pos,
+ data, NULL);
else
- ret = csio_hw_edc_read(hw, mem, pos, data, NULL);
+ ret = hw->chip_ops->chip_edc_read(hw, mem, pos,
+ data, NULL);
if (ret)
return ret;
@@ -108,7 +110,7 @@ static const struct file_operations csio_mem_debugfs_fops = {
.llseek = default_llseek,
};
-static void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
+void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
unsigned int idx, unsigned int size_mb)
{
struct dentry *de;
@@ -131,9 +133,8 @@ static int csio_setup_debugfs(struct csio_hw *hw)
csio_add_debugfs_mem(hw, "edc0", MEM_EDC0, 5);
if (i & EDRAM1_ENABLE)
csio_add_debugfs_mem(hw, "edc1", MEM_EDC1, 5);
- if (i & EXT_MEM_ENABLE)
- csio_add_debugfs_mem(hw, "mc", MEM_MC,
- EXT_MEM_SIZE_GET(csio_rd_reg32(hw, MA_EXT_MEMORY_BAR)));
+
+ hw->chip_ops->chip_dfs_create_ext_mem(hw);
return 0;
}
@@ -1169,7 +1170,7 @@ static struct pci_error_handlers csio_err_handler = {
};
static DEFINE_PCI_DEVICE_TABLE(csio_pci_tbl) = {
- CSIO_DEVICE(CSIO_DEVID_T440DBG_FCOE, 0), /* T440DBG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T440DBG_FCOE, 0), /* T4 DEBUG FCOE */
CSIO_DEVICE(CSIO_DEVID_T420CR_FCOE, 0), /* T420CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T422CR_FCOE, 0), /* T422CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T440CR_FCOE, 0), /* T440CR FCOE */
@@ -1184,8 +1185,34 @@ static DEFINE_PCI_DEVICE_TABLE(csio_pci_tbl) = {
CSIO_DEVICE(CSIO_DEVID_B404_FCOE, 0), /* B404 FCOE */
CSIO_DEVICE(CSIO_DEVID_T480CR_FCOE, 0), /* T480 CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T440LPCR_FCOE, 0), /* T440 LP-CR FCOE */
- CSIO_DEVICE(CSIO_DEVID_PE10K, 0), /* PE10K FCOE */
- CSIO_DEVICE(CSIO_DEVID_PE10K_PF1, 0), /* PE10K FCOE on PF1 */
+ CSIO_DEVICE(CSIO_DEVID_AMSTERDAM_T4_FCOE, 0), /* AMSTERDAM T4 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T480_FCOE, 0), /* HUAWEI T480 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T440_FCOE, 0), /* HUAWEI T440 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_STG310_FCOE, 0), /* HUAWEI STG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_ACROMAG_XMC_XAUI, 0), /* ACROMAG XAUI FCOE */
+ CSIO_DEVICE(CSIO_DEVID_QUANTA_MEZZ_SFP_FCOE, 0),/* QUANTA MEZZ FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_10GT_FCOE, 0), /* HUAWEI 10GT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T440_TOE_FCOE, 0),/* HUAWEI T4 TOE FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580DBG_FCOE, 0), /* T5 DEBUG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520CR_FCOE, 0), /* T520CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T522CR_FCOE, 0), /* T522CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540CR_FCOE, 0), /* T540CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520BCH_FCOE, 0), /* T520BCH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540BCH_FCOE, 0), /* T540BCH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540CH_FCOE, 0), /* T540CH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520SO_FCOE, 0), /* T520SO FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520CX_FCOE, 0), /* T520CX FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520BT_FCOE, 0), /* T520BT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T504BT_FCOE, 0), /* T504BT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_B520_FCOE, 0), /* B520 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_B504_FCOE, 0), /* B504 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580CR2_FCOE, 0), /* T580 CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540LPCR_FCOE, 0), /* T540 LP-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_AMSTERDAM_T5_FCOE, 0), /* AMSTERDAM T5 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580LPCR_FCOE, 0), /* T580 LP-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520LLCR_FCOE, 0), /* T520 LL-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T560CR_FCOE, 0), /* T560 CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580CR_FCOE, 0), /* T580 CR FCOE */
{ 0, 0, 0, 0, 0, 0, 0 }
};
@@ -1259,4 +1286,5 @@ MODULE_DESCRIPTION(CSIO_DRV_DESC);
MODULE_LICENSE(CSIO_DRV_LICENSE);
MODULE_DEVICE_TABLE(pci, csio_pci_tbl);
MODULE_VERSION(CSIO_DRV_VERSION);
-MODULE_FIRMWARE(CSIO_FW_FNAME);
+MODULE_FIRMWARE(FW_FNAME_T4);
+MODULE_FIRMWARE(FW_FNAME_T5);
diff --git a/drivers/scsi/csiostor/csio_init.h b/drivers/scsi/csiostor/csio_init.h
index 0838fd7ec9c7..5cc5d317a442 100644
--- a/drivers/scsi/csiostor/csio_init.h
+++ b/drivers/scsi/csiostor/csio_init.h
@@ -52,31 +52,6 @@
#define CSIO_DRV_DESC "Chelsio FCoE driver"
#define CSIO_DRV_VERSION "1.0.0"
-#define CSIO_DEVICE(devid, idx) \
-{ PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
-
-#define CSIO_IS_T4_FPGA(_dev) (((_dev) == CSIO_DEVID_PE10K) ||\
- ((_dev) == CSIO_DEVID_PE10K_PF1))
-
-/* FCoE device IDs */
-#define CSIO_DEVID_PE10K 0xA000
-#define CSIO_DEVID_PE10K_PF1 0xA001
-#define CSIO_DEVID_T440DBG_FCOE 0x4600
-#define CSIO_DEVID_T420CR_FCOE 0x4601
-#define CSIO_DEVID_T422CR_FCOE 0x4602
-#define CSIO_DEVID_T440CR_FCOE 0x4603
-#define CSIO_DEVID_T420BCH_FCOE 0x4604
-#define CSIO_DEVID_T440BCH_FCOE 0x4605
-#define CSIO_DEVID_T440CH_FCOE 0x4606
-#define CSIO_DEVID_T420SO_FCOE 0x4607
-#define CSIO_DEVID_T420CX_FCOE 0x4608
-#define CSIO_DEVID_T420BT_FCOE 0x4609
-#define CSIO_DEVID_T404BT_FCOE 0x460A
-#define CSIO_DEVID_B420_FCOE 0x460B
-#define CSIO_DEVID_B404_FCOE 0x460C
-#define CSIO_DEVID_T480CR_FCOE 0x460D
-#define CSIO_DEVID_T440LPCR_FCOE 0x460E
-
extern struct fc_function_template csio_fc_transport_funcs;
extern struct fc_function_template csio_fc_transport_vport_funcs;
@@ -100,6 +75,10 @@ struct csio_lnode *csio_shost_init(struct csio_hw *, struct device *, bool,
void csio_shost_exit(struct csio_lnode *);
void csio_lnodes_exit(struct csio_hw *, bool);
+/* DebugFS helper routines */
+void csio_add_debugfs_mem(struct csio_hw *, const char *,
+ unsigned int, unsigned int);
+
static inline struct Scsi_Host *
csio_ln_to_shost(struct csio_lnode *ln)
{
diff --git a/drivers/scsi/csiostor/csio_lnode.h b/drivers/scsi/csiostor/csio_lnode.h
index 8d84988ab06d..0f9c04175b11 100644
--- a/drivers/scsi/csiostor/csio_lnode.h
+++ b/drivers/scsi/csiostor/csio_lnode.h
@@ -114,7 +114,7 @@ struct csio_lnode_stats {
uint32_t n_rnode_match; /* matched rnode */
uint32_t n_dev_loss_tmo; /* Device loss timeout */
uint32_t n_fdmi_err; /* fdmi err */
- uint32_t n_evt_fw[RSCN_DEV_LOST]; /* fw events */
+ uint32_t n_evt_fw[PROTO_ERR_IMPL_LOGO]; /* fw events */
enum csio_ln_ev n_evt_sm[CSIO_LNE_MAX_EVENT]; /* State m/c events */
uint32_t n_rnode_alloc; /* rnode allocated */
uint32_t n_rnode_free; /* rnode freed */
diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c
index 5b27c48f6836..f5d9ee1fda62 100644
--- a/drivers/scsi/csiostor/csio_mb.c
+++ b/drivers/scsi/csiostor/csio_mb.c
@@ -182,7 +182,7 @@ csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
* @tmo: Command timeout.
* @pf: PF number.
* @vf: VF number.
- * @nparams: Number of paramters
+ * @nparams: Number of parameters
* @params: Parameter mnemonic array.
* @val: Parameter value array.
* @wr: Write/Read PARAMS.
@@ -721,7 +721,7 @@ csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @mbp: Mailbox structure to initialize
* @priv: Private data
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -752,7 +752,7 @@ csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @priv: Private data
* @mb_tmo: Mailbox time-out period (in ms).
* @cascaded_req: TRUE - if this request is cascased with Eq-alloc request.
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -817,7 +817,7 @@ csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @mbp: Mailbox structure to initialize
* @priv: Private data.
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -840,7 +840,7 @@ csio_mb_eq_ofld_alloc_write(struct csio_hw *hw, struct csio_mb *mbp,
* @hw: The HW structure.
* @mbp: Mailbox structure to initialize.
* @retval: Firmware return value.
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
*
*/
void
@@ -870,7 +870,7 @@ csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
* @mbp: Mailbox structure to initialize
* @priv: Private data area.
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters, that is to be freed.
+ * @eq_ofld_params: (Offload) Egress queue parameters, that is to be freed.
* @cbfn: The call-back function
*
*
diff --git a/drivers/scsi/csiostor/csio_rnode.c b/drivers/scsi/csiostor/csio_rnode.c
index 51c6a388de2b..e9c3b045f587 100644
--- a/drivers/scsi/csiostor/csio_rnode.c
+++ b/drivers/scsi/csiostor/csio_rnode.c
@@ -302,7 +302,7 @@ csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
{
uint8_t rport_type;
struct csio_rnode *rn, *match_rn;
- uint32_t vnp_flowid;
+ uint32_t vnp_flowid = 0;
__be32 *port_id;
port_id = (__be32 *)&rdevp->r_id[0];
@@ -350,6 +350,14 @@ csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
* Else, go ahead and alloc a new rnode.
*/
if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
+ if (rn == match_rn)
+ goto found_rnode;
+ csio_ln_dbg(ln,
+ "nport_id:x%x and wwpn:%llx"
+ " match for ssni:x%x\n",
+ rn->nport_id,
+ wwn_to_u64(rdevp->wwpn),
+ rdev_flowid);
if (csio_is_rnode_ready(rn)) {
csio_ln_warn(ln,
"rnode is already"
diff --git a/drivers/scsi/csiostor/csio_rnode.h b/drivers/scsi/csiostor/csio_rnode.h
index a3b434c801da..65940096a80d 100644
--- a/drivers/scsi/csiostor/csio_rnode.h
+++ b/drivers/scsi/csiostor/csio_rnode.h
@@ -63,7 +63,7 @@ struct csio_rnode_stats {
uint32_t n_err_nomem; /* error nomem */
uint32_t n_evt_unexp; /* unexpected event */
uint32_t n_evt_drop; /* unexpected event */
- uint32_t n_evt_fw[RSCN_DEV_LOST]; /* fw events */
+ uint32_t n_evt_fw[PROTO_ERR_IMPL_LOGO]; /* fw events */
enum csio_rn_ev n_evt_sm[CSIO_RNFE_MAX_EVENT]; /* State m/c events */
uint32_t n_lun_rst; /* Number of resets of
* of LUNs under this
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index c32df1bdaa97..4255ce264abf 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -85,8 +85,8 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq)
*/
if (flq->inc_idx >= 8) {
csio_wr_reg32(hw, DBPRIO(1) | QID(flq->un.fl.flid) |
- PIDX(flq->inc_idx / 8),
- MYPF_REG(SGE_PF_KDOORBELL));
+ CSIO_HW_PIDX(hw, flq->inc_idx / 8),
+ MYPF_REG(SGE_PF_KDOORBELL));
flq->inc_idx &= 7;
}
}
@@ -989,7 +989,8 @@ csio_wr_issue(struct csio_hw *hw, int qidx, bool prio)
wmb();
/* Ring SGE Doorbell writing q->pidx into it */
csio_wr_reg32(hw, DBPRIO(prio) | QID(q->un.eq.physeqid) |
- PIDX(q->inc_idx), MYPF_REG(SGE_PF_KDOORBELL));
+ CSIO_HW_PIDX(hw, q->inc_idx),
+ MYPF_REG(SGE_PF_KDOORBELL));
q->inc_idx = 0;
return 0;
@@ -1331,20 +1332,30 @@ csio_wr_fixup_host_params(struct csio_hw *hw)
/* FL BUFFER SIZE#0 is Page size i,e already aligned to cache line */
csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0);
- csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) +
- sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE2);
- csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) +
- sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE3);
+
+ /*
+ * If using hard params, the following will get set correctly
+ * in csio_wr_set_sge().
+ */
+ if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) {
+ csio_wr_reg32(hw,
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) +
+ sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
+ SGE_FL_BUFFER_SIZE2);
+ csio_wr_reg32(hw,
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) +
+ sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
+ SGE_FL_BUFFER_SIZE3);
+ }
csio_wr_reg32(hw, HPZ0(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ);
/* default value of rx_dma_offset of the NIC driver */
csio_set_reg_field(hw, SGE_CONTROL, PKTSHIFT_MASK,
PKTSHIFT(CSIO_SGE_RX_DMA_OFFSET));
+
+ csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG,
+ CSUM_HAS_PSEUDO_HDR, 0);
}
static void
@@ -1460,18 +1471,21 @@ csio_wr_set_sge(struct csio_hw *hw)
* and generate an interrupt when this occurs so we can recover.
*/
csio_set_reg_field(hw, SGE_DBFIFO_STATUS,
- HP_INT_THRESH(HP_INT_THRESH_MASK) |
- LP_INT_THRESH(LP_INT_THRESH_MASK),
- HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) |
- LP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH));
+ HP_INT_THRESH(HP_INT_THRESH_MASK) |
+ CSIO_HW_LP_INT_THRESH(hw, CSIO_HW_M_LP_INT_THRESH(hw)),
+ HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) |
+ CSIO_HW_LP_INT_THRESH(hw, CSIO_SGE_DBFIFO_INT_THRESH));
+
csio_set_reg_field(hw, SGE_DOORBELL_CONTROL, ENABLE_DROP,
ENABLE_DROP);
/* SGE_FL_BUFFER_SIZE0 is set up by csio_wr_fixup_host_params(). */
CSIO_SET_FLBUF_SIZE(hw, 1, CSIO_SGE_FLBUF_SIZE1);
- CSIO_SET_FLBUF_SIZE(hw, 2, CSIO_SGE_FLBUF_SIZE2);
- CSIO_SET_FLBUF_SIZE(hw, 3, CSIO_SGE_FLBUF_SIZE3);
+ csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE2 + sge->csio_fl_align - 1)
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2);
+ csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE3 + sge->csio_fl_align - 1)
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3);
CSIO_SET_FLBUF_SIZE(hw, 4, CSIO_SGE_FLBUF_SIZE4);
CSIO_SET_FLBUF_SIZE(hw, 5, CSIO_SGE_FLBUF_SIZE5);
CSIO_SET_FLBUF_SIZE(hw, 6, CSIO_SGE_FLBUF_SIZE6);
@@ -1522,22 +1536,24 @@ void
csio_wr_sge_init(struct csio_hw *hw)
{
/*
- * If we are master:
+ * If we are master and chip is not initialized:
* - If we plan to use the config file, we need to fixup some
* host specific registers, and read the rest of the SGE
* configuration.
* - If we dont plan to use the config file, we need to initialize
* SGE entirely, including fixing the host specific registers.
+ * If we are master and chip is initialized, just read and work off of
+ * the already initialized SGE values.
* If we arent the master, we are only allowed to read and work off of
* the already initialized SGE values.
*
* Therefore, before calling this function, we assume that the master-
- * ship of the card, and whether to use config file or not, have
- * already been decided. In other words, CSIO_HWF_USING_SOFT_PARAMS and
- * CSIO_HWF_MASTER should be set/unset.
+ * ship of the card, state and whether to use config file or not, have
+ * already been decided.
*/
if (csio_is_hw_master(hw)) {
- csio_wr_fixup_host_params(hw);
+ if (hw->fw_state != CSIO_DEV_STATE_INIT)
+ csio_wr_fixup_host_params(hw);
if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS)
csio_wr_get_sge(hw);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index fed486bfd3f4..694e13c45dfd 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -4616,26 +4616,21 @@ static void adapter_uninit(struct AdapterCtlBlk *acb)
#undef SPRINTF
-#define SPRINTF(args...) pos += sprintf(pos, args)
+#define SPRINTF(args...) seq_printf(m,##args)
#undef YESNO
#define YESNO(YN) \
if (YN) SPRINTF(" Yes ");\
else SPRINTF(" No ")
-static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
- char **start, off_t offset, int length, int inout)
+static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
int spd, spd1;
- char *pos = buffer;
struct DeviceCtlBlk *dcb;
unsigned long flags;
int dev;
- if (inout) /* Has data been written to the file ? */
- return -EPERM;
-
SPRINTF(DC395X_BANNER " PCI SCSI Host Adapter\n");
SPRINTF(" Driver Version " DC395X_VERSION "\n");
@@ -4735,22 +4730,15 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
SPRINTF("END\n");
}
- *start = buffer + offset;
DC395x_UNLOCK_IO(acb->scsi_host, flags);
-
- if (pos - buffer < offset)
- return 0;
- else if (pos - buffer - offset < length)
- return pos - buffer - offset;
- else
- return length;
+ return 0;
}
static struct scsi_host_template dc395x_driver_template = {
.module = THIS_MODULE,
.proc_name = DC395X_NAME,
- .proc_info = dc395x_proc_info,
+ .show_info = dc395x_show_info,
.name = DC395X_BANNER " " DC395X_VERSION,
.queuecommand = dc395x_queue_command,
.bios_param = dc395x_bios_param,
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6f32f1..68adb8955d2d 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -232,13 +232,13 @@ static void stpg_endio(struct request *req, int error)
struct scsi_sense_hdr sense_hdr;
unsigned err = SCSI_DH_OK;
- if (error || host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
+ if (host_byte(req->errors) != DID_OK ||
+ msg_byte(req->errors) != COMMAND_COMPLETE) {
err = SCSI_DH_IO;
goto done;
}
- if (h->senselen > 0) {
+ if (req->sense_len > 0) {
err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr);
if (!err) {
@@ -255,7 +255,9 @@ static void stpg_endio(struct request *req, int error)
ALUA_DH_NAME, sense_hdr.sense_key,
sense_hdr.asc, sense_hdr.ascq);
err = SCSI_DH_IO;
- }
+ } else if (error)
+ err = SCSI_DH_IO;
+
if (err == SCSI_DH_OK) {
h->state = TPGS_STATE_OPTIMIZED;
sdev_printk(KERN_INFO, h->sdev,
@@ -710,6 +712,10 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
return result;
}
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
/*
* alua_activate - activate a path
* @sdev: device on the path to be activated
@@ -731,6 +737,9 @@ static int alua_activate(struct scsi_device *sdev,
if (err != SCSI_DH_OK)
goto out;
+ if (optimize_stpg)
+ h->flags |= ALUA_OPTIMIZE_STPG;
+
if (h->tpgs & TPGS_MODE_EXPLICIT) {
switch (h->state) {
case TPGS_STATE_NONOPTIMIZED:
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b6e2700ec1c6..19e1b422260a 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -553,36 +553,14 @@ static const char *adpt_info(struct Scsi_Host *host)
return (char *) (pHba->detail);
}
-static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int adpt_show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct adpt_device* d;
int id;
int chan;
- int len = 0;
- int begin = 0;
- int pos = 0;
adpt_hba* pHba;
int unit;
- *start = buffer;
- if (inout == TRUE) {
- /*
- * The user has done a write and wants us to take the
- * data in the buffer and do something with it.
- * proc_scsiwrite calls us with inout = 1
- *
- * Read data from buffer (writing to us) - NOT SUPPORTED
- */
- return -EINVAL;
- }
-
- /*
- * inout = 0 means the user has done a read and wants information
- * returned, so we write information about the cards into the buffer
- * proc_scsiread() calls us with inout = 0
- */
-
// Find HBA (host bus adapter) we are looking for
mutex_lock(&adpt_configuration_lock);
for (pHba = hba_chain; pHba; pHba = pHba->next) {
@@ -596,86 +574,30 @@ static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, of
}
host = pHba->host;
- len = sprintf(buffer , "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION);
- len += sprintf(buffer+len, "%s\n", pHba->detail);
- len += sprintf(buffer+len, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n",
+ seq_printf(m, "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION);
+ seq_printf(m, "%s\n", pHba->detail);
+ seq_printf(m, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n",
pHba->host->host_no, pHba->name, host->irq);
- len += sprintf(buffer+len, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n",
+ seq_printf(m, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n",
host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize);
- pos = begin + len;
-
- /* CHECKPOINT */
- if(pos > offset + length) {
- goto stop_output;
- }
- if(pos <= offset) {
- /*
- * If we haven't even written to where we last left
- * off (the last time we were called), reset the
- * beginning pointer.
- */
- len = 0;
- begin = pos;
- }
- len += sprintf(buffer+len, "Devices:\n");
+ seq_printf(m, "Devices:\n");
for(chan = 0; chan < MAX_CHANNEL; chan++) {
for(id = 0; id < MAX_ID; id++) {
d = pHba->channel[chan].device[id];
- while(d){
- len += sprintf(buffer+len,"\t%-24.24s", d->pScsi_dev->vendor);
- len += sprintf(buffer+len," Rev: %-8.8s\n", d->pScsi_dev->rev);
- pos = begin + len;
-
-
- /* CHECKPOINT */
- if(pos > offset + length) {
- goto stop_output;
- }
- if(pos <= offset) {
- len = 0;
- begin = pos;
- }
+ while(d) {
+ seq_printf(m,"\t%-24.24s", d->pScsi_dev->vendor);
+ seq_printf(m," Rev: %-8.8s\n", d->pScsi_dev->rev);
unit = d->pI2o_dev->lct_data.tid;
- len += sprintf(buffer+len, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d) (%s)\n\n",
+ seq_printf(m, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d) (%s)\n\n",
unit, (int)d->scsi_channel, (int)d->scsi_id, (int)d->scsi_lun,
scsi_device_online(d->pScsi_dev)? "online":"offline");
- pos = begin + len;
-
- /* CHECKPOINT */
- if(pos > offset + length) {
- goto stop_output;
- }
- if(pos <= offset) {
- len = 0;
- begin = pos;
- }
-
d = d->next_lun;
}
}
}
-
- /*
- * begin is where we last checked our position with regards to offset
- * begin is always less than offset. len is relative to begin. It
- * is the number of bytes written past begin
- *
- */
-stop_output:
- /* stop the output and calculate the correct length */
- *(buffer + len) = '\0';
-
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin);
- if(len > length) {
- len = length;
- } else if(len < 0){
- len = 0;
- **start = '\0';
- }
- return len;
+ return 0;
}
/*
@@ -3639,7 +3561,7 @@ static struct scsi_host_template driver_template = {
.module = THIS_MODULE,
.name = "dpt_i2o",
.proc_name = "dpt_i2o",
- .proc_info = adpt_proc_info,
+ .show_info = adpt_show_info,
.info = adpt_info,
.queuecommand = adpt_queue,
.eh_abort_handler = adpt_abort,
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 4b11bb04f5c4..d01f01604140 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -216,7 +216,8 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
int sig, count;
tpnt->proc_name = "dtc3x80";
- tpnt->proc_info = &dtc_proc_info;
+ tpnt->show_info = dtc_show_info;
+ tpnt->write_info = dtc_write_info;
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
addr = 0;
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index cdc621204b66..92d7cfc3f4fc 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -88,7 +88,8 @@ static int dtc_bus_reset(Scsi_Cmnd *);
#define NCR5380_queue_command dtc_queue_command
#define NCR5380_abort dtc_abort
#define NCR5380_bus_reset dtc_bus_reset
-#define NCR5380_proc_info dtc_proc_info
+#define NCR5380_show_info dtc_show_info
+#define NCR5380_write_info dtc_write_info
/* 15 12 11 10
1001 1100 0000 0000 */
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index d5f8362335d3..356def44ce58 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -92,58 +92,22 @@ static unsigned long queue_counter;
static struct scsi_host_template driver_template;
-/*
- * eata_proc_info
- * inout : decides on the direction of the dataflow and the meaning of the
- * variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file
- * from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer
- * else number of bytes in the buffer
- */
-static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
- int length, int rw)
+static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
- int len = 0;
- off_t begin = 0, pos = 0;
-
- if (rw)
- return -ENOSYS;
-
- len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+ seq_printf(m, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
- len += sprintf(buffer + len, "queued commands: %10ld\n"
+ seq_printf(m, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
- len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+ seq_printf(m, "\nscsi%-2d: HBA %.10s\n",
shost->host_no, SD(shost)->name);
- len += sprintf(buffer + len, "Firmware revision: v%s\n",
+ seq_printf(m, "Firmware revision: v%s\n",
SD(shost)->revision);
- len += sprintf(buffer + len, "IO: PIO\n");
- len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
- len += sprintf(buffer + len, "Host Bus: %s\n",
+ seq_printf(m, "IO: PIO\n");
+ seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base);
+ seq_printf(m, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
(SD(shost)->bustype == 'E')?"EISA":"ISA ");
-
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
-
-stop_output:
- DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
-
- return len;
+ return 0;
}
static int eata_pio_release(struct Scsi_Host *sh)
@@ -985,7 +949,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
static struct scsi_host_template driver_template = {
.proc_name = "eata_pio",
.name = "EATA (Extended Attachment) PIO driver",
- .proc_info = eata_pio_proc_info,
+ .show_info = eata_pio_show_info,
.detect = eata_pio_detect,
.release = eata_pio_release,
.queuecommand = eata_pio_queue,
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index b5d92fc93c70..292b24f9bf93 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -490,7 +490,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
{
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
- struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
rtnl_lock();
if (!fcoe->removed)
@@ -501,7 +500,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(fip);
scsi_host_put(fip->lp->host);
- fcoe_ctlr_device_delete(ctlr_dev);
dev_put(netdev);
module_put(THIS_MODULE);
}
@@ -1657,7 +1655,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
skb->priority = fcoe->priority;
if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN &&
- fcoe->realdev->features & NETIF_F_HW_VLAN_TX) {
+ fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) {
skb->vlan_tci = VLAN_TAG_PRESENT |
vlan_dev_vlan_id(fcoe->netdev);
skb->dev = fcoe->realdev;
@@ -2194,6 +2192,8 @@ out_nodev:
*/
static void fcoe_destroy_work(struct work_struct *work)
{
+ struct fcoe_ctlr_device *cdev;
+ struct fcoe_ctlr *ctlr;
struct fcoe_port *port;
struct fcoe_interface *fcoe;
struct Scsi_Host *shost;
@@ -2224,10 +2224,15 @@ static void fcoe_destroy_work(struct work_struct *work)
mutex_lock(&fcoe_config_mutex);
fcoe = port->priv;
+ ctlr = fcoe_to_ctlr(fcoe);
+ cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
+
fcoe_if_destroy(port->lport);
fcoe_interface_cleanup(fcoe);
mutex_unlock(&fcoe_config_mutex);
+
+ fcoe_ctlr_device_delete(cdev);
}
/**
@@ -2335,7 +2340,9 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
rc = -EIO;
rtnl_unlock();
fcoe_interface_cleanup(fcoe);
- goto out_nortnl;
+ mutex_unlock(&fcoe_config_mutex);
+ fcoe_ctlr_device_delete(ctlr_dev);
+ goto out;
}
/* Make this the "master" N_Port */
@@ -2375,8 +2382,8 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
out_nodev:
rtnl_unlock();
-out_nortnl:
mutex_unlock(&fcoe_config_mutex);
+out:
return rc;
}
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 08c3bc398da2..cd743c545ce9 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2161,7 +2161,7 @@ static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
fip->probe_tries++;
- wait = random32() % FIP_VN_PROBE_WAIT;
+ wait = prandom_u32() % FIP_VN_PROBE_WAIT;
} else
wait = FIP_VN_RLIM_INT;
mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
@@ -2794,7 +2794,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
fcoe_all_vn2vn, 0);
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_BEACON_INT +
- (random32() % FIP_VN_BEACON_FUZZ));
+ (prandom_u32() % FIP_VN_BEACON_FUZZ));
}
if (time_before(fip->port_ka_time, next_time))
next_time = fip->port_ka_time;
@@ -2815,6 +2815,47 @@ unlock:
}
/**
+ * fcoe_ctlr_mode_set() - Set or reset the ctlr's mode
+ * @lport: The local port to be (re)configured
+ * @fip: The FCoE controller whose mode is changing
+ * @fip_mode: The new fip mode
+ *
+ * Note that the we shouldn't be changing the libfc discovery settings
+ * (fc_disc_config) while an lport is going through the libfc state
+ * machine. The mode can only be changed when a fcoe_ctlr device is
+ * disabled, so that should ensure that this routine is only called
+ * when nothing is happening.
+ */
+void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
+ enum fip_state fip_mode)
+{
+ void *priv;
+
+ WARN_ON(lport->state != LPORT_ST_RESET &&
+ lport->state != LPORT_ST_DISABLED);
+
+ if (fip_mode == FIP_MODE_VN2VN) {
+ lport->rport_priv_size = sizeof(struct fcoe_rport);
+ lport->point_to_multipoint = 1;
+ lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
+ lport->tt.disc_start = fcoe_ctlr_disc_start;
+ lport->tt.disc_stop = fcoe_ctlr_disc_stop;
+ lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
+ priv = fip;
+ } else {
+ lport->rport_priv_size = 0;
+ lport->point_to_multipoint = 0;
+ lport->tt.disc_recv_req = NULL;
+ lport->tt.disc_start = NULL;
+ lport->tt.disc_stop = NULL;
+ lport->tt.disc_stop_final = NULL;
+ priv = lport;
+ }
+
+ fc_disc_config(lport, priv);
+}
+
+/**
* fcoe_libfc_config() - Sets up libfc related properties for local port
* @lport: The local port to configure libfc for
* @fip: The FCoE controller in use by the local port
@@ -2833,21 +2874,9 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
fc_exch_init(lport);
fc_elsct_init(lport);
fc_lport_init(lport);
- if (fip->mode == FIP_MODE_VN2VN)
- lport->rport_priv_size = sizeof(struct fcoe_rport);
fc_rport_init(lport);
- if (fip->mode == FIP_MODE_VN2VN) {
- lport->point_to_multipoint = 1;
- lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
- lport->tt.disc_start = fcoe_ctlr_disc_start;
- lport->tt.disc_stop = fcoe_ctlr_disc_stop;
- lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
- mutex_init(&lport->disc.disc_mutex);
- INIT_LIST_HEAD(&lport->disc.rports);
- lport->disc.priv = fip;
- } else {
- fc_disc_init(lport);
- }
+ fc_disc_init(lport);
+ fcoe_ctlr_mode_set(lport, fip, fip->mode);
return 0;
}
EXPORT_SYMBOL_GPL(fcoe_libfc_config);
@@ -2875,6 +2904,7 @@ EXPORT_SYMBOL(fcoe_fcf_get_selected);
void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
{
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+ struct fc_lport *lport = ctlr->lp;
mutex_lock(&ctlr->ctlr_mutex);
switch (ctlr_dev->mode) {
@@ -2888,5 +2918,7 @@ void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
}
mutex_unlock(&ctlr->ctlr_mutex);
+
+ fcoe_ctlr_mode_set(lport, ctlr, ctlr->mode);
}
EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode);
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5041f925c191..5cec6c60ca22 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -745,42 +745,36 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
#include "NCR5380.c"
-#define PRINTP(x) len += sprintf(buffer+len, x)
+#define PRINTP(x) seq_printf(m, x)
#define ANDP ,
-static int sprint_opcode(char *buffer, int len, int opcode)
+static void sprint_opcode(struct seq_file *m, int opcode)
{
- int start = len;
PRINTP("0x%02x " ANDP opcode);
- return len - start;
}
-static int sprint_command(char *buffer, int len, unsigned char *command)
+static void sprint_command(struct seq_file *m, unsigned char *command)
{
- int i, s, start = len;
- len += sprint_opcode(buffer, len, command[0]);
+ int i, s;
+ sprint_opcode(m, command[0]);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
PRINTP("%02x " ANDP command[i]);
PRINTP("\n");
- return len - start;
}
/**
* sprintf_Scsi_Cmnd - print a scsi command
- * @buffer: buffr to print into
- * @len: buffer length
+ * @m: seq_fil to print into
* @cmd: SCSI command block
*
* Print out the target and command data in hex
*/
-static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd)
+static void sprint_Scsi_Cmnd(struct seq_file *m, Scsi_Cmnd * cmd)
{
- int start = len;
PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun);
PRINTP(" command = ");
- len += sprint_command(buffer, len, cmd->cmnd);
- return len - start;
+ sprint_command(m, cmd->cmnd);
}
/**
@@ -800,9 +794,8 @@ static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd)
* Locks: global cli/lock for queue walk
*/
-static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout)
+static int generic_NCR5380_show_info(struct seq_file *m, struct Scsi_Host *scsi_ptr)
{
- int len = 0;
NCR5380_local_declare();
unsigned long flags;
unsigned char status;
@@ -853,16 +846,16 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
for (i = 0; i < 8; i++)
if (dev->vendor[i] >= 0x20)
- *(buffer + (len++)) = dev->vendor[i];
- *(buffer + (len++)) = ' ';
+ seq_putc(m, dev->vendor[i]);
+ seq_putc(m, ' ');
for (i = 0; i < 16; i++)
if (dev->model[i] >= 0x20)
- *(buffer + (len++)) = dev->model[i];
- *(buffer + (len++)) = ' ';
+ seq_putc(m, dev->model[i]);
+ seq_putc(m, ' ');
for (i = 0; i < 4; i++)
if (dev->rev[i] >= 0x20)
- *(buffer + (len++)) = dev->rev[i];
- *(buffer + (len++)) = ' ';
+ seq_putc(m, dev->rev[i]);
+ seq_putc(m, ' ');
PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr);
if (tr)
@@ -886,32 +879,28 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
if (!hostdata->connected) {
PRINTP("No currently connected command\n");
} else {
- len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected);
+ sprint_Scsi_Cmnd(m, (Scsi_Cmnd *) hostdata->connected);
}
PRINTP("issue_queue\n");
for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- len += sprint_Scsi_Cmnd(buffer, len, ptr);
+ sprint_Scsi_Cmnd(m, ptr);
PRINTP("disconnected_queue\n");
for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- len += sprint_Scsi_Cmnd(buffer, len, ptr);
+ sprint_Scsi_Cmnd(m, ptr);
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
spin_unlock_irqrestore(scsi_ptr->host_lock, flags);
- return len;
+ return 0;
}
#undef PRINTP
#undef ANDP
static struct scsi_host_template driver_template = {
- .proc_info = generic_NCR5380_proc_info,
+ .show_info = generic_NCR5380_show_info,
.name = "Generic NCR5380/NCR53C400 Scsi Driver",
.detect = generic_NCR5380_detect,
.release = generic_NCR5380_release_resources,
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 59bceac51a4c..6d55b4e7e792 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4676,7 +4676,8 @@ static struct scsi_host_template gdth_template = {
.eh_bus_reset_handler = gdth_eh_bus_reset,
.slave_configure = gdth_slave_configure,
.bios_param = gdth_bios_param,
- .proc_info = gdth_proc_info,
+ .show_info = gdth_show_info,
+ .write_info = gdth_set_info,
.eh_timed_out = gdth_timed_out,
.proc_name = "gdth",
.can_queue = GDTH_MAXCMDS,
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index fbf6f0f4b0dd..3fd8b83ffbf9 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -1007,6 +1007,7 @@ typedef struct {
/* function prototyping */
-int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
+int gdth_show_info(struct seq_file *, struct Scsi_Host *);
+int gdth_set_info(struct Scsi_Host *, char *, int);
#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 652754319a4b..9fb632684863 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -5,23 +5,9 @@
#include <linux/completion.h>
#include <linux/slab.h>
-int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,
- int inout)
+int gdth_set_info(struct Scsi_Host *host, char *buffer, int length)
{
gdth_ha_str *ha = shost_priv(host);
-
- TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
- length,(int)offset,inout));
-
- if (inout)
- return(gdth_set_info(buffer,length,host,ha));
- else
- return(gdth_get_info(buffer,start,offset,length,host,ha));
-}
-
-static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- gdth_ha_str *ha)
-{
int ret_val = -EINVAL;
TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
@@ -149,12 +135,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
return(-EINVAL);
}
-static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host, gdth_ha_str *ha)
+int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
{
- int size = 0,len = 0;
+ gdth_ha_str *ha = shost_priv(host);
int hlen;
- off_t begin = 0,pos = 0;
int id, i, j, k, sec, flag;
int no_mdrv = 0, drv_no, is_mirr;
u32 cnt;
@@ -189,8 +173,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
/* request is i.e. "cat /proc/scsi/gdth/0" */
/* format: %-15s\t%-10s\t%-15s\t%s */
/* driver parameters */
- size = sprintf(buffer+len,"Driver Parameters:\n");
- len += size; pos = begin + len;
+ seq_printf(m, "Driver Parameters:\n");
if (reserve_list[0] == 0xff)
strcpy(hrec, "--");
else {
@@ -201,69 +184,50 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]);
}
}
- size = sprintf(buffer+len,
+ seq_printf(m,
" reserve_mode: \t%d \treserve_list: \t%s\n",
reserve_mode, hrec);
- len += size; pos = begin + len;
- size = sprintf(buffer+len,
+ seq_printf(m,
" max_ids: \t%-3d \thdr_channel: \t%d\n",
max_ids, hdr_channel);
- len += size; pos = begin + len;
/* controller information */
- size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
- len += size; pos = begin + len;
- strcpy(hrec, ha->binfo.type_string);
- size = sprintf(buffer+len,
+ seq_printf(m,"\nDisk Array Controller Information:\n");
+ seq_printf(m,
" Number: \t%d \tName: \t%s\n",
- ha->hanum, hrec);
- len += size; pos = begin + len;
+ ha->hanum, ha->binfo.type_string);
+ seq_printf(m,
+ " Driver Ver.: \t%-10s\tFirmware Ver.: \t",
+ GDTH_VERSION_STR);
if (ha->more_proc)
- sprintf(hrec, "%d.%02d.%02d-%c%03X",
+ seq_printf(m, "%d.%02d.%02d-%c%03X\n",
(u8)(ha->binfo.upd_fw_ver>>24),
(u8)(ha->binfo.upd_fw_ver>>16),
(u8)(ha->binfo.upd_fw_ver),
ha->bfeat.raid ? 'R':'N',
ha->binfo.upd_revision);
else
- sprintf(hrec, "%d.%02d", (u8)(ha->cpar.version>>8),
+ seq_printf(m, "%d.%02d\n", (u8)(ha->cpar.version>>8),
(u8)(ha->cpar.version));
-
- size = sprintf(buffer+len,
- " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n",
- GDTH_VERSION_STR, hrec);
- len += size; pos = begin + len;
- if (ha->more_proc) {
+ if (ha->more_proc)
/* more information: 1. about controller */
- size = sprintf(buffer+len,
+ seq_printf(m,
" Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n",
ha->binfo.ser_no, ha->binfo.memsize / 1024);
- len += size; pos = begin + len;
- }
#ifdef GDTH_DMA_STATISTICS
/* controller statistics */
- size = sprintf(buffer+len,"\nController Statistics:\n");
- len += size; pos = begin + len;
- size = sprintf(buffer+len,
+ seq_printf(m,"\nController Statistics:\n");
+ seq_printf(m,
" 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
ha->dma32_cnt, ha->dma64_cnt);
- len += size; pos = begin + len;
#endif
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
-
if (ha->more_proc) {
/* more information: 2. about physical devices */
- size = sprintf(buffer+len,"\nPhysical Devices:");
- len += size; pos = begin + len;
+ seq_printf(m, "\nPhysical Devices:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -309,21 +273,19 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
strncpy(hrec+8,pdi->product,16);
strncpy(hrec+24,pdi->revision,4);
hrec[28] = 0;
- size = sprintf(buffer+len,
+ seq_printf(m,
"\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n",
'A'+i,pdi->target_id,pdi->lun,hrec);
- len += size; pos = begin + len;
flag = TRUE;
pdi->no_ldrive &= 0xffff;
if (pdi->no_ldrive == 0xffff)
strcpy(hrec,"--");
else
sprintf(hrec,"%d",pdi->no_ldrive);
- size = sprintf(buffer+len,
+ seq_printf(m,
" Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n",
pdi->blkcnt/(1024*1024/pdi->blksize),
hrec);
- len += size; pos = begin + len;
} else {
pdi->devtype = 0xff;
}
@@ -333,11 +295,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
for (k = 0; k < pds->count; ++k) {
if (pds->list[k].tid == pdi->target_id &&
pds->list[k].lun == pdi->lun) {
- size = sprintf(buffer+len,
+ seq_printf(m,
" Retries: \t%-6d \tReassigns: \t%d\n",
pds->list[k].retries,
pds->list[k].reassigns);
- len += size; pos = begin + len;
break;
}
}
@@ -355,32 +316,20 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
pdef->sddc_type = 0x08;
if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
- size = sprintf(buffer+len,
+ seq_printf(m,
" Grown Defects:\t%d\n",
pdef->sddc_cnt);
- len += size; pos = begin + len;
}
}
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length) {
- gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- goto stop_output;
- }
}
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- if (!flag) {
- size = sprintf(buffer+len, "\n --\n");
- len += size; pos = begin + len;
- }
+ if (!flag)
+ seq_printf(m, "\n --\n");
/* 3. about logical drives */
- size = sprintf(buffer+len,"\nLogical Drives:");
- len += size; pos = begin + len;
+ seq_printf(m,"\nLogical Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -418,10 +367,9 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
}
if (drv_no == i) {
- size = sprintf(buffer+len,
+ seq_printf(m,
"\n Number: \t%-2d \tStatus: \t%s\n",
drv_no, hrec);
- len += size; pos = begin + len;
flag = TRUE;
no_mdrv = pcdi->cd_ldcnt;
if (no_mdrv > 1 || pcdi->ld_slave != -1) {
@@ -436,61 +384,37 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
} else {
strcpy(hrec, "???");
}
- size = sprintf(buffer+len,
+ seq_printf(m,
" Capacity [MB]:\t%-6d \tType: \t%s\n",
pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
hrec);
- len += size; pos = begin + len;
} else {
- size = sprintf(buffer+len,
+ seq_printf(m,
" Slave Number: \t%-2d \tStatus: \t%s\n",
drv_no & 0x7fff, hrec);
- len += size; pos = begin + len;
}
drv_no = pcdi->ld_slave;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length) {
- gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- goto stop_output;
- }
} while (drv_no != -1);
- if (is_mirr) {
- size = sprintf(buffer+len,
+ if (is_mirr)
+ seq_printf(m,
" Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n",
no_mdrv - j - k, k);
- len += size; pos = begin + len;
- }
-
+
if (!ha->hdr[i].is_arraydrv)
strcpy(hrec, "--");
else
sprintf(hrec, "%d", ha->hdr[i].master_no);
- size = sprintf(buffer+len,
+ seq_printf(m,
" To Array Drv.:\t%s\n", hrec);
- len += size; pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length) {
- gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- goto stop_output;
- }
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- if (!flag) {
- size = sprintf(buffer+len, "\n --\n");
- len += size; pos = begin + len;
- }
+ if (!flag)
+ seq_printf(m, "\n --\n");
/* 4. about array drives */
- size = sprintf(buffer+len,"\nArray Drives:");
- len += size; pos = begin + len;
+ seq_printf(m,"\nArray Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -525,10 +449,9 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
strcat(hrec, "/expand");
else if (pai->ai_ext_state & 0x1)
strcat(hrec, "/patch");
- size = sprintf(buffer+len,
+ seq_printf(m,
"\n Number: \t%-2d \tStatus: \t%s\n",
i,hrec);
- len += size; pos = begin + len;
flag = TRUE;
if (pai->ai_type == 0)
@@ -539,31 +462,19 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
strcpy(hrec, "RAID-5");
else
strcpy(hrec, "RAID-10");
- size = sprintf(buffer+len,
+ seq_printf(m,
" Capacity [MB]:\t%-6d \tType: \t%s\n",
pai->ai_size/(1024*1024/pai->ai_secsize),
hrec);
- len += size; pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length) {
- gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- goto stop_output;
- }
}
}
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
- if (!flag) {
- size = sprintf(buffer+len, "\n --\n");
- len += size; pos = begin + len;
- }
+ if (!flag)
+ seq_printf(m, "\n --\n");
/* 5. about host drives */
- size = sprintf(buffer+len,"\nHost Drives:");
- len += size; pos = begin + len;
+ seq_printf(m,"\nHost Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
@@ -605,33 +516,22 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
if (!(ha->hdr[i].present))
continue;
- size = sprintf(buffer+len,
+ seq_printf(m,
"\n Number: \t%-2d \tArr/Log. Drive:\t%d\n",
i, ha->hdr[i].ldr_no);
- len += size; pos = begin + len;
flag = TRUE;
- size = sprintf(buffer+len,
+ seq_printf(m,
" Capacity [MB]:\t%-6d \tStart Sector: \t%d\n",
(u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
- len += size; pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
}
- if (!flag) {
- size = sprintf(buffer+len, "\n --\n");
- len += size; pos = begin + len;
- }
+ if (!flag)
+ seq_printf(m, "\n --\n");
}
/* controller events */
- size = sprintf(buffer+len,"\nController Events:\n");
- len += size; pos = begin + len;
+ seq_printf(m,"\nController Events:\n");
for (id = -1;;) {
id = gdth_read_event(ha, id, estr);
@@ -643,29 +543,14 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
do_gettimeofday(&tv);
sec = (int)(tv.tv_sec - estr->first_stamp);
if (sec < 0) sec = 0;
- size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
+ seq_printf(m," date- %02d:%02d:%02d\t%s\n",
sec/3600, sec%3600/60, sec%60, hrec);
- len += size; pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
}
if (id == -1)
break;
}
-
stop_output:
- *start = buffer +(offset-begin);
- len -= (offset-begin);
- if (len > length)
- len = length;
- TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
- len,(int)pos,(int)begin,(int)offset,length,size));
- rc = len;
-
+ rc = 0;
free_fail:
kfree(gdtcmd);
kfree(estr);
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index dab15f59f2cc..aaa618198972 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -8,11 +8,6 @@
int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info);
-static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- gdth_ha_str *ha);
-static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host, gdth_ha_str *ha);
-
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
int length, gdth_ha_str *ha);
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index dbe4cc6b9f8b..2203ac281103 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -191,7 +191,8 @@ static int gvp11_bus_reset(struct scsi_cmnd *cmd)
static struct scsi_host_template gvp11_scsi_template = {
.module = THIS_MODULE,
.name = "GVP Series II SCSI",
- .proc_info = wd33c93_proc_info,
+ .show_info = wd33c93_show_info,
+ .write_info = wd33c93_write_info,
.proc_name = "GVP11",
.queuecommand = wd33c93_queuecommand,
.eh_abort_handler = wd33c93_abort,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index a044f593e8b9..d0fa4b6c551f 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1899,8 +1899,8 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
sdev->allow_restart = 1;
blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
}
- scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
spin_unlock_irqrestore(shost->host_lock, lock_flags);
+ scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
return 0;
}
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 26cd9d1d7571..89a8266560d0 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -121,45 +121,26 @@ static inline void imm_pb_release(imm_struct *dev)
* testing...
* Also gives a method to use a script to obtain optimum timings (TODO)
*/
-static inline int imm_proc_write(imm_struct *dev, char *buffer, int length)
+static int imm_write_info(struct Scsi_Host *host, char *buffer, int length)
{
- unsigned long x;
+ imm_struct *dev = imm_dev(host);
if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
- x = simple_strtoul(buffer + 5, NULL, 0);
- dev->mode = x;
+ dev->mode = simple_strtoul(buffer + 5, NULL, 0);
return length;
}
printk("imm /proc: invalid variable\n");
- return (-EINVAL);
+ return -EINVAL;
}
-static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start,
- off_t offset, int length, int inout)
+static int imm_show_info(struct seq_file *m, struct Scsi_Host *host)
{
imm_struct *dev = imm_dev(host);
- int len = 0;
-
- if (inout)
- return imm_proc_write(dev, buffer, length);
-
- len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION);
- len +=
- sprintf(buffer + len, "Parport : %s\n",
- dev->dev->port->name);
- len +=
- sprintf(buffer + len, "Mode : %s\n",
- IMM_MODE_STRING[dev->mode]);
- /* Request for beyond end of buffer */
- if (offset > len)
- return 0;
-
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
- return len;
+ seq_printf(m, "Version : %s\n", IMM_VERSION);
+ seq_printf(m, "Parport : %s\n", dev->dev->port->name);
+ seq_printf(m, "Mode : %s\n", IMM_MODE_STRING[dev->mode]);
+ return 0;
}
#if IMM_DEBUG > 0
@@ -1118,7 +1099,8 @@ static int imm_adjust_queue(struct scsi_device *device)
static struct scsi_host_template imm_template = {
.module = THIS_MODULE,
.proc_name = "imm",
- .proc_info = imm_proc_info,
+ .show_info = imm_show_info,
+ .write_info = imm_write_info,
.name = "Iomega VPI2 (imm) interface",
.queuecommand = imm_queuecommand,
.eh_abort_handler = imm_abort,
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index deb5b6d8398e..bf028218ac36 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2166,152 +2166,117 @@ static int in2000_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
-static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
+static int in2000_write_info(struct Scsi_Host *instance, char *buf, int len)
{
#ifdef PROC_INTERFACE
char *bp;
- char tbuf[128];
- unsigned long flags;
struct IN2000_hostdata *hd;
- Scsi_Cmnd *cmd;
int x, i;
- static int stop = 0;
hd = (struct IN2000_hostdata *) instance->hostdata;
-/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
- * keywords (same format as command-line, but only ONE per read):
- * debug
- * disconnect
- * period
- * resync
- * proc
- */
-
- if (in) {
- buf[len] = '\0';
- bp = buf;
- if (!strncmp(bp, "debug:", 6)) {
- bp += 6;
- hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
- } else if (!strncmp(bp, "disconnect:", 11)) {
- bp += 11;
- x = simple_strtoul(bp, NULL, 0);
- if (x < DIS_NEVER || x > DIS_ALWAYS)
- x = DIS_ADAPTIVE;
- hd->disconnect = x;
- } else if (!strncmp(bp, "period:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
- hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns;
- } else if (!strncmp(bp, "resync:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
- for (i = 0; i < 7; i++)
- if (x & (1 << i))
- hd->sync_stat[i] = SS_UNSET;
- } else if (!strncmp(bp, "proc:", 5)) {
- bp += 5;
- hd->proc = simple_strtoul(bp, NULL, 0);
- } else if (!strncmp(bp, "level2:", 7)) {
- bp += 7;
- hd->level2 = simple_strtoul(bp, NULL, 0);
- }
- return len;
+ buf[len] = '\0';
+ bp = buf;
+ if (!strncmp(bp, "debug:", 6)) {
+ bp += 6;
+ hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
+ } else if (!strncmp(bp, "disconnect:", 11)) {
+ bp += 11;
+ x = simple_strtoul(bp, NULL, 0);
+ if (x < DIS_NEVER || x > DIS_ALWAYS)
+ x = DIS_ADAPTIVE;
+ hd->disconnect = x;
+ } else if (!strncmp(bp, "period:", 7)) {
+ bp += 7;
+ x = simple_strtoul(bp, NULL, 0);
+ hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns;
+ } else if (!strncmp(bp, "resync:", 7)) {
+ bp += 7;
+ x = simple_strtoul(bp, NULL, 0);
+ for (i = 0; i < 7; i++)
+ if (x & (1 << i))
+ hd->sync_stat[i] = SS_UNSET;
+ } else if (!strncmp(bp, "proc:", 5)) {
+ bp += 5;
+ hd->proc = simple_strtoul(bp, NULL, 0);
+ } else if (!strncmp(bp, "level2:", 7)) {
+ bp += 7;
+ hd->level2 = simple_strtoul(bp, NULL, 0);
}
+#endif
+ return len;
+}
+
+static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance)
+{
+
+#ifdef PROC_INTERFACE
+ unsigned long flags;
+ struct IN2000_hostdata *hd;
+ Scsi_Cmnd *cmd;
+ int x;
+
+ hd = (struct IN2000_hostdata *) instance->hostdata;
spin_lock_irqsave(instance->host_lock, flags);
- bp = buf;
- *bp = '\0';
- if (hd->proc & PR_VERSION) {
- sprintf(tbuf, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE);
- strcat(bp, tbuf);
- }
+ if (hd->proc & PR_VERSION)
+ seq_printf(m, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE);
+
if (hd->proc & PR_INFO) {
- sprintf(tbuf, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
- strcat(bp, tbuf);
- strcat(bp, "\nsync_xfer[] = ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\nsync_stat[] = ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
- strcat(bp, tbuf);
- }
+ seq_printf(m, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
+ seq_printf(m, "\nsync_xfer[] = ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%02x", hd->sync_xfer[x]);
+ seq_printf(m, "\nsync_stat[] = ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%02x", hd->sync_stat[x]);
}
#ifdef PROC_STATISTICS
if (hd->proc & PR_STATISTICS) {
- strcat(bp, "\ncommands issued: ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\ndisconnects allowed:");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\ndisconnects done: ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
- strcat(bp, tbuf);
- }
- sprintf(tbuf, "\ninterrupts: \t%ld", hd->int_cnt);
- strcat(bp, tbuf);
+ seq_printf(m, "\ncommands issued: ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
+ seq_printf(m, "\ndisconnects allowed:");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
+ seq_printf(m, "\ndisconnects done: ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
+ seq_printf(m, "\ninterrupts: \t%ld", hd->int_cnt);
}
#endif
if (hd->proc & PR_CONNECTED) {
- strcat(bp, "\nconnected: ");
+ seq_printf(m, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *) hd->connected;
- sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
+ seq_printf(m, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
}
}
if (hd->proc & PR_INPUTQ) {
- strcat(bp, "\ninput_Q: ");
+ seq_printf(m, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
- sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
+ seq_printf(m, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
}
if (hd->proc & PR_DISCQ) {
- strcat(bp, "\ndisconnected_Q:");
+ seq_printf(m, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
- sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
+ seq_printf(m, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
}
if (hd->proc & PR_TEST) {
; /* insert your own custom function here */
}
- strcat(bp, "\n");
+ seq_printf(m, "\n");
spin_unlock_irqrestore(instance->host_lock, flags);
- *start = buf;
- if (stop) {
- stop = 0;
- return 0; /* return 0 to signal end-of-file */
- }
- if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */
- stop = 1;
- if (hd->proc & PR_STOP) /* stop every other time */
- stop = 1;
- return strlen(bp);
-
-#else /* PROC_INTERFACE */
-
- return 0;
-
#endif /* PROC_INTERFACE */
-
+ return 0;
}
MODULE_LICENSE("GPL");
@@ -2319,7 +2284,8 @@ MODULE_LICENSE("GPL");
static struct scsi_host_template driver_template = {
.proc_name = "in2000",
- .proc_info = in2000_proc_info,
+ .write_info = in2000_write_info,
+ .show_info = in2000_show_info,
.name = "Always IN2000",
.detect = in2000_detect,
.release = in2000_release,
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f328089a1060..2197b57fb225 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -5148,7 +5148,7 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd)
ipr_trace;
}
- list_add_tail(&ipr_cmd->queue, &hrrq->hrrq_free_q);
+ list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
if (!ipr_is_naca_model(res))
res->needs_sync_complete = 1;
@@ -9349,7 +9349,10 @@ static int ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, struct pci_dev *pdev)
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
+ if (ioa_cfg->intr_flag == IPR_USE_MSIX)
+ rc = request_irq(ioa_cfg->vectors_info[0].vec, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
+ else
+ rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
if (rc) {
dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq);
return rc;
@@ -9371,7 +9374,10 @@ static int ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, struct pci_dev *pdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- free_irq(pdev->irq, ioa_cfg);
+ if (ioa_cfg->intr_flag == IPR_USE_MSIX)
+ free_irq(ioa_cfg->vectors_info[0].vec, ioa_cfg);
+ else
+ free_irq(pdev->irq, ioa_cfg);
LEAVE;
@@ -9722,6 +9728,7 @@ static void __ipr_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
flush_work(&ioa_cfg->work_q);
+ INIT_LIST_HEAD(&ioa_cfg->used_res_q);
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
spin_lock(&ipr_driver_lock);
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 9aa86a315a08..8d5ea8a1e5a6 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -326,10 +326,9 @@ static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
unsigned int count);
-static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
-static int ips_host_info(ips_ha_t *, char *, off_t, int);
-static void copy_mem_info(IPS_INFOSTR *, char *, int);
-static int copy_info(IPS_INFOSTR *, char *, ...);
+static int ips_write_info(struct Scsi_Host *, char *, int);
+static int ips_show_info(struct seq_file *, struct Scsi_Host *);
+static int ips_host_info(ips_ha_t *, struct seq_file *);
static int ips_abort_init(ips_ha_t * ha, int index);
static int ips_init_phase2(int index);
@@ -367,7 +366,8 @@ static struct scsi_host_template ips_driver_template = {
.eh_abort_handler = ips_eh_abort,
.eh_host_reset_handler = ips_eh_reset,
.proc_name = "ips",
- .proc_info = ips_proc_info,
+ .show_info = ips_show_info,
+ .write_info = ips_write_info,
.slave_configure = ips_slave_configure,
.bios_param = ips_biosparam,
.this_id = -1,
@@ -1433,25 +1433,12 @@ ips_info(struct Scsi_Host *SH)
return (bp);
}
-/****************************************************************************/
-/* */
-/* Routine Name: ips_proc_info */
-/* */
-/* Routine Description: */
-/* */
-/* The passthru interface for the driver */
-/* */
-/****************************************************************************/
static int
-ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int func)
+ips_write_info(struct Scsi_Host *host, char *buffer, int length)
{
int i;
- int ret;
ips_ha_t *ha = NULL;
- METHOD_TRACE("ips_proc_info", 1);
-
/* Find our host structure */
for (i = 0; i < ips_next_controller; i++) {
if (ips_sh[i]) {
@@ -1465,18 +1452,29 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
if (!ha)
return (-EINVAL);
- if (func) {
- /* write */
- return (0);
- } else {
- /* read */
- if (start)
- *start = buffer;
+ return 0;
+}
- ret = ips_host_info(ha, buffer, offset, length);
+static int
+ips_show_info(struct seq_file *m, struct Scsi_Host *host)
+{
+ int i;
+ ips_ha_t *ha = NULL;
- return (ret);
+ /* Find our host structure */
+ for (i = 0; i < ips_next_controller; i++) {
+ if (ips_sh[i]) {
+ if (ips_sh[i] == host) {
+ ha = (ips_ha_t *) ips_sh[i]->hostdata;
+ break;
+ }
+ }
}
+
+ if (!ha)
+ return (-EINVAL);
+
+ return ips_host_info(ha, m);
}
/*--------------------------------------------------------------------------*/
@@ -2035,183 +2033,113 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
/* */
/****************************************************************************/
static int
-ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
+ips_host_info(ips_ha_t *ha, struct seq_file *m)
{
- IPS_INFOSTR info;
-
METHOD_TRACE("ips_host_info", 1);
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
- info.localpos = 0;
-
- copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
+ seq_printf(m, "\nIBM ServeRAID General Information:\n\n");
if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
(le16_to_cpu(ha->nvram->adapter_type) != 0))
- copy_info(&info, "\tController Type : %s\n",
+ seq_printf(m, "\tController Type : %s\n",
ips_adapter_name[ha->ad_type - 1]);
else
- copy_info(&info,
+ seq_printf(m,
"\tController Type : Unknown\n");
if (ha->io_addr)
- copy_info(&info,
- "\tIO region : 0x%lx (%d bytes)\n",
+ seq_printf(m,
+ "\tIO region : 0x%x (%d bytes)\n",
ha->io_addr, ha->io_len);
if (ha->mem_addr) {
- copy_info(&info,
- "\tMemory region : 0x%lx (%d bytes)\n",
+ seq_printf(m,
+ "\tMemory region : 0x%x (%d bytes)\n",
ha->mem_addr, ha->mem_len);
- copy_info(&info,
+ seq_printf(m,
"\tShared memory address : 0x%lx\n",
- ha->mem_ptr);
+ (unsigned long)ha->mem_ptr);
}
- copy_info(&info, "\tIRQ number : %d\n", ha->pcidev->irq);
+ seq_printf(m, "\tIRQ number : %d\n", ha->pcidev->irq);
/* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
/* That keeps everything happy for "text" operations on the proc file. */
if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
if (ha->nvram->bios_low[3] == 0) {
- copy_info(&info,
- "\tBIOS Version : %c%c%c%c%c%c%c\n",
- ha->nvram->bios_high[0], ha->nvram->bios_high[1],
- ha->nvram->bios_high[2], ha->nvram->bios_high[3],
- ha->nvram->bios_low[0], ha->nvram->bios_low[1],
- ha->nvram->bios_low[2]);
+ seq_printf(m,
+ "\tBIOS Version : %c%c%c%c%c%c%c\n",
+ ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+ ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+ ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+ ha->nvram->bios_low[2]);
} else {
- copy_info(&info,
- "\tBIOS Version : %c%c%c%c%c%c%c%c\n",
- ha->nvram->bios_high[0], ha->nvram->bios_high[1],
- ha->nvram->bios_high[2], ha->nvram->bios_high[3],
- ha->nvram->bios_low[0], ha->nvram->bios_low[1],
- ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
+ seq_printf(m,
+ "\tBIOS Version : %c%c%c%c%c%c%c%c\n",
+ ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+ ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+ ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+ ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
}
}
if (ha->enq->CodeBlkVersion[7] == 0) {
- copy_info(&info,
- "\tFirmware Version : %c%c%c%c%c%c%c\n",
- ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
- ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
- ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
- ha->enq->CodeBlkVersion[6]);
+ seq_printf(m,
+ "\tFirmware Version : %c%c%c%c%c%c%c\n",
+ ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
+ ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
+ ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
+ ha->enq->CodeBlkVersion[6]);
} else {
- copy_info(&info,
- "\tFirmware Version : %c%c%c%c%c%c%c%c\n",
- ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
- ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
- ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
- ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
+ seq_printf(m,
+ "\tFirmware Version : %c%c%c%c%c%c%c%c\n",
+ ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
+ ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
+ ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
+ ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
}
if (ha->enq->BootBlkVersion[7] == 0) {
- copy_info(&info,
- "\tBoot Block Version : %c%c%c%c%c%c%c\n",
- ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
- ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
- ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
- ha->enq->BootBlkVersion[6]);
+ seq_printf(m,
+ "\tBoot Block Version : %c%c%c%c%c%c%c\n",
+ ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
+ ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
+ ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
+ ha->enq->BootBlkVersion[6]);
} else {
- copy_info(&info,
- "\tBoot Block Version : %c%c%c%c%c%c%c%c\n",
- ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
- ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
- ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
- ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
+ seq_printf(m,
+ "\tBoot Block Version : %c%c%c%c%c%c%c%c\n",
+ ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
+ ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
+ ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
+ ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
}
- copy_info(&info, "\tDriver Version : %s%s\n",
+ seq_printf(m, "\tDriver Version : %s%s\n",
IPS_VERSION_HIGH, IPS_VERSION_LOW);
- copy_info(&info, "\tDriver Build : %d\n",
+ seq_printf(m, "\tDriver Build : %d\n",
IPS_BUILD_IDENT);
- copy_info(&info, "\tMax Physical Devices : %d\n",
+ seq_printf(m, "\tMax Physical Devices : %d\n",
ha->enq->ucMaxPhysicalDevices);
- copy_info(&info, "\tMax Active Commands : %d\n",
+ seq_printf(m, "\tMax Active Commands : %d\n",
ha->max_cmds);
- copy_info(&info, "\tCurrent Queued Commands : %d\n",
+ seq_printf(m, "\tCurrent Queued Commands : %d\n",
ha->scb_waitlist.count);
- copy_info(&info, "\tCurrent Active Commands : %d\n",
+ seq_printf(m, "\tCurrent Active Commands : %d\n",
ha->scb_activelist.count - ha->num_ioctl);
- copy_info(&info, "\tCurrent Queued PT Commands : %d\n",
+ seq_printf(m, "\tCurrent Queued PT Commands : %d\n",
ha->copp_waitlist.count);
- copy_info(&info, "\tCurrent Active PT Commands : %d\n",
+ seq_printf(m, "\tCurrent Active PT Commands : %d\n",
ha->num_ioctl);
- copy_info(&info, "\n");
-
- return (info.localpos);
-}
-
-/****************************************************************************/
-/* */
-/* Routine Name: copy_mem_info */
-/* */
-/* Routine Description: */
-/* */
-/* Copy data into an IPS_INFOSTR structure */
-/* */
-/****************************************************************************/
-static void
-copy_mem_info(IPS_INFOSTR * info, char *data, int len)
-{
- METHOD_TRACE("copy_mem_info", 1);
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
-
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- info->pos += (info->offset - info->pos);
- }
-
- if (info->localpos + len > info->length)
- len = info->length - info->localpos;
+ seq_printf(m, "\n");
- if (len > 0) {
- memcpy(info->buffer + info->localpos, data, len);
- info->pos += len;
- info->localpos += len;
- }
-}
-
-/****************************************************************************/
-/* */
-/* Routine Name: copy_info */
-/* */
-/* Routine Description: */
-/* */
-/* printf style wrapper for an info structure */
-/* */
-/****************************************************************************/
-static int
-copy_info(IPS_INFOSTR * info, char *fmt, ...)
-{
- va_list args;
- char buf[128];
- int len;
-
- METHOD_TRACE("copy_info", 1);
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
-
- return (len);
+ return 0;
}
/****************************************************************************/
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index f2df0593332b..45b9566b928e 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -416,7 +416,6 @@
/*
* Scsi_Host Template
*/
- static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[]);
static int ips_slave_configure(struct scsi_device *SDptr);
@@ -959,14 +958,6 @@ typedef union {
IPS_ENH_SG_LIST *enh_list;
} IPS_SG_LIST;
-typedef struct _IPS_INFOSTR {
- char *buffer;
- int length;
- int offset;
- int pos;
- int localpos;
-} IPS_INFOSTR;
-
typedef struct {
char *option_name;
int *option_flag;
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 2839baa82a5a..d25d0d859f05 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -721,7 +721,7 @@ static void isci_pci_remove(struct pci_dev *pdev)
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int isci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -770,18 +770,16 @@ static int isci_resume(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume);
-#endif
static struct pci_driver isci_pci_driver = {
.name = DRV_NAME,
.id_table = isci_id_table,
.probe = isci_pci_probe,
.remove = isci_pci_remove,
-#ifdef CONFIG_PM
.driver.pm = &isci_pm_ops,
-#endif
};
static __init int isci_init(void)
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 1b91ca0dc1e3..9e2588a6881c 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -370,17 +370,24 @@ static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn)
static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
{
struct iscsi_conn *conn = task->conn;
- int rc;
+ unsigned long pflags = current->flags;
+ int rc = 0;
+
+ current->flags |= PF_MEMALLOC;
while (iscsi_sw_tcp_xmit_qlen(conn)) {
rc = iscsi_sw_tcp_xmit(conn);
- if (rc == 0)
- return -EAGAIN;
+ if (rc == 0) {
+ rc = -EAGAIN;
+ break;
+ }
if (rc < 0)
- return rc;
+ break;
+ rc = 0;
}
- return 0;
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
+ return rc;
}
/*
@@ -665,6 +672,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
sk->sk_reuse = SK_CAN_REUSE;
sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
sk->sk_allocation = GFP_ATOMIC;
+ sk_set_memalloc(sk);
iscsi_sw_tcp_conn_set_callbacks(conn);
tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage;
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 8e561e6a557c..880a9068ca12 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -712,12 +712,13 @@ static void fc_disc_stop_final(struct fc_lport *lport)
}
/**
- * fc_disc_init() - Initialize the discovery layer for a local port
- * @lport: The local port that needs the discovery layer to be initialized
+ * fc_disc_config() - Configure the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be configured
+ * @priv: Private data structre for users of the discovery layer
*/
-int fc_disc_init(struct fc_lport *lport)
+void fc_disc_config(struct fc_lport *lport, void *priv)
{
- struct fc_disc *disc;
+ struct fc_disc *disc = &lport->disc;
if (!lport->tt.disc_start)
lport->tt.disc_start = fc_disc_start;
@@ -732,12 +733,21 @@ int fc_disc_init(struct fc_lport *lport)
lport->tt.disc_recv_req = fc_disc_recv_req;
disc = &lport->disc;
+
+ disc->priv = priv;
+}
+EXPORT_SYMBOL(fc_disc_config);
+
+/**
+ * fc_disc_init() - Initialize the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be initialized
+ */
+void fc_disc_init(struct fc_lport *lport)
+{
+ struct fc_disc *disc = &lport->disc;
+
INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
mutex_init(&disc->disc_mutex);
INIT_LIST_HEAD(&disc->rports);
-
- disc->priv = lport;
-
- return 0;
}
EXPORT_SYMBOL(fc_disc_init);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 82c3fd4bc938..5de946984500 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -507,7 +507,6 @@ static void iscsi_free_task(struct iscsi_task *task)
kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
if (sc) {
- task->sc = NULL;
/* SCSI eh reuses commands to verify us */
sc->SCp.ptr = NULL;
/*
@@ -3142,7 +3141,7 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
-static int iscsi_switch_str_param(char **param, char *new_val_buf)
+int iscsi_switch_str_param(char **param, char *new_val_buf)
{
char *new_val;
@@ -3159,6 +3158,7 @@ static int iscsi_switch_str_param(char **param, char *new_val_buf)
*param = new_val;
return 0;
}
+EXPORT_SYMBOL_GPL(iscsi_switch_str_param);
int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf, int buflen)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 7af776737b40..f42b0e15410f 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -235,6 +235,17 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
linkrate = phy->linkrate;
memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+ /* Handle vacant phy - rest of dr data is not valid so skip it */
+ if (phy->phy_state == PHY_VACANT) {
+ memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ phy->attached_dev_type = NO_DEVICE;
+ if (!test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
+ phy->phy_id = phy_id;
+ goto skip;
+ } else
+ goto out;
+ }
+
phy->attached_dev_type = to_dev_type(dr);
if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))
goto out;
@@ -272,6 +283,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
phy->phy->maximum_linkrate = dr->pmax_linkrate;
phy->phy->negotiated_linkrate = phy->linkrate;
+ skip:
if (new_phy)
if (sas_phy_add(phy->phy)) {
sas_phy_free(phy->phy);
@@ -388,7 +400,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single)
if (!disc_req)
return -ENOMEM;
- disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
if (!disc_resp) {
kfree(disc_req);
return -ENOMEM;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index a364cae9e984..9290713af253 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -692,7 +692,7 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
*/
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- while (pring->txcmplq_cnt) {
+ while (!list_empty(&pring->txcmplq)) {
msleep(10);
if (cnt++ > 500) { /* 5 secs */
lpfc_printf_log(phba,
@@ -2302,11 +2302,17 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
"FCF Fast failover=1 Priority failover=2");
-int lpfc_enable_rrq;
+int lpfc_enable_rrq = 2;
module_param(lpfc_enable_rrq, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
lpfc_param_show(enable_rrq);
-lpfc_param_init(enable_rrq, 0, 0, 1);
+/*
+# lpfc_enable_rrq: Track XRI/OXID reuse after IO failures
+# 0x0 = disabled, XRI/OXID use not tracked.
+# 0x1 = XRI/OXID reuse is timed with ratov, RRQ sent.
+# 0x2 = XRI/OXID reuse is timed with ratov, No RRQ sent.
+*/
+lpfc_param_init(enable_rrq, 2, 0, 2);
static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL);
/*
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 32d5683e6181..888666892004 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -64,18 +64,14 @@ struct lpfc_bsg_event {
struct list_head events_to_get;
struct list_head events_to_see;
- /* job waiting for this event to finish */
- struct fc_bsg_job *set_job;
+ /* driver data associated with the job */
+ void *dd_data;
};
struct lpfc_bsg_iocb {
struct lpfc_iocbq *cmdiocbq;
- struct lpfc_iocbq *rspiocbq;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *rmp;
struct lpfc_nodelist *ndlp;
-
- /* job waiting for this iocb to finish */
- struct fc_bsg_job *set_job;
};
struct lpfc_bsg_mbox {
@@ -86,20 +82,13 @@ struct lpfc_bsg_mbox {
uint32_t mbOffset; /* from app */
uint32_t inExtWLen; /* from app */
uint32_t outExtWLen; /* from app */
-
- /* job waiting for this mbox command to finish */
- struct fc_bsg_job *set_job;
};
#define MENLO_DID 0x0000FC0E
struct lpfc_bsg_menlo {
struct lpfc_iocbq *cmdiocbq;
- struct lpfc_iocbq *rspiocbq;
- struct lpfc_dmabuf *bmp;
-
- /* job waiting for this iocb to finish */
- struct fc_bsg_job *set_job;
+ struct lpfc_dmabuf *rmp;
};
#define TYPE_EVT 1
@@ -108,6 +97,7 @@ struct lpfc_bsg_menlo {
#define TYPE_MENLO 4
struct bsg_job_data {
uint32_t type;
+ struct fc_bsg_job *set_job; /* job waiting for this iocb to finish */
union {
struct lpfc_bsg_event *evt;
struct lpfc_bsg_iocb iocb;
@@ -141,6 +131,138 @@ struct lpfc_dmabufext {
uint32_t flag;
};
+static void
+lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
+{
+ struct lpfc_dmabuf *mlast, *next_mlast;
+
+ if (mlist) {
+ list_for_each_entry_safe(mlast, next_mlast, &mlist->list,
+ list) {
+ lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
+ list_del(&mlast->list);
+ kfree(mlast);
+ }
+ lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
+ kfree(mlist);
+ }
+ return;
+}
+
+static struct lpfc_dmabuf *
+lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size,
+ int outbound_buffers, struct ulp_bde64 *bpl,
+ int *bpl_entries)
+{
+ struct lpfc_dmabuf *mlist = NULL;
+ struct lpfc_dmabuf *mp;
+ unsigned int bytes_left = size;
+
+ /* Verify we can support the size specified */
+ if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE)))
+ return NULL;
+
+ /* Determine the number of dma buffers to allocate */
+ *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 :
+ size/LPFC_BPL_SIZE);
+
+ /* Allocate dma buffer and place in BPL passed */
+ while (bytes_left) {
+ /* Allocate dma buffer */
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!mp) {
+ if (mlist)
+ lpfc_free_bsg_buffers(phba, mlist);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&mp->list);
+ mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
+
+ if (!mp->virt) {
+ kfree(mp);
+ if (mlist)
+ lpfc_free_bsg_buffers(phba, mlist);
+ return NULL;
+ }
+
+ /* Queue it to a linked list */
+ if (!mlist)
+ mlist = mp;
+ else
+ list_add_tail(&mp->list, &mlist->list);
+
+ /* Add buffer to buffer pointer list */
+ if (outbound_buffers)
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ else
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys));
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys));
+ bpl->tus.f.bdeSize = (uint16_t)
+ (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE :
+ bytes_left);
+ bytes_left -= bpl->tus.f.bdeSize;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ bpl++;
+ }
+ return mlist;
+}
+
+static unsigned int
+lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers,
+ struct fc_bsg_buffer *bsg_buffers,
+ unsigned int bytes_to_transfer, int to_buffers)
+{
+
+ struct lpfc_dmabuf *mp;
+ unsigned int transfer_bytes, bytes_copied = 0;
+ unsigned int sg_offset, dma_offset;
+ unsigned char *dma_address, *sg_address;
+ struct scatterlist *sgel;
+ LIST_HEAD(temp_list);
+
+
+ list_splice_init(&dma_buffers->list, &temp_list);
+ list_add(&dma_buffers->list, &temp_list);
+ sg_offset = 0;
+ sgel = bsg_buffers->sg_list;
+ list_for_each_entry(mp, &temp_list, list) {
+ dma_offset = 0;
+ while (bytes_to_transfer && sgel &&
+ (dma_offset < LPFC_BPL_SIZE)) {
+ dma_address = mp->virt + dma_offset;
+ if (sg_offset) {
+ /* Continue previous partial transfer of sg */
+ sg_address = sg_virt(sgel) + sg_offset;
+ transfer_bytes = sgel->length - sg_offset;
+ } else {
+ sg_address = sg_virt(sgel);
+ transfer_bytes = sgel->length;
+ }
+ if (bytes_to_transfer < transfer_bytes)
+ transfer_bytes = bytes_to_transfer;
+ if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset))
+ transfer_bytes = LPFC_BPL_SIZE - dma_offset;
+ if (to_buffers)
+ memcpy(dma_address, sg_address, transfer_bytes);
+ else
+ memcpy(sg_address, dma_address, transfer_bytes);
+ dma_offset += transfer_bytes;
+ sg_offset += transfer_bytes;
+ bytes_to_transfer -= transfer_bytes;
+ bytes_copied += transfer_bytes;
+ if (sg_offset >= sgel->length) {
+ sg_offset = 0;
+ sgel = sg_next(sgel);
+ }
+ }
+ }
+ list_del_init(&dma_buffers->list);
+ list_splice(&temp_list, &dma_buffers->list);
+ return bytes_copied;
+}
+
/**
* lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler
* @phba: Pointer to HBA context object.
@@ -166,62 +288,72 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp, *rmp;
struct lpfc_nodelist *ndlp;
struct lpfc_bsg_iocb *iocb;
unsigned long flags;
+ unsigned int rsp_size;
int rc = 0;
+ dd_data = cmdiocbq->context1;
+
+ /* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context2;
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- lpfc_sli_release_iocbq(phba, cmdiocbq);
- return;
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
iocb = &dd_data->context_un.iocb;
- job = iocb->set_job;
- job->dd_data = NULL; /* so timeout handler does not reply */
-
- bmp = iocb->bmp;
+ ndlp = iocb->ndlp;
+ rmp = iocb->rmp;
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
rsp = &rspiocbq->iocb;
- ndlp = cmdiocbq->context1;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Copy the completed data or set the error status */
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ rsp_size = rsp->un.genreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ lpfc_bsg_copy_data(rmp, &job->reply_payload,
+ rsp_size, 0);
+ }
+ }
+ lpfc_free_bsg_buffers(phba, cmp);
+ lpfc_free_bsg_buffers(phba, rmp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ kfree(bmp);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
- kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -240,12 +372,9 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
uint32_t timeout;
struct lpfc_iocbq *cmdiocbq = NULL;
IOCB_t *cmd;
- struct lpfc_dmabuf *bmp = NULL;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
int request_nseg;
int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
uint32_t creg_val;
int rc = 0;
@@ -268,54 +397,50 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
goto no_ndlp;
}
- bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!bmp) {
- rc = -ENOMEM;
- goto free_ndlp;
- }
-
if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
rc = -ENODEV;
- goto free_bmp;
+ goto free_ndlp;
}
cmdiocbq = lpfc_sli_get_iocbq(phba);
if (!cmdiocbq) {
rc = -ENOMEM;
- goto free_bmp;
+ goto free_ndlp;
}
cmd = &cmdiocbq->iocb;
+
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!bmp) {
+ rc = -ENOMEM;
+ goto free_cmdiocbq;
+ }
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
- goto free_cmdiocbq;
+ goto free_bmp;
}
INIT_LIST_HEAD(&bmp->list);
+
bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &request_nseg);
+ if (!cmp) {
+ rc = -ENOMEM;
+ goto free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl += request_nseg;
+ reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
+ rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
+ bpl, &reply_nseg);
+ if (!rmp) {
+ rc = -ENOMEM;
+ goto free_cmp;
}
cmd->un.genreq64.bdl.ulpIoTag32 = 0;
@@ -343,17 +468,20 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
cmd->ulpTimeout = timeout;
cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
- cmdiocbq->context1 = ndlp;
- cmdiocbq->context2 = dd_data;
+ cmdiocbq->context1 = dd_data;
+ cmdiocbq->context2 = cmp;
+ cmdiocbq->context3 = bmp;
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = bmp;
+ dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = rmp;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
rc = -EIO ;
- goto free_cmdiocbq;
+ goto free_rmp;
}
creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
writel(creg_val, phba->HCregaddr);
@@ -368,19 +496,18 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
else
rc = -EIO;
-
/* iocb failed so cleanup */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-
-free_cmdiocbq:
- lpfc_sli_release_iocbq(phba, cmdiocbq);
+free_rmp:
+ lpfc_free_bsg_buffers(phba, rmp);
+free_cmp:
+ lpfc_free_bsg_buffers(phba, cmp);
free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
+free_cmdiocbq:
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
free_ndlp:
lpfc_nlp_put(ndlp);
no_ndlp:
@@ -418,67 +545,68 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
struct fc_bsg_job *job;
IOCB_t *rsp;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *pbuflist = NULL;
+ struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL;
struct fc_bsg_ctels_reply *els_reply;
uint8_t *rjt_data;
unsigned long flags;
+ unsigned int rsp_size;
int rc = 0;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = cmdiocbq->context1;
- /* normal completion and timeout crossed paths, already done */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
+ ndlp = dd_data->context_un.iocb.ndlp;
+ cmdiocbq->context1 = ndlp;
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = dd_data->context_un.iocb.set_job;
- cmdiocbq = dd_data->context_un.iocb.cmdiocbq;
- rspiocbq = dd_data->context_un.iocb.rspiocbq;
rsp = &rspiocbq->iocb;
- ndlp = dd_data->context_un.iocb.ndlp;
+ pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
+ prsp = (struct lpfc_dmabuf *)pcmd->list.next;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Copy the completed job data or determine the job status if job is
+ * still active
+ */
- if (job->reply->result == -EAGAIN)
- rc = -EAGAIN;
- else if (rsp->ulpStatus == IOSTAT_SUCCESS)
- job->reply->reply_payload_rcv_len =
- rsp->un.elsreq64.bdl.bdeSize;
- else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
- job->reply->reply_payload_rcv_len =
- sizeof(struct fc_bsg_ctels_reply);
- /* LS_RJT data returned in word 4 */
- rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
- els_reply = &job->reply->reply_data.ctels_reply;
- els_reply->status = FC_CTELS_STATUS_REJECT;
- els_reply->rjt_data.action = rjt_data[3];
- els_reply->rjt_data.reason_code = rjt_data[2];
- els_reply->rjt_data.reason_explanation = rjt_data[1];
- els_reply->rjt_data.vendor_unique = rjt_data[0];
- } else
- rc = -EIO;
+ if (job) {
+ if (rsp->ulpStatus == IOSTAT_SUCCESS) {
+ rsp_size = rsp->un.elsreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ prsp->virt,
+ rsp_size);
+ } else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
+ job->reply->reply_payload_rcv_len =
+ sizeof(struct fc_bsg_ctels_reply);
+ /* LS_RJT data returned in word 4 */
+ rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
+ els_reply = &job->reply->reply_data.ctels_reply;
+ els_reply->status = FC_CTELS_STATUS_REJECT;
+ els_reply->rjt_data.action = rjt_data[3];
+ els_reply->rjt_data.reason_code = rjt_data[2];
+ els_reply->rjt_data.reason_explanation = rjt_data[1];
+ els_reply->rjt_data.vendor_unique = rjt_data[0];
+ } else {
+ rc = -EIO;
+ }
+ }
- pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
- lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
- lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
+ lpfc_els_free_iocb(phba, cmdiocbq);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- job->dd_data = NULL;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -496,19 +624,8 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
uint32_t elscmd;
uint32_t cmdsize;
uint32_t rspsize;
- struct lpfc_iocbq *rspiocbq;
struct lpfc_iocbq *cmdiocbq;
- IOCB_t *rsp;
uint16_t rpi = 0;
- struct lpfc_dmabuf *pcmd;
- struct lpfc_dmabuf *prsp;
- struct lpfc_dmabuf *pbuflist = NULL;
- struct ulp_bde64 *bpl;
- int request_nseg;
- int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
uint32_t creg_val;
int rc = 0;
@@ -516,6 +633,15 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
+ /* verify the els command is not greater than the
+ * maximum ELS transfer size.
+ */
+
+ if (job->request_payload.payload_len > FCELSSIZE) {
+ rc = -EINVAL;
+ goto no_dd_data;
+ }
+
/* allocate our bsg tracking structure */
dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
if (!dd_data) {
@@ -525,88 +651,51 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
goto no_dd_data;
}
- if (!lpfc_nlp_get(ndlp)) {
- rc = -ENODEV;
- goto free_dd_data;
- }
-
elscmd = job->request->rqst_data.r_els.els_code;
cmdsize = job->request_payload.payload_len;
rspsize = job->reply_payload.payload_len;
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- lpfc_nlp_put(ndlp);
- rc = -ENOMEM;
+
+ if (!lpfc_nlp_get(ndlp)) {
+ rc = -ENODEV;
goto free_dd_data;
}
- rsp = &rspiocbq->iocb;
- rpi = ndlp->nlp_rpi;
+ /* We will use the allocated dma buffers by prep els iocb for command
+ * and response to ensure if the job times out and the request is freed,
+ * we won't be dma into memory that is no longer allocated to for the
+ * request.
+ */
cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp,
ndlp->nlp_DID, elscmd);
if (!cmdiocbq) {
rc = -EIO;
- goto free_rspiocbq;
+ goto release_ndlp;
}
- /* prep els iocb set context1 to the ndlp, context2 to the command
- * dmabuf, context3 holds the data dmabuf
- */
- pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2;
- prsp = (struct lpfc_dmabuf *) pcmd->list.next;
- lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
- kfree(pcmd);
- lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
- kfree(prsp);
- cmdiocbq->context2 = NULL;
-
- pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
- bpl = (struct ulp_bde64 *) pbuflist->virt;
-
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
- }
+ rpi = ndlp->nlp_rpi;
+
+ /* Transfer the request payload to allocated command dma buffer */
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt,
+ cmdsize);
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
- }
- cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
- (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
if (phba->sli_rev == LPFC_SLI_REV4)
cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi];
else
cmdiocbq->iocb.ulpContext = rpi;
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
- cmdiocbq->context1 = NULL;
- cmdiocbq->context2 = NULL;
-
- cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
cmdiocbq->context1 = dd_data;
cmdiocbq->context_un.ndlp = ndlp;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.rspiocbq = rspiocbq;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = NULL;
dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = NULL;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
@@ -617,8 +706,9 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
writel(creg_val, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
+
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
- lpfc_nlp_put(ndlp);
+
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
else if (rc == IOCB_BUSY)
@@ -627,17 +717,12 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
rc = -EIO;
linkdown_err:
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
-
- lpfc_sli_release_iocbq(phba, cmdiocbq);
+ cmdiocbq->context1 = ndlp;
+ lpfc_els_free_iocb(phba, cmdiocbq);
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
+release_ndlp:
+ lpfc_nlp_put(ndlp);
free_dd_data:
kfree(dd_data);
@@ -680,6 +765,7 @@ lpfc_bsg_event_free(struct kref *kref)
kfree(ed);
}
+ kfree(evt->dd_data);
kfree(evt);
}
@@ -723,6 +809,7 @@ lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id)
evt->req_id = ev_req_id;
evt->reg_id = ev_reg_id;
evt->wait_time_stamp = jiffies;
+ evt->dd_data = NULL;
init_waitqueue_head(&evt->wq);
kref_init(&evt->kref);
return evt;
@@ -790,6 +877,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_hbq_entry *hbqe;
struct lpfc_sli_ct_request *ct_req;
struct fc_bsg_job *job = NULL;
+ struct bsg_job_data *dd_data = NULL;
unsigned long flags;
int size = 0;
@@ -986,10 +1074,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
list_move(evt->events_to_see.prev, &evt->events_to_get);
- lpfc_bsg_event_unref(evt);
- job = evt->set_job;
- evt->set_job = NULL;
+ dd_data = (struct bsg_job_data *)evt->dd_data;
+ job = dd_data->set_job;
+ dd_data->set_job = NULL;
+ lpfc_bsg_event_unref(evt);
if (job) {
job->reply->reply_payload_rcv_len = size;
/* make error code available to userspace */
@@ -1078,14 +1167,6 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
goto job_error;
}
- dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
- if (dd_data == NULL) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
- "2734 Failed allocation of dd_data\n");
- rc = -ENOMEM;
- goto job_error;
- }
-
event_req = (struct set_ct_event *)
job->request->rqst_data.h_vendor.vendor_cmd;
ev_mask = ((uint32_t)(unsigned long)event_req->type_mask &
@@ -1095,6 +1176,7 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
if (evt->reg_id == event_req->ev_reg_id) {
lpfc_bsg_event_ref(evt);
evt->wait_time_stamp = jiffies;
+ dd_data = (struct bsg_job_data *)evt->dd_data;
break;
}
}
@@ -1102,6 +1184,13 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
if (&evt->node == &phba->ct_ev_waiters) {
/* no event waiting struct yet - first call */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (dd_data == NULL) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2734 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto job_error;
+ }
evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id,
event_req->ev_req_id);
if (!evt) {
@@ -1111,7 +1200,10 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
rc = -ENOMEM;
goto job_error;
}
-
+ dd_data->type = TYPE_EVT;
+ dd_data->set_job = NULL;
+ dd_data->context_un.evt = evt;
+ evt->dd_data = (void *)dd_data;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_add(&evt->node, &phba->ct_ev_waiters);
lpfc_bsg_event_ref(evt);
@@ -1121,9 +1213,7 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
spin_lock_irqsave(&phba->ct_ev_lock, flags);
evt->waiting = 1;
- dd_data->type = TYPE_EVT;
- dd_data->context_un.evt = evt;
- evt->set_job = job; /* for unsolicited command */
+ dd_data->set_job = job; /* for unsolicited command */
job->dd_data = dd_data; /* for fc transport timeout callback*/
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
return 0; /* call job done later */
@@ -1252,57 +1342,64 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp;
struct lpfc_nodelist *ndlp;
unsigned long flags;
int rc = 0;
+ dd_data = cmdiocbq->context1;
+
+ /* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context2;
- /* normal completion and timeout crossed paths, already done */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = dd_data->context_un.iocb.set_job;
- bmp = dd_data->context_un.iocb.bmp;
- rsp = &rspiocbq->iocb;
ndlp = dd_data->context_un.iocb.ndlp;
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
+ rsp = &rspiocbq->iocb;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ /* Copy the completed job data or set the error status */
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ job->reply->reply_payload_rcv_len = 0;
+ }
+ }
+ lpfc_free_bsg_buffers(phba, cmp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ kfree(bmp);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
- kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- job->dd_data = NULL;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -1316,7 +1413,8 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
**/
static int
lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
- struct lpfc_dmabuf *bmp, int num_entry)
+ struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp,
+ int num_entry)
{
IOCB_t *icmd;
struct lpfc_iocbq *ctiocb = NULL;
@@ -1377,7 +1475,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
/* Check if the ndlp is active */
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
- rc = -IOCB_ERROR;
+ rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
@@ -1385,7 +1483,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
* we respond
*/
if (!lpfc_nlp_get(ndlp)) {
- rc = -IOCB_ERROR;
+ rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
@@ -1407,17 +1505,17 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
ctiocb->iocb_cmpl = NULL;
ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
ctiocb->vport = phba->pport;
+ ctiocb->context1 = dd_data;
+ ctiocb->context2 = cmp;
ctiocb->context3 = bmp;
-
ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
- ctiocb->context2 = dd_data;
- ctiocb->context1 = ndlp;
+
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = ctiocb;
- dd_data->context_un.iocb.rspiocbq = NULL;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = bmp;
dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = NULL;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
@@ -1454,11 +1552,8 @@ lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job)
struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *)
job->request->rqst_data.h_vendor.vendor_cmd;
struct ulp_bde64 *bpl;
- struct lpfc_dmabuf *bmp = NULL;
- struct scatterlist *sgel = NULL;
- int request_nseg;
- int numbde;
- dma_addr_t busaddr;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL;
+ int bpl_entries;
uint32_t tag = mgmt_resp->tag;
unsigned long reqbfrcnt =
(unsigned long)job->request_payload.payload_len;
@@ -1486,30 +1581,28 @@ lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job)
INIT_LIST_HEAD(&bmp->list);
bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64));
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &bpl_entries);
+ if (!cmp) {
+ rc = -ENOMEM;
+ goto send_mgmt_rsp_free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg);
+ rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
- /* TBD need to handle a timeout */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
rc = -EACCES;
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+
+ lpfc_free_bsg_buffers(phba, cmp);
send_mgmt_rsp_free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
send_mgmt_rsp_exit:
/* make error code available to userspace */
@@ -1559,7 +1652,7 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
scsi_block_requests(shost);
}
- while (pring->txcmplq_cnt) {
+ while (!list_empty(&pring->txcmplq)) {
if (i++ > 500) /* wait up to 5 seconds */
break;
msleep(10);
@@ -3193,13 +3286,7 @@ lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
unsigned long flags;
uint8_t *pmb, *pmb_buf;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = pmboxq->context1;
- /* job already timed out? */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
/*
* The outgoing buffer is readily referred from the dma buffer,
@@ -3209,29 +3296,33 @@ lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
- job = dd_data->context_un.mbox.set_job;
+ /* Determine if job has been aborted */
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Copy the mailbox data to the job if it is still active */
+
if (job) {
size = job->reply_payload.payload_len;
job->reply->reply_payload_rcv_len =
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
pmb_buf, size);
- /* need to hold the lock until we set job->dd_data to NULL
- * to hold off the timeout handler returning to the mid-layer
- * while we are still processing the job.
- */
- job->dd_data = NULL;
- dd_data->context_un.mbox.set_job = NULL;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- } else {
- dd_data->context_un.mbox.set_job = NULL;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
}
+ dd_data->set_job = NULL;
mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers);
kfree(dd_data);
+ /* Complete the job if the job is still active */
+
if (job) {
job->reply->result = 0;
job->job_done(job);
@@ -3377,19 +3468,22 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
struct lpfc_sli_config_mbox *sli_cfg_mbx;
uint8_t *pmbx;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = pmboxq->context1;
- /* has the job already timed out? */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = NULL;
- goto job_done_out;
+
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
/*
* The outgoing buffer is readily referred from the dma buffer,
* just need to get header part from mailboxq structure.
*/
+
pmb = (uint8_t *)&pmboxq->u.mb;
pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
/* Copy the byte swapped response mailbox back to the user */
@@ -3406,21 +3500,18 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len);
}
- job = dd_data->context_un.mbox.set_job;
+ /* Complete the job if the job is still active */
+
if (job) {
size = job->reply_payload.payload_len;
job->reply->reply_payload_rcv_len =
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
pmb_buf, size);
+
/* result for successful */
job->reply->result = 0;
- job->dd_data = NULL;
- /* need to hold the lock util we set job->dd_data to NULL
- * to hold off the timeout handler from midlayer to take
- * any action.
- */
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2937 SLI_CONFIG ext-buffer maibox command "
"(x%x/x%x) complete bsg job done, bsize:%d\n",
@@ -3431,20 +3522,18 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
phba->mbox_ext_buf_ctx.mboxType,
dma_ebuf, sta_pos_addr,
phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);
- } else
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-
-job_done_out:
- if (!job)
+ } else {
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2938 SLI_CONFIG ext-buffer maibox "
"command (x%x/x%x) failure, rc:x%x\n",
phba->mbox_ext_buf_ctx.nembType,
phba->mbox_ext_buf_ctx.mboxType, rc);
+ }
+
+
/* state change */
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE;
kfree(dd_data);
-
return job;
}
@@ -3461,8 +3550,10 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
struct fc_bsg_job *job;
+ job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
+
/* handle the BSG job with mailbox command */
- if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+ if (!job)
pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3470,15 +3561,13 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
"complete, ctxState:x%x, mbxStatus:x%x\n",
phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
- job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
-
if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1)
lpfc_bsg_mbox_ext_session_reset(phba);
/* free base driver mailbox structure memory */
mempool_free(pmboxq, phba->mbox_mem_pool);
- /* complete the bsg job if we have it */
+ /* if the job is still active, call job done */
if (job)
job->job_done(job);
@@ -3498,8 +3587,10 @@ lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
struct fc_bsg_job *job;
+ job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
+
/* handle the BSG job with the mailbox command */
- if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+ if (!job)
pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3507,13 +3598,11 @@ lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
"complete, ctxState:x%x, mbxStatus:x%x\n",
phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
- job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
-
/* free all memory, including dma buffers */
mempool_free(pmboxq, phba->mbox_mem_pool);
lpfc_bsg_mbox_ext_session_reset(phba);
- /* complete the bsg job if we have it */
+ /* if the job is still active, call job done */
if (job)
job->job_done(job);
@@ -3759,9 +3848,9 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
@@ -3928,14 +4017,14 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
- phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
+ phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3951,6 +4040,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
}
/* wait for additoinal external buffers */
+
job->reply->result = 0;
job->job_done(job);
return SLI_CONFIG_HANDLED;
@@ -4268,9 +4358,9 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
@@ -4455,7 +4545,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
uint8_t *from;
uint32_t size;
-
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
@@ -4681,9 +4770,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* setup context field to pass wait_queue pointer to wake function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
- dd_data->context_un.mbox.set_job = job;
dd_data->context_un.mbox.ext = ext;
dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
@@ -4741,7 +4830,7 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) {
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
- "2737 Mix-and-match backward compability "
+ "2737 Mix-and-match backward compatibility "
"between MBOX_REQ old size:%d and "
"new request size:%d\n",
(int)(job->request_len -
@@ -4797,75 +4886,79 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp, *rmp;
struct lpfc_bsg_menlo *menlo;
unsigned long flags;
struct menlo_response *menlo_resp;
+ unsigned int rsp_size;
int rc = 0;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = cmdiocbq->context1;
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
-
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
menlo = &dd_data->context_un.menlo;
- job = menlo->set_job;
- job->dd_data = NULL; /* so timeout handler does not reply */
-
- spin_lock(&phba->hbalock);
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
- spin_unlock(&phba->hbalock);
-
- bmp = menlo->bmp;
- rspiocbq = menlo->rspiocbq;
+ rmp = menlo->rmp;
rsp = &rspiocbq->iocb;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Copy the job data or set the failing status for the job */
- /* always return the xri, this would be used in the case
- * of a menlo download to allow the data to be sent as a continuation
- * of the exchange.
- */
- menlo_resp = (struct menlo_response *)
- job->reply->reply_data.vendor_reply.vendor_rsp;
- menlo_resp->xri = rsp->ulpContext;
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ /* always return the xri, this would be used in the case
+ * of a menlo download to allow the data to be sent as a
+ * continuation of the exchange.
+ */
+
+ menlo_resp = (struct menlo_response *)
+ job->reply->reply_data.vendor_reply.vendor_rsp;
+ menlo_resp->xri = rsp->ulpContext;
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ rsp_size = rsp->un.genreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ lpfc_bsg_copy_data(rmp, &job->reply_payload,
+ rsp_size, 0);
+ }
+
+ }
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
lpfc_sli_release_iocbq(phba, cmdiocbq);
+ lpfc_free_bsg_buffers(phba, cmp);
+ lpfc_free_bsg_buffers(phba, rmp);
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
+
return;
}
@@ -4883,17 +4976,14 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_iocbq *cmdiocbq, *rspiocbq;
- IOCB_t *cmd, *rsp;
+ struct lpfc_iocbq *cmdiocbq;
+ IOCB_t *cmd;
int rc = 0;
struct menlo_command *menlo_cmd;
struct menlo_response *menlo_resp;
- struct lpfc_dmabuf *bmp = NULL;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
int request_nseg;
int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
struct ulp_bde64 *bpl = NULL;
@@ -4948,50 +5038,38 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
goto free_dd;
}
- cmdiocbq = lpfc_sli_get_iocbq(phba);
- if (!cmdiocbq) {
+ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+ if (!bmp->virt) {
rc = -ENOMEM;
goto free_bmp;
}
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- rc = -ENOMEM;
- goto free_cmdiocbq;
- }
-
- rsp = &rspiocbq->iocb;
+ INIT_LIST_HEAD(&bmp->list);
- bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
- if (!bmp->virt) {
+ bpl = (struct ulp_bde64 *)bmp->virt;
+ request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &request_nseg);
+ if (!cmp) {
rc = -ENOMEM;
- goto free_rspiocbq;
+ goto free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- INIT_LIST_HEAD(&bmp->list);
- bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl += request_nseg;
+ reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
+ rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
+ bpl, &reply_nseg);
+ if (!rmp) {
+ rc = -ENOMEM;
+ goto free_cmp;
}
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ if (!cmdiocbq) {
+ rc = -ENOMEM;
+ goto free_rmp;
}
cmd = &cmdiocbq->iocb;
@@ -5013,11 +5091,10 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
cmdiocbq->vport = phba->pport;
/* We want the firmware to timeout before we do */
cmd->ulpTimeout = MENLO_TIMEOUT - 5;
- cmdiocbq->context3 = bmp;
- cmdiocbq->context2 = rspiocbq;
cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp;
cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->context2 = cmp;
+ cmdiocbq->context3 = bmp;
if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) {
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->ulpPU = MENLO_PU; /* 3 */
@@ -5031,29 +5108,25 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
}
dd_data->type = TYPE_MENLO;
+ dd_data->set_job = job;
dd_data->context_un.menlo.cmdiocbq = cmdiocbq;
- dd_data->context_un.menlo.rspiocbq = rspiocbq;
- dd_data->context_un.menlo.set_job = job;
- dd_data->context_un.menlo.bmp = bmp;
+ dd_data->context_un.menlo.rmp = rmp;
+ job->dd_data = dd_data;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
MENLO_TIMEOUT - 5);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
- /* iocb failed so cleanup */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
-free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
+
+free_rmp:
+ lpfc_free_bsg_buffers(phba, rmp);
+free_cmp:
+ lpfc_free_bsg_buffers(phba, cmp);
free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
free_dd:
kfree(dd_data);
@@ -5162,70 +5235,94 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
- struct lpfc_bsg_event *evt;
- struct lpfc_bsg_iocb *iocb;
- struct lpfc_bsg_mbox *mbox;
- struct lpfc_bsg_menlo *menlo;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct bsg_job_data *dd_data;
unsigned long flags;
+ int rc = 0;
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *check_iocb, *next_iocb;
+
+ /* if job's driver data is NULL, the command completed or is in the
+ * the process of completing. In this case, return status to request
+ * so the timeout is retried. This avoids double completion issues
+ * and the request will be pulled off the timer queue when the
+ * command's completion handler executes. Otherwise, prevent the
+ * command's completion handler from executing the job done callback
+ * and continue processing to abort the outstanding the command.
+ */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = (struct bsg_job_data *)job->dd_data;
- /* timeout and completion crossed paths if no dd_data */
- if (!dd_data) {
+ if (dd_data) {
+ dd_data->set_job = NULL;
+ job->dd_data = NULL;
+ } else {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return 0;
+ return -EAGAIN;
}
switch (dd_data->type) {
case TYPE_IOCB:
- iocb = &dd_data->context_un.iocb;
- cmdiocb = iocb->cmdiocbq;
- /* hint to completion handler that the job timed out */
- job->reply->result = -EAGAIN;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- /* this will call our completion handler */
+ /* Check to see if IOCB was issued to the port or not. If not,
+ * remove it from the txq queue and call cancel iocbs.
+ * Otherwise, call abort iotag
+ */
+
+ cmdiocb = dd_data->context_un.iocb.cmdiocbq;
spin_lock_irq(&phba->hbalock);
- lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+ list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
+ list) {
+ if (check_iocb == cmdiocb) {
+ list_move_tail(&check_iocb->list, &completions);
+ break;
+ }
+ }
+ if (list_empty(&completions))
+ lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ if (!list_empty(&completions)) {
+ lpfc_sli_cancel_iocbs(phba, &completions,
+ IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+ }
break;
+
case TYPE_EVT:
- evt = dd_data->context_un.evt;
- /* this event has no job anymore */
- evt->set_job = NULL;
- job->dd_data = NULL;
- job->reply->reply_payload_rcv_len = 0;
- /* Return -EAGAIN which is our way of signallying the
- * app to retry.
- */
- job->reply->result = -EAGAIN;
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job->job_done(job);
break;
+
case TYPE_MBOX:
- mbox = &dd_data->context_un.mbox;
- /* this mbox has no job anymore */
- mbox->set_job = NULL;
- job->dd_data = NULL;
- job->reply->reply_payload_rcv_len = 0;
- job->reply->result = -EAGAIN;
- /* the mbox completion handler can now be run */
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job->job_done(job);
+ /* Update the ext buf ctx state if needed */
+
if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
break;
case TYPE_MENLO:
- menlo = &dd_data->context_un.menlo;
- cmdiocb = menlo->cmdiocbq;
- /* hint to completion handler that the job timed out */
- job->reply->result = -EAGAIN;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- /* this will call our completion handler */
+ /* Check to see if IOCB was issued to the port or not. If not,
+ * remove it from the txq queue and call cancel iocbs.
+ * Otherwise, call abort iotag.
+ */
+
+ cmdiocb = dd_data->context_un.menlo.cmdiocbq;
spin_lock_irq(&phba->hbalock);
- lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+ list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
+ list) {
+ if (check_iocb == cmdiocb) {
+ list_move_tail(&check_iocb->list, &completions);
+ break;
+ }
+ }
+ if (list_empty(&completions))
+ lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ if (!list_empty(&completions)) {
+ lpfc_sli_cancel_iocbs(phba, &completions,
+ IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+ }
break;
default:
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
@@ -5236,5 +5333,5 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
* otherwise an error message will be displayed on the console
* so always return success (zero)
*/
- return 0;
+ return rc;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 76ca65dae781..7631893ae005 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -106,6 +106,7 @@ void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_cleanup(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
+int lpfc_unregister_fcf_prep(struct lpfc_hba *);
struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
void lpfc_worker_wake_up(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 08d156a9094f..bbed8471bf0b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -484,6 +484,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
vport->port_state = LPFC_FABRIC_CFG_LINK;
memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
mboxq->context1 = dmabuf;
@@ -700,6 +701,20 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
}
+ /*
+ * For FC we need to do some special processing because of the SLI
+ * Port's default settings of the Common Service Parameters.
+ */
+ if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+ lpfc_unregister_fcf_prep(phba);
+
+ /* This should just update the VFI CSPs*/
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_issue_reg_vfi(vport);
+ }
+
if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
@@ -6225,7 +6240,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
spin_unlock_irq(&phba->hbalock);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ if (!list_empty(&phba->sli.ring[LPFC_ELS_RING].txcmplq))
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
}
@@ -6279,7 +6294,6 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
continue;
list_move_tail(&piocb->list, &completions);
- pring->txq_cnt--;
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -6339,7 +6353,6 @@ lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
cmd->ulpCommand == CMD_ABORT_XRI_CN)
continue;
list_move_tail(&piocb->list, &completions);
- pring->txq_cnt--;
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
if (piocb->iocb_flag & LPFC_IO_LIBDFC)
@@ -8065,7 +8078,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
rxid, 1);
/* Check if TXQ queue needs to be serviced */
- if (pring->txq_cnt)
+ if (!(list_empty(&pring->txq)))
lpfc_worker_wake_up(phba);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index d7096ad94d3f..326e05a65a73 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -691,12 +691,15 @@ lpfc_work_done(struct lpfc_hba *phba)
/* Set the lpfc data pending flag */
set_bit(LPFC_DATA_READY, &phba->data_flags);
} else {
- pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
- lpfc_sli_handle_slow_ring_event(phba, pring,
- (status &
- HA_RXMASK));
+ if (phba->link_state >= LPFC_LINK_UP) {
+ pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+ lpfc_sli_handle_slow_ring_event(phba, pring,
+ (status &
+ HA_RXMASK));
+ }
}
- if ((phba->sli_rev == LPFC_SLI_REV4) && pring->txq_cnt)
+ if ((phba->sli_rev == LPFC_SLI_REV4) &
+ (!list_empty(&pring->txq)))
lpfc_drain_txq(phba);
/*
* Turn on Ring interrupts
@@ -1732,7 +1735,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* use through a sequence of @fcf_cnt eligible FCF records with equal
* probability. To perform integer manunipulation of random numbers with
* size unit32_t, the lower 16 bits of the 32-bit random number returned
- * from random32() are taken as the random random number generated.
+ * from prandom_u32() are taken as the random random number generated.
*
* Returns true when outcome is for the newly read FCF record should be
* chosen; otherwise, return false when outcome is for keeping the previously
@@ -1744,7 +1747,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
uint32_t rand_num;
/* Get 16-bit uniform random number */
- rand_num = (0xFFFF & random32());
+ rand_num = 0xFFFF & prandom_u32();
/* Decision with probability 1/fcf_cnt */
if ((fcf_cnt * rand_num) < 0xFFFF)
@@ -1792,6 +1795,8 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
virt_addr = mboxq->sge_array->addr[0];
shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
+ lpfc_sli_pcimem_bcopy(shdr, shdr,
+ sizeof(union lpfc_sli4_cfg_shdr));
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (shdr_status || shdr_add_status) {
@@ -2380,7 +2385,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.eligible_fcf_cnt = 1;
/* Seeding the random number generator for random selection */
seed = (uint32_t)(0xFFFFFFFF & jiffies);
- srandom32(seed);
+ prandom_seed(seed);
}
spin_unlock_irq(&phba->hbalock);
goto read_next_fcf;
@@ -2888,6 +2893,11 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
goto out_free_mem;
}
+
+ /* If the VFI is already registered, there is nothing else to do */
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ goto out_free_mem;
+
/* The VPI is implicitly registered when the VFI is registered */
spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
@@ -2980,6 +2990,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
struct lpfc_dmabuf *mp;
int rc;
struct fcf_record *fcf_record;
+ uint32_t fc_flags = 0;
spin_lock_irq(&phba->hbalock);
switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
@@ -3011,11 +3022,8 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
"1309 Link Up Event npiv not supported in loop "
"topology\n");
/* Get Loop Map information */
- if (bf_get(lpfc_mbx_read_top_il, la)) {
- spin_lock(shost->host_lock);
- vport->fc_flag |= FC_LBIT;
- spin_unlock(shost->host_lock);
- }
+ if (bf_get(lpfc_mbx_read_top_il, la))
+ fc_flags |= FC_LBIT;
vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
i = la->lilpBde64.tus.f.bdeSize;
@@ -3064,12 +3072,16 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
}
vport->fc_myDID = phba->fc_pref_DID;
- spin_lock(shost->host_lock);
- vport->fc_flag |= FC_LBIT;
- spin_unlock(shost->host_lock);
+ fc_flags |= FC_LBIT;
}
spin_unlock_irq(&phba->hbalock);
+ if (fc_flags) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= fc_flags;
+ spin_unlock_irq(shost->host_lock);
+ }
+
lpfc_linkup(phba);
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!sparam_mbox)
@@ -3237,8 +3249,7 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
vport->fc_flag &= ~FC_BYPASSED_MODE;
spin_unlock_irq(shost->host_lock);
- if ((phba->fc_eventTag < la->eventTag) ||
- (phba->fc_eventTag == la->eventTag)) {
+ if (phba->fc_eventTag <= la->eventTag) {
phba->fc_stat.LinkMultiEvent++;
if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)
if (phba->fc_eventTag != 0)
@@ -3246,16 +3257,18 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
phba->fc_eventTag = la->eventTag;
- spin_lock_irq(&phba->hbalock);
- if (bf_get(lpfc_mbx_read_top_mm, la))
- phba->sli.sli_flag |= LPFC_MENLO_MAINT;
- else
- phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
- spin_unlock_irq(&phba->hbalock);
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ spin_lock_irq(&phba->hbalock);
+ if (bf_get(lpfc_mbx_read_top_mm, la))
+ phba->sli.sli_flag |= LPFC_MENLO_MAINT;
+ else
+ phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
+ spin_unlock_irq(&phba->hbalock);
+ }
phba->link_events++;
if ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) &&
- (!bf_get(lpfc_mbx_read_top_mm, la))) {
+ !(phba->sli.sli_flag & LPFC_MENLO_MAINT)) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -3300,8 +3313,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
bf_get(lpfc_mbx_read_top_fa, la));
lpfc_mbx_issue_link_down(phba);
}
- if ((bf_get(lpfc_mbx_read_top_mm, la)) &&
- (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)) {
+ if ((phba->sli.sli_flag & LPFC_MENLO_MAINT) &&
+ ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP))) {
if (phba->link_state != LPFC_LINK_DOWN) {
phba->fc_stat.LinkDown++;
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -3329,8 +3342,9 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
}
- if (bf_get(lpfc_mbx_read_top_fa, la)) {
- if (bf_get(lpfc_mbx_read_top_mm, la))
+ if ((phba->sli_rev < LPFC_SLI_REV4) &&
+ bf_get(lpfc_mbx_read_top_fa, la)) {
+ if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
lpfc_issue_clear_la(phba, vport);
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"1311 fa %d\n",
@@ -4354,7 +4368,6 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
with an error */
list_move_tail(&iocb->list,
&completions);
- pring->txq_cnt--;
}
}
spin_unlock_irq(&phba->hbalock);
@@ -5055,7 +5068,6 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
(icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 6e93b886cd4d..1dd2f6f0a127 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1958,6 +1958,9 @@ struct lpfc_mbx_init_vfi {
struct lpfc_mbx_reg_vfi {
uint32_t word1;
+#define lpfc_reg_vfi_upd_SHIFT 29
+#define lpfc_reg_vfi_upd_MASK 0x00000001
+#define lpfc_reg_vfi_upd_WORD word1
#define lpfc_reg_vfi_vp_SHIFT 28
#define lpfc_reg_vfi_vp_MASK 0x00000001
#define lpfc_reg_vfi_vp_WORD word1
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 314b4f61b9e3..90b8b0515e23 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -839,7 +839,6 @@ lpfc_hba_down_post_s3(struct lpfc_hba *phba)
* way, nothing should be on txcmplq as it will NEVER complete.
*/
list_splice_init(&pring->txcmplq, &completions);
- pring->txcmplq_cnt = 0;
spin_unlock_irq(&phba->hbalock);
/* Cancel all the IOCBs from the completions list */
@@ -2915,9 +2914,9 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
sglq_entry->state = SGL_FREED;
list_add_tail(&sglq_entry->list, &els_sgl_list);
}
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
} else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) {
/* els xri-sgl shrinked */
xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt;
@@ -3015,9 +3014,9 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
psb->cur_iocbq.sli4_lxritag = lxri;
psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
}
- spin_lock(&phba->scsi_buf_list_lock);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list);
- spin_unlock(&phba->scsi_buf_list_lock);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
return 0;
@@ -4004,6 +4003,52 @@ lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_perform_inuse_fcf_recovery - Perform inuse fcf recovery
+ * @vport: pointer to lpfc hba data structure.
+ *
+ * This routine is to perform FCF recovery when the in-use FCF either dead or
+ * got modified.
+ **/
+static void
+lpfc_sli4_perform_inuse_fcf_recovery(struct lpfc_hba *phba,
+ struct lpfc_acqe_fip *acqe_fip)
+{
+ int rc;
+
+ spin_lock_irq(&phba->hbalock);
+ /* Mark the fast failover process in progress */
+ phba->fcf.fcf_flag |= FCF_DEAD_DISC;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+ "2771 Start FCF fast failover process due to in-use "
+ "FCF DEAD/MODIFIED event: evt_tag:x%x, index:x%x\n",
+ acqe_fip->event_tag, acqe_fip->index);
+ rc = lpfc_sli4_redisc_fcf_table(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
+ "2772 Issue FCF rediscover mabilbox command "
+ "failed, fail through to FCF dead event\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+ spin_unlock_irq(&phba->hbalock);
+ /*
+ * Last resort will fail over by treating this as a link
+ * down to FCF registration.
+ */
+ lpfc_sli4_fcf_dead_failthrough(phba);
+ } else {
+ /* Reset FCF roundrobin bmask for new discovery */
+ lpfc_sli4_clear_fcf_rr_bmask(phba);
+ /*
+ * Handling fast FCF failover to a DEAD FCF event is
+ * considered equalivant to receiving CVL to all vports.
+ */
+ lpfc_sli4_perform_all_vport_cvl(phba);
+ }
+}
+
+/**
* lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async fcoe completion queue entry.
@@ -4068,9 +4113,22 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
break;
}
- /* If the FCF has been in discovered state, do nothing. */
- if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
+ /* If FCF has been in discovered state, perform rediscovery
+ * only if the FCF with the same index of the in-use FCF got
+ * modified during normal operation. Otherwise, do nothing.
+ */
+ if (phba->pport->port_state > LPFC_FLOGI) {
spin_unlock_irq(&phba->hbalock);
+ if (phba->fcf.current_rec.fcf_indx ==
+ acqe_fip->index) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+ "3300 In-use FCF (%d) "
+ "modified, perform FCF "
+ "rediscovery\n",
+ acqe_fip->index);
+ lpfc_sli4_perform_inuse_fcf_recovery(phba,
+ acqe_fip);
+ }
break;
}
spin_unlock_irq(&phba->hbalock);
@@ -4123,39 +4181,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
* is no longer valid as we are not in the middle of FCF
* failover process already.
*/
- spin_lock_irq(&phba->hbalock);
- /* Mark the fast failover process in progress */
- phba->fcf.fcf_flag |= FCF_DEAD_DISC;
- spin_unlock_irq(&phba->hbalock);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
- "2771 Start FCF fast failover process due to "
- "FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
- "\n", acqe_fip->event_tag, acqe_fip->index);
- rc = lpfc_sli4_redisc_fcf_table(phba);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
- LOG_DISCOVERY,
- "2772 Issue FCF rediscover mabilbox "
- "command failed, fail through to FCF "
- "dead event\n");
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
- spin_unlock_irq(&phba->hbalock);
- /*
- * Last resort will fail over by treating this
- * as a link down to FCF registration.
- */
- lpfc_sli4_fcf_dead_failthrough(phba);
- } else {
- /* Reset FCF roundrobin bmask for new discovery */
- lpfc_sli4_clear_fcf_rr_bmask(phba);
- /*
- * Handling fast FCF failover to a DEAD FCF event is
- * considered equalivant to receiving CVL to all vports.
- */
- lpfc_sli4_perform_all_vport_cvl(phba);
- }
+ lpfc_sli4_perform_inuse_fcf_recovery(phba, acqe_fip);
break;
case LPFC_FIP_EVENT_TYPE_CVL:
phba->fcoe_cvl_eventtag = acqe_fip->event_tag;
@@ -10368,36 +10394,6 @@ lpfc_io_resume(struct pci_dev *pdev)
return;
}
-/**
- * lpfc_mgmt_open - method called when 'lpfcmgmt' is opened from userspace
- * @inode: pointer to the inode representing the lpfcmgmt device
- * @filep: pointer to the file representing the open lpfcmgmt device
- *
- * This routine puts a reference count on the lpfc module whenever the
- * character device is opened
- **/
-static int
-lpfc_mgmt_open(struct inode *inode, struct file *filep)
-{
- try_module_get(THIS_MODULE);
- return 0;
-}
-
-/**
- * lpfc_mgmt_release - method called when 'lpfcmgmt' is closed in userspace
- * @inode: pointer to the inode representing the lpfcmgmt device
- * @filep: pointer to the file representing the open lpfcmgmt device
- *
- * This routine removes a reference count from the lpfc module when the
- * character device is closed
- **/
-static int
-lpfc_mgmt_release(struct inode *inode, struct file *filep)
-{
- module_put(THIS_MODULE);
- return 0;
-}
-
static struct pci_device_id lpfc_id_table[] = {
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
PCI_ANY_ID, PCI_ANY_ID, },
@@ -10515,8 +10511,7 @@ static struct pci_driver lpfc_driver = {
};
static const struct file_operations lpfc_mgmt_fop = {
- .open = lpfc_mgmt_open,
- .release = lpfc_mgmt_release,
+ .owner = THIS_MODULE,
};
static struct miscdevice lpfc_mgmt_dev = {
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index efc9cd9def8b..a7a9fa468308 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2126,32 +2126,40 @@ void
lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
{
struct lpfc_mbx_reg_vfi *reg_vfi;
+ struct lpfc_hba *phba = vport->phba;
memset(mbox, 0, sizeof(*mbox));
reg_vfi = &mbox->u.mqe.un.reg_vfi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI);
bf_set(lpfc_reg_vfi_vp, reg_vfi, 1);
bf_set(lpfc_reg_vfi_vfi, reg_vfi,
- vport->phba->sli4_hba.vfi_ids[vport->vfi]);
- bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
- bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->phba->vpi_ids[vport->vpi]);
+ phba->sli4_hba.vfi_ids[vport->vfi]);
+ bf_set(lpfc_reg_vfi_fcfi, reg_vfi, phba->fcf.fcfi);
+ bf_set(lpfc_reg_vfi_vpi, reg_vfi, phba->vpi_ids[vport->vpi]);
memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
- reg_vfi->e_d_tov = vport->phba->fc_edtov;
- reg_vfi->r_a_tov = vport->phba->fc_ratov;
+ reg_vfi->e_d_tov = phba->fc_edtov;
+ reg_vfi->r_a_tov = phba->fc_ratov;
reg_vfi->bde.addrHigh = putPaddrHigh(phys);
reg_vfi->bde.addrLow = putPaddrLow(phys);
reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
+
+ /* Only FC supports upd bit */
+ if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
+ (vport->fc_flag & FC_VFI_REGISTERED)) {
+ bf_set(lpfc_reg_vfi_vp, reg_vfi, 0);
+ bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
+ }
lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX,
"3134 Register VFI, mydid:x%x, fcfi:%d, "
" vfi:%d, vpi:%d, fc_pname:%x%x\n",
vport->fc_myDID,
- vport->phba->fcf.fcfi,
- vport->phba->sli4_hba.vfi_ids[vport->vfi],
- vport->phba->vpi_ids[vport->vpi],
+ phba->fcf.fcfi,
+ phba->sli4_hba.vfi_ids[vport->vfi],
+ phba->vpi_ids[vport->vpi],
reg_vfi->wwn[0], reg_vfi->wwn[1]);
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 46128c679202..82f4d3542289 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -226,7 +226,6 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
/* It matches, so deque and call compl with anp error */
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 98af07c6e300..74b8710e1e90 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -732,7 +732,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
psb->exch_busy = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
- if (pring->txq_cnt)
+ if (!list_empty(&pring->txq))
lpfc_worker_wake_up(phba);
return;
@@ -885,9 +885,9 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
int num_posted, rc = 0;
/* get all SCSI buffers need to repost to a local list */
- spin_lock(&phba->scsi_buf_list_lock);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist);
- spin_unlock(&phba->scsi_buf_list_lock);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
/* post the list of scsi buffer sgls to port if available */
if (!list_empty(&post_sblist)) {
@@ -4246,7 +4246,7 @@ static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba)
unsigned long poll_tmo_expires =
(jiffies + msecs_to_jiffies(phba->cfg_poll_tmo));
- if (phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt)
+ if (!list_empty(&phba->sli.ring[LPFC_FCP_RING].txcmplq))
mod_timer(&phba->fcp_poll_timer,
poll_tmo_expires);
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 74b67d98e952..35dd17eb0f27 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -438,11 +438,12 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
struct lpfc_rqe *temp_hrqe;
struct lpfc_rqe *temp_drqe;
struct lpfc_register doorbell;
- int put_index = hq->host_index;
+ int put_index;
/* sanity check on queue memory */
if (unlikely(!hq) || unlikely(!dq))
return -ENOMEM;
+ put_index = hq->host_index;
temp_hrqe = hq->qe[hq->host_index].rqe;
temp_drqe = dq->qe[dq->host_index].rqe;
@@ -872,14 +873,16 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
xritag, rxid, ndlp->nlp_DID, send_rrq);
return -EINVAL;
}
- rrq->send_rrq = send_rrq;
+ if (phba->cfg_enable_rrq == 1)
+ rrq->send_rrq = send_rrq;
+ else
+ rrq->send_rrq = 0;
rrq->xritag = xritag;
rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
rrq->ndlp = ndlp;
rrq->nlp_DID = ndlp->nlp_DID;
rrq->vport = ndlp->vport;
rrq->rxid = rxid;
- rrq->send_rrq = send_rrq;
spin_lock_irqsave(&phba->hbalock, iflags);
empty = list_empty(&phba->active_rrq_list);
list_add_tail(&rrq->list, &phba->active_rrq_list);
@@ -1008,6 +1011,18 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
else
sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag);
+ /*
+ ** This should have been removed from the txcmplq before calling
+ ** iocbq_release. The normal completion
+ ** path should have already done the list_del_init.
+ */
+ if (unlikely(!list_empty(&iocbq->list))) {
+ if (iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)
+ iocbq->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+ list_del_init(&iocbq->list);
+ }
+
+
if (sglq) {
if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) &&
(sglq->state != SGL_XRI_ABORTED)) {
@@ -1024,7 +1039,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
&phba->sli4_hba.lpfc_sgl_list);
/* Check if TXQ queue needs to be serviced */
- if (pring->txq_cnt)
+ if (!list_empty(&pring->txq))
lpfc_worker_wake_up(phba);
}
}
@@ -1056,6 +1071,14 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
/*
+ ** This should have been removed from the txcmplq before calling
+ ** iocbq_release. The normal completion
+ ** path should have already done the list_del_init.
+ */
+ if (unlikely(!list_empty(&iocbq->list)))
+ list_del_init(&iocbq->list);
+
+ /*
* Clean all volatile data fields, preserve iotag and node struct.
*/
memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
@@ -1121,7 +1144,6 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist,
while (!list_empty(iocblist)) {
list_remove_head(iocblist, piocb, struct lpfc_iocbq, list);
-
if (!piocb->iocb_cmpl)
lpfc_sli_release_iocbq(phba, piocb);
else {
@@ -1309,9 +1331,6 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
list_add_tail(&piocb->list, &pring->txcmplq);
piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
- pring->txcmplq_cnt++;
- if (pring->txcmplq_cnt > pring->txcmplq_max)
- pring->txcmplq_max = pring->txcmplq_cnt;
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
@@ -1343,8 +1362,6 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
struct lpfc_iocbq *cmd_iocb;
list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
- if (cmd_iocb != NULL)
- pring->txq_cnt--;
return cmd_iocb;
}
@@ -1613,8 +1630,9 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* (c) link attention events can be processed (fcp ring only)
* (d) IOCB processing is not blocked by the outstanding mbox command.
*/
- if (pring->txq_cnt &&
- lpfc_is_link_up(phba) &&
+
+ if (lpfc_is_link_up(phba) &&
+ (!list_empty(&pring->txq)) &&
(pring->ringno != phba->sli.fcp_ring ||
phba->sli.sli_flag & LPFC_PROCESS_LA)) {
@@ -2611,7 +2629,6 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
- pring->txcmplq_cnt--;
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
}
return cmd_iocb;
@@ -2649,7 +2666,6 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
/* remove from txcmpl queue list */
list_del_init(&cmd_iocb->list);
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
- pring->txcmplq_cnt--;
return cmd_iocb;
}
}
@@ -3498,7 +3514,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
*/
spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txq, &completions);
- pring->txq_cnt = 0;
/* Next issue ABTS for everything on the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
@@ -3535,11 +3550,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
/* Retrieve everything on txq */
list_splice_init(&pring->txq, &txq);
- pring->txq_cnt = 0;
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
- pring->txcmplq_cnt = 0;
/* Indicate the I/O queues are flushed */
phba->hba_flag |= HBA_FCP_IOQ_FLUSH;
@@ -5987,9 +6000,9 @@ lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
LIST_HEAD(post_sgl_list);
LIST_HEAD(free_sgl_list);
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
list_for_each_entry_safe(sglq_entry, sglq_entry_next,
&allc_sgl_list, list) {
@@ -6090,10 +6103,10 @@ lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
/* push els sgls posted to the availble list */
if (!list_empty(&post_sgl_list)) {
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&post_sgl_list,
&phba->sli4_hba.lpfc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3161 Failure to post els sgl to port.\n");
@@ -7614,7 +7627,6 @@ __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
- pring->txq_cnt++;
}
/**
@@ -8386,7 +8398,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
- if (pring->txq_cnt) {
+ if (!list_empty(&pring->txq)) {
if (!(flag & SLI_IOCB_RET_IOCB)) {
__lpfc_sli_ringtx_put(phba,
pring, piocb);
@@ -9054,7 +9066,6 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
if (iocb->vport != vport)
continue;
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
/* Next issue ABTS for everything on the txcmplq */
@@ -9123,8 +9134,6 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
* given to the FW yet.
*/
list_splice_init(&pring->txq, &completions);
- pring->txq_cnt = 0;
-
}
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -9965,6 +9974,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
+ struct lpfc_iocbq *iocb;
+ int txq_cnt = 0;
+ int txcmplq_cnt = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
/*
* If the caller has provided a response iocbq buffer, then context2
@@ -10012,9 +10024,17 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
retval = IOCB_TIMEDOUT;
}
} else if (retval == IOCB_BUSY) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
- phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+ if (phba->cfg_log_verbose & LOG_SLI) {
+ list_for_each_entry(iocb, &pring->txq, list) {
+ txq_cnt++;
+ }
+ list_for_each_entry(iocb, &pring->txcmplq, list) {
+ txcmplq_cnt++;
+ }
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+ phba->iocb_cnt, txq_cnt, txcmplq_cnt);
+ }
return retval;
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -11297,16 +11317,25 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
struct lpfc_sli_ring *pring = cq->pring;
+ int txq_cnt = 0;
+ int txcmplq_cnt = 0;
+ int fcp_txcmplq_cnt = 0;
/* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
+ if (!list_empty(&pring->txq))
+ txq_cnt++;
+ if (!list_empty(&pring->txcmplq))
+ txcmplq_cnt++;
+ if (!list_empty(&phba->sli.ring[LPFC_FCP_RING].txcmplq))
+ fcp_txcmplq_cnt++;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
"fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
- pring->txq_cnt, phba->iocb_cnt,
- phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
- phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
+ txq_cnt, phba->iocb_cnt,
+ fcp_txcmplq_cnt,
+ txcmplq_cnt);
return false;
}
@@ -15481,11 +15510,18 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
LPFC_SLI4_FCF_TBL_INDX_MAX);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"3060 Last IDX %d\n", last_index);
- if (list_empty(&phba->fcf.fcf_pri_list)) {
+
+ /* Verify the priority list has 2 or more entries */
+ spin_lock_irq(&phba->hbalock);
+ if (list_empty(&phba->fcf.fcf_pri_list) ||
+ list_is_singular(&phba->fcf.fcf_pri_list)) {
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
"3061 Last IDX %d\n", last_index);
return 0; /* Empty rr list */
}
+ spin_unlock_irq(&phba->hbalock);
+
next_fcf_pri = 0;
/*
* Clear the rr_bmask and set all of the bits that are at this
@@ -16244,14 +16280,19 @@ lpfc_drain_txq(struct lpfc_hba *phba)
char *fail_msg = NULL;
struct lpfc_sglq *sglq;
union lpfc_wqe wqe;
+ int txq_cnt = 0;
spin_lock_irqsave(&phba->hbalock, iflags);
- if (pring->txq_cnt > pring->txq_max)
- pring->txq_max = pring->txq_cnt;
+ list_for_each_entry(piocbq, &pring->txq, list) {
+ txq_cnt++;
+ }
+
+ if (txq_cnt > pring->txq_max)
+ pring->txq_max = txq_cnt;
spin_unlock_irqrestore(&phba->hbalock, iflags);
- while (pring->txq_cnt) {
+ while (!list_empty(&pring->txq)) {
spin_lock_irqsave(&phba->hbalock, iflags);
piocbq = lpfc_sli_ringtx_get(phba, pring);
@@ -16259,7 +16300,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
spin_unlock_irqrestore(&phba->hbalock, iflags);
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2823 txq empty and txq_cnt is %d\n ",
- pring->txq_cnt);
+ txq_cnt);
break;
}
sglq = __lpfc_sli_get_sglq(phba, piocbq);
@@ -16268,6 +16309,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
spin_unlock_irqrestore(&phba->hbalock, iflags);
break;
}
+ txq_cnt--;
/* The xri and iocb resources secured,
* attempt to issue request
@@ -16299,5 +16341,5 @@ lpfc_drain_txq(struct lpfc_hba *phba)
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
- return pring->txq_cnt;
+ return txq_cnt;
}
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index f3b7795a296b..664cd04f7cd8 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.37"
+#define LPFC_DRIVER_VERSION "8.3.38"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 24828b54773a..858075723c87 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -561,7 +561,8 @@ static int macscsi_pwrite (struct Scsi_Host *instance,
static struct scsi_host_template driver_template = {
.proc_name = "Mac5380",
- .proc_info = macscsi_proc_info,
+ .show_info = macscsi_show_info,
+ .write_info = macscsi_write_info,
.name = "Macintosh NCR5380 SCSI",
.detect = macscsi_detect,
.release = macscsi_release,
diff --git a/drivers/scsi/mac_scsi.h b/drivers/scsi/mac_scsi.h
index d26e331c6c12..7dc62fce1c4c 100644
--- a/drivers/scsi/mac_scsi.h
+++ b/drivers/scsi/mac_scsi.h
@@ -72,7 +72,8 @@
#define NCR5380_queue_command macscsi_queue_command
#define NCR5380_abort macscsi_abort
#define NCR5380_bus_reset macscsi_bus_reset
-#define NCR5380_proc_info macscsi_proc_info
+#define NCR5380_show_info macscsi_show_info
+#define NCR5380_write_info macscsi_write_info
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 9504ec0ec682..846f475f62c1 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -39,6 +39,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <linux/module.h>
#include <linux/list.h>
@@ -2069,385 +2070,201 @@ mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
#ifdef CONFIG_PROC_FS
/* Following code handles /proc fs */
-#define CREATE_READ_PROC(string, func) create_proc_read_entry(string, \
- S_IRUSR | S_IFREG, \
- controller_proc_dir_entry, \
- func, adapter)
-
-/**
- * mega_create_proc_entry()
- * @index - index in soft state array
- * @parent - parent node for this /proc entry
- *
- * Creates /proc entries for our controllers.
- */
-static void
-mega_create_proc_entry(int index, struct proc_dir_entry *parent)
-{
- struct proc_dir_entry *controller_proc_dir_entry = NULL;
- u8 string[64] = { 0 };
- adapter_t *adapter = hba_soft_state[index];
-
- sprintf(string, "hba%d", adapter->host->host_no);
-
- controller_proc_dir_entry =
- adapter->controller_proc_dir_entry = proc_mkdir(string, parent);
-
- if(!controller_proc_dir_entry) {
- printk(KERN_WARNING "\nmegaraid: proc_mkdir failed\n");
- return;
- }
- adapter->proc_read = CREATE_READ_PROC("config", proc_read_config);
- adapter->proc_stat = CREATE_READ_PROC("stat", proc_read_stat);
- adapter->proc_mbox = CREATE_READ_PROC("mailbox", proc_read_mbox);
-#if MEGA_HAVE_ENH_PROC
- adapter->proc_rr = CREATE_READ_PROC("rebuild-rate", proc_rebuild_rate);
- adapter->proc_battery = CREATE_READ_PROC("battery-status",
- proc_battery);
-
- /*
- * Display each physical drive on its channel
- */
- adapter->proc_pdrvstat[0] = CREATE_READ_PROC("diskdrives-ch0",
- proc_pdrv_ch0);
- adapter->proc_pdrvstat[1] = CREATE_READ_PROC("diskdrives-ch1",
- proc_pdrv_ch1);
- adapter->proc_pdrvstat[2] = CREATE_READ_PROC("diskdrives-ch2",
- proc_pdrv_ch2);
- adapter->proc_pdrvstat[3] = CREATE_READ_PROC("diskdrives-ch3",
- proc_pdrv_ch3);
-
- /*
- * Display a set of up to 10 logical drive through each of following
- * /proc entries
- */
- adapter->proc_rdrvstat[0] = CREATE_READ_PROC("raiddrives-0-9",
- proc_rdrv_10);
- adapter->proc_rdrvstat[1] = CREATE_READ_PROC("raiddrives-10-19",
- proc_rdrv_20);
- adapter->proc_rdrvstat[2] = CREATE_READ_PROC("raiddrives-20-29",
- proc_rdrv_30);
- adapter->proc_rdrvstat[3] = CREATE_READ_PROC("raiddrives-30-39",
- proc_rdrv_40);
-#endif
-}
-
-
/**
- * proc_read_config()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_config()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
* Display configuration information about the controller.
*/
static int
-proc_read_config(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_config(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
- int len = 0;
-
- len += sprintf(page+len, "%s", MEGARAID_VERSION);
+ adapter_t *adapter = m->private;
+ seq_puts(m, MEGARAID_VERSION);
if(adapter->product_info.product_name[0])
- len += sprintf(page+len, "%s\n",
- adapter->product_info.product_name);
-
- len += sprintf(page+len, "Controller Type: ");
+ seq_printf(m, "%s\n", adapter->product_info.product_name);
- if( adapter->flag & BOARD_MEMMAP ) {
- len += sprintf(page+len,
- "438/466/467/471/493/518/520/531/532\n");
- }
- else {
- len += sprintf(page+len,
- "418/428/434\n");
- }
+ seq_puts(m, "Controller Type: ");
- if(adapter->flag & BOARD_40LD) {
- len += sprintf(page+len,
- "Controller Supports 40 Logical Drives\n");
- }
+ if( adapter->flag & BOARD_MEMMAP )
+ seq_puts(m, "438/466/467/471/493/518/520/531/532\n");
+ else
+ seq_puts(m, "418/428/434\n");
- if(adapter->flag & BOARD_64BIT) {
- len += sprintf(page+len,
- "Controller capable of 64-bit memory addressing\n");
- }
- if( adapter->has_64bit_addr ) {
- len += sprintf(page+len,
- "Controller using 64-bit memory addressing\n");
- }
- else {
- len += sprintf(page+len,
- "Controller is not using 64-bit memory addressing\n");
- }
+ if(adapter->flag & BOARD_40LD)
+ seq_puts(m, "Controller Supports 40 Logical Drives\n");
- len += sprintf(page+len, "Base = %08lx, Irq = %d, ", adapter->base,
- adapter->host->irq);
-
- len += sprintf(page+len, "Logical Drives = %d, Channels = %d\n",
- adapter->numldrv, adapter->product_info.nchannels);
-
- len += sprintf(page+len, "Version =%s:%s, DRAM = %dMb\n",
- adapter->fw_version, adapter->bios_version,
- adapter->product_info.dram_size);
-
- len += sprintf(page+len,
- "Controller Queue Depth = %d, Driver Queue Depth = %d\n",
- adapter->product_info.max_commands, adapter->max_cmds);
-
- len += sprintf(page+len, "support_ext_cdb = %d\n",
- adapter->support_ext_cdb);
- len += sprintf(page+len, "support_random_del = %d\n",
- adapter->support_random_del);
- len += sprintf(page+len, "boot_ldrv_enabled = %d\n",
- adapter->boot_ldrv_enabled);
- len += sprintf(page+len, "boot_ldrv = %d\n",
- adapter->boot_ldrv);
- len += sprintf(page+len, "boot_pdrv_enabled = %d\n",
- adapter->boot_pdrv_enabled);
- len += sprintf(page+len, "boot_pdrv_ch = %d\n",
- adapter->boot_pdrv_ch);
- len += sprintf(page+len, "boot_pdrv_tgt = %d\n",
- adapter->boot_pdrv_tgt);
- len += sprintf(page+len, "quiescent = %d\n",
- atomic_read(&adapter->quiescent));
- len += sprintf(page+len, "has_cluster = %d\n",
- adapter->has_cluster);
-
- len += sprintf(page+len, "\nModule Parameters:\n");
- len += sprintf(page+len, "max_cmd_per_lun = %d\n",
- max_cmd_per_lun);
- len += sprintf(page+len, "max_sectors_per_io = %d\n",
- max_sectors_per_io);
-
- *eof = 1;
-
- return len;
+ if(adapter->flag & BOARD_64BIT)
+ seq_puts(m, "Controller capable of 64-bit memory addressing\n");
+ if( adapter->has_64bit_addr )
+ seq_puts(m, "Controller using 64-bit memory addressing\n");
+ else
+ seq_puts(m, "Controller is not using 64-bit memory addressing\n");
+
+ seq_printf(m, "Base = %08lx, Irq = %d, ",
+ adapter->base, adapter->host->irq);
+
+ seq_printf(m, "Logical Drives = %d, Channels = %d\n",
+ adapter->numldrv, adapter->product_info.nchannels);
+
+ seq_printf(m, "Version =%s:%s, DRAM = %dMb\n",
+ adapter->fw_version, adapter->bios_version,
+ adapter->product_info.dram_size);
+
+ seq_printf(m, "Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+ adapter->product_info.max_commands, adapter->max_cmds);
+
+ seq_printf(m, "support_ext_cdb = %d\n", adapter->support_ext_cdb);
+ seq_printf(m, "support_random_del = %d\n", adapter->support_random_del);
+ seq_printf(m, "boot_ldrv_enabled = %d\n", adapter->boot_ldrv_enabled);
+ seq_printf(m, "boot_ldrv = %d\n", adapter->boot_ldrv);
+ seq_printf(m, "boot_pdrv_enabled = %d\n", adapter->boot_pdrv_enabled);
+ seq_printf(m, "boot_pdrv_ch = %d\n", adapter->boot_pdrv_ch);
+ seq_printf(m, "boot_pdrv_tgt = %d\n", adapter->boot_pdrv_tgt);
+ seq_printf(m, "quiescent = %d\n",
+ atomic_read(&adapter->quiescent));
+ seq_printf(m, "has_cluster = %d\n", adapter->has_cluster);
+
+ seq_puts(m, "\nModule Parameters:\n");
+ seq_printf(m, "max_cmd_per_lun = %d\n", max_cmd_per_lun);
+ seq_printf(m, "max_sectors_per_io = %d\n", max_sectors_per_io);
+ return 0;
}
-
-
/**
- * proc_read_stat()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_stat()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
- * Diaplay statistical information about the I/O activity.
+ * Display statistical information about the I/O activity.
*/
static int
-proc_read_stat(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_stat(struct seq_file *m, void *v)
{
- adapter_t *adapter;
- int len;
+ adapter_t *adapter = m->private;
+#if MEGA_HAVE_STATS
int i;
+#endif
- i = 0; /* avoid compilation warnings */
- len = 0;
- adapter = (adapter_t *)data;
-
- len = sprintf(page, "Statistical Information for this controller\n");
- len += sprintf(page+len, "pend_cmds = %d\n",
- atomic_read(&adapter->pend_cmds));
+ seq_puts(m, "Statistical Information for this controller\n");
+ seq_printf(m, "pend_cmds = %d\n", atomic_read(&adapter->pend_cmds));
#if MEGA_HAVE_STATS
for(i = 0; i < adapter->numldrv; i++) {
- len += sprintf(page+len, "Logical Drive %d:\n", i);
-
- len += sprintf(page+len,
- "\tReads Issued = %lu, Writes Issued = %lu\n",
- adapter->nreads[i], adapter->nwrites[i]);
-
- len += sprintf(page+len,
- "\tSectors Read = %lu, Sectors Written = %lu\n",
- adapter->nreadblocks[i], adapter->nwriteblocks[i]);
-
- len += sprintf(page+len,
- "\tRead errors = %lu, Write errors = %lu\n\n",
- adapter->rd_errors[i], adapter->wr_errors[i]);
+ seq_printf(m, "Logical Drive %d:\n", i);
+ seq_printf(m, "\tReads Issued = %lu, Writes Issued = %lu\n",
+ adapter->nreads[i], adapter->nwrites[i]);
+ seq_printf(m, "\tSectors Read = %lu, Sectors Written = %lu\n",
+ adapter->nreadblocks[i], adapter->nwriteblocks[i]);
+ seq_printf(m, "\tRead errors = %lu, Write errors = %lu\n\n",
+ adapter->rd_errors[i], adapter->wr_errors[i]);
}
#else
- len += sprintf(page+len,
- "IO and error counters not compiled in driver.\n");
+ seq_puts(m, "IO and error counters not compiled in driver.\n");
#endif
-
- *eof = 1;
-
- return len;
+ return 0;
}
/**
- * proc_read_mbox()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_mbox()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
* Display mailbox information for the last command issued. This information
* is good for debugging.
*/
static int
-proc_read_mbox(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_mbox(struct seq_file *m, void *v)
{
-
- adapter_t *adapter = (adapter_t *)data;
+ adapter_t *adapter = m->private;
volatile mbox_t *mbox = adapter->mbox;
- int len = 0;
-
- len = sprintf(page, "Contents of Mail Box Structure\n");
- len += sprintf(page+len, " Fw Command = 0x%02x\n",
- mbox->m_out.cmd);
- len += sprintf(page+len, " Cmd Sequence = 0x%02x\n",
- mbox->m_out.cmdid);
- len += sprintf(page+len, " No of Sectors= %04d\n",
- mbox->m_out.numsectors);
- len += sprintf(page+len, " LBA = 0x%02x\n",
- mbox->m_out.lba);
- len += sprintf(page+len, " DTA = 0x%08x\n",
- mbox->m_out.xferaddr);
- len += sprintf(page+len, " Logical Drive= 0x%02x\n",
- mbox->m_out.logdrv);
- len += sprintf(page+len, " No of SG Elmt= 0x%02x\n",
- mbox->m_out.numsgelements);
- len += sprintf(page+len, " Busy = %01x\n",
- mbox->m_in.busy);
- len += sprintf(page+len, " Status = 0x%02x\n",
- mbox->m_in.status);
-
- *eof = 1;
-
- return len;
+
+ seq_puts(m, "Contents of Mail Box Structure\n");
+ seq_printf(m, " Fw Command = 0x%02x\n", mbox->m_out.cmd);
+ seq_printf(m, " Cmd Sequence = 0x%02x\n", mbox->m_out.cmdid);
+ seq_printf(m, " No of Sectors= %04d\n", mbox->m_out.numsectors);
+ seq_printf(m, " LBA = 0x%02x\n", mbox->m_out.lba);
+ seq_printf(m, " DTA = 0x%08x\n", mbox->m_out.xferaddr);
+ seq_printf(m, " Logical Drive= 0x%02x\n", mbox->m_out.logdrv);
+ seq_printf(m, " No of SG Elmt= 0x%02x\n", mbox->m_out.numsgelements);
+ seq_printf(m, " Busy = %01x\n", mbox->m_in.busy);
+ seq_printf(m, " Status = 0x%02x\n", mbox->m_in.status);
+ return 0;
}
/**
- * proc_rebuild_rate()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_rebuild_rate()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
* Display current rebuild rate
*/
static int
-proc_rebuild_rate(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_rebuild_rate(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
+ adapter_t *adapter = m->private;
dma_addr_t dma_handle;
caddr_t inquiry;
struct pci_dev *pdev;
- int len = 0;
- if( make_local_pdev(adapter, &pdev) != 0 ) {
- *eof = 1;
- return len;
- }
+ if( make_local_pdev(adapter, &pdev) != 0 )
+ return 0;
- if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
- free_local_pdev(pdev);
- *eof = 1;
- return len;
- }
+ if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL )
+ goto free_pdev;
if( mega_adapinq(adapter, dma_handle) != 0 ) {
-
- len = sprintf(page, "Adapter inquiry failed.\n");
-
+ seq_puts(m, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- free_local_pdev(pdev);
-
- *eof = 1;
-
- return len;
+ goto free_inquiry;
}
- if( adapter->flag & BOARD_40LD ) {
- len = sprintf(page, "Rebuild Rate: [%d%%]\n",
- ((mega_inquiry3 *)inquiry)->rebuild_rate);
- }
- else {
- len = sprintf(page, "Rebuild Rate: [%d%%]\n",
+ if( adapter->flag & BOARD_40LD )
+ seq_printf(m, "Rebuild Rate: [%d%%]\n",
+ ((mega_inquiry3 *)inquiry)->rebuild_rate);
+ else
+ seq_printf(m, "Rebuild Rate: [%d%%]\n",
((mraid_ext_inquiry *)
- inquiry)->raid_inq.adapter_info.rebuild_rate);
- }
-
+ inquiry)->raid_inq.adapter_info.rebuild_rate);
+free_inquiry:
mega_free_inquiry(inquiry, dma_handle, pdev);
-
+free_pdev:
free_local_pdev(pdev);
-
- *eof = 1;
-
- return len;
+ return 0;
}
/**
- * proc_battery()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_battery()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
* Display information about the battery module on the controller.
*/
static int
-proc_battery(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_battery(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
+ adapter_t *adapter = m->private;
dma_addr_t dma_handle;
caddr_t inquiry;
struct pci_dev *pdev;
- u8 battery_status = 0;
- char str[256];
- int len = 0;
+ u8 battery_status;
- if( make_local_pdev(adapter, &pdev) != 0 ) {
- *eof = 1;
- return len;
- }
+ if( make_local_pdev(adapter, &pdev) != 0 )
+ return 0;
- if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
- free_local_pdev(pdev);
- *eof = 1;
- return len;
- }
+ if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL )
+ goto free_pdev;
if( mega_adapinq(adapter, dma_handle) != 0 ) {
-
- len = sprintf(page, "Adapter inquiry failed.\n");
-
+ seq_printf(m, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- free_local_pdev(pdev);
-
- *eof = 1;
-
- return len;
+ goto free_inquiry;
}
if( adapter->flag & BOARD_40LD ) {
@@ -2461,146 +2278,80 @@ proc_battery(char *page, char **start, off_t offset, int count, int *eof,
/*
* Decode the battery status
*/
- sprintf(str, "Battery Status:[%d]", battery_status);
+ seq_printf(m, "Battery Status:[%d]", battery_status);
if(battery_status == MEGA_BATT_CHARGE_DONE)
- strcat(str, " Charge Done");
+ seq_puts(m, " Charge Done");
if(battery_status & MEGA_BATT_MODULE_MISSING)
- strcat(str, " Module Missing");
+ seq_puts(m, " Module Missing");
if(battery_status & MEGA_BATT_LOW_VOLTAGE)
- strcat(str, " Low Voltage");
+ seq_puts(m, " Low Voltage");
if(battery_status & MEGA_BATT_TEMP_HIGH)
- strcat(str, " Temperature High");
+ seq_puts(m, " Temperature High");
if(battery_status & MEGA_BATT_PACK_MISSING)
- strcat(str, " Pack Missing");
+ seq_puts(m, " Pack Missing");
if(battery_status & MEGA_BATT_CHARGE_INPROG)
- strcat(str, " Charge In-progress");
+ seq_puts(m, " Charge In-progress");
if(battery_status & MEGA_BATT_CHARGE_FAIL)
- strcat(str, " Charge Fail");
+ seq_puts(m, " Charge Fail");
if(battery_status & MEGA_BATT_CYCLES_EXCEEDED)
- strcat(str, " Cycles Exceeded");
-
- len = sprintf(page, "%s\n", str);
+ seq_puts(m, " Cycles Exceeded");
+ seq_putc(m, '\n');
+free_inquiry:
mega_free_inquiry(inquiry, dma_handle, pdev);
-
+free_pdev:
free_local_pdev(pdev);
-
- *eof = 1;
-
- return len;
-}
-
-
-/**
- * proc_pdrv_ch0()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
- *
- * Display information about the physical drives on physical channel 0.
- */
-static int
-proc_pdrv_ch0(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
-{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_pdrv(adapter, page, 0));
-}
-
-
-/**
- * proc_pdrv_ch1()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
- *
- * Display information about the physical drives on physical channel 1.
- */
-static int
-proc_pdrv_ch1(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
-{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_pdrv(adapter, page, 1));
+ return 0;
}
-/**
- * proc_pdrv_ch2()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
- *
- * Display information about the physical drives on physical channel 2.
+/*
+ * Display scsi inquiry
*/
-static int
-proc_pdrv_ch2(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+static void
+mega_print_inquiry(struct seq_file *m, char *scsi_inq)
{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_pdrv(adapter, page, 2));
-}
+ int i;
+ seq_puts(m, " Vendor: ");
+ seq_write(m, scsi_inq + 8, 8);
+ seq_puts(m, " Model: ");
+ seq_write(m, scsi_inq + 16, 16);
+ seq_puts(m, " Rev: ");
+ seq_write(m, scsi_inq + 32, 4);
+ seq_putc(m, '\n');
-/**
- * proc_pdrv_ch3()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
- *
- * Display information about the physical drives on physical channel 3.
- */
-static int
-proc_pdrv_ch3(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
-{
- adapter_t *adapter = (adapter_t *)data;
+ i = scsi_inq[0] & 0x1f;
+ seq_printf(m, " Type: %s ", scsi_device_type(i));
- *eof = 1;
+ seq_printf(m, " ANSI SCSI revision: %02x",
+ scsi_inq[2] & 0x07);
- return (proc_pdrv(adapter, page, 3));
+ if( (scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1 )
+ seq_puts(m, " CCS\n");
+ else
+ seq_putc(m, '\n');
}
-
/**
- * proc_pdrv()
+ * proc_show_pdrv()
+ * @m - Synthetic file construction data
* @page - buffer to write the data in
* @adapter - pointer to our soft state
*
* Display information about the physical drives.
*/
static int
-proc_pdrv(adapter_t *adapter, char *page, int channel)
+proc_show_pdrv(struct seq_file *m, adapter_t *adapter, int channel)
{
dma_addr_t dma_handle;
char *scsi_inq;
@@ -2611,32 +2362,24 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
u8 state;
int tgt;
int max_channels;
- int len = 0;
- char str[80];
int i;
- if( make_local_pdev(adapter, &pdev) != 0 ) {
- return len;
- }
+ if( make_local_pdev(adapter, &pdev) != 0 )
+ return 0;
- if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
+ if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL )
goto free_pdev;
- }
if( mega_adapinq(adapter, dma_handle) != 0 ) {
- len = sprintf(page, "Adapter inquiry failed.\n");
-
+ seq_puts(m, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
-
goto free_inquiry;
}
scsi_inq = pci_alloc_consistent(pdev, 256, &scsi_inq_dma_handle);
-
if( scsi_inq == NULL ) {
- len = sprintf(page, "memory not available for scsi inq.\n");
-
+ seq_puts(m, "memory not available for scsi inq.\n");
goto free_inquiry;
}
@@ -2659,39 +2402,31 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
i = channel*16 + tgt;
state = *(pdrv_state + i);
-
switch( state & 0x0F ) {
-
case PDRV_ONLINE:
- sprintf(str,
- "Channel:%2d Id:%2d State: Online",
- channel, tgt);
+ seq_printf(m, "Channel:%2d Id:%2d State: Online",
+ channel, tgt);
break;
case PDRV_FAILED:
- sprintf(str,
- "Channel:%2d Id:%2d State: Failed",
- channel, tgt);
+ seq_printf(m, "Channel:%2d Id:%2d State: Failed",
+ channel, tgt);
break;
case PDRV_RBLD:
- sprintf(str,
- "Channel:%2d Id:%2d State: Rebuild",
- channel, tgt);
+ seq_printf(m, "Channel:%2d Id:%2d State: Rebuild",
+ channel, tgt);
break;
case PDRV_HOTSPARE:
- sprintf(str,
- "Channel:%2d Id:%2d State: Hot spare",
- channel, tgt);
+ seq_printf(m, "Channel:%2d Id:%2d State: Hot spare",
+ channel, tgt);
break;
default:
- sprintf(str,
- "Channel:%2d Id:%2d State: Un-configured",
- channel, tgt);
+ seq_printf(m, "Channel:%2d Id:%2d State: Un-configured",
+ channel, tgt);
break;
-
}
/*
@@ -2710,11 +2445,8 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
* Check for overflow. We print less than 240
* characters for inquiry
*/
- if( (len + 240) >= PAGE_SIZE ) break;
-
- len += sprintf(page+len, "%s.\n", str);
-
- len += mega_print_inquiry(page+len, scsi_inq);
+ seq_puts(m, ".\n");
+ mega_print_inquiry(m, scsi_inq);
}
free_pci:
@@ -2723,150 +2455,68 @@ free_inquiry:
mega_free_inquiry(inquiry, dma_handle, pdev);
free_pdev:
free_local_pdev(pdev);
-
- return len;
-}
-
-
-/*
- * Display scsi inquiry
- */
-static int
-mega_print_inquiry(char *page, char *scsi_inq)
-{
- int len = 0;
- int i;
-
- len = sprintf(page, " Vendor: ");
- for( i = 8; i < 16; i++ ) {
- len += sprintf(page+len, "%c", scsi_inq[i]);
- }
-
- len += sprintf(page+len, " Model: ");
-
- for( i = 16; i < 32; i++ ) {
- len += sprintf(page+len, "%c", scsi_inq[i]);
- }
-
- len += sprintf(page+len, " Rev: ");
-
- for( i = 32; i < 36; i++ ) {
- len += sprintf(page+len, "%c", scsi_inq[i]);
- }
-
- len += sprintf(page+len, "\n");
-
- i = scsi_inq[0] & 0x1f;
-
- len += sprintf(page+len, " Type: %s ", scsi_device_type(i));
-
- len += sprintf(page+len,
- " ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
-
- if( (scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1 )
- len += sprintf(page+len, " CCS\n");
- else
- len += sprintf(page+len, "\n");
-
- return len;
+ return 0;
}
-
/**
- * proc_rdrv_10()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_pdrv_ch0()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
- * Display real time information about the logical drives 0 through 9.
+ * Display information about the physical drives on physical channel 0.
*/
static int
-proc_rdrv_10(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_pdrv_ch0(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_rdrv(adapter, page, 0, 9));
+ return proc_show_pdrv(m, m->private, 0);
}
/**
- * proc_rdrv_20()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_pdrv_ch1()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
- * Display real time information about the logical drives 0 through 9.
+ * Display information about the physical drives on physical channel 1.
*/
static int
-proc_rdrv_20(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_pdrv_ch1(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_rdrv(adapter, page, 10, 19));
+ return proc_show_pdrv(m, m->private, 1);
}
/**
- * proc_rdrv_30()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_pdrv_ch2()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
- * Display real time information about the logical drives 0 through 9.
+ * Display information about the physical drives on physical channel 2.
*/
static int
-proc_rdrv_30(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_pdrv_ch2(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_rdrv(adapter, page, 20, 29));
+ return proc_show_pdrv(m, m->private, 2);
}
/**
- * proc_rdrv_40()
- * @page - buffer to write the data in
- * @start - where the actual data has been written in page
- * @offset - same meaning as the read system call
- * @count - same meaning as the read system call
- * @eof - set if no more data needs to be returned
- * @data - pointer to our soft state
+ * proc_show_pdrv_ch3()
+ * @m - Synthetic file construction data
+ * @v - File iterator
*
- * Display real time information about the logical drives 0 through 9.
+ * Display information about the physical drives on physical channel 3.
*/
static int
-proc_rdrv_40(char *page, char **start, off_t offset, int count, int *eof,
- void *data)
+proc_show_pdrv_ch3(struct seq_file *m, void *v)
{
- adapter_t *adapter = (adapter_t *)data;
-
- *eof = 1;
-
- return (proc_rdrv(adapter, page, 30, 39));
+ return proc_show_pdrv(m, m->private, 3);
}
/**
- * proc_rdrv()
- * @page - buffer to write the data in
+ * proc_show_rdrv()
+ * @m - Synthetic file construction data
* @adapter - pointer to our soft state
* @start - starting logical drive to display
* @end - ending logical drive to display
@@ -2875,7 +2525,7 @@ proc_rdrv_40(char *page, char **start, off_t offset, int count, int *eof,
* /proc/scsi/scsi interface
*/
static int
-proc_rdrv(adapter_t *adapter, char *page, int start, int end )
+proc_show_rdrv(struct seq_file *m, adapter_t *adapter, int start, int end )
{
dma_addr_t dma_handle;
logdrv_param *lparam;
@@ -2887,29 +2537,18 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
u8 *rdrv_state;
int num_ldrv;
u32 array_sz;
- int len = 0;
int i;
- if( make_local_pdev(adapter, &pdev) != 0 ) {
- return len;
- }
+ if( make_local_pdev(adapter, &pdev) != 0 )
+ return 0;
- if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
- free_local_pdev(pdev);
- return len;
- }
+ if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL )
+ goto free_pdev;
if( mega_adapinq(adapter, dma_handle) != 0 ) {
-
- len = sprintf(page, "Adapter inquiry failed.\n");
-
+ seq_puts(m, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- free_local_pdev(pdev);
-
- return len;
+ goto free_inquiry;
}
memset(&mc, 0, sizeof(megacmd_t));
@@ -2935,13 +2574,8 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
&disk_array_dma_handle);
if( disk_array == NULL ) {
- len = sprintf(page, "memory not available.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- free_local_pdev(pdev);
-
- return len;
+ seq_puts(m, "memory not available.\n");
+ goto free_inquiry;
}
mc.xferaddr = (u32)disk_array_dma_handle;
@@ -2951,17 +2585,8 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
mc.opcode = OP_DCMD_READ_CONFIG;
if( mega_internal_command(adapter, &mc, NULL) ) {
-
- len = sprintf(page, "40LD read config failed.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- pci_free_consistent(pdev, array_sz, disk_array,
- disk_array_dma_handle);
-
- free_local_pdev(pdev);
-
- return len;
+ seq_puts(m, "40LD read config failed.\n");
+ goto free_pci;
}
}
@@ -2969,24 +2594,10 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
mc.cmd = NEW_READ_CONFIG_8LD;
if( mega_internal_command(adapter, &mc, NULL) ) {
-
mc.cmd = READ_CONFIG_8LD;
-
- if( mega_internal_command(adapter, &mc,
- NULL) ){
-
- len = sprintf(page,
- "8LD read config failed.\n");
-
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
- pci_free_consistent(pdev, array_sz,
- disk_array,
- disk_array_dma_handle);
-
- free_local_pdev(pdev);
-
- return len;
+ if( mega_internal_command(adapter, &mc, NULL) ) {
+ seq_puts(m, "8LD read config failed.\n");
+ goto free_pci;
}
}
}
@@ -3006,29 +2617,23 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
* Check for overflow. We print less than 240 characters for
* information about each logical drive.
*/
- if( (len + 240) >= PAGE_SIZE ) break;
-
- len += sprintf(page+len, "Logical drive:%2d:, ", i);
+ seq_printf(m, "Logical drive:%2d:, ", i);
switch( rdrv_state[i] & 0x0F ) {
case RDRV_OFFLINE:
- len += sprintf(page+len, "state: offline");
+ seq_puts(m, "state: offline");
break;
-
case RDRV_DEGRADED:
- len += sprintf(page+len, "state: degraded");
+ seq_puts(m, "state: degraded");
break;
-
case RDRV_OPTIMAL:
- len += sprintf(page+len, "state: optimal");
+ seq_puts(m, "state: optimal");
break;
-
case RDRV_DELETED:
- len += sprintf(page+len, "state: deleted");
+ seq_puts(m, "state: deleted");
break;
-
default:
- len += sprintf(page+len, "state: unknown");
+ seq_puts(m, "state: unknown");
break;
}
@@ -3036,84 +2641,203 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
* Check if check consistency or initialization is going on
* for this logical drive.
*/
- if( (rdrv_state[i] & 0xF0) == 0x20 ) {
- len += sprintf(page+len,
- ", check-consistency in progress");
- }
- else if( (rdrv_state[i] & 0xF0) == 0x10 ) {
- len += sprintf(page+len,
- ", initialization in progress");
- }
+ if( (rdrv_state[i] & 0xF0) == 0x20 )
+ seq_puts(m, ", check-consistency in progress");
+ else if( (rdrv_state[i] & 0xF0) == 0x10 )
+ seq_puts(m, ", initialization in progress");
- len += sprintf(page+len, "\n");
-
- len += sprintf(page+len, "Span depth:%3d, ",
- lparam->span_depth);
-
- len += sprintf(page+len, "RAID level:%3d, ",
- lparam->level);
-
- len += sprintf(page+len, "Stripe size:%3d, ",
- lparam->stripe_sz ? lparam->stripe_sz/2: 128);
-
- len += sprintf(page+len, "Row size:%3d\n",
- lparam->row_size);
+ seq_putc(m, '\n');
+ seq_printf(m, "Span depth:%3d, ", lparam->span_depth);
+ seq_printf(m, "RAID level:%3d, ", lparam->level);
+ seq_printf(m, "Stripe size:%3d, ",
+ lparam->stripe_sz ? lparam->stripe_sz/2: 128);
+ seq_printf(m, "Row size:%3d\n", lparam->row_size);
- len += sprintf(page+len, "Read Policy: ");
-
+ seq_puts(m, "Read Policy: ");
switch(lparam->read_ahead) {
-
case NO_READ_AHEAD:
- len += sprintf(page+len, "No read ahead, ");
+ seq_puts(m, "No read ahead, ");
break;
-
case READ_AHEAD:
- len += sprintf(page+len, "Read ahead, ");
+ seq_puts(m, "Read ahead, ");
break;
-
case ADAP_READ_AHEAD:
- len += sprintf(page+len, "Adaptive, ");
+ seq_puts(m, "Adaptive, ");
break;
}
- len += sprintf(page+len, "Write Policy: ");
-
+ seq_puts(m, "Write Policy: ");
switch(lparam->write_mode) {
-
case WRMODE_WRITE_THRU:
- len += sprintf(page+len, "Write thru, ");
+ seq_puts(m, "Write thru, ");
break;
-
case WRMODE_WRITE_BACK:
- len += sprintf(page+len, "Write back, ");
+ seq_puts(m, "Write back, ");
break;
}
- len += sprintf(page+len, "Cache Policy: ");
-
+ seq_puts(m, "Cache Policy: ");
switch(lparam->direct_io) {
-
case CACHED_IO:
- len += sprintf(page+len, "Cached IO\n\n");
+ seq_puts(m, "Cached IO\n\n");
break;
-
case DIRECT_IO:
- len += sprintf(page+len, "Direct IO\n\n");
+ seq_puts(m, "Direct IO\n\n");
break;
}
}
- mega_free_inquiry(inquiry, dma_handle, pdev);
-
+free_pci:
pci_free_consistent(pdev, array_sz, disk_array,
disk_array_dma_handle);
-
+free_inquiry:
+ mega_free_inquiry(inquiry, dma_handle, pdev);
+free_pdev:
free_local_pdev(pdev);
+ return 0;
+}
+
+/**
+ * proc_show_rdrv_10()
+ * @m - Synthetic file construction data
+ * @v - File iterator
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_show_rdrv_10(struct seq_file *m, void *v)
+{
+ return proc_show_rdrv(m, m->private, 0, 9);
+}
+
+
+/**
+ * proc_show_rdrv_20()
+ * @m - Synthetic file construction data
+ * @v - File iterator
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_show_rdrv_20(struct seq_file *m, void *v)
+{
+ return proc_show_rdrv(m, m->private, 10, 19);
+}
+
+
+/**
+ * proc_show_rdrv_30()
+ * @m - Synthetic file construction data
+ * @v - File iterator
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_show_rdrv_30(struct seq_file *m, void *v)
+{
+ return proc_show_rdrv(m, m->private, 20, 29);
+}
+
+
+/**
+ * proc_show_rdrv_40()
+ * @m - Synthetic file construction data
+ * @v - File iterator
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_show_rdrv_40(struct seq_file *m, void *v)
+{
+ return proc_show_rdrv(m, m->private, 30, 39);
+}
+
+
+/*
+ * seq_file wrappers for procfile show routines.
+ */
+static int mega_proc_open(struct inode *inode, struct file *file)
+{
+ adapter_t *adapter = proc_get_parent_data(inode);
+ int (*show)(struct seq_file *, void *) = PDE_DATA(inode);
+
+ return single_open(file, show, adapter);
+}
+
+static const struct file_operations mega_proc_fops = {
+ .open = mega_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
+ * Table of proc files we need to create.
+ */
+struct mega_proc_file {
+ const char *name;
+ unsigned short ptr_offset;
+ int (*show) (struct seq_file *m, void *v);
+};
+
+static const struct mega_proc_file mega_proc_files[] = {
+ { "config", offsetof(adapter_t, proc_read), proc_show_config },
+ { "stat", offsetof(adapter_t, proc_stat), proc_show_stat },
+ { "mailbox", offsetof(adapter_t, proc_mbox), proc_show_mbox },
+#if MEGA_HAVE_ENH_PROC
+ { "rebuild-rate", offsetof(adapter_t, proc_rr), proc_show_rebuild_rate },
+ { "battery-status", offsetof(adapter_t, proc_battery), proc_show_battery },
+ { "diskdrives-ch0", offsetof(adapter_t, proc_pdrvstat[0]), proc_show_pdrv_ch0 },
+ { "diskdrives-ch1", offsetof(adapter_t, proc_pdrvstat[1]), proc_show_pdrv_ch1 },
+ { "diskdrives-ch2", offsetof(adapter_t, proc_pdrvstat[2]), proc_show_pdrv_ch2 },
+ { "diskdrives-ch3", offsetof(adapter_t, proc_pdrvstat[3]), proc_show_pdrv_ch3 },
+ { "raiddrives-0-9", offsetof(adapter_t, proc_rdrvstat[0]), proc_show_rdrv_10 },
+ { "raiddrives-10-19", offsetof(adapter_t, proc_rdrvstat[1]), proc_show_rdrv_20 },
+ { "raiddrives-20-29", offsetof(adapter_t, proc_rdrvstat[2]), proc_show_rdrv_30 },
+ { "raiddrives-30-39", offsetof(adapter_t, proc_rdrvstat[3]), proc_show_rdrv_40 },
+#endif
+ { NULL }
+};
- return len;
+/**
+ * mega_create_proc_entry()
+ * @index - index in soft state array
+ * @parent - parent node for this /proc entry
+ *
+ * Creates /proc entries for our controllers.
+ */
+static void
+mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+ const struct mega_proc_file *f;
+ adapter_t *adapter = hba_soft_state[index];
+ struct proc_dir_entry *dir, *de, **ppde;
+ u8 string[16];
+
+ sprintf(string, "hba%d", adapter->host->host_no);
+
+ dir = adapter->controller_proc_dir_entry =
+ proc_mkdir_data(string, 0, parent, adapter);
+ if(!dir) {
+ printk(KERN_WARNING "\nmegaraid: proc_mkdir failed\n");
+ return;
+ }
+
+ for (f = mega_proc_files; f->name; f++) {
+ de = proc_create_data(f->name, S_IRUSR, dir, &mega_proc_fops,
+ f->show);
+ if (!de) {
+ printk(KERN_WARNING "\nmegaraid: proc_create failed\n");
+ return;
+ }
+
+ ppde = (void *)adapter + f->ptr_offset;
+ *ppde = de;
+ }
}
+
#else
static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
{
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4fb2adf6b80d..4d0ce4e78dfd 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -987,24 +987,7 @@ static int mega_init_scb (adapter_t *);
static int mega_is_bios_enabled (adapter_t *);
#ifdef CONFIG_PROC_FS
-static int mega_print_inquiry(char *, char *);
static void mega_create_proc_entry(int, struct proc_dir_entry *);
-static int proc_read_config(char *, char **, off_t, int, int *, void *);
-static int proc_read_stat(char *, char **, off_t, int, int *, void *);
-static int proc_read_mbox(char *, char **, off_t, int, int *, void *);
-static int proc_rebuild_rate(char *, char **, off_t, int, int *, void *);
-static int proc_battery(char *, char **, off_t, int, int *, void *);
-static int proc_pdrv_ch0(char *, char **, off_t, int, int *, void *);
-static int proc_pdrv_ch1(char *, char **, off_t, int, int *, void *);
-static int proc_pdrv_ch2(char *, char **, off_t, int, int *, void *);
-static int proc_pdrv_ch3(char *, char **, off_t, int, int *, void *);
-static int proc_pdrv(adapter_t *, char *, int);
-static int proc_rdrv_10(char *, char **, off_t, int, int *, void *);
-static int proc_rdrv_20(char *, char **, off_t, int, int *, void *);
-static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
-static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
-static int proc_rdrv(adapter_t *, char *, int, int);
-
static int mega_adapinq(adapter_t *, dma_addr_t);
static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
#endif
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 408d2548a748..684cc343cf09 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1488,7 +1488,4 @@ struct megasas_mgmt_info {
int max_index;
};
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 9d53540207ec..7c90d57b867e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -3984,12 +3984,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (reset_devices) {
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos),
+ pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
&control);
if (control & PCI_MSIX_FLAGS_ENABLE) {
dev_info(&pdev->dev, "resetting MSI-X\n");
pci_write_config_word(pdev,
- msi_control_reg(pos),
+ pos + PCI_MSIX_FLAGS,
control &
~PCI_MSIX_FLAGS_ENABLE);
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index 08685c4cf231..eec052c2670a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -505,19 +505,6 @@ _ctl_fasync(int fd, struct file *filep, int mode)
}
/**
- * _ctl_release -
- * @inode -
- * @filep -
- *
- * Called when application releases the fasyn callback handler.
- */
-static int
-_ctl_release(struct inode *inode, struct file *filep)
-{
- return fasync_helper(-1, filep, 0, &async_queue);
-}
-
-/**
* _ctl_poll -
* @file -
* @wait -
@@ -3027,7 +3014,6 @@ struct device_attribute *mpt2sas_dev_attrs[] = {
static const struct file_operations ctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = _ctl_ioctl,
- .release = _ctl_release,
.poll = _ctl_poll,
.fasync = _ctl_fasync,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 1df9ed4f371d..4db0c7a18bd8 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -148,7 +148,7 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
desc = "raid_config";
break;
case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
- desc = "driver_mappping";
+ desc = "driver_mapping";
break;
}
break;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 054d5231c974..0b402b6f2d26 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -503,19 +503,6 @@ _ctl_fasync(int fd, struct file *filep, int mode)
}
/**
- * _ctl_release -
- * @inode -
- * @filep -
- *
- * Called when application releases the fasyn callback handler.
- */
-static int
-_ctl_release(struct inode *inode, struct file *filep)
-{
- return fasync_helper(-1, filep, 0, &async_queue);
-}
-
-/**
* _ctl_poll -
* @file -
* @wait -
@@ -3233,7 +3220,6 @@ struct device_attribute *mpt3sas_dev_attrs[] = {
static const struct file_operations ctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = _ctl_ioctl,
- .release = _ctl_release,
.poll = _ctl_poll,
.fasync = _ctl_fasync,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index c29d0dbb9660..e7f6661a8862 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -76,7 +76,8 @@ int mvme147_detect(struct scsi_host_template *tpnt)
called++;
tpnt->proc_name = "MVME147";
- tpnt->proc_info = &wd33c93_proc_info;
+ tpnt->show_info = wd33c93_show_info,
+ tpnt->write_info = wd33c93_write_info,
instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
if (!instance)
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index ce90d0546cdd..74550922ad55 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -703,7 +703,7 @@ static struct pci_device_id mvs_pci_table[] = {
{ PCI_VDEVICE(TTI, 0x2744), chip_9480 },
{ PCI_VDEVICE(TTI, 0x2760), chip_9480 },
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9480,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
@@ -712,7 +712,7 @@ static struct pci_device_id mvs_pci_table[] = {
.driver_data = chip_9480,
},
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9445,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
@@ -721,7 +721,7 @@ static struct pci_device_id mvs_pci_table[] = {
.driver_data = chip_9445,
},
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9485,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 4594ccaaf49b..c3601b57a80c 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -49,8 +49,8 @@ MODULE_AUTHOR("jyli@marvell.com");
MODULE_DESCRIPTION("Marvell UMI Driver");
static DEFINE_PCI_DEVICE_TABLE(mvumi_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9143) },
- { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9580) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9143) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9580) },
{ 0 }
};
diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h
index e360135fd1bd..41f168702ac7 100644
--- a/drivers/scsi/mvumi.h
+++ b/drivers/scsi/mvumi.h
@@ -32,7 +32,6 @@
#define VER_BUILD 1500
#define MV_DRIVER_NAME "mvumi"
-#define PCI_VENDOR_ID_MARVELL_2 0x1b4b
#define PCI_DEVICE_ID_MARVELL_MV9143 0x9143
#define PCI_DEVICE_ID_MARVELL_MV9580 0x9580
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 1cc0c1c69c88..1e3879dcbdcc 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -192,7 +192,7 @@ static int __init init_nsp32 (void);
static void __exit exit_nsp32 (void);
/* struct struct scsi_host_template */
-static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);
+static int nsp32_show_info (struct seq_file *, struct Scsi_Host *);
static int nsp32_detect (struct pci_dev *pdev);
static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
@@ -268,7 +268,7 @@ static void nsp32_dmessage(const char *, int, int, char *, ...);
static struct scsi_host_template nsp32_template = {
.proc_name = "nsp32",
.name = "Workbit NinjaSCSI-32Bi/UDE",
- .proc_info = nsp32_proc_info,
+ .show_info = nsp32_show_info,
.info = nsp32_info,
.queuecommand = nsp32_queuecommand,
.can_queue = 1,
@@ -1442,19 +1442,10 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
}
#undef SPRINTF
-#define SPRINTF(args...) \
- do { \
- if(length > (pos - buffer)) { \
- pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
- nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
- } \
- } while(0)
-
-static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start,
- off_t offset, int length, int inout)
+#define SPRINTF(args...) seq_printf(m, ##args)
+
+static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
{
- char *pos = buffer;
- int thislength;
unsigned long flags;
nsp32_hw_data *data;
int hostno;
@@ -1463,11 +1454,6 @@ static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start,
int id, speed;
long model;
- /* Write is not supported, just return. */
- if (inout == TRUE) {
- return -EINVAL;
- }
-
hostno = host->host_no;
data = (nsp32_hw_data *)host->hostdata;
base = host->io_port;
@@ -1527,20 +1513,7 @@ static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start,
}
SPRINTF("\n");
}
-
-
- thislength = pos - (buffer + offset);
-
- if(thislength < 0) {
- *start = NULL;
- return 0;
- }
-
-
- thislength = min(thislength, length);
- *start = buffer + offset;
-
- return thislength;
+ return 0;
}
#undef SPRINTF
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f25ca33..aa66361ed44b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1049,7 +1049,7 @@ static struct bio *_create_sg_bios(struct osd_request *or,
bio = bio_kmalloc(GFP_KERNEL, numentries);
if (unlikely(!bio)) {
- OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries);
+ OSD_DEBUG("Failed to allocate BIO size=%u\n", numentries);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 2f72c9807b12..62f1a6031765 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -388,7 +388,8 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
int count;
tpnt->proc_name = "pas16";
- tpnt->proc_info = &pas16_proc_info;
+ tpnt->show_info = pas16_show_info;
+ tpnt->write_info = pas16_write_info;
if (pas16_addr != 0) {
overrides[0].io_port = pas16_addr;
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index a04281cace2e..3721342835e9 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -163,7 +163,8 @@ static int pas16_bus_reset(Scsi_Cmnd *);
#define NCR5380_queue_command pas16_queue_command
#define NCR5380_abort pas16_abort
#define NCR5380_bus_reset pas16_bus_reset
-#define NCR5380_proc_info pas16_proc_info
+#define NCR5380_show_info pas16_show_info
+#define NCR5380_write_info pas16_write_info
/* 15 14 12 10 7 5 3
1101 0100 1010 1000 */
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index b61a753eb896..987fbb1b244e 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -76,7 +76,7 @@ MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0
static struct scsi_host_template nsp_driver_template = {
.proc_name = "nsp_cs",
- .proc_info = nsp_proc_info,
+ .show_info = nsp_show_info,
.name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
.info = nsp_info,
.queuecommand = nsp_queuecommand,
@@ -1365,33 +1365,19 @@ static const char *nsp_info(struct Scsi_Host *shpnt)
}
#undef SPRINTF
-#define SPRINTF(args...) \
- do { \
- if(length > (pos - buffer)) { \
- pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
- nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
- } \
- } while(0)
-
-static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
- off_t offset, int length, int inout)
+#define SPRINTF(args...) seq_printf(m, ##args)
+
+static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
{
int id;
- char *pos = buffer;
- int thislength;
int speed;
unsigned long flags;
nsp_hw_data *data;
int hostno;
- if (inout) {
- return -EINVAL;
- }
-
hostno = host->host_no;
data = (nsp_hw_data *)host->hostdata;
-
SPRINTF("NinjaSCSI status\n\n");
SPRINTF("Driver version: $Revision: 1.23 $\n");
SPRINTF("SCSI host No.: %d\n", hostno);
@@ -1458,19 +1444,7 @@ static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
}
SPRINTF("\n");
}
-
- thislength = pos - (buffer + offset);
-
- if(thislength < 0) {
- *start = NULL;
- return 0;
- }
-
-
- thislength = min(thislength, length);
- *start = buffer + offset;
-
- return thislength;
+ return 0;
}
#undef SPRINTF
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 7fc9a9d0a448..afd64f0adc4b 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -292,13 +292,8 @@ static int nsp_cs_config (struct pcmcia_device *link);
/* Linux SCSI subsystem specific functions */
static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht);
static const char *nsp_info (struct Scsi_Host *shpnt);
-static int nsp_proc_info (
- struct Scsi_Host *host,
- char *buffer,
- char **start,
- off_t offset,
- int length,
- int inout);
+static int nsp_show_info (struct seq_file *m,
+ struct Scsi_Host *host);
static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt);
/* Error handler */
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index b46f5e906837..8e1b73775065 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -3599,19 +3599,6 @@ static int pmcraid_chr_open(struct inode *inode, struct file *filep)
}
/**
- * pmcraid_release - char node "release" entry point
- */
-static int pmcraid_chr_release(struct inode *inode, struct file *filep)
-{
- struct pmcraid_instance *pinstance = filep->private_data;
-
- filep->private_data = NULL;
- fasync_helper(-1, filep, 0, &pinstance->aen_queue);
-
- return 0;
-}
-
-/**
* pmcraid_fasync - Async notifier registration from applications
*
* This function adds the calling process to a driver global queue. When an
@@ -4167,7 +4154,6 @@ static long pmcraid_chr_ioctl(
static const struct file_operations pmcraid_fops = {
.owner = THIS_MODULE,
.open = pmcraid_chr_open,
- .release = pmcraid_chr_release,
.fasync = pmcraid_chr_fasync,
.unlocked_ioctl = pmcraid_chr_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index d164c9639361..1db8b26063b4 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -118,8 +118,9 @@ static inline void ppa_pb_release(ppa_struct *dev)
* Also gives a method to use a script to obtain optimum timings (TODO)
*/
-static inline int ppa_proc_write(ppa_struct *dev, char *buffer, int length)
+static inline int ppa_write_info(struct Scsi_Host *host, char *buffer, int length)
{
+ ppa_struct *dev = ppa_dev(host);
unsigned long x;
if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
@@ -137,35 +138,17 @@ static inline int ppa_proc_write(ppa_struct *dev, char *buffer, int length)
return -EINVAL;
}
-static int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
+static int ppa_show_info(struct seq_file *m, struct Scsi_Host *host)
{
- int len = 0;
ppa_struct *dev = ppa_dev(host);
- if (inout)
- return ppa_proc_write(dev, buffer, length);
-
- len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
- len +=
- sprintf(buffer + len, "Parport : %s\n",
- dev->dev->port->name);
- len +=
- sprintf(buffer + len, "Mode : %s\n",
- PPA_MODE_STRING[dev->mode]);
+ seq_printf(m, "Version : %s\n", PPA_VERSION);
+ seq_printf(m, "Parport : %s\n", dev->dev->port->name);
+ seq_printf(m, "Mode : %s\n", PPA_MODE_STRING[dev->mode]);
#if PPA_DEBUG > 0
- len +=
- sprintf(buffer + len, "recon_tmo : %lu\n", dev->recon_tmo);
+ seq_printf(m, "recon_tmo : %lu\n", dev->recon_tmo);
#endif
-
- /* Request for beyond end of buffer */
- if (offset > length)
- return 0;
-
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
- return len;
+ return 0;
}
static int device_check(ppa_struct *dev);
@@ -981,7 +964,8 @@ static int ppa_adjust_queue(struct scsi_device *device)
static struct scsi_host_template ppa_template = {
.module = THIS_MODULE,
.proc_name = "ppa",
- .proc_info = ppa_proc_info,
+ .show_info = ppa_show_info,
+ .write_info = ppa_write_info,
.name = "Iomega VPI0 (ppa) interface",
.queuecommand = ppa_queuecommand,
.eh_abort_handler = ppa_abort,
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index dce7d788cdc9..c37b244cf8ae 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
- qla_nx.o qla_target.o
+ qla_nx.o qla_mr.o qla_target.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 1d82eef4e1eb..bf60c631abb5 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -888,7 +888,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
uint32_t sn;
- if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(vha->hw)) {
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.serial_num);
+ } else if (IS_FWI2_CAPABLE(ha)) {
qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", buf);
}
@@ -912,6 +915,11 @@ qla2x00_isp_id_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
+ if (IS_QLAFX00(vha->hw))
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.hw_version);
+
return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
@@ -922,6 +930,11 @@ qla2x00_model_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ if (IS_QLAFX00(vha->hw))
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.product_name);
+
return snprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number);
}
@@ -1304,6 +1317,12 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
int rval = QLA_FUNCTION_FAILED;
uint16_t state[5];
+ uint32_t pstate;
+
+ if (IS_QLAFX00(vha->hw)) {
+ pstate = qlafx00_fw_state_show(dev, attr, buf);
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
+ }
if (qla2x00_reset_active(vha))
ql_log(ql_log_warn, vha, 0x707c,
@@ -1454,6 +1473,11 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
(shost_priv(shost)))->hw;
u32 speed = FC_PORTSPEED_UNKNOWN;
+ if (IS_QLAFX00(ha)) {
+ qlafx00_get_host_speed(shost);
+ return;
+ }
+
switch (ha->link_data_rate) {
case PORT_SPEED_1GB:
speed = FC_PORTSPEED_1GBIT;
@@ -1637,6 +1661,9 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
{
scsi_qla_host_t *vha = shost_priv(shost);
+ if (IS_QLAFX00(vha->hw))
+ return 0;
+
qla2x00_loop_reset(vha);
return 0;
}
@@ -1655,6 +1682,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat = &vha->fc_host_stat;
memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
+ if (IS_QLAFX00(vha->hw))
+ goto done;
+
if (test_bit(UNLOADING, &vha->dpc_flags))
goto done;
@@ -1938,11 +1968,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
"Timer for the VP[%d] has stopped\n", vha->vp_idx);
}
- /* No pending activities shall be there on the vha now */
- if (ql2xextended_error_logging & ql_dbg_user)
- msleep(random32()%10); /* Just to see if something falls on
- * the net we have placed below */
-
BUG_ON(atomic_read(&vha->vref_count));
qla2x00_free_fcports(vha);
@@ -2092,6 +2117,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
FC_PORTSPEED_1GBIT;
else if (IS_QLA23XX(ha))
speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
+ else if (IS_QLAFX00(ha))
+ speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
+ FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
else
speed = FC_PORTSPEED_1GBIT;
fc_host_supported_speeds(vha->host) = speed;
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index ad54099cb805..39719f892488 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -30,14 +30,31 @@ qla2x00_bsg_sp_free(void *data, void *ptr)
struct scsi_qla_host *vha = sp->fcport->vha;
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
struct qla_hw_data *ha = vha->hw;
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
- dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
- bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (sp->type == SRB_FXIOCB_BCMD) {
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
- dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
- bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ }
if (sp->type == SRB_CT_CMD ||
+ sp->type == SRB_FXIOCB_BCMD ||
sp->type == SRB_ELS_CMD_HST)
kfree(sp->fcport);
qla2x00_rel_sp(vha, sp);
@@ -751,6 +768,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
elreq.transfer_size = req_data_len;
elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+ elreq.iteration_count =
+ bsg_job->request->rqst_data.h_vendor.vendor_cmd[2];
if (atomic_read(&vha->loop_state) == LOOP_READY &&
(ha->current_topology == ISP_CFG_F ||
@@ -1883,6 +1902,128 @@ done:
}
static int
+qlafx00_mgmt_cmd(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = (DRIVER_ERROR << 16);
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
+ srb_t *sp;
+ int req_sg_cnt = 0, rsp_sg_cnt = 0;
+ struct fc_port *fcport;
+ char *type = "FC_BSG_HST_FX_MGMT";
+
+ /* Copy the IOCB specific information */
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+ /* Dump the vendor information */
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf,
+ (uint8_t *)piocb_rqst, sizeof(struct qla_mt_iocb_rqst_fx00));
+
+ if (!vha->flags.online) {
+ ql_log(ql_log_warn, vha, 0x70d0,
+ "Host is not online.\n");
+ rval = -EIO;
+ goto done;
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
+ req_sg_cnt = dma_map_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (!req_sg_cnt) {
+ ql_log(ql_log_warn, vha, 0x70c7,
+ "dma_map_sg return %d for request\n", req_sg_cnt);
+ rval = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
+ rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (!rsp_sg_cnt) {
+ ql_log(ql_log_warn, vha, 0x70c8,
+ "dma_map_sg return %d for reply\n", rsp_sg_cnt);
+ rval = -ENOMEM;
+ goto done_unmap_req_sg;
+ }
+ }
+
+ ql_dbg(ql_dbg_user, vha, 0x70c9,
+ "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
+ "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
+ req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
+
+ /* Allocate a dummy fcport structure, since functions preparing the
+ * IOCB and mailbox command retrieves port specific information
+ * from fcport structure. For Host based ELS commands there will be
+ * no fcport structure allocated
+ */
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_warn, vha, 0x70ca,
+ "Failed to allocate fcport.\n");
+ rval = -ENOMEM;
+ goto done_unmap_rsp_sg;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ ql_log(ql_log_warn, vha, 0x70cb,
+ "qla2x00_get_sp failed.\n");
+ rval = -ENOMEM;
+ goto done_free_fcport;
+ }
+
+ /* Initialize all required fields of fcport */
+ fcport->vha = vha;
+ fcport->loop_id = piocb_rqst->dataword;
+
+ sp->type = SRB_FXIOCB_BCMD;
+ sp->name = "bsg_fx_mgmt";
+ sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
+ sp->u.bsg_job = bsg_job;
+ sp->free = qla2x00_bsg_sp_free;
+ sp->done = qla2x00_bsg_job_done;
+
+ ql_dbg(ql_dbg_user, vha, 0x70cc,
+ "bsg rqst type: %s fx_mgmt_type: %x id=%x\n",
+ type, piocb_rqst->func_type, fcport->loop_id);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x70cd,
+ "qla2x00_start_sp failed=%d.\n", rval);
+ mempool_free(sp, ha->srb_mempool);
+ rval = -EIO;
+ goto done_free_fcport;
+ }
+ return rval;
+
+done_free_fcport:
+ kfree(fcport);
+
+done_unmap_rsp_sg:
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done_unmap_req_sg:
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+done:
+ return rval;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -1928,6 +2069,8 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_DIAG_IO_CMD:
return qla24xx_process_bidir_cmd(bsg_job);
+ case QL_VND_FX00_MGMT_CMD:
+ return qlafx00_mgmt_cmd(bsg_job);
default:
return -ENOSYS;
}
@@ -2007,7 +2150,8 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
sp = req->outstanding_cmds[cnt];
if (sp) {
if (((sp->type == SRB_CT_CMD) ||
- (sp->type == SRB_ELS_CMD_HST))
+ (sp->type == SRB_ELS_CMD_HST) ||
+ (sp->type == SRB_FXIOCB_BCMD))
&& (sp->u.bsg_job == bsg_job)) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index e9f6b9bbf29a..04f770332c2b 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -22,6 +22,7 @@
#define QL_VND_DIAG_IO_CMD 0x0A
#define QL_VND_WRITE_I2C 0x10
#define QL_VND_READ_I2C 0x11
+#define QL_VND_FX00_MGMT_CMD 0x12
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 1626de52e32a..cfa2a20dee97 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,27 +11,31 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x0126 | 0x4b,0xba,0xfa |
- * | Mailbox commands | 0x115b | 0x111a-0x111b |
- * | | | 0x112c-0x112e |
- * | | | 0x113a |
- * | Device Discovery | 0x2087 | 0x2020-0x2022, |
+ * | Module Init and Probe | 0x014f | 0x4b,0xba,0xfa |
+ * | Mailbox commands | 0x1179 | 0x111a-0x111b |
+ * | | | 0x1155-0x1158 |
+ * | Device Discovery | 0x2095 | 0x2020-0x2022, |
* | | | 0x2016 |
- * | Queue Command and IO tracing | 0x3031 | 0x3006-0x300b |
+ * | Queue Command and IO tracing | 0x3058 | 0x3006-0x300b |
* | | | 0x3027-0x3028 |
- * | | | 0x302d-0x302e |
- * | DPC Thread | 0x401d | 0x4002,0x4013 |
- * | Async Events | 0x5071 | 0x502b-0x502f |
+ * | | | 0x303d-0x3041 |
+ * | | | 0x302d,0x3033 |
+ * | | | 0x3036,0x3038 |
+ * | | | 0x303a |
+ * | DPC Thread | 0x4022 | 0x4002,0x4013 |
+ * | Async Events | 0x5081 | 0x502b-0x502f |
* | | | 0x5047,0x5052 |
+ * | | | 0x5040,0x5075 |
* | Timer Routines | 0x6011 | |
- * | User Space Interactions | 0x70c4 | 0x7018,0x702e, |
+ * | User Space Interactions | 0x70dd | 0x7018,0x702e, |
* | | | 0x7020,0x7024, |
* | | | 0x7039,0x7045, |
* | | | 0x7073-0x7075, |
- * | | | 0x708c, |
+ * | | | 0x707b,0x708c, |
* | | | 0x70a5,0x70a6, |
* | | | 0x70a8,0x70ab, |
- * | | | 0x70ad-0x70ae |
+ * | | | 0x70ad-0x70ae, |
+ * | | | 0x70d1-0x70da |
* | Task Management | 0x803c | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
@@ -401,7 +405,7 @@ qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr,
void *ring;
} aq, *aqp;
- if (!ha->tgt.atio_q_length)
+ if (!ha->tgt.atio_ring)
return ptr;
num_queues = 1;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c6509911772b..c32efc753229 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -245,7 +245,6 @@
#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */
#include "qla_fw.h"
-
/*
* Timeout timer counts in seconds
*/
@@ -265,6 +264,7 @@
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
+#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
struct req_que;
@@ -284,6 +284,7 @@ struct sd_dif_tuple {
struct srb_cmd {
struct scsi_cmnd *cmd; /* Linux SCSI command pkt */
uint32_t request_sense_length;
+ uint32_t fw_sense_length;
uint8_t *request_sense_ptr;
void *ctx;
};
@@ -321,7 +322,39 @@ struct srb_iocb {
uint32_t flags;
uint32_t lun;
uint32_t data;
+ struct completion comp;
+ uint32_t comp_status;
} tmf;
+ struct {
+#define SRB_FXDISC_REQ_DMA_VALID BIT_0
+#define SRB_FXDISC_RESP_DMA_VALID BIT_1
+#define SRB_FXDISC_REQ_DWRD_VALID BIT_2
+#define SRB_FXDISC_RSP_DWRD_VALID BIT_3
+#define FXDISC_TIMEOUT 20
+ uint8_t flags;
+ uint32_t req_len;
+ uint32_t rsp_len;
+ void *req_addr;
+ void *rsp_addr;
+ dma_addr_t req_dma_handle;
+ dma_addr_t rsp_dma_handle;
+ uint32_t adapter_id;
+ uint32_t adapter_id_hi;
+ uint32_t req_func_type;
+ uint32_t req_data;
+ uint32_t req_data_extra;
+ uint32_t result;
+ uint32_t seq_number;
+ uint32_t fw_flags;
+ struct completion fxiocb_comp;
+ uint32_t reserved_0;
+ uint8_t reserved_1;
+ } fxiocb;
+ struct {
+ uint32_t cmd_hndl;
+ uint32_t comp_status;
+ struct completion comp;
+ } abt;
} u;
struct timer_list timer;
@@ -338,6 +371,10 @@ struct srb_iocb {
#define SRB_TM_CMD 7
#define SRB_SCSI_CMD 8
#define SRB_BIDI_CMD 9
+#define SRB_FXIOCB_DCMD 10
+#define SRB_FXIOCB_BCMD 11
+#define SRB_ABT_CMD 12
+
typedef struct srb {
atomic_t ref_count;
@@ -368,6 +405,10 @@ typedef struct srb {
(sp->u.scmd.request_sense_ptr)
#define SET_CMD_SENSE_PTR(sp, ptr) \
(sp->u.scmd.request_sense_ptr = ptr)
+#define GET_FW_SENSE_LEN(sp) \
+ (sp->u.scmd.fw_sense_length)
+#define SET_FW_SENSE_LEN(sp, len) \
+ (sp->u.scmd.fw_sense_length = len)
struct msg_echo_lb {
dma_addr_t send_dma;
@@ -376,6 +417,7 @@ struct msg_echo_lb {
uint16_t rsp_sg_cnt;
uint16_t options;
uint32_t transfer_size;
+ uint32_t iteration_count;
};
/*
@@ -542,11 +584,74 @@ struct device_reg_25xxmq {
uint32_t atio_q_out;
};
+
+struct device_reg_fx00 {
+ uint32_t mailbox0; /* 00 */
+ uint32_t mailbox1; /* 04 */
+ uint32_t mailbox2; /* 08 */
+ uint32_t mailbox3; /* 0C */
+ uint32_t mailbox4; /* 10 */
+ uint32_t mailbox5; /* 14 */
+ uint32_t mailbox6; /* 18 */
+ uint32_t mailbox7; /* 1C */
+ uint32_t mailbox8; /* 20 */
+ uint32_t mailbox9; /* 24 */
+ uint32_t mailbox10; /* 28 */
+ uint32_t mailbox11;
+ uint32_t mailbox12;
+ uint32_t mailbox13;
+ uint32_t mailbox14;
+ uint32_t mailbox15;
+ uint32_t mailbox16;
+ uint32_t mailbox17;
+ uint32_t mailbox18;
+ uint32_t mailbox19;
+ uint32_t mailbox20;
+ uint32_t mailbox21;
+ uint32_t mailbox22;
+ uint32_t mailbox23;
+ uint32_t mailbox24;
+ uint32_t mailbox25;
+ uint32_t mailbox26;
+ uint32_t mailbox27;
+ uint32_t mailbox28;
+ uint32_t mailbox29;
+ uint32_t mailbox30;
+ uint32_t mailbox31;
+ uint32_t aenmailbox0;
+ uint32_t aenmailbox1;
+ uint32_t aenmailbox2;
+ uint32_t aenmailbox3;
+ uint32_t aenmailbox4;
+ uint32_t aenmailbox5;
+ uint32_t aenmailbox6;
+ uint32_t aenmailbox7;
+ /* Request Queue. */
+ uint32_t req_q_in; /* A0 - Request Queue In-Pointer */
+ uint32_t req_q_out; /* A4 - Request Queue Out-Pointer */
+ /* Response Queue. */
+ uint32_t rsp_q_in; /* A8 - Response Queue In-Pointer */
+ uint32_t rsp_q_out; /* AC - Response Queue Out-Pointer */
+ /* Init values shadowed on FW Up Event */
+ uint32_t initval0; /* B0 */
+ uint32_t initval1; /* B4 */
+ uint32_t initval2; /* B8 */
+ uint32_t initval3; /* BC */
+ uint32_t initval4; /* C0 */
+ uint32_t initval5; /* C4 */
+ uint32_t initval6; /* C8 */
+ uint32_t initval7; /* CC */
+ uint32_t fwheartbeat; /* D0 */
+};
+
+
+
typedef union {
struct device_reg_2xxx isp;
struct device_reg_24xx isp24;
struct device_reg_25xxmq isp25mq;
struct device_reg_82xx isp82;
+ struct device_reg_fx00 ispfx00;
} device_reg_t;
#define ISP_REQ_Q_IN(ha, reg) \
@@ -602,6 +707,20 @@ typedef struct {
#define IOCTL_CMD BIT_2
} mbx_cmd_t;
+struct mbx_cmd_32 {
+ uint32_t out_mb; /* outbound from driver */
+ uint32_t in_mb; /* Incoming from RISC */
+ uint32_t mb[MAILBOX_REGISTER_COUNT];
+ long buf_size;
+ void *bufp;
+ uint32_t tov;
+ uint8_t flags;
+#define MBX_DMA_IN BIT_0
+#define MBX_DMA_OUT BIT_1
+#define IOCTL_CMD BIT_2
+};
+
+
#define MBX_TOV_SECONDS 30
/*
@@ -677,6 +796,15 @@ typedef struct {
#define MBA_BYPASS_NOTIFICATION 0x8043 /* Auto bypass notification. */
#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */
#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */
+#define MBA_FW_NOT_STARTED 0x8050 /* Firmware not started */
+#define MBA_FW_STARTING 0x8051 /* Firmware starting */
+#define MBA_FW_RESTART_CMPLT 0x8060 /* Firmware restart complete */
+#define MBA_INIT_REQUIRED 0x8061 /* Initialization required */
+#define MBA_SHUTDOWN_REQUESTED 0x8062 /* Shutdown Requested */
+#define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */
+#define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change
+ Notification */
+#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
/* 83XX FCoE specific */
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
@@ -798,6 +926,12 @@ typedef struct {
#define MBC_LUN_RESET 0x7E /* Send LUN reset */
/*
+ * all the Mt. Rainier mailbox command codes that clash with FC/FCoE ones
+ * should be defined with MBC_MR_*
+ */
+#define MBC_MR_DRV_SHUTDOWN 0x6A
+
+/*
* ISP24xx mailbox commands
*/
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
@@ -863,7 +997,6 @@ typedef struct {
#define MBX_1 BIT_1
#define MBX_0 BIT_0
-#define RNID_TYPE_SET_VERSION 0x9
#define RNID_TYPE_ASIC_TEMP 0xC
/*
@@ -1059,6 +1192,30 @@ typedef struct {
uint8_t reserved_3[26];
} init_cb_t;
+
+struct init_cb_fx {
+ uint16_t version;
+ uint16_t reserved_1[13];
+ uint16_t request_q_outpointer;
+ uint16_t response_q_inpointer;
+ uint16_t reserved_2[2];
+ uint16_t response_q_length;
+ uint16_t request_q_length;
+ uint16_t reserved_3[2];
+ uint32_t request_q_address[2];
+ uint32_t response_q_address[2];
+ uint16_t reserved_4[4];
+ uint8_t response_q_msivec;
+ uint8_t reserved_5[19];
+ uint16_t interrupt_delay_timer;
+ uint16_t reserved_6;
+ uint32_t fwoptions1;
+ uint32_t fwoptions2;
+ uint32_t fwoptions3;
+ uint8_t reserved_7[24];
+};
+
+
/*
* Get Link Status mailbox command return buffer.
*/
@@ -1832,6 +1989,9 @@ typedef struct fc_port {
uint16_t loop_id;
uint16_t old_loop_id;
+ uint16_t tgt_id;
+ uint16_t old_tgt_id;
+
uint8_t fcp_prio;
uint8_t fabric_port_name[WWN_SIZE];
@@ -1849,8 +2009,15 @@ typedef struct fc_port {
uint8_t fc4_type;
uint8_t scan_state;
+
+ unsigned long last_queue_full;
+ unsigned long last_ramp_up;
+
+ uint16_t port_id;
} fc_port_t;
+#include "qla_mr.h"
+
/*
* Fibre channel port/lun states.
*/
@@ -2392,6 +2559,7 @@ struct isp_operations {
int (*start_scsi) (srb_t *);
int (*abort_isp) (struct scsi_qla_host *);
int (*iospace_config)(struct qla_hw_data*);
+ int (*initialize_adapter)(struct scsi_qla_host *);
};
/* MSI-X Support *************************************************************/
@@ -2430,6 +2598,7 @@ enum qla_work_type {
QLA_EVT_ASYNC_ADISC,
QLA_EVT_ASYNC_ADISC_DONE,
QLA_EVT_UEVENT,
+ QLA_EVT_AENFX,
};
@@ -2457,7 +2626,15 @@ struct qla_work_evt {
u32 code;
#define QLA_UEVENT_CODE_FW_DUMP 0
} uevent;
- } u;
+ struct {
+ uint32_t evtcode;
+ uint32_t mbx[8];
+ uint32_t count;
+ } aenfx;
+ struct {
+ srb_t *sp;
+ } iosb;
+ } u;
};
struct qla_chip_state_84xx {
@@ -2521,6 +2698,11 @@ struct rsp_que {
struct req_que *req;
srb_t *status_srb; /* status continuation entry */
struct work_struct q_work;
+
+ dma_addr_t dma_fx00;
+ response_t *ring_fx00;
+ uint16_t length_fx00;
+ uint8_t rsp_pkt[REQUEST_ENTRY_SIZE];
};
/* Request queue data structure */
@@ -2545,6 +2727,11 @@ struct req_que {
uint16_t num_outstanding_cmds;
#define MAX_Q_DEPTH 32
int max_q_depth;
+
+ dma_addr_t dma_fx00;
+ request_t *ring_fx00;
+ uint16_t length_fx00;
+ uint8_t req_pkt[REQUEST_ENTRY_SIZE];
};
/* Place holder for FW buffer parameters */
@@ -2634,7 +2821,10 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
- /* 32 bits */
+
+ uint32_t mr_reset_hdlr_active:1;
+ uint32_t mr_intr_valid:1;
+ /* 34 bits */
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2651,7 +2841,21 @@ struct qla_hw_data {
resource_size_t pio_address;
#define MIN_IOBASE_LEN 0x100
-/* Multi queue data structs */
+ dma_addr_t bar0_hdl;
+
+ void __iomem *cregbase;
+ dma_addr_t bar2_hdl;
+#define BAR0_LEN_FX00 (1024 * 1024)
+#define BAR2_LEN_FX00 (128 * 1024)
+
+ uint32_t rqstq_intr_code;
+ uint32_t mbx_intr_code;
+ uint32_t req_que_len;
+ uint32_t rsp_que_len;
+ uint32_t req_que_off;
+ uint32_t rsp_que_off;
+
+ /* Multi queue data structs */
device_reg_t __iomem *mqiobase;
device_reg_t __iomem *msixbase;
uint16_t msix_count;
@@ -2730,7 +2934,8 @@ struct qla_hw_data {
#define DT_ISP8021 BIT_14
#define DT_ISP2031 BIT_15
#define DT_ISP8031 BIT_16
-#define DT_ISP_LAST (DT_ISP8031 << 1)
+#define DT_ISPFX00 BIT_17
+#define DT_ISP_LAST (DT_ISPFX00 << 1)
#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
@@ -2758,6 +2963,7 @@ struct qla_hw_data {
#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031)
#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031)
+#define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2822,6 +3028,7 @@ struct qla_hw_data {
uint16_t r_a_tov;
int port_down_retry_count;
uint8_t mbx_count;
+ uint8_t aen_mbx_count;
uint32_t login_retry_count;
/* SNS command interfaces. */
@@ -2869,9 +3076,13 @@ struct qla_hw_data {
void *swl;
/* These are used by mailbox operations. */
- volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+ uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+ uint32_t mailbox_out32[MAILBOX_REGISTER_COUNT];
+ uint32_t aenmb[AEN_MAILBOX_REGISTER_COUNT_FX00];
mbx_cmd_t *mcp;
+ struct mbx_cmd_32 *mcp32;
+
unsigned long mbx_cmd_flags;
#define MBX_INTERRUPT 1
#define MBX_INTR_WAIT 2
@@ -3015,6 +3226,7 @@ struct qla_hw_data {
int cur_vport_count;
struct qla_chip_state_84xx *cs84xx;
+ struct qla_statistics qla_stats;
struct isp_operations *isp_ops;
struct workqueue_struct *wq;
struct qlfc_fw fw_buf;
@@ -3081,6 +3293,8 @@ struct qla_hw_data {
unsigned long host_last_rampup_time;
int cfg_lun_q_depth;
+ struct mr_data_fx00 mr;
+
struct qlt_hw_data tgt;
uint16_t thermal_support;
#define THERMAL_SUPPORT_I2C BIT_0
@@ -3110,6 +3324,8 @@ typedef struct scsi_qla_host {
uint32_t process_response_queue :1;
uint32_t difdix_supported:1;
uint32_t delete_progress:1;
+
+ uint32_t fw_tgt_reported:1;
} flags;
atomic_t loop_state;
@@ -3145,6 +3361,9 @@ typedef struct scsi_qla_host {
#define SCR_PENDING 21 /* SCR in target mode */
#define HOST_RAMP_DOWN_QUEUE_DEPTH 22
#define HOST_RAMP_UP_QUEUE_DEPTH 23
+#define PORT_UPDATE_NEEDED 24
+#define FX00_RESET_RECOVERY 25
+#define FX00_TARGET_SCAN 26
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
@@ -3235,6 +3454,10 @@ struct qla_tgt_vp_map {
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
atomic_read(&ha->loop_state) == LOOP_DOWN)
+#define STATE_TRANSITION(ha) \
+ (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \
+ test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+
#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \
atomic_inc(&__vha->vref_count); \
mb(); \
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index eb3ca21a7f17..026bfde33e67 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -86,6 +86,7 @@ extern int qla2xxx_mctp_dump(scsi_qla_host_t *);
extern int
qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *);
+extern int qla2x00_init_rings(scsi_qla_host_t *);
/*
* Global Data in qla_os.c source file.
@@ -134,7 +135,6 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
-extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -158,6 +158,7 @@ extern int qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
+extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
/*
* Global Functions in qla_mid.c source file.
@@ -211,8 +212,6 @@ extern int qla24xx_start_scsi(srb_t *sp);
int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
-extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t);
-extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
extern int qla24xx_dif_start_scsi(srb_t *);
extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t);
extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *);
@@ -358,9 +357,6 @@ extern int
qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
extern int
-qla2x00_set_driver_version(scsi_qla_host_t *, char *);
-
-extern int
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *,
uint16_t, uint16_t, uint16_t, uint16_t);
@@ -427,6 +423,12 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
extern int qla2x00_get_data_rate(scsi_qla_host_t *);
extern const char *qla2x00_get_link_speed_str(struct qla_hw_data *, uint16_t);
+extern srb_t *
+qla2x00_get_sp_from_handle(scsi_qla_host_t *, const char *, struct req_que *,
+ void *);
+extern void
+qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *,
+ uint32_t);
/*
* Global Function Prototypes in qla_sup.c source file.
@@ -564,6 +566,42 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+/* qlafx00 related functions */
+extern int qlafx00_pci_config(struct scsi_qla_host *);
+extern int qlafx00_initialize_adapter(struct scsi_qla_host *);
+extern void qlafx00_soft_reset(scsi_qla_host_t *);
+extern int qlafx00_chip_diag(scsi_qla_host_t *);
+extern void qlafx00_config_rings(struct scsi_qla_host *);
+extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
+extern char *qlafx00_fw_version_str(struct scsi_qla_host *, char *);
+extern irqreturn_t qlafx00_intr_handler(int, void *);
+extern void qlafx00_enable_intrs(struct qla_hw_data *);
+extern void qlafx00_disable_intrs(struct qla_hw_data *);
+extern int qlafx00_abort_command(srb_t *);
+extern int qlafx00_abort_target(fc_port_t *, unsigned int, int);
+extern int qlafx00_lun_reset(fc_port_t *, unsigned int, int);
+extern int qlafx00_start_scsi(srb_t *);
+extern int qlafx00_abort_isp(scsi_qla_host_t *);
+extern int qlafx00_iospace_config(struct qla_hw_data *);
+extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
+extern int qlafx00_fw_ready(scsi_qla_host_t *);
+extern int qlafx00_configure_devices(scsi_qla_host_t *);
+extern int qlafx00_reset_initialize(scsi_qla_host_t *);
+extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint8_t);
+extern int qlafx00_process_aen(struct scsi_qla_host *, struct qla_work_evt *);
+extern int qlafx00_post_aenfx_work(struct scsi_qla_host *, uint32_t,
+ uint32_t *, int);
+extern uint32_t qlafx00_fw_state_show(struct device *,
+ struct device_attribute *, char *);
+extern void qlafx00_get_host_speed(struct Scsi_Host *);
+extern void qlafx00_init_response_q_entries(struct rsp_que *);
+
+extern void qlafx00_tm_iocb(srb_t *, struct tsk_mgmt_entry_fx00 *);
+extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
+extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
+extern void qlafx00_timer_routine(scsi_qla_host_t *);
+extern int qlafx00_rescan_isp(scsi_qla_host_t *);
+
/* qla82xx related functions */
/* PCI related functions */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 9b455250c101..d0ea8b921177 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -639,9 +639,14 @@ void
qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn)
{
struct qla_hw_data *ha = vha->hw;
- sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
- ha->fw_major_version, ha->fw_minor_version,
- ha->fw_subminor_version, qla2x00_version_str);
+
+ if (IS_QLAFX00(ha))
+ sprintf(snn, "%s FW:v%s DVR:v%s", ha->model_number,
+ ha->mr.fw_version, qla2x00_version_str);
+ else
+ sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s", ha->model_number,
+ ha->fw_major_version, ha->fw_minor_version,
+ ha->fw_subminor_version, qla2x00_version_str);
}
/**
@@ -923,7 +928,7 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
sns_cmd->p.gpn_data[9] != 0x02) {
ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e,
"GPN_ID failed, rejected request, gpn_rsp:\n");
- ql_dump_buffer(ql_dbg_disc, vha, 0x207f,
+ ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207f,
sns_cmd->p.gpn_data, 16);
rval = QLA_FUNCTION_FAILED;
} else {
@@ -1718,7 +1723,8 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA2100(ha) || IS_QLA2200(ha))
+ if (IS_QLA2100(ha) || IS_QLA2200(ha) ||
+ IS_QLAFX00(ha))
return QLA_FUNCTION_FAILED;
rval = qla2x00_mgmt_svr_login(vha);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index edf4d14a1335..3565dfd8f370 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -25,7 +25,6 @@
*/
static int qla2x00_isp_firmware(scsi_qla_host_t *);
static int qla2x00_setup_chip(scsi_qla_host_t *);
-static int qla2x00_init_rings(scsi_qla_host_t *);
static int qla2x00_fw_ready(scsi_qla_host_t *);
static int qla2x00_configure_hba(scsi_qla_host_t *);
static int qla2x00_configure_loop(scsi_qla_host_t *);
@@ -83,7 +82,9 @@ qla2x00_get_async_timeout(struct scsi_qla_host *vha)
/* Firmware should use switch negotiated r_a_tov for timeout. */
tmo = ha->r_a_tov / 10 * 2;
- if (!IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(ha)) {
+ tmo = FX00_DEF_RATOV * 2;
+ } else if (!IS_FWI2_CAPABLE(ha)) {
/*
* Except for earlier ISPs where the timeout is seeded from the
* initialization control block.
@@ -619,8 +620,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
qla24xx_read_fcp_prio_cfg(vha);
- qla2x00_set_driver_version(vha, QLA2XXX_VERSION);
-
return (rval);
}
@@ -1399,7 +1398,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mq_size += ha->max_rsp_queues *
(rsp->length * sizeof(response_t));
}
- if (ha->tgt.atio_q_length)
+ if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
@@ -1979,7 +1978,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
*
* Returns 0 on success.
*/
-static int
+int
qla2x00_init_rings(scsi_qla_host_t *vha)
{
int rval;
@@ -2014,7 +2013,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (!rsp)
continue;
/* Initialize response queue entries */
- qla2x00_init_response_q_entries(rsp);
+ if (IS_QLAFX00(ha))
+ qlafx00_init_response_q_entries(rsp);
+ else
+ qla2x00_init_response_q_entries(rsp);
}
ha->tgt.atio_ring_ptr = ha->tgt.atio_ring;
@@ -2026,11 +2028,16 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
+
+ if (IS_QLAFX00(ha)) {
+ rval = qlafx00_init_firmware(vha, ha->init_cb_size);
+ goto next_check;
+ }
+
/* Update any ISP specific firmware options before initialization. */
ha->isp_ops->update_fw_options(vha);
- ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
-
if (ha->flags.npiv_supported) {
if (ha->operating_mode == LOOP && !IS_CNA_CAPABLE(ha))
ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
@@ -2044,6 +2051,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
}
rval = qla2x00_init_firmware(vha, ha->init_cb_size);
+next_check:
if (rval) {
ql_log(ql_log_fatal, vha, 0x00d2,
"Init Firmware **** FAILED ****.\n");
@@ -2071,6 +2079,9 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
uint16_t state[5];
struct qla_hw_data *ha = vha->hw;
+ if (IS_QLAFX00(vha->hw))
+ return qlafx00_fw_ready(vha);
+
rval = QLA_SUCCESS;
/* 20 seconds for loop down. */
@@ -3136,6 +3147,12 @@ void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
fcport->vha = vha;
+
+ if (IS_QLAFX00(vha->hw)) {
+ qla2x00_set_fcport_state(fcport, FCS_ONLINE);
+ qla2x00_reg_remote_port(vha, fcport);
+ return;
+ }
fcport->login_retry = 0;
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
@@ -3896,15 +3913,24 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
- /* Issue a marker after FW becomes ready. */
- qla2x00_marker(vha, req, rsp, 0, 0,
- MK_SYNC_ALL);
- vha->marker_needed = 0;
+ if (!IS_QLAFX00(vha->hw)) {
+ /*
+ * Issue a marker after FW becomes
+ * ready.
+ */
+ qla2x00_marker(vha, req, rsp, 0, 0,
+ MK_SYNC_ALL);
+ vha->marker_needed = 0;
+ }
/* Remap devices on Loop. */
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
- qla2x00_configure_loop(vha);
+ if (IS_QLAFX00(vha->hw))
+ qlafx00_configure_devices(vha);
+ else
+ qla2x00_configure_loop(vha);
+
wait_time--;
} while (!atomic_read(&vha->loop_down_timer) &&
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
@@ -3970,9 +3996,7 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
if (fcport->drport &&
atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
spin_unlock_irqrestore(&ha->vport_slock, flags);
-
qla2x00_rport_del(fcport);
-
spin_lock_irqsave(&ha->vport_slock, flags);
}
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 68e2c4afc134..98ab921070d2 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -5,6 +5,28 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
+/**
+ * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
+ * Continuation Type 1 IOCBs to allocate.
+ *
+ * @dsds: number of data segment decriptors needed
+ *
+ * Returns the number of IOCB entries needed to store @dsds.
+ */
+static inline uint16_t
+qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
+{
+ uint16_t iocbs;
+
+ iocbs = 1;
+ if (dsds > 1) {
+ iocbs += (dsds - 1) / 5;
+ if ((dsds - 1) % 5)
+ iocbs++;
+ }
+ return iocbs;
+}
+
/*
* qla2x00_debounce_register
* Debounce register.
@@ -58,6 +80,17 @@ host_to_fcp_swap(uint8_t *fcp, uint32_t bsize)
}
static inline void
+host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
+{
+ uint32_t *isrc = (uint32_t *) src;
+ uint32_t *odest = (uint32_t *) dst;
+ uint32_t iter = bsize >> 2;
+
+ for (; iter ; iter--)
+ *odest++ = cpu_to_le32(*isrc++);
+}
+
+static inline void
qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
{
int i;
@@ -213,12 +246,18 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout;
add_timer(&sp->u.iocb_cmd.timer);
sp->free = qla2x00_sp_free;
+ if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
+ (sp->type == SRB_FXIOCB_DCMD))
+ init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
}
static inline int
qla2x00_gid_list_size(struct qla_hw_data *ha)
{
- return sizeof(struct gid_list_info) * ha->max_fibre_devices;
+ if (IS_QLAFX00(ha))
+ return sizeof(uint32_t) * 32;
+ else
+ return sizeof(struct gid_list_info) * ha->max_fibre_devices;
}
static inline void
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index d2630317cce8..15e4080b347c 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -135,7 +135,8 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
/* Load packet defaults. */
- *((uint32_t *)(&cont_pkt->entry_type)) =
+ *((uint32_t *)(&cont_pkt->entry_type)) = IS_QLAFX00(vha->hw) ?
+ __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00) :
__constant_cpu_to_le32(CONTINUE_A64_TYPE);
return (cont_pkt);
@@ -486,6 +487,10 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
if (ha->mqenable || IS_QLA83XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
+ } else if (IS_QLAFX00(ha)) {
+ WRT_REG_DWORD(&reg->ispfx00.req_q_in, req->ring_index);
+ RD_REG_DWORD_RELAXED(&reg->ispfx00.req_q_in);
+ QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
@@ -514,11 +519,12 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
uint16_t lun, uint8_t type)
{
mrk_entry_t *mrk;
- struct mrk_entry_24xx *mrk24;
+ struct mrk_entry_24xx *mrk24 = NULL;
+ struct mrk_entry_fx00 *mrkfx = NULL;
+
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- mrk24 = NULL;
req = ha->req_q_map[0];
mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, NULL);
if (mrk == NULL) {
@@ -531,7 +537,15 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(ha)) {
+ mrkfx = (struct mrk_entry_fx00 *) mrk;
+ mrkfx->handle = MAKE_HANDLE(req->id, mrkfx->handle);
+ mrkfx->handle_hi = 0;
+ mrkfx->tgt_id = cpu_to_le16(loop_id);
+ mrkfx->lun[1] = LSB(lun);
+ mrkfx->lun[2] = MSB(lun);
+ host_to_fcp_swap(mrkfx->lun, sizeof(mrkfx->lun));
+ } else if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
@@ -589,28 +603,6 @@ int qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked)
return QLA_SUCCESS;
}
-/**
- * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
- * Continuation Type 1 IOCBs to allocate.
- *
- * @dsds: number of data segment decriptors needed
- *
- * Returns the number of IOCB entries needed to store @dsds.
- */
-inline uint16_t
-qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
-{
- uint16_t iocbs;
-
- iocbs = 1;
- if (dsds > 1) {
- iocbs += (dsds - 1) / 5;
- if ((dsds - 1) % 5)
- iocbs++;
- }
- return iocbs;
-}
-
static inline int
qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
uint16_t tot_dsds)
@@ -1583,7 +1575,6 @@ queuing_error:
return QLA_FUNCTION_FAILED;
}
-
/**
* qla24xx_dif_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
@@ -1852,6 +1843,8 @@ skip_cmd_array:
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
+ else if (IS_QLAFX00(ha))
+ cnt = RD_REG_DWORD(&reg->ispfx00.req_q_out);
else
cnt = qla2x00_debounce_register(
ISP_REQ_Q_OUT(ha, &reg->isp));
@@ -1869,8 +1862,13 @@ skip_cmd_array:
req->cnt -= req_cnt;
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
- pkt->entry_count = req_cnt;
- pkt->handle = handle;
+ if (IS_QLAFX00(ha)) {
+ WRT_REG_BYTE(&pkt->entry_count, req_cnt);
+ WRT_REG_WORD(&pkt->handle, handle);
+ } else {
+ pkt->entry_count = req_cnt;
+ pkt->handle = handle;
+ }
queuing_error:
return pkt;
@@ -2625,7 +2623,16 @@ qla2x00_start_sp(srb_t *sp)
qla2x00_adisc_iocb(sp, pkt);
break;
case SRB_TM_CMD:
- qla24xx_tm_iocb(sp, pkt);
+ IS_QLAFX00(ha) ?
+ qlafx00_tm_iocb(sp, pkt) :
+ qla24xx_tm_iocb(sp, pkt);
+ break;
+ case SRB_FXIOCB_DCMD:
+ case SRB_FXIOCB_BCMD:
+ qlafx00_fxdisc_iocb(sp, pkt);
+ break;
+ case SRB_ABT_CMD:
+ qlafx00_abort_iocb(sp, pkt);
break;
default:
break;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e9dbd74c20d3..259d9205d876 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -13,11 +13,7 @@
#include <scsi/scsi_bsg_fc.h>
#include <scsi/scsi_eh.h>
-#include "qla_target.h"
-
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_process_completed_request(struct scsi_qla_host *,
- struct req_que *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
@@ -1065,9 +1061,9 @@ skip_rio:
* @ha: SCSI driver HA context
* @index: SRB index
*/
-static void
+void
qla2x00_process_completed_request(struct scsi_qla_host *vha,
- struct req_que *req, uint32_t index)
+ struct req_que *req, uint32_t index)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
@@ -1101,7 +1097,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
}
}
-static srb_t *
+srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
struct req_que *req, void *iocb)
{
@@ -1994,7 +1990,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
- lscsi_status = scsi_status & STATUS_MASK;
+ lscsi_status = scsi_status & STATUS_MASK;
fcport = sp->fcport;
@@ -2939,7 +2935,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
/* If possible, enable MSI-X. */
if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha))
goto skip_msi;
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -2972,7 +2968,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
skip_msix:
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_QLA8001(ha) && !IS_QLA82XX(ha))
+ !IS_QLA8001(ha) && !IS_QLA82XX(ha) && !IS_QLAFX00(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
@@ -2998,9 +2994,11 @@ skip_msi:
"Failed to reserve interrupt %d already in use.\n",
ha->pdev->irq);
goto fail;
- } else if (!ha->flags.msi_enabled)
+ } else if (!ha->flags.msi_enabled) {
ql_dbg(ql_dbg_init, vha, 0x0125,
"INTa mode: Enabled.\n");
+ ha->flags.mr_intr_valid = 1;
+ }
clear_risc_ints:
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 186dd59ce4fa..9e5d89db7272 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3866,64 +3866,6 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
return rval;
}
-int
-qla2x00_set_driver_version(scsi_qla_host_t *vha, char *version)
-{
- int rval;
- mbx_cmd_t mc;
- mbx_cmd_t *mcp = &mc;
- int len;
- uint16_t dwlen;
- uint8_t *str;
- dma_addr_t str_dma;
- struct qla_hw_data *ha = vha->hw;
-
- if (!IS_FWI2_CAPABLE(ha) || IS_QLA82XX(ha))
- return QLA_FUNCTION_FAILED;
-
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1155,
- "Entered %s.\n", __func__);
-
- str = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &str_dma);
- if (!str) {
- ql_log(ql_log_warn, vha, 0x1156,
- "Failed to allocate driver version param.\n");
- return QLA_MEMORY_ALLOC_FAILED;
- }
-
- memcpy(str, "\x7\x3\x11\x0", 4);
- dwlen = str[0];
- len = dwlen * sizeof(uint32_t) - 4;
- memset(str + 4, 0, len);
- if (len > strlen(version))
- len = strlen(version);
- memcpy(str + 4, version, len);
-
- mcp->mb[0] = MBC_SET_RNID_PARAMS;
- mcp->mb[1] = RNID_TYPE_SET_VERSION << 8 | dwlen;
- mcp->mb[2] = MSW(LSD(str_dma));
- mcp->mb[3] = LSW(LSD(str_dma));
- mcp->mb[6] = MSW(MSD(str_dma));
- mcp->mb[7] = LSW(MSD(str_dma));
- mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- mcp->in_mb = MBX_0;
- mcp->tov = MBX_TOV_SECONDS;
- mcp->flags = 0;
- rval = qla2x00_mailbox_command(vha, mcp);
-
- if (rval != QLA_SUCCESS) {
- ql_dbg(ql_dbg_mbx, vha, 0x1157,
- "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
- } else {
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1158,
- "Done %s.\n", __func__);
- }
-
- dma_pool_free(ha->s_dma_pool, str, str_dma);
-
- return rval;
-}
-
static int
qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
{
@@ -4171,7 +4113,6 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t iter_cnt = 0x1;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f7,
"Entered %s.\n", __func__);
@@ -4197,8 +4138,8 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
mcp->mb[7] = MSW(MSD(mreq->rcv_dma));
/* Iteration count */
- mcp->mb[18] = LSW(iter_cnt);
- mcp->mb[19] = MSW(iter_cnt);
+ mcp->mb[18] = LSW(mreq->iteration_count);
+ mcp->mb[19] = MSW(mreq->iteration_count);
mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
@@ -4576,7 +4517,8 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
goto done;
ql_log(ql_log_warn, vha, 0x10c9,
- "Thermal not supported by I2C.\n");
+ "Thermal not supported through I2C bus, trying alternate "
+ "method (ISP access).\n");
ha->thermal_support &= ~THERMAL_SUPPORT_I2C;
}
@@ -4586,7 +4528,7 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
goto done;
ql_log(ql_log_warn, vha, 0x1019,
- "Thermal not supported by ISP.\n");
+ "Thermal not supported through ISP.\n");
ha->thermal_support &= ~THERMAL_SUPPORT_ISP;
}
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
new file mode 100644
index 000000000000..729b74389f83
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -0,0 +1,3476 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
+#include <scsi/scsi_tcq.h>
+#include <linux/utsname.h>
+
+
+/* QLAFX00 specific Mailbox implementation functions */
+
+/*
+ * qlafx00_mailbox_command
+ * Issue mailbox command and waits for completion.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * mcp = driver internal mbx struct pointer.
+ *
+ * Output:
+ * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data.
+ *
+ * Returns:
+ * 0 : QLA_SUCCESS = cmd performed success
+ * 1 : QLA_FUNCTION_FAILED (error encountered)
+ * 6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered)
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
+
+{
+ int rval;
+ unsigned long flags = 0;
+ device_reg_t __iomem *reg;
+ uint8_t abort_active;
+ uint8_t io_lock_on;
+ uint16_t command = 0;
+ uint32_t *iptr;
+ uint32_t __iomem *optr;
+ uint32_t cnt;
+ uint32_t mboxes;
+ unsigned long wait_time;
+ struct qla_hw_data *ha = vha->hw;
+ scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+ if (ha->pdev->error_state > pci_channel_io_frozen) {
+ ql_log(ql_log_warn, vha, 0x115c,
+ "error_state is greater than pci_channel_io_frozen, "
+ "exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (vha->device_flags & DFLG_DEV_FAILED) {
+ ql_log(ql_log_warn, vha, 0x115f,
+ "Device in failed state, exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ reg = ha->iobase;
+ io_lock_on = base_vha->flags.init_done;
+
+ rval = QLA_SUCCESS;
+ abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+
+ if (ha->flags.pci_channel_io_perm_failure) {
+ ql_log(ql_log_warn, vha, 0x1175,
+ "Perm failure on EEH timeout MBX, exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (ha->flags.isp82xx_fw_hung) {
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ ql_log(ql_log_warn, vha, 0x1176,
+ "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
+ /*
+ * Wait for active mailbox commands to finish by waiting at most tov
+ * seconds. This is to serialize actual issuing of mailbox cmds during
+ * non ISP abort time.
+ */
+ if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
+ /* Timeout occurred. Return error. */
+ ql_log(ql_log_warn, vha, 0x1177,
+ "Cmd access timeout, cmd=0x%x, Exiting.\n",
+ mcp->mb[0]);
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ ha->flags.mbox_busy = 1;
+ /* Save mailbox command for debug */
+ ha->mcp32 = mcp;
+
+ ql_dbg(ql_dbg_mbx, vha, 0x1178,
+ "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Load mailbox registers. */
+ optr = (uint32_t __iomem *)&reg->ispfx00.mailbox0;
+
+ iptr = mcp->mb;
+ command = mcp->mb[0];
+ mboxes = mcp->out_mb;
+
+ for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ if (mboxes & BIT_0)
+ WRT_REG_DWORD(optr, *iptr);
+
+ mboxes >>= 1;
+ optr++;
+ iptr++;
+ }
+
+ /* Issue set host interrupt command to send cmd out. */
+ ha->flags.mbox_int = 0;
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1172,
+ (uint8_t *)mcp->mb, 16);
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1173,
+ ((uint8_t *)mcp->mb + 0x10), 16);
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1174,
+ ((uint8_t *)mcp->mb + 0x20), 8);
+
+ /* Unlock mbx registers and wait for interrupt */
+ ql_dbg(ql_dbg_mbx, vha, 0x1179,
+ "Going to unlock irq & waiting for interrupts. "
+ "jiffies=%lx.\n", jiffies);
+
+ /* Wait for mbx cmd completion until timeout */
+ if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
+ set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+ QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
+
+ clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+ } else {
+ ql_dbg(ql_dbg_mbx, vha, 0x112c,
+ "Cmd=%x Polling Mode.\n", command);
+
+ QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
+ while (!ha->flags.mbox_int) {
+ if (time_after(jiffies, wait_time))
+ break;
+
+ /* Check for pending interrupts. */
+ qla2x00_poll(ha->rsp_q_map[0]);
+
+ if (!ha->flags.mbox_int &&
+ !(IS_QLA2200(ha) &&
+ command == MBC_LOAD_RISC_RAM_EXTENDED))
+ usleep_range(10000, 11000);
+ } /* while */
+ ql_dbg(ql_dbg_mbx, vha, 0x112d,
+ "Waited %d sec.\n",
+ (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
+ }
+
+ /* Check whether we timed out */
+ if (ha->flags.mbox_int) {
+ uint32_t *iptr2;
+
+ ql_dbg(ql_dbg_mbx, vha, 0x112e,
+ "Cmd=%x completed.\n", command);
+
+ /* Got interrupt. Clear the flag. */
+ ha->flags.mbox_int = 0;
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ if (ha->mailbox_out32[0] != MBS_COMMAND_COMPLETE)
+ rval = QLA_FUNCTION_FAILED;
+
+ /* Load return mailbox registers. */
+ iptr2 = mcp->mb;
+ iptr = (uint32_t *)&ha->mailbox_out32[0];
+ mboxes = mcp->in_mb;
+ for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ if (mboxes & BIT_0)
+ *iptr2 = *iptr;
+
+ mboxes >>= 1;
+ iptr2++;
+ iptr++;
+ }
+ } else {
+
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ ha->flags.mbox_busy = 0;
+
+ /* Clean up */
+ ha->mcp32 = NULL;
+
+ if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
+ ql_dbg(ql_dbg_mbx, vha, 0x113a,
+ "checking for additional resp interrupt.\n");
+
+ /* polling mode for non isp_abort commands. */
+ qla2x00_poll(ha->rsp_q_map[0]);
+ }
+
+ if (rval == QLA_FUNCTION_TIMEOUT &&
+ mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) {
+ if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
+ ha->flags.eeh_busy) {
+ /* not in dpc. schedule it for dpc to take over. */
+ ql_dbg(ql_dbg_mbx, vha, 0x115d,
+ "Timeout, schedule isp_abort_needed.\n");
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ ql_log(ql_log_info, base_vha, 0x115e,
+ "Mailbox cmd timeout occurred, cmd=0x%x, "
+ "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
+ "abort.\n", command, mcp->mb[0],
+ ha->flags.eeh_busy);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ } else if (!abort_active) {
+ /* call abort directly since we are in the DPC thread */
+ ql_dbg(ql_dbg_mbx, vha, 0x1160,
+ "Timeout, calling abort_isp.\n");
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ ql_log(ql_log_info, base_vha, 0x1161,
+ "Mailbox cmd timeout occurred, cmd=0x%x, "
+ "mb[0]=0x%x. Scheduling ISP abort ",
+ command, mcp->mb[0]);
+
+ set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ if (ha->isp_ops->abort_isp(vha)) {
+ /* Failed. retry later. */
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ }
+ clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ ql_dbg(ql_dbg_mbx, vha, 0x1162,
+ "Finished abort_isp.\n");
+ }
+ }
+ }
+
+premature_exit:
+ /* Allow next mbx cmd to come in. */
+ complete(&ha->mbx_cmd_comp);
+
+ if (rval) {
+ ql_log(ql_log_warn, base_vha, 0x1163,
+ "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, "
+ "mb[3]=%x, cmd=%x ****.\n",
+ mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
+ } else {
+ ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_driver_shutdown
+ * Indicate a driver shutdown to firmware.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1166,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_MR_DRV_SHUTDOWN;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_0;
+ if (tmo)
+ mcp->tov = tmo;
+ else
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1167,
+ "Failed=%x.\n", rval);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1168,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_get_firmware_state
+ * Get adapter firmware state.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ * qla7xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_get_firmware_state(scsi_qla_host_t *vha, uint32_t *states)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1169,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ /* Return firmware states. */
+ states[0] = mcp->mb[1];
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x116a,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116b,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/*
+ * qlafx00_init_firmware
+ * Initialize adapter firmware.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * dptr = Initialization control block pointer.
+ * size = size of initialization control block.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ * qlafx00 local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qlafx00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116c,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+
+ mcp->mb[1] = 0;
+ mcp->mb[2] = MSD(ha->init_cb_dma);
+ mcp->mb[3] = LSD(ha->init_cb_dma);
+
+ mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x116d,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116e,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/*
+ * qlafx00_mbx_reg_test
+ */
+static int
+qlafx00_mbx_reg_test(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116f,
+ "Entered %s.\n", __func__);
+
+
+ mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
+ mcp->mb[1] = 0xAAAA;
+ mcp->mb[2] = 0x5555;
+ mcp->mb[3] = 0xAA55;
+ mcp->mb[4] = 0x55AA;
+ mcp->mb[5] = 0xA5A5;
+ mcp->mb[6] = 0x5A5A;
+ mcp->mb[7] = 0x2525;
+ mcp->mb[8] = 0xBBBB;
+ mcp->mb[9] = 0x6666;
+ mcp->mb[10] = 0xBB66;
+ mcp->mb[11] = 0x66BB;
+ mcp->mb[12] = 0xB6B6;
+ mcp->mb[13] = 0x6B6B;
+ mcp->mb[14] = 0x3636;
+ mcp->mb[15] = 0xCCCC;
+
+
+ mcp->out_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
+ MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
+ MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->buf_size = 0;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qlafx00_mailbox_command(vha, mcp);
+ if (rval == QLA_SUCCESS) {
+ if (mcp->mb[17] != 0xAAAA || mcp->mb[18] != 0x5555 ||
+ mcp->mb[19] != 0xAA55 || mcp->mb[20] != 0x55AA)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[21] != 0xA5A5 || mcp->mb[22] != 0x5A5A ||
+ mcp->mb[23] != 0x2525 || mcp->mb[24] != 0xBBBB)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[25] != 0x6666 || mcp->mb[26] != 0xBB66 ||
+ mcp->mb[27] != 0x66BB || mcp->mb[28] != 0xB6B6)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[29] != 0x6B6B || mcp->mb[30] != 0x3636 ||
+ mcp->mb[31] != 0xCCCC)
+ rval = QLA_FUNCTION_FAILED;
+ }
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1170,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1171,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/**
+ * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_pci_config(scsi_qla_host_t *vha)
+{
+ uint16_t w;
+ struct qla_hw_data *ha = vha->hw;
+
+ pci_set_master(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
+
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+ /* PCIe -- adjust Maximum Read Request Size (2048). */
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
+
+ ha->chip_revision = ha->pdev->revision;
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qlafx00_warm_reset() - Perform warm reset of iSA(CPUs being reset on SOC).
+ * @ha: HA context
+ *
+ */
+static inline void
+qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
+{
+ unsigned long flags = 0;
+ struct qla_hw_data *ha = vha->hw;
+ int i, core;
+ uint32_t cnt;
+
+ /* Set all 4 cores in reset */
+ for (i = 0; i < 4; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_SW_RST_CONTROL_REG_CORE0 + 8*i), (0xF01));
+ }
+
+ /* Set all 4 core Clock gating control */
+ for (i = 0; i < 4; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_SW_RST_CONTROL_REG_CORE0 + 4 + 8*i), (0x01010101));
+ }
+
+ /* Reset all units in Fabric */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x11F0101));
+
+ /* Reset all interrupt control registers */
+ for (i = 0; i < 115; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_INTERRUPT_SOURCE_I_CONTROL_REG + 4*i), (0x0));
+ }
+
+ /* Reset Timers control registers. per core */
+ for (core = 0; core < 4; core++)
+ for (i = 0; i < 8; i++)
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_CORE_TIMER_REG + 0x100*core + 4*i), (0x0));
+
+ /* Reset per core IRQ ack register */
+ for (core = 0; core < 4; core++)
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_IRQ_ACK_REG + 0x100*core), (0x3FF));
+
+ /* Set Fabric control and config to defaults */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONTROL_REG, (0x2));
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONFIG_REG, (0x3));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Kick in Fabric units */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x0));
+
+ /* Kick in Core0 to start boot process */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_SW_RST_CONTROL_REG_CORE0, (0xF00));
+
+ /* Wait 10secs for soft-reset to complete. */
+ for (cnt = 10; cnt; cnt--) {
+ msleep(1000);
+ barrier();
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qlafx00_soft_reset() - Soft Reset ISPFx00.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+void
+qlafx00_soft_reset(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (unlikely(pci_channel_offline(ha->pdev) &&
+ ha->flags.pci_channel_io_perm_failure))
+ return;
+
+ ha->isp_ops->disable_intrs(ha);
+ qlafx00_soc_cpu_reset(vha);
+ ha->isp_ops->enable_intrs(ha);
+}
+
+/**
+ * qlafx00_chip_diag() - Test ISPFx00 for proper operation.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_chip_diag(scsi_qla_host_t *vha)
+{
+ int rval = 0;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+
+ ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
+
+ rval = qlafx00_mbx_reg_test(vha);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x1165,
+ "Failed mailbox send register test\n");
+ } else {
+ /* Flag a successful rval */
+ rval = QLA_SUCCESS;
+ }
+ return rval;
+}
+
+void
+qlafx00_config_rings(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ struct init_cb_fx *icb;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+
+ /* Setup ring parameters in initialization control block. */
+ icb = (struct init_cb_fx *)ha->init_cb;
+ icb->request_q_outpointer = __constant_cpu_to_le16(0);
+ icb->response_q_inpointer = __constant_cpu_to_le16(0);
+ icb->request_q_length = cpu_to_le16(req->length);
+ icb->response_q_length = cpu_to_le16(rsp->length);
+ icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
+ icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
+ icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
+ icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+
+ WRT_REG_DWORD(&reg->req_q_in, 0);
+ WRT_REG_DWORD(&reg->req_q_out, 0);
+
+ WRT_REG_DWORD(&reg->rsp_q_in, 0);
+ WRT_REG_DWORD(&reg->rsp_q_out, 0);
+
+ /* PCI posting */
+ RD_REG_DWORD(&reg->rsp_q_out);
+}
+
+char *
+qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int pcie_reg;
+
+ pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+ if (pcie_reg) {
+ strcpy(str, "PCIe iSA");
+ return str;
+ }
+ return str;
+}
+
+char *
+qlafx00_fw_version_str(struct scsi_qla_host *vha, char *str)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ sprintf(str, "%s", ha->mr.fw_version);
+ return str;
+}
+
+void
+qlafx00_enable_intrs(struct qla_hw_data *ha)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ QLAFX00_ENABLE_ICNTRL_REG(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlafx00_disable_intrs(struct qla_hw_data *ha)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ QLAFX00_DISABLE_ICNTRL_REG(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qlafx00_tmf_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
+ tmf->u.tmf.comp_status = CS_TIMEOUT;
+ complete(&tmf->u.tmf.comp);
+}
+
+static void
+qlafx00_tmf_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
+ complete(&tmf->u.tmf.comp);
+}
+
+static int
+qlafx00_async_tm_cmd(fc_port_t *fcport, uint32_t flags,
+ uint32_t lun, uint32_t tag)
+{
+ scsi_qla_host_t *vha = fcport->vha;
+ struct srb_iocb *tm_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ tm_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_TM_CMD;
+ sp->name = "tmf";
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ tm_iocb->u.tmf.flags = flags;
+ tm_iocb->u.tmf.lun = lun;
+ tm_iocb->u.tmf.data = tag;
+ sp->done = qlafx00_tmf_sp_done;
+ tm_iocb->timeout = qlafx00_tmf_iocb_timeout;
+ init_completion(&tm_iocb->u.tmf.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507b,
+ "Task management command issued target_id=%x\n",
+ fcport->tgt_id);
+
+ wait_for_completion(&tm_iocb->u.tmf.comp);
+
+ rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+int
+qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
+{
+ return qlafx00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+}
+
+int
+qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
+{
+ return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+}
+
+int
+qlafx00_iospace_config(struct qla_hw_data *ha)
+{
+ if (pci_request_selected_regions(ha->pdev, ha->bars,
+ QLA2XXX_DRIVER_NAME)) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x014e,
+ "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ /* Use MMIO operations for all accesses. */
+ if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x014f,
+ "Invalid pci I/O region size (%s).\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+ if (pci_resource_len(ha->pdev, 0) < BAR0_LEN_FX00) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x0127,
+ "Invalid PCI mem BAR0 region size (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ ha->cregbase =
+ ioremap_nocache(pci_resource_start(ha->pdev, 0), BAR0_LEN_FX00);
+ if (!ha->cregbase) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x0128,
+ "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ if (!(pci_resource_flags(ha->pdev, 2) & IORESOURCE_MEM)) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x0129,
+ "region #2 not an MMIO resource (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+ if (pci_resource_len(ha->pdev, 2) < BAR2_LEN_FX00) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x012a,
+ "Invalid PCI mem BAR2 region size (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ ha->iobase =
+ ioremap_nocache(pci_resource_start(ha->pdev, 2), BAR2_LEN_FX00);
+ if (!ha->iobase) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x012b,
+ "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ /* Determine queue resources */
+ ha->max_req_queues = ha->max_rsp_queues = 1;
+
+ ql_log_pci(ql_log_info, ha->pdev, 0x012c,
+ "Bars 0x%x, iobase0 0x%p, iobase2 0x%p\n",
+ ha->bars, ha->cregbase, ha->iobase);
+
+ return 0;
+
+iospace_error_exit:
+ return -ENOMEM;
+}
+
+static void
+qlafx00_save_queue_ptrs(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+
+ req->length_fx00 = req->length;
+ req->ring_fx00 = req->ring;
+ req->dma_fx00 = req->dma;
+
+ rsp->length_fx00 = rsp->length;
+ rsp->ring_fx00 = rsp->ring;
+ rsp->dma_fx00 = rsp->dma;
+
+ ql_dbg(ql_dbg_init, vha, 0x012d,
+ "req: %p, ring_fx00: %p, length_fx00: 0x%x,"
+ "req->dma_fx00: 0x%llx\n", req, req->ring_fx00,
+ req->length_fx00, (u64)req->dma_fx00);
+
+ ql_dbg(ql_dbg_init, vha, 0x012e,
+ "rsp: %p, ring_fx00: %p, length_fx00: 0x%x,"
+ "rsp->dma_fx00: 0x%llx\n", rsp, rsp->ring_fx00,
+ rsp->length_fx00, (u64)rsp->dma_fx00);
+}
+
+static int
+qlafx00_config_queues(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+ dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2);
+
+ req->length = ha->req_que_len;
+ req->ring = (void *)ha->iobase + ha->req_que_off;
+ req->dma = bar2_hdl + ha->req_que_off;
+ if ((!req->ring) || (req->length == 0)) {
+ ql_log_pci(ql_log_info, ha->pdev, 0x012f,
+ "Unable to allocate memory for req_ring\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x0130,
+ "req: %p req_ring pointer %p req len 0x%x "
+ "req off 0x%x\n, req->dma: 0x%llx",
+ req, req->ring, req->length,
+ ha->req_que_off, (u64)req->dma);
+
+ rsp->length = ha->rsp_que_len;
+ rsp->ring = (void *)ha->iobase + ha->rsp_que_off;
+ rsp->dma = bar2_hdl + ha->rsp_que_off;
+ if ((!rsp->ring) || (rsp->length == 0)) {
+ ql_log_pci(ql_log_info, ha->pdev, 0x0131,
+ "Unable to allocate memory for rsp_ring\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x0132,
+ "rsp: %p rsp_ring pointer %p rsp len 0x%x "
+ "rsp off 0x%x, rsp->dma: 0x%llx\n",
+ rsp, rsp->ring, rsp->length,
+ ha->rsp_que_off, (u64)rsp->dma);
+
+ return QLA_SUCCESS;
+}
+
+static int
+qlafx00_init_fw_ready(scsi_qla_host_t *vha)
+{
+ int rval = 0;
+ unsigned long wtime;
+ uint16_t wait_time; /* Wait time */
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ uint32_t aenmbx, aenmbx7 = 0;
+ uint32_t state[5];
+ bool done = false;
+
+ /* 30 seconds wait - Adjust if required */
+ wait_time = 30;
+
+ /* wait time before firmware ready */
+ wtime = jiffies + (wait_time * HZ);
+ do {
+ aenmbx = RD_REG_DWORD(&reg->aenmailbox0);
+ barrier();
+ ql_dbg(ql_dbg_mbx, vha, 0x0133,
+ "aenmbx: 0x%x\n", aenmbx);
+
+ switch (aenmbx) {
+ case MBA_FW_NOT_STARTED:
+ case MBA_FW_STARTING:
+ break;
+
+ case MBA_SYSTEM_ERR:
+ case MBA_REQ_TRANSFER_ERR:
+ case MBA_RSP_TRANSFER_ERR:
+ case MBA_FW_INIT_FAILURE:
+ qlafx00_soft_reset(vha);
+ break;
+
+ case MBA_FW_RESTART_CMPLT:
+ /* Set the mbx and rqstq intr code */
+ aenmbx7 = RD_REG_DWORD(&reg->aenmailbox7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->aenmailbox3);
+ ha->req_que_len = RD_REG_DWORD(&reg->aenmailbox5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->aenmailbox6);
+ WRT_REG_DWORD(&reg->aenmailbox0, 0);
+ RD_REG_DWORD_RELAXED(&reg->aenmailbox0);
+ ql_dbg(ql_dbg_init, vha, 0x0134,
+ "f/w returned mbx_intr_code: 0x%x, "
+ "rqstq_intr_code: 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code);
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+ rval = QLA_SUCCESS;
+ done = true;
+ break;
+
+ default:
+ /* If fw is apparently not ready. In order to continue,
+ * we might need to issue Mbox cmd, but the problem is
+ * that the DoorBell vector values that come with the
+ * 8060 AEN are most likely gone by now (and thus no
+ * bell would be rung on the fw side when mbox cmd is
+ * issued). We have to therefore grab the 8060 AEN
+ * shadow regs (filled in by FW when the last 8060
+ * AEN was being posted).
+ * Do the following to determine what is needed in
+ * order to get the FW ready:
+ * 1. reload the 8060 AEN values from the shadow regs
+ * 2. clear int status to get rid of possible pending
+ * interrupts
+ * 3. issue Get FW State Mbox cmd to determine fw state
+ * Set the mbx and rqstq intr code from Shadow Regs
+ */
+ aenmbx7 = RD_REG_DWORD(&reg->initval7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->initval1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->initval3);
+ ha->req_que_len = RD_REG_DWORD(&reg->initval5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->initval6);
+ ql_dbg(ql_dbg_init, vha, 0x0135,
+ "f/w returned mbx_intr_code: 0x%x, "
+ "rqstq_intr_code: 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code);
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ /* Get the FW state */
+ rval = qlafx00_get_firmware_state(vha, state);
+ if (rval != QLA_SUCCESS) {
+ /* Retry if timer has not expired */
+ break;
+ }
+
+ if (state[0] == FSTATE_FX00_CONFIG_WAIT) {
+ /* Firmware is waiting to be
+ * initialized by driver
+ */
+ rval = QLA_SUCCESS;
+ done = true;
+ break;
+ }
+
+ /* Issue driver shutdown and wait until f/w recovers.
+ * Driver should continue to poll until 8060 AEN is
+ * received indicating firmware recovery.
+ */
+ ql_dbg(ql_dbg_init, vha, 0x0136,
+ "Sending Driver shutdown fw_state 0x%x\n",
+ state[0]);
+
+ rval = qlafx00_driver_shutdown(vha, 10);
+ if (rval != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ break;
+ }
+ msleep(500);
+
+ wtime = jiffies + (wait_time * HZ);
+ break;
+ }
+
+ if (!done) {
+ if (time_after_eq(jiffies, wtime)) {
+ ql_dbg(ql_dbg_init, vha, 0x0137,
+ "Init f/w failed: aen[7]: 0x%x\n",
+ RD_REG_DWORD(&reg->aenmailbox7));
+ rval = QLA_FUNCTION_FAILED;
+ done = true;
+ break;
+ }
+ /* Delay for a while */
+ msleep(500);
+ }
+ } while (!done);
+
+ if (rval)
+ ql_dbg(ql_dbg_init, vha, 0x0138,
+ "%s **** FAILED ****.\n", __func__);
+ else
+ ql_dbg(ql_dbg_init, vha, 0x0139,
+ "%s **** SUCCESS ****.\n", __func__);
+
+ return rval;
+}
+
+/*
+ * qlafx00_fw_ready() - Waits for firmware ready.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_fw_ready(scsi_qla_host_t *vha)
+{
+ int rval;
+ unsigned long wtime;
+ uint16_t wait_time; /* Wait time if loop is coming ready */
+ uint32_t state[5];
+
+ rval = QLA_SUCCESS;
+
+ wait_time = 10;
+
+ /* wait time before firmware ready */
+ wtime = jiffies + (wait_time * HZ);
+
+ /* Wait for ISP to finish init */
+ if (!vha->flags.init_done)
+ ql_dbg(ql_dbg_init, vha, 0x013a,
+ "Waiting for init to complete...\n");
+
+ do {
+ rval = qlafx00_get_firmware_state(vha, state);
+
+ if (rval == QLA_SUCCESS) {
+ if (state[0] == FSTATE_FX00_INITIALIZED) {
+ ql_dbg(ql_dbg_init, vha, 0x013b,
+ "fw_state=%x\n", state[0]);
+ rval = QLA_SUCCESS;
+ break;
+ }
+ }
+ rval = QLA_FUNCTION_FAILED;
+
+ if (time_after_eq(jiffies, wtime))
+ break;
+
+ /* Delay for a while */
+ msleep(500);
+
+ ql_dbg(ql_dbg_init, vha, 0x013c,
+ "fw_state=%x curr time=%lx.\n", state[0], jiffies);
+ } while (1);
+
+
+ if (rval)
+ ql_dbg(ql_dbg_init, vha, 0x013d,
+ "Firmware ready **** FAILED ****.\n");
+ else
+ ql_dbg(ql_dbg_init, vha, 0x013e,
+ "Firmware ready **** SUCCESS ****.\n");
+
+ return rval;
+}
+
+static int
+qlafx00_find_all_targets(scsi_qla_host_t *vha,
+ struct list_head *new_fcports)
+{
+ int rval;
+ uint16_t tgt_id;
+ fc_port_t *fcport, *new_fcport;
+ int found;
+ struct qla_hw_data *ha = vha->hw;
+
+ rval = QLA_SUCCESS;
+
+ if (!test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
+ return QLA_FUNCTION_FAILED;
+
+ if ((atomic_read(&vha->loop_down_timer) ||
+ STATE_TRANSITION(vha))) {
+ atomic_set(&vha->loop_down_timer, 0);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088,
+ "Listing Target bit map...\n");
+ ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha,
+ 0x2089, (uint8_t *)ha->gid_list, 32);
+
+ /* Allocate temporary rmtport for any new rmtports discovered. */
+ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (new_fcport == NULL)
+ return QLA_MEMORY_ALLOC_FAILED;
+
+ for_each_set_bit(tgt_id, (void *)ha->gid_list,
+ QLAFX00_TGT_NODE_LIST_SIZE) {
+
+ /* Send get target node info */
+ new_fcport->tgt_id = tgt_id;
+ rval = qlafx00_fx_disc(vha, new_fcport,
+ FXDISC_GET_TGT_NODE_INFO);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x208a,
+ "Target info scan failed -- assuming zero-entry "
+ "result...\n");
+ continue;
+ }
+
+ /* Locate matching device in database. */
+ found = 0;
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (memcmp(new_fcport->port_name,
+ fcport->port_name, WWN_SIZE))
+ continue;
+
+ found++;
+
+ /*
+ * If tgt_id is same and state FCS_ONLINE, nothing
+ * changed.
+ */
+ if (fcport->tgt_id == new_fcport->tgt_id &&
+ atomic_read(&fcport->state) == FCS_ONLINE)
+ break;
+
+ /*
+ * Tgt ID changed or device was marked to be updated.
+ */
+ ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x208b,
+ "TGT-ID Change(%s): Present tgt id: "
+ "0x%x state: 0x%x "
+ "wwnn = %llx wwpn = %llx.\n",
+ __func__, fcport->tgt_id,
+ atomic_read(&fcport->state),
+ (unsigned long long)wwn_to_u64(fcport->node_name),
+ (unsigned long long)wwn_to_u64(fcport->port_name));
+
+ ql_log(ql_log_info, vha, 0x208c,
+ "TGT-ID Announce(%s): Discovered tgt "
+ "id 0x%x wwnn = %llx "
+ "wwpn = %llx.\n", __func__, new_fcport->tgt_id,
+ (unsigned long long)
+ wwn_to_u64(new_fcport->node_name),
+ (unsigned long long)
+ wwn_to_u64(new_fcport->port_name));
+
+ if (atomic_read(&fcport->state) != FCS_ONLINE) {
+ fcport->old_tgt_id = fcport->tgt_id;
+ fcport->tgt_id = new_fcport->tgt_id;
+ ql_log(ql_log_info, vha, 0x208d,
+ "TGT-ID: New fcport Added: %p\n", fcport);
+ qla2x00_update_fcport(vha, fcport);
+ } else {
+ ql_log(ql_log_info, vha, 0x208e,
+ " Existing TGT-ID %x did not get "
+ " offline event from firmware.\n",
+ fcport->old_tgt_id);
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ kfree(new_fcport);
+ return rval;
+ }
+ break;
+ }
+
+ if (found)
+ continue;
+
+ /* If device was not in our fcports list, then add it. */
+ list_add_tail(&new_fcport->list, new_fcports);
+
+ /* Allocate a new replacement fcport. */
+ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (new_fcport == NULL)
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+
+ kfree(new_fcport);
+ return rval;
+}
+
+/*
+ * qlafx00_configure_all_targets
+ * Setup target devices with node ID's.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ * BIT_0 = error
+ */
+static int
+qlafx00_configure_all_targets(scsi_qla_host_t *vha)
+{
+ int rval;
+ fc_port_t *fcport, *rmptemp;
+ LIST_HEAD(new_fcports);
+
+ rval = qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
+ FXDISC_GET_TGT_NODE_LIST);
+ if (rval != QLA_SUCCESS) {
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return rval;
+ }
+
+ rval = qlafx00_find_all_targets(vha, &new_fcports);
+ if (rval != QLA_SUCCESS) {
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return rval;
+ }
+
+ /*
+ * Delete all previous devices marked lost.
+ */
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+ break;
+
+ if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+ if (fcport->port_type != FCT_INITIATOR)
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ }
+ }
+
+ /*
+ * Add the new devices to our devices list.
+ */
+ list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+ break;
+
+ qla2x00_update_fcport(vha, fcport);
+ list_move_tail(&fcport->list, &vha->vp_fcports);
+ ql_log(ql_log_info, vha, 0x208f,
+ "Attach new target id 0x%x wwnn = %llx "
+ "wwpn = %llx.\n",
+ fcport->tgt_id,
+ (unsigned long long)wwn_to_u64(fcport->node_name),
+ (unsigned long long)wwn_to_u64(fcport->port_name));
+ }
+
+ /* Free all new device structures not processed. */
+ list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
+ list_del(&fcport->list);
+ kfree(fcport);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_configure_devices
+ * Updates Fibre Channel Device Database with what is actually on loop.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ * 1 = error.
+ * 2 = database was full and device was not configured.
+ */
+int
+qlafx00_configure_devices(scsi_qla_host_t *vha)
+{
+ int rval;
+ unsigned long flags, save_flags;
+ rval = QLA_SUCCESS;
+
+ save_flags = flags = vha->dpc_flags;
+
+ ql_dbg(ql_dbg_disc, vha, 0x2090,
+ "Configure devices -- dpc flags =0x%lx\n", flags);
+
+ rval = qlafx00_configure_all_targets(vha);
+
+ if (rval == QLA_SUCCESS) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ atomic_set(&vha->loop_state, LOOP_READY);
+ ql_log(ql_log_info, vha, 0x2091,
+ "Device Ready\n");
+ }
+ }
+
+ if (rval) {
+ ql_dbg(ql_dbg_disc, vha, 0x2092,
+ "%s *** FAILED ***.\n", __func__);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0x2093,
+ "%s: exiting normally.\n", __func__);
+ }
+ return rval;
+}
+
+static void
+qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ fc_port_t *fcport;
+
+ vha->flags.online = 0;
+ ha->flags.chip_reset_done = 0;
+ ha->mr.fw_hbt_en = 0;
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ vha->qla_stats.total_isp_aborts++;
+
+ ql_log(ql_log_info, vha, 0x013f,
+ "Performing ISP error recovery - ha = %p.\n", ha);
+
+ ha->isp_ops->reset_chip(vha);
+
+ if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer,
+ QLAFX00_LOOP_DOWN_TIME);
+ } else {
+ if (!atomic_read(&vha->loop_down_timer))
+ atomic_set(&vha->loop_down_timer,
+ QLAFX00_LOOP_DOWN_TIME);
+ }
+
+ /* Clear all async request states across all VPs. */
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ fcport->flags = 0;
+ if (atomic_read(&fcport->state) == FCS_ONLINE)
+ qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
+ }
+
+ if (!ha->flags.eeh_busy) {
+ /* Requeue all commands in outstanding command list. */
+ qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+ }
+
+ qla2x00_free_irqs(vha);
+ set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+
+ /* Clear the Interrupts */
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ ql_log(ql_log_info, vha, 0x0140,
+ "%s Done done - ha=%p.\n", __func__, ha);
+}
+
+/**
+ * qlafx00_init_response_q_entries() - Initializes response queue entries.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ *
+ * Returns 0 on success.
+ */
+void
+qlafx00_init_response_q_entries(struct rsp_que *rsp)
+{
+ uint16_t cnt;
+ response_t *pkt;
+
+ rsp->ring_ptr = rsp->ring;
+ rsp->ring_index = 0;
+ rsp->status_srb = NULL;
+ pkt = rsp->ring_ptr;
+ for (cnt = 0; cnt < rsp->length; cnt++) {
+ pkt->signature = RESPONSE_PROCESSED;
+ WRT_REG_DWORD(&pkt->signature, RESPONSE_PROCESSED);
+ pkt++;
+ }
+}
+
+int
+qlafx00_rescan_isp(scsi_qla_host_t *vha)
+{
+ uint32_t status = QLA_FUNCTION_FAILED;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ uint32_t aenmbx7;
+
+ qla2x00_request_irqs(ha, ha->rsp_q_map[0]);
+
+ aenmbx7 = RD_REG_DWORD(&reg->aenmailbox7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->aenmailbox3);
+ ha->req_que_len = RD_REG_DWORD(&reg->aenmailbox5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->aenmailbox6);
+
+ ql_dbg(ql_dbg_disc, vha, 0x2094,
+ "fw returned mbx_intr_code: 0x%x, rqstq_intr_code: 0x%x "
+ " Req que offset 0x%x Rsp que offset 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code,
+ ha->req_que_off, ha->rsp_que_len);
+
+ /* Clear the Interrupts */
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ status = qla2x00_init_rings(vha);
+ if (!status) {
+ vha->flags.online = 1;
+
+ /* if no cable then assume it's good */
+ if ((vha->device_flags & DFLG_NO_CABLE))
+ status = 0;
+ /* Register system information */
+ if (qlafx00_fx_disc(vha,
+ &vha->hw->mr.fcport, FXDISC_REG_HOST_INFO))
+ ql_dbg(ql_dbg_disc, vha, 0x2095,
+ "failed to register host info\n");
+ }
+ scsi_unblock_requests(vha->host);
+ return status;
+}
+
+void
+qlafx00_timer_routine(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t fw_heart_beat;
+ uint32_t aenmbx0;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+
+ /* Check firmware health */
+ if (ha->mr.fw_hbt_cnt)
+ ha->mr.fw_hbt_cnt--;
+ else {
+ if ((!ha->flags.mr_reset_hdlr_active) &&
+ (!test_bit(UNLOADING, &vha->dpc_flags)) &&
+ (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
+ (ha->mr.fw_hbt_en)) {
+ fw_heart_beat = RD_REG_DWORD(&reg->fwheartbeat);
+ if (fw_heart_beat != ha->mr.old_fw_hbt_cnt) {
+ ha->mr.old_fw_hbt_cnt = fw_heart_beat;
+ ha->mr.fw_hbt_miss_cnt = 0;
+ } else {
+ ha->mr.fw_hbt_miss_cnt++;
+ if (ha->mr.fw_hbt_miss_cnt ==
+ QLAFX00_HEARTBEAT_MISS_CNT) {
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_hbt_miss_cnt = 0;
+ }
+ }
+ }
+ ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
+ }
+
+ if (test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags)) {
+ /* Reset recovery to be performed in timer routine */
+ aenmbx0 = RD_REG_DWORD(&reg->aenmailbox0);
+ if (ha->mr.fw_reset_timer_exp) {
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_reset_timer_exp = 0;
+ } else if (aenmbx0 == MBA_FW_RESTART_CMPLT) {
+ /* Wake up DPC to rescan the targets */
+ set_bit(FX00_TARGET_SCAN, &vha->dpc_flags);
+ clear_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ } else if ((aenmbx0 == MBA_FW_STARTING) &&
+ (!ha->mr.fw_hbt_en)) {
+ ha->mr.fw_hbt_en = 1;
+ } else if (!ha->mr.fw_reset_timer_tick) {
+ if (aenmbx0 == ha->mr.old_aenmbx0_state)
+ ha->mr.fw_reset_timer_exp = 1;
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ } else if (aenmbx0 == 0xFFFFFFFF) {
+ uint32_t data0, data1;
+
+ data0 = QLAFX00_RD_REG(ha,
+ QLAFX00_BAR1_BASE_ADDR_REG);
+ data1 = QLAFX00_RD_REG(ha,
+ QLAFX00_PEX0_WIN0_BASE_ADDR_REG);
+
+ data0 &= 0xffff0000;
+ data1 &= 0x0000ffff;
+
+ QLAFX00_WR_REG(ha,
+ QLAFX00_PEX0_WIN0_BASE_ADDR_REG,
+ (data0 | data1));
+ } else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
+ ha->mr.fw_reset_timer_tick =
+ QLAFX00_MAX_RESET_INTERVAL;
+ }
+ ha->mr.old_aenmbx0_state = aenmbx0;
+ ha->mr.fw_reset_timer_tick--;
+ }
+}
+
+/*
+ * qlfx00a_reset_initialize
+ * Re-initialize after a iSA device reset.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_reset_initialize(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->device_flags & DFLG_DEV_FAILED) {
+ ql_dbg(ql_dbg_init, vha, 0x0142,
+ "Device in failed state\n");
+ return QLA_SUCCESS;
+ }
+
+ ha->flags.mr_reset_hdlr_active = 1;
+
+ if (vha->flags.online) {
+ scsi_block_requests(vha->host);
+ qlafx00_abort_isp_cleanup(vha);
+ }
+
+ ql_log(ql_log_info, vha, 0x0143,
+ "(%s): succeeded.\n", __func__);
+ ha->flags.mr_reset_hdlr_active = 0;
+ return QLA_SUCCESS;
+}
+
+/*
+ * qlafx00_abort_isp
+ * Resets ISP and aborts all outstanding commands.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_abort_isp(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->flags.online) {
+ if (unlikely(pci_channel_offline(ha->pdev) &&
+ ha->flags.pci_channel_io_perm_failure)) {
+ clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+ return QLA_SUCCESS;
+ }
+
+ scsi_block_requests(vha->host);
+ qlafx00_abort_isp_cleanup(vha);
+ }
+
+ ql_log(ql_log_info, vha, 0x0145,
+ "(%s): succeeded.\n", __func__);
+
+ return QLA_SUCCESS;
+}
+
+static inline fc_port_t*
+qlafx00_get_fcport(struct scsi_qla_host *vha, int tgt_id)
+{
+ fc_port_t *fcport;
+
+ /* Check for matching device in remote port list. */
+ fcport = NULL;
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (fcport->tgt_id == tgt_id) {
+ ql_dbg(ql_dbg_async, vha, 0x5072,
+ "Matching fcport(%p) found with TGT-ID: 0x%x "
+ "and Remote TGT_ID: 0x%x\n",
+ fcport, fcport->tgt_id, tgt_id);
+ break;
+ }
+ }
+ return fcport;
+}
+
+static void
+qlafx00_tgt_detach(struct scsi_qla_host *vha, int tgt_id)
+{
+ fc_port_t *fcport;
+
+ ql_log(ql_log_info, vha, 0x5073,
+ "Detach TGT-ID: 0x%x\n", tgt_id);
+
+ fcport = qlafx00_get_fcport(vha, tgt_id);
+ if (!fcport)
+ return;
+
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+
+ return;
+}
+
+int
+qlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
+{
+ int rval = 0;
+ uint32_t aen_code, aen_data;
+
+ aen_code = FCH_EVT_VENDOR_UNIQUE;
+ aen_data = evt->u.aenfx.evtcode;
+
+ switch (evt->u.aenfx.evtcode) {
+ case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
+ if (evt->u.aenfx.mbx[1] == 0) {
+ if (evt->u.aenfx.mbx[2] == 1) {
+ if (!vha->flags.fw_tgt_reported)
+ vha->flags.fw_tgt_reported = 1;
+ atomic_set(&vha->loop_down_timer, 0);
+ atomic_set(&vha->loop_state, LOOP_UP);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ } else if (evt->u.aenfx.mbx[2] == 2) {
+ qlafx00_tgt_detach(vha, evt->u.aenfx.mbx[3]);
+ }
+ } else if (evt->u.aenfx.mbx[1] == 0xffff) {
+ if (evt->u.aenfx.mbx[2] == 1) {
+ if (!vha->flags.fw_tgt_reported)
+ vha->flags.fw_tgt_reported = 1;
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ } else if (evt->u.aenfx.mbx[2] == 2) {
+ vha->device_flags |= DFLG_NO_CABLE;
+ qla2x00_mark_all_devices_lost(vha, 1);
+ }
+ }
+ break;
+ case QLAFX00_MBA_LINK_UP:
+ aen_code = FCH_EVT_LINKUP;
+ aen_data = 0;
+ break;
+ case QLAFX00_MBA_LINK_DOWN:
+ aen_code = FCH_EVT_LINKDOWN;
+ aen_data = 0;
+ break;
+ }
+
+ fc_host_post_event(vha->host, fc_get_event_number(),
+ aen_code, aen_data);
+
+ return rval;
+}
+
+static void
+qlafx00_update_host_attr(scsi_qla_host_t *vha, struct port_info_data *pinfo)
+{
+ u64 port_name = 0, node_name = 0;
+
+ port_name = (unsigned long long)wwn_to_u64(pinfo->port_name);
+ node_name = (unsigned long long)wwn_to_u64(pinfo->node_name);
+
+ fc_host_node_name(vha->host) = node_name;
+ fc_host_port_name(vha->host) = port_name;
+ if (!pinfo->port_type)
+ vha->hw->current_topology = ISP_CFG_F;
+ if (pinfo->link_status == QLAFX00_LINK_STATUS_UP)
+ atomic_set(&vha->loop_state, LOOP_READY);
+ else if (pinfo->link_status == QLAFX00_LINK_STATUS_DOWN)
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->hw->link_data_rate = (uint16_t)pinfo->link_config;
+}
+
+static void
+qla2x00_fxdisc_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+
+ complete(&lio->u.fxiocb.fxiocb_comp);
+}
+
+static void
+qla2x00_fxdisc_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+
+ complete(&lio->u.fxiocb.fxiocb_comp);
+}
+
+int
+qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
+{
+ srb_t *sp;
+ struct srb_iocb *fdisc;
+ int rval = QLA_FUNCTION_FAILED;
+ struct qla_hw_data *ha = vha->hw;
+ struct host_system_info *phost_info;
+ struct register_host_info *preg_hsi;
+ struct new_utsname *p_sysid = NULL;
+ struct timeval tv;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ fdisc = &sp->u.iocb_cmd;
+ switch (fx_type) {
+ case FXDISC_GET_CONFIG_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID;
+ fdisc->u.fxiocb.rsp_len = sizeof(struct config_info_data);
+ break;
+ case FXDISC_GET_PORT_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
+ fdisc->u.fxiocb.req_data = fcport->port_id;
+ break;
+ case FXDISC_GET_TGT_NODE_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
+ fdisc->u.fxiocb.req_data = fcport->tgt_id;
+ break;
+ case FXDISC_GET_TGT_NODE_LIST:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_LIST_SIZE;
+ break;
+ case FXDISC_REG_HOST_INFO:
+ fdisc->u.fxiocb.flags = SRB_FXDISC_REQ_DMA_VALID;
+ fdisc->u.fxiocb.req_len = sizeof(struct register_host_info);
+ p_sysid = utsname();
+ if (!p_sysid) {
+ ql_log(ql_log_warn, vha, 0x303c,
+ "Not able to get the system informtion\n");
+ goto done_free_sp;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (fdisc->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
+ fdisc->u.fxiocb.req_addr = dma_alloc_coherent(&ha->pdev->dev,
+ fdisc->u.fxiocb.req_len,
+ &fdisc->u.fxiocb.req_dma_handle, GFP_KERNEL);
+ if (!fdisc->u.fxiocb.req_addr)
+ goto done_free_sp;
+
+ if (fx_type == FXDISC_REG_HOST_INFO) {
+ preg_hsi = (struct register_host_info *)
+ fdisc->u.fxiocb.req_addr;
+ phost_info = &preg_hsi->hsi;
+ memset(preg_hsi, 0, sizeof(struct register_host_info));
+ phost_info->os_type = OS_TYPE_LINUX;
+ strncpy(phost_info->sysname,
+ p_sysid->sysname, SYSNAME_LENGTH);
+ strncpy(phost_info->nodename,
+ p_sysid->nodename, NODENAME_LENGTH);
+ strncpy(phost_info->release,
+ p_sysid->release, RELEASE_LENGTH);
+ strncpy(phost_info->version,
+ p_sysid->version, VERSION_LENGTH);
+ strncpy(phost_info->machine,
+ p_sysid->machine, MACHINE_LENGTH);
+ strncpy(phost_info->domainname,
+ p_sysid->domainname, DOMNAME_LENGTH);
+ strncpy(phost_info->hostdriver,
+ QLA2XXX_VERSION, VERSION_LENGTH);
+ do_gettimeofday(&tv);
+ preg_hsi->utc = (uint64_t)tv.tv_sec;
+ ql_dbg(ql_dbg_init, vha, 0x0149,
+ "ISP%04X: Host registration with firmware\n",
+ ha->pdev->device);
+ ql_dbg(ql_dbg_init, vha, 0x014a,
+ "os_type = '%d', sysname = '%s', nodname = '%s'\n",
+ phost_info->os_type,
+ phost_info->sysname,
+ phost_info->nodename);
+ ql_dbg(ql_dbg_init, vha, 0x014b,
+ "release = '%s', version = '%s'\n",
+ phost_info->release,
+ phost_info->version);
+ ql_dbg(ql_dbg_init, vha, 0x014c,
+ "machine = '%s' "
+ "domainname = '%s', hostdriver = '%s'\n",
+ phost_info->machine,
+ phost_info->domainname,
+ phost_info->hostdriver);
+ ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d,
+ (uint8_t *)phost_info,
+ sizeof(struct host_system_info));
+ }
+ }
+
+ if (fdisc->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
+ fdisc->u.fxiocb.rsp_addr = dma_alloc_coherent(&ha->pdev->dev,
+ fdisc->u.fxiocb.rsp_len,
+ &fdisc->u.fxiocb.rsp_dma_handle, GFP_KERNEL);
+ if (!fdisc->u.fxiocb.rsp_addr)
+ goto done_unmap_req;
+ }
+
+ sp->type = SRB_FXIOCB_DCMD;
+ sp->name = "fxdisc";
+ qla2x00_init_timer(sp, FXDISC_TIMEOUT);
+ fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
+ fdisc->u.fxiocb.req_func_type = fx_type;
+ sp->done = qla2x00_fxdisc_sp_done;
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_unmap_dma;
+
+ wait_for_completion(&fdisc->u.fxiocb.fxiocb_comp);
+
+ if (fx_type == FXDISC_GET_CONFIG_INFO) {
+ struct config_info_data *pinfo =
+ (struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(&vha->hw->mr.product_name, pinfo->product_name,
+ sizeof(vha->hw->mr.product_name));
+ memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
+ sizeof(vha->hw->mr.symbolic_name));
+ memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
+ sizeof(vha->hw->mr.serial_num));
+ memcpy(&vha->hw->mr.hw_version, pinfo->hw_version,
+ sizeof(vha->hw->mr.hw_version));
+ memcpy(&vha->hw->mr.fw_version, pinfo->fw_version,
+ sizeof(vha->hw->mr.fw_version));
+ strim(vha->hw->mr.fw_version);
+ memcpy(&vha->hw->mr.uboot_version, pinfo->uboot_version,
+ sizeof(vha->hw->mr.uboot_version));
+ memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
+ sizeof(vha->hw->mr.fru_serial_num));
+ } else if (fx_type == FXDISC_GET_PORT_INFO) {
+ struct port_info_data *pinfo =
+ (struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(vha->node_name, pinfo->node_name, WWN_SIZE);
+ memcpy(vha->port_name, pinfo->port_name, WWN_SIZE);
+ vha->d_id.b.domain = pinfo->port_id[0];
+ vha->d_id.b.area = pinfo->port_id[1];
+ vha->d_id.b.al_pa = pinfo->port_id[2];
+ qlafx00_update_host_attr(vha, pinfo);
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141,
+ (uint8_t *)pinfo, 16);
+ } else if (fx_type == FXDISC_GET_TGT_NODE_INFO) {
+ struct qlafx00_tgt_node_info *pinfo =
+ (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(fcport->node_name, pinfo->tgt_node_wwnn, WWN_SIZE);
+ memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE);
+ fcport->port_type = FCT_TARGET;
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144,
+ (uint8_t *)pinfo, 16);
+ } else if (fx_type == FXDISC_GET_TGT_NODE_LIST) {
+ struct qlafx00_tgt_node_info *pinfo =
+ (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
+ (uint8_t *)pinfo, 16);
+ memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
+ }
+ rval = fdisc->u.fxiocb.result;
+
+done_unmap_dma:
+ if (fdisc->u.fxiocb.rsp_addr)
+ dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.rsp_len,
+ fdisc->u.fxiocb.rsp_addr, fdisc->u.fxiocb.rsp_dma_handle);
+
+done_unmap_req:
+ if (fdisc->u.fxiocb.req_addr)
+ dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len,
+ fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle);
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+static void
+qlafx00_abort_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ abt->u.abt.comp_status = CS_TIMEOUT;
+ complete(&abt->u.abt.comp);
+}
+
+static void
+qlafx00_abort_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ complete(&abt->u.abt.comp);
+}
+
+static int
+qlafx00_async_abt_cmd(srb_t *cmd_sp)
+{
+ scsi_qla_host_t *vha = cmd_sp->fcport->vha;
+ fc_port_t *fcport = cmd_sp->fcport;
+ struct srb_iocb *abt_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ abt_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_ABT_CMD;
+ sp->name = "abort";
+ qla2x00_init_timer(sp, FXDISC_TIMEOUT);
+ abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
+ sp->done = qlafx00_abort_sp_done;
+ abt_iocb->timeout = qlafx00_abort_iocb_timeout;
+ init_completion(&abt_iocb->u.abt.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, target_id=%x\n",
+ cmd_sp->handle, fcport->tgt_id);
+
+ wait_for_completion(&abt_iocb->u.abt.comp);
+
+ rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+int
+qlafx00_abort_command(srb_t *sp)
+{
+ unsigned long flags = 0;
+
+ uint32_t handle;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = vha->req;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (handle = 1; handle < DEFAULT_OUTSTANDING_COMMANDS; handle++) {
+ if (req->outstanding_cmds[handle] == sp)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (handle == DEFAULT_OUTSTANDING_COMMANDS) {
+ /* Command not found. */
+ return QLA_FUNCTION_FAILED;
+ }
+ return qlafx00_async_abt_cmd(sp);
+}
+
+/*
+ * qlafx00_initialize_adapter
+ * Initialize board.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_initialize_adapter(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Clear adapter flags. */
+ vha->flags.online = 0;
+ ha->flags.chip_reset_done = 0;
+ vha->flags.reset_active = 0;
+ ha->flags.pci_channel_io_perm_failure = 0;
+ ha->flags.eeh_busy = 0;
+ ha->thermal_support = 0;
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->device_flags = DFLG_NO_CABLE;
+ vha->dpc_flags = 0;
+ vha->flags.management_server_logged_in = 0;
+ vha->marker_needed = 0;
+ ha->isp_abort_cnt = 0;
+ ha->beacon_blink_led = 0;
+
+ set_bit(0, ha->req_qid_map);
+ set_bit(0, ha->rsp_qid_map);
+
+ ql_dbg(ql_dbg_init, vha, 0x0147,
+ "Configuring PCI space...\n");
+
+ rval = ha->isp_ops->pci_config(vha);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x0148,
+ "Unable to configure PCI space.\n");
+ return rval;
+ }
+
+ rval = qlafx00_init_fw_ready(vha);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ qlafx00_save_queue_ptrs(vha);
+
+ rval = qlafx00_config_queues(vha);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ /*
+ * Allocate the array of outstanding commands
+ * now that we know the firmware resources.
+ */
+ rval = qla2x00_alloc_outstanding_cmds(ha, vha->req);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ rval = qla2x00_init_rings(vha);
+ ha->flags.chip_reset_done = 1;
+
+ return rval;
+}
+
+uint32_t
+qlafx00_fw_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int rval = QLA_FUNCTION_FAILED;
+ uint32_t state[1];
+
+ if (qla2x00_reset_active(vha))
+ ql_log(ql_log_warn, vha, 0x70ce,
+ "ISP reset active.\n");
+ else if (!vha->hw->flags.eeh_busy) {
+ rval = qlafx00_get_firmware_state(vha, state);
+ }
+ if (rval != QLA_SUCCESS)
+ memset(state, -1, sizeof(state));
+
+ return state[0];
+}
+
+void
+qlafx00_get_host_speed(struct Scsi_Host *shost)
+{
+ struct qla_hw_data *ha = ((struct scsi_qla_host *)
+ (shost_priv(shost)))->hw;
+ u32 speed = FC_PORTSPEED_UNKNOWN;
+
+ switch (ha->link_data_rate) {
+ case QLAFX00_PORT_SPEED_2G:
+ speed = FC_PORTSPEED_2GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_4G:
+ speed = FC_PORTSPEED_4GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_8G:
+ speed = FC_PORTSPEED_8GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_10G:
+ speed = FC_PORTSPEED_10GBIT;
+ break;
+ }
+ fc_host_speed(shost) = speed;
+}
+
+/** QLAFX00 specific ISR implementation functions */
+
+static inline void
+qlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
+ uint32_t sense_len, struct rsp_que *rsp, int res)
+{
+ struct scsi_qla_host *vha = sp->fcport->vha;
+ struct scsi_cmnd *cp = GET_CMD_SP(sp);
+ uint32_t track_sense_len;
+
+ SET_FW_SENSE_LEN(sp, sense_len);
+
+ if (sense_len >= SCSI_SENSE_BUFFERSIZE)
+ sense_len = SCSI_SENSE_BUFFERSIZE;
+
+ SET_CMD_SENSE_LEN(sp, sense_len);
+ SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
+ track_sense_len = sense_len;
+
+ if (sense_len > par_sense_len)
+ sense_len = par_sense_len;
+
+ memcpy(cp->sense_buffer, sense_data, sense_len);
+
+ SET_FW_SENSE_LEN(sp, GET_FW_SENSE_LEN(sp) - sense_len);
+
+ SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
+ track_sense_len -= sense_len;
+ SET_CMD_SENSE_LEN(sp, track_sense_len);
+
+ ql_dbg(ql_dbg_io, vha, 0x304d,
+ "sense_len=0x%x par_sense_len=0x%x track_sense_len=0x%x.\n",
+ sense_len, par_sense_len, track_sense_len);
+ if (GET_FW_SENSE_LEN(sp) > 0) {
+ rsp->status_srb = sp;
+ cp->result = res;
+ }
+
+ if (sense_len) {
+ ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3039,
+ "Check condition Sense data, nexus%ld:%d:%d cmd=%p.\n",
+ sp->fcport->vha->host_no, cp->device->id, cp->device->lun,
+ cp);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3049,
+ cp->sense_buffer, sense_len);
+ }
+}
+
+static void
+qlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
+ uint16_t sstatus, uint16_t cpstatus)
+{
+ struct srb_iocb *tmf;
+
+ tmf = &sp->u.iocb_cmd;
+ if (cpstatus != CS_COMPLETE ||
+ (sstatus & SS_RESPONSE_INFO_LEN_VALID))
+ cpstatus = CS_INCOMPLETE;
+ tmf->u.tmf.comp_status = cpstatus;
+ sp->done(vha, sp, 0);
+}
+
+static void
+qlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct abort_iocb_entry_fx00 *pkt)
+{
+ const char func[] = "ABT_IOCB";
+ srb_t *sp;
+ struct srb_iocb *abt;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ abt = &sp->u.iocb_cmd;
+ abt->u.abt.comp_status = le32_to_cpu(pkt->tgt_id_sts);
+ sp->done(vha, sp, 0);
+}
+
+static void
+qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct ioctl_iocb_entry_fx00 *pkt)
+{
+ const char func[] = "IOSB_IOCB";
+ srb_t *sp;
+ struct fc_bsg_job *bsg_job;
+ struct srb_iocb *iocb_job;
+ int res;
+ struct qla_mt_iocb_rsp_fx00 fstatus;
+ uint8_t *fw_sts_ptr;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ if (sp->type == SRB_FXIOCB_DCMD) {
+ iocb_job = &sp->u.iocb_cmd;
+ iocb_job->u.fxiocb.seq_number = le32_to_cpu(pkt->seq_no);
+ iocb_job->u.fxiocb.fw_flags = le32_to_cpu(pkt->fw_iotcl_flags);
+ iocb_job->u.fxiocb.result = le32_to_cpu(pkt->status);
+ if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
+ iocb_job->u.fxiocb.req_data =
+ le32_to_cpu(pkt->dataword_r);
+ } else {
+ bsg_job = sp->u.bsg_job;
+
+ memset(&fstatus, 0, sizeof(struct qla_mt_iocb_rsp_fx00));
+
+ fstatus.reserved_1 = pkt->reserved_0;
+ fstatus.func_type = pkt->comp_func_num;
+ fstatus.ioctl_flags = pkt->fw_iotcl_flags;
+ fstatus.ioctl_data = pkt->dataword_r;
+ fstatus.adapid = pkt->adapid;
+ fstatus.adapid_hi = pkt->adapid_hi;
+ fstatus.reserved_2 = pkt->reserved_1;
+ fstatus.res_count = pkt->residuallen;
+ fstatus.status = pkt->status;
+ fstatus.seq_number = pkt->seq_no;
+ memcpy(fstatus.reserved_3,
+ pkt->reserved_2, 20 * sizeof(uint8_t));
+
+ fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+ sizeof(struct fc_bsg_reply);
+
+ memcpy(fw_sts_ptr, (uint8_t *)&fstatus,
+ sizeof(struct qla_mt_iocb_rsp_fx00));
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
+ sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t);
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x5080,
+ (uint8_t *)pkt, sizeof(struct ioctl_iocb_entry_fx00));
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x5074,
+ (uint8_t *)fw_sts_ptr, sizeof(struct qla_mt_iocb_rsp_fx00));
+
+ res = bsg_job->reply->result = DID_OK << 16;
+ bsg_job->reply->reply_payload_rcv_len =
+ bsg_job->reply_payload.payload_len;
+ }
+ sp->done(vha, sp, res);
+}
+
+/**
+ * qlafx00_status_entry() - Process a Status IOCB entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
+{
+ srb_t *sp;
+ fc_port_t *fcport;
+ struct scsi_cmnd *cp;
+ struct sts_entry_fx00 *sts;
+ uint16_t comp_status;
+ uint16_t scsi_status;
+ uint16_t ox_id;
+ uint8_t lscsi_status;
+ int32_t resid;
+ uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
+ fw_resid_len;
+ uint8_t *rsp_info = NULL, *sense_data = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t hindex, handle;
+ uint16_t que;
+ struct req_que *req;
+ int logit = 1;
+ int res = 0;
+
+ sts = (struct sts_entry_fx00 *) pkt;
+
+ comp_status = le16_to_cpu(sts->comp_status);
+ scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
+ hindex = sts->handle;
+ handle = LSW(hindex);
+
+ que = MSW(hindex);
+ req = ha->req_q_map[que];
+
+ /* Validate handle. */
+ if (handle < req->num_outstanding_cmds)
+ sp = req->outstanding_cmds[handle];
+ else
+ sp = NULL;
+
+ if (sp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3034,
+ "Invalid status handle (0x%x).\n", handle);
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+
+ if (sp->type == SRB_TM_CMD) {
+ req->outstanding_cmds[handle] = NULL;
+ qlafx00_tm_iocb_entry(vha, req, pkt, sp,
+ scsi_status, comp_status);
+ return;
+ }
+
+ /* Fast path completion. */
+ if (comp_status == CS_COMPLETE && scsi_status == 0) {
+ qla2x00_do_host_ramp_up(vha);
+ qla2x00_process_completed_request(vha, req, handle);
+ return;
+ }
+
+ req->outstanding_cmds[handle] = NULL;
+ cp = GET_CMD_SP(sp);
+ if (cp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3048,
+ "Command already returned (0x%x/%p).\n",
+ handle, sp);
+
+ return;
+ }
+
+ lscsi_status = scsi_status & STATUS_MASK;
+
+ fcport = sp->fcport;
+
+ ox_id = 0;
+ sense_len = par_sense_len = rsp_info_len = resid_len =
+ fw_resid_len = 0;
+ if (scsi_status & SS_SENSE_LEN_VALID)
+ sense_len = le32_to_cpu(sts->sense_len);
+ if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+ resid_len = le32_to_cpu(sts->residual_len);
+ if (comp_status == CS_DATA_UNDERRUN)
+ fw_resid_len = le32_to_cpu(sts->residual_len);
+ rsp_info = sense_data = sts->data;
+ par_sense_len = sizeof(sts->data);
+
+ /* Check for overrun. */
+ if (comp_status == CS_COMPLETE &&
+ scsi_status & SS_RESIDUAL_OVER)
+ comp_status = CS_DATA_OVERRUN;
+
+ /*
+ * Based on Host and scsi status generate status code for Linux
+ */
+ switch (comp_status) {
+ case CS_COMPLETE:
+ case CS_QUEUE_FULL:
+ if (scsi_status == 0) {
+ res = DID_OK << 16;
+ break;
+ }
+ if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
+ resid = resid_len;
+ scsi_set_resid(cp, resid);
+
+ if (!lscsi_status &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3050,
+ "Mid-layer underflow "
+ "detected (0x%x of 0x%x bytes).\n",
+ resid, scsi_bufflen(cp));
+
+ res = DID_ERROR << 16;
+ break;
+ }
+ }
+ res = DID_OK << 16 | lscsi_status;
+
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
+ "QUEUE FULL detected.\n");
+ break;
+ }
+ logit = 0;
+ if (lscsi_status != SS_CHECK_CONDITION)
+ break;
+
+ memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ if (!(scsi_status & SS_SENSE_LEN_VALID))
+ break;
+
+ qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
+ rsp, res);
+ break;
+
+ case CS_DATA_UNDERRUN:
+ /* Use F/W calculated residual length. */
+ if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
+ resid = fw_resid_len;
+ else
+ resid = resid_len;
+ scsi_set_resid(cp, resid);
+ if (scsi_status & SS_RESIDUAL_UNDER) {
+ if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
+ && fw_resid_len != resid_len) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
+ "Dropped frame(s) detected "
+ "(0x%x of 0x%x bytes).\n",
+ resid, scsi_bufflen(cp));
+
+ res = DID_ERROR << 16 | lscsi_status;
+ goto check_scsi_status;
+ }
+
+ if (!lscsi_status &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3053,
+ "Mid-layer underflow "
+ "detected (0x%x of 0x%x bytes, "
+ "cp->underflow: 0x%x).\n",
+ resid, scsi_bufflen(cp), cp->underflow);
+
+ res = DID_ERROR << 16;
+ break;
+ }
+ } else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
+ lscsi_status != SAM_STAT_BUSY) {
+ /*
+ * scsi status of task set and busy are considered
+ * to be task not completed.
+ */
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3054,
+ "Dropped frame(s) detected (0x%x "
+ "of 0x%x bytes).\n", resid,
+ scsi_bufflen(cp));
+
+ res = DID_ERROR << 16 | lscsi_status;
+ goto check_scsi_status;
+ } else {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
+ "scsi_status: 0x%x, lscsi_status: 0x%x\n",
+ scsi_status, lscsi_status);
+ }
+
+ res = DID_OK << 16 | lscsi_status;
+ logit = 0;
+
+check_scsi_status:
+ /*
+ * Check to see if SCSI Status is non zero. If so report SCSI
+ * Status.
+ */
+ if (lscsi_status != 0) {
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
+ "QUEUE FULL detected.\n");
+ logit = 1;
+ break;
+ }
+ if (lscsi_status != SS_CHECK_CONDITION)
+ break;
+
+ memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ if (!(scsi_status & SS_SENSE_LEN_VALID))
+ break;
+
+ qlafx00_handle_sense(sp, sense_data, par_sense_len,
+ sense_len, rsp, res);
+ }
+ break;
+
+ case CS_PORT_LOGGED_OUT:
+ case CS_PORT_CONFIG_CHG:
+ case CS_PORT_BUSY:
+ case CS_INCOMPLETE:
+ case CS_PORT_UNAVAILABLE:
+ case CS_TIMEOUT:
+ case CS_RESET:
+
+ /*
+ * We are going to have the fc class block the rport
+ * while we try to recover so instruct the mid layer
+ * to requeue until the class decides how to handle this.
+ */
+ res = DID_TRANSPORT_DISRUPTED << 16;
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3057,
+ "Port down status: port-state=0x%x.\n",
+ atomic_read(&fcport->state));
+
+ if (atomic_read(&fcport->state) == FCS_ONLINE)
+ qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
+ break;
+
+ case CS_ABORTED:
+ res = DID_RESET << 16;
+ break;
+
+ default:
+ res = DID_ERROR << 16;
+ break;
+ }
+
+ if (logit)
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
+ "FCP command status: 0x%x-0x%x (0x%x) "
+ "nexus=%ld:%d:%d tgt_id: 0x%x lscsi_status: 0x%x"
+ "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
+ "rsp_info=0x%x resid=0x%x fw_resid=0x%x "
+ "sense_len=0x%x, par_sense_len=0x%x, rsp_info_len=0x%x\n",
+ comp_status, scsi_status, res, vha->host_no,
+ cp->device->id, cp->device->lun, fcport->tgt_id,
+ lscsi_status, cp->cmnd[0], cp->cmnd[1], cp->cmnd[2],
+ cp->cmnd[3], cp->cmnd[4], cp->cmnd[5], cp->cmnd[6],
+ cp->cmnd[7], cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp),
+ rsp_info_len, resid_len, fw_resid_len, sense_len,
+ par_sense_len, rsp_info_len);
+
+ if (!res)
+ qla2x00_do_host_ramp_up(vha);
+
+ if (rsp->status_srb == NULL)
+ sp->done(ha, sp, res);
+}
+
+/**
+ * qlafx00_status_cont_entry() - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
+{
+ uint8_t sense_sz = 0;
+ struct qla_hw_data *ha = rsp->hw;
+ struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
+ srb_t *sp = rsp->status_srb;
+ struct scsi_cmnd *cp;
+ uint32_t sense_len;
+ uint8_t *sense_ptr;
+
+ if (!sp) {
+ ql_dbg(ql_dbg_io, vha, 0x3037,
+ "no SP, sp = %p\n", sp);
+ return;
+ }
+
+ if (!GET_FW_SENSE_LEN(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x304b,
+ "no fw sense data, sp = %p\n", sp);
+ return;
+ }
+ cp = GET_CMD_SP(sp);
+ if (cp == NULL) {
+ ql_log(ql_log_warn, vha, 0x303b,
+ "cmd is NULL: already returned to OS (sp=%p).\n", sp);
+
+ rsp->status_srb = NULL;
+ return;
+ }
+
+ if (!GET_CMD_SENSE_LEN(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x304c,
+ "no sense data, sp = %p\n", sp);
+ } else {
+ sense_len = GET_CMD_SENSE_LEN(sp);
+ sense_ptr = GET_CMD_SENSE_PTR(sp);
+ ql_dbg(ql_dbg_io, vha, 0x304f,
+ "sp=%p sense_len=0x%x sense_ptr=%p.\n",
+ sp, sense_len, sense_ptr);
+
+ if (sense_len > sizeof(pkt->data))
+ sense_sz = sizeof(pkt->data);
+ else
+ sense_sz = sense_len;
+
+ /* Move sense data. */
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e,
+ (uint8_t *)pkt, sizeof(sts_cont_entry_t));
+ memcpy(sense_ptr, pkt->data, sense_sz);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a,
+ sense_ptr, sense_sz);
+
+ sense_len -= sense_sz;
+ sense_ptr += sense_sz;
+
+ SET_CMD_SENSE_PTR(sp, sense_ptr);
+ SET_CMD_SENSE_LEN(sp, sense_len);
+ }
+ sense_len = GET_FW_SENSE_LEN(sp);
+ sense_len = (sense_len > sizeof(pkt->data)) ?
+ (sense_len - sizeof(pkt->data)) : 0;
+ SET_FW_SENSE_LEN(sp, sense_len);
+
+ /* Place command on done queue. */
+ if (sense_len == 0) {
+ rsp->status_srb = NULL;
+ sp->done(ha, sp, cp->result);
+ }
+}
+
+/**
+ * qlafx00_multistatus_entry() - Process Multi response queue entries.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_multistatus_entry(struct scsi_qla_host *vha,
+ struct rsp_que *rsp, void *pkt)
+{
+ srb_t *sp;
+ struct multi_sts_entry_fx00 *stsmfx;
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t handle, hindex, handle_count, i;
+ uint16_t que;
+ struct req_que *req;
+ uint32_t *handle_ptr;
+
+ stsmfx = (struct multi_sts_entry_fx00 *) pkt;
+
+ handle_count = stsmfx->handle_count;
+
+ if (handle_count > MAX_HANDLE_COUNT) {
+ ql_dbg(ql_dbg_io, vha, 0x3035,
+ "Invalid handle count (0x%x).\n", handle_count);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+
+ handle_ptr = (uint32_t *) &stsmfx->handles[0];
+
+ for (i = 0; i < handle_count; i++) {
+ hindex = le32_to_cpu(*handle_ptr);
+ handle = LSW(hindex);
+ que = MSW(hindex);
+ req = ha->req_q_map[que];
+
+ /* Validate handle. */
+ if (handle < req->num_outstanding_cmds)
+ sp = req->outstanding_cmds[handle];
+ else
+ sp = NULL;
+
+ if (sp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3044,
+ "Invalid status handle (0x%x).\n", handle);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+ qla2x00_process_completed_request(vha, req, handle);
+ handle_ptr++;
+ }
+}
+
+/**
+ * qlafx00_error_entry() - Process an error entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
+ struct sts_entry_fx00 *pkt, uint8_t estatus, uint8_t etype)
+{
+ srb_t *sp;
+ struct qla_hw_data *ha = vha->hw;
+ const char func[] = "ERROR-IOCB";
+ uint16_t que = MSW(pkt->handle);
+ struct req_que *req = NULL;
+ int res = DID_ERROR << 16;
+
+ ql_dbg(ql_dbg_async, vha, 0x507f,
+ "type of error status in response: 0x%x\n", estatus);
+
+ req = ha->req_q_map[que];
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (sp) {
+ sp->done(ha, sp, res);
+ return;
+ }
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+}
+
+/**
+ * qlafx00_process_response_queue() - Process response queue entries.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_process_response_queue(struct scsi_qla_host *vha,
+ struct rsp_que *rsp)
+{
+ struct sts_entry_fx00 *pkt;
+ response_t *lptr;
+
+ if (!vha->flags.online)
+ return;
+
+ while (RD_REG_DWORD(&(rsp->ring_ptr->signature)) !=
+ RESPONSE_PROCESSED) {
+ lptr = rsp->ring_ptr;
+ memcpy_fromio(rsp->rsp_pkt, lptr, sizeof(rsp->rsp_pkt));
+ pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
+
+ rsp->ring_index++;
+ if (rsp->ring_index == rsp->length) {
+ rsp->ring_index = 0;
+ rsp->ring_ptr = rsp->ring;
+ } else {
+ rsp->ring_ptr++;
+ }
+
+ if (pkt->entry_status != 0 &&
+ pkt->entry_type != IOCTL_IOSB_TYPE_FX00) {
+ qlafx00_error_entry(vha, rsp,
+ (struct sts_entry_fx00 *)pkt, pkt->entry_status,
+ pkt->entry_type);
+ goto next_iter;
+ continue;
+ }
+
+ switch (pkt->entry_type) {
+ case STATUS_TYPE_FX00:
+ qlafx00_status_entry(vha, rsp, pkt);
+ break;
+
+ case STATUS_CONT_TYPE_FX00:
+ qlafx00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
+ break;
+
+ case MULTI_STATUS_TYPE_FX00:
+ qlafx00_multistatus_entry(vha, rsp, pkt);
+ break;
+
+ case ABORT_IOCB_TYPE_FX00:
+ qlafx00_abort_iocb_entry(vha, rsp->req,
+ (struct abort_iocb_entry_fx00 *)pkt);
+ break;
+
+ case IOCTL_IOSB_TYPE_FX00:
+ qlafx00_ioctl_iosb_entry(vha, rsp->req,
+ (struct ioctl_iocb_entry_fx00 *)pkt);
+ break;
+ default:
+ /* Type Not Supported. */
+ ql_dbg(ql_dbg_async, vha, 0x5081,
+ "Received unknown response pkt type %x "
+ "entry status=%x.\n",
+ pkt->entry_type, pkt->entry_status);
+ break;
+ }
+next_iter:
+ WRT_REG_DWORD(&lptr->signature, RESPONSE_PROCESSED);
+ wmb();
+ }
+
+ /* Adjust ring index */
+ WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
+}
+
+/**
+ * qlafx00_async_event() - Process aynchronous events.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_async_event(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg;
+ int data_size = 1;
+
+ reg = &ha->iobase->ispfx00;
+ /* Setup to process RIO completion. */
+ switch (ha->aenmb[0]) {
+ case QLAFX00_MBA_SYSTEM_ERR: /* System Error */
+ ql_log(ql_log_warn, vha, 0x5079,
+ "ISP System Error - mbx1=%x\n", ha->aenmb[0]);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+
+ case QLAFX00_MBA_SHUTDOWN_RQSTD: /* Shutdown requested */
+ ql_dbg(ql_dbg_async, vha, 0x5076,
+ "Asynchronous FW shutdown requested.\n");
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ break;
+
+ case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
+ ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ql_dbg(ql_dbg_async, vha, 0x5077,
+ "Asynchronous port Update received "
+ "aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
+ ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
+ data_size = 4;
+ break;
+ default:
+ ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ha->aenmb[4] = RD_REG_WORD(&reg->aenmailbox4);
+ ha->aenmb[5] = RD_REG_WORD(&reg->aenmailbox5);
+ ha->aenmb[6] = RD_REG_WORD(&reg->aenmailbox6);
+ ha->aenmb[7] = RD_REG_WORD(&reg->aenmailbox7);
+ ql_dbg(ql_dbg_async, vha, 0x5078,
+ "AEN:%04x %04x %04x %04x :%04x %04x %04x %04x\n",
+ ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3],
+ ha->aenmb[4], ha->aenmb[5], ha->aenmb[6], ha->aenmb[7]);
+ break;
+ }
+ qlafx00_post_aenfx_work(vha, ha->aenmb[0],
+ (uint32_t *)ha->aenmb, data_size);
+}
+
+/**
+ *
+ * qlafx00x_mbx_completion() - Process mailbox command completions.
+ * @ha: SCSI driver HA context
+ * @mb16: Mailbox16 register
+ */
+static void
+qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
+{
+ uint16_t cnt;
+ uint16_t __iomem *wptr;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+
+ if (!ha->mcp32)
+ ql_dbg(ql_dbg_async, vha, 0x507e, "MBX pointer ERROR.\n");
+
+ /* Load return mailbox registers. */
+ ha->flags.mbox_int = 1;
+ ha->mailbox_out32[0] = mb0;
+ wptr = (uint16_t __iomem *)&reg->mailbox17;
+
+ for (cnt = 1; cnt < ha->mbx_count; cnt++) {
+ ha->mailbox_out32[cnt] = RD_REG_WORD(wptr);
+ wptr++;
+ }
+}
+
+/**
+ * qlafx00_intr_handler() - Process interrupts for the ISPFX00.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qlafx00_intr_handler(int irq, void *dev_id)
+{
+ scsi_qla_host_t *vha;
+ struct qla_hw_data *ha;
+ struct device_reg_fx00 __iomem *reg;
+ int status;
+ unsigned long iter;
+ uint32_t stat;
+ uint32_t mb[8];
+ struct rsp_que *rsp;
+ unsigned long flags;
+ uint32_t clr_intr = 0;
+
+ rsp = (struct rsp_que *) dev_id;
+ if (!rsp) {
+ ql_log(ql_log_info, NULL, 0x507d,
+ "%s: NULL response queue pointer.\n", __func__);
+ return IRQ_NONE;
+ }
+
+ ha = rsp->hw;
+ reg = &ha->iobase->ispfx00;
+ status = 0;
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ vha = pci_get_drvdata(ha->pdev);
+ for (iter = 50; iter--; clr_intr = 0) {
+ stat = QLAFX00_RD_INTR_REG(ha);
+ if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
+ break;
+
+ switch (stat & QLAFX00_HST_INT_STS_BITS) {
+ case QLAFX00_INTR_MB_CMPLT:
+ case QLAFX00_INTR_MB_RSP_CMPLT:
+ case QLAFX00_INTR_MB_ASYNC_CMPLT:
+ case QLAFX00_INTR_ALL_CMPLT:
+ mb[0] = RD_REG_WORD(&reg->mailbox16);
+ qlafx00_mbx_completion(vha, mb[0]);
+ status |= MBX_INTERRUPT;
+ clr_intr |= QLAFX00_INTR_MB_CMPLT;
+ break;
+ case QLAFX00_INTR_ASYNC_CMPLT:
+ case QLAFX00_INTR_RSP_ASYNC_CMPLT:
+ ha->aenmb[0] = RD_REG_WORD(&reg->aenmailbox0);
+ qlafx00_async_event(vha);
+ clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
+ break;
+ case QLAFX00_INTR_RSP_CMPLT:
+ qlafx00_process_response_queue(vha, rsp);
+ clr_intr |= QLAFX00_INTR_RSP_CMPLT;
+ break;
+ default:
+ ql_dbg(ql_dbg_async, vha, 0x507a,
+ "Unrecognized interrupt type (%d).\n", stat);
+ break;
+ }
+ QLAFX00_CLR_INTR_REG(ha, clr_intr);
+ QLAFX00_RD_INTR_REG(ha);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ complete(&ha->mbx_intr_comp);
+ }
+ return IRQ_HANDLED;
+}
+
+/** QLAFX00 specific IOCB implementation functions */
+
+static inline cont_a64_entry_t *
+qlafx00_prep_cont_type1_iocb(struct req_que *req,
+ cont_a64_entry_t *lcont_pkt)
+{
+ cont_a64_entry_t *cont_pkt;
+
+ /* Adjust ring index. */
+ req->ring_index++;
+ if (req->ring_index == req->length) {
+ req->ring_index = 0;
+ req->ring_ptr = req->ring;
+ } else {
+ req->ring_ptr++;
+ }
+
+ cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
+
+ /* Load packet defaults. */
+ *((uint32_t *)(&lcont_pkt->entry_type)) =
+ __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00);
+
+ return cont_pkt;
+}
+
+static inline void
+qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
+ uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
+{
+ uint16_t avail_dsds;
+ uint32_t *cur_dsd;
+ scsi_qla_host_t *vha;
+ struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i, cont;
+ struct req_que *req;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt;
+
+ vha = sp->fcport->vha;
+ req = vha->req;
+
+ cmd = GET_CMD_SP(sp);
+ cont = 0;
+ cont_pkt = NULL;
+
+ /* Update entry type to indicate Command Type 3 IOCB */
+ *((uint32_t *)(&lcmd_pkt->entry_type)) =
+ __constant_cpu_to_le32(FX00_COMMAND_TYPE_7);
+
+ /* No data transfer */
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
+ lcmd_pkt->byte_count = __constant_cpu_to_le32(0);
+ return;
+ }
+
+ /* Set transfer direction */
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ lcmd_pkt->cntrl_flags =
+ __constant_cpu_to_le16(TMF_WRITE_DATA);
+ vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+ } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ lcmd_pkt->cntrl_flags =
+ __constant_cpu_to_le16(TMF_READ_DATA);
+ vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+ }
+
+ /* One DSD is available in the Command Type 3 IOCB */
+ avail_dsds = 1;
+ cur_dsd = (uint32_t *)&lcmd_pkt->dseg_0_address;
+
+ /* Load data segments */
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
+ cur_dsd = (uint32_t *)lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+}
+
+/**
+ * qlafx00_start_scsi() - Send a SCSI command to the ISP
+ * @sp: command to send to the ISP
+ *
+ * Returns non-zero if a failure occurred, else zero.
+ */
+int
+qlafx00_start_scsi(srb_t *sp)
+{
+ int ret, nseg;
+ unsigned long flags;
+ uint32_t index;
+ uint32_t handle;
+ uint16_t cnt;
+ uint16_t req_cnt;
+ uint16_t tot_dsds;
+ struct req_que *req = NULL;
+ struct rsp_que *rsp = NULL;
+ struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+ struct scsi_qla_host *vha = sp->fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct cmd_type_7_fx00 *cmd_pkt;
+ struct cmd_type_7_fx00 lcmd_pkt;
+ struct scsi_lun llun;
+ char tag[2];
+
+ /* Setup device pointers. */
+ ret = 0;
+
+ rsp = ha->rsp_q_map[0];
+ req = vha->req;
+
+ /* So we know we haven't pci_map'ed anything yet */
+ tot_dsds = 0;
+
+ /* Forcing marker needed for now */
+ vha->marker_needed = 0;
+
+ /* Send marker if required */
+ if (vha->marker_needed != 0) {
+ if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+ QLA_SUCCESS)
+ return QLA_FUNCTION_FAILED;
+ vha->marker_needed = 0;
+ }
+
+ /* Acquire ring specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Check for room in outstanding command list. */
+ handle = req->current_outstanding_cmd;
+ for (index = 1; index < req->num_outstanding_cmds; index++) {
+ handle++;
+ if (handle == req->num_outstanding_cmds)
+ handle = 1;
+ if (!req->outstanding_cmds[handle])
+ break;
+ }
+ if (index == req->num_outstanding_cmds)
+ goto queuing_error;
+
+ /* Map the sg table so we have an accurate count of sg entries needed */
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
+ goto queuing_error;
+ } else
+ nseg = 0;
+
+ tot_dsds = nseg;
+ req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+ if (req->cnt < (req_cnt + 2)) {
+ cnt = RD_REG_DWORD_RELAXED(req->req_q_out);
+
+ if (req->ring_index < cnt)
+ req->cnt = cnt - req->ring_index;
+ else
+ req->cnt = req->length -
+ (req->ring_index - cnt);
+ if (req->cnt < (req_cnt + 2))
+ goto queuing_error;
+ }
+
+ /* Build command packet. */
+ req->current_outstanding_cmd = handle;
+ req->outstanding_cmds[handle] = sp;
+ sp->handle = handle;
+ cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+ req->cnt -= req_cnt;
+
+ cmd_pkt = (struct cmd_type_7_fx00 *)req->ring_ptr;
+
+ memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
+
+ lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle);
+ lcmd_pkt.handle_hi = 0;
+ lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
+ lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
+
+ int_to_scsilun(cmd->device->lun, &llun);
+ host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun,
+ sizeof(lcmd_pkt.lun));
+
+ /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ lcmd_pkt.task = TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ lcmd_pkt.task = TSK_ORDERED;
+ break;
+ }
+ }
+
+ /* Load SCSI command packet. */
+ host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb));
+ lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+
+ /* Build IOCB segments */
+ qlafx00_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, &lcmd_pkt);
+
+ /* Set total data segment count. */
+ lcmd_pkt.entry_count = (uint8_t)req_cnt;
+
+ /* Specify response queue number where completion should happen */
+ lcmd_pkt.entry_status = (uint8_t) rsp->id;
+
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
+ (uint8_t *)cmd->cmnd, cmd->cmd_len);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032,
+ (uint8_t *)&lcmd_pkt, REQUEST_ENTRY_SIZE);
+
+ memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE);
+ wmb();
+
+ /* Adjust ring index. */
+ req->ring_index++;
+ if (req->ring_index == req->length) {
+ req->ring_index = 0;
+ req->ring_ptr = req->ring;
+ } else
+ req->ring_ptr++;
+
+ sp->flags |= SRB_DMA_VALID;
+
+ /* Set chip new ring index. */
+ WRT_REG_DWORD(req->req_q_in, req->ring_index);
+ QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return QLA_SUCCESS;
+
+queuing_error:
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_FUNCTION_FAILED;
+}
+
+void
+qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+ struct tsk_mgmt_entry_fx00 tm_iocb;
+ struct scsi_lun llun;
+
+ memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00));
+ tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
+ tm_iocb.entry_count = 1;
+ tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ tm_iocb.handle_hi = 0;
+ tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
+ tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
+ tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
+ if (tm_iocb.control_flags == TCF_LUN_RESET) {
+ int_to_scsilun(fxio->u.tmf.lun, &llun);
+ host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
+ sizeof(struct scsi_lun));
+ }
+
+ memcpy((void __iomem *)ptm_iocb, &tm_iocb,
+ sizeof(struct tsk_mgmt_entry_fx00));
+ wmb();
+}
+
+void
+qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+ struct abort_iocb_entry_fx00 abt_iocb;
+
+ memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00));
+ abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00;
+ abt_iocb.entry_count = 1;
+ abt_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ abt_iocb.abort_handle =
+ cpu_to_le32(MAKE_HANDLE(req->id, fxio->u.abt.cmd_hndl));
+ abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
+ abt_iocb.req_que_no = cpu_to_le16(req->id);
+
+ memcpy((void __iomem *)pabt_iocb, &abt_iocb,
+ sizeof(struct abort_iocb_entry_fx00));
+ wmb();
+}
+
+void
+qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
+ struct fc_bsg_job *bsg_job;
+ struct fxdisc_entry_fx00 fx_iocb;
+ uint8_t entry_cnt = 1;
+
+ memset(&fx_iocb, 0, sizeof(struct fxdisc_entry_fx00));
+ fx_iocb.entry_type = FX00_IOCB_TYPE;
+ fx_iocb.handle = cpu_to_le32(sp->handle);
+ fx_iocb.entry_count = entry_cnt;
+
+ if (sp->type == SRB_FXIOCB_DCMD) {
+ fx_iocb.func_num =
+ cpu_to_le16(sp->u.iocb_cmd.u.fxiocb.req_func_type);
+ fx_iocb.adapid = cpu_to_le32(fxio->u.fxiocb.adapter_id);
+ fx_iocb.adapid_hi = cpu_to_le32(fxio->u.fxiocb.adapter_id_hi);
+ fx_iocb.reserved_0 = cpu_to_le32(fxio->u.fxiocb.reserved_0);
+ fx_iocb.reserved_1 = cpu_to_le32(fxio->u.fxiocb.reserved_1);
+ fx_iocb.dataword_extra =
+ cpu_to_le32(fxio->u.fxiocb.req_data_extra);
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
+ fx_iocb.req_dsdcnt = cpu_to_le16(1);
+ fx_iocb.req_xfrcnt =
+ cpu_to_le16(fxio->u.fxiocb.req_len);
+ fx_iocb.dseg_rq_address[0] =
+ cpu_to_le32(LSD(fxio->u.fxiocb.req_dma_handle));
+ fx_iocb.dseg_rq_address[1] =
+ cpu_to_le32(MSD(fxio->u.fxiocb.req_dma_handle));
+ fx_iocb.dseg_rq_len =
+ cpu_to_le32(fxio->u.fxiocb.req_len);
+ }
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
+ fx_iocb.rsp_dsdcnt = cpu_to_le16(1);
+ fx_iocb.rsp_xfrcnt =
+ cpu_to_le16(fxio->u.fxiocb.rsp_len);
+ fx_iocb.dseg_rsp_address[0] =
+ cpu_to_le32(LSD(fxio->u.fxiocb.rsp_dma_handle));
+ fx_iocb.dseg_rsp_address[1] =
+ cpu_to_le32(MSD(fxio->u.fxiocb.rsp_dma_handle));
+ fx_iocb.dseg_rsp_len =
+ cpu_to_le32(fxio->u.fxiocb.rsp_len);
+ }
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
+ fx_iocb.dataword =
+ cpu_to_le32(fxio->u.fxiocb.req_data);
+ }
+ fx_iocb.flags = fxio->u.fxiocb.flags;
+ } else {
+ struct scatterlist *sg;
+ bsg_job = sp->u.bsg_job;
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+ fx_iocb.func_num = piocb_rqst->func_type;
+ fx_iocb.adapid = piocb_rqst->adapid;
+ fx_iocb.adapid_hi = piocb_rqst->adapid_hi;
+ fx_iocb.reserved_0 = piocb_rqst->reserved_0;
+ fx_iocb.reserved_1 = piocb_rqst->reserved_1;
+ fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
+ fx_iocb.dataword = piocb_rqst->dataword;
+ fx_iocb.req_xfrcnt = cpu_to_le16(piocb_rqst->req_len);
+ fx_iocb.rsp_xfrcnt = cpu_to_le16(piocb_rqst->rsp_len);
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
+ int avail_dsds, tot_dsds;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt = NULL;
+ uint32_t *cur_dsd;
+ int index = 0, cont = 0;
+
+ fx_iocb.req_dsdcnt =
+ cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ tot_dsds =
+ cpu_to_le32(bsg_job->request_payload.sg_cnt);
+ cur_dsd = (uint32_t *)&fx_iocb.dseg_rq_address[0];
+ avail_dsds = 1;
+ for_each_sg(bsg_job->request_payload.sg_list, sg,
+ tot_dsds, index) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0,
+ REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(
+ sp->fcport->vha->req,
+ &lcont_pkt);
+ cur_dsd = (uint32_t *)
+ lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ entry_cnt++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio(
+ (void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(
+ ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3042,
+ (uint8_t *)&lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3043,
+ (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
+ int avail_dsds, tot_dsds;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt = NULL;
+ uint32_t *cur_dsd;
+ int index = 0, cont = 0;
+
+ fx_iocb.rsp_dsdcnt =
+ cpu_to_le16(bsg_job->reply_payload.sg_cnt);
+ tot_dsds = cpu_to_le32(bsg_job->reply_payload.sg_cnt);
+ cur_dsd = (uint32_t *)&fx_iocb.dseg_rsp_address[0];
+ avail_dsds = 1;
+
+ for_each_sg(bsg_job->reply_payload.sg_list, sg,
+ tot_dsds, index) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0,
+ REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(
+ sp->fcport->vha->req,
+ &lcont_pkt);
+ cur_dsd = (uint32_t *)
+ lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ entry_cnt++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(
+ ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3045,
+ (uint8_t *)&lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3046,
+ (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
+ fx_iocb.dataword = cpu_to_le32(piocb_rqst->dataword);
+ fx_iocb.flags = piocb_rqst->flags;
+ fx_iocb.entry_count = entry_cnt;
+ }
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3047,
+ (uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00));
+
+ memcpy((void __iomem *)pfxiocb, &fx_iocb,
+ sizeof(struct fxdisc_entry_fx00));
+ wmb();
+}
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
new file mode 100644
index 000000000000..cc327dc2fd10
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -0,0 +1,510 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_MR_H
+#define __QLA_MR_H
+
+/*
+ * The PCI VendorID and DeviceID for our board.
+ */
+#define PCI_DEVICE_ID_QLOGIC_ISPF001 0xF001
+
+/* FX00 specific definitions */
+
+#define FX00_COMMAND_TYPE_7 0x07 /* Command Type 7 entry for 7XXX */
+struct cmd_type_7_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi;
+
+ uint16_t tgt_idx; /* Target Idx. */
+ uint16_t timeout; /* Command timeout. */
+
+ uint16_t dseg_count; /* Data segment count. */
+ uint16_t scsi_rsp_dsd_len;
+
+ struct scsi_lun lun; /* LUN (LE). */
+
+ uint8_t cntrl_flags;
+
+ uint8_t task_mgmt_flags; /* Task management flags. */
+
+ uint8_t task;
+
+ uint8_t crn;
+
+ uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
+ uint32_t byte_count; /* Total byte count. */
+
+ uint32_t dseg_0_address[2]; /* Data segment 0 address. */
+ uint32_t dseg_0_len; /* Data segment 0 length. */
+};
+
+/*
+ * ISP queue - marker entry structure definition.
+ */
+struct mrk_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t handle_count; /* Handle count. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id; /* Target ID. */
+
+ uint8_t modifier; /* Modifier (7-0). */
+ uint8_t reserved_1;
+
+ uint8_t reserved_2[5];
+
+ uint8_t lun[8]; /* FCP LUN (BE). */
+ uint8_t reserved_3[36];
+};
+
+
+#define STATUS_TYPE_FX00 0x01 /* Status entry. */
+struct sts_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t comp_status; /* Completion status. */
+ uint16_t reserved_0; /* OX_ID used by the firmware. */
+
+ uint32_t residual_len; /* FW calc residual transfer length. */
+
+ uint16_t reserved_1;
+ uint16_t state_flags; /* State flags. */
+
+ uint16_t reserved_2;
+ uint16_t scsi_status; /* SCSI status. */
+
+ uint32_t sense_len; /* FCP SENSE length. */
+ uint8_t data[32]; /* FCP response/sense information. */
+};
+
+
+#define MAX_HANDLE_COUNT 15
+#define MULTI_STATUS_TYPE_FX00 0x0D
+
+struct multi_sts_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t handle_count;
+ uint8_t entry_status;
+
+ uint32_t handles[MAX_HANDLE_COUNT];
+};
+
+#define TSK_MGMT_IOCB_TYPE_FX00 0x05
+struct tsk_mgmt_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define;
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id; /* Target Idx. */
+
+ uint16_t reserved_1;
+
+ uint16_t delay; /* Activity delay in seconds. */
+
+ uint16_t timeout; /* Command timeout. */
+
+ struct scsi_lun lun; /* LUN (LE). */
+
+ uint32_t control_flags; /* Control Flags. */
+
+ uint8_t reserved_2[32];
+};
+
+
+#define ABORT_IOCB_TYPE_FX00 0x08 /* Abort IOCB status. */
+struct abort_iocb_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id_sts; /* Completion status. */
+ uint16_t options;
+
+ uint32_t abort_handle; /* System handle. */
+ uint32_t abort_handle_hi; /* System handle. */
+
+ uint16_t req_que_no;
+ uint8_t reserved_1[38];
+};
+
+#define IOCTL_IOSB_TYPE_FX00 0x0C
+struct ioctl_iocb_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t reserved_0; /* System handle. */
+
+ uint16_t comp_func_num;
+ uint16_t fw_iotcl_flags;
+
+ uint32_t dataword_r; /* Data word returned */
+ uint32_t adapid; /* Adapter ID */
+ uint32_t adapid_hi; /* Adapter ID high */
+ uint32_t reserved_1;
+
+ uint32_t seq_no;
+ uint8_t reserved_2[20];
+ uint32_t residuallen;
+ uint32_t status;
+};
+
+#define STATUS_CONT_TYPE_FX00 0x04
+
+#define FX00_IOCB_TYPE 0x0B
+struct fxdisc_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System Defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t reserved_0; /* System handle. */
+
+ uint16_t func_num;
+ uint16_t req_xfrcnt;
+ uint16_t req_dsdcnt;
+ uint16_t rsp_xfrcnt;
+ uint16_t rsp_dsdcnt;
+ uint8_t flags;
+ uint8_t reserved_1;
+
+ uint32_t dseg_rq_address[2]; /* Data segment 0 address. */
+ uint32_t dseg_rq_len; /* Data segment 0 length. */
+ uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */
+ uint32_t dseg_rsp_len; /* Data segment 1 length. */
+
+ uint32_t dataword;
+ uint32_t adapid;
+ uint32_t adapid_hi;
+ uint32_t dataword_extra;
+};
+
+struct qlafx00_tgt_node_info {
+ uint8_t tgt_node_wwpn[WWN_SIZE];
+ uint8_t tgt_node_wwnn[WWN_SIZE];
+ uint32_t tgt_node_state;
+ uint8_t reserved[128];
+ uint32_t reserved_1[8];
+ uint64_t reserved_2[4];
+} __packed;
+
+#define QLAFX00_TGT_NODE_INFO sizeof(struct qlafx00_tgt_node_info)
+
+#define QLAFX00_LINK_STATUS_DOWN 0x10
+#define QLAFX00_LINK_STATUS_UP 0x11
+
+#define QLAFX00_PORT_SPEED_2G 0x2
+#define QLAFX00_PORT_SPEED_4G 0x4
+#define QLAFX00_PORT_SPEED_8G 0x8
+#define QLAFX00_PORT_SPEED_10G 0xa
+struct port_info_data {
+ uint8_t port_state;
+ uint8_t port_type;
+ uint16_t port_identifier;
+ uint32_t up_port_state;
+ uint8_t fw_ver_num[32];
+ uint8_t portal_attrib;
+ uint16_t host_option;
+ uint8_t reset_delay;
+ uint8_t pdwn_retry_cnt;
+ uint16_t max_luns2tgt;
+ uint8_t risc_ver;
+ uint8_t pconn_option;
+ uint16_t risc_option;
+ uint16_t max_frame_len;
+ uint16_t max_iocb_alloc;
+ uint16_t exec_throttle;
+ uint8_t retry_cnt;
+ uint8_t retry_delay;
+ uint8_t port_name[8];
+ uint8_t port_id[3];
+ uint8_t link_status;
+ uint8_t plink_rate;
+ uint32_t link_config;
+ uint16_t adap_haddr;
+ uint8_t tgt_disc;
+ uint8_t log_tout;
+ uint8_t node_name[8];
+ uint16_t erisc_opt1;
+ uint8_t resp_acc_tmr;
+ uint8_t intr_del_tmr;
+ uint8_t erisc_opt2;
+ uint8_t alt_port_name[8];
+ uint8_t alt_node_name[8];
+ uint8_t link_down_tout;
+ uint8_t conn_type;
+ uint8_t fc_fw_mode;
+ uint32_t uiReserved[48];
+} __packed;
+
+/* OS Type Designations */
+#define OS_TYPE_UNKNOWN 0
+#define OS_TYPE_LINUX 2
+
+/* Linux Info */
+#define SYSNAME_LENGTH 128
+#define NODENAME_LENGTH 64
+#define RELEASE_LENGTH 64
+#define VERSION_LENGTH 64
+#define MACHINE_LENGTH 64
+#define DOMNAME_LENGTH 64
+
+struct host_system_info {
+ uint32_t os_type;
+ char sysname[SYSNAME_LENGTH];
+ char nodename[NODENAME_LENGTH];
+ char release[RELEASE_LENGTH];
+ char version[VERSION_LENGTH];
+ char machine[MACHINE_LENGTH];
+ char domainname[DOMNAME_LENGTH];
+ char hostdriver[VERSION_LENGTH];
+ uint32_t reserved[64];
+} __packed;
+
+struct register_host_info {
+ struct host_system_info hsi; /* host system info */
+ uint64_t utc; /* UTC (system time) */
+ uint32_t reserved[64]; /* future additions */
+} __packed;
+
+
+#define QLAFX00_PORT_DATA_INFO (sizeof(struct port_info_data))
+#define QLAFX00_TGT_NODE_LIST_SIZE (sizeof(uint32_t) * 32)
+
+struct config_info_data {
+ uint8_t product_name[256];
+ uint8_t symbolic_name[64];
+ uint8_t serial_num[32];
+ uint8_t hw_version[16];
+ uint8_t fw_version[16];
+ uint8_t uboot_version[16];
+ uint8_t fru_serial_num[32];
+
+ uint8_t fc_port_count;
+ uint8_t iscsi_port_count;
+ uint8_t reserved1[2];
+
+ uint8_t mode;
+ uint8_t log_level;
+ uint8_t reserved2[2];
+
+ uint32_t log_size;
+
+ uint8_t tgt_pres_mode;
+ uint8_t iqn_flags;
+ uint8_t lun_mapping;
+
+ uint64_t adapter_id;
+
+ uint32_t cluster_key_len;
+ uint8_t cluster_key[10];
+
+ uint64_t cluster_master_id;
+ uint64_t cluster_slave_id;
+ uint8_t cluster_flags;
+} __packed;
+
+#define FXDISC_GET_CONFIG_INFO 0x01
+#define FXDISC_GET_PORT_INFO 0x02
+#define FXDISC_GET_TGT_NODE_INFO 0x80
+#define FXDISC_GET_TGT_NODE_LIST 0x81
+#define FXDISC_REG_HOST_INFO 0x99
+
+#define QLAFX00_HBA_ICNTRL_REG 0x21B08
+#define QLAFX00_ICR_ENB_MASK 0x80000000
+#define QLAFX00_ICR_DIS_MASK 0x7fffffff
+#define QLAFX00_HST_RST_REG 0x18264
+#define QLAFX00_HST_TO_HBA_REG 0x20A04
+#define QLAFX00_HBA_TO_HOST_REG 0x21B70
+#define QLAFX00_HST_INT_STS_BITS 0x7
+#define QLAFX00_BAR1_BASE_ADDR_REG 0x40018
+#define QLAFX00_PEX0_WIN0_BASE_ADDR_REG 0x41824
+
+#define QLAFX00_INTR_MB_CMPLT 0x1
+#define QLAFX00_INTR_RSP_CMPLT 0x2
+#define QLAFX00_INTR_MB_RSP_CMPLT 0x3
+#define QLAFX00_INTR_ASYNC_CMPLT 0x4
+#define QLAFX00_INTR_MB_ASYNC_CMPLT 0x5
+#define QLAFX00_INTR_RSP_ASYNC_CMPLT 0x6
+#define QLAFX00_INTR_ALL_CMPLT 0x7
+
+#define QLAFX00_MBA_SYSTEM_ERR 0x8002
+#define QLAFX00_MBA_LINK_UP 0x8011
+#define QLAFX00_MBA_LINK_DOWN 0x8012
+#define QLAFX00_MBA_PORT_UPDATE 0x8014
+#define QLAFX00_MBA_SHUTDOWN_RQSTD 0x8062
+
+#define SOC_SW_RST_CONTROL_REG_CORE0 0x0020800
+#define SOC_FABRIC_RST_CONTROL_REG 0x0020840
+#define SOC_FABRIC_CONTROL_REG 0x0020200
+#define SOC_FABRIC_CONFIG_REG 0x0020204
+
+#define SOC_INTERRUPT_SOURCE_I_CONTROL_REG 0x0020B00
+#define SOC_CORE_TIMER_REG 0x0021850
+#define SOC_IRQ_ACK_REG 0x00218b4
+
+#define CONTINUE_A64_TYPE_FX00 0x03 /* Continuation entry. */
+
+#define QLAFX00_SET_HST_INTR(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HST_TO_HBA_REG, \
+ value)
+
+#define QLAFX00_CLR_HST_INTR(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG, \
+ ~value)
+
+#define QLAFX00_RD_INTR_REG(ha) \
+ RD_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG)
+
+#define QLAFX00_CLR_INTR_REG(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG, \
+ ~value)
+
+#define QLAFX00_SET_HBA_SOC_REG(ha, off, val)\
+ WRT_REG_DWORD((ha)->cregbase + off, val)
+
+#define QLAFX00_GET_HBA_SOC_REG(ha, off)\
+ RD_REG_DWORD((ha)->cregbase + off)
+
+#define QLAFX00_HBA_RST_REG(ha, val)\
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HST_RST_REG, val)
+
+#define QLAFX00_RD_ICNTRL_REG(ha) \
+ RD_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG)
+
+#define QLAFX00_ENABLE_ICNTRL_REG(ha) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG, \
+ (QLAFX00_GET_HBA_SOC_REG(ha, QLAFX00_HBA_ICNTRL_REG) | \
+ QLAFX00_ICR_ENB_MASK))
+
+#define QLAFX00_DISABLE_ICNTRL_REG(ha) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG, \
+ (QLAFX00_GET_HBA_SOC_REG(ha, QLAFX00_HBA_ICNTRL_REG) & \
+ QLAFX00_ICR_DIS_MASK))
+
+#define QLAFX00_RD_REG(ha, off) \
+ RD_REG_DWORD((ha)->cregbase + off)
+
+#define QLAFX00_WR_REG(ha, off, val) \
+ WRT_REG_DWORD((ha)->cregbase + off, val)
+
+struct qla_mt_iocb_rqst_fx00 {
+ uint32_t reserved_0;
+
+ uint16_t func_type;
+ uint8_t flags;
+ uint8_t reserved_1;
+
+ uint32_t dataword;
+
+ uint32_t adapid;
+ uint32_t adapid_hi;
+
+ uint32_t dataword_extra;
+
+ uint32_t req_len;
+
+ uint32_t rsp_len;
+};
+
+struct qla_mt_iocb_rsp_fx00 {
+ uint32_t reserved_1;
+
+ uint16_t func_type;
+ uint16_t ioctl_flags;
+
+ uint32_t ioctl_data;
+
+ uint32_t adapid;
+ uint32_t adapid_hi;
+
+ uint32_t reserved_2;
+ uint32_t seq_number;
+
+ uint8_t reserved_3[20];
+
+ int32_t res_count;
+
+ uint32_t status;
+};
+
+
+#define MAILBOX_REGISTER_COUNT_FX00 16
+#define AEN_MAILBOX_REGISTER_COUNT_FX00 8
+#define MAX_FIBRE_DEVICES_FX00 512
+#define MAX_LUNS_FX00 0x1024
+#define MAX_TARGETS_FX00 MAX_ISA_DEVICES
+#define REQUEST_ENTRY_CNT_FX00 512 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+
+/*
+ * Firmware state codes for QLAFX00 adapters
+ */
+#define FSTATE_FX00_CONFIG_WAIT 0x0000 /* Waiting for driver to issue
+ * Initialize FW Mbox cmd
+ */
+#define FSTATE_FX00_INITIALIZED 0x1000 /* FW has been initialized by
+ * the driver
+ */
+
+#define FX00_DEF_RATOV 10
+
+struct mr_data_fx00 {
+ uint8_t product_name[256];
+ uint8_t symbolic_name[64];
+ uint8_t serial_num[32];
+ uint8_t hw_version[16];
+ uint8_t fw_version[16];
+ uint8_t uboot_version[16];
+ uint8_t fru_serial_num[32];
+ fc_port_t fcport; /* fcport used for requests
+ * that are not linked
+ * to a particular target
+ */
+ uint8_t fw_hbt_en;
+ uint8_t fw_hbt_cnt;
+ uint8_t fw_hbt_miss_cnt;
+ uint32_t old_fw_hbt_cnt;
+ uint16_t fw_reset_timer_tick;
+ uint8_t fw_reset_timer_exp;
+ uint32_t old_aenmbx0_state;
+};
+
+#define QLAFX00_LOOP_DOWN_TIME 615 /* 600 */
+#define QLAFX00_HEARTBEAT_INTERVAL 6 /* number of seconds */
+#define QLAFX00_HEARTBEAT_MISS_CNT 3 /* number of miss */
+#define QLAFX00_RESET_INTERVAL 120 /* number of seconds */
+#define QLAFX00_MAX_RESET_INTERVAL 600 /* number of seconds */
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2c6dd3dfe0f4..5307bf86d5e0 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -47,6 +47,7 @@ MODULE_PARM_DESC(ql2xenableclass2,
"Specify if Class 2 operations are supported from the very "
"beginning. Default is 0 - class 2 not supported.");
+
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO);
MODULE_PARM_DESC(ql2xlogintimeout,
@@ -354,7 +355,12 @@ fail_req_map:
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
{
- if (req && req->ring)
+ if (IS_QLAFX00(ha)) {
+ if (req && req->ring_fx00)
+ dma_free_coherent(&ha->pdev->dev,
+ (req->length_fx00 + 1) * sizeof(request_t),
+ req->ring_fx00, req->dma_fx00);
+ } else if (req && req->ring)
dma_free_coherent(&ha->pdev->dev,
(req->length + 1) * sizeof(request_t),
req->ring, req->dma);
@@ -368,11 +374,16 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
{
- if (rsp && rsp->ring)
+ if (IS_QLAFX00(ha)) {
+ if (rsp && rsp->ring)
+ dma_free_coherent(&ha->pdev->dev,
+ (rsp->length_fx00 + 1) * sizeof(request_t),
+ rsp->ring_fx00, rsp->dma_fx00);
+ } else if (rsp && rsp->ring) {
dma_free_coherent(&ha->pdev->dev,
(rsp->length + 1) * sizeof(response_t),
rsp->ring, rsp->dma);
-
+ }
kfree(rsp);
rsp = NULL;
}
@@ -633,7 +644,7 @@ qla2x00_sp_free_dma(void *vha, void *ptr)
qla2x00_rel_sp(sp->fcport->vha, sp);
}
-static void
+void
qla2x00_sp_compl(void *data, void *ptr, int res)
{
struct qla_hw_data *ha = (struct qla_hw_data *)data;
@@ -657,6 +668,9 @@ qla2x00_sp_compl(void *data, void *ptr, int res)
cmd->scsi_done(cmd);
}
+/* If we are SP1 here, we need to still take and release the host_lock as SP1
+ * does not have the changes necessary to avoid taking host->host_lock.
+ */
static int
qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
@@ -1304,6 +1318,9 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
}
}
+ if (IS_QLAFX00(ha))
+ return QLA_SUCCESS;
+
if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -1858,6 +1875,7 @@ static struct isp_operations qla2100_isp_ops = {
.start_scsi = qla2x00_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla2300_isp_ops = {
@@ -1895,6 +1913,7 @@ static struct isp_operations qla2300_isp_ops = {
.start_scsi = qla2x00_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla24xx_isp_ops = {
@@ -1932,6 +1951,7 @@ static struct isp_operations qla24xx_isp_ops = {
.start_scsi = qla24xx_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla25xx_isp_ops = {
@@ -1969,6 +1989,7 @@ static struct isp_operations qla25xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla81xx_isp_ops = {
@@ -2006,6 +2027,7 @@ static struct isp_operations qla81xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla82xx_isp_ops = {
@@ -2043,6 +2065,7 @@ static struct isp_operations qla82xx_isp_ops = {
.start_scsi = qla82xx_start_scsi,
.abort_isp = qla82xx_abort_isp,
.iospace_config = qla82xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla83xx_isp_ops = {
@@ -2080,6 +2103,45 @@ static struct isp_operations qla83xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla83xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
+};
+
+static struct isp_operations qlafx00_isp_ops = {
+ .pci_config = qlafx00_pci_config,
+ .reset_chip = qlafx00_soft_reset,
+ .chip_diag = qlafx00_chip_diag,
+ .config_rings = qlafx00_config_rings,
+ .reset_adapter = qlafx00_soft_reset,
+ .nvram_config = NULL,
+ .update_fw_options = NULL,
+ .load_risc = NULL,
+ .pci_info_str = qlafx00_pci_info_str,
+ .fw_version_str = qlafx00_fw_version_str,
+ .intr_handler = qlafx00_intr_handler,
+ .enable_intrs = qlafx00_enable_intrs,
+ .disable_intrs = qlafx00_disable_intrs,
+ .abort_command = qlafx00_abort_command,
+ .target_reset = qlafx00_abort_target,
+ .lun_reset = qlafx00_lun_reset,
+ .fabric_login = NULL,
+ .fabric_logout = NULL,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla24xx_read_nvram_data,
+ .write_nvram = qla24xx_write_nvram_data,
+ .fw_dump = NULL,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = NULL,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+ .start_scsi = qlafx00_start_scsi,
+ .abort_isp = qlafx00_abort_isp,
+ .iospace_config = qlafx00_iospace_config,
+ .initialize_adapter = qlafx00_initialize_adapter,
};
static inline void
@@ -2192,6 +2254,9 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISPF001:
+ ha->device_type |= DT_ISPFX00;
+ break;
}
if (IS_QLA82XX(ha))
@@ -2265,7 +2330,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2436,6 +2502,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
ha->nvram_conf_off = ~0;
ha->nvram_data_off = ~0;
+ } else if (IS_QLAFX00(ha)) {
+ ha->max_fibre_devices = MAX_FIBRE_DEVICES_FX00;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT_FX00;
+ ha->aen_mbx_count = AEN_MAILBOX_REGISTER_COUNT_FX00;
+ req_length = REQUEST_ENTRY_CNT_FX00;
+ rsp_length = RESPONSE_ENTRY_CNT_FX00;
+ ha->init_cb_size = sizeof(struct init_cb_fx);
+ ha->isp_ops = &qlafx00_isp_ops;
+ ha->port_down_retry_count = 30; /* default value */
+ ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ ha->mr.fw_hbt_en = 1;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -2500,13 +2578,24 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host = base_vha->host;
base_vha->req = req;
- host->can_queue = req->length + 128;
+ if (IS_QLAFX00(ha))
+ host->can_queue = 1024;
+ else
+ host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
else
base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
base_vha->vp_idx;
+ /* Setup fcport template structure. */
+ ha->mr.fcport.vha = base_vha;
+ ha->mr.fcport.port_type = FCT_UNKNOWN;
+ ha->mr.fcport.loop_id = FC_NO_LOOP_ID;
+ qla2x00_set_fcport_state(&ha->mr.fcport, FCS_UNCONFIGURED);
+ ha->mr.fcport.supported_classes = FC_COS_UNSPECIFIED;
+ ha->mr.fcport.scan_state = 1;
+
/* Set the SG table size based on ISP type */
if (!IS_FWI2_CAPABLE(ha)) {
if (IS_QLA2100(ha))
@@ -2562,6 +2651,13 @@ que_init:
rsp->req = req;
req->rsp = rsp;
+ if (IS_QLAFX00(ha)) {
+ ha->rsp_q_map[0] = rsp;
+ ha->req_q_map[0] = req;
+ set_bit(0, ha->req_qid_map);
+ set_bit(0, ha->rsp_qid_map);
+ }
+
/* FWI2-capable only. */
req->req_q_in = &ha->iobase->isp24.req_q_in;
req->req_q_out = &ha->iobase->isp24.req_q_out;
@@ -2574,6 +2670,13 @@ que_init:
rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out;
}
+ if (IS_QLAFX00(ha)) {
+ req->req_q_in = &ha->iobase->ispfx00.req_q_in;
+ req->req_q_out = &ha->iobase->ispfx00.req_q_out;
+ rsp->rsp_q_in = &ha->iobase->ispfx00.rsp_q_in;
+ rsp->rsp_q_out = &ha->iobase->ispfx00.rsp_q_out;
+ }
+
if (IS_QLA82XX(ha)) {
req->req_q_out = &ha->iobase->isp82.req_q_out[0];
rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
@@ -2595,7 +2698,7 @@ que_init:
"req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out);
- if (qla2x00_initialize_adapter(base_vha)) {
+ if (ha->isp_ops->initialize_adapter(base_vha)) {
ql_log(ql_log_fatal, base_vha, 0x00d6,
"Failed to initialize adapter - Adapter flags %x.\n",
base_vha->device_flags);
@@ -2720,6 +2823,18 @@ skip_dpc:
qla2x00_alloc_sysfs_attr(base_vha);
+ if (IS_QLAFX00(ha)) {
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
+
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_GET_PORT_INFO);
+
+ /* Register system information */
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_REG_HOST_INFO);
+ }
+
qla2x00_init_host_attr(base_vha);
qla2x00_dfs_setup(base_vha);
@@ -2777,6 +2892,8 @@ iospace_config_failed:
} else {
if (ha->iobase)
iounmap(ha->iobase);
+ if (ha->cregbase)
+ iounmap(ha->cregbase);
}
pci_release_selected_regions(ha->pdev, ha->bars);
kfree(ha);
@@ -2960,6 +3077,9 @@ qla2x00_remove_one(struct pci_dev *pdev)
if (ha->iobase)
iounmap(ha->iobase);
+ if (ha->cregbase)
+ iounmap(ha->cregbase);
+
if (ha->mqiobase)
iounmap(ha->mqiobase);
@@ -3068,6 +3188,12 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport,
int do_login, int defer)
{
+ if (IS_QLAFX00(vha->hw)) {
+ qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
+ qla2x00_schedule_rport_del(vha, fcport, defer);
+ return;
+ }
+
if (atomic_read(&fcport->state) == FCS_ONLINE &&
vha->vp_idx == fcport->vha->vp_idx) {
qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
@@ -3710,6 +3836,22 @@ qla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code)
kobject_uevent_env(&vha->hw->pdev->dev.kobj, KOBJ_CHANGE, envp);
}
+int
+qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode,
+ uint32_t *data, int cnt)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(vha, QLA_EVT_AENFX);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.aenfx.evtcode = evtcode;
+ e->u.aenfx.count = cnt;
+ memcpy(e->u.aenfx.mbx, data, sizeof(*data) * cnt);
+ return qla2x00_post_work(vha, e);
+}
+
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
@@ -3758,6 +3900,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_UEVENT:
qla2x00_uevent_emit(vha, e->u.uevent.code);
break;
+ case QLA_EVT_AENFX:
+ qlafx00_process_aen(vha, e);
+ break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
@@ -4592,6 +4737,38 @@ qla2x00_do_dpc(void *data)
ql_dbg(ql_dbg_dpc, base_vha, 0x4006,
"FCoE context reset end.\n");
}
+ } else if (IS_QLAFX00(ha)) {
+ if (test_and_clear_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags)) {
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4020,
+ "Firmware Reset Recovery\n");
+ if (qlafx00_reset_initialize(base_vha)) {
+ /* Failed. Abort isp later. */
+ if (!test_bit(UNLOADING,
+ &base_vha->dpc_flags))
+ set_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags);
+ ql_dbg(ql_dbg_dpc, base_vha,
+ 0x4021,
+ "Reset Recovery Failed\n");
+ }
+ }
+
+ if (test_and_clear_bit(FX00_TARGET_SCAN,
+ &base_vha->dpc_flags)) {
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4022,
+ "ISPFx00 Target Scan scheduled\n");
+ if (qlafx00_rescan_isp(base_vha)) {
+ if (!test_bit(UNLOADING,
+ &base_vha->dpc_flags))
+ set_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags);
+ ql_dbg(ql_dbg_dpc, base_vha, 0x401e,
+ "ISPFx00 Target Scan Failed\n");
+ }
+ ql_dbg(ql_dbg_dpc, base_vha, 0x401f,
+ "ISPFx00 Target Scan End\n");
+ }
}
if (test_and_clear_bit(ISP_ABORT_NEEDED,
@@ -4630,6 +4807,9 @@ qla2x00_do_dpc(void *data)
clear_bit(SCR_PENDING, &base_vha->dpc_flags);
}
+ if (IS_QLAFX00(ha))
+ goto loop_resync_check;
+
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n");
@@ -4654,7 +4834,7 @@ qla2x00_do_dpc(void *data)
}
if (test_and_clear_bit(RESET_MARKER_NEEDED,
- &base_vha->dpc_flags) &&
+ &base_vha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
ql_dbg(ql_dbg_dpc, base_vha, 0x400b,
@@ -4677,9 +4857,9 @@ qla2x00_do_dpc(void *data)
ql_dbg(ql_dbg_dpc, base_vha, 0x400e,
"Relogin end.\n");
}
-
+loop_resync_check:
if (test_and_clear_bit(LOOP_RESYNC_NEEDED,
- &base_vha->dpc_flags)) {
+ &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x400f,
"Loop resync scheduled.\n");
@@ -4697,6 +4877,9 @@ qla2x00_do_dpc(void *data)
"Loop resync end.\n");
}
+ if (IS_QLAFX00(ha))
+ goto intr_on_check;
+
if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) &&
atomic_read(&base_vha->loop_state) == LOOP_READY) {
clear_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags);
@@ -4714,7 +4897,7 @@ qla2x00_do_dpc(void *data)
if (test_and_clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
&base_vha->dpc_flags))
qla2x00_host_ramp_up_queuedepth(base_vha);
-
+intr_on_check:
if (!ha->interrupts_on)
ha->isp_ops->enable_intrs(ha);
@@ -4722,7 +4905,8 @@ qla2x00_do_dpc(void *data)
&base_vha->dpc_flags))
ha->isp_ops->beacon_blink(base_vha);
- qla2x00_do_dpc_all_vps(base_vha);
+ if (!IS_QLAFX00(ha))
+ qla2x00_do_dpc_all_vps(base_vha);
ha->dpc_active = 0;
end_loop:
@@ -4818,6 +5002,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
qla82xx_watchdog(vha);
}
+ if (!vha->vp_idx && IS_QLAFX00(ha))
+ qlafx00_timer_routine(vha);
+
/* Loop down handler. */
if (atomic_read(&vha->loop_down_timer) > 0 &&
!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
@@ -5335,6 +5522,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -5351,7 +5539,7 @@ static struct pci_driver qla2xxx_pci_driver = {
.err_handler = &qla2xxx_err_handler,
};
-static struct file_operations apidev_fops = {
+static const struct file_operations apidev_fops = {
.owner = THIS_MODULE,
.llseek = noop_llseek,
};
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 61b5d8c2b5da..fcdc22306cab 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -2585,25 +2585,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
ha->tgt.tgt_ops->free_cmd(cmd);
}
-/* ha->hardware_lock supposed to be held on entry */
-/* called via callback from qla2xxx */
-void qlt_ctio_completion(struct scsi_qla_host *vha, uint32_t handle)
-{
- struct qla_hw_data *ha = vha->hw;
- struct qla_tgt *tgt = ha->tgt.qla_tgt;
-
- if (likely(tgt == NULL)) {
- ql_dbg(ql_dbg_tgt, vha, 0xe021,
- "CTIO, but target mode not enabled"
- " (ha %d %p handle %#x)", vha->vp_idx, ha, handle);
- return;
- }
-
- tgt->irq_cmd_count++;
- qlt_do_ctio_completion(vha, handle, CTIO_SUCCESS, NULL);
- tgt->irq_cmd_count--;
-}
-
static inline int qlt_get_fcp_task_attr(struct scsi_qla_host *vha,
uint8_t task_codes)
{
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index ff9ccb9fd036..b33e411f28a0 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -980,7 +980,6 @@ extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
-extern void qlt_ctio_completion(struct scsi_qla_host *, uint32_t);
extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *);
extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 2b6e478d9e33..6c66d22eb1b1 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.04.00.08-k"
+#define QLA2XXX_VERSION "8.05.00.03-k"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 4
+#define QLA_DRIVER_MINOR_VER 5
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 5d8fe4f75650..d607eb8e24cb 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1629,9 +1629,37 @@ static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha)
ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n");
}
+/**
+ * qla4_83xx_eport_init - Initialize EPort.
+ * @ha: Pointer to host adapter structure.
+ *
+ * If EPort hardware is in reset state before disabling pause, there would be
+ * serious hardware wedging issues. To prevent this perform eport init everytime
+ * before disabling pause frames.
+ **/
+static void qla4_83xx_eport_init(struct scsi_qla_host *ha)
+{
+ /* Clear the 8 registers */
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0);
+
+ /* Write any value to Reset Control register */
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF);
+
+ ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n");
+}
+
void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
{
ha->isp_ops->idc_lock(ha);
+ /* Before disabling pause frames, ensure that eport is not in reset */
+ qla4_83xx_eport_init(ha);
qla4_83xx_dump_pause_control_regs(ha);
__qla4_83xx_disable_pause(ha);
ha->isp_ops->idc_unlock(ha);
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h
index 6a00f903f2a6..fab237fa32cc 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.h
+++ b/drivers/scsi/qla4xxx/ql4_83xx.h
@@ -55,6 +55,16 @@
#define QLA83XX_SET_PAUSE_VAL 0x0
#define QLA83XX_SET_TC_MAX_CELL_VAL 0x03FF03FF
+#define QLA83XX_RESET_CONTROL 0x28084E50
+#define QLA83XX_RESET_REG 0x28084E60
+#define QLA83XX_RESET_PORT0 0x28084E70
+#define QLA83XX_RESET_PORT1 0x28084E80
+#define QLA83XX_RESET_PORT2 0x28084E90
+#define QLA83XX_RESET_PORT3 0x28084EA0
+#define QLA83XX_RESET_SRE_SHIM 0x28084EB0
+#define QLA83XX_RESET_EPG_SHIM 0x28084EC0
+#define QLA83XX_RESET_ETHER_PCS 0x28084ED0
+
/* qla_83xx_reg_tbl registers */
#define QLA83XX_PEG_HALT_STATUS1 0x34A8
#define QLA83XX_PEG_HALT_STATUS2 0x34AC
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
index 5b0afc18ef18..51c365bcf912 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.h
+++ b/drivers/scsi/qla4xxx/ql4_dbg.h
@@ -12,6 +12,7 @@
/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
/* #define QL_DEBUG_LEVEL_4 */
/* #define QL_DEBUG_LEVEL_5 */
+/* #define QL_DEBUG_LEVEL_7 */
/* #define QL_DEBUG_LEVEL_9 */
#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
@@ -48,6 +49,12 @@
#define DEBUG5(x) do {} while (0);
#endif /* */
+#if defined(QL_DEBUG_LEVEL_7)
+#define DEBUG7(x) do {x; } while (0)
+#else /* */
+#define DEBUG7(x) do {} while (0)
+#endif /* */
+
#if defined(QL_DEBUG_LEVEL_9)
#define DEBUG9(x) do {x;} while (0);
#else /* */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 129f5dd02822..ddf16a86bbf5 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -159,6 +159,22 @@
#define LSDW(x) ((u32)((u64)(x)))
#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
+#define DEV_DB_NON_PERSISTENT 0
+#define DEV_DB_PERSISTENT 1
+
+#define COPY_ISID(dst_isid, src_isid) { \
+ int i, j; \
+ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \
+ dst_isid[i++] = src_isid[j--]; \
+}
+
+#define SET_BITVAL(o, n, v) { \
+ if (o) \
+ n |= v; \
+ else \
+ n &= ~v; \
+}
+
/*
* Retry & Timeout Values
*/
@@ -363,6 +379,8 @@ struct ql82xx_hw_data {
uint32_t flt_iscsi_param;
uint32_t flt_region_chap;
uint32_t flt_chap_size;
+ uint32_t flt_region_ddb;
+ uint32_t flt_ddb_size;
};
struct qla4_8xxx_legacy_intr_set {
@@ -501,6 +519,7 @@ struct scsi_qla_host {
#define AF_INIT_DONE 1 /* 0x00000002 */
#define AF_MBOX_COMMAND 2 /* 0x00000004 */
#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_ST_DISCOVERY_IN_PROGRESS 4 /* 0x00000010 */
#define AF_INTERRUPTS_ON 6 /* 0x00000040 */
#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
#define AF_LINK_UP 8 /* 0x00000100 */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index ad9d2e2d370f..c7b8892b5a83 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -288,6 +288,8 @@ union external_hw_config_reg {
#define FA_GOLD_RISC_CODE_ADDR_82 0x80000
#define FA_FLASH_ISCSI_CHAP 0x540000
#define FA_FLASH_CHAP_SIZE 0xC0000
+#define FA_FLASH_ISCSI_DDB 0x420000
+#define FA_FLASH_DDB_SIZE 0x080000
/* Flash Description Table */
struct qla_fdt_layout {
@@ -348,6 +350,7 @@ struct qla_flt_header {
#define FLT_REG_BOOT_CODE_82 0x78
#define FLT_REG_ISCSI_PARAM 0x65
#define FLT_REG_ISCSI_CHAP 0x63
+#define FLT_REG_ISCSI_DDB 0x6A
struct qla_flt_region {
uint32_t code;
@@ -490,12 +493,16 @@ struct qla_flt_region {
#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
+#define MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED 0x802A
#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
+#define MBOX_ASTS_INITIALIZATION_FAILED 0x8031
+#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036
#define MBOX_ASTS_IDC_COMPLETE 0x8100
#define MBOX_ASTS_IDC_REQUEST_NOTIFICATION 0x8101
+#define MBOX_ASTS_DCBX_CONF_CHANGE 0x8110
#define MBOX_ASTS_TXSCVR_INSERTED 0x8130
#define MBOX_ASTS_TXSCVR_REMOVED 0x8131
@@ -779,12 +786,41 @@ struct dev_db_entry {
#define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */
#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */
+#define OPT_IS_FW_ASSIGNED_IPV6 11
+#define OPT_IPV6_DEVICE 8
+#define OPT_AUTO_SENDTGTS_DISABLE 6
+#define OPT_DISC_SESSION 4
+#define OPT_ENTRY_STATE 3
uint16_t exec_throttle; /* 02-03 */
uint16_t exec_count; /* 04-05 */
uint16_t res0; /* 06-07 */
uint16_t iscsi_options; /* 08-09 */
+#define ISCSIOPT_HEADER_DIGEST_EN 13
+#define ISCSIOPT_DATA_DIGEST_EN 12
+#define ISCSIOPT_IMMEDIATE_DATA_EN 11
+#define ISCSIOPT_INITIAL_R2T_EN 10
+#define ISCSIOPT_DATA_SEQ_IN_ORDER 9
+#define ISCSIOPT_DATA_PDU_IN_ORDER 8
+#define ISCSIOPT_CHAP_AUTH_EN 7
+#define ISCSIOPT_SNACK_REQ_EN 6
+#define ISCSIOPT_DISCOVERY_LOGOUT_EN 5
+#define ISCSIOPT_BIDI_CHAP_EN 4
+#define ISCSIOPT_DISCOVERY_AUTH_OPTIONAL 3
+#define ISCSIOPT_ERL1 1
+#define ISCSIOPT_ERL0 0
+
uint16_t tcp_options; /* 0A-0B */
+#define TCPOPT_TIMESTAMP_STAT 6
+#define TCPOPT_NAGLE_DISABLE 5
+#define TCPOPT_WSF_DISABLE 4
+#define TCPOPT_TIMER_SCALE3 3
+#define TCPOPT_TIMER_SCALE2 2
+#define TCPOPT_TIMER_SCALE1 1
+#define TCPOPT_TIMESTAMP_EN 0
+
uint16_t ip_options; /* 0C-0D */
+#define IPOPT_FRAGMENT_DISABLE 4
+
uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */
#define BYTE_UNITS 512
uint32_t res1; /* 10-13 */
@@ -816,6 +852,8 @@ struct dev_db_entry {
* much RAM */
uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */
uint8_t res5[0x10]; /* 1B0-1BF */
+#define DDB_NO_LINK 0xFFFF
+#define DDB_ISNS 0xFFFD
uint16_t ddb_link; /* 1C0-1C1 */
uint16_t chap_tbl_idx; /* 1C2-1C3 */
uint16_t tgt_portal_grp; /* 1C4-1C5 */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 982293edf02c..4a428009f699 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -191,6 +191,9 @@ int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
uint32_t status, uint32_t pid,
uint32_t data_size, uint8_t *data);
+int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index);
/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
@@ -224,8 +227,6 @@ void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha,
int qla4_83xx_isp_reset(struct scsi_qla_host *ha);
void qla4_83xx_queue_iocb(struct scsi_qla_host *ha);
void qla4_83xx_complete_iocb(struct scsi_qla_host *ha);
-uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
-uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr);
void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val);
int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
@@ -261,6 +262,10 @@ int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha);
void qla4_83xx_disable_pause(struct scsi_qla_host *ha);
void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha);
int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha);
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
+ dma_addr_t dma_addr);
+int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
+ char *password, uint16_t chap_index);
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 1b83dc283d2e..482287f4005f 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -396,7 +396,6 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
task_data = task->dd_data;
memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status));
- ha->req_q_count += task_data->iocb_req_cnt;
ha->iocb_cnt -= task_data->iocb_req_cnt;
queue_work(ha->task_wq, &task_data->task_work);
}
@@ -416,7 +415,6 @@ static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha,
return mrb;
/* update counters */
- ha->req_q_count += mrb->iocb_cnt;
ha->iocb_cnt -= mrb->iocb_cnt;
return mrb;
@@ -877,6 +875,43 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
}
break;
+ case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x Received IPv6 default router changed notification\n",
+ ha->host_no, mbox_sts[0]));
+ break;
+
+ case MBOX_ASTS_INITIALIZATION_FAILED:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",
+ ha->host_no, mbox_sts[0],
+ mbox_sts[3]));
+ break;
+
+ case MBOX_ASTS_SYSTEM_WARNING_EVENT:
+ DEBUG2(ql4_printk(KERN_WARNING, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ break;
+
+ case MBOX_ASTS_DCBX_CONF_CHANGE:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x Received DCBX configuration changed notification\n",
+ ha->host_no, mbox_sts[0]));
+ break;
+
default:
DEBUG2(printk(KERN_WARNING
"scsi%ld: AEN %04x UNKNOWN\n",
@@ -1099,8 +1134,8 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id)
status = qla4_82xx_rd_32(ha, ISR_INT_STATE_REG);
if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) {
- DEBUG2(ql4_printk(KERN_INFO, ha,
- "%s legacy Int not triggered\n", __func__));
+ DEBUG7(ql4_printk(KERN_INFO, ha,
+ "%s legacy Int not triggered\n", __func__));
return IRQ_NONE;
}
@@ -1158,7 +1193,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)
/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
if (!(leg_int_ptr & LEG_INT_PTR_B31)) {
- DEBUG2(ql4_printk(KERN_ERR, ha,
+ DEBUG7(ql4_printk(KERN_ERR, ha,
"%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n",
__func__));
return IRQ_NONE;
@@ -1166,7 +1201,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)
/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) {
- DEBUG2(ql4_printk(KERN_ERR, ha,
+ DEBUG7(ql4_printk(KERN_ERR, ha,
"%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n",
__func__, (leg_int_ptr & PF_BITS_MASK),
ha->pf_bit));
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 160d33697216..a501beab3ffe 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1129,6 +1129,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
+ uint32_t scsi_lun[2];
int status = QLA_SUCCESS;
DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
@@ -1140,10 +1141,16 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
*/
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+ int_to_scsilun(lun, (struct scsi_lun *) scsi_lun);
mbox_cmd[0] = MBOX_CMD_LUN_RESET;
mbox_cmd[1] = ddb_entry->fw_ddb_index;
- mbox_cmd[2] = lun << 8;
+ /* FW expects LUN bytes 0-3 in Incoming Mailbox 2
+ * (LUN byte 0 is LSByte, byte 3 is MSByte) */
+ mbox_cmd[2] = cpu_to_le32(scsi_lun[0]);
+ /* FW expects LUN bytes 4-7 in Incoming Mailbox 3
+ * (LUN byte 4 is LSByte, byte 7 is MSByte) */
+ mbox_cmd[3] = cpu_to_le32(scsi_lun[1]);
mbox_cmd[5] = 0x01; /* Immediate Command Enable */
qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
@@ -1281,8 +1288,8 @@ exit_about_fw:
return status;
}
-static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
- dma_addr_t dma_addr)
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
+ dma_addr_t dma_addr)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -1410,6 +1417,55 @@ exit_bootdb_failed:
return status;
}
+int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index)
+{
+ uint32_t dev_db_start_offset;
+ uint32_t dev_db_end_offset;
+ int status = QLA_ERROR;
+
+ memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
+
+ if (is_qla40XX(ha)) {
+ dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ dev_db_end_offset = FLASH_OFFSET_DB_END;
+ } else {
+ dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
+ (ha->hw.flt_region_ddb << 2);
+ /* flt_ddb_size is DDB table size for both ports
+ * so divide it by 2 to calculate the offset for second port
+ */
+ if (ha->port_num == 1)
+ dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
+
+ dev_db_end_offset = dev_db_start_offset +
+ (ha->hw.flt_ddb_size / 2);
+ }
+
+ dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry));
+
+ if (dev_db_start_offset > dev_db_end_offset) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s:Invalid DDB index %d", __func__,
+ ddb_index));
+ goto exit_fdb_failed;
+ }
+
+ if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ sizeof(*fw_ddb_entry)) != QLA_SUCCESS) {
+ ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash failed\n",
+ ha->host_no, __func__);
+ goto exit_fdb_failed;
+ }
+
+ if (fw_ddb_entry->cookie == DDB_VALID_COOKIE)
+ status = QLA_SUCCESS;
+
+exit_fdb_failed:
+ return status;
+}
+
int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
uint16_t idx)
{
@@ -1503,6 +1559,62 @@ exit_set_chap:
return ret;
}
+
+int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
+ char *password, uint16_t chap_index)
+{
+ int rval = QLA_ERROR;
+ struct ql4_chap_table *chap_table = NULL;
+ int max_chap_entries;
+
+ if (!ha->chap_list) {
+ ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ if (!username || !password) {
+ ql4_printk(KERN_ERR, ha, "No memory for username & secret\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ if (is_qla80XX(ha))
+ max_chap_entries = (ha->hw.flt_chap_size / 2) /
+ sizeof(struct ql4_chap_table);
+ else
+ max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+ if (chap_index > max_chap_entries) {
+ ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ mutex_lock(&ha->chap_sem);
+ chap_table = (struct ql4_chap_table *)ha->chap_list + chap_index;
+ if (chap_table->cookie != __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
+ rval = QLA_ERROR;
+ goto exit_unlock_uni_chap;
+ }
+
+ if (!(chap_table->flags & BIT_6)) {
+ ql4_printk(KERN_ERR, ha, "Unidirectional entry not set\n");
+ rval = QLA_ERROR;
+ goto exit_unlock_uni_chap;
+ }
+
+ strncpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
+ strncpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
+
+ rval = QLA_SUCCESS;
+
+exit_unlock_uni_chap:
+ mutex_unlock(&ha->chap_sem);
+exit_uni_chap:
+ return rval;
+}
+
/**
* qla4xxx_get_chap_index - Get chap index given username and secret
* @ha: pointer to adapter structure
@@ -1524,7 +1636,7 @@ int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
int max_chap_entries = 0;
struct ql4_chap_table *chap_table;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 71d3d234f526..eaf00c162eb2 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -2089,7 +2089,7 @@ static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
if (r_addr & 0xf) {
DEBUG2(ql4_printk(KERN_INFO, ha,
- "[%s]: Read addr 0x%x not 16 bytes alligned\n",
+ "[%s]: Read addr 0x%x not 16 bytes aligned\n",
__func__, r_addr));
return QLA_ERROR;
}
@@ -3154,6 +3154,10 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
hw->flt_region_chap = start;
hw->flt_chap_size = le32_to_cpu(region->size);
break;
+ case FLT_REG_ISCSI_DDB:
+ hw->flt_region_ddb = start;
+ hw->flt_ddb_size = le32_to_cpu(region->size);
+ break;
}
}
goto done;
@@ -3166,14 +3170,19 @@ no_flash_data:
hw->flt_region_boot = FA_BOOT_CODE_ADDR_82;
hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
hw->flt_region_fw = FA_RISC_CODE_ADDR_82;
- hw->flt_region_chap = FA_FLASH_ISCSI_CHAP;
+ hw->flt_region_chap = FA_FLASH_ISCSI_CHAP >> 2;
hw->flt_chap_size = FA_FLASH_CHAP_SIZE;
+ hw->flt_region_ddb = FA_FLASH_ISCSI_DDB >> 2;
+ hw->flt_ddb_size = FA_FLASH_DDB_SIZE;
done:
- DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x "
- "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt,
- hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload,
- hw->flt_region_fw));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x chap_size=0x%x ddb=0x%x ddb_size=0x%x\n",
+ loc, hw->flt_region_flt, hw->flt_region_fdt,
+ hw->flt_region_boot, hw->flt_region_bootload,
+ hw->flt_region_fw, hw->flt_region_chap,
+ hw->flt_chap_size, hw->flt_region_ddb,
+ hw->flt_ddb_size));
}
static void
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 6142729167f4..a47f99957ba8 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -166,6 +166,26 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
int reason);
+/*
+ * iSCSI Flash DDB sysfs entry points
+ */
+static int
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len);
+static int
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf);
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
+ int len);
+static int
+qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
+
static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
QLA82XX_LEGACY_INTR_CONFIG;
@@ -232,6 +252,13 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
.send_ping = qla4xxx_send_ping,
.get_chap = qla4xxx_get_chap_list,
.delete_chap = qla4xxx_delete_chap,
+ .get_flashnode_param = qla4xxx_sysfs_ddb_get_param,
+ .set_flashnode_param = qla4xxx_sysfs_ddb_set_param,
+ .new_flashnode = qla4xxx_sysfs_ddb_add,
+ .del_flashnode = qla4xxx_sysfs_ddb_delete,
+ .login_flashnode = qla4xxx_sysfs_ddb_login,
+ .logout_flashnode = qla4xxx_sysfs_ddb_logout,
+ .logout_flashnode_sid = qla4xxx_sysfs_ddb_logout_sid,
};
static struct scsi_transport_template *qla4xxx_scsi_transport;
@@ -376,6 +403,68 @@ static umode_t qla4_attr_is_visible(int param_type, int param)
default:
return 0;
}
+ case ISCSI_FLASHNODE_PARAM:
+ switch (param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ case ISCSI_FLASHNODE_ERL:
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ case ISCSI_FLASHNODE_MAX_R2T:
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ case ISCSI_FLASHNODE_ISID:
+ case ISCSI_FLASHNODE_TSID:
+ case ISCSI_FLASHNODE_PORT:
+ case ISCSI_FLASHNODE_MAX_BURST:
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ case ISCSI_FLASHNODE_IPADDR:
+ case ISCSI_FLASHNODE_ALIAS:
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ case ISCSI_FLASHNODE_IPV6_TC:
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ case ISCSI_FLASHNODE_NAME:
+ case ISCSI_FLASHNODE_TPGT:
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
+ case ISCSI_FLASHNODE_USERNAME:
+ case ISCSI_FLASHNODE_PASSWORD:
+ case ISCSI_FLASHNODE_STATSN:
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
}
return 0;
@@ -391,7 +480,7 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
int valid_chap_entries = 0;
int ret = 0, i;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -495,7 +584,7 @@ static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
memset(chap_table, 0, sizeof(struct ql4_chap_table));
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -1922,6 +2011,252 @@ static int qla4xxx_task_xmit(struct iscsi_task *task)
return -ENOSYS;
}
+static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
+ struct iscsi_bus_flash_conn *conn,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ unsigned long options = 0;
+ int rc = 0;
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
+ rc = iscsi_switch_str_param(&sess->portal_type,
+ PORTAL_TYPE_IPV6);
+ if (rc)
+ goto exit_copy;
+ } else {
+ rc = iscsi_switch_str_param(&sess->portal_type,
+ PORTAL_TYPE_IPV4);
+ if (rc)
+ goto exit_copy;
+ }
+
+ sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
+ &options);
+ sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
+ sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+ conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
+ conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
+ sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
+ sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
+ sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
+ &options);
+ sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
+ sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
+ conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
+ sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
+ &options);
+ sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
+ sess->discovery_auth_optional =
+ test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
+ if (test_bit(ISCSIOPT_ERL1, &options))
+ sess->erl |= BIT_1;
+ if (test_bit(ISCSIOPT_ERL0, &options))
+ sess->erl |= BIT_0;
+
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
+ conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
+ conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
+ conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
+ if (test_bit(TCPOPT_TIMER_SCALE3, &options))
+ conn->tcp_timer_scale |= BIT_3;
+ if (test_bit(TCPOPT_TIMER_SCALE2, &options))
+ conn->tcp_timer_scale |= BIT_2;
+ if (test_bit(TCPOPT_TIMER_SCALE1, &options))
+ conn->tcp_timer_scale |= BIT_1;
+
+ conn->tcp_timer_scale >>= 1;
+ conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
+ conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
+
+ conn->max_recv_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
+ conn->max_xmit_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
+ sess->first_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
+ sess->max_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
+ sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
+ sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+ sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
+ sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
+ conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
+ conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
+ conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
+ conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
+ conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
+ conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
+ conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
+ sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
+ sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
+ sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
+ sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
+
+ sess->default_taskmgmt_timeout =
+ le16_to_cpu(fw_ddb_entry->def_timeout);
+ conn->port = le16_to_cpu(fw_ddb_entry->port);
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->ipaddress) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->redirect_ipaddr) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
+ memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
+
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
+ conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
+
+ conn->link_local_ipv6_addr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->link_local_ipv6_addr) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ memcpy(conn->link_local_ipv6_addr,
+ fw_ddb_entry->link_local_ipv6_addr, IPv6_ADDR_LEN);
+ } else {
+ conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
+ }
+
+ if (fw_ddb_entry->iscsi_name[0]) {
+ rc = iscsi_switch_str_param(&sess->targetname,
+ (char *)fw_ddb_entry->iscsi_name);
+ if (rc)
+ goto exit_copy;
+ }
+
+ if (fw_ddb_entry->iscsi_alias[0]) {
+ rc = iscsi_switch_str_param(&sess->targetalias,
+ (char *)fw_ddb_entry->iscsi_alias);
+ if (rc)
+ goto exit_copy;
+ }
+
+ COPY_ISID(sess->isid, fw_ddb_entry->isid);
+
+exit_copy:
+ return rc;
+}
+
+static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
+ struct iscsi_bus_flash_conn *conn,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ uint16_t options;
+ int rc = 0;
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11);
+ if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= BIT_8;
+ else
+ options &= ~BIT_8;
+
+ SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
+ SET_BITVAL(sess->discovery_sess, options, BIT_4);
+ SET_BITVAL(sess->entry_state, options, BIT_3);
+ fw_ddb_entry->options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+ SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
+ SET_BITVAL(conn->datadgst_en, options, BIT_12);
+ SET_BITVAL(sess->imm_data_en, options, BIT_11);
+ SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
+ SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
+ SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
+ SET_BITVAL(sess->chap_auth_en, options, BIT_7);
+ SET_BITVAL(conn->snack_req_en, options, BIT_6);
+ SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
+ SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
+ SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
+ SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
+ SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
+ fw_ddb_entry->iscsi_options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
+ SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
+ SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
+ SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
+ SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
+ fw_ddb_entry->tcp_options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
+ SET_BITVAL(conn->fragment_disable, options, BIT_4);
+ fw_ddb_entry->ip_options = cpu_to_le16(options);
+
+ fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
+ fw_ddb_entry->iscsi_max_rcv_data_seg_len =
+ cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
+ fw_ddb_entry->iscsi_max_snd_data_seg_len =
+ cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
+ fw_ddb_entry->iscsi_first_burst_len =
+ cpu_to_le16(sess->first_burst / BYTE_UNITS);
+ fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
+ BYTE_UNITS);
+ fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
+ fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
+ fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
+ fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
+ fw_ddb_entry->tcp_xmt_wsf = cpu_to_le16(conn->tcp_xmit_wsf);
+ fw_ddb_entry->tcp_rcv_wsf = cpu_to_le16(conn->tcp_recv_wsf);
+ fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
+ fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
+ fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
+ fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
+ fw_ddb_entry->stat_sn = cpu_to_le16(conn->statsn);
+ fw_ddb_entry->exp_stat_sn = cpu_to_le16(conn->exp_statsn);
+ fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type);
+ fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
+ fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
+ fw_ddb_entry->port = cpu_to_le16(conn->port);
+ fw_ddb_entry->def_timeout =
+ cpu_to_le16(sess->default_taskmgmt_timeout);
+
+ if (conn->ipaddress)
+ memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
+ sizeof(fw_ddb_entry->ip_addr));
+
+ if (conn->redirect_ipaddr)
+ memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
+ sizeof(fw_ddb_entry->tgt_addr));
+
+ if (conn->link_local_ipv6_addr)
+ memcpy(fw_ddb_entry->link_local_ipv6_addr,
+ conn->link_local_ipv6_addr,
+ sizeof(fw_ddb_entry->link_local_ipv6_addr));
+
+ if (sess->targetname)
+ memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
+ sizeof(fw_ddb_entry->iscsi_name));
+
+ if (sess->targetalias)
+ memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
+ sizeof(fw_ddb_entry->iscsi_alias));
+
+ COPY_ISID(fw_ddb_entry->isid, sess->isid);
+
+ return rc;
+}
+
static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
struct dev_db_entry *fw_ddb_entry,
struct iscsi_cls_session *cls_sess,
@@ -2543,6 +2878,7 @@ static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
{
uint32_t dev_state;
+ uint32_t idc_ctrl;
/* don't poll if reset is going on */
if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
@@ -2561,10 +2897,23 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
qla4xxx_wake_dpc(ha);
} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+
+ ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
+ __func__);
+
+ if (is_qla8032(ha)) {
+ idc_ctrl = qla4_83xx_rd_reg(ha,
+ QLA83XX_IDC_DRV_CTRL);
+ if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
+ ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
+ __func__);
+ qla4xxx_mailbox_premature_completion(
+ ha);
+ }
+ }
+
if (is_qla8032(ha) ||
(is_qla8022(ha) && !ql4xdontresethba)) {
- ql4_printk(KERN_INFO, ha, "%s: HW State: "
- "NEED RESET!\n", __func__);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
qla4xxx_wake_dpc(ha);
}
@@ -3737,8 +4086,8 @@ static struct isp_operations qla4_83xx_isp_ops = {
.reset_firmware = qla4_8xxx_stop_firmware,
.queue_iocb = qla4_83xx_queue_iocb,
.complete_iocb = qla4_83xx_complete_iocb,
- .rd_shdw_req_q_out = qla4_83xx_rd_shdw_req_q_out,
- .rd_shdw_rsp_q_in = qla4_83xx_rd_shdw_rsp_q_in,
+ .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out,
+ .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in,
.get_sys_info = qla4_8xxx_get_sys_info,
.rd_reg_direct = qla4_83xx_rd_reg,
.wr_reg_direct = qla4_83xx_wr_reg,
@@ -3761,11 +4110,6 @@ uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
}
-uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
-{
- return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out));
-}
-
uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
{
return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
@@ -3776,11 +4120,6 @@ uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
}
-uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
-{
- return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in));
-}
-
static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
@@ -4005,7 +4344,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
if (val & BIT_7)
ddb_index[1] = (val & 0x7f);
- } else if (is_qla8022(ha)) {
+ } else if (is_qla80XX(ha)) {
buf = dma_alloc_coherent(&ha->pdev->dev, size,
&buf_dma, GFP_KERNEL);
if (!buf) {
@@ -4083,7 +4422,7 @@ static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
int max_chap_entries = 0;
struct ql4_chap_table *chap_table;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -5058,6 +5397,1342 @@ exit_nt_list:
dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
}
+static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
+ struct list_head *list_nt)
+{
+ struct dev_db_entry *fw_ddb_entry;
+ dma_addr_t fw_ddb_dma;
+ int max_ddbs;
+ int fw_idx_size;
+ int ret;
+ uint32_t idx = 0, next_idx = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t conn_id = 0;
+ struct qla_ddb_index *nt_ddb_idx;
+
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
+ &fw_ddb_dma);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
+ goto exit_new_nt_list;
+ }
+ max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
+ MAX_DEV_DB_ENTRIES;
+ fw_idx_size = sizeof(struct qla_ddb_index);
+
+ for (idx = 0; idx < max_ddbs; idx = next_idx) {
+ ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
+ NULL, &next_idx, &state,
+ &conn_err, NULL, &conn_id);
+ if (ret == QLA_ERROR)
+ break;
+
+ /* Check if NT, then add it to list */
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
+ goto continue_next_new_nt;
+
+ if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
+ goto continue_next_new_nt;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Adding DDB to session = 0x%x\n", idx));
+
+ nt_ddb_idx = vmalloc(fw_idx_size);
+ if (!nt_ddb_idx)
+ break;
+
+ nt_ddb_idx->fw_ddb_idx = idx;
+
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
+ if (ret == QLA_SUCCESS) {
+ /* free nt_ddb_idx and do not add to list_nt */
+ vfree(nt_ddb_idx);
+ goto continue_next_new_nt;
+ }
+
+ list_add_tail(&nt_ddb_idx->list, list_nt);
+
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
+ idx);
+ if (ret == QLA_ERROR)
+ goto exit_new_nt_list;
+
+continue_next_new_nt:
+ if (next_idx == 0)
+ break;
+ }
+
+exit_new_nt_list:
+ if (fw_ddb_entry)
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+}
+
+/**
+ * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
+ * @dev: dev associated with the sysfs entry
+ * @data: pointer to flashnode session object
+ *
+ * Returns:
+ * 1: if flashnode entry is non-persistent
+ * 0: if flashnode entry is persistent
+ **/
+static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
+{
+ struct iscsi_bus_flash_session *fnode_sess;
+
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ return 0;
+
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+
+ return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
+}
+
+/**
+ * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
+ * @ha: pointer to host
+ * @fw_ddb_entry: flash ddb data
+ * @idx: target index
+ * @user: if set then this call is made from userland else from kernel
+ *
+ * Returns:
+ * On sucess: QLA_SUCCESS
+ * On failure: QLA_ERROR
+ *
+ * This create separate sysfs entries for session and connection attributes of
+ * the given fw ddb entry.
+ * If this is invoked as a result of a userspace call then the entry is marked
+ * as nonpersistent using flash_state field.
+ **/
+int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t *idx, int user)
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ struct iscsi_bus_flash_conn *fnode_conn = NULL;
+ int rc = QLA_ERROR;
+
+ fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
+ &qla4xxx_iscsi_transport, 0);
+ if (!fnode_sess) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
+ __func__, *idx, ha->host_no);
+ goto exit_tgt_create;
+ }
+
+ fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
+ &qla4xxx_iscsi_transport, 0);
+ if (!fnode_conn) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
+ __func__, *idx, ha->host_no);
+ goto free_sess;
+ }
+
+ if (user) {
+ fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
+ } else {
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
+
+ if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
+ fnode_sess->is_boot_target = 1;
+ else
+ fnode_sess->is_boot_target = 0;
+ }
+
+ rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
+ fw_ddb_entry);
+
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
+ __func__, fnode_sess->dev.kobj.name);
+
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
+ __func__, fnode_conn->dev.kobj.name);
+
+ return QLA_SUCCESS;
+
+free_sess:
+ iscsi_destroy_flashnode_sess(fnode_sess);
+
+exit_tgt_create:
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
+ * @shost: pointer to host
+ * @buf: type of ddb entry (ipv4/ipv6)
+ * @len: length of buf
+ *
+ * This creates new ddb entry in the flash by finding first free index and
+ * storing default ddb there. And then create sysfs entry for the new ddb entry.
+ **/
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
+ int len)
+{
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ struct device *dev;
+ uint16_t idx = 0;
+ uint16_t max_ddbs = 0;
+ uint32_t options = 0;
+ uint32_t rval = QLA_ERROR;
+
+ if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
+ strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
+ __func__));
+ goto exit_ddb_add;
+ }
+
+ max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
+ MAX_DEV_DB_ENTRIES;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ goto exit_ddb_add;
+ }
+
+ dev = iscsi_find_flashnode_sess(ha->host, NULL,
+ qla4xxx_sysfs_ddb_is_non_persistent);
+ if (dev) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: A non-persistent entry %s found\n",
+ __func__, dev->kobj.name);
+ goto exit_ddb_add;
+ }
+
+ for (idx = 0; idx < max_ddbs; idx++) {
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
+ fw_ddb_entry_dma, idx))
+ break;
+ }
+
+ if (idx == max_ddbs)
+ goto exit_ddb_add;
+
+ if (!strncasecmp("ipv6", buf, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (rval == QLA_ERROR)
+ goto exit_ddb_add;
+
+ rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
+
+exit_ddb_add:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ if (rval == QLA_SUCCESS)
+ return idx;
+ else
+ return -EIO;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This writes the contents of target ddb buffer to Flash with a valid cookie
+ * value in order to make the ddb entry persistent.
+ **/
+static int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t options = 0;
+ int rval = 0;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ rval = -ENOMEM;
+ goto exit_ddb_apply;
+ }
+
+ if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (rval == QLA_ERROR)
+ goto exit_ddb_apply;
+
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
+
+ rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
+
+ if (rval == QLA_SUCCESS) {
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
+ ql4_printk(KERN_INFO, ha,
+ "%s: flash node %u of host %lu written to flash\n",
+ __func__, fnode_sess->target_id, ha->host_no);
+ } else {
+ rval = -EIO;
+ ql4_printk(KERN_ERR, ha,
+ "%s: Error while writing flash node %u of host %lu to flash\n",
+ __func__, fnode_sess->target_id, ha->host_no);
+ }
+
+exit_ddb_apply:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return rval;
+}
+
+static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t idx)
+{
+ struct dev_db_entry *ddb_entry = NULL;
+ dma_addr_t ddb_entry_dma;
+ unsigned long wtime;
+ uint32_t mbx_sts = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t tmo = 0;
+ int ret = 0;
+
+ ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
+ &ddb_entry_dma, GFP_KERNEL);
+ if (!ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ return QLA_ERROR;
+ }
+
+ memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
+
+ ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to set ddb entry for index %d\n",
+ __func__, idx));
+ goto exit_ddb_conn_open;
+ }
+
+ qla4xxx_conn_open(ha, idx);
+
+ /* To ensure that sendtargets is done, wait for at least 12 secs */
+ tmo = ((ha->def_timeout > LOGIN_TOV) &&
+ (ha->def_timeout < LOGIN_TOV * 10) ?
+ ha->def_timeout : LOGIN_TOV);
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Default time to wait for login to ddb %d\n", tmo));
+
+ wtime = jiffies + (HZ * tmo);
+ do {
+ ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
+ NULL, &state, &conn_err, NULL,
+ NULL);
+ if (ret == QLA_ERROR)
+ continue;
+
+ if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
+ state == DDB_DS_SESSION_FAILED)
+ break;
+
+ schedule_timeout_uninterruptible(HZ / 10);
+ } while (time_after(wtime, jiffies));
+
+exit_ddb_conn_open:
+ if (ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
+ ddb_entry, ddb_entry_dma);
+ return ret;
+}
+
+static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
+ struct list_head list_nt;
+ uint16_t ddb_index;
+ int ret = 0;
+
+ if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: A discovery already in progress!\n", __func__);
+ return QLA_ERROR;
+ }
+
+ INIT_LIST_HEAD(&list_nt);
+
+ set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
+
+ ret = qla4xxx_get_ddb_index(ha, &ddb_index);
+ if (ret == QLA_ERROR)
+ goto exit_login_st_clr_bit;
+
+ ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
+ if (ret == QLA_ERROR)
+ goto exit_login_st;
+
+ qla4xxx_build_new_nt_list(ha, &list_nt);
+
+ list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
+ list_del_init(&ddb_idx->list);
+ qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
+ vfree(ddb_idx);
+ }
+
+exit_login_st:
+ if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
+ ql4_printk(KERN_ERR, ha,
+ "Unable to clear DDB index = 0x%x\n", ddb_index);
+ }
+
+ clear_bit(ddb_index, ha->ddb_idx_map);
+
+exit_login_st_clr_bit:
+ clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
+ return ret;
+}
+
+static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t idx)
+{
+ int ret = QLA_ERROR;
+
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
+ if (ret != QLA_SUCCESS)
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
+ idx);
+ else
+ ret = -EPERM;
+
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_login - Login to the specified target
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This logs in to the specified target
+ **/
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t options = 0;
+ int ret = 0;
+
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Target info is not persistent\n", __func__);
+ ret = -EIO;
+ goto exit_ddb_login;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ ret = -ENOMEM;
+ goto exit_ddb_login;
+ }
+
+ if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (ret == QLA_ERROR)
+ goto exit_ddb_login;
+
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
+
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
+ ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry);
+ else
+ ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
+ fnode_sess->target_id);
+
+ if (ret > 0)
+ ret = -EIO;
+
+exit_ddb_login:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
+ * @cls_sess: pointer to session to be logged out
+ *
+ * This performs session log out from the specified target
+ **/
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
+{
+ struct iscsi_session *sess;
+ struct ddb_entry *ddb_entry = NULL;
+ struct scsi_qla_host *ha;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ unsigned long flags;
+ unsigned long wtime;
+ uint32_t ddb_state;
+ int options;
+ int ret = 0;
+
+ sess = cls_sess->dd_data;
+ ddb_entry = sess->dd_data;
+ ha = ddb_entry->ha;
+
+ if (ddb_entry->ddb_type != FLASH_DDB) {
+ ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
+ __func__);
+ ret = -ENXIO;
+ goto exit_ddb_logout;
+ }
+
+ if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Logout from boot target entry is not permitted.\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ options = LOGOUT_OPTION_CLOSE_SESSION;
+ if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
+ ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
+ ret = -EIO;
+ goto exit_ddb_logout;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ wtime = jiffies + (HZ * LOGOUT_TOV);
+ do {
+ ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+ fw_ddb_entry, fw_ddb_entry_dma,
+ NULL, NULL, &ddb_state, NULL,
+ NULL, NULL);
+ if (ret == QLA_ERROR)
+ goto ddb_logout_clr_sess;
+
+ if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
+ (ddb_state == DDB_DS_SESSION_FAILED))
+ goto ddb_logout_clr_sess;
+
+ schedule_timeout_uninterruptible(HZ);
+ } while ((time_after(wtime, jiffies)));
+
+ddb_logout_clr_sess:
+ qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+ /*
+ * we have decremented the reference count of the driver
+ * when we setup the session to have the driver unload
+ * to be seamless without actually destroying the
+ * session
+ **/
+ try_module_get(qla4xxx_iscsi_transport.owner);
+ iscsi_destroy_endpoint(ddb_entry->conn->ep);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qla4xxx_free_ddb(ha, ddb_entry);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ iscsi_session_teardown(ddb_entry->sess);
+
+ ret = QLA_SUCCESS;
+
+exit_ddb_logout:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_logout - Logout from the specified target
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This performs log out from the specified target
+ **/
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct ql4_tuple_ddb *flash_tddb = NULL;
+ struct ql4_tuple_ddb *tmp_tddb = NULL;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ struct ddb_entry *ddb_entry = NULL;
+ dma_addr_t fw_ddb_dma;
+ uint32_t next_idx = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t conn_id = 0;
+ int idx, index;
+ int status, ret = 0;
+
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
+ &fw_ddb_dma);
+ if (fw_ddb_entry == NULL) {
+ ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ flash_tddb = vzalloc(sizeof(*flash_tddb));
+ if (!flash_tddb) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s:Memory Allocation failed.\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ tmp_tddb = vzalloc(sizeof(*tmp_tddb));
+ if (!tmp_tddb) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s:Memory Allocation failed.\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ if (!fnode_sess->targetname) {
+ ql4_printk(KERN_ERR, ha,
+ "%s:Cannot logout from SendTarget entry\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ if (fnode_sess->is_boot_target) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Logout from boot target entry is not permitted.\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
+ ISCSI_NAME_SIZE);
+
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
+ else
+ sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
+
+ flash_tddb->tpgt = fnode_sess->tpgt;
+ flash_tddb->port = fnode_conn->port;
+
+ COPY_ISID(flash_tddb->isid, fnode_sess->isid);
+
+ for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
+ if (ddb_entry == NULL)
+ continue;
+
+ if (ddb_entry->ddb_type != FLASH_DDB)
+ continue;
+
+ index = ddb_entry->sess->target_id;
+ status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
+ fw_ddb_dma, NULL, &next_idx,
+ &state, &conn_err, NULL,
+ &conn_id);
+ if (status == QLA_ERROR) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
+
+ status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
+ true);
+ if (status == QLA_SUCCESS) {
+ ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
+ break;
+ }
+ }
+
+ if (idx == MAX_DDB_ENTRIES)
+ ret = -ESRCH;
+
+exit_ddb_logout:
+ if (flash_tddb)
+ vfree(flash_tddb);
+ if (tmp_tddb)
+ vfree(tmp_tddb);
+ if (fw_ddb_entry)
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+
+ return ret;
+}
+
+static int
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct ql4_chap_table chap_tbl;
+ struct device *dev;
+ int parent_type, parent_index = 0xffff;
+ int rc = 0;
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev)
+ return -EIO;
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ switch (param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
+ break;
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
+ break;
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
+ break;
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
+ break;
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
+ break;
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
+ break;
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
+ break;
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
+ break;
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
+ break;
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
+ break;
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
+ break;
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
+ break;
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
+ break;
+ case ISCSI_FLASHNODE_ERL:
+ rc = sprintf(buf, "%u\n", fnode_sess->erl);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
+ break;
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
+ break;
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
+ break;
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
+ break;
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
+ break;
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
+ break;
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
+ break;
+ case ISCSI_FLASHNODE_MAX_R2T:
+ rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
+ break;
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
+ break;
+ case ISCSI_FLASHNODE_ISID:
+ rc = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+ fnode_sess->isid[0], fnode_sess->isid[1],
+ fnode_sess->isid[2], fnode_sess->isid[3],
+ fnode_sess->isid[4], fnode_sess->isid[5]);
+ break;
+ case ISCSI_FLASHNODE_TSID:
+ rc = sprintf(buf, "%u\n", fnode_sess->tsid);
+ break;
+ case ISCSI_FLASHNODE_PORT:
+ rc = sprintf(buf, "%d\n", fnode_conn->port);
+ break;
+ case ISCSI_FLASHNODE_MAX_BURST:
+ rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
+ break;
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ rc = sprintf(buf, "%u\n",
+ fnode_sess->default_taskmgmt_timeout);
+ break;
+ case ISCSI_FLASHNODE_IPADDR:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
+ else
+ rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
+ break;
+ case ISCSI_FLASHNODE_ALIAS:
+ if (fnode_sess->targetalias)
+ rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n",
+ fnode_conn->redirect_ipaddr);
+ else
+ rc = sprintf(buf, "%pI4\n",
+ fnode_conn->redirect_ipaddr);
+ break;
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
+ break;
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ rc = sprintf(buf, "%u\n", fnode_conn->local_port);
+ break;
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
+ break;
+ case ISCSI_FLASHNODE_IPV6_TC:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%u\n",
+ fnode_conn->ipv6_traffic_class);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
+ break;
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n",
+ fnode_conn->link_local_ipv6_addr);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+ if ((fnode_sess->discovery_parent_idx) >= 0 &&
+ (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES))
+ parent_index = fnode_sess->discovery_parent_idx;
+
+ rc = sprintf(buf, "%u\n", parent_index);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ if (fnode_sess->discovery_parent_type == DDB_ISNS)
+ parent_type = ISCSI_DISC_PARENT_ISNS;
+ else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
+ else if (fnode_sess->discovery_parent_type >= 0 &&
+ fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
+ parent_type = ISCSI_DISC_PARENT_SENDTGT;
+ else
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
+
+ rc = sprintf(buf, "%s\n",
+ iscsi_get_discovery_parent_name(parent_type));
+ break;
+ case ISCSI_FLASHNODE_NAME:
+ if (fnode_sess->targetname)
+ rc = sprintf(buf, "%s\n", fnode_sess->targetname);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_TPGT:
+ rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
+ break;
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
+ break;
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
+ break;
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
+ break;
+ case ISCSI_FLASHNODE_USERNAME:
+ if (fnode_sess->chap_auth_en) {
+ qla4xxx_get_uni_chap_at_index(ha,
+ chap_tbl.name,
+ chap_tbl.secret,
+ fnode_sess->chap_out_idx);
+ rc = sprintf(buf, "%s\n", chap_tbl.name);
+ } else {
+ rc = sprintf(buf, "\n");
+ }
+ break;
+ case ISCSI_FLASHNODE_PASSWORD:
+ if (fnode_sess->chap_auth_en) {
+ qla4xxx_get_uni_chap_at_index(ha,
+ chap_tbl.name,
+ chap_tbl.secret,
+ fnode_sess->chap_out_idx);
+ rc = sprintf(buf, "%s\n", chap_tbl.secret);
+ } else {
+ rc = sprintf(buf, "\n");
+ }
+ break;
+ case ISCSI_FLASHNODE_STATSN:
+ rc = sprintf(buf, "%u\n", fnode_conn->statsn);
+ break;
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
+ break;
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
+ rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
+ break;
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ * @data: Parameters and their values to update
+ * @len: len of data
+ *
+ * This sets the parameter of flash ddb entry and writes them to flash
+ **/
+static int
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ struct iscsi_flashnode_param_info *fnode_param;
+ struct nlattr *attr;
+ int rc = QLA_ERROR;
+ uint32_t rem = len;
+
+ fw_ddb_entry = kzalloc(sizeof(*fw_ddb_entry), GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate ddb buffer\n",
+ __func__));
+ return -ENOMEM;
+ }
+
+ nla_for_each_attr(attr, data, len, rem) {
+ fnode_param = nla_data(attr);
+
+ switch (fnode_param->param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ memcpy(fnode_sess->portal_type, fnode_param->value,
+ strlen(fnode_sess->portal_type));
+ break;
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ fnode_sess->auto_snd_tgt_disable =
+ fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ fnode_sess->discovery_sess = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ fnode_sess->entry_state = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ fnode_conn->hdrdgst_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ fnode_conn->datadgst_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ fnode_sess->imm_data_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ fnode_sess->initial_r2t_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ fnode_sess->dataseq_inorder_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ fnode_sess->pdu_inorder_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ fnode_sess->chap_auth_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ fnode_conn->snack_req_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ fnode_sess->discovery_logout_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ fnode_sess->bidi_chap_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ fnode_sess->discovery_auth_optional =
+ fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_ERL:
+ fnode_sess->erl = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ fnode_conn->tcp_nagle_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ fnode_conn->tcp_wsf_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ fnode_conn->tcp_timer_scale = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ fnode_conn->tcp_timestamp_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ fnode_conn->fragment_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ fnode_conn->max_recv_dlength =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ fnode_conn->max_xmit_dlength =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ fnode_sess->first_burst =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ fnode_sess->time2retain =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_R2T:
+ fnode_sess->max_r2t =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ fnode_conn->keepalive_timeout =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_ISID:
+ memcpy(fnode_sess->isid, fnode_param->value,
+ sizeof(fnode_sess->isid));
+ break;
+ case ISCSI_FLASHNODE_TSID:
+ fnode_sess->tsid = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_PORT:
+ fnode_conn->port = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_BURST:
+ fnode_sess->max_burst = *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ fnode_sess->default_taskmgmt_timeout =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_IPADDR:
+ memcpy(fnode_conn->ipaddress, fnode_param->value,
+ IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_ALIAS:
+ rc = iscsi_switch_str_param(&fnode_sess->targetalias,
+ (char *)fnode_param->value);
+ break;
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
+ IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ fnode_conn->max_segment_size =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ fnode_conn->local_port =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ fnode_conn->ipv4_tos = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IPV6_TC:
+ fnode_conn->ipv6_traffic_class = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ fnode_conn->ipv6_flow_label = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_NAME:
+ rc = iscsi_switch_str_param(&fnode_sess->targetname,
+ (char *)fnode_param->value);
+ break;
+ case ISCSI_FLASHNODE_TPGT:
+ fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ memcpy(fnode_conn->link_local_ipv6_addr,
+ fnode_param->value, IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ fnode_sess->discovery_parent_type =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ fnode_conn->tcp_xmit_wsf =
+ *(uint8_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ fnode_conn->tcp_recv_wsf =
+ *(uint8_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_STATSN:
+ fnode_conn->statsn = *(uint32_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ fnode_conn->exp_statsn =
+ *(uint32_t *)fnode_param->value;
+ break;
+ default:
+ ql4_printk(KERN_ERR, ha,
+ "%s: No such sysfs attribute\n", __func__);
+ rc = -ENOSYS;
+ goto exit_set_param;
+ }
+ }
+
+ rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
+
+exit_set_param:
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ *
+ * This invalidates the flash ddb entry at the given index
+ **/
+static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ uint32_t dev_db_start_offset;
+ uint32_t dev_db_end_offset;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint16_t *ddb_cookie = NULL;
+ size_t ddb_size;
+ void *pddb = NULL;
+ int target_id;
+ int rc = 0;
+
+ if (!fnode_sess) {
+ rc = -EINVAL;
+ goto exit_ddb_del;
+ }
+
+ if (fnode_sess->is_boot_target) {
+ rc = -EPERM;
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Deletion of boot target entry is not permitted.\n",
+ __func__));
+ goto exit_ddb_del;
+ }
+
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
+ goto sysfs_ddb_del;
+
+ if (is_qla40XX(ha)) {
+ dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ dev_db_end_offset = FLASH_OFFSET_DB_END;
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+ ddb_size = sizeof(*fw_ddb_entry);
+ } else {
+ dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
+ (ha->hw.flt_region_ddb << 2);
+ /* flt_ddb_size is DDB table size for both ports
+ * so divide it by 2 to calculate the offset for second port
+ */
+ if (ha->port_num == 1)
+ dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
+
+ dev_db_end_offset = dev_db_start_offset +
+ (ha->hw.flt_ddb_size / 2);
+
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+ dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) -
+ (void *)fw_ddb_entry;
+
+ ddb_size = sizeof(*ddb_cookie);
+ }
+
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
+ __func__, dev_db_start_offset, dev_db_end_offset));
+
+ if (dev_db_start_offset > dev_db_end_offset) {
+ rc = -EIO;
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
+ __func__, fnode_sess->target_id));
+ goto exit_ddb_del;
+ }
+
+ pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!pddb) {
+ rc = -ENOMEM;
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ goto exit_ddb_del;
+ }
+
+ if (is_qla40XX(ha)) {
+ fw_ddb_entry = pddb;
+ memset(fw_ddb_entry, 0, ddb_size);
+ ddb_cookie = &fw_ddb_entry->cookie;
+ } else {
+ ddb_cookie = pddb;
+ }
+
+ /* invalidate the cookie */
+ *ddb_cookie = 0xFFEE;
+ qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ ddb_size, FLASH_OPT_RMW_COMMIT);
+
+sysfs_ddb_del:
+ target_id = fnode_sess->target_id;
+ iscsi_destroy_flashnode_sess(fnode_sess);
+ ql4_printk(KERN_INFO, ha,
+ "%s: session and conn entries for flashnode %u of host %lu deleted\n",
+ __func__, target_id, ha->host_no);
+exit_ddb_del:
+ if (pddb)
+ dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
+ fw_ddb_entry_dma);
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
+ * @ha: pointer to adapter structure
+ *
+ * Export the firmware DDB for all send targets and normal targets to sysfs.
+ **/
+static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint16_t max_ddbs;
+ uint16_t idx = 0;
+ int ret = QLA_SUCCESS;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ return -ENOMEM;
+ }
+
+ max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
+ MAX_DEV_DB_ENTRIES;
+
+ for (idx = 0; idx < max_ddbs; idx++) {
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
+ idx))
+ continue;
+
+ ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
+ if (ret) {
+ ret = -EIO;
+ break;
+ }
+ }
+
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+ fw_ddb_entry_dma);
+
+ return ret;
+}
+
+static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
+{
+ iscsi_destroy_all_flashnode(ha->host);
+}
+
/**
* qla4xxx_build_ddb_list - Build ddb list and setup sessions
* @ha: pointer to adapter structure
@@ -5341,8 +7016,11 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
/* Dont retry adapter initialization if IRQ allocation failed */
- if (!test_bit(AF_IRQ_ATTACHED, &ha->flags))
+ if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n",
+ __func__);
goto skip_retry_init;
+ }
while ((!test_bit(AF_ONLINE, &ha->flags)) &&
init_retry_count++ < MAX_INIT_RETRIES) {
@@ -5445,6 +7123,10 @@ skip_retry_init:
ql4_printk(KERN_ERR, ha,
"%s: No iSCSI boot target configured\n", __func__);
+ if (qla4xxx_sysfs_ddb_export(ha))
+ ql4_printk(KERN_ERR, ha,
+ "%s: Error exporting ddb to sysfs\n", __func__);
+
/* Perform the build ddb list and login to each */
qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
@@ -5570,6 +7252,7 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev)
qla4xxx_destroy_fw_ddb_session(ha);
qla4_8xxx_free_sysfs_attr(ha);
+ qla4xxx_sysfs_ddb_remove(ha);
scsi_remove_host(ha->host);
qla4xxx_free_adapter(ha);
@@ -5669,7 +7352,6 @@ struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
/* update counters */
if (srb->flags & SRB_DMA_VALID) {
- ha->req_q_count += srb->iocb_cnt;
ha->iocb_cnt -= srb->iocb_cnt;
if (srb->cmd)
srb->cmd->host_scribble =
@@ -6081,6 +7763,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
{
struct scsi_qla_host *ha = to_qla_host(shost);
int rval = QLA_SUCCESS;
+ uint32_t idc_ctrl;
if (ql4xdontresethba) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
@@ -6111,6 +7794,14 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
}
recover_adapter:
+ /* For ISP83XX set graceful reset bit in IDC_DRV_CTRL if
+ * reset is issued by application */
+ if (is_qla8032(ha) && test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+ qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
+ (idc_ctrl | GRACEFUL_RESET_BIT1));
+ }
+
rval = qla4xxx_recover_adapter(ha);
if (rval != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 6775a45af315..83e0fec35d56 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.03.00-k4"
+#define QLA4XXX_DRIVER_VERSION "5.03.00-k8"
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 5cda11c07c68..5add6f4e7928 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2823,31 +2823,27 @@ static const char * scsi_debug_info(struct Scsi_Host * shp)
/* scsi_debug_proc_info
* Used if the driver currently has no own support for /proc/scsi
*/
-static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
+static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
{
- int len, pos, begin;
- int orig_length;
+ char arr[16];
+ int opts;
+ int minLen = length > 15 ? 15 : length;
- orig_length = length;
-
- if (inout == 1) {
- char arr[16];
- int minLen = length > 15 ? 15 : length;
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ memcpy(arr, buffer, minLen);
+ arr[minLen] = '\0';
+ if (1 != sscanf(arr, "%d", &opts))
+ return -EINVAL;
+ scsi_debug_opts = opts;
+ if (scsi_debug_every_nth != 0)
+ scsi_debug_cmnd_count = 0;
+ return length;
+}
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- memcpy(arr, buffer, minLen);
- arr[minLen] = '\0';
- if (1 != sscanf(arr, "%d", &pos))
- return -EINVAL;
- scsi_debug_opts = pos;
- if (scsi_debug_every_nth != 0)
- scsi_debug_cmnd_count = 0;
- return length;
- }
- begin = 0;
- pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
+static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
+{
+ seq_printf(m, "scsi_debug adapter driver, version "
"%s [%s]\n"
"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
"every_nth=%d(curr:%d)\n"
@@ -2862,15 +2858,7 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta
scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
num_host_resets, dix_reads, dix_writes, dif_errors);
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin);
- if (len > length)
- len = length;
- return len;
+ return 0;
}
static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
@@ -3957,7 +3945,8 @@ write:
static DEF_SCSI_QCMD(scsi_debug_queuecommand)
static struct scsi_host_template sdebug_driver_template = {
- .proc_info = scsi_debug_proc_info,
+ .show_info = scsi_debug_show_info,
+ .write_info = scsi_debug_write_info,
.proc_name = sdebug_proc_name,
.name = "SCSI DEBUG",
.info = scsi_debug_info,
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 65123a21b97e..fe30ea94ffe6 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -50,7 +50,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
u32 rlen;
int err, tport;
- while (skb->len >= NLMSG_SPACE(0)) {
+ while (skb->len >= NLMSG_HDRLEN) {
err = 0;
nlh = nlmsg_hdr(skb);
@@ -70,7 +70,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
goto next_msg;
}
- hdr = NLMSG_DATA(nlh);
+ hdr = nlmsg_data(nlh);
if ((hdr->version != SCSI_NL_VERSION) ||
(hdr->magic != SCSI_NL_MAGIC)) {
err = -EPROTOTYPE;
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index ad747dc337da..db66357211ed 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -45,58 +45,50 @@ static struct proc_dir_entry *proc_scsi;
/* Protect sht->present and sht->proc_dir */
static DEFINE_MUTEX(global_host_template_mutex);
-/**
- * proc_scsi_read - handle read from /proc by calling host's proc_info() command
- * @buffer: passed to proc_info
- * @start: passed to proc_info
- * @offset: passed to proc_info
- * @length: passed to proc_info
- * @eof: returns whether length read was less than requested
- * @data: pointer to a &struct Scsi_Host
- */
-
-static int proc_scsi_read(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data)
-{
- struct Scsi_Host *shost = data;
- int n;
-
- n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0);
- *eof = (n < length);
-
- return n;
-}
-
-/**
- * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info()
- * @file: not used
- * @buf: source of data to write.
- * @count: number of bytes (at most PROC_BLOCK_SIZE) to write.
- * @data: pointer to &struct Scsi_Host
- */
-static int proc_scsi_write_proc(struct file *file, const char __user *buf,
- unsigned long count, void *data)
+static ssize_t proc_scsi_host_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
- struct Scsi_Host *shost = data;
+ struct Scsi_Host *shost = PDE_DATA(file_inode(file));
ssize_t ret = -ENOMEM;
char *page;
- char *start;
if (count > PROC_BLOCK_SIZE)
return -EOVERFLOW;
+ if (!shost->hostt->write_info)
+ return -EINVAL;
+
page = (char *)__get_free_page(GFP_KERNEL);
if (page) {
ret = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
- ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1);
+ ret = shost->hostt->write_info(shost, page, count);
}
out:
free_page((unsigned long)page);
return ret;
}
+static int proc_scsi_show(struct seq_file *m, void *v)
+{
+ struct Scsi_Host *shost = m->private;
+ return shost->hostt->show_info(m, shost);
+}
+
+static int proc_scsi_host_open(struct inode *inode, struct file *file)
+{
+ return single_open_size(file, proc_scsi_show, PDE_DATA(inode),
+ 4 * PAGE_SIZE);
+}
+
+static const struct file_operations proc_scsi_fops = {
+ .open = proc_scsi_host_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = proc_scsi_host_write
+};
+
/**
* scsi_proc_hostdir_add - Create directory in /proc for a scsi host
* @sht: owner of this directory
@@ -106,7 +98,7 @@ out:
void scsi_proc_hostdir_add(struct scsi_host_template *sht)
{
- if (!sht->proc_info)
+ if (!sht->show_info)
return;
mutex_lock(&global_host_template_mutex);
@@ -125,7 +117,7 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
*/
void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
{
- if (!sht->proc_info)
+ if (!sht->show_info)
return;
mutex_lock(&global_host_template_mutex);
@@ -151,16 +143,12 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
return;
sprintf(name,"%d", shost->host_no);
- p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
- sht->proc_dir, proc_scsi_read, shost);
- if (!p) {
+ p = proc_create_data(name, S_IRUGO | S_IWUSR,
+ sht->proc_dir, &proc_scsi_fops, shost);
+ if (!p)
printk(KERN_ERR "%s: Failed to register host %d in"
"%s\n", __func__, shost->host_no,
sht->proc_name);
- return;
- }
-
- p->write_proc = proc_scsi_write_proc;
}
/**
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index e894ca7b54c0..e106c276aa00 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -35,7 +35,6 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
-#include <linux/netlink.h>
#include <net/netlink.h>
#include <scsi/scsi_netlink_fc.h>
#include <scsi/scsi_bsg_fc.h>
@@ -534,7 +533,7 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
struct nlmsghdr *nlh;
struct fc_nl_event *event;
const char *name;
- u32 len, skblen;
+ u32 len;
int err;
if (!scsi_nl_sock) {
@@ -543,21 +542,19 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
}
len = FC_NL_MSGALIGN(sizeof(*event));
- skblen = NLMSG_SPACE(len);
- skb = alloc_skb(skblen, GFP_KERNEL);
+ skb = nlmsg_new(len, GFP_KERNEL);
if (!skb) {
err = -ENOBUFS;
goto send_fail;
}
- nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
- skblen - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0);
if (!nlh) {
err = -ENOBUFS;
goto send_fail_skb;
}
- event = NLMSG_DATA(nlh);
+ event = nlmsg_data(nlh);
INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
FC_NL_ASYNC_EVENT, len);
@@ -604,7 +601,7 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct fc_nl_event *event;
- u32 len, skblen;
+ u32 len;
int err;
if (!scsi_nl_sock) {
@@ -613,21 +610,19 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
}
len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
- skblen = NLMSG_SPACE(len);
- skb = alloc_skb(skblen, GFP_KERNEL);
+ skb = nlmsg_new(len, GFP_KERNEL);
if (!skb) {
err = -ENOBUFS;
goto send_vendor_fail;
}
- nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
- skblen - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0);
if (!nlh) {
err = -ENOBUFS;
goto send_vendor_fail_skb;
}
- event = NLMSG_DATA(nlh);
+ event = nlmsg_data(nlh);
INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
FC_NL_ASYNC_EVENT, len);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0a74b975efdf..47799a33d6ca 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/bsg-lib.h>
#include <linux/idr.h>
+#include <linux/list.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -460,6 +461,689 @@ void iscsi_destroy_iface(struct iscsi_iface *iface)
EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
/*
+ * Interface to display flash node params to sysfs
+ */
+
+#define ISCSI_FLASHNODE_ATTR(_prefix, _name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_prefix##_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+/* flash node session attrs show */
+#define iscsi_flashnode_sess_attr_show(type, name, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct iscsi_bus_flash_session *fnode_sess = \
+ iscsi_dev_to_flash_session(dev);\
+ struct iscsi_transport *t = fnode_sess->transport; \
+ return t->get_flashnode_param(fnode_sess, param, buf); \
+} \
+
+
+#define iscsi_flashnode_sess_attr(type, name, param) \
+ iscsi_flashnode_sess_attr_show(type, name, param) \
+static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
+ show_##type##_##name, NULL);
+
+/* Flash node session attributes */
+
+iscsi_flashnode_sess_attr(fnode, auto_snd_tgt_disable,
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE);
+iscsi_flashnode_sess_attr(fnode, discovery_session,
+ ISCSI_FLASHNODE_DISCOVERY_SESS);
+iscsi_flashnode_sess_attr(fnode, portal_type, ISCSI_FLASHNODE_PORTAL_TYPE);
+iscsi_flashnode_sess_attr(fnode, entry_enable, ISCSI_FLASHNODE_ENTRY_EN);
+iscsi_flashnode_sess_attr(fnode, immediate_data, ISCSI_FLASHNODE_IMM_DATA_EN);
+iscsi_flashnode_sess_attr(fnode, initial_r2t, ISCSI_FLASHNODE_INITIAL_R2T_EN);
+iscsi_flashnode_sess_attr(fnode, data_seq_in_order,
+ ISCSI_FLASHNODE_DATASEQ_INORDER);
+iscsi_flashnode_sess_attr(fnode, data_pdu_in_order,
+ ISCSI_FLASHNODE_PDU_INORDER);
+iscsi_flashnode_sess_attr(fnode, chap_auth, ISCSI_FLASHNODE_CHAP_AUTH_EN);
+iscsi_flashnode_sess_attr(fnode, discovery_logout,
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN);
+iscsi_flashnode_sess_attr(fnode, bidi_chap, ISCSI_FLASHNODE_BIDI_CHAP_EN);
+iscsi_flashnode_sess_attr(fnode, discovery_auth_optional,
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL);
+iscsi_flashnode_sess_attr(fnode, erl, ISCSI_FLASHNODE_ERL);
+iscsi_flashnode_sess_attr(fnode, first_burst_len, ISCSI_FLASHNODE_FIRST_BURST);
+iscsi_flashnode_sess_attr(fnode, def_time2wait, ISCSI_FLASHNODE_DEF_TIME2WAIT);
+iscsi_flashnode_sess_attr(fnode, def_time2retain,
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN);
+iscsi_flashnode_sess_attr(fnode, max_outstanding_r2t, ISCSI_FLASHNODE_MAX_R2T);
+iscsi_flashnode_sess_attr(fnode, isid, ISCSI_FLASHNODE_ISID);
+iscsi_flashnode_sess_attr(fnode, tsid, ISCSI_FLASHNODE_TSID);
+iscsi_flashnode_sess_attr(fnode, max_burst_len, ISCSI_FLASHNODE_MAX_BURST);
+iscsi_flashnode_sess_attr(fnode, def_taskmgmt_tmo,
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO);
+iscsi_flashnode_sess_attr(fnode, targetalias, ISCSI_FLASHNODE_ALIAS);
+iscsi_flashnode_sess_attr(fnode, targetname, ISCSI_FLASHNODE_NAME);
+iscsi_flashnode_sess_attr(fnode, tpgt, ISCSI_FLASHNODE_TPGT);
+iscsi_flashnode_sess_attr(fnode, discovery_parent_idx,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX);
+iscsi_flashnode_sess_attr(fnode, discovery_parent_type,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE);
+iscsi_flashnode_sess_attr(fnode, chap_in_idx, ISCSI_FLASHNODE_CHAP_IN_IDX);
+iscsi_flashnode_sess_attr(fnode, chap_out_idx, ISCSI_FLASHNODE_CHAP_OUT_IDX);
+iscsi_flashnode_sess_attr(fnode, username, ISCSI_FLASHNODE_USERNAME);
+iscsi_flashnode_sess_attr(fnode, username_in, ISCSI_FLASHNODE_USERNAME_IN);
+iscsi_flashnode_sess_attr(fnode, password, ISCSI_FLASHNODE_PASSWORD);
+iscsi_flashnode_sess_attr(fnode, password_in, ISCSI_FLASHNODE_PASSWORD_IN);
+iscsi_flashnode_sess_attr(fnode, is_boot_target, ISCSI_FLASHNODE_IS_BOOT_TGT);
+
+static struct attribute *iscsi_flashnode_sess_attrs[] = {
+ &dev_attr_fnode_auto_snd_tgt_disable.attr,
+ &dev_attr_fnode_discovery_session.attr,
+ &dev_attr_fnode_portal_type.attr,
+ &dev_attr_fnode_entry_enable.attr,
+ &dev_attr_fnode_immediate_data.attr,
+ &dev_attr_fnode_initial_r2t.attr,
+ &dev_attr_fnode_data_seq_in_order.attr,
+ &dev_attr_fnode_data_pdu_in_order.attr,
+ &dev_attr_fnode_chap_auth.attr,
+ &dev_attr_fnode_discovery_logout.attr,
+ &dev_attr_fnode_bidi_chap.attr,
+ &dev_attr_fnode_discovery_auth_optional.attr,
+ &dev_attr_fnode_erl.attr,
+ &dev_attr_fnode_first_burst_len.attr,
+ &dev_attr_fnode_def_time2wait.attr,
+ &dev_attr_fnode_def_time2retain.attr,
+ &dev_attr_fnode_max_outstanding_r2t.attr,
+ &dev_attr_fnode_isid.attr,
+ &dev_attr_fnode_tsid.attr,
+ &dev_attr_fnode_max_burst_len.attr,
+ &dev_attr_fnode_def_taskmgmt_tmo.attr,
+ &dev_attr_fnode_targetalias.attr,
+ &dev_attr_fnode_targetname.attr,
+ &dev_attr_fnode_tpgt.attr,
+ &dev_attr_fnode_discovery_parent_idx.attr,
+ &dev_attr_fnode_discovery_parent_type.attr,
+ &dev_attr_fnode_chap_in_idx.attr,
+ &dev_attr_fnode_chap_out_idx.attr,
+ &dev_attr_fnode_username.attr,
+ &dev_attr_fnode_username_in.attr,
+ &dev_attr_fnode_password.attr,
+ &dev_attr_fnode_password_in.attr,
+ &dev_attr_fnode_is_boot_target.attr,
+ NULL,
+};
+
+static umode_t iscsi_flashnode_sess_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_bus_flash_session *fnode_sess =
+ iscsi_dev_to_flash_session(dev);
+ struct iscsi_transport *t = fnode_sess->transport;
+ int param;
+
+ if (attr == &dev_attr_fnode_auto_snd_tgt_disable.attr) {
+ param = ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE;
+ } else if (attr == &dev_attr_fnode_discovery_session.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_SESS;
+ } else if (attr == &dev_attr_fnode_portal_type.attr) {
+ param = ISCSI_FLASHNODE_PORTAL_TYPE;
+ } else if (attr == &dev_attr_fnode_entry_enable.attr) {
+ param = ISCSI_FLASHNODE_ENTRY_EN;
+ } else if (attr == &dev_attr_fnode_immediate_data.attr) {
+ param = ISCSI_FLASHNODE_IMM_DATA_EN;
+ } else if (attr == &dev_attr_fnode_initial_r2t.attr) {
+ param = ISCSI_FLASHNODE_INITIAL_R2T_EN;
+ } else if (attr == &dev_attr_fnode_data_seq_in_order.attr) {
+ param = ISCSI_FLASHNODE_DATASEQ_INORDER;
+ } else if (attr == &dev_attr_fnode_data_pdu_in_order.attr) {
+ param = ISCSI_FLASHNODE_PDU_INORDER;
+ } else if (attr == &dev_attr_fnode_chap_auth.attr) {
+ param = ISCSI_FLASHNODE_CHAP_AUTH_EN;
+ } else if (attr == &dev_attr_fnode_discovery_logout.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN;
+ } else if (attr == &dev_attr_fnode_bidi_chap.attr) {
+ param = ISCSI_FLASHNODE_BIDI_CHAP_EN;
+ } else if (attr == &dev_attr_fnode_discovery_auth_optional.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL;
+ } else if (attr == &dev_attr_fnode_erl.attr) {
+ param = ISCSI_FLASHNODE_ERL;
+ } else if (attr == &dev_attr_fnode_first_burst_len.attr) {
+ param = ISCSI_FLASHNODE_FIRST_BURST;
+ } else if (attr == &dev_attr_fnode_def_time2wait.attr) {
+ param = ISCSI_FLASHNODE_DEF_TIME2WAIT;
+ } else if (attr == &dev_attr_fnode_def_time2retain.attr) {
+ param = ISCSI_FLASHNODE_DEF_TIME2RETAIN;
+ } else if (attr == &dev_attr_fnode_max_outstanding_r2t.attr) {
+ param = ISCSI_FLASHNODE_MAX_R2T;
+ } else if (attr == &dev_attr_fnode_isid.attr) {
+ param = ISCSI_FLASHNODE_ISID;
+ } else if (attr == &dev_attr_fnode_tsid.attr) {
+ param = ISCSI_FLASHNODE_TSID;
+ } else if (attr == &dev_attr_fnode_max_burst_len.attr) {
+ param = ISCSI_FLASHNODE_MAX_BURST;
+ } else if (attr == &dev_attr_fnode_def_taskmgmt_tmo.attr) {
+ param = ISCSI_FLASHNODE_DEF_TASKMGMT_TMO;
+ } else if (attr == &dev_attr_fnode_targetalias.attr) {
+ param = ISCSI_FLASHNODE_ALIAS;
+ } else if (attr == &dev_attr_fnode_targetname.attr) {
+ param = ISCSI_FLASHNODE_NAME;
+ } else if (attr == &dev_attr_fnode_tpgt.attr) {
+ param = ISCSI_FLASHNODE_TPGT;
+ } else if (attr == &dev_attr_fnode_discovery_parent_idx.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX;
+ } else if (attr == &dev_attr_fnode_discovery_parent_type.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE;
+ } else if (attr == &dev_attr_fnode_chap_in_idx.attr) {
+ param = ISCSI_FLASHNODE_CHAP_IN_IDX;
+ } else if (attr == &dev_attr_fnode_chap_out_idx.attr) {
+ param = ISCSI_FLASHNODE_CHAP_OUT_IDX;
+ } else if (attr == &dev_attr_fnode_username.attr) {
+ param = ISCSI_FLASHNODE_USERNAME;
+ } else if (attr == &dev_attr_fnode_username_in.attr) {
+ param = ISCSI_FLASHNODE_USERNAME_IN;
+ } else if (attr == &dev_attr_fnode_password.attr) {
+ param = ISCSI_FLASHNODE_PASSWORD;
+ } else if (attr == &dev_attr_fnode_password_in.attr) {
+ param = ISCSI_FLASHNODE_PASSWORD_IN;
+ } else if (attr == &dev_attr_fnode_is_boot_target.attr) {
+ param = ISCSI_FLASHNODE_IS_BOOT_TGT;
+ } else {
+ WARN_ONCE(1, "Invalid flashnode session attr");
+ return 0;
+ }
+
+ return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
+}
+
+static struct attribute_group iscsi_flashnode_sess_attr_group = {
+ .attrs = iscsi_flashnode_sess_attrs,
+ .is_visible = iscsi_flashnode_sess_attr_is_visible,
+};
+
+static const struct attribute_group *iscsi_flashnode_sess_attr_groups[] = {
+ &iscsi_flashnode_sess_attr_group,
+ NULL,
+};
+
+static void iscsi_flashnode_sess_release(struct device *dev)
+{
+ struct iscsi_bus_flash_session *fnode_sess =
+ iscsi_dev_to_flash_session(dev);
+
+ kfree(fnode_sess->targetname);
+ kfree(fnode_sess->targetalias);
+ kfree(fnode_sess->portal_type);
+ kfree(fnode_sess);
+}
+
+struct device_type iscsi_flashnode_sess_dev_type = {
+ .name = "iscsi_flashnode_sess_dev_type",
+ .groups = iscsi_flashnode_sess_attr_groups,
+ .release = iscsi_flashnode_sess_release,
+};
+
+/* flash node connection attrs show */
+#define iscsi_flashnode_conn_attr_show(type, name, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);\
+ struct iscsi_bus_flash_session *fnode_sess = \
+ iscsi_flash_conn_to_flash_session(fnode_conn);\
+ struct iscsi_transport *t = fnode_conn->transport; \
+ return t->get_flashnode_param(fnode_sess, param, buf); \
+} \
+
+
+#define iscsi_flashnode_conn_attr(type, name, param) \
+ iscsi_flashnode_conn_attr_show(type, name, param) \
+static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
+ show_##type##_##name, NULL);
+
+/* Flash node connection attributes */
+
+iscsi_flashnode_conn_attr(fnode, is_fw_assigned_ipv6,
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6);
+iscsi_flashnode_conn_attr(fnode, header_digest, ISCSI_FLASHNODE_HDR_DGST_EN);
+iscsi_flashnode_conn_attr(fnode, data_digest, ISCSI_FLASHNODE_DATA_DGST_EN);
+iscsi_flashnode_conn_attr(fnode, snack_req, ISCSI_FLASHNODE_SNACK_REQ_EN);
+iscsi_flashnode_conn_attr(fnode, tcp_timestamp_stat,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT);
+iscsi_flashnode_conn_attr(fnode, tcp_nagle_disable,
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE);
+iscsi_flashnode_conn_attr(fnode, tcp_wsf_disable,
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE);
+iscsi_flashnode_conn_attr(fnode, tcp_timer_scale,
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE);
+iscsi_flashnode_conn_attr(fnode, tcp_timestamp_enable,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN);
+iscsi_flashnode_conn_attr(fnode, fragment_disable,
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE);
+iscsi_flashnode_conn_attr(fnode, keepalive_tmo, ISCSI_FLASHNODE_KEEPALIVE_TMO);
+iscsi_flashnode_conn_attr(fnode, port, ISCSI_FLASHNODE_PORT);
+iscsi_flashnode_conn_attr(fnode, ipaddress, ISCSI_FLASHNODE_IPADDR);
+iscsi_flashnode_conn_attr(fnode, max_recv_dlength,
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH);
+iscsi_flashnode_conn_attr(fnode, max_xmit_dlength,
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH);
+iscsi_flashnode_conn_attr(fnode, local_port, ISCSI_FLASHNODE_LOCAL_PORT);
+iscsi_flashnode_conn_attr(fnode, ipv4_tos, ISCSI_FLASHNODE_IPV4_TOS);
+iscsi_flashnode_conn_attr(fnode, ipv6_traffic_class, ISCSI_FLASHNODE_IPV6_TC);
+iscsi_flashnode_conn_attr(fnode, ipv6_flow_label,
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL);
+iscsi_flashnode_conn_attr(fnode, redirect_ipaddr,
+ ISCSI_FLASHNODE_REDIRECT_IPADDR);
+iscsi_flashnode_conn_attr(fnode, max_segment_size,
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE);
+iscsi_flashnode_conn_attr(fnode, link_local_ipv6,
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6);
+iscsi_flashnode_conn_attr(fnode, tcp_xmit_wsf, ISCSI_FLASHNODE_TCP_XMIT_WSF);
+iscsi_flashnode_conn_attr(fnode, tcp_recv_wsf, ISCSI_FLASHNODE_TCP_RECV_WSF);
+iscsi_flashnode_conn_attr(fnode, statsn, ISCSI_FLASHNODE_STATSN);
+iscsi_flashnode_conn_attr(fnode, exp_statsn, ISCSI_FLASHNODE_EXP_STATSN);
+
+static struct attribute *iscsi_flashnode_conn_attrs[] = {
+ &dev_attr_fnode_is_fw_assigned_ipv6.attr,
+ &dev_attr_fnode_header_digest.attr,
+ &dev_attr_fnode_data_digest.attr,
+ &dev_attr_fnode_snack_req.attr,
+ &dev_attr_fnode_tcp_timestamp_stat.attr,
+ &dev_attr_fnode_tcp_nagle_disable.attr,
+ &dev_attr_fnode_tcp_wsf_disable.attr,
+ &dev_attr_fnode_tcp_timer_scale.attr,
+ &dev_attr_fnode_tcp_timestamp_enable.attr,
+ &dev_attr_fnode_fragment_disable.attr,
+ &dev_attr_fnode_max_recv_dlength.attr,
+ &dev_attr_fnode_max_xmit_dlength.attr,
+ &dev_attr_fnode_keepalive_tmo.attr,
+ &dev_attr_fnode_port.attr,
+ &dev_attr_fnode_ipaddress.attr,
+ &dev_attr_fnode_redirect_ipaddr.attr,
+ &dev_attr_fnode_max_segment_size.attr,
+ &dev_attr_fnode_local_port.attr,
+ &dev_attr_fnode_ipv4_tos.attr,
+ &dev_attr_fnode_ipv6_traffic_class.attr,
+ &dev_attr_fnode_ipv6_flow_label.attr,
+ &dev_attr_fnode_link_local_ipv6.attr,
+ &dev_attr_fnode_tcp_xmit_wsf.attr,
+ &dev_attr_fnode_tcp_recv_wsf.attr,
+ &dev_attr_fnode_statsn.attr,
+ &dev_attr_fnode_exp_statsn.attr,
+ NULL,
+};
+
+static umode_t iscsi_flashnode_conn_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
+ struct iscsi_transport *t = fnode_conn->transport;
+ int param;
+
+ if (attr == &dev_attr_fnode_is_fw_assigned_ipv6.attr) {
+ param = ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6;
+ } else if (attr == &dev_attr_fnode_header_digest.attr) {
+ param = ISCSI_FLASHNODE_HDR_DGST_EN;
+ } else if (attr == &dev_attr_fnode_data_digest.attr) {
+ param = ISCSI_FLASHNODE_DATA_DGST_EN;
+ } else if (attr == &dev_attr_fnode_snack_req.attr) {
+ param = ISCSI_FLASHNODE_SNACK_REQ_EN;
+ } else if (attr == &dev_attr_fnode_tcp_timestamp_stat.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT;
+ } else if (attr == &dev_attr_fnode_tcp_nagle_disable.attr) {
+ param = ISCSI_FLASHNODE_TCP_NAGLE_DISABLE;
+ } else if (attr == &dev_attr_fnode_tcp_wsf_disable.attr) {
+ param = ISCSI_FLASHNODE_TCP_WSF_DISABLE;
+ } else if (attr == &dev_attr_fnode_tcp_timer_scale.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMER_SCALE;
+ } else if (attr == &dev_attr_fnode_tcp_timestamp_enable.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMESTAMP_EN;
+ } else if (attr == &dev_attr_fnode_fragment_disable.attr) {
+ param = ISCSI_FLASHNODE_IP_FRAG_DISABLE;
+ } else if (attr == &dev_attr_fnode_max_recv_dlength.attr) {
+ param = ISCSI_FLASHNODE_MAX_RECV_DLENGTH;
+ } else if (attr == &dev_attr_fnode_max_xmit_dlength.attr) {
+ param = ISCSI_FLASHNODE_MAX_XMIT_DLENGTH;
+ } else if (attr == &dev_attr_fnode_keepalive_tmo.attr) {
+ param = ISCSI_FLASHNODE_KEEPALIVE_TMO;
+ } else if (attr == &dev_attr_fnode_port.attr) {
+ param = ISCSI_FLASHNODE_PORT;
+ } else if (attr == &dev_attr_fnode_ipaddress.attr) {
+ param = ISCSI_FLASHNODE_IPADDR;
+ } else if (attr == &dev_attr_fnode_redirect_ipaddr.attr) {
+ param = ISCSI_FLASHNODE_REDIRECT_IPADDR;
+ } else if (attr == &dev_attr_fnode_max_segment_size.attr) {
+ param = ISCSI_FLASHNODE_MAX_SEGMENT_SIZE;
+ } else if (attr == &dev_attr_fnode_local_port.attr) {
+ param = ISCSI_FLASHNODE_LOCAL_PORT;
+ } else if (attr == &dev_attr_fnode_ipv4_tos.attr) {
+ param = ISCSI_FLASHNODE_IPV4_TOS;
+ } else if (attr == &dev_attr_fnode_ipv6_traffic_class.attr) {
+ param = ISCSI_FLASHNODE_IPV6_TC;
+ } else if (attr == &dev_attr_fnode_ipv6_flow_label.attr) {
+ param = ISCSI_FLASHNODE_IPV6_FLOW_LABEL;
+ } else if (attr == &dev_attr_fnode_link_local_ipv6.attr) {
+ param = ISCSI_FLASHNODE_LINK_LOCAL_IPV6;
+ } else if (attr == &dev_attr_fnode_tcp_xmit_wsf.attr) {
+ param = ISCSI_FLASHNODE_TCP_XMIT_WSF;
+ } else if (attr == &dev_attr_fnode_tcp_recv_wsf.attr) {
+ param = ISCSI_FLASHNODE_TCP_RECV_WSF;
+ } else if (attr == &dev_attr_fnode_statsn.attr) {
+ param = ISCSI_FLASHNODE_STATSN;
+ } else if (attr == &dev_attr_fnode_exp_statsn.attr) {
+ param = ISCSI_FLASHNODE_EXP_STATSN;
+ } else {
+ WARN_ONCE(1, "Invalid flashnode connection attr");
+ return 0;
+ }
+
+ return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
+}
+
+static struct attribute_group iscsi_flashnode_conn_attr_group = {
+ .attrs = iscsi_flashnode_conn_attrs,
+ .is_visible = iscsi_flashnode_conn_attr_is_visible,
+};
+
+static const struct attribute_group *iscsi_flashnode_conn_attr_groups[] = {
+ &iscsi_flashnode_conn_attr_group,
+ NULL,
+};
+
+static void iscsi_flashnode_conn_release(struct device *dev)
+{
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ kfree(fnode_conn->ipaddress);
+ kfree(fnode_conn->redirect_ipaddr);
+ kfree(fnode_conn->link_local_ipv6_addr);
+ kfree(fnode_conn);
+}
+
+struct device_type iscsi_flashnode_conn_dev_type = {
+ .name = "iscsi_flashnode_conn_dev_type",
+ .groups = iscsi_flashnode_conn_attr_groups,
+ .release = iscsi_flashnode_conn_release,
+};
+
+struct bus_type iscsi_flashnode_bus;
+
+int iscsi_flashnode_bus_match(struct device *dev,
+ struct device_driver *drv)
+{
+ if (dev->bus == &iscsi_flashnode_bus)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_flashnode_bus_match);
+
+struct bus_type iscsi_flashnode_bus = {
+ .name = "iscsi_flashnode",
+ .match = &iscsi_flashnode_bus_match,
+};
+
+/**
+ * iscsi_create_flashnode_sess - Add flashnode session entry in sysfs
+ * @shost: pointer to host data
+ * @index: index of flashnode to add in sysfs
+ * @transport: pointer to transport data
+ * @dd_size: total size to allocate
+ *
+ * Adds a sysfs entry for the flashnode session attributes
+ *
+ * Returns:
+ * pointer to allocated flashnode sess on sucess
+ * %NULL on failure
+ */
+struct iscsi_bus_flash_session *
+iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
+ struct iscsi_transport *transport,
+ int dd_size)
+{
+ struct iscsi_bus_flash_session *fnode_sess;
+ int err;
+
+ fnode_sess = kzalloc(sizeof(*fnode_sess) + dd_size, GFP_KERNEL);
+ if (!fnode_sess)
+ return NULL;
+
+ fnode_sess->transport = transport;
+ fnode_sess->target_id = index;
+ fnode_sess->dev.type = &iscsi_flashnode_sess_dev_type;
+ fnode_sess->dev.bus = &iscsi_flashnode_bus;
+ fnode_sess->dev.parent = &shost->shost_gendev;
+ dev_set_name(&fnode_sess->dev, "flashnode_sess-%u:%u",
+ shost->host_no, index);
+
+ err = device_register(&fnode_sess->dev);
+ if (err)
+ goto free_fnode_sess;
+
+ if (dd_size)
+ fnode_sess->dd_data = &fnode_sess[1];
+
+ return fnode_sess;
+
+free_fnode_sess:
+ kfree(fnode_sess);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_flashnode_sess);
+
+/**
+ * iscsi_create_flashnode_conn - Add flashnode conn entry in sysfs
+ * @shost: pointer to host data
+ * @fnode_sess: pointer to the parent flashnode session entry
+ * @transport: pointer to transport data
+ * @dd_size: total size to allocate
+ *
+ * Adds a sysfs entry for the flashnode connection attributes
+ *
+ * Returns:
+ * pointer to allocated flashnode conn on success
+ * %NULL on failure
+ */
+struct iscsi_bus_flash_conn *
+iscsi_create_flashnode_conn(struct Scsi_Host *shost,
+ struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_transport *transport,
+ int dd_size)
+{
+ struct iscsi_bus_flash_conn *fnode_conn;
+ int err;
+
+ fnode_conn = kzalloc(sizeof(*fnode_conn) + dd_size, GFP_KERNEL);
+ if (!fnode_conn)
+ return NULL;
+
+ fnode_conn->transport = transport;
+ fnode_conn->dev.type = &iscsi_flashnode_conn_dev_type;
+ fnode_conn->dev.bus = &iscsi_flashnode_bus;
+ fnode_conn->dev.parent = &fnode_sess->dev;
+ dev_set_name(&fnode_conn->dev, "flashnode_conn-%u:%u:0",
+ shost->host_no, fnode_sess->target_id);
+
+ err = device_register(&fnode_conn->dev);
+ if (err)
+ goto free_fnode_conn;
+
+ if (dd_size)
+ fnode_conn->dd_data = &fnode_conn[1];
+
+ return fnode_conn;
+
+free_fnode_conn:
+ kfree(fnode_conn);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_flashnode_conn);
+
+/**
+ * iscsi_is_flashnode_conn_dev - verify passed device is to be flashnode conn
+ * @dev: device to verify
+ * @data: pointer to data containing value to use for verification
+ *
+ * Verifies if the passed device is flashnode conn device
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int iscsi_is_flashnode_conn_dev(struct device *dev, void *data)
+{
+ return dev->bus == &iscsi_flashnode_bus;
+}
+EXPORT_SYMBOL_GPL(iscsi_is_flashnode_conn_dev);
+
+static int iscsi_destroy_flashnode_conn(struct iscsi_bus_flash_conn *fnode_conn)
+{
+ device_unregister(&fnode_conn->dev);
+ return 0;
+}
+
+static int flashnode_match_index(struct device *dev, void *data)
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ int ret = 0;
+
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ goto exit_match_index;
+
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+ ret = (fnode_sess->target_id == *((int *)data)) ? 1 : 0;
+
+exit_match_index:
+ return ret;
+}
+
+/**
+ * iscsi_get_flashnode_by_index -finds flashnode session entry by index
+ * @shost: pointer to host data
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode session object for the passed index
+ *
+ * Returns:
+ * pointer to found flashnode session object on success
+ * %NULL on failure
+ */
+static struct iscsi_bus_flash_session *
+iscsi_get_flashnode_by_index(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ if (dev)
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+
+ return fnode_sess;
+}
+
+/**
+ * iscsi_find_flashnode_sess - finds flashnode session entry
+ * @shost: pointer to host data
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode session object comparing the data passed using logic
+ * defined in passed function pointer
+ *
+ * Returns:
+ * pointer to found flashnode session device object on success
+ * %NULL on failure
+ */
+struct device *
+iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(iscsi_find_flashnode_sess);
+
+/**
+ * iscsi_find_flashnode_conn - finds flashnode connection entry
+ * @fnode_sess: pointer to parent flashnode session entry
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode connection object comparing the data passed using logic
+ * defined in passed function pointer
+ *
+ * Returns:
+ * pointer to found flashnode connection device object on success
+ * %NULL on failure
+ */
+struct device *
+iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess,
+ void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+
+ dev = device_find_child(&fnode_sess->dev, data, fn);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(iscsi_find_flashnode_conn);
+
+static int iscsi_iter_destroy_flashnode_conn_fn(struct device *dev, void *data)
+{
+ if (!iscsi_is_flashnode_conn_dev(dev, NULL))
+ return 0;
+
+ return iscsi_destroy_flashnode_conn(iscsi_dev_to_flash_conn(dev));
+}
+
+/**
+ * iscsi_destroy_flashnode_sess - destory flashnode session entry
+ * @fnode_sess: pointer to flashnode session entry to be destroyed
+ *
+ * Deletes the flashnode session entry and all children flashnode connection
+ * entries from sysfs
+ */
+void iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess)
+{
+ int err;
+
+ err = device_for_each_child(&fnode_sess->dev, NULL,
+ iscsi_iter_destroy_flashnode_conn_fn);
+ if (err)
+ pr_err("Could not delete all connections for %s. Error %d.\n",
+ fnode_sess->dev.kobj.name, err);
+
+ device_unregister(&fnode_sess->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_flashnode_sess);
+
+static int iscsi_iter_destroy_flashnode_fn(struct device *dev, void *data)
+{
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ return 0;
+
+ iscsi_destroy_flashnode_sess(iscsi_dev_to_flash_session(dev));
+ return 0;
+}
+
+/**
+ * iscsi_destroy_all_flashnode - destory all flashnode session entries
+ * @shost: pointer to host data
+ *
+ * Destroys all the flashnode session entries and all corresponding children
+ * flashnode connection entries from sysfs
+ */
+void iscsi_destroy_all_flashnode(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL,
+ iscsi_iter_destroy_flashnode_fn);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_all_flashnode);
+
+/*
* BSG support
*/
/**
@@ -1344,8 +2028,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_uevent *ev;
char *pdu;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
- data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
+ data_size);
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1360,7 +2044,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
memset(ev, 0, sizeof(*ev));
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_RECV_PDU;
@@ -1381,7 +2065,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
@@ -1390,7 +2074,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
memset(ev, 0, sizeof(*ev));
ev->type = type;
ev->transport_handle = iscsi_handle(transport);
@@ -1415,7 +2099,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
struct sk_buff *skb;
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev));
+ int len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1429,7 +2113,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_CONN_ERROR;
ev->r.connerror.error = error;
@@ -1450,7 +2134,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
struct sk_buff *skb;
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev));
+ int len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1464,7 +2148,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_CONN_LOGIN_STATE;
ev->r.conn_login.state = state;
@@ -1484,7 +2168,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_NOIO);
if (!skb) {
@@ -1494,7 +2178,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(transport);
ev->type = ISCSI_KEVENT_HOST_EVENT;
ev->r.host_event.host_no = host_no;
@@ -1515,7 +2199,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_NOIO);
if (!skb) {
@@ -1524,7 +2208,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(transport);
ev->type = ISCSI_KEVENT_PING_COMP;
ev->r.ping_comp.host_no = host_no;
@@ -1543,7 +2227,7 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
- int len = NLMSG_SPACE(size);
+ int len = nlmsg_total_size(size);
int flags = multi ? NLM_F_MULTI : 0;
int t = done ? NLMSG_DONE : type;
@@ -1555,24 +2239,24 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
nlh->nlmsg_flags = flags;
- memcpy(NLMSG_DATA(nlh), payload, size);
+ memcpy(nlmsg_data(nlh), payload, size);
return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
}
static int
iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
{
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct iscsi_stats *stats;
struct sk_buff *skbstat;
struct iscsi_cls_conn *conn;
struct nlmsghdr *nlhstat;
struct iscsi_uevent *evstat;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- ISCSI_STATS_CUSTOM_MAX);
+ int len = nlmsg_total_size(sizeof(*ev) +
+ sizeof(struct iscsi_stats) +
+ sizeof(struct iscsi_stats_custom) *
+ ISCSI_STATS_CUSTOM_MAX);
int err = 0;
priv = iscsi_if_transport_lookup(transport);
@@ -1595,7 +2279,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
(len - sizeof(*nlhstat)), 0);
- evstat = NLMSG_DATA(nlhstat);
+ evstat = nlmsg_data(nlhstat);
memset(evstat, 0, sizeof(*evstat));
evstat->transport_handle = iscsi_handle(conn->transport);
evstat->type = nlh->nlmsg_type;
@@ -1608,12 +2292,12 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
memset(stats, 0, sizeof(*stats));
transport->get_stats(conn, stats);
- actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- stats->custom_length);
+ actual_size = nlmsg_total_size(sizeof(struct iscsi_uevent) +
+ sizeof(struct iscsi_stats) +
+ sizeof(struct iscsi_stats_custom) *
+ stats->custom_length);
actual_size -= sizeof(*nlhstat);
- actual_size = NLMSG_LENGTH(actual_size);
+ actual_size = nlmsg_msg_size(actual_size);
skb_trim(skbstat, NLMSG_ALIGN(actual_size));
nlhstat->nlmsg_len = actual_size;
@@ -1637,7 +2321,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
struct iscsi_uevent *ev;
struct sk_buff *skb;
struct nlmsghdr *nlh;
- int rc, len = NLMSG_SPACE(sizeof(*ev));
+ int rc, len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(session->transport);
if (!priv)
@@ -1653,7 +2337,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(session->transport);
ev->type = event;
@@ -2005,7 +2689,7 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
static int
iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
{
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct Scsi_Host *shost = NULL;
struct iscsi_chap_rec *chap_rec;
struct iscsi_internal *priv;
@@ -2024,7 +2708,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
return -EINVAL;
chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
- len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+ len = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
shost = scsi_host_lookup(ev->u.get_chap.host_no);
if (!shost) {
@@ -2045,7 +2729,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
(len - sizeof(*nlhchap)), 0);
- evchap = NLMSG_DATA(nlhchap);
+ evchap = nlmsg_data(nlhchap);
memset(evchap, 0, sizeof(*evchap));
evchap->transport_handle = iscsi_handle(transport);
evchap->type = nlh->nlmsg_type;
@@ -2058,7 +2742,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
&evchap->u.get_chap.num_entries, buf);
- actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+ actual_size = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
skb_trim(skbchap, NLMSG_ALIGN(actual_size));
nlhchap->nlmsg_len = actual_size;
@@ -2092,11 +2776,299 @@ static int iscsi_delete_chap(struct iscsi_transport *transport,
return err;
}
+static const struct {
+ enum iscsi_discovery_parent_type value;
+ char *name;
+} iscsi_discovery_parent_names[] = {
+ {ISCSI_DISC_PARENT_UNKNOWN, "Unknown" },
+ {ISCSI_DISC_PARENT_SENDTGT, "Sendtarget" },
+ {ISCSI_DISC_PARENT_ISNS, "isns" },
+};
+
+char *iscsi_get_discovery_parent_name(int parent_type)
+{
+ int i;
+ char *state = "Unknown!";
+
+ for (i = 0; i < ARRAY_SIZE(iscsi_discovery_parent_names); i++) {
+ if (iscsi_discovery_parent_names[i].value & parent_type) {
+ state = iscsi_discovery_parent_names[i].name;
+ break;
+ }
+ }
+ return state;
+}
+EXPORT_SYMBOL_GPL(iscsi_get_discovery_parent_name);
+
+static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->set_flashnode_param) {
+ err = -ENOSYS;
+ goto exit_set_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.set_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.set_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.set_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.set_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+ err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_set_fnode:
+ return err;
+}
+
+static int iscsi_new_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ int index;
+ int err = 0;
+
+ if (!transport->new_flashnode) {
+ err = -ENOSYS;
+ goto exit_new_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.new_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.new_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ index = transport->new_flashnode(shost, data, len);
+
+ if (index >= 0)
+ ev->r.new_flashnode_ret.flashnode_idx = index;
+ else
+ err = -EIO;
+
+put_host:
+ scsi_host_put(shost);
+
+exit_new_fnode:
+ return err;
+}
+
+static int iscsi_del_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->del_flashnode) {
+ err = -ENOSYS;
+ goto exit_del_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.del_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.del_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.del_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.del_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ err = transport->del_flashnode(fnode_sess);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_del_fnode:
+ return err;
+}
+
+static int iscsi_login_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->login_flashnode) {
+ err = -ENOSYS;
+ goto exit_login_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.login_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.login_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.login_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.login_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+ err = transport->login_flashnode(fnode_sess, fnode_conn);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_login_fnode:
+ return err;
+}
+
+static int iscsi_logout_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->logout_flashnode) {
+ err = -ENOSYS;
+ goto exit_logout_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.logout_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.logout_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ err = transport->logout_flashnode(fnode_sess, fnode_conn);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_logout_fnode:
+ return err;
+}
+
+static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_cls_session *session;
+ int err = 0;
+
+ if (!transport->logout_flashnode_sid) {
+ err = -ENOSYS;
+ goto exit_logout_sid;
+ }
+
+ shost = scsi_host_lookup(ev->u.logout_flashnode_sid.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ session = iscsi_session_lookup(ev->u.logout_flashnode_sid.sid);
+ if (!session) {
+ pr_err("%s could not find session id %u\n",
+ __func__, ev->u.logout_flashnode_sid.sid);
+ err = -EINVAL;
+ goto put_host;
+ }
+
+ err = transport->logout_flashnode_sid(session);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_logout_sid:
+ return err;
+}
+
static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
{
int err = 0;
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct iscsi_transport *transport = NULL;
struct iscsi_internal *priv;
struct iscsi_cls_session *session;
@@ -2246,6 +3218,27 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
case ISCSI_UEVENT_DELETE_CHAP:
err = iscsi_delete_chap(transport, ev);
break;
+ case ISCSI_UEVENT_SET_FLASHNODE_PARAMS:
+ err = iscsi_set_flashnode_param(transport, ev,
+ nlmsg_attrlen(nlh,
+ sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_NEW_FLASHNODE:
+ err = iscsi_new_flashnode(transport, ev,
+ nlmsg_attrlen(nlh, sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_DEL_FLASHNODE:
+ err = iscsi_del_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGIN_FLASHNODE:
+ err = iscsi_login_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGOUT_FLASHNODE:
+ err = iscsi_logout_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGOUT_FLASHNODE_SID:
+ err = iscsi_logout_flashnode_sid(transport, ev);
+ break;
default:
err = -ENOSYS;
break;
@@ -2263,7 +3256,7 @@ static void
iscsi_if_rx(struct sk_buff *skb)
{
mutex_lock(&rx_queue_mutex);
- while (skb->len >= NLMSG_SPACE(0)) {
+ while (skb->len >= NLMSG_HDRLEN) {
int err;
uint32_t rlen;
struct nlmsghdr *nlh;
@@ -2276,7 +3269,7 @@ iscsi_if_rx(struct sk_buff *skb)
break;
}
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
if (rlen > skb->len)
rlen = skb->len;
@@ -2981,10 +3974,14 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
+ err = bus_register(&iscsi_flashnode_bus);
+ if (err)
+ goto unregister_session_class;
+
nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, &cfg);
if (!nls) {
err = -ENOBUFS;
- goto unregister_session_class;
+ goto unregister_flashnode_bus;
}
iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
@@ -2995,6 +3992,8 @@ static __init int iscsi_transport_init(void)
release_nls:
netlink_kernel_release(nls);
+unregister_flashnode_bus:
+ bus_unregister(&iscsi_flashnode_bus);
unregister_session_class:
transport_class_unregister(&iscsi_session_class);
unregister_conn_class:
@@ -3014,6 +4013,7 @@ static void __exit iscsi_transport_exit(void)
{
destroy_workqueue(iscsi_eh_timer_workq);
netlink_kernel_release(nls);
+ bus_unregister(&iscsi_flashnode_bus);
transport_class_unregister(&iscsi_connection_class);
transport_class_unregister(&iscsi_session_class);
transport_class_unregister(&iscsi_host_class);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 7992635d405f..e6689776b4f6 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1188,7 +1188,7 @@ error_autopm:
*
* Locking: called with bdev->bd_mutex held.
**/
-static int sd_release(struct gendisk *disk, fmode_t mode)
+static void sd_release(struct gendisk *disk, fmode_t mode)
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device;
@@ -1207,7 +1207,6 @@ static int sd_release(struct gendisk *disk, fmode_t mode)
scsi_autopm_put_device(sdev);
scsi_disk_put(sdkp);
- return 0;
}
static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9f0c46547459..df5e961484e1 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -35,6 +35,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/aio.h>
#include <linux/errno.h>
#include <linux/mtio.h>
#include <linux/ioctl.h>
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index f2884ee90710..119d67f9c47e 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -541,14 +541,13 @@ static int sr_block_open(struct block_device *bdev, fmode_t mode)
return ret;
}
-static int sr_block_release(struct gendisk *disk, fmode_t mode)
+static void sr_block_release(struct gendisk *disk, fmode_t mode)
{
struct scsi_cd *cd = scsi_cd(disk);
mutex_lock(&sr_mutex);
cdrom_release(&cd->cdi, mode);
scsi_cd_put(cd);
mutex_unlock(&sr_mutex);
- return 0;
}
static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 86974471af68..2a32036a9404 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4112,6 +4112,10 @@ static int st_probe(struct device *dev)
tpnt->disk = disk;
disk->private_data = &tpnt->driver;
disk->queue = SDp->request_queue;
+ /* SCSI tape doesn't register this gendisk via add_disk(). Manually
+ * take queue reference that release_disk() expects. */
+ if (!blk_get_queue(disk->queue))
+ goto out_put_disk;
tpnt->driver = &st_template;
tpnt->device = SDp;
@@ -4185,7 +4189,7 @@ static int st_probe(struct device *dev)
idr_preload_end();
if (error < 0) {
pr_warn("st: idr allocation failed: %d\n", error);
- goto out_put_disk;
+ goto out_put_queue;
}
tpnt->index = error;
sprintf(disk->disk_name, "st%d", tpnt->index);
@@ -4211,6 +4215,8 @@ out_remove_devs:
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, tpnt->index);
spin_unlock(&st_index_lock);
+out_put_queue:
+ blk_put_queue(disk->queue);
out_put_disk:
put_disk(disk);
kfree(tpnt);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 7e12a2e4e0a3..636bbe0ea84c 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -661,121 +661,94 @@ static void __init NCR5380_print_options (struct Scsi_Host *instance)
* Inputs : instance, pointer to this instance.
*/
-static void NCR5380_print_status (struct Scsi_Host *instance)
+static void lprint_Scsi_Cmnd(Scsi_Cmnd *cmd)
{
- char *pr_bfr;
- char *start;
- int len;
-
- NCR_PRINT(NDEBUG_ANY);
- NCR_PRINT_PHASE(NDEBUG_ANY);
-
- pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
- if (!pr_bfr) {
- printk("NCR5380_print_status: no memory for print buffer\n");
- return;
- }
- len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
- pr_bfr[len] = 0;
- printk("\n%s\n", pr_bfr);
- free_page((unsigned long) pr_bfr);
+ int i, s;
+ unsigned char *command;
+ printk("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ printk(KERN_CONT " command = ");
+ command = cmd->cmnd;
+ printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ printk(KERN_CONT " %02x", command[i]);
+ printk("\n");
}
-
-/******************************************/
-/*
- * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written
-*/
-
-#undef SPRINTF
-#define SPRINTF(fmt,args...) \
- do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
- pos += sprintf(pos, fmt , ## args); } while(0)
-static
-char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer,
- int length);
-
-static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
- char **start, off_t offset, int length, int inout)
+static void NCR5380_print_status(struct Scsi_Host *instance)
{
- char *pos = buffer;
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
- unsigned long flags;
- off_t begin = 0;
-#define check_offset() \
- do { \
- if (pos - buffer < offset - begin) { \
- begin += pos - buffer; \
- pos = buffer; \
- } \
- } while (0)
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- if (inout) { /* Has data been written to the file ? */
- return(-ENOSYS); /* Currently this is a no-op */
- }
- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- check_offset();
- local_irq_save(flags);
- SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
- check_offset();
- if (!hostdata->connected)
- SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
- else
- pos = lprint_Scsi_Cmnd ((struct scsi_cmnd *) hostdata->connected,
- pos, buffer, length);
- SPRINTF("scsi%d: issue_queue\n", HOSTNO);
- check_offset();
- for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
- check_offset();
- }
-
- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
- check_offset();
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
- check_offset();
- }
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
+
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ printk("\nNCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ local_irq_save(flags);
+ printk("NCR5380: coroutine is%s running.\n",
+ main_running ? "" : "n't");
+ if (!hostdata->connected)
+ printk("scsi%d: no currently connected command\n", HOSTNO);
+ else
+ lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected);
+ printk("scsi%d: issue_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ lprint_Scsi_Cmnd(ptr);
+
+ printk("scsi%d: disconnected_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr))
+ lprint_Scsi_Cmnd(ptr);
- local_irq_restore(flags);
- *start = buffer + (offset - begin);
- if (pos - buffer < offset - begin)
- return 0;
- else if (pos - buffer - (offset - begin) < length)
- return pos - buffer - (offset - begin);
- return length;
+ local_irq_restore(flags);
+ printk("\n");
}
-static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer,
- int length)
+static void show_Scsi_Cmnd(Scsi_Cmnd *cmd, struct seq_file *m)
{
- int i, s;
- unsigned char *command;
- SPRINTF("scsi%d: destination target %d, lun %d\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- SPRINTF(" command = ");
- command = cmd->cmnd;
- SPRINTF("%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- SPRINTF(" %02x", command[i]);
- SPRINTF("\n");
- return pos;
+ int i, s;
+ unsigned char *command;
+ seq_printf(m, "scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ seq_printf(m, " command = ");
+ command = cmd->cmnd;
+ seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ seq_printf(m, " %02x", command[i]);
+ seq_printf(m, "\n");
}
+static int NCR5380_show_info(struct seq_file *m, struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ seq_printf(m, "NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ local_irq_save(flags);
+ seq_printf(m, "NCR5380: coroutine is%s running.\n",
+ main_running ? "" : "n't");
+ if (!hostdata->connected)
+ seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
+ else
+ show_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
+ seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ show_Scsi_Cmnd(ptr, m);
+
+ seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr))
+ show_Scsi_Cmnd(ptr, m);
+
+ local_irq_restore(flags);
+ return 0;
+}
/*
* Function : void NCR5380_init (struct Scsi_Host *instance)
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 6e25889db9d4..e2c009b033ce 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -626,6 +626,7 @@ static int sun3scsi_dma_finish(int write_flag)
#include "sun3_NCR5380.c"
static struct scsi_host_template driver_template = {
+ .show_info = sun3scsi_show_info,
.name = SUN3_SCSI_NAME,
.detect = sun3scsi_detect,
.release = sun3scsi_release,
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index bcefd8458e65..a8da9c710fea 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -100,7 +100,7 @@ static int sun3scsi_release (struct Scsi_Host *);
#define NCR5380_queue_command sun3scsi_queue_command
#define NCR5380_bus_reset sun3scsi_bus_reset
#define NCR5380_abort sun3scsi_abort
-#define NCR5380_proc_info sun3scsi_proc_info
+#define NCR5380_show_info sun3scsi_show_info
#define NCR5380_dma_xfer_len(i, cmd, phase) \
sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 599568299fbe..bac55f7f69f9 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1171,112 +1171,36 @@ printk("sym_user_command: data=%ld\n", uc->data);
#endif /* SYM_LINUX_USER_COMMAND_SUPPORT */
-#ifdef SYM_LINUX_USER_INFO_SUPPORT
-/*
- * Informations through the proc file system.
- */
-struct info_str {
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
-
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return len;
-}
-
/*
* Copy formatted information into the input buffer.
*/
-static int sym_host_info(struct Scsi_Host *shost, char *ptr, off_t offset, int len)
+static int sym_show_info(struct seq_file *m, struct Scsi_Host *shost)
{
+#ifdef SYM_LINUX_USER_INFO_SUPPORT
struct sym_data *sym_data = shost_priv(shost);
struct pci_dev *pdev = sym_data->pdev;
struct sym_hcb *np = sym_data->ncb;
- struct info_str info;
-
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
- copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, "
- "revision id 0x%x\n", np->s.chip_name,
- pdev->device, pdev->revision);
- copy_info(&info, "At PCI address %s, IRQ %u\n",
+ seq_printf(m, "Chip " NAME53C "%s, device id 0x%x, "
+ "revision id 0x%x\n", np->s.chip_name,
+ pdev->device, pdev->revision);
+ seq_printf(m, "At PCI address %s, IRQ %u\n",
pci_name(pdev), pdev->irq);
- copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n",
- (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
- np->maxwide ? "Wide" : "Narrow",
- np->minsync_dt ? ", DT capable" : "");
+ seq_printf(m, "Min. period factor %d, %s SCSI BUS%s\n",
+ (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
+ np->maxwide ? "Wide" : "Narrow",
+ np->minsync_dt ? ", DT capable" : "");
- copy_info(&info, "Max. started commands %d, "
- "max. commands per LUN %d\n",
- SYM_CONF_MAX_START, SYM_CONF_MAX_TAG);
+ seq_printf(m, "Max. started commands %d, "
+ "max. commands per LUN %d\n",
+ SYM_CONF_MAX_START, SYM_CONF_MAX_TAG);
- return info.pos > info.offset? info.pos - info.offset : 0;
-}
-#endif /* SYM_LINUX_USER_INFO_SUPPORT */
-
-/*
- * Entry point of the scsi proc fs of the driver.
- * - func = 0 means read (returns adapter infos)
- * - func = 1 means write (not yet merget from sym53c8xx)
- */
-static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
- char **start, off_t offset, int length, int func)
-{
- int retv;
-
- if (func) {
-#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
- retv = sym_user_command(shost, buffer, length);
-#else
- retv = -EINVAL;
-#endif
- } else {
- if (start)
- *start = buffer;
-#ifdef SYM_LINUX_USER_INFO_SUPPORT
- retv = sym_host_info(shost, buffer, offset, length);
+ return 0;
#else
- retv = -EINVAL;
-#endif
- }
-
- return retv;
+ return -EINVAL;
+#endif /* SYM_LINUX_USER_INFO_SUPPORT */
}
+
#endif /* SYM_LINUX_PROC_INFO_SUPPORT */
/*
@@ -1742,7 +1666,10 @@ static struct scsi_host_template sym2_template = {
.use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xFFFF,
#ifdef SYM_LINUX_PROC_INFO_SUPPORT
- .proc_info = sym53c8xx_proc_info,
+ .show_info = sym_show_info,
+#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
+ .write_info = sym_user_command,
+#endif
.proc_name = NAME53C8XX,
#endif
};
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index d672d97fb84a..f1e4b4148c75 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -201,7 +201,8 @@ int __init t128_detect(struct scsi_host_template * tpnt){
int sig, count;
tpnt->proc_name = "t128";
- tpnt->proc_info = &t128_proc_info;
+ tpnt->show_info = t128_show_info;
+ tpnt->write_info = t128_write_info;
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
base = 0;
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index ada1115079c9..1df82c28e56d 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -140,7 +140,8 @@ static int t128_bus_reset(struct scsi_cmnd *);
#define NCR5380_queue_command t128_queue_command
#define NCR5380_abort t128_abort
#define NCR5380_bus_reset t128_bus_reset
-#define NCR5380_proc_info t128_proc_info
+#define NCR5380_show_info t128_show_info
+#define NCR5380_write_info t128_write_info
/* 15 14 12 10 7 5 3
1101 0100 1010 1000 */
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 3449a1f8c656..2168258fb2c3 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -13,6 +13,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mempool.h>
@@ -20,12 +22,14 @@
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/virtio_scsi.h>
+#include <linux/cpu.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#define VIRTIO_SCSI_MEMPOOL_SZ 64
#define VIRTIO_SCSI_EVENT_LEN 8
+#define VIRTIO_SCSI_VQ_BASE 2
/* Command queue element */
struct virtio_scsi_cmd {
@@ -57,27 +61,61 @@ struct virtio_scsi_vq {
struct virtqueue *vq;
};
-/* Per-target queue state */
+/*
+ * Per-target queue state.
+ *
+ * This struct holds the data needed by the queue steering policy. When a
+ * target is sent multiple requests, we need to drive them to the same queue so
+ * that FIFO processing order is kept. However, if a target was idle, we can
+ * choose a queue arbitrarily. In this case the queue is chosen according to
+ * the current VCPU, so the driver expects the number of request queues to be
+ * equal to the number of VCPUs. This makes it easy and fast to select the
+ * queue, and also lets the driver optimize the IRQ affinity for the virtqueues
+ * (each virtqueue's affinity is set to the CPU that "owns" the queue).
+ *
+ * An interesting effect of this policy is that only writes to req_vq need to
+ * take the tgt_lock. Read can be done outside the lock because:
+ *
+ * - writes of req_vq only occur when atomic_inc_return(&tgt->reqs) returns 1.
+ * In that case, no other CPU is reading req_vq: even if they were in
+ * virtscsi_queuecommand_multi, they would be spinning on tgt_lock.
+ *
+ * - reads of req_vq only occur when the target is not idle (reqs != 0).
+ * A CPU that enters virtscsi_queuecommand_multi will not modify req_vq.
+ *
+ * Similarly, decrements of reqs are never concurrent with writes of req_vq.
+ * Thus they can happen outside the tgt_lock, provided of course we make reqs
+ * an atomic_t.
+ */
struct virtio_scsi_target_state {
- /* Protects sg. Lock hierarchy is tgt_lock -> vq_lock. */
+ /* This spinlock never held at the same time as vq_lock. */
spinlock_t tgt_lock;
- /* For sglist construction when adding commands to the virtqueue. */
- struct scatterlist sg[];
+ /* Count of outstanding requests. */
+ atomic_t reqs;
+
+ /* Currently active virtqueue for requests sent to this target. */
+ struct virtio_scsi_vq *req_vq;
};
/* Driver instance state */
struct virtio_scsi {
struct virtio_device *vdev;
- struct virtio_scsi_vq ctrl_vq;
- struct virtio_scsi_vq event_vq;
- struct virtio_scsi_vq req_vq;
-
/* Get some buffers ready for event vq */
struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];
- struct virtio_scsi_target_state *tgt[];
+ u32 num_queues;
+
+ /* If the affinity hint is set for virtqueues */
+ bool affinity_hint_set;
+
+ /* CPU hotplug notifier */
+ struct notifier_block nb;
+
+ struct virtio_scsi_vq ctrl_vq;
+ struct virtio_scsi_vq event_vq;
+ struct virtio_scsi_vq req_vqs[];
};
static struct kmem_cache *virtscsi_cmd_cache;
@@ -107,11 +145,13 @@ static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid)
*
* Called with vq_lock held.
*/
-static void virtscsi_complete_cmd(void *buf)
+static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
{
struct virtio_scsi_cmd *cmd = buf;
struct scsi_cmnd *sc = cmd->sc;
struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
+ struct virtio_scsi_target_state *tgt =
+ scsi_target(sc->device)->hostdata;
dev_dbg(&sc->device->sdev_gendev,
"cmd %p response %u status %#02x sense_len %u\n",
@@ -166,32 +206,71 @@ static void virtscsi_complete_cmd(void *buf)
mempool_free(cmd, virtscsi_cmd_pool);
sc->scsi_done(sc);
+
+ atomic_dec(&tgt->reqs);
}
-static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf))
+static void virtscsi_vq_done(struct virtio_scsi *vscsi,
+ struct virtio_scsi_vq *virtscsi_vq,
+ void (*fn)(struct virtio_scsi *vscsi, void *buf))
{
void *buf;
unsigned int len;
+ unsigned long flags;
+ struct virtqueue *vq = virtscsi_vq->vq;
+ spin_lock_irqsave(&virtscsi_vq->vq_lock, flags);
do {
virtqueue_disable_cb(vq);
while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
- fn(buf);
+ fn(vscsi, buf);
} while (!virtqueue_enable_cb(vq));
+ spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
}
static void virtscsi_req_done(struct virtqueue *vq)
{
struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
struct virtio_scsi *vscsi = shost_priv(sh);
- unsigned long flags;
+ int index = vq->index - VIRTIO_SCSI_VQ_BASE;
+ struct virtio_scsi_vq *req_vq = &vscsi->req_vqs[index];
- spin_lock_irqsave(&vscsi->req_vq.vq_lock, flags);
- virtscsi_vq_done(vq, virtscsi_complete_cmd);
- spin_unlock_irqrestore(&vscsi->req_vq.vq_lock, flags);
+ /*
+ * Read req_vq before decrementing the reqs field in
+ * virtscsi_complete_cmd.
+ *
+ * With barriers:
+ *
+ * CPU #0 virtscsi_queuecommand_multi (CPU #1)
+ * ------------------------------------------------------------
+ * lock vq_lock
+ * read req_vq
+ * read reqs (reqs = 1)
+ * write reqs (reqs = 0)
+ * increment reqs (reqs = 1)
+ * write req_vq
+ *
+ * Possible reordering without barriers:
+ *
+ * CPU #0 virtscsi_queuecommand_multi (CPU #1)
+ * ------------------------------------------------------------
+ * lock vq_lock
+ * read reqs (reqs = 1)
+ * write reqs (reqs = 0)
+ * increment reqs (reqs = 1)
+ * write req_vq
+ * read (wrong) req_vq
+ *
+ * We do not need a full smp_rmb, because req_vq is required to get
+ * to tgt->reqs: tgt is &vscsi->tgt[sc->device->id], where sc is stored
+ * in the virtqueue as the user token.
+ */
+ smp_read_barrier_depends();
+
+ virtscsi_vq_done(vscsi, req_vq, virtscsi_complete_cmd);
};
-static void virtscsi_complete_free(void *buf)
+static void virtscsi_complete_free(struct virtio_scsi *vscsi, void *buf)
{
struct virtio_scsi_cmd *cmd = buf;
@@ -205,11 +284,8 @@ static void virtscsi_ctrl_done(struct virtqueue *vq)
{
struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
struct virtio_scsi *vscsi = shost_priv(sh);
- unsigned long flags;
- spin_lock_irqsave(&vscsi->ctrl_vq.vq_lock, flags);
- virtscsi_vq_done(vq, virtscsi_complete_free);
- spin_unlock_irqrestore(&vscsi->ctrl_vq.vq_lock, flags);
+ virtscsi_vq_done(vscsi, &vscsi->ctrl_vq, virtscsi_complete_free);
};
static int virtscsi_kick_event(struct virtio_scsi *vscsi,
@@ -223,8 +299,8 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
- err = virtqueue_add_buf(vscsi->event_vq.vq, &sg, 0, 1, event_node,
- GFP_ATOMIC);
+ err = virtqueue_add_inbuf(vscsi->event_vq.vq, &sg, 1, event_node,
+ GFP_ATOMIC);
if (!err)
virtqueue_kick(vscsi->event_vq.vq);
@@ -254,7 +330,7 @@ static void virtscsi_cancel_event_work(struct virtio_scsi *vscsi)
}
static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
- struct virtio_scsi_event *event)
+ struct virtio_scsi_event *event)
{
struct scsi_device *sdev;
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
@@ -332,7 +408,7 @@ static void virtscsi_handle_event(struct work_struct *work)
virtscsi_kick_event(vscsi, event_node);
}
-static void virtscsi_complete_event(void *buf)
+static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf)
{
struct virtio_scsi_event_node *event_node = buf;
@@ -344,82 +420,65 @@ static void virtscsi_event_done(struct virtqueue *vq)
{
struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
struct virtio_scsi *vscsi = shost_priv(sh);
- unsigned long flags;
- spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
- virtscsi_vq_done(vq, virtscsi_complete_event);
- spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
+ virtscsi_vq_done(vscsi, &vscsi->event_vq, virtscsi_complete_event);
};
-static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
- struct scsi_data_buffer *sdb)
-{
- struct sg_table *table = &sdb->table;
- struct scatterlist *sg_elem;
- unsigned int idx = *p_idx;
- int i;
-
- for_each_sg(table->sgl, sg_elem, table->nents, i)
- sg[idx++] = *sg_elem;
-
- *p_idx = idx;
-}
-
/**
- * virtscsi_map_cmd - map a scsi_cmd to a virtqueue scatterlist
- * @vscsi : virtio_scsi state
+ * virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue
+ * @vq : the struct virtqueue we're talking about
* @cmd : command structure
- * @out_num : number of read-only elements
- * @in_num : number of write-only elements
* @req_size : size of the request buffer
* @resp_size : size of the response buffer
- *
- * Called with tgt_lock held.
+ * @gfp : flags to use for memory allocations
*/
-static void virtscsi_map_cmd(struct virtio_scsi_target_state *tgt,
- struct virtio_scsi_cmd *cmd,
- unsigned *out_num, unsigned *in_num,
- size_t req_size, size_t resp_size)
+static int virtscsi_add_cmd(struct virtqueue *vq,
+ struct virtio_scsi_cmd *cmd,
+ size_t req_size, size_t resp_size, gfp_t gfp)
{
struct scsi_cmnd *sc = cmd->sc;
- struct scatterlist *sg = tgt->sg;
- unsigned int idx = 0;
+ struct scatterlist *sgs[4], req, resp;
+ struct sg_table *out, *in;
+ unsigned out_num = 0, in_num = 0;
+
+ out = in = NULL;
+
+ if (sc && sc->sc_data_direction != DMA_NONE) {
+ if (sc->sc_data_direction != DMA_FROM_DEVICE)
+ out = &scsi_out(sc)->table;
+ if (sc->sc_data_direction != DMA_TO_DEVICE)
+ in = &scsi_in(sc)->table;
+ }
/* Request header. */
- sg_set_buf(&sg[idx++], &cmd->req, req_size);
+ sg_init_one(&req, &cmd->req, req_size);
+ sgs[out_num++] = &req;
/* Data-out buffer. */
- if (sc && sc->sc_data_direction != DMA_FROM_DEVICE)
- virtscsi_map_sgl(sg, &idx, scsi_out(sc));
-
- *out_num = idx;
+ if (out)
+ sgs[out_num++] = out->sgl;
/* Response header. */
- sg_set_buf(&sg[idx++], &cmd->resp, resp_size);
+ sg_init_one(&resp, &cmd->resp, resp_size);
+ sgs[out_num + in_num++] = &resp;
/* Data-in buffer */
- if (sc && sc->sc_data_direction != DMA_TO_DEVICE)
- virtscsi_map_sgl(sg, &idx, scsi_in(sc));
+ if (in)
+ sgs[out_num + in_num++] = in->sgl;
- *in_num = idx - *out_num;
+ return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, gfp);
}
-static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
- struct virtio_scsi_vq *vq,
+static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq,
struct virtio_scsi_cmd *cmd,
size_t req_size, size_t resp_size, gfp_t gfp)
{
- unsigned int out_num, in_num;
unsigned long flags;
int err;
bool needs_kick = false;
- spin_lock_irqsave(&tgt->tgt_lock, flags);
- virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size);
-
- spin_lock(&vq->vq_lock);
- err = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
- spin_unlock(&tgt->tgt_lock);
+ spin_lock_irqsave(&vq->vq_lock, flags);
+ err = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size, gfp);
if (!err)
needs_kick = virtqueue_kick_prepare(vq->vq);
@@ -430,10 +489,10 @@ static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
return err;
}
-static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
+static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
+ struct virtio_scsi_vq *req_vq,
+ struct scsi_cmnd *sc)
{
- struct virtio_scsi *vscsi = shost_priv(sh);
- struct virtio_scsi_target_state *tgt = vscsi->tgt[sc->device->id];
struct virtio_scsi_cmd *cmd;
int ret;
@@ -467,7 +526,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
- if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd,
+ if (virtscsi_kick_cmd(req_vq, cmd,
sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
GFP_ATOMIC) == 0)
ret = 0;
@@ -478,14 +537,62 @@ out:
return ret;
}
+static int virtscsi_queuecommand_single(struct Scsi_Host *sh,
+ struct scsi_cmnd *sc)
+{
+ struct virtio_scsi *vscsi = shost_priv(sh);
+ struct virtio_scsi_target_state *tgt =
+ scsi_target(sc->device)->hostdata;
+
+ atomic_inc(&tgt->reqs);
+ return virtscsi_queuecommand(vscsi, &vscsi->req_vqs[0], sc);
+}
+
+static struct virtio_scsi_vq *virtscsi_pick_vq(struct virtio_scsi *vscsi,
+ struct virtio_scsi_target_state *tgt)
+{
+ struct virtio_scsi_vq *vq;
+ unsigned long flags;
+ u32 queue_num;
+
+ spin_lock_irqsave(&tgt->tgt_lock, flags);
+
+ /*
+ * The memory barrier after atomic_inc_return matches
+ * the smp_read_barrier_depends() in virtscsi_req_done.
+ */
+ if (atomic_inc_return(&tgt->reqs) > 1)
+ vq = ACCESS_ONCE(tgt->req_vq);
+ else {
+ queue_num = smp_processor_id();
+ while (unlikely(queue_num >= vscsi->num_queues))
+ queue_num -= vscsi->num_queues;
+
+ tgt->req_vq = vq = &vscsi->req_vqs[queue_num];
+ }
+
+ spin_unlock_irqrestore(&tgt->tgt_lock, flags);
+ return vq;
+}
+
+static int virtscsi_queuecommand_multi(struct Scsi_Host *sh,
+ struct scsi_cmnd *sc)
+{
+ struct virtio_scsi *vscsi = shost_priv(sh);
+ struct virtio_scsi_target_state *tgt =
+ scsi_target(sc->device)->hostdata;
+ struct virtio_scsi_vq *req_vq = virtscsi_pick_vq(vscsi, tgt);
+
+ return virtscsi_queuecommand(vscsi, req_vq, sc);
+}
+
static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
{
DECLARE_COMPLETION_ONSTACK(comp);
- struct virtio_scsi_target_state *tgt = vscsi->tgt[cmd->sc->device->id];
int ret = FAILED;
cmd->comp = &comp;
- if (virtscsi_kick_cmd(tgt, &vscsi->ctrl_vq, cmd,
+ if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd,
sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
GFP_NOIO) < 0)
goto out;
@@ -547,18 +654,57 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
return virtscsi_tmf(vscsi, cmd);
}
-static struct scsi_host_template virtscsi_host_template = {
+static int virtscsi_target_alloc(struct scsi_target *starget)
+{
+ struct virtio_scsi_target_state *tgt =
+ kmalloc(sizeof(*tgt), GFP_KERNEL);
+ if (!tgt)
+ return -ENOMEM;
+
+ spin_lock_init(&tgt->tgt_lock);
+ atomic_set(&tgt->reqs, 0);
+ tgt->req_vq = NULL;
+
+ starget->hostdata = tgt;
+ return 0;
+}
+
+static void virtscsi_target_destroy(struct scsi_target *starget)
+{
+ struct virtio_scsi_target_state *tgt = starget->hostdata;
+ kfree(tgt);
+}
+
+static struct scsi_host_template virtscsi_host_template_single = {
+ .module = THIS_MODULE,
+ .name = "Virtio SCSI HBA",
+ .proc_name = "virtio_scsi",
+ .this_id = -1,
+ .queuecommand = virtscsi_queuecommand_single,
+ .eh_abort_handler = virtscsi_abort,
+ .eh_device_reset_handler = virtscsi_device_reset,
+
+ .can_queue = 1024,
+ .dma_boundary = UINT_MAX,
+ .use_clustering = ENABLE_CLUSTERING,
+ .target_alloc = virtscsi_target_alloc,
+ .target_destroy = virtscsi_target_destroy,
+};
+
+static struct scsi_host_template virtscsi_host_template_multi = {
.module = THIS_MODULE,
.name = "Virtio SCSI HBA",
.proc_name = "virtio_scsi",
- .queuecommand = virtscsi_queuecommand,
.this_id = -1,
+ .queuecommand = virtscsi_queuecommand_multi,
.eh_abort_handler = virtscsi_abort,
.eh_device_reset_handler = virtscsi_device_reset,
.can_queue = 1024,
.dma_boundary = UINT_MAX,
.use_clustering = ENABLE_CLUSTERING,
+ .target_alloc = virtscsi_target_alloc,
+ .target_destroy = virtscsi_target_destroy,
};
#define virtscsi_config_get(vdev, fld) \
@@ -578,29 +724,69 @@ static struct scsi_host_template virtscsi_host_template = {
&__val, sizeof(__val)); \
})
-static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
- struct virtqueue *vq)
+static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
{
- spin_lock_init(&virtscsi_vq->vq_lock);
- virtscsi_vq->vq = vq;
+ int i;
+ int cpu;
+
+ /* In multiqueue mode, when the number of cpu is equal
+ * to the number of request queues, we let the qeueues
+ * to be private to one cpu by setting the affinity hint
+ * to eliminate the contention.
+ */
+ if ((vscsi->num_queues == 1 ||
+ vscsi->num_queues != num_online_cpus()) && affinity) {
+ if (vscsi->affinity_hint_set)
+ affinity = false;
+ else
+ return;
+ }
+
+ if (affinity) {
+ i = 0;
+ for_each_online_cpu(cpu) {
+ virtqueue_set_affinity(vscsi->req_vqs[i].vq, cpu);
+ i++;
+ }
+
+ vscsi->affinity_hint_set = true;
+ } else {
+ for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
+ virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
+
+ vscsi->affinity_hint_set = false;
+ }
}
-static struct virtio_scsi_target_state *virtscsi_alloc_tgt(
- struct virtio_device *vdev, int sg_elems)
+static void virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
{
- struct virtio_scsi_target_state *tgt;
- gfp_t gfp_mask = GFP_KERNEL;
-
- /* We need extra sg elements at head and tail. */
- tgt = kmalloc(sizeof(*tgt) + sizeof(tgt->sg[0]) * (sg_elems + 2),
- gfp_mask);
+ get_online_cpus();
+ __virtscsi_set_affinity(vscsi, affinity);
+ put_online_cpus();
+}
- if (!tgt)
- return NULL;
+static int virtscsi_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ struct virtio_scsi *vscsi = container_of(nfb, struct virtio_scsi, nb);
+ switch(action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ __virtscsi_set_affinity(vscsi, true);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
- spin_lock_init(&tgt->tgt_lock);
- sg_init_table(tgt->sg, sg_elems + 2);
- return tgt;
+static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
+ struct virtqueue *vq)
+{
+ spin_lock_init(&virtscsi_vq->vq_lock);
+ virtscsi_vq->vq = vq;
}
static void virtscsi_scan(struct virtio_device *vdev)
@@ -614,46 +800,56 @@ static void virtscsi_remove_vqs(struct virtio_device *vdev)
{
struct Scsi_Host *sh = virtio_scsi_host(vdev);
struct virtio_scsi *vscsi = shost_priv(sh);
- u32 i, num_targets;
+
+ virtscsi_set_affinity(vscsi, false);
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
- num_targets = sh->max_id;
- for (i = 0; i < num_targets; i++) {
- kfree(vscsi->tgt[i]);
- vscsi->tgt[i] = NULL;
- }
-
vdev->config->del_vqs(vdev);
}
static int virtscsi_init(struct virtio_device *vdev,
- struct virtio_scsi *vscsi, int num_targets)
+ struct virtio_scsi *vscsi)
{
int err;
- struct virtqueue *vqs[3];
- u32 i, sg_elems;
+ u32 i;
+ u32 num_vqs;
+ vq_callback_t **callbacks;
+ const char **names;
+ struct virtqueue **vqs;
+
+ num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE;
+ vqs = kmalloc(num_vqs * sizeof(struct virtqueue *), GFP_KERNEL);
+ callbacks = kmalloc(num_vqs * sizeof(vq_callback_t *), GFP_KERNEL);
+ names = kmalloc(num_vqs * sizeof(char *), GFP_KERNEL);
+
+ if (!callbacks || !vqs || !names) {
+ err = -ENOMEM;
+ goto out;
+ }
- vq_callback_t *callbacks[] = {
- virtscsi_ctrl_done,
- virtscsi_event_done,
- virtscsi_req_done
- };
- const char *names[] = {
- "control",
- "event",
- "request"
- };
+ callbacks[0] = virtscsi_ctrl_done;
+ callbacks[1] = virtscsi_event_done;
+ names[0] = "control";
+ names[1] = "event";
+ for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs; i++) {
+ callbacks[i] = virtscsi_req_done;
+ names[i] = "request";
+ }
/* Discover virtqueues and write information to configuration. */
- err = vdev->config->find_vqs(vdev, 3, vqs, callbacks, names);
+ err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names);
if (err)
- return err;
+ goto out;
virtscsi_init_vq(&vscsi->ctrl_vq, vqs[0]);
virtscsi_init_vq(&vscsi->event_vq, vqs[1]);
- virtscsi_init_vq(&vscsi->req_vq, vqs[2]);
+ for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs; i++)
+ virtscsi_init_vq(&vscsi->req_vqs[i - VIRTIO_SCSI_VQ_BASE],
+ vqs[i]);
+
+ virtscsi_set_affinity(vscsi, true);
virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
@@ -661,19 +857,12 @@ static int virtscsi_init(struct virtio_device *vdev,
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
virtscsi_kick_event_all(vscsi);
- /* We need to know how many segments before we allocate. */
- sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
-
- for (i = 0; i < num_targets; i++) {
- vscsi->tgt[i] = virtscsi_alloc_tgt(vdev, sg_elems);
- if (!vscsi->tgt[i]) {
- err = -ENOMEM;
- goto out;
- }
- }
err = 0;
out:
+ kfree(names);
+ kfree(callbacks);
+ kfree(vqs);
if (err)
virtscsi_remove_vqs(vdev);
return err;
@@ -686,13 +875,21 @@ static int virtscsi_probe(struct virtio_device *vdev)
int err;
u32 sg_elems, num_targets;
u32 cmd_per_lun;
+ u32 num_queues;
+ struct scsi_host_template *hostt;
+
+ /* We need to know how many queues before we allocate. */
+ num_queues = virtscsi_config_get(vdev, num_queues) ? : 1;
- /* Allocate memory and link the structs together. */
num_targets = virtscsi_config_get(vdev, max_target) + 1;
- shost = scsi_host_alloc(&virtscsi_host_template,
- sizeof(*vscsi)
- + num_targets * sizeof(struct virtio_scsi_target_state));
+ if (num_queues == 1)
+ hostt = &virtscsi_host_template_single;
+ else
+ hostt = &virtscsi_host_template_multi;
+
+ shost = scsi_host_alloc(hostt,
+ sizeof(*vscsi) + sizeof(vscsi->req_vqs[0]) * num_queues);
if (!shost)
return -ENOMEM;
@@ -700,12 +897,20 @@ static int virtscsi_probe(struct virtio_device *vdev)
shost->sg_tablesize = sg_elems;
vscsi = shost_priv(shost);
vscsi->vdev = vdev;
+ vscsi->num_queues = num_queues;
vdev->priv = shost;
- err = virtscsi_init(vdev, vscsi, num_targets);
+ err = virtscsi_init(vdev, vscsi);
if (err)
goto virtscsi_init_failed;
+ vscsi->nb.notifier_call = &virtscsi_cpu_callback;
+ err = register_hotcpu_notifier(&vscsi->nb);
+ if (err) {
+ pr_err("registering cpu notifier failed\n");
+ goto scsi_add_host_failed;
+ }
+
cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
@@ -743,6 +948,8 @@ static void virtscsi_remove(struct virtio_device *vdev)
scsi_remove_host(shost);
+ unregister_hotcpu_notifier(&vscsi->nb);
+
virtscsi_remove_vqs(vdev);
scsi_host_put(shost);
}
@@ -759,7 +966,7 @@ static int virtscsi_restore(struct virtio_device *vdev)
struct Scsi_Host *sh = virtio_scsi_host(vdev);
struct virtio_scsi *vscsi = shost_priv(sh);
- return virtscsi_init(vdev, vscsi, sh->max_id);
+ return virtscsi_init(vdev, vscsi);
}
#endif
@@ -794,8 +1001,7 @@ static int __init init(void)
virtscsi_cmd_cache = KMEM_CACHE(virtio_scsi_cmd, 0);
if (!virtscsi_cmd_cache) {
- printk(KERN_ERR "kmem_cache_create() for "
- "virtscsi_cmd_cache failed\n");
+ pr_err("kmem_cache_create() for virtscsi_cmd_cache failed\n");
goto error;
}
@@ -804,8 +1010,7 @@ static int __init init(void)
mempool_create_slab_pool(VIRTIO_SCSI_MEMPOOL_SZ,
virtscsi_cmd_cache);
if (!virtscsi_cmd_pool) {
- printk(KERN_ERR "mempool_create() for"
- "virtscsi_cmd_pool failed\n");
+ pr_err("mempool_create() for virtscsi_cmd_pool failed\n");
goto error;
}
ret = register_virtio_driver(&virtio_scsi_driver);
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index c0ee4ea28a19..41883a87931d 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -2054,22 +2054,16 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
printk(" Version %s - %s\n", WD33C93_VERSION, WD33C93_DATE);
}
-int
-wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
+int wd33c93_write_info(struct Scsi_Host *instance, char *buf, int len)
{
-
#ifdef PROC_INTERFACE
-
char *bp;
- char tbuf[128];
struct WD33C93_hostdata *hd;
- struct scsi_cmnd *cmd;
int x;
- static int stop = 0;
hd = (struct WD33C93_hostdata *) instance->hostdata;
-/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
+/* We accept the following
* keywords (same format as command-line, but arguments are not optional):
* debug
* disconnect
@@ -2083,145 +2077,124 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
* nosync
*/
- if (in) {
- buf[len] = '\0';
- for (bp = buf; *bp; ) {
- while (',' == *bp || ' ' == *bp)
- ++bp;
- if (!strncmp(bp, "debug:", 6)) {
- hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK;
- } else if (!strncmp(bp, "disconnect:", 11)) {
- x = simple_strtoul(bp+11, &bp, 0);
- if (x < DIS_NEVER || x > DIS_ALWAYS)
- x = DIS_ADAPTIVE;
- hd->disconnect = x;
- } else if (!strncmp(bp, "period:", 7)) {
+ buf[len] = '\0';
+ for (bp = buf; *bp; ) {
+ while (',' == *bp || ' ' == *bp)
+ ++bp;
+ if (!strncmp(bp, "debug:", 6)) {
+ hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK;
+ } else if (!strncmp(bp, "disconnect:", 11)) {
+ x = simple_strtoul(bp+11, &bp, 0);
+ if (x < DIS_NEVER || x > DIS_ALWAYS)
+ x = DIS_ADAPTIVE;
+ hd->disconnect = x;
+ } else if (!strncmp(bp, "period:", 7)) {
+ x = simple_strtoul(bp+7, &bp, 0);
+ hd->default_sx_per =
+ hd->sx_table[round_period((unsigned int) x,
+ hd->sx_table)].period_ns;
+ } else if (!strncmp(bp, "resync:", 7)) {
+ set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0));
+ } else if (!strncmp(bp, "proc:", 5)) {
+ hd->proc = simple_strtoul(bp+5, &bp, 0);
+ } else if (!strncmp(bp, "nodma:", 6)) {
+ hd->no_dma = simple_strtoul(bp+6, &bp, 0);
+ } else if (!strncmp(bp, "level2:", 7)) {
+ hd->level2 = simple_strtoul(bp+7, &bp, 0);
+ } else if (!strncmp(bp, "burst:", 6)) {
+ hd->dma_mode =
+ simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA;
+ } else if (!strncmp(bp, "fast:", 5)) {
+ x = !!simple_strtol(bp+5, &bp, 0);
+ if (x != hd->fast)
+ set_resync(hd, 0xff);
+ hd->fast = x;
+ } else if (!strncmp(bp, "nosync:", 7)) {
x = simple_strtoul(bp+7, &bp, 0);
- hd->default_sx_per =
- hd->sx_table[round_period((unsigned int) x,
- hd->sx_table)].period_ns;
- } else if (!strncmp(bp, "resync:", 7)) {
- set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0));
- } else if (!strncmp(bp, "proc:", 5)) {
- hd->proc = simple_strtoul(bp+5, &bp, 0);
- } else if (!strncmp(bp, "nodma:", 6)) {
- hd->no_dma = simple_strtoul(bp+6, &bp, 0);
- } else if (!strncmp(bp, "level2:", 7)) {
- hd->level2 = simple_strtoul(bp+7, &bp, 0);
- } else if (!strncmp(bp, "burst:", 6)) {
- hd->dma_mode =
- simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA;
- } else if (!strncmp(bp, "fast:", 5)) {
- x = !!simple_strtol(bp+5, &bp, 0);
- if (x != hd->fast)
- set_resync(hd, 0xff);
- hd->fast = x;
- } else if (!strncmp(bp, "nosync:", 7)) {
- x = simple_strtoul(bp+7, &bp, 0);
- set_resync(hd, x ^ hd->no_sync);
- hd->no_sync = x;
- } else {
- break; /* unknown keyword,syntax-error,... */
- }
+ set_resync(hd, x ^ hd->no_sync);
+ hd->no_sync = x;
+ } else {
+ break; /* unknown keyword,syntax-error,... */
}
- return len;
}
+ return len;
+#else
+ return 0;
+#endif
+}
+
+int
+wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
+{
+#ifdef PROC_INTERFACE
+ struct WD33C93_hostdata *hd;
+ struct scsi_cmnd *cmd;
+ int x;
+
+ hd = (struct WD33C93_hostdata *) instance->hostdata;
spin_lock_irq(&hd->lock);
- bp = buf;
- *bp = '\0';
- if (hd->proc & PR_VERSION) {
- sprintf(tbuf, "\nVersion %s - %s.",
+ if (hd->proc & PR_VERSION)
+ seq_printf(m, "\nVersion %s - %s.",
WD33C93_VERSION, WD33C93_DATE);
- strcat(bp, tbuf);
- }
+
if (hd->proc & PR_INFO) {
- sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d"
+ seq_printf(m, "\nclock_freq=%02x no_sync=%02x no_dma=%d"
" dma_mode=%02x fast=%d",
hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast);
- strcat(bp, tbuf);
- strcat(bp, "\nsync_xfer[] = ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\nsync_stat[] = ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
- strcat(bp, tbuf);
- }
+ seq_printf(m, "\nsync_xfer[] = ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%02x", hd->sync_xfer[x]);
+ seq_printf(m, "\nsync_stat[] = ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%02x", hd->sync_stat[x]);
}
#ifdef PROC_STATISTICS
if (hd->proc & PR_STATISTICS) {
- strcat(bp, "\ncommands issued: ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\ndisconnects allowed:");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
- strcat(bp, tbuf);
- }
- strcat(bp, "\ndisconnects done: ");
- for (x = 0; x < 7; x++) {
- sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
- strcat(bp, tbuf);
- }
- sprintf(tbuf,
+ seq_printf(m, "\ncommands issued: ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
+ seq_printf(m, "\ndisconnects allowed:");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
+ seq_printf(m, "\ndisconnects done: ");
+ for (x = 0; x < 7; x++)
+ seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
+ seq_printf(m,
"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
hd->int_cnt, hd->dma_cnt, hd->pio_cnt);
- strcat(bp, tbuf);
}
#endif
if (hd->proc & PR_CONNECTED) {
- strcat(bp, "\nconnected: ");
+ seq_printf(m, "\nconnected: ");
if (hd->connected) {
cmd = (struct scsi_cmnd *) hd->connected;
- sprintf(tbuf, " %d:%d(%02x)",
+ seq_printf(m, " %d:%d(%02x)",
cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
}
}
if (hd->proc & PR_INPUTQ) {
- strcat(bp, "\ninput_Q: ");
+ seq_printf(m, "\ninput_Q: ");
cmd = (struct scsi_cmnd *) hd->input_Q;
while (cmd) {
- sprintf(tbuf, " %d:%d(%02x)",
+ seq_printf(m, " %d:%d(%02x)",
cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
}
if (hd->proc & PR_DISCQ) {
- strcat(bp, "\ndisconnected_Q:");
+ seq_printf(m, "\ndisconnected_Q:");
cmd = (struct scsi_cmnd *) hd->disconnected_Q;
while (cmd) {
- sprintf(tbuf, " %d:%d(%02x)",
+ seq_printf(m, " %d:%d(%02x)",
cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
- strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
}
- strcat(bp, "\n");
+ seq_printf(m, "\n");
spin_unlock_irq(&hd->lock);
- *start = buf;
- if (stop) {
- stop = 0;
- return 0;
- }
- if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */
- stop = 1;
- if (hd->proc & PR_STOP) /* stop every other time */
- stop = 1;
- return strlen(bp);
-
-#else /* PROC_INTERFACE */
-
- return 0;
-
#endif /* PROC_INTERFACE */
-
+ return 0;
}
EXPORT_SYMBOL(wd33c93_host_reset);
@@ -2229,4 +2202,5 @@ EXPORT_SYMBOL(wd33c93_init);
EXPORT_SYMBOL(wd33c93_abort);
EXPORT_SYMBOL(wd33c93_queuecommand);
EXPORT_SYMBOL(wd33c93_intr);
-EXPORT_SYMBOL(wd33c93_proc_info);
+EXPORT_SYMBOL(wd33c93_show_info);
+EXPORT_SYMBOL(wd33c93_write_info);
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 3b463d7304dc..08abe508e9ad 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -345,7 +345,8 @@ void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs,
int wd33c93_abort (struct scsi_cmnd *cmd);
int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd);
void wd33c93_intr (struct Scsi_Host *instance);
-int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+int wd33c93_show_info(struct seq_file *, struct Scsi_Host *);
+int wd33c93_write_info(struct Scsi_Host *, char *, int);
int wd33c93_host_reset (struct scsi_cmnd *);
#endif /* WD33C93_H */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index d89a5dfd3ade..f9a6e4b0affe 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1296,9 +1296,9 @@ static void wd7000_revision(Adapter * host)
#undef SPRINTF
-#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
+#define SPRINTF(args...) { seq_printf(m, ## args); }
-static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host)
+static int wd7000_set_info(struct Scsi_Host *host, char *buffer, int length)
{
dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
@@ -1310,22 +1310,15 @@ static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host)
}
-static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
+static int wd7000_show_info(struct seq_file *m, struct Scsi_Host *host)
{
Adapter *adapter = (Adapter *)host->hostdata;
unsigned long flags;
- char *pos = buffer;
#ifdef WD7000_DEBUG
Mailbox *ogmbs, *icmbs;
short count;
#endif
- /*
- * Has data been written to the file ?
- */
- if (inout)
- return (wd7000_set_info(buffer, length, host));
-
spin_lock_irqsave(host->host_lock, flags);
SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
SPRINTF(" IO base: 0x%x\n", adapter->iobase);
@@ -1368,17 +1361,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
spin_unlock_irqrestore(host->host_lock, flags);
- /*
- * Calculate start of next buffer, and return value.
- */
- *start = buffer + offset;
-
- if ((pos - buffer) < offset)
- return (0);
- else if ((pos - buffer - offset) < length)
- return (pos - buffer - offset);
- else
- return (length);
+ return 0;
}
@@ -1413,7 +1396,8 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt)
for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
tpnt->proc_name = "wd7000";
- tpnt->proc_info = &wd7000_proc_info;
+ tpnt->show_info = &wd7000_show_info;
+ tpnt->write_info = wd7000_set_info;
/*
* Set up SCB free list, which is shared by all adapters
@@ -1658,7 +1642,8 @@ MODULE_LICENSE("GPL");
static struct scsi_host_template driver_template = {
.proc_name = "wd7000",
- .proc_info = wd7000_proc_info,
+ .show_info = wd7000_show_info,
+ .write_info = wd7000_set_info,
.name = "Western Digital WD-7000",
.detect = wd7000_detect,
.release = wd7000_release,