summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-9xxx.c145
-rw-r--r--drivers/scsi/3w-9xxx.h14
-rw-r--r--drivers/scsi/3w-xxxx.c5
-rw-r--r--drivers/scsi/3w-xxxx.h2
-rw-r--r--drivers/scsi/53c700.c93
-rw-r--r--drivers/scsi/53c700.h18
-rw-r--r--drivers/scsi/53c7xx.c6
-rw-r--r--drivers/scsi/BusLogic.c25
-rw-r--r--drivers/scsi/BusLogic.h7
-rw-r--r--drivers/scsi/Kconfig76
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/NCR5380.c17
-rw-r--r--drivers/scsi/NCR5380.h6
-rw-r--r--drivers/scsi/NCR53C9x.c6
-rw-r--r--drivers/scsi/NCR53C9x.h2
-rw-r--r--drivers/scsi/NCR53c406a.c18
-rw-r--r--drivers/scsi/NCR_D700.c4
-rw-r--r--drivers/scsi/NCR_Q720.c4
-rw-r--r--drivers/scsi/a100u2w.c4
-rw-r--r--drivers/scsi/a2091.c2
-rw-r--r--drivers/scsi/a3000.c2
-rw-r--r--drivers/scsi/aacraid/aacraid.h4
-rw-r--r--drivers/scsi/aacraid/commsup.c23
-rw-r--r--drivers/scsi/aacraid/rx.c4
-rw-r--r--drivers/scsi/aacraid/sa.c2
-rw-r--r--drivers/scsi/advansys.c10
-rw-r--r--drivers/scsi/aha152x.c19
-rw-r--r--drivers/scsi/aha1542.c12
-rw-r--r--drivers/scsi/aha1740.c14
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx4
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx4
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h66
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c350
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_inline.h33
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c51
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h7
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c15
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.h1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h11
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c40
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_inline.h3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c76
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h15
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c10
-rw-r--r--drivers/scsi/aic7xxx_old.c316
-rw-r--r--drivers/scsi/aic94xx/Kconfig1
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c23
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h15
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c59
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c193
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c8
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c5
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.h2
-rw-r--r--drivers/scsi/amiga7xx.h2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c3
-rw-r--r--drivers/scsi/arm/acornscsi.c53
-rw-r--r--drivers/scsi/arm/acornscsi.h4
-rw-r--r--drivers/scsi/arm/arxescsi.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c3
-rw-r--r--drivers/scsi/arm/eesox.c3
-rw-r--r--drivers/scsi/arm/fas216.c50
-rw-r--r--drivers/scsi/arm/fas216.h36
-rw-r--r--drivers/scsi/arm/powertec.c4
-rw-r--r--drivers/scsi/arm/queue.c37
-rw-r--r--drivers/scsi/arm/queue.h28
-rw-r--r--drivers/scsi/arm/scsi.h2
-rw-r--r--drivers/scsi/atari_NCR5380.c2
-rw-r--r--drivers/scsi/atari_dma_emul.c4
-rw-r--r--drivers/scsi/atari_scsi.c10
-rw-r--r--drivers/scsi/atp870u.c2
-rw-r--r--drivers/scsi/bvme6000.h2
-rw-r--r--drivers/scsi/dc395x.c9
-rw-r--r--drivers/scsi/dec_esp.c12
-rw-r--r--drivers/scsi/dmx3191d.c2
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h12
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/dpti.h4
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c5
-rw-r--r--drivers/scsi/eata_pio.c9
-rw-r--r--drivers/scsi/esp.c4
-rw-r--r--drivers/scsi/fd_mcs.c6
-rw-r--r--drivers/scsi/fdomain.c47
-rw-r--r--drivers/scsi/gdth.c14
-rw-r--r--drivers/scsi/gdth.h10
-rw-r--r--drivers/scsi/gvp11.c2
-rw-r--r--drivers/scsi/hosts.c8
-rw-r--r--drivers/scsi/hosts.h2
-rw-r--r--drivers/scsi/hptiop.c2
-rw-r--r--drivers/scsi/ibmmca.c3
-rw-r--r--drivers/scsi/ibmvscsi/Makefile2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c960
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c5
-rw-r--r--drivers/scsi/ide-scsi.c22
-rw-r--r--drivers/scsi/imm.c14
-rw-r--r--drivers/scsi/imm.h1
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c21
-rw-r--r--drivers/scsi/ipr.c940
-rw-r--r--drivers/scsi/ipr.h97
-rw-r--r--drivers/scsi/ips.c123
-rw-r--r--drivers/scsi/ips.h25
-rw-r--r--drivers/scsi/iscsi_tcp.c22
-rw-r--r--drivers/scsi/libiscsi.c85
-rw-r--r--drivers/scsi/libsas/sas_discover.c22
-rw-r--r--drivers/scsi/libsas/sas_event.c14
-rw-r--r--drivers/scsi/libsas/sas_expander.c120
-rw-r--r--drivers/scsi/libsas/sas_init.c12
-rw-r--r--drivers/scsi/libsas/sas_internal.h12
-rw-r--r--drivers/scsi/libsas/sas_phy.c45
-rw-r--r--drivers/scsi/libsas/sas_port.c30
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c94
-rw-r--r--drivers/scsi/libsrp.c441
-rw-r--r--drivers/scsi/lpfc/lpfc.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c121
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c34
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c231
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h35
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c142
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c9
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c56
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac53c94.c10
-rw-r--r--drivers/scsi/mac_esp.c14
-rw-r--r--drivers/scsi/megaraid.c19
-rw-r--r--drivers/scsi/megaraid.h7
-rw-r--r--drivers/scsi/megaraid/mega_common.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c368
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h22
-rw-r--r--drivers/scsi/mesh.c12
-rw-r--r--drivers/scsi/mvme147.c2
-rw-r--r--drivers/scsi/mvme16x.h2
-rw-r--r--drivers/scsi/ncr53c8xx.c35
-rw-r--r--drivers/scsi/ncr53c8xx.h8
-rw-r--r--drivers/scsi/nsp32.c6
-rw-r--r--drivers/scsi/nsp32.h42
-rw-r--r--drivers/scsi/oktagon_esp.c6
-rw-r--r--drivers/scsi/osst.c134
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c7
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c5
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c51
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h48
-rw-r--r--drivers/scsi/pcmcia/nsp_debug.c4
-rw-r--r--drivers/scsi/pcmcia/nsp_message.c4
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c11
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c14
-rw-r--r--drivers/scsi/pluto.c6
-rw-r--r--drivers/scsi/ppa.c14
-rw-r--r--drivers/scsi/ppa.h1
-rw-r--r--drivers/scsi/psi240i.c40
-rw-r--r--drivers/scsi/psi240i.h6
-rw-r--r--drivers/scsi/qla1280.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c108
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h14
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h46
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h19
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c228
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c201
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c104
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c151
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/Kconfig7
-rw-r--r--drivers/scsi/qla4xxx/Makefile5
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c197
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.h55
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h595
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h848
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h79
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c1315
-rw-r--r--drivers/scsi/qla4xxx/ql4_inline.h84
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c374
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c797
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c930
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c232
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.h254
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c1679
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h8
-rw-r--r--drivers/scsi/qlogicfas408.c26
-rw-r--r--drivers/scsi/qlogicfas408.h31
-rw-r--r--drivers/scsi/qlogicpti.c6
-rw-r--r--drivers/scsi/qlogicpti_asm.c4
-rw-r--r--drivers/scsi/raid_class.c20
-rw-r--r--drivers/scsi/scsi.c62
-rw-r--r--drivers/scsi/scsi_debug.c141
-rw-r--r--drivers/scsi/scsi_devinfo.c16
-rw-r--r--drivers/scsi/scsi_error.c35
-rw-r--r--drivers/scsi/scsi_lib.c374
-rw-r--r--drivers/scsi/scsi_priv.h3
-rw-r--r--drivers/scsi/scsi_scan.c250
-rw-r--r--drivers/scsi/scsi_sysfs.c12
-rw-r--r--drivers/scsi/scsi_tgt_if.c352
-rw-r--r--drivers/scsi/scsi_tgt_lib.c745
-rw-r--r--drivers/scsi/scsi_tgt_priv.h25
-rw-r--r--drivers/scsi/scsi_transport_fc.c60
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c256
-rw-r--r--drivers/scsi/scsi_transport_sas.c1
-rw-r--r--drivers/scsi/scsi_transport_spi.c7
-rw-r--r--drivers/scsi/scsi_wait_scan.c31
-rw-r--r--drivers/scsi/sd.c59
-rw-r--r--drivers/scsi/seagate.c37
-rw-r--r--drivers/scsi/seagate.h19
-rw-r--r--drivers/scsi/sg.c76
-rw-r--r--drivers/scsi/sgiwd93.c2
-rw-r--r--drivers/scsi/sim710.c1
-rw-r--r--drivers/scsi/st.c138
-rw-r--r--drivers/scsi/stex.c319
-rw-r--r--drivers/scsi/sun3_NCR5380.c117
-rw-r--r--drivers/scsi/sun3_scsi.c17
-rw-r--r--drivers/scsi/sun3_scsi.h9
-rw-r--r--drivers/scsi/sun3_scsi_vme.c17
-rw-r--r--drivers/scsi/sym53c416.c3
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/t128.h39
-rw-r--r--drivers/scsi/tmscsim.c21
-rw-r--r--drivers/scsi/u14-34f.c5
-rw-r--r--drivers/scsi/ultrastor.c13
-rw-r--r--drivers/scsi/wd7000.c4
236 files changed, 15775 insertions, 3059 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 5a9475e56d0..b091a0fc4eb 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -66,6 +66,9 @@
2.26.02.006 - Fix 9550SX pchip reset timeout.
Add big endian support.
2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
+ 2.26.02.008 - Free irq handler in __twa_shutdown().
+ Serialize reset code.
+ Add support for 9650SE controllers.
*/
#include <linux/module.h>
@@ -89,7 +92,7 @@
#include "3w-9xxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "2.26.02.007"
+#define TW_DRIVER_VERSION "2.26.02.008"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -566,9 +569,9 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
goto out;
}
- tw_dev->working_srl = fw_on_ctlr_srl;
- tw_dev->working_branch = fw_on_ctlr_branch;
- tw_dev->working_build = fw_on_ctlr_build;
+ tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
+ tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
+ tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
/* Try base mode compatibility */
if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
@@ -590,10 +593,23 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
}
goto out;
}
- tw_dev->working_srl = TW_BASE_FW_SRL;
- tw_dev->working_branch = TW_BASE_FW_BRANCH;
- tw_dev->working_build = TW_BASE_FW_BUILD;
- }
+ tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
+ tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
+ tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
+ }
+
+ /* Load rest of compatibility struct */
+ strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
+ tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
+ tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+ tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
+ tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
+ tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
+ tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
+ tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
+ tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
+ tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
+
retval = 0;
out:
return retval;
@@ -631,7 +647,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
goto out2;
/* Check data buffer size */
- if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+ if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
retval = TW_IOCTL_ERROR_OS_EINVAL;
goto out2;
}
@@ -680,13 +696,6 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
/* Now wait for command to complete */
timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
- /* See if we reset while waiting for the ioctl to complete */
- if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
- clear_bit(TW_IN_RESET, &tw_dev->flags);
- retval = TW_IOCTL_ERROR_OS_ERESTARTSYS;
- goto out3;
- }
-
/* We timed out, and didn't get an interrupt */
if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
/* Now we need to reset the board */
@@ -694,11 +703,6 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
tw_dev->host->host_no, TW_DRIVER, 0xc,
cmd);
retval = TW_IOCTL_ERROR_OS_EIO;
- spin_lock_irqsave(tw_dev->host->host_lock, flags);
- tw_dev->state[request_id] = TW_S_COMPLETED;
- twa_free_request_id(tw_dev, request_id);
- tw_dev->posted_request_count--;
- spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
twa_reset_device_extension(tw_dev, 1);
goto out3;
}
@@ -717,16 +721,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
tw_ioctl->driver_command.status = 0;
/* Copy compatiblity struct into ioctl data buffer */
tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
- strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
- tw_compat_info->working_srl = tw_dev->working_srl;
- tw_compat_info->working_branch = tw_dev->working_branch;
- tw_compat_info->working_build = tw_dev->working_build;
- tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL;
- tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
- tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD;
- tw_compat_info->driver_srl_low = TW_BASE_FW_SRL;
- tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH;
- tw_compat_info->driver_build_low = TW_BASE_FW_BUILD;
+ memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info));
break;
case TW_IOCTL_GET_LAST_EVENT:
if (tw_dev->event_queue_wrapped) {
@@ -895,7 +890,8 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
}
if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
+ if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags)))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
}
@@ -939,10 +935,12 @@ static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
unsigned long before;
int retval = 1;
- if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) {
+ if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) ||
+ (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) {
before = jiffies;
while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
+ msleep(1);
if (time_after(jiffies, before + HZ * 30))
goto out;
}
@@ -1192,7 +1190,7 @@ out:
} /* End twa_initialize_device_extension() */
/* This function is the interrupt service routine */
-static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t twa_interrupt(int irq, void *dev_instance)
{
int request_id, error = 0;
u32 status_reg_value;
@@ -1214,6 +1212,10 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *re
handled = 1;
+ /* If we are resetting, bail */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags))
+ goto twa_interrupt_bail;
+
/* Check controller for errors */
if (twa_check_bits(status_reg_value)) {
if (twa_decode_bits(tw_dev, status_reg_value)) {
@@ -1355,8 +1357,8 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
newcommand = &full_command_packet->command.newcommand;
- newcommand->request_id__lunl =
- TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
+ newcommand->request_id__lunl =
+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
newcommand->sg_list[0].length = cpu_to_le32(length);
newcommand->sgl_entries__lunh =
@@ -1531,6 +1533,13 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
int retval = 1;
command_que_value = tw_dev->command_packet_phys[request_id];
+
+ /* For 9650SE write low 4 bytes first */
+ if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ command_que_value += TW_COMMAND_OFFSET;
+ writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
+ }
+
status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
if (twa_check_bits(status_reg_value))
@@ -1557,13 +1566,17 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
goto out;
} else {
- /* We successfully posted the command packet */
- if (sizeof(dma_addr_t) > 4) {
- command_que_value += TW_COMMAND_OFFSET;
- writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
- writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+ if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ /* Now write upper 4 bytes */
+ writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
} else {
- writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+ if (sizeof(dma_addr_t) > 4) {
+ command_que_value += TW_COMMAND_OFFSET;
+ writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+ writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+ } else {
+ writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+ }
}
tw_dev->state[request_id] = TW_S_POSTED;
tw_dev->posted_request_count++;
@@ -1620,14 +1633,9 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_res
goto out;
TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+ clear_bit(TW_IN_RESET, &tw_dev->flags);
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
- /* Wake up any ioctl that was pending before the reset */
- if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
- clear_bit(TW_IN_RESET, &tw_dev->flags);
- } else {
- tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
- wake_up(&tw_dev->ioctl_wqueue);
- }
retval = 0;
out:
return retval;
@@ -1736,6 +1744,9 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
"WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
+ /* Make sure we are not issuing an ioctl or resetting from ioctl */
+ mutex_lock(&tw_dev->ioctl_lock);
+
/* Now reset the card and some of the device extension data */
if (twa_reset_device_extension(tw_dev, 0)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
@@ -1744,6 +1755,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
retval = SUCCESS;
out:
+ mutex_unlock(&tw_dev->ioctl_lock);
return retval;
} /* End twa_scsi_eh_reset() */
@@ -1753,8 +1765,14 @@ static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+ /* If we are resetting due to timed out ioctl, report as busy */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+ retval = SCSI_MLQUEUE_HOST_BUSY;
+ goto out;
+ }
+
/* Check if this FW supports luns */
- if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
+ if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
SCpnt->result = (DID_BAD_TARGET << 16);
done(SCpnt);
retval = 0;
@@ -1960,6 +1978,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev)
/* Disable interrupts */
TW_DISABLE_INTERRUPTS(tw_dev);
+ /* Free up the IRQ */
+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
/* Tell the card we are shutting down */
@@ -2091,21 +2112,25 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
/* Initialize the card */
if (twa_reset_sequence(tw_dev, 0))
- goto out_release_mem_region;
+ goto out_iounmap;
/* Set host specific parameters */
- host->max_id = TW_MAX_UNITS;
+ if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE)
+ host->max_id = TW_MAX_UNITS_9650SE;
+ else
+ host->max_id = TW_MAX_UNITS;
+
host->max_cmd_len = TW_MAX_CDB_LEN;
/* Channels aren't supported by adapter */
- host->max_lun = TW_MAX_LUNS(tw_dev->working_srl);
+ host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
host->max_channel = 0;
/* Register the card with the kernel SCSI layer */
retval = scsi_add_host(host, &pdev->dev);
if (retval) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
- goto out_release_mem_region;
+ goto out_iounmap;
}
pci_set_drvdata(pdev, host);
@@ -2145,6 +2170,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
out_remove_host:
scsi_remove_host(host);
+out_iounmap:
+ iounmap(tw_dev->base_addr);
out_release_mem_region:
pci_release_regions(pdev);
out_free_device_extension:
@@ -2170,12 +2197,12 @@ static void twa_remove(struct pci_dev *pdev)
twa_major = -1;
}
- /* Free up the IRQ */
- free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
-
/* Shutdown the card */
__twa_shutdown(tw_dev);
+ /* Free IO remapping */
+ iounmap(tw_dev->base_addr);
+
/* Free up the mem region */
pci_release_regions(pdev);
@@ -2193,6 +2220,8 @@ static struct pci_device_id twa_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
@@ -2211,7 +2240,7 @@ static int __init twa_init(void)
{
printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
- return pci_module_init(&twa_driver);
+ return pci_register_driver(&twa_driver);
} /* End twa_init() */
/* This function is called on driver exit */
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index e5685be96f4..7901517d451 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -289,7 +289,6 @@ static twa_message_type twa_error_table[] = {
#define TW_STATUS_VALID_INTERRUPT 0x00DF0000
/* PCI related defines */
-#define TW_NUMDEVICES 1
#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
#define TW_PCI_CLEAR_PCI_ABORT 0x2000
@@ -335,6 +334,7 @@ static twa_message_type twa_error_table[] = {
#define TW_ALIGNMENT_9000 4 /* 4 bytes */
#define TW_ALIGNMENT_9000_SGL 0x3
#define TW_MAX_UNITS 16
+#define TW_MAX_UNITS_9650SE 32
#define TW_INIT_MESSAGE_CREDITS 0x100
#define TW_INIT_COMMAND_PACKET_SIZE 0x3
#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6
@@ -354,7 +354,6 @@ static twa_message_type twa_error_table[] = {
#define TW_MAX_RESPONSE_DRAIN 256
#define TW_MAX_AEN_DRAIN 40
#define TW_IN_RESET 2
-#define TW_IN_CHRDEV_IOCTL 3
#define TW_IN_ATTENTION_LOOP 4
#define TW_MAX_SECTORS 256
#define TW_AEN_WAIT_TIME 1000
@@ -417,6 +416,9 @@ static twa_message_type twa_error_table[] = {
#ifndef PCI_DEVICE_ID_3WARE_9550SX
#define PCI_DEVICE_ID_3WARE_9550SX 0x1003
#endif
+#ifndef PCI_DEVICE_ID_3WARE_9650SE
+#define PCI_DEVICE_ID_3WARE_9650SE 0x1004
+#endif
/* Bitmask macros to eliminate bitfields */
@@ -442,6 +444,7 @@ static twa_message_type twa_error_table[] = {
#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
#define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
#define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
+#define TW_COMMAND_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x20)
#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
#define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30)
#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
@@ -626,6 +629,9 @@ typedef struct TAG_TW_Compatibility_Info
unsigned short driver_srl_low;
unsigned short driver_branch_low;
unsigned short driver_build_low;
+ unsigned short fw_on_ctlr_srl;
+ unsigned short fw_on_ctlr_branch;
+ unsigned short fw_on_ctlr_build;
} TW_Compatibility_Info;
#pragma pack()
@@ -668,9 +674,7 @@ typedef struct TAG_TW_Device_Extension {
wait_queue_head_t ioctl_wqueue;
struct mutex ioctl_lock;
char aen_clobber;
- unsigned short working_srl;
- unsigned short working_branch;
- unsigned short working_build;
+ TW_Compatibility_Info tw_compat_info;
} TW_Device_Extension;
#endif /* _3W_9XXX_H */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index f3a5f422a8e..99a259c5a0c 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2078,8 +2078,7 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
} /* End tw_scsi_queue() */
/* This function is the interrupt service routine */
-static irqreturn_t tw_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t tw_interrupt(int irq, void *dev_instance)
{
int request_id;
u32 status_reg_value;
@@ -2486,7 +2485,7 @@ static int __init tw_init(void)
{
printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
- return pci_module_init(&tw_driver);
+ return pci_register_driver(&tw_driver);
} /* End tw_init() */
/* This function is called on driver exit */
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 31fe5ea1592..bbd654a2b9b 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -74,7 +74,7 @@ static char *tw_aen_string[] = {
[0x00D] = "ERROR: Logical unit deleted: Unit #",
[0x00F] = "WARNING: SMART threshold exceeded: Port #",
[0x021] = "WARNING: ATA UDMA downgrade: Port #",
- [0x021] = "WARNING: ATA UDMA upgrade: Port #",
+ [0x022] = "WARNING: ATA UDMA upgrade: Port #",
[0x023] = "WARNING: Sector repair occurred: Port #",
[0x024] = "ERROR: SBUF integrity check failure",
[0x025] = "ERROR: Lost cached write: Port #",
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 657a3ab7539..68103e508db 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -313,7 +313,7 @@ NCR_700_detect(struct scsi_host_template *tpnt,
hostdata->status = memory + STATUS_OFFSET;
/* all of these offsets are L1_CACHE_BYTES separated. It is fatal
* if this isn't sufficient separation to avoid dma flushing issues */
- BUG_ON(!dma_is_consistent(pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());
+ BUG_ON(!dma_is_consistent(hostdata->dev, pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());
hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
hostdata->dev = dev;
@@ -362,11 +362,11 @@ NCR_700_detect(struct scsi_host_template *tpnt,
for (j = 0; j < PATCHES; j++)
script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
/* now patch up fixed addresses. */
- script_patch_32(script, MessageLocation,
+ script_patch_32(hostdata->dev, script, MessageLocation,
pScript + MSGOUT_OFFSET);
- script_patch_32(script, StatusAddress,
+ script_patch_32(hostdata->dev, script, StatusAddress,
pScript + STATUS_OFFSET);
- script_patch_32(script, ReceiveMsgAddress,
+ script_patch_32(hostdata->dev, script, ReceiveMsgAddress,
pScript + MSGIN_OFFSET);
hostdata->script = script;
@@ -622,8 +622,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
/* restore the old result if the request sense was
* successful */
- if(result == 0)
+ if (result == 0)
result = cmnd[7];
+ /* restore the original length */
+ SCp->cmd_len = cmnd[8];
} else
NCR_700_unmap(hostdata, SCp, slot);
@@ -819,8 +821,9 @@ process_extended_message(struct Scsi_Host *host,
shost_printk(KERN_WARNING, host,
"Unexpected SDTR msg\n");
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
- script_patch_16(hostdata->script, MessageCount, 1);
+ dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE);
+ script_patch_16(hostdata->dev, hostdata->script,
+ MessageCount, 1);
/* SendMsgOut returns, so set up the return
* address */
resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
@@ -831,8 +834,9 @@ process_extended_message(struct Scsi_Host *host,
printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
host->host_no, pun, lun);
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
- script_patch_16(hostdata->script, MessageCount, 1);
+ dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE);
+ script_patch_16(hostdata->dev, hostdata->script, MessageCount,
+ 1);
resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
break;
@@ -845,8 +849,9 @@ process_extended_message(struct Scsi_Host *host,
printk("\n");
/* just reject it */
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
- script_patch_16(hostdata->script, MessageCount, 1);
+ dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE);
+ script_patch_16(hostdata->dev, hostdata->script, MessageCount,
+ 1);
/* SendMsgOut returns, so set up the return
* address */
resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
@@ -927,8 +932,9 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata
printk("\n");
/* just reject it */
hostdata->msgout[0] = A_REJECT_MSG;
- dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
- script_patch_16(hostdata->script, MessageCount, 1);
+ dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE);
+ script_patch_16(hostdata->dev, hostdata->script, MessageCount,
+ 1);
/* SendMsgOut returns, so set up the return
* address */
resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
@@ -937,7 +943,7 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata
}
NCR_700_writel(temp, host, TEMP_REG);
/* set us up to receive another message */
- dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE, DMA_FROM_DEVICE);
+ dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, DMA_FROM_DEVICE);
return resume_offset;
}
@@ -1007,6 +1013,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
* of the command */
cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
cmnd[7] = hostdata->status[0];
+ cmnd[8] = SCp->cmd_len;
+ SCp->cmd_len = 6; /* command length for
+ * REQUEST_SENSE */
slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
@@ -1014,9 +1023,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
slot->SG[1].pAddr = 0;
slot->resume_offset = hostdata->pScript;
- dma_cache_sync(slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
- dma_cache_sync(SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
-
+ dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
+ dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+
/* queue the command for reissue */
slot->state = NCR_700_SLOT_QUEUED;
slot->flags = NCR_700_FLAG_AUTOSENSE;
@@ -1131,11 +1140,12 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
hostdata->cmd = slot->cmnd;
/* re-patch for this command */
- script_patch_32_abs(hostdata->script, CommandAddress,
- slot->pCmd);
- script_patch_16(hostdata->script,
+ script_patch_32_abs(hostdata->dev, hostdata->script,
+ CommandAddress, slot->pCmd);
+ script_patch_16(hostdata->dev, hostdata->script,
CommandCount, slot->cmnd->cmd_len);
- script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+ script_patch_32_abs(hostdata->dev, hostdata->script,
+ SGScriptStartAddress,
to32bit(&slot->pSG[0].ins));
/* Note: setting SXFER only works if we're
@@ -1145,13 +1155,13 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
* should therefore always clear ACK */
NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
host, SXFER_REG);
- dma_cache_sync(hostdata->msgin,
+ dma_cache_sync(hostdata->dev, hostdata->msgin,
MSG_ARRAY_SIZE, DMA_FROM_DEVICE);
- dma_cache_sync(hostdata->msgout,
+ dma_cache_sync(hostdata->dev, hostdata->msgout,
MSG_ARRAY_SIZE, DMA_TO_DEVICE);
/* I'm just being paranoid here, the command should
* already have been flushed from the cache */
- dma_cache_sync(slot->cmnd->cmnd,
+ dma_cache_sync(hostdata->dev, slot->cmnd->cmnd,
slot->cmnd->cmd_len, DMA_TO_DEVICE);
@@ -1215,7 +1225,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
hostdata->reselection_id = reselection_id;
/* just in case we have a stale simple tag message, clear it */
hostdata->msgin[1] = 0;
- dma_cache_sync(hostdata->msgin,
+ dma_cache_sync(hostdata->dev, hostdata->msgin,
MSG_ARRAY_SIZE, DMA_BIDIRECTIONAL);
if(hostdata->tag_negotiated & (1<<reselection_id)) {
resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
@@ -1331,7 +1341,7 @@ process_selection(struct Scsi_Host *host, __u32 dsp)
hostdata->cmd = NULL;
/* clear any stale simple tag message */
hostdata->msgin[1] = 0;
- dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE,
+ dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE,
DMA_BIDIRECTIONAL);
if(id == 0xff) {
@@ -1428,29 +1438,30 @@ NCR_700_start_command(struct scsi_cmnd *SCp)
NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
}
- script_patch_16(hostdata->script, MessageCount, count);
+ script_patch_16(hostdata->dev, hostdata->script, MessageCount, count);
- script_patch_ID(hostdata->script,
+ script_patch_ID(hostdata->dev, hostdata->script,
Device_ID, 1<<scmd_id(SCp));
- script_patch_32_abs(hostdata->script, CommandAddress,
+ script_patch_32_abs(hostdata->dev, hostdata->script, CommandAddress,
slot->pCmd);
- script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
+ script_patch_16(hostdata->dev, hostdata->script, CommandCount,
+ SCp->cmd_len);
/* finally plumb the beginning of the SG list into the script
* */
- script_patch_32_abs(hostdata->script, SGScriptStartAddress,
- to32bit(&slot->pSG[0].ins));
+ script_patch_32_abs(hostdata->dev, hostdata->script,
+ SGScriptStartAddress, to32bit(&slot->pSG[0].ins));
NCR_700_clear_fifo(SCp->device->host);
if(slot->resume_offset == 0)
slot->resume_offset = hostdata->pScript;
/* now perform all the writebacks and invalidates */
- dma_cache_sync(hostdata->msgout, count, DMA_TO_DEVICE);
- dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE,
+ dma_cache_sync(hostdata->dev, hostdata->msgout, count, DMA_TO_DEVICE);
+ dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE,
DMA_FROM_DEVICE);
- dma_cache_sync(SCp->cmnd, SCp->cmd_len, DMA_TO_DEVICE);
- dma_cache_sync(hostdata->status, 1, DMA_FROM_DEVICE);
+ dma_cache_sync(hostdata->dev, SCp->cmnd, SCp->cmd_len, DMA_TO_DEVICE);
+ dma_cache_sync(hostdata->dev, hostdata->status, 1, DMA_FROM_DEVICE);
/* set the synchronous period/offset */
NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
@@ -1462,7 +1473,7 @@ NCR_700_start_command(struct scsi_cmnd *SCp)
}
irqreturn_t
-NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
+NCR_700_intr(int irq, void *dev_id)
{
struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
struct NCR_700_Host_Parameters *hostdata =
@@ -1626,7 +1637,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
slot->SG[i].pAddr = 0;
}
- dma_cache_sync(slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
+ dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
/* and pretend we disconnected after
* the command phase */
resume_offset = hostdata->pScript + Ent_MsgInDuringData;
@@ -1892,9 +1903,9 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
}
slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
slot->SG[i].pAddr = 0;
- dma_cache_sync(slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
+ dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
DEBUG((" SETTING %08lx to %x\n",
- (&slot->pSG[i].ins),
+ (&slot->pSG[i].ins),
slot->SG[i].ins));
}
slot->resume_offset = 0;
@@ -1939,7 +1950,7 @@ NCR_700_abort(struct scsi_cmnd * SCp)
STATIC int
NCR_700_bus_reset(struct scsi_cmnd * SCp)
{
- DECLARE_COMPLETION(complete);
+ DECLARE_COMPLETION_ONSTACK(complete);
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 97ebe71b701..f38822db421 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -57,7 +57,7 @@ struct NCR_700_Host_Parameters;
struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
struct NCR_700_Host_Parameters *, struct device *);
int NCR_700_release(struct Scsi_Host *host);
-irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
+irqreturn_t NCR_700_intr(int, void *);
enum NCR_700_Host_State {
@@ -415,31 +415,31 @@ struct NCR_700_Host_Parameters {
#define NCR_710_MIN_XFERP 0
#define NCR_700_MIN_PERIOD 25 /* for SDTR message, 100ns */
-#define script_patch_32(script, symbol, value) \
+#define script_patch_32(dev, script, symbol, value) \
{ \
int i; \
for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
__u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \
(script)[A_##symbol##_used[i]] = bS_to_host(val); \
- dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
DEBUG((" script, patching %s at %d to 0x%lx\n", \
#symbol, A_##symbol##_used[i], (value))); \
} \
}
-#define script_patch_32_abs(script, symbol, value) \
+#define script_patch_32_abs(dev, script, symbol, value) \
{ \
int i; \
for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
(script)[A_##symbol##_used[i]] = bS_to_host(value); \
- dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
DEBUG((" script, patching %s at %d to 0x%lx\n", \
#symbol, A_##symbol##_used[i], (value))); \
} \
}
/* Used for patching the SCSI ID in the SELECT instruction */
-#define script_patch_ID(script, symbol, value) \
+#define script_patch_ID(dev, script, symbol, value) \
{ \
int i; \
for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
@@ -447,13 +447,13 @@ struct NCR_700_Host_Parameters {
val &= 0xff00ffff; \
val |= ((value) & 0xff) << 16; \
(script)[A_##symbol##_used[i]] = bS_to_host(val); \
- dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
DEBUG((" script, patching ID field %s at %d to 0x%x\n", \
#symbol, A_##symbol##_used[i], val)); \
} \
}
-#define script_patch_16(script, symbol, value) \
+#define script_patch_16(dev, script, symbol, value) \
{ \
int i; \
for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
@@ -461,7 +461,7 @@ struct NCR_700_Host_Parameters {
val &= 0xffff0000; \
val |= ((value) & 0xffff); \
(script)[A_##symbol##_used[i]] = bS_to_host(val); \
- dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+ dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
DEBUG((" script, patching short field %s at %d to 0x%x\n", \
#symbol, A_##symbol##_used[i], val)); \
} \
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index acf292736b4..640536ef77d 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -323,7 +323,7 @@ static int shutdown (struct Scsi_Host *host);
static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
static int disable (struct Scsi_Host *host);
static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id);
static void NCR53c7x0_intfly (struct Scsi_Host *host);
static int ncr_halt (struct Scsi_Host *host);
static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
@@ -4227,7 +4227,7 @@ restart:
}
/*
- * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id)
*
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
* the same IRQ line.
@@ -4241,7 +4241,7 @@ restart:
*/
static irqreturn_t
-NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+NCR53c7x0_intr (int irq, void *dev_id)
{
NCR53c7x0_local_declare();
struct Scsi_Host *host; /* Host we are looking at */
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 4ea49fd7965..3075204915c 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2186,21 +2186,21 @@ static int __init BusLogic_init(void)
if (BusLogic_ProbeOptions.NoProbe)
return -ENODEV;
- BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *)
- kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC);
+ BusLogic_ProbeInfoList =
+ kzalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_KERNEL);
if (BusLogic_ProbeInfoList == NULL) {
BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
return -ENOMEM;
}
- memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo));
- PrototypeHostAdapter = (struct BusLogic_HostAdapter *)
- kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC);
+
+ PrototypeHostAdapter =
+ kzalloc(sizeof(struct BusLogic_HostAdapter), GFP_KERNEL);
if (PrototypeHostAdapter == NULL) {
kfree(BusLogic_ProbeInfoList);
BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL);
return -ENOMEM;
}
- memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter));
+
#ifdef MODULE
if (BusLogic != NULL)
BusLogic_Setup(BusLogic);
@@ -2653,7 +2653,7 @@ static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapt
Adapters.
*/
-static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters)
+static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier)
{
struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier;
unsigned long ProcessorFlags;
@@ -3600,5 +3600,16 @@ static void __exit BusLogic_exit(void)
__setup("BusLogic=", BusLogic_Setup);
+static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
+
module_init(BusLogic_init);
module_exit(BusLogic_exit);
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 9792e5af525..cca6d45eee4 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -237,10 +237,7 @@ enum BusLogic_BIOS_DiskGeometryTranslation {
Define a Boolean data type.
*/
-typedef enum {
- false,
- true
-} PACKED boolean;
+typedef bool boolean;
/*
Define a 10^18 Statistics Byte Counter data type.
@@ -1350,7 +1347,7 @@ static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device
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 *, struct pt_regs *);
+static irqreturn_t BusLogic_InterruptHandler(int, void *);
static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset);
static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...);
static int __init BusLogic_Setup(char *);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index c4dfcc91ddd..60f58272718 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -3,11 +3,13 @@ menu "SCSI device support"
config RAID_ATTRS
tristate "RAID Transport Class"
default n
+ depends on BLOCK
---help---
Provides RAID
config SCSI
tristate "SCSI device support"
+ depends on BLOCK
---help---
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
any other SCSI device under Linux, say Y and make sure that you know
@@ -27,6 +29,13 @@ config SCSI
However, do not compile this as a module if your root file system
(the one containing the directory /) is located on a SCSI device.
+config SCSI_TGT
+ tristate "SCSI target support"
+ depends on SCSI && EXPERIMENTAL
+ ---help---
+ If you want to use SCSI target mode drivers enable this option.
+ If you choose M, the module will be called scsi_tgt.
+
config SCSI_NETLINK
bool
default n
@@ -38,10 +47,10 @@ config SCSI_PROC_FS
default y
---help---
This option enables support for the various files in
- /proc/scsi. In Linux 2.6 this has been superceeded by
+ /proc/scsi. In Linux 2.6 this has been superseded by
files in sysfs but many legacy applications rely on this.
- If unusure say Y.
+ If unsure say Y.
comment "SCSI support type (disk, tape, CD-ROM)"
depends on SCSI
@@ -83,7 +92,7 @@ config CHR_DEV_OSST
tristate "SCSI OnStream SC-x0 tape support"
depends on SCSI
---help---
- The OnStream SC-x0 SCSI tape drives can not be driven by the
+ The OnStream SC-x0 SCSI tape drives cannot be driven by the
standard st driver, but instead need this special osst driver and
use the /dev/osstX char device nodes (major 206). Via usb-storage
and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
@@ -214,6 +223,23 @@ config SCSI_LOGGING
there should be no noticeable performance impact as long as you have
logging turned off.
+config SCSI_SCAN_ASYNC
+ bool "Asynchronous SCSI scanning"
+ depends on SCSI
+ help
+ The SCSI subsystem can probe for devices while the rest of the
+ system continues booting, and even probe devices on different
+ busses in parallel, leading to a significant speed-up.
+ If you have built SCSI as modules, enabling this option can
+ be a problem as the devices may not have been found by the
+ time your system expects them to have been. You can load the
+ scsi_wait_scan module to ensure that all scans have completed.
+ If you build your SCSI drivers into the kernel, then everything
+ will work fine if you say Y here.
+
+ You can override this choice by specifying scsi_mod.scan="sync"
+ or "async" on the kernel's command line.
+
menu "SCSI Transports"
depends on SCSI
@@ -795,6 +821,20 @@ config SCSI_IBMVSCSI
To compile this driver as a module, choose M here: the
module will be called ibmvscsic.
+config SCSI_IBMVSCSIS
+ tristate "IBM Virtual SCSI Server support"
+ depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
+ help
+ This is the SRP target driver for IBM pSeries virtual environments.
+
+ The userspace component needed to initialize the driver and
+ documentation can be found:
+
+ http://stgt.berlios.de/
+
+ To compile this driver as a module, choose M here: the
+ module will be called ibmvstgt.
+
config SCSI_INITIO
tristate "Initio 9100U(W) support"
depends on PCI && SCSI
@@ -942,8 +982,13 @@ config SCSI_STEX
tristate "Promise SuperTrak EX Series support"
depends on PCI && SCSI
---help---
- This driver supports Promise SuperTrak EX8350/8300/16350/16300
- Storage controllers.
+ This driver supports Promise SuperTrak EX series storage controllers.
+
+ Promise provides Linux RAID configuration utility for these
+ controllers. Please visit <http://www.promise.com> to download.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stex.
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
@@ -1014,7 +1059,7 @@ config SCSI_SYM53C8XX_MMIO
config SCSI_IPR
tristate "IBM Power Linux RAID adapter support"
- depends on PCI && SCSI
+ depends on PCI && SCSI && ATA
select FW_LOADER
---help---
This driver supports the IBM Power Linux family RAID adapters.
@@ -1024,6 +1069,7 @@ config SCSI_IPR
config SCSI_IPR_TRACE
bool "enable driver internal trace"
depends on SCSI_IPR
+ default y
help
If you say Y here, the driver will trace all commands issued
to the adapter. Performance impact is minimal. Trace can be
@@ -1032,6 +1078,7 @@ config SCSI_IPR_TRACE
config SCSI_IPR_DUMP
bool "enable adapter dump support"
depends on SCSI_IPR
+ default y
help
If you say Y here, the driver will support adapter crash dump.
If you enable this support, the iprdump daemon can be used
@@ -1244,6 +1291,7 @@ config SCSI_QLOGICPTI
module will be called qlogicpti.
source "drivers/scsi/qla2xxx/Kconfig"
+source "drivers/scsi/qla4xxx/Kconfig"
config SCSI_LPFC
tristate "Emulex LightPulse Fibre Channel Support"
@@ -1260,8 +1308,8 @@ config SCSI_SEAGATE
These are 8-bit SCSI controllers; the ST-01 is also supported by
this driver. It is explained in section 3.9 of the SCSI-HOWTO,
available from <http://www.tldp.org/docs.html#howto>. If it
- doesn't work out of the box, you may have to change some settings in
- <file:drivers/scsi/seagate.h>.
+ doesn't work out of the box, you may have to change some macros at
+ compiletime, which are described in <file:drivers/scsi/seagate.c>.
To compile this driver as a module, choose M here: the
module will be called seagate.
@@ -1689,7 +1737,7 @@ config SCSI_NCR53C7xx_FAST
config SUN3_SCSI
tristate "Sun3 NCR5380 SCSI"
- depends on SUN3 && SCSI && BROKEN
+ depends on SUN3 && SCSI
select SCSI_SPI_ATTRS
help
This option will enable support for the OBIO (onboard io) NCR5380
@@ -1731,6 +1779,16 @@ config ZFCP
called zfcp. If you want to compile it as a module, say M here
and read <file:Documentation/modules.txt>.
+config SCSI_SRP
+ tristate "SCSI RDMA Protocol helper library"
+ depends on SCSI && PCI
+ select SCSI_TGT
+ help
+ If you wish to use SRP target drivers, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called libsrp.
+
endmenu
source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1ef951be7a5..bd7c9888f7f 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -21,6 +21,7 @@ CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
subdir-$(CONFIG_PCMCIA) += pcmcia
obj-$(CONFIG_SCSI) += scsi_mod.o
+obj-$(CONFIG_SCSI_TGT) += scsi_tgt.o
obj-$(CONFIG_RAID_ATTRS) += raid_class.o
@@ -84,6 +85,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
@@ -124,7 +126,9 @@ obj-$(CONFIG_SCSI_FCAL) += fcal.o
obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_IPR) += ipr.o
+obj-$(CONFIG_SCSI_SRP) += libsrp.o
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
@@ -140,6 +144,8 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
+obj-$(CONFIG_SCSI) += scsi_wait_scan.o
+
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
scsi_scan.o scsi_sysfs.o \
@@ -148,6 +154,8 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
+scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
+
sd_mod-objs := sd.o
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 616810ad17d..bb3cb336054 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -558,8 +558,7 @@ static int probe_irq __initdata = 0;
* used by the IRQ probe code.
*/
-static irqreturn_t __init probe_intr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t __init probe_intr(int irq, void *dev_id)
{
probe_irq = irq;
return IRQ_HANDLED;
@@ -850,7 +849,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
hostdata->issue_queue = NULL;
hostdata->disconnected_queue = NULL;
- INIT_WORK(&hostdata->coroutine, NCR5380_main, hostdata);
+ INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
#ifdef NCR5380_STATS
for (i = 0; i < 8; ++i) {
@@ -1017,7 +1016,7 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* Run the coroutine if it isn't already running. */
/* Kick off command processing */
- schedule_work(&hostdata->coroutine);
+ schedule_delayed_work(&hostdata->coroutine, 0);
return 0;
}
@@ -1034,9 +1033,10 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
* host lock and called routines may take the isa dma lock.
*/
-static void NCR5380_main(void *p)
+static void NCR5380_main(struct work_struct *work)
{
- struct NCR5380_hostdata *hostdata = p;
+ struct NCR5380_hostdata *hostdata =
+ container_of(work, struct NCR5380_hostdata, coroutine.work);
struct Scsi_Host *instance = hostdata->host;
Scsi_Cmnd *tmp, *prev;
int done;
@@ -1148,7 +1148,6 @@ static void NCR5380_main(void *p)
* NCR5380_intr - generic NCR5380 irq handler
* @irq: interrupt number
* @dev_id: device info
- * @regs: registers (unused)
*
* Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
* from the disconnected queue, and restarting NCR5380_main()
@@ -1157,7 +1156,7 @@ static void NCR5380_main(void *p)
* Locks: takes the needed instance locks
*/
-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
NCR5380_local_declare();
struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
@@ -1223,7 +1222,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs)
} /* if BASR_IRQ */
spin_unlock_irqrestore(instance->host_lock, flags);
if(!done)
- schedule_work(&hostdata->coroutine);
+ schedule_delayed_work(&hostdata->coroutine, 0);
} while (!done);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index c3462e358d1..713a108c02e 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -271,7 +271,7 @@ struct NCR5380_hostdata {
unsigned long time_expires; /* in jiffies, set prior to sleeping */
int select_time; /* timer in select for target response */
volatile Scsi_Cmnd *selecting;
- struct work_struct coroutine; /* our co-routine */
+ struct delayed_work coroutine; /* our co-routine */
#ifdef NCR5380_STATS
unsigned timebase; /* Base for time calcs */
long time_read[8]; /* time to do reads */
@@ -296,9 +296,9 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags);
static void NCR5380_exit(struct Scsi_Host *instance);
static void NCR5380_information_transfer(struct Scsi_Host *instance);
#ifndef DONT_USE_INTR
-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t NCR5380_intr(int irq, void *dev_id);
#endif
-static void NCR5380_main(void *ptr);
+static void NCR5380_main(struct work_struct *work);
static void NCR5380_print_options(struct Scsi_Host *instance);
#ifdef NDEBUG
static void NCR5380_print_phase(struct Scsi_Host *instance);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index bdc6bb262bc..3c912ee29da 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -96,7 +96,7 @@ enum {
static struct NCR_ESP *espchain;
int nesps = 0, esps_in_use = 0, esps_running = 0;
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+irqreturn_t esp_intr(int irq, void *dev_id);
/* Debugging routines */
static struct esp_cmdstrings {
@@ -3533,7 +3533,7 @@ state_machine:
}
#ifndef CONFIG_SMP
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp;
unsigned long flags;
@@ -3570,7 +3570,7 @@ repeat:
}
#else
/* For SMP we only service one ESP on the list list at our IRQ level! */
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp;
unsigned long flags;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 481653c977c..521e3f842cf 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -656,7 +656,7 @@ extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
-extern irqreturn_t esp_intr(int, void *, struct pt_regs *);
+extern irqreturn_t esp_intr(int, void *);
extern const char *esp_info(struct Scsi_Host *);
extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
extern int esp_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 8472c535902..8578555d58f 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -168,8 +168,8 @@ enum Phase {
};
/* Static function prototypes */
-static void NCR53c406a_intr(int, void *, struct pt_regs *);
-static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *);
+static void NCR53c406a_intr(void *);
+static irqreturn_t do_NCR53c406a_intr(int, void *);
static void chip_init(void);
static void calc_port_addr(void);
#ifndef IRQ_LEV
@@ -220,9 +220,11 @@ static void *addresses[] = {
static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
#define PORT_COUNT ARRAY_SIZE(ports)
+#ifndef MODULE
/* possible interrupt channels */
static unsigned short intrs[] = { 10, 11, 12, 15 };
#define INTR_COUNT ARRAY_SIZE(intrs)
+#endif /* !MODULE */
/* signatures for NCR 53c406a based controllers */
#if USE_BIOS
@@ -605,6 +607,7 @@ static int NCR53c406a_release(struct Scsi_Host *shost)
return 0;
}
+#ifndef MODULE
/* called from init/main.c */
static int __init NCR53c406a_setup(char *str)
{
@@ -661,6 +664,8 @@ static int __init NCR53c406a_setup(char *str)
__setup("ncr53c406a=", NCR53c406a_setup);
+#endif /* !MODULE */
+
static const char *NCR53c406a_info(struct Scsi_Host *SChost)
{
DEB(printk("NCR53c406a_info called\n"));
@@ -685,7 +690,7 @@ static void wait_intr(void)
return;
}
- NCR53c406a_intr(0, NULL, NULL);
+ NCR53c406a_intr(NULL);
}
#endif
@@ -761,19 +766,18 @@ static int NCR53c406a_biosparm(struct scsi_device *disk,
return 0;
}
-static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- NCR53c406a_intr(0, dev_id, regs);
+ NCR53c406a_intr(dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs)
+static void NCR53c406a_intr(void *dev_id)
{
DEB(unsigned char fifo_size;
)
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index d05681f9d81..9859cd17fc5 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -226,14 +226,14 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
}
static int
-NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
+NCR_D700_intr(int irq, void *data)
{
struct NCR_D700_private *p = (struct NCR_D700_private *)data;
int i, found = 0;
for (i = 0; i < 2; i++)
if (p->hosts[i] &&
- NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED)
+ NCR_700_intr(irq, p->hosts[i]) == IRQ_HANDLED)
found++;
return found ? IRQ_HANDLED : IRQ_NONE;
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index c39ffbb86e3..778844c3544 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -54,7 +54,7 @@ static struct scsi_host_template NCR_Q720_tpnt = {
};
static irqreturn_t
-NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
+NCR_Q720_intr(int irq, void *data)
{
struct NCR_Q720_private *p = (struct NCR_Q720_private *)data;
__u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4;
@@ -68,7 +68,7 @@ NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
while((siop = ffz(sir)) < p->siops) {
sir |= 1<<siop;
- ncr53c8xx_intr(irq, p->hosts[siop], regs);
+ ncr53c8xx_intr(irq, p->hosts[siop]);
}
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index d7e9fab54c6..2650a5d0a16 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1013,7 +1013,7 @@ static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
/*
* Interrupt handler (main routine of the driver)
*/
-static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
+static irqreturn_t inia100_intr(int irqno, void *devid)
{
struct Scsi_Host *host = (struct Scsi_Host *)devid;
ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
@@ -1187,7 +1187,7 @@ static struct pci_driver inia100_pci_driver = {
static int __init inia100_init(void)
{
- return pci_module_init(&inia100_pci_driver);
+ return pci_register_driver(&inia100_pci_driver);
}
static void __exit inia100_exit(void)
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 08540692860..f77016d31ca 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -24,7 +24,7 @@
#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
-static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
+static irqreturn_t a2091_intr (int irq, void *_instance)
{
unsigned long flags;
unsigned int status;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 7bf46d40b56..1299bc8edef 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -26,7 +26,7 @@
static struct Scsi_Host *a3000_host = NULL;
-static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t a3000_intr (int irq, void *dummy)
{
unsigned long flags;
unsigned int status = DMA(a3000_host)->ISTR;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index eb3ed91bac7..4f8b4c53d43 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -11,8 +11,8 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2409
-# define AAC_DRIVER_BRANCH "-mh2"
+# define AAC_DRIVER_BUILD 2423
+# define AAC_DRIVER_BRANCH "-mh3"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 19e42ac07cb..4893a6d06a3 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -518,6 +518,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
*/
unsigned long count = 36000000L; /* 3 minutes */
while (down_trylock(&fibptr->event_wait)) {
+ int blink;
if (--count == 0) {
spin_lock_irqsave(q->lock, qflags);
q->numpending--;
@@ -530,6 +531,14 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
return -ETIMEDOUT;
}
+ if ((blink = aac_adapter_check_health(dev)) > 0) {
+ if (wait == -1) {
+ printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n"
+ "Usually a result of a serious unrecoverable hardware problem\n",
+ blink);
+ }
+ return -EFAULT;
+ }
udelay(5);
}
} else if (down_interruptible(&fibptr->event_wait)) {
@@ -1093,6 +1102,20 @@ static int _aac_reset_adapter(struct aac_dev *aac)
goto out;
}
+ /*
+ * Loop through the fibs, close the synchronous FIBS
+ */
+ for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+ struct fib *fib = &aac->fibs[index];
+ if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+ (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) {
+ unsigned long flagv;
+ spin_lock_irqsave(&fib->event_lock, flagv);
+ up(&fib->event_wait);
+ spin_unlock_irqrestore(&fib->event_lock, flagv);
+ schedule();
+ }
+ }
index = aac->cardtype;
/*
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index a1d214d770e..dcc8b0ea7a9 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -46,11 +46,11 @@
#include "aacraid.h"
-static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t aac_rx_intr(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
- dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs));
+ dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id));
if (dev->new_comm_interface) {
u32 Index = rx_readl(dev, MUnit.OutboundQueue);
if (Index == 0xFFFFFFFFL)
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index f906ead239d..511b0a938fb 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -46,7 +46,7 @@
#include "aacraid.h"
-static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t aac_sa_intr(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
unsigned short intstat, mask;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 773f02e3b10..2b344356a29 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -3881,7 +3881,7 @@ typedef struct asc_board {
/*
* The following fields are used only for Wide Boards.
*/
- void *ioremap_addr; /* I/O Memory remap address. */
+ void __iomem *ioremap_addr; /* I/O Memory remap address. */
ushort ioport; /* I/O Port address. */
ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
adv_req_t *orig_reqp; /* adv_req_t memory block. */
@@ -3951,7 +3951,7 @@ typedef struct _PCI_CONFIG_SPACE_
/* Number of boards detected in system. */
STATIC int asc_board_count = 0;
-STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
+STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
/* Overrun buffer used by all narrow boards. */
STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
@@ -3999,7 +3999,7 @@ STATIC PortAddr _asc_def_iop_base[];
* advansys.h contains function prototypes for functions global to Linux.
*/
-STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *);
+STATIC irqreturn_t advansys_interrupt(int, void *);
STATIC int advansys_slave_configure(struct scsi_device *);
STATIC void asc_scsi_done_list(struct scsi_cmnd *);
STATIC int asc_execute_scsi_cmnd(struct scsi_cmnd *);
@@ -5997,7 +5997,7 @@ static struct scsi_host_template driver_template = {
* an AdvanSys adapter.
*/
STATIC irqreturn_t
-advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+advansys_interrupt(int irq, void *dev_id)
{
ulong flags;
int i;
@@ -6621,7 +6621,7 @@ adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
dma_map_single(dev, scp->request_buffer,
scp->request_bufflen, scp->sc_data_direction);
} else {
- scsiqp->vdata_addr = 0;
+ scsiqp->vdata_addr = NULL;
scp->SCp.dma_handle = 0;
}
scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index fb6a476eb87..0cec742d12e 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -238,7 +238,7 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/blkdev.h>
#include <asm/system.h>
#include <linux/errno.h>
@@ -673,7 +673,7 @@ static struct {
};
/* setup & interrupt */
-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
+static irqreturn_t intr(int irq, void *dev_id);
static void reset_ports(struct Scsi_Host *shpnt);
static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
static void done(struct Scsi_Host *shpnt, int error);
@@ -757,14 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
return ptr;
}
-static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swintr(int irqno, void *dev_id)
{
- struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
-
- if (!shpnt) {
- printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
- return IRQ_NONE;
- }
+ struct Scsi_Host *shpnt = dev_id;
HOSTDATA(shpnt)->swint++;
@@ -1448,7 +1443,7 @@ static struct work_struct aha152x_tq;
* Run service completions on the card with interrupts enabled.
*
*/
-static void run(void)
+static void run(struct work_struct *work)
{
struct aha152x_hostdata *hd;
@@ -1463,7 +1458,7 @@ static void run(void)
* Interrupt handler
*
*/
-static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t intr(int irqno, void *dev_id)
{
struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
unsigned long flags;
@@ -1504,7 +1499,7 @@ static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
HOSTDATA(shpnt)->service=1;
/* Poke the BH handler */
- INIT_WORK(&aha152x_tq, (void *) run, NULL);
+ INIT_WORK(&aha152x_tq, run);
schedule_work(&aha152x_tq);
}
DO_UNLOCK(flags);
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 24f0f546179..d7a61a6bdaa 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -174,9 +174,8 @@ static DEFINE_SPINLOCK(aha1542_lock);
static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
static int aha1542_restart(struct Scsi_Host *shost);
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs);
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id);
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id);
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
@@ -416,8 +415,7 @@ fail:
}
/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *shost;
@@ -427,13 +425,13 @@ static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
panic("Splunge!");
spin_lock_irqsave(shost->host_lock, flags);
- aha1542_intr_handle(shost, dev_id, regs);
+ aha1542_intr_handle(shost, dev_id);
spin_unlock_irqrestore(shost->host_lock, flags);
return IRQ_HANDLED;
}
/* A "high" level interrupt handler */
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
{
void (*my_done) (Scsi_Cmnd *) = NULL;
int errstatus, mbi, mbo, mbistatus;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 0e4a7ebe300..d7af9c63a04 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -223,8 +223,7 @@ static int aha1740_test_port(unsigned int base)
}
/* A "high" level interrupt handler */
-static irqreturn_t aha1740_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
{
struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
void (*my_done)(Scsi_Cmnd *);
@@ -587,7 +586,7 @@ static struct scsi_host_template aha1740_template = {
static int aha1740_probe (struct device *dev)
{
- int slotbase;
+ int slotbase, rc;
unsigned int irq_level, irq_type, translation;
struct Scsi_Host *shpnt;
struct aha1740_hostdata *host;
@@ -642,10 +641,16 @@ static int aha1740_probe (struct device *dev)
}
eisa_set_drvdata (edev, shpnt);
- scsi_add_host (shpnt, dev); /* XXX handle failure */
+
+ rc = scsi_add_host (shpnt, dev);
+ if (rc)
+ goto err_irq;
+
scsi_scan_host (shpnt);
return 0;
+ err_irq:
+ free_irq(irq_level, shpnt);
err_unmap:
dma_unmap_single (&edev->dev, host->ecb_dma_addr,
sizeof (host->ecb), DMA_BIDIRECTIONAL);
@@ -681,6 +686,7 @@ static struct eisa_device_id aha1740_ids[] = {
{ "ADP0400" }, /* 1744 */
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, aha1740_ids);
static struct eisa_driver aha1740_driver = {
.id_table = aha1740_ids,
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 7955ebe8e1e..911ea1756e5 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -22,12 +22,12 @@ config AIC79XX_CMDS_PER_DEVICE
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
- and display a console message inidicating this value.
+ and display a console message indicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
- the default is set to 32. Higher values may result in higer performance
+ the default is set to 32. Higher values may result in higher performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 5517da5855f..cd93f9a8611 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -27,12 +27,12 @@ config AIC7XXX_CMDS_PER_DEVICE
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
- and display a console message inidicating this value.
+ and display a console message indicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
- the default is set to 32. Higher values may result in higer performance
+ the default is set to 32. Higher values may result in higher performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index 867cbe23579..1ac119733ba 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids[] = {
{ "ADP7770", 5 }, /* AIC7770 generic */
{ "" }
};
-
+MODULE_DEVICE_TABLE(eisa, aic7770_ids);
+
static struct eisa_driver aic7770_driver = {
.id_table = aic7770_ids,
.driver = {
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index df3346b5caf..170a4344cbb 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -53,14 +53,6 @@ struct ahd_platform_data;
struct scb_platform_data;
/****************************** Useful Macros *********************************/
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
#ifndef TRUE
#define TRUE 1
#endif
@@ -972,8 +964,6 @@ int ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
int ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
u_int start_addr, u_int count);
-int ahd_wait_seeprom(struct ahd_softc *ahd);
-int ahd_verify_vpd_cksum(struct vpd_config *vpd);
int ahd_verify_cksum(struct seeprom_config *sc);
int ahd_acquire_seeprom(struct ahd_softc *ahd);
void ahd_release_seeprom(struct ahd_softc *ahd);
@@ -1320,8 +1310,6 @@ struct ahd_pci_identity {
char *name;
ahd_device_setup_t *setup;
};
-extern struct ahd_pci_identity ahd_pci_ident_table [];
-extern const u_int ahd_num_pci_devs;
/***************************** VL/EISA Declarations ***************************/
struct aic7770_identity {
@@ -1339,15 +1327,6 @@ extern const int ahd_num_aic7770_devs;
/*************************** Function Declarations ****************************/
/******************************************************************************/
void ahd_reset_cmds_pending(struct ahd_softc *ahd);
-u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
-void ahd_busy_tcl(struct ahd_softc *ahd,
- u_int tcl, u_int busyid);
-static __inline void ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl);
-static __inline void
-ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
-{
- ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
-}
/***************************** PCI Front End *********************************/
struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
@@ -1356,7 +1335,6 @@ int ahd_pci_config(struct ahd_softc *,
int ahd_pci_test_register_access(struct ahd_softc *);
/************************** SCB and SCB queue management **********************/
-int ahd_probe_scbs(struct ahd_softc *);
void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
struct scb *scb);
int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
@@ -1374,33 +1352,20 @@ int ahd_parse_vpddata(struct ahd_softc *ahd,
int ahd_parse_cfgdata(struct ahd_softc *ahd,
struct seeprom_config *sc);
void ahd_intr_enable(struct ahd_softc *ahd, int enable);
-void ahd_update_coalescing_values(struct ahd_softc *ahd,
- u_int timer,
- u_int maxcmds,
- u_int mincmds);
-void ahd_enable_coalescing(struct ahd_softc *ahd,
- int enable);
void ahd_pause_and_flushwork(struct ahd_softc *ahd);
int ahd_suspend(struct ahd_softc *ahd);
-int ahd_resume(struct ahd_softc *ahd);
void ahd_set_unit(struct ahd_softc *, int);
void ahd_set_name(struct ahd_softc *, char *);
struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
-void ahd_alloc_scbs(struct ahd_softc *ahd);
void ahd_free(struct ahd_softc *ahd);
int ahd_reset(struct ahd_softc *ahd, int reinit);
-void ahd_shutdown(void *arg);
int ahd_write_flexport(struct ahd_softc *ahd,
u_int addr, u_int value);
int ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
uint8_t *value);
-int ahd_wait_flexport(struct ahd_softc *ahd);
/*************************** Interrupt Services *******************************/
-void ahd_pci_intr(struct ahd_softc *ahd);
-void ahd_clear_intstat(struct ahd_softc *ahd);
-void ahd_flush_qoutfifo(struct ahd_softc *ahd);
void ahd_run_qoutfifo(struct ahd_softc *ahd);
#ifdef AHD_TARGET_MODE
void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
@@ -1409,7 +1374,6 @@ void ahd_handle_hwerrint(struct ahd_softc *ahd);
void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
void ahd_handle_scsiint(struct ahd_softc *ahd,
u_int intstat);
-void ahd_clear_critical_section(struct ahd_softc *ahd);
/***************************** Error Recovery *********************************/
typedef enum {
@@ -1426,23 +1390,9 @@ int ahd_search_disc_list(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
int stop_on_first, int remove,
int save_state);
-void ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
int ahd_reset_channel(struct ahd_softc *ahd, char channel,
int initiate_reset);
-int ahd_abort_scbs(struct ahd_softc *ahd, int target,
- char channel, int lun, u_int tag,
- role_t role, uint32_t status);
-void ahd_restart(struct ahd_softc *ahd);
-void ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo);
-void ahd_handle_scb_status(struct ahd_softc *ahd,
- struct scb *scb);
-void ahd_handle_scsi_status(struct ahd_softc *ahd,
- struct scb *scb);
-void ahd_calc_residual(struct ahd_softc *ahd,
- struct scb *scb);
/*************************** Utility Functions ********************************/
-struct ahd_phase_table_entry*
- ahd_lookup_phase_entry(int phase);
void ahd_compile_devinfo(struct ahd_devinfo *devinfo,
u_int our_id, u_int target,
u_int lun, char channel,
@@ -1450,14 +1400,6 @@ void ahd_compile_devinfo(struct ahd_devinfo *devinfo,
/************************** Transfer Negotiation ******************************/
void ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
u_int *ppr_options, u_int maxsync);
-void ahd_validate_offset(struct ahd_softc *ahd,
- struct ahd_initiator_tinfo *tinfo,
- u_int period, u_int *offset,
- int wide, role_t role);
-void ahd_validate_width(struct ahd_softc *ahd,
- struct ahd_initiator_tinfo *tinfo,
- u_int *bus_width,
- role_t role);
/*
* Negotiation types. These are used to qualify if we should renegotiate
* even if our goal and current transport parameters are identical.
@@ -1486,11 +1428,6 @@ typedef enum {
AHD_QUEUE_TAGGED
} ahd_queue_alg;
-void ahd_set_tags(struct ahd_softc *ahd,
- struct scsi_cmnd *cmd,
- struct ahd_devinfo *devinfo,
- ahd_queue_alg alg);
-
/**************************** Target Mode *************************************/
#ifdef AHD_TARGET_MODE
void ahd_send_lstate_events(struct ahd_softc *,
@@ -1528,10 +1465,8 @@ extern uint32_t ahd_debug;
#define AHD_SHOW_INT_COALESCING 0x10000
#define AHD_DEBUG_SEQUENCER 0x20000
#endif
-void ahd_print_scb(struct scb *scb);
void ahd_print_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
-void ahd_dump_sglist(struct scb *scb);
void ahd_dump_card_state(struct ahd_softc *ahd);
int ahd_print_register(ahd_reg_parse_entry_t *table,
u_int num_entries,
@@ -1540,5 +1475,4 @@ int ahd_print_register(ahd_reg_parse_entry_t *table,
u_int value,
u_int *cur_column,
u_int wrap_point);
-void ahd_dump_scbs(struct ahd_softc *ahd);
#endif /* _AIC79XX_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 653818d2f80..07a86a30f67 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -52,7 +52,7 @@
/***************************** Lookup Tables **********************************/
-char *ahd_chip_names[] =
+static char *ahd_chip_names[] =
{
"NONE",
"aic7901",
@@ -237,10 +237,33 @@ static int ahd_handle_target_cmd(struct ahd_softc *ahd,
struct target_cmd *cmd);
#endif
+static int ahd_abort_scbs(struct ahd_softc *ahd, int target,
+ char channel, int lun, u_int tag,
+ role_t role, uint32_t status);
+static void ahd_alloc_scbs(struct ahd_softc *ahd);
+static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl,
+ u_int scbid);
+static void ahd_calc_residual(struct ahd_softc *ahd,
+ struct scb *scb);
+static void ahd_clear_critical_section(struct ahd_softc *ahd);
+static void ahd_clear_intstat(struct ahd_softc *ahd);
+static void ahd_enable_coalescing(struct ahd_softc *ahd,
+ int enable);
+static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
+static void ahd_freeze_devq(struct ahd_softc *ahd,
+ struct scb *scb);
+static void ahd_handle_scb_status(struct ahd_softc *ahd,
+ struct scb *scb);
+static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
+static void ahd_shutdown(void *arg);
+static void ahd_update_coalescing_values(struct ahd_softc *ahd,
+ u_int timer,
+ u_int maxcmds,
+ u_int mincmds);
+static int ahd_verify_vpd_cksum(struct vpd_config *vpd);
+static int ahd_wait_seeprom(struct ahd_softc *ahd);
+
/******************************** Private Inlines *****************************/
-static __inline void ahd_assert_atn(struct ahd_softc *ahd);
-static __inline int ahd_currently_packetized(struct ahd_softc *ahd);
-static __inline int ahd_set_active_fifo(struct ahd_softc *ahd);
static __inline void
ahd_assert_atn(struct ahd_softc *ahd)
@@ -294,11 +317,44 @@ ahd_set_active_fifo(struct ahd_softc *ahd)
}
}
+static __inline void
+ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
+{
+ ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
+}
+
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static __inline void
+ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
+{
+ uint32_t sgptr;
+
+ sgptr = ahd_le32toh(scb->hscb->sgptr);
+ if ((sgptr & SG_STATUS_VALID) != 0)
+ ahd_calc_residual(ahd, scb);
+}
+
+static __inline void
+ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ uint32_t sgptr;
+
+ sgptr = ahd_le32toh(scb->hscb->sgptr);
+ if ((sgptr & SG_STATUS_VALID) != 0)
+ ahd_handle_scb_status(ahd, scb);
+ else
+ ahd_done(ahd, scb);
+}
+
+
/************************* Sequencer Execution Control ************************/
/*
* Restart the sequencer program from address zero
*/
-void
+static void
ahd_restart(struct ahd_softc *ahd)
{
@@ -342,7 +398,7 @@ ahd_restart(struct ahd_softc *ahd)
ahd_unpause(ahd);
}
-void
+static void
ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
{
ahd_mode_state saved_modes;
@@ -366,7 +422,7 @@ ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
* Flush and completed commands that are sitting in the command
* complete queues down on the chip but have yet to be dma'ed back up.
*/
-void
+static void
ahd_flush_qoutfifo(struct ahd_softc *ahd)
{
struct scb *scb;
@@ -905,6 +961,51 @@ ahd_handle_hwerrint(struct ahd_softc *ahd)
ahd_free(ahd);
}
+#ifdef AHD_DEBUG
+static void
+ahd_dump_sglist(struct scb *scb)
+{
+ int i;
+
+ if (scb->sg_count > 0) {
+ if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
+ struct ahd_dma64_seg *sg_list;
+
+ sg_list = (struct ahd_dma64_seg*)scb->sg_list;
+ for (i = 0; i < scb->sg_count; i++) {
+ uint64_t addr;
+ uint32_t len;
+
+ addr = ahd_le64toh(sg_list[i].addr);
+ len = ahd_le32toh(sg_list[i].len);
+ printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+ i,
+ (uint32_t)((addr >> 32) & 0xFFFFFFFF),
+ (uint32_t)(addr & 0xFFFFFFFF),
+ sg_list[i].len & AHD_SG_LEN_MASK,
+ (sg_list[i].len & AHD_DMA_LAST_SEG)
+ ? " Last" : "");
+ }
+ } else {
+ struct ahd_dma_seg *sg_list;
+
+ sg_list = (struct ahd_dma_seg*)scb->sg_list;
+ for (i = 0; i < scb->sg_count; i++) {
+ uint32_t len;
+
+ len = ahd_le32toh(sg_list[i].len);
+ printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+ i,
+ (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
+ ahd_le32toh(sg_list[i].addr),
+ len & AHD_SG_LEN_MASK,
+ len & AHD_DMA_LAST_SEG ? " Last" : "");
+ }
+ }
+ }
+}
+#endif /* AHD_DEBUG */
+
void
ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
{
@@ -1053,10 +1154,12 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
* If a target takes us into the command phase
* assume that it has been externally reset and
* has thus lost our previous packetized negotiation
- * agreement.
- * Revert to async/narrow transfers until we
- * can renegotiate with the device and notify
- * the OSM about the reset.
+ * agreement. Since we have not sent an identify
+ * message and may not have fully qualified the
+ * connection, we change our command to TUR, assert
+ * ATN and ABORT the task when we go to message in
+ * phase. The OSM will see the REQUEUE_REQUEST
+ * status and retry the command.
*/
scbid = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbid);
@@ -1083,7 +1186,28 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_set_syncrate(ahd, &devinfo, /*period*/0,
/*offset*/0, /*ppr_options*/0,
AHD_TRANS_ACTIVE, /*paused*/TRUE);
- scb->flags |= SCB_EXTERNAL_RESET;
+ /* Hand-craft TUR command */
+ ahd_outb(ahd, SCB_CDB_STORE, 0);
+ ahd_outb(ahd, SCB_CDB_STORE+1, 0);
+ ahd_outb(ahd, SCB_CDB_STORE+2, 0);
+ ahd_outb(ahd, SCB_CDB_STORE+3, 0);
+ ahd_outb(ahd, SCB_CDB_STORE+4, 0);
+ ahd_outb(ahd, SCB_CDB_STORE+5, 0);
+ ahd_outb(ahd, SCB_CDB_LEN, 6);
+ scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE);
+ scb->hscb->control |= MK_MESSAGE;
+ ahd_outb(ahd, SCB_CONTROL, scb->hscb->control);
+ ahd_outb(ahd, MSG_OUT, HOST_MSG);
+ ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid);
+ /*
+ * The lun is 0, regardless of the SCB's lun
+ * as we have not sent an identify message.
+ */
+ ahd_outb(ahd, SAVED_LUN, 0);
+ ahd_outb(ahd, SEQ_FLAGS, 0);
+ ahd_assert_atn(ahd);
+ scb->flags &= ~SCB_PACKETIZED;
+ scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET;
ahd_freeze_devq(ahd, scb);
ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
ahd_freeze_scb(scb);
@@ -1519,8 +1643,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
/*
* Ignore external resets after a bus reset.
*/
- if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE))
+ if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) {
+ ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
return;
+ }
/*
* Clear bus reset flag
@@ -2200,6 +2326,22 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
if (sent_msg == MSG_ABORT_TAG)
tag = SCB_GET_TAG(scb);
+ if ((scb->flags & SCB_EXTERNAL_RESET) != 0) {
+ /*
+ * This abort is in response to an
+ * unexpected switch to command phase
+ * for a packetized connection. Since
+ * the identify message was never sent,
+ * "saved lun" is 0. We really want to
+ * abort only the SCB that encountered
+ * this error, which could have a different
+ * lun. The SCB will be retried so the OS
+ * will see the UA after renegotiating to
+ * packetized.
+ */
+ tag = SCB_GET_TAG(scb);
+ saved_lun = scb->hscb->lun;
+ }
found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
tag, ROLE_INITIATOR,
CAM_REQ_ABORTED);
@@ -2523,7 +2665,7 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
}
#define AHD_MAX_STEPS 2000
-void
+static void
ahd_clear_critical_section(struct ahd_softc *ahd)
{
ahd_mode_state saved_modes;
@@ -2646,7 +2788,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
/*
* Clear any pending interrupt status.
*/
-void
+static void
ahd_clear_intstat(struct ahd_softc *ahd)
{
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
@@ -2677,6 +2819,8 @@ ahd_clear_intstat(struct ahd_softc *ahd)
#ifdef AHD_DEBUG
uint32_t ahd_debug = AHD_DEBUG_OPTS;
#endif
+
+#if 0
void
ahd_print_scb(struct scb *scb)
{
@@ -2701,49 +2845,7 @@ ahd_print_scb(struct scb *scb)
SCB_GET_TAG(scb));
ahd_dump_sglist(scb);
}
-
-void
-ahd_dump_sglist(struct scb *scb)
-{
- int i;
-
- if (scb->sg_count > 0) {
- if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
- struct ahd_dma64_seg *sg_list;
-
- sg_list = (struct ahd_dma64_seg*)scb->sg_list;
- for (i = 0; i < scb->sg_count; i++) {
- uint64_t addr;
- uint32_t len;
-
- addr = ahd_le64toh(sg_list[i].addr);
- len = ahd_le32toh(sg_list[i].len);
- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
- i,
- (uint32_t)((addr >> 32) & 0xFFFFFFFF),
- (uint32_t)(addr & 0xFFFFFFFF),
- sg_list[i].len & AHD_SG_LEN_MASK,
- (sg_list[i].len & AHD_DMA_LAST_SEG)
- ? " Last" : "");
- }
- } else {
- struct ahd_dma_seg *sg_list;
-
- sg_list = (struct ahd_dma_seg*)scb->sg_list;
- for (i = 0; i < scb->sg_count; i++) {
- uint32_t len;
-
- len = ahd_le32toh(sg_list[i].len);
- printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
- i,
- (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
- ahd_le32toh(sg_list[i].addr),
- len & AHD_SG_LEN_MASK,
- len & AHD_DMA_LAST_SEG ? " Last" : "");
- }
- }
- }
-}
+#endif /* 0 */
/************************* Transfer Negotiation *******************************/
/*
@@ -2850,14 +2952,14 @@ ahd_devlimited_syncrate(struct ahd_softc *ahd,
transinfo = &tinfo->goal;
*ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN);
if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
- maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2);
+ maxsync = max(maxsync, (u_int)AHD_SYNCRATE_ULTRA2);
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
}
if (transinfo->period == 0) {
*period = 0;
*ppr_options = 0;
} else {
- *period = MAX(*period, transinfo->period);
+ *period = max(*period, (u_int)transinfo->period);
ahd_find_syncrate(ahd, period, ppr_options, maxsync);
}
}
@@ -2906,7 +3008,7 @@ ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
* Truncate the given synchronous offset to a value the
* current adapter type and syncrate are capable of.
*/
-void
+static void
ahd_validate_offset(struct ahd_softc *ahd,
struct ahd_initiator_tinfo *tinfo,
u_int period, u_int *offset, int wide,
@@ -2924,12 +3026,12 @@ ahd_validate_offset(struct ahd_softc *ahd,
maxoffset = MAX_OFFSET_PACED;
} else
maxoffset = MAX_OFFSET_NON_PACED;
- *offset = MIN(*offset, maxoffset);
+ *offset = min(*offset, maxoffset);
if (tinfo != NULL) {
if (role == ROLE_TARGET)
- *offset = MIN(*offset, tinfo->user.offset);
+ *offset = min(*offset, (u_int)tinfo->user.offset);
else
- *offset = MIN(*offset, tinfo->goal.offset);
+ *offset = min(*offset, (u_int)tinfo->goal.offset);
}
}
@@ -2937,7 +3039,7 @@ ahd_validate_offset(struct ahd_softc *ahd,
* Truncate the given transfer width parameter to a value the
* current adapter type is capable of.
*/
-void
+static void
ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
u_int *bus_width, role_t role)
{
@@ -2955,9 +3057,9 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
}
if (tinfo != NULL) {
if (role == ROLE_TARGET)
- *bus_width = MIN(tinfo->user.width, *bus_width);
+ *bus_width = min((u_int)tinfo->user.width, *bus_width);
else
- *bus_width = MIN(tinfo->goal.width, *bus_width);
+ *bus_width = min((u_int)tinfo->goal.width, *bus_width);
}
}
@@ -3210,7 +3312,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
/*
* Update the current state of tagged queuing for a given target.
*/
-void
+static void
ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{
@@ -3466,7 +3568,7 @@ ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
devinfo->target, devinfo->lun);
}
-struct ahd_phase_table_entry*
+static struct ahd_phase_table_entry*
ahd_lookup_phase_entry(int phase)
{
struct ahd_phase_table_entry *entry;
@@ -5351,7 +5453,7 @@ ahd_free(struct ahd_softc *ahd)
return;
}
-void
+static void
ahd_shutdown(void *arg)
{
struct ahd_softc *ahd;
@@ -5480,7 +5582,7 @@ ahd_reset(struct ahd_softc *ahd, int reinit)
/*
* Determine the number of SCBs available on the controller
*/
-int
+static int
ahd_probe_scbs(struct ahd_softc *ahd) {
int i;
@@ -5929,7 +6031,7 @@ ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
ahd_platform_scb_free(ahd, scb);
}
-void
+static void
ahd_alloc_scbs(struct ahd_softc *ahd)
{
struct scb_data *scb_data;
@@ -6057,9 +6159,9 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
#endif
}
- newcount = MIN(scb_data->sense_left, scb_data->scbs_left);
- newcount = MIN(newcount, scb_data->sgs_left);
- newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
+ newcount = min(scb_data->sense_left, scb_data->scbs_left);
+ newcount = min(newcount, scb_data->sgs_left);
+ newcount = min(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
for (i = 0; i < newcount; i++) {
struct scb_platform_data *pdata;
u_int col_tag;
@@ -6982,7 +7084,7 @@ ahd_intr_enable(struct ahd_softc *ahd, int enable)
ahd_outb(ahd, HCNTRL, hcntrl);
}
-void
+static void
ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
u_int mincmds)
{
@@ -7000,7 +7102,7 @@ ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds);
}
-void
+static void
ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
{
@@ -7070,6 +7172,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS;
}
+#if 0
int
ahd_suspend(struct ahd_softc *ahd)
{
@@ -7083,7 +7186,9 @@ ahd_suspend(struct ahd_softc *ahd)
ahd_shutdown(ahd);
return (0);
}
+#endif /* 0 */
+#if 0
int
ahd_resume(struct ahd_softc *ahd)
{
@@ -7093,6 +7198,7 @@ ahd_resume(struct ahd_softc *ahd)
ahd_restart(ahd);
return (0);
}
+#endif /* 0 */
/************************** Busy Target Table *********************************/
/*
@@ -7125,7 +7231,7 @@ ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
/*
* Return the untagged transaction id for a given target/channel lun.
*/
-u_int
+static u_int
ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
{
u_int scbid;
@@ -7138,7 +7244,7 @@ ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
return (scbid);
}
-void
+static void
ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
{
u_int scb_offset;
@@ -7186,7 +7292,7 @@ ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target,
return match;
}
-void
+static void
ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
{
int target;
@@ -7690,7 +7796,7 @@ ahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid)
* been modified from CAM_REQ_INPROG. This routine assumes that the sequencer
* is paused before it is called.
*/
-int
+static int
ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
int lun, u_int tag, role_t role, uint32_t status)
{
@@ -7920,6 +8026,11 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
ahd_clear_fifo(ahd, 1);
/*
+ * Clear SCSI interrupt status
+ */
+ ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
+
+ /*
* Reenable selections
*/
ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
@@ -7952,10 +8063,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
}
}
#endif
- /* Notify the XPT that a bus reset occurred */
- ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD, AC_BUS_RESET);
-
/*
* Revert to async/narrow transfers until we renegotiate.
*/
@@ -7977,6 +8084,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
}
}
+ /* Notify the XPT that a bus reset occurred */
+ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD, AC_BUS_RESET);
+
ahd_restart(ahd);
return (found);
@@ -8019,18 +8130,8 @@ ahd_stat_timer(void *arg)
}
/****************************** Status Processing *****************************/
-void
-ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
-{
- if (scb->hscb->shared_data.istatus.scsi_status != 0) {
- ahd_handle_scsi_status(ahd, scb);
- } else {
- ahd_calc_residual(ahd, scb);
- ahd_done(ahd, scb);
- }
-}
-void
+static void
ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
{
struct hardware_scb *hscb;
@@ -8238,10 +8339,21 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
}
}
+static void
+ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
+{
+ if (scb->hscb->shared_data.istatus.scsi_status != 0) {
+ ahd_handle_scsi_status(ahd, scb);
+ } else {
+ ahd_calc_residual(ahd, scb);
+ ahd_done(ahd, scb);
+ }
+}
+
/*
* Calculate the residual for a just completed SCB.
*/
-void
+static void
ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
{
struct hardware_scb *hscb;
@@ -8668,7 +8780,7 @@ ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address)
if (skip_addr > i) {
int end_addr;
- end_addr = MIN(address, skip_addr);
+ end_addr = min(address, skip_addr);
address_offset += end_addr - i;
i = skip_addr;
} else {
@@ -9092,6 +9204,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_unpause(ahd);
}
+#if 0
void
ahd_dump_scbs(struct ahd_softc *ahd)
{
@@ -9117,6 +9230,7 @@ ahd_dump_scbs(struct ahd_softc *ahd)
ahd_set_scbptr(ahd, saved_scb_index);
ahd_restore_modes(ahd, saved_modes);
}
+#endif /* 0 */
/**************************** Flexport Logic **********************************/
/*
@@ -9219,7 +9333,7 @@ ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
/*
* Wait ~100us for the serial eeprom to satisfy our request.
*/
-int
+static int
ahd_wait_seeprom(struct ahd_softc *ahd)
{
int cnt;
@@ -9237,7 +9351,7 @@ ahd_wait_seeprom(struct ahd_softc *ahd)
* Validate the two checksums in the per_channel
* vital product data struct.
*/
-int
+static int
ahd_verify_vpd_cksum(struct vpd_config *vpd)
{
int i;
@@ -9316,6 +9430,24 @@ ahd_release_seeprom(struct ahd_softc *ahd)
/* Currently a no-op */
}
+/*
+ * Wait at most 2 seconds for flexport arbitration to succeed.
+ */
+static int
+ahd_wait_flexport(struct ahd_softc *ahd)
+{
+ int cnt;
+
+ AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+ cnt = 1000000 * 2 / 5;
+ while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
+ ahd_delay(5);
+
+ if (cnt == 0)
+ return (ETIMEDOUT);
+ return (0);
+}
+
int
ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value)
{
@@ -9357,24 +9489,6 @@ ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value)
return (0);
}
-/*
- * Wait at most 2 seconds for flexport arbitration to succeed.
- */
-int
-ahd_wait_flexport(struct ahd_softc *ahd)
-{
- int cnt;
-
- AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
- cnt = 1000000 * 2 / 5;
- while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
- ahd_delay(5);
-
- if (cnt == 0)
- return (ETIMEDOUT);
- return (0);
-}
-
/************************* Target Mode ****************************************/
#ifdef AHD_TARGET_MODE
cam_status
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index 8ad3ce945b9..2ceb67f4af2 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -418,10 +418,6 @@ ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
}
/*********************** Miscelaneous Support Functions ***********************/
-static __inline void ahd_complete_scb(struct ahd_softc *ahd,
- struct scb *scb);
-static __inline void ahd_update_residual(struct ahd_softc *ahd,
- struct scb *scb);
static __inline struct ahd_initiator_tinfo *
ahd_fetch_transinfo(struct ahd_softc *ahd,
char channel, u_int our_id,
@@ -467,32 +463,6 @@ static __inline uint32_t
ahd_get_sense_bufaddr(struct ahd_softc *ahd,
struct scb *scb);
-static __inline void
-ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- uint32_t sgptr;
-
- sgptr = ahd_le32toh(scb->hscb->sgptr);
- if ((sgptr & SG_STATUS_VALID) != 0)
- ahd_handle_scb_status(ahd, scb);
- else
- ahd_done(ahd, scb);
-}
-
-/*
- * Determine whether the sequencer reported a residual
- * for this SCB/transaction.
- */
-static __inline void
-ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
-{
- uint32_t sgptr;
-
- sgptr = ahd_le32toh(scb->hscb->sgptr);
- if ((sgptr & SG_STATUS_VALID) != 0)
- ahd_calc_residual(ahd, scb);
-}
-
/*
* Return pointers to the transfer negotiation information
* for the specified our_id/remote_id pair.
@@ -527,7 +497,8 @@ ahd_inw(struct ahd_softc *ahd, u_int port)
* or have other side effects when the low byte is
* read.
*/
- return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
+ uint16_t r = ahd_inb(ahd, port+1) << 8;
+ return r | ahd_inb(ahd, port);
}
static __inline void
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index c7eeaced324..9bfcca5ede0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -293,7 +293,7 @@ static uint32_t aic79xx_seltime;
* force all outstanding transactions to be serviced prior to a new
* transaction.
*/
-uint32_t aic79xx_periodic_otag;
+static uint32_t aic79xx_periodic_otag;
/* Some storage boxes are using an LSI chip which has a bug making it
* impossible to use aic79xx Rev B chip in 320 speeds. The following
@@ -646,7 +646,7 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd)
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
unsigned long flags;
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
reset_scb = NULL;
paused = FALSE;
@@ -773,6 +773,7 @@ struct scsi_host_template aic79xx_driver_template = {
#endif
.can_queue = AHD_MAX_QUEUE,
.this_id = -1,
+ .max_sectors = 8192,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
.slave_alloc = ahd_linux_slave_alloc,
@@ -1557,7 +1558,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
* SCSI controller interrupt handler.
*/
irqreturn_t
-ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahd_linux_isr(int irq, void *dev_id)
{
struct ahd_softc *ahd;
u_long flags;
@@ -1813,9 +1814,9 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
u_int sense_offset;
if (scb->flags & SCB_SENSE) {
- sense_size = MIN(sizeof(struct scsi_sense_data)
+ sense_size = min(sizeof(struct scsi_sense_data)
- ahd_get_sense_residual(scb),
- sizeof(cmd->sense_buffer));
+ (u_long)sizeof(cmd->sense_buffer));
sense_offset = 0;
} else {
/*
@@ -1824,7 +1825,8 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
*/
siu = (struct scsi_status_iu_header *)
scb->sense_data;
- sense_size = MIN(scsi_4btoul(siu->sense_length),
+ sense_size = min_t(size_t,
+ scsi_4btoul(siu->sense_length),
sizeof(cmd->sense_buffer));
sense_offset = SIU_SENSE_OFFSET(siu);
}
@@ -2251,7 +2253,7 @@ done:
if (paused)
ahd_unpause(ahd);
if (wait) {
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
ahd->platform_data->eh_done = &done;
ahd_unlock(ahd, &flags);
@@ -2634,8 +2636,22 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp)
pcomp ? "Enable" : "Disable");
#endif
- if (pcomp)
+ if (pcomp) {
+ uint8_t precomp;
+
+ if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
+ struct ahd_linux_iocell_opts *iocell_opts;
+
+ iocell_opts = &aic79xx_iocell_info[ahd->unit];
+ precomp = iocell_opts->precomp;
+ } else {
+ precomp = AIC79XX_DEFAULT_PRECOMP;
+ }
ppr_options |= MSG_EXT_PPR_PCOMP_EN;
+ AHD_SET_PRECOMP(ahd, precomp);
+ } else {
+ AHD_SET_PRECOMP(ahd, 0);
+ }
ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
starget->channel + 'A', ROLE_INITIATOR);
@@ -2678,7 +2694,25 @@ static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold)
ahd_unlock(ahd, &flags);
}
+static void ahd_linux_get_signalling(struct Scsi_Host *shost)
+{
+ struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
+ unsigned long flags;
+ u8 mode;
+
+ ahd_lock(ahd, &flags);
+ ahd_pause(ahd);
+ mode = ahd_inb(ahd, SBLKCTL);
+ ahd_unpause(ahd);
+ ahd_unlock(ahd, &flags);
+ if (mode & ENAB40)
+ spi_signalling(shost) = SPI_SIGNAL_LVD;
+ else if (mode & ENAB20)
+ spi_signalling(shost) = SPI_SIGNAL_SE;
+ else
+ spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
+}
static struct spi_function_template ahd_linux_transport_functions = {
.set_offset = ahd_linux_set_offset,
@@ -2703,6 +2737,7 @@ static struct spi_function_template ahd_linux_transport_functions = {
.show_pcomp_en = 1,
.set_hold_mcs = ahd_linux_set_hold_mcs,
.show_hold_mcs = 1,
+ .get_signalling = ahd_linux_get_signalling,
};
static int __init
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 601340d8441..3a67fc578d7 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -506,9 +506,6 @@ struct info_str {
int pos;
};
-void ahd_format_transinfo(struct info_str *info,
- struct ahd_transinfo *tinfo);
-
/******************************** Locking *************************************/
static __inline void
ahd_lockinit(struct ahd_softc *ahd)
@@ -582,8 +579,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags)
#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */
#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */
-extern struct pci_driver aic79xx_pci_driver;
-
typedef enum
{
AHD_POWER_STATE_D0,
@@ -862,7 +857,7 @@ int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status);
irqreturn_t
- ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+ ahd_linux_isr(int irq, void *dev_id);
void ahd_done(struct ahd_softc*, struct scb*);
void ahd_send_async(struct ahd_softc *, char channel,
u_int target, u_int lun, ac_code);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 50a41eda580..1a3ab6aa856 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -62,6 +62,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
/* aic7901 based controllers */
ID(ID_AHA_29320A),
ID(ID_AHA_29320ALP),
+ ID(ID_AHA_29320LPE),
/* aic7902 based controllers */
ID(ID_AHA_29320),
ID(ID_AHA_29320B),
@@ -82,7 +83,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
-struct pci_driver aic79xx_pci_driver = {
+static struct pci_driver aic79xx_pci_driver = {
.name = "aic79xx",
.probe = ahd_linux_pci_dev_probe,
.remove = ahd_linux_pci_dev_remove,
@@ -198,7 +199,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int
ahd_linux_pci_init(void)
{
- return (pci_module_init(&aic79xx_pci_driver));
+ return pci_register_driver(&aic79xx_pci_driver);
}
void
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 14850f31aaf..2cf7bb3123f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -97,7 +97,7 @@ static ahd_device_setup_t ahd_aic7901A_setup;
static ahd_device_setup_t ahd_aic7902_setup;
static ahd_device_setup_t ahd_aic790X_setup;
-struct ahd_pci_identity ahd_pci_ident_table [] =
+static struct ahd_pci_identity ahd_pci_ident_table [] =
{
/* aic7901 based controllers */
{
@@ -109,7 +109,13 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
{
ID_AHA_29320ALP,
ID_ALL_MASK,
- "Adaptec 29320ALP Ultra320 SCSI adapter",
+ "Adaptec 29320ALP PCIx Ultra320 SCSI adapter",
+ ahd_aic7901_setup
+ },
+ {
+ ID_AHA_29320LPE,
+ ID_ALL_MASK,
+ "Adaptec 29320LPE PCIe Ultra320 SCSI adapter",
ahd_aic7901_setup
},
/* aic7901A based controllers */
@@ -201,7 +207,7 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
}
};
-const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
+static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
#define DEVCONFIG 0x40
#define PCIXINITPAT 0x0000E000ul
@@ -245,6 +251,7 @@ static int ahd_check_extport(struct ahd_softc *ahd);
static void ahd_configure_termination(struct ahd_softc *ahd,
u_int adapter_control);
static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
+static void ahd_pci_intr(struct ahd_softc *ahd);
struct ahd_pci_identity *
ahd_find_pci_device(ahd_dev_softc_t pci)
@@ -757,7 +764,7 @@ static const char *pci_status_strings[] =
"%s: Address or Write Phase Parity Error Detected in %s.\n"
};
-void
+static void
ahd_pci_intr(struct ahd_softc *ahd)
{
uint8_t pci_status[8];
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
index da45153668c..16b7c70a673 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.h
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -51,6 +51,7 @@
#define ID_AIC7901 0x800F9005FFFF9005ull
#define ID_AHA_29320A 0x8000900500609005ull
#define ID_AHA_29320ALP 0x8017900500449005ull
+#define ID_AHA_29320LPE 0x8017900500459005ull
#define ID_AIC7901A 0x801E9005FFFF9005ull
#define ID_AHA_29320LP 0x8014900500449005ull
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index c5f0ee59150..6b28bebcbca 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -136,7 +136,7 @@ copy_info(struct info_str *info, char *fmt, ...)
return (len);
}
-void
+static void
ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
{
u_int speed;
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 62ff8c3dc2b..954c7c24501 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -54,14 +54,6 @@ struct scb_platform_data;
struct seeprom_descriptor;
/****************************** Useful Macros *********************************/
-#ifndef MAX
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
#ifndef TRUE
#define TRUE 1
#endif
@@ -1135,8 +1127,6 @@ struct ahc_pci_identity {
char *name;
ahc_device_setup_t *setup;
};
-extern struct ahc_pci_identity ahc_pci_ident_table[];
-extern const u_int ahc_num_pci_devs;
/***************************** VL/EISA Declarations ***************************/
struct aic7770_identity {
@@ -1289,6 +1279,7 @@ typedef enum {
} ahc_queue_alg;
void ahc_set_tags(struct ahc_softc *ahc,
+ struct scsi_cmnd *cmd,
struct ahc_devinfo *devinfo,
ahc_queue_alg alg);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 93e4e40944b..50ef785224d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -1671,7 +1671,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
transinfo = &tinfo->goal;
*ppr_options &= transinfo->ppr_options;
if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
- maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ maxsync = max(maxsync, (u_int)AHC_SYNCRATE_ULTRA2);
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
}
if (transinfo->period == 0) {
@@ -1679,7 +1679,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc,
*ppr_options = 0;
return (NULL);
}
- *period = MAX(*period, transinfo->period);
+ *period = max(*period, (u_int)transinfo->period);
return (ahc_find_syncrate(ahc, period, ppr_options, maxsync));
}
@@ -1804,12 +1804,12 @@ ahc_validate_offset(struct ahc_softc *ahc,
else
maxoffset = MAX_OFFSET_8BIT;
}
- *offset = MIN(*offset, maxoffset);
+ *offset = min(*offset, maxoffset);
if (tinfo != NULL) {
if (role == ROLE_TARGET)
- *offset = MIN(*offset, tinfo->user.offset);
+ *offset = min(*offset, (u_int)tinfo->user.offset);
else
- *offset = MIN(*offset, tinfo->goal.offset);
+ *offset = min(*offset, (u_int)tinfo->goal.offset);
}
}
@@ -1835,9 +1835,9 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
}
if (tinfo != NULL) {
if (role == ROLE_TARGET)
- *bus_width = MIN(tinfo->user.width, *bus_width);
+ *bus_width = min((u_int)tinfo->user.width, *bus_width);
else
- *bus_width = MIN(tinfo->goal.width, *bus_width);
+ *bus_width = min((u_int)tinfo->goal.width, *bus_width);
}
}
@@ -1986,7 +1986,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
tinfo->curr.ppr_options = ppr_options;
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
if (offset != 0) {
printf("%s: target %d synchronous at %sMHz%s, "
@@ -2056,7 +2056,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
tinfo->curr.width = width;
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
printf("%s: target %d using %dbit transfers\n",
ahc_name(ahc), devinfo->target,
@@ -2074,12 +2074,14 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
* Update the current state of tagged queuing for a given target.
*/
void
-ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
- ahc_queue_alg alg)
+ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+ struct ahc_devinfo *devinfo, ahc_queue_alg alg)
{
- ahc_platform_set_tags(ahc, devinfo, alg);
+ struct scsi_device *sdev = cmd->device;
+
+ ahc_platform_set_tags(ahc, sdev, devinfo, alg);
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- devinfo->lun, AC_TRANSFER_NEG, &alg);
+ devinfo->lun, AC_TRANSFER_NEG);
}
/*
@@ -3489,7 +3491,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
printf("(%s:%c:%d:%d): refuses tagged commands. "
"Performing non-tagged I/O\n", ahc_name(ahc),
devinfo->channel, devinfo->target, devinfo->lun);
- ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE);
+ ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE);
mask = ~0x23;
} else {
printf("(%s:%c:%d:%d): refuses %s tagged commands. "
@@ -3497,7 +3499,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
ahc_name(ahc), devinfo->channel, devinfo->target,
devinfo->lun, tag_type == MSG_ORDERED_TASK
? "ordered" : "head of queue");
- ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC);
+ ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_BASIC);
mask = ~0x03;
}
@@ -3763,7 +3765,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
if (status != CAM_SEL_TIMEOUT)
ahc_send_async(ahc, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR);
if (message != NULL
&& (verbose_level <= bootverbose))
@@ -4406,7 +4408,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc)
physaddr = sg_map->sg_physaddr;
newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
- newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
+ newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
for (i = 0; i < newcount; i++) {
struct scb_platform_data *pdata;
#ifndef __linux__
@@ -6018,7 +6020,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
#endif
/* Notify the XPT that a bus reset occurred */
ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
+ CAM_LUN_WILDCARD, AC_BUS_RESET);
/*
* Revert to async/narrow transfers until we renegotiate.
@@ -6442,7 +6444,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
if (skip_addr > i) {
int end_addr;
- end_addr = MIN(address, skip_addr);
+ end_addr = min(address, skip_addr);
address_offset += end_addr - i;
i = skip_addr;
} else {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
index 2cc8a17ed8b..8e1954cdd84 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -300,7 +300,8 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
static __inline uint16_t
ahc_inw(struct ahc_softc *ahc, u_int port)
{
- return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
+ uint16_t r = ahc_inb(ahc, port+1) << 8;
+ return r | ahc_inb(ahc, port);
}
static __inline void
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 64c8b88a429..660f26e23a3 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -328,7 +328,7 @@ static uint32_t aic7xxx_seltime;
* force all outstanding transactions to be serviced prior to a new
* transaction.
*/
-uint32_t aic7xxx_periodic_otag;
+static uint32_t aic7xxx_periodic_otag;
/*
* Module information and settable options.
@@ -512,7 +512,6 @@ ahc_linux_target_alloc(struct scsi_target *starget)
struct seeprom_config *sc = ahc->seep_config;
unsigned long flags;
struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget);
- struct ahc_linux_target *targ = scsi_transport_target_data(starget);
unsigned short scsirate;
struct ahc_devinfo devinfo;
struct ahc_initiator_tinfo *tinfo;
@@ -533,7 +532,6 @@ ahc_linux_target_alloc(struct scsi_target *starget)
BUG_ON(*ahc_targp != NULL);
*ahc_targp = starget;
- memset(targ, 0, sizeof(*targ));
if (sc) {
int maxsync = AHC_SYNCRATE_DT;
@@ -594,14 +592,11 @@ ahc_linux_slave_alloc(struct scsi_device *sdev)
struct ahc_softc *ahc =
*((struct ahc_softc **)sdev->host->hostdata);
struct scsi_target *starget = sdev->sdev_target;
- struct ahc_linux_target *targ = scsi_transport_target_data(starget);
struct ahc_linux_device *dev;
if (bootverbose)
printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id);
- BUG_ON(targ->sdev[sdev->lun] != NULL);
-
dev = scsi_transport_device_data(sdev);
memset(dev, 0, sizeof(*dev));
@@ -618,8 +613,6 @@ ahc_linux_slave_alloc(struct scsi_device *sdev)
*/
dev->maxtags = 0;
- targ->sdev[sdev->lun] = sdev;
-
spi_period(starget) = 0;
return 0;
@@ -644,22 +637,6 @@ ahc_linux_slave_configure(struct scsi_device *sdev)
return 0;
}
-static void
-ahc_linux_slave_destroy(struct scsi_device *sdev)
-{
- struct ahc_softc *ahc;
- struct ahc_linux_device *dev = scsi_transport_device_data(sdev);
- struct ahc_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
-
- ahc = *((struct ahc_softc **)sdev->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Destroy %d\n", ahc_name(ahc), sdev->id);
-
- BUG_ON(dev->active);
-
- targ->sdev[sdev->lun] = NULL;
-}
-
#if defined(__i386__)
/*
* Return the disk geometry for the given SCSI device.
@@ -777,11 +754,11 @@ struct scsi_host_template aic7xxx_driver_template = {
#endif
.can_queue = AHC_MAX_QUEUE,
.this_id = -1,
+ .max_sectors = 8192,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
.slave_alloc = ahc_linux_slave_alloc,
.slave_configure = ahc_linux_slave_configure,
- .slave_destroy = ahc_linux_slave_destroy,
.target_alloc = ahc_linux_target_alloc,
.target_destroy = ahc_linux_target_destroy,
};
@@ -1203,21 +1180,13 @@ void
ahc_platform_free(struct ahc_softc *ahc)
{
struct scsi_target *starget;
- int i, j;
+ int i;
if (ahc->platform_data != NULL) {
/* destroy all of the device and target objects */
for (i = 0; i < AHC_NUM_TARGETS; i++) {
starget = ahc->platform_data->starget[i];
if (starget != NULL) {
- for (j = 0; j < AHC_NUM_LUNS; j++) {
- struct ahc_linux_target *targ =
- scsi_transport_target_data(starget);
-
- if (targ->sdev[j] == NULL)
- continue;
- targ->sdev[j] = NULL;
- }
ahc->platform_data->starget[i] = NULL;
}
}
@@ -1251,24 +1220,13 @@ ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
}
void
-ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
- ahc_queue_alg alg)
+ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
+ struct ahc_devinfo *devinfo, ahc_queue_alg alg)
{
- struct scsi_target *starget;
- struct ahc_linux_target *targ;
struct ahc_linux_device *dev;
- struct scsi_device *sdev;
- u_int target_offset;
int was_queuing;
int now_queuing;
- target_offset = devinfo->target;
- if (devinfo->channel != 'A')
- target_offset += 8;
- starget = ahc->platform_data->starget[target_offset];
- targ = scsi_transport_target_data(starget);
- BUG_ON(targ == NULL);
- sdev = targ->sdev[devinfo->lun];
if (sdev == NULL)
return;
dev = scsi_transport_device_data(sdev);
@@ -1401,11 +1359,15 @@ ahc_linux_device_queue_depth(struct scsi_device *sdev)
tags = ahc_linux_user_tagdepth(ahc, &devinfo);
if (tags != 0 && sdev->tagged_supported != 0) {
- ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
+ ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_TAGGED);
+ ahc_send_async(ahc, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
ahc_print_devinfo(ahc, &devinfo);
printf("Tagged Queuing enabled. Depth %d\n", tags);
} else {
- ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
+ ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE);
+ ahc_send_async(ahc, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
}
}
@@ -1608,7 +1570,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
* SCSI controller interrupt handler.
*/
irqreturn_t
-ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahc_linux_isr(int irq, void *dev_id)
{
struct ahc_softc *ahc;
u_long flags;
@@ -1629,7 +1591,7 @@ ahc_platform_flushwork(struct ahc_softc *ahc)
void
ahc_send_async(struct ahc_softc *ahc, char channel,
- u_int target, u_int lun, ac_code code, void *arg)
+ u_int target, u_int lun, ac_code code)
{
switch (code) {
case AC_TRANSFER_NEG:
@@ -1875,9 +1837,9 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
if (scb->flags & SCB_SENSE) {
u_int sense_size;
- sense_size = MIN(sizeof(struct scsi_sense_data)
+ sense_size = min(sizeof(struct scsi_sense_data)
- ahc_get_sense_residual(scb),
- sizeof(cmd->sense_buffer));
+ (u_long)sizeof(cmd->sense_buffer));
memcpy(cmd->sense_buffer,
ahc_get_sense_buf(ahc, scb), sense_size);
if (sense_size < sizeof(cmd->sense_buffer))
@@ -1946,7 +1908,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
}
ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);
ahc_set_scsi_status(scb, SCSI_STATUS_OK);
- ahc_platform_set_tags(ahc, &devinfo,
+ ahc_platform_set_tags(ahc, sdev, &devinfo,
(dev->flags & AHC_DEV_Q_BASIC)
? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
break;
@@ -1957,7 +1919,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
*/
dev->openings = 1;
ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
- ahc_platform_set_tags(ahc, &devinfo,
+ ahc_platform_set_tags(ahc, sdev, &devinfo,
(dev->flags & AHC_DEV_Q_BASIC)
? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
break;
@@ -2335,7 +2297,7 @@ done:
if (paused)
ahc_unpause(ahc);
if (wait) {
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
ahc->platform_data->eh_done = &done;
ahc_unlock(ahc, &flags);
@@ -2599,8 +2561,6 @@ ahc_linux_init(void)
if (!ahc_linux_transport_template)
return -ENODEV;
- scsi_transport_reserve_target(ahc_linux_transport_template,
- sizeof(struct ahc_linux_target));
scsi_transport_reserve_device(ahc_linux_transport_template,
sizeof(struct ahc_linux_device));
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index d42a71ee076..85ae5d836fa 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -256,7 +256,6 @@ typedef enum {
AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
} ahc_linux_dev_flags;
-struct ahc_linux_target;
struct ahc_linux_device {
/*
* The number of transactions currently
@@ -329,12 +328,6 @@ struct ahc_linux_device {
#define AHC_OTAG_THRESH 500
};
-struct ahc_linux_target {
- struct scsi_device *sdev[AHC_NUM_LUNS];
- struct ahc_transinfo last_tinfo;
- struct ahc_softc *ahc;
-};
-
/********************* Definitions Required by the Core ***********************/
/*
* Number of SG segments we require. So long as the S/G segments for
@@ -533,8 +526,6 @@ ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
#define PCIR_SUBVEND_0 0x2c
#define PCIR_SUBDEV_0 0x2e
-extern struct pci_driver aic7xxx_pci_driver;
-
typedef enum
{
AHC_POWER_STATE_D0,
@@ -824,17 +815,17 @@ ahc_freeze_scb(struct scb *scb)
}
}
-void ahc_platform_set_tags(struct ahc_softc *ahc,
+void ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
struct ahc_devinfo *devinfo, ahc_queue_alg);
int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status);
irqreturn_t
- ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+ ahc_linux_isr(int irq, void *dev_id);
void ahc_platform_flushwork(struct ahc_softc *ahc);
void ahc_done(struct ahc_softc*, struct scb*);
void ahc_send_async(struct ahc_softc *, char channel,
- u_int target, u_int lun, ac_code, void *);
+ u_int target, u_int lun, ac_code);
void ahc_print_path(struct ahc_softc *, struct scb *);
void ahc_platform_dump_card_state(struct ahc_softc *ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 7e42f07a27f..ea5687df732 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -130,7 +130,7 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
-struct pci_driver aic7xxx_pci_driver = {
+static struct pci_driver aic7xxx_pci_driver = {
.name = "aic7xxx",
.probe = ahc_linux_pci_dev_probe,
.remove = ahc_linux_pci_dev_remove,
@@ -246,8 +246,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int
ahc_linux_pci_init(void)
{
- /* Translate error or zero return into zero or one */
- return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
+ return pci_register_driver(&aic7xxx_pci_driver);
}
void
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 63cab2d7455..09c8172c9e5 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -168,7 +168,7 @@ static ahc_device_setup_t ahc_aha394XX_setup;
static ahc_device_setup_t ahc_aha494XX_setup;
static ahc_device_setup_t ahc_aha398XX_setup;
-struct ahc_pci_identity ahc_pci_ident_table [] =
+static struct ahc_pci_identity ahc_pci_ident_table [] =
{
/* aic7850 based controllers */
{
@@ -559,7 +559,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
}
};
-const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table);
+static const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table);
#define AHC_394X_SLOT_CHANNEL_A 4
#define AHC_394X_SLOT_CHANNEL_B 5
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 5914b4aa4a8..99e5443e753 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -182,7 +182,6 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
u_int our_id, char channel, u_int target_id,
u_int target_offset)
{
- struct ahc_linux_target *targ;
struct scsi_target *starget;
struct ahc_initiator_tinfo *tinfo;
struct ahc_tmode_tstate *tstate;
@@ -198,7 +197,6 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
starget = ahc->platform_data->starget[target_offset];
if (!starget)
return;
- targ = scsi_transport_target_data(starget);
copy_info(info, "\tGoal: ");
ahc_format_transinfo(info, &tinfo->goal);
@@ -208,7 +206,7 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
struct scsi_device *sdev;
- sdev = targ->sdev[lun];
+ sdev = scsi_device_lookup_by_target(starget, lun);
if (sdev == NULL)
continue;
@@ -383,11 +381,11 @@ ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
}
copy_info(&info, "\n");
- max_targ = 15;
+ max_targ = 16;
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
- max_targ = 7;
+ max_targ = 8;
- for (i = 0; i <= max_targ; i++) {
+ for (i = 0; i < max_targ; i++) {
u_int our_id;
u_int target_id;
char channel;
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 5dcef48d414..46eed10b25d 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -780,24 +780,26 @@ typedef enum {
} ahc_bugs;
struct aic7xxx_scb {
- struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- struct aic7xxx_scb *q_next; /* next scb in queue */
- volatile scb_flag_type flags; /* current state of scb */
- struct hw_scatterlist *sg_list; /* SG list in adapter format */
- unsigned char tag_action;
- unsigned char sg_count;
- unsigned char *sense_cmd; /*
- * Allocate 6 characters for
- * sense command.
- */
- unsigned char *cmnd;
- unsigned int sg_length; /* We init this during buildscb so we
- * don't have to calculate anything
- * during underflow/overflow/stat code
- */
- void *kmalloc_ptr;
- struct aic7xxx_scb_dma *scb_dma;
+ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+ struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */
+ struct aic7xxx_scb *q_next; /* next scb in queue */
+ volatile scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char tag_action;
+ unsigned char sg_count;
+ unsigned char *sense_cmd; /*
+ * Allocate 6 characters for
+ * sense command.
+ */
+ unsigned char *cmnd;
+ unsigned int sg_length; /*
+ * We init this during
+ * buildscb so we don't have
+ * to calculate anything during
+ * underflow/overflow/stat code
+ */
+ void *kmalloc_ptr;
+ struct aic7xxx_scb_dma *scb_dma;
};
/*
@@ -918,79 +920,77 @@ struct aic7xxx_host {
* We are grouping things here....first, items that get either read or
* written with nearly every interrupt
*/
- volatile long flags;
- ahc_feature features; /* chip features */
- unsigned long base; /* card base address */
- volatile unsigned char __iomem *maddr; /* memory mapped address */
- unsigned long isr_count; /* Interrupt count */
- unsigned long spurious_int;
- scb_data_type *scb_data;
- struct aic7xxx_cmd_queue {
- Scsi_Cmnd *head;
- Scsi_Cmnd *tail;
- } completeq;
+ volatile long flags;
+ ahc_feature features; /* chip features */
+ unsigned long base; /* card base address */
+ volatile unsigned char __iomem *maddr; /* memory mapped address */
+ unsigned long isr_count; /* Interrupt count */
+ unsigned long spurious_int;
+ scb_data_type *scb_data;
+ struct aic7xxx_cmd_queue {
+ struct scsi_cmnd *head;
+ struct scsi_cmnd *tail;
+ } completeq;
- /*
- * Things read/written on nearly every entry into aic7xxx_queue()
- */
- volatile scb_queue_type waiting_scbs;
- unsigned char unpause; /* unpause value for HCNTRL */
- unsigned char pause; /* pause value for HCNTRL */
- volatile unsigned char qoutfifonext;
- volatile unsigned char activescbs; /* active scbs */
- volatile unsigned char max_activescbs;
- volatile unsigned char qinfifonext;
- volatile unsigned char *untagged_scbs;
- volatile unsigned char *qoutfifo;
- volatile unsigned char *qinfifo;
-
- unsigned char dev_last_queue_full[MAX_TARGETS];
- unsigned char dev_last_queue_full_count[MAX_TARGETS];
- unsigned short ultraenb; /* Gets downloaded to card as a
- bitmap */
- unsigned short discenable; /* Gets downloaded to card as a
- bitmap */
- transinfo_type user[MAX_TARGETS];
-
- unsigned char msg_buf[13]; /* The message for the target */
- unsigned char msg_type;
+ /*
+ * Things read/written on nearly every entry into aic7xxx_queue()
+ */
+ volatile scb_queue_type waiting_scbs;
+ unsigned char unpause; /* unpause value for HCNTRL */
+ unsigned char pause; /* pause value for HCNTRL */
+ volatile unsigned char qoutfifonext;
+ volatile unsigned char activescbs; /* active scbs */
+ volatile unsigned char max_activescbs;
+ volatile unsigned char qinfifonext;
+ volatile unsigned char *untagged_scbs;
+ volatile unsigned char *qoutfifo;
+ volatile unsigned char *qinfifo;
+
+ unsigned char dev_last_queue_full[MAX_TARGETS];
+ unsigned char dev_last_queue_full_count[MAX_TARGETS];
+ unsigned short ultraenb; /* Gets downloaded to card as a bitmap */
+ unsigned short discenable; /* Gets downloaded to card as a bitmap */
+ transinfo_type user[MAX_TARGETS];
+
+ unsigned char msg_buf[13]; /* The message for the target */
+ unsigned char msg_type;
#define MSG_TYPE_NONE 0x00
#define MSG_TYPE_INITIATOR_MSGOUT 0x01
#define MSG_TYPE_INITIATOR_MSGIN 0x02
- unsigned char msg_len; /* Length of message */
- unsigned char msg_index; /* Index into msg_buf array */
+ unsigned char msg_len; /* Length of message */
+ unsigned char msg_index; /* Index into msg_buf array */
- /*
- * We put the less frequently used host structure items after the more
- * frequently used items to try and ease the burden on the cache subsystem.
- * These entries are not *commonly* accessed, whereas the preceding entries
- * are accessed very often.
- */
-
- unsigned int irq; /* IRQ for this adapter */
- int instance; /* aic7xxx instance number */
- int scsi_id; /* host adapter SCSI ID */
- int scsi_id_b; /* channel B for twin adapters */
- unsigned int bios_address;
- int board_name_index;
- unsigned short bios_control; /* bios control - SEEPROM */
- unsigned short adapter_control; /* adapter control - SEEPROM */
- struct pci_dev *pdev;
- unsigned char pci_bus;
- unsigned char pci_device_fn;
- struct seeprom_config sc;
- unsigned short sc_type;
- unsigned short sc_size;
- struct aic7xxx_host *next; /* allow for multiple IRQs */
- struct Scsi_Host *host; /* pointer to scsi host */
- struct list_head aic_devs; /* all aic_dev structs on host */
- int host_no; /* SCSI host number */
- unsigned long mbase; /* I/O memory address */
- ahc_chip chip; /* chip type */
- ahc_bugs bugs;
- dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
+ /*
+ * We put the less frequently used host structure items
+ * after the more frequently used items to try and ease
+ * the burden on the cache subsystem.
+ * These entries are not *commonly* accessed, whereas
+ * the preceding entries are accessed very often.
+ */
+ unsigned int irq; /* IRQ for this adapter */
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ unsigned int bios_address;
+ int board_name_index;
+ unsigned short bios_control; /* bios control - SEEPROM */
+ unsigned short adapter_control; /* adapter control - SEEPROM */
+ struct pci_dev *pdev;
+ unsigned char pci_bus;
+ unsigned char pci_device_fn;
+ struct seeprom_config sc;
+ unsigned short sc_type;
+ unsigned short sc_size;
+ struct aic7xxx_host *next; /* allow for multiple IRQs */
+ struct Scsi_Host *host; /* pointer to scsi host */
+ struct list_head aic_devs; /* all aic_dev structs on host */
+ int host_no; /* SCSI host number */
+ unsigned long mbase; /* I/O memory address */
+ ahc_chip chip; /* chip type */
+ ahc_bugs bugs;
+ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
};
/*
@@ -1271,7 +1271,7 @@ static void aic7xxx_set_syncrate(struct aic7xxx_host *p,
static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
int lun, unsigned int width, unsigned int type,
struct aic_dev_data *aic_dev);
-static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd);
static void aic7xxx_print_card(struct aic7xxx_host *p);
static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
@@ -2626,7 +2626,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
* we're finished. This function queues the completed commands.
*-F*************************************************************************/
static void
-aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
{
aic7xxx_position(cmd) = SCB_LIST_NULL;
cmd->host_scribble = (char *)p->completeq.head;
@@ -2640,18 +2640,16 @@ aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
* Description:
* Process the completed command queue.
*-F*************************************************************************/
-static void
-aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
{
- Scsi_Cmnd *cmd;
-
- while (p->completeq.head != NULL)
- {
- cmd = p->completeq.head;
- p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
- cmd->host_scribble = NULL;
- cmd->scsi_done(cmd);
- }
+ struct scsi_cmnd *cmd;
+
+ while (p->completeq.head != NULL) {
+ cmd = p->completeq.head;
+ p->completeq.head = (struct scsi_cmnd *) cmd->host_scribble;
+ cmd->host_scribble = NULL;
+ cmd->scsi_done(cmd);
+ }
}
/*+F*************************************************************************
@@ -2687,11 +2685,11 @@ aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
static void
aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- Scsi_Cmnd *cmd = scb->cmd;
- struct aic_dev_data *aic_dev = cmd->device->hostdata;
- int tindex = TARGET_INDEX(cmd);
- struct aic7xxx_scb *scbp;
- unsigned char queue_depth;
+ struct scsi_cmnd *cmd = scb->cmd;
+ struct aic_dev_data *aic_dev = cmd->device->hostdata;
+ int tindex = TARGET_INDEX(cmd);
+ struct aic7xxx_scb *scbp;
+ unsigned char queue_depth;
if (cmd->use_sg > 1)
{
@@ -2862,7 +2860,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
aic_dev->r_total++;
ptr = aic_dev->r_bins;
}
- if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER)
+ if(cmd->device->simple_tags && cmd->request->cmd_flags & REQ_HARDBARRIER)
{
aic_dev->barrier_total++;
if(scb->tag_action == MSG_ORDERED_Q_TAG)
@@ -2891,7 +2889,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* aic7xxx_run_done_queue
*
* Description:
- * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the
* aborted list, and adds each scb to the free list. If complete
* is TRUE, we also process the commands complete list.
*-F*************************************************************************/
@@ -3826,9 +3824,9 @@ aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
static void
aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_hwscb *hscb;
- Scsi_Cmnd *cmd;
- int actual, i;
+ struct aic7xxx_hwscb *hscb;
+ struct scsi_cmnd *cmd;
+ int actual, i;
cmd = scb->cmd;
hscb = scb->hscb;
@@ -4219,20 +4217,20 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case BAD_STATUS:
{
- unsigned char scb_index;
- struct aic7xxx_hwscb *hscb;
- Scsi_Cmnd *cmd;
-
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencer running in the common case of command completes
- * without error. The sequencer will have DMA'd the SCB back
- * up to us, so we can reference the drivers SCB array.
- *
- * Set the default return value to 0 indicating not to send
- * sense. The sense code will change this if needed and this
- * reduces code duplication.
- */
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ struct scsi_cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
+ *
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
aic_outb(p, 0, RETURN_1);
scb_index = aic_inb(p, SCB_TAG);
if (scb_index > p->scb_data->numscbs)
@@ -5800,9 +5798,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
}
else if ((status & SELTO) != 0)
{
- unsigned char scbptr;
- unsigned char nextscb;
- Scsi_Cmnd *cmd;
+ unsigned char scbptr;
+ unsigned char nextscb;
+ struct scsi_cmnd *cmd;
scbptr = aic_inb(p, WAITING_SCBH);
if (scbptr > p->scb_data->maxhscbs)
@@ -5941,11 +5939,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
/*
* Determine the bus phase and queue an appropriate message.
*/
- char *phase;
- Scsi_Cmnd *cmd;
- unsigned char mesg_out = MSG_NOOP;
- unsigned char lastphase = aic_inb(p, LASTPHASE);
- unsigned char sstat2 = aic_inb(p, SSTAT2);
+ char *phase;
+ struct scsi_cmnd *cmd;
+ unsigned char mesg_out = MSG_NOOP;
+ unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned char sstat2 = aic_inb(p, SSTAT2);
cmd = scb->cmd;
switch (lastphase)
@@ -6248,10 +6246,10 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
static void
aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
{
- struct aic7xxx_scb *scb = NULL;
- struct aic_dev_data *aic_dev;
- Scsi_Cmnd *cmd;
- unsigned char scb_index, tindex;
+ struct aic7xxx_scb *scb = NULL;
+ struct aic_dev_data *aic_dev;
+ struct scsi_cmnd *cmd;
+ unsigned char scb_index, tindex;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
@@ -6347,12 +6345,12 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
* SCSI controller interrupt handler.
*-F*************************************************************************/
static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_isr(void *dev_id)
{
struct aic7xxx_host *p;
unsigned char intstat;
- p = (struct aic7xxx_host *)dev_id;
+ p = dev_id;
/*
* Just a few sanity checks. Make sure that we have an int pending.
@@ -6479,7 +6477,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* anything like it, please inform the Gross Hack Police immediately
*-F*************************************************************************/
static irqreturn_t
-do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+do_aic7xxx_isr(int irq, void *dev_id)
{
unsigned long cpu_flags;
struct aic7xxx_host *p;
@@ -6491,7 +6489,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
p->flags |= AHC_IN_ISR;
do
{
- aic7xxx_isr(irq, dev_id, regs);
+ aic7xxx_isr(dev_id);
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
@@ -10131,9 +10129,8 @@ skip_pci_controller:
* Description:
* Build a SCB.
*-F*************************************************************************/
-static void
-aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
- struct aic7xxx_scb *scb)
+static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
+ struct aic7xxx_scb *scb)
{
unsigned short mask;
struct aic7xxx_hwscb *hscb;
@@ -10158,7 +10155,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
/* We always force TEST_UNIT_READY to untagged */
if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
{
- if (req->flags & REQ_HARDBARRIER)
+ if (req->cmd_flags & REQ_HARDBARRIER)
{
if(sdptr->ordered_tags)
{
@@ -10285,8 +10282,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* Description:
* Queue a SCB to the controller.
*-F*************************************************************************/
-static int
-aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
@@ -10319,11 +10315,11 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
}
scb->cmd = cmd;
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
- * is set up properly, and the parity error flag is reset, then send
- * the SCB to the sequencer and watch the fun begin.
- */
+ /*
+ * Make sure the scsi_cmnd pointer is saved, the struct it points to
+ * is set up properly, and the parity error flag is reset, then send
+ * the SCB to the sequencer and watch the fun begin.
+ */
aic7xxx_position(cmd) = scb->hscb->tag;
cmd->scsi_done = fn;
cmd->result = DID_OK;
@@ -10356,8 +10352,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
* aborted, then we will reset the channel and have all devices renegotiate.
* Returns an enumerated type that indicates the status of the operation.
*-F*************************************************************************/
-static int
-__aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
@@ -10382,7 +10377,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
hscb = scb->hscb;
- aic7xxx_isr(p->irq, (void *)p, NULL);
+ aic7xxx_isr(p);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
@@ -10550,8 +10545,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
return SUCCESS;
}
-static int
-aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
{
int rc;
@@ -10570,8 +10564,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
* Description:
* Abort the current SCSI command(s).
*-F*************************************************************************/
-static void
-aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
{
printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
@@ -10595,8 +10588,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
* Description:
* Abort the current SCSI command(s).
*-F*************************************************************************/
-static int
-__aic7xxx_abort(Scsi_Cmnd *cmd)
+static int __aic7xxx_abort(struct scsi_cmnd *cmd)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
@@ -10616,7 +10608,7 @@ __aic7xxx_abort(Scsi_Cmnd *cmd)
else
return FAILED;
- aic7xxx_isr(p->irq, (void *)p, NULL);
+ aic7xxx_isr(p);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
@@ -10813,8 +10805,7 @@ success:
return SUCCESS;
}
-static int
-aic7xxx_abort(Scsi_Cmnd *cmd)
+static int aic7xxx_abort(struct scsi_cmnd *cmd)
{
int rc;
@@ -10836,8 +10827,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
* DEVICE RESET message - on the offending target before pulling
* the SCSI bus reset line.
*-F*************************************************************************/
-static int
-aic7xxx_reset(Scsi_Cmnd *cmd)
+static int aic7xxx_reset(struct scsi_cmnd *cmd)
{
struct aic7xxx_scb *scb;
struct aic7xxx_host *p;
@@ -10873,7 +10863,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd)
while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
- aic7xxx_isr(p->irq, p, (void *)NULL );
+ aic7xxx_isr(p);
pause_sequencer(p);
}
aic7xxx_done_cmds_complete(p);
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
index 0ed391d8ee8..c83fe751d0b 100644
--- a/drivers/scsi/aic94xx/Kconfig
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -28,6 +28,7 @@ config SCSI_AIC94XX
tristate "Adaptec AIC94xx SAS/SATA support"
depends on PCI
select SCSI_SAS_LIBSAS
+ select FW_LOADER
help
This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
AIC94xx chip based host adapters.
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 71a031df7a3..32f513b1b78 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -56,8 +56,8 @@
/* 2*ITNL timeout + 1 second */
#define AIC94XX_SCB_TIMEOUT (5*HZ)
-extern kmem_cache_t *asd_dma_token_cache;
-extern kmem_cache_t *asd_ascb_cache;
+extern struct kmem_cache *asd_dma_token_cache;
+extern struct kmem_cache *asd_ascb_cache;
extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 1d8c5e5f442..da94e126ca8 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -112,6 +112,21 @@ static int asd_init_phy(struct asd_phy *phy)
return 0;
}
+static void asd_init_ports(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ spin_lock_init(&asd_ha->asd_ports_lock);
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ struct asd_port *asd_port = &asd_ha->asd_ports[i];
+
+ memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE);
+ memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ asd_port->phy_mask = 0;
+ asd_port->num_phys = 0;
+ }
+}
+
static int asd_init_phys(struct asd_ha_struct *asd_ha)
{
u8 i;
@@ -121,6 +136,7 @@ static int asd_init_phys(struct asd_ha_struct *asd_ha)
struct asd_phy *phy = &asd_ha->phys[i];
phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
+ phy->asd_port = NULL;
phy->sas_phy.enabled = 0;
phy->sas_phy.id = i;
@@ -658,6 +674,8 @@ int asd_init_hw(struct asd_ha_struct *asd_ha)
goto Out;
}
+ asd_init_ports(asd_ha);
+
err = asd_init_scbs(asd_ha);
if (err) {
asd_printk("couldn't initialize scbs for %s\n",
@@ -996,11 +1014,10 @@ static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
* asd_hw_isr -- host adapter interrupt service routine
* @irq: ignored
* @dev_id: pointer to host adapter structure
- * @regs: ignored
*
* The ISR processes done list entries and level 3 error handling.
*/
-irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t asd_hw_isr(int irq, void *dev_id)
{
struct asd_ha_struct *asd_ha = dev_id;
u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
@@ -1030,7 +1047,7 @@ irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
gfp_t gfp_flags)
{
- extern kmem_cache_t *asd_ascb_cache;
+ extern struct kmem_cache *asd_ascb_cache;
struct asd_seq_data *seq = &asd_ha->seq;
struct asd_ascb *ascb;
unsigned long flags;
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 8498144aa5e..c6c3d18222f 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -46,6 +46,7 @@
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
@@ -192,6 +193,16 @@ struct asd_seq_data {
struct asd_ascb **escb_arr; /* array of pointers to escbs */
};
+/* This is an internal port structure. These are used to get accurate
+ * phy_mask for updating DDB 0.
+ */
+struct asd_port {
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 attached_sas_addr[SAS_ADDR_SIZE];
+ u32 phy_mask;
+ int num_phys;
+};
+
/* This is the Host Adapter structure. It describes the hardware
* SAS adapter.
*/
@@ -210,6 +221,8 @@ struct asd_ha_struct {
struct hw_profile hw_prof;
struct asd_phy phys[ASD_MAX_PHYS];
+ spinlock_t asd_ports_lock;
+ struct asd_port asd_ports[ASD_MAX_PHYS];
struct asd_sas_port ports[ASD_MAX_PHYS];
struct dma_pool *scb_pool;
@@ -371,7 +384,7 @@ static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
/* ---------- Function declarations ---------- */
int asd_init_hw(struct asd_ha_struct *asd_ha);
-irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t asd_hw_isr(int irq, void *dev_id);
struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index ee2ccad7048..fbc82b00a41 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -310,11 +309,29 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
}
static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
-static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
{
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ int err;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ if (err)
+ return err;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ if (err)
+ goto err_rev;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ if (err)
+ goto err_biosb;
+
+ return 0;
+
+err_biosb:
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+err_rev:
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ return err;
}
static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
@@ -433,8 +450,8 @@ static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
asd_ha->scb_pool = NULL;
}
-kmem_cache_t *asd_dma_token_cache;
-kmem_cache_t *asd_ascb_cache;
+struct kmem_cache *asd_dma_token_cache;
+struct kmem_cache *asd_ascb_cache;
static int asd_create_global_caches(void)
{
@@ -646,7 +663,9 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
}
ASD_DPRINTK("escbs posted\n");
- asd_create_dev_attrs(asd_ha);
+ err = asd_create_dev_attrs(asd_ha);
+ if (err)
+ goto Err_dev_attrs;
err = asd_register_sas_ha(asd_ha);
if (err)
@@ -669,6 +688,7 @@ Err_en_phys:
asd_unregister_sas_ha(asd_ha);
Err_reg_sas:
asd_remove_dev_attrs(asd_ha);
+Err_dev_attrs:
Err_escbs:
asd_disable_ints(asd_ha);
free_irq(dev->irq, asd_ha);
@@ -704,6 +724,15 @@ static void asd_free_queues(struct asd_ha_struct *asd_ha)
list_for_each_safe(pos, n, &pending) {
struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+ /*
+ * Delete unexpired ascb timers. This may happen if we issue
+ * a CONTROL PHY scb to an adapter and rmmod before the scb
+ * times out. Apparently we don't wait for the CONTROL PHY
+ * to complete, so it doesn't matter if we kill the timer.
+ */
+ del_timer_sync(&ascb->timer);
+ WARN_ON(ascb->scb->header.opcode != CONTROL_PHY);
+
list_del_init(pos);
ASD_DPRINTK("freeing from pending\n");
asd_ascb_free(ascb);
@@ -755,9 +784,9 @@ static ssize_t asd_version_show(struct device_driver *driver, char *buf)
}
static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
-static void asd_create_driver_attrs(struct device_driver *driver)
+static int asd_create_driver_attrs(struct device_driver *driver)
{
- driver_create_file(driver, &driver_attr_version);
+ return driver_create_file(driver, &driver_attr_version);
}
static void asd_remove_driver_attrs(struct device_driver *driver)
@@ -766,8 +795,6 @@ static void asd_remove_driver_attrs(struct device_driver *driver)
}
static struct sas_domain_function_template aic94xx_transport_functions = {
- .lldd_port_formed = asd_update_port_links,
-
.lldd_dev_found = asd_dev_found,
.lldd_dev_gone = asd_dev_gone,
@@ -794,6 +821,8 @@ static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
0, 0, 1},
{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
+ 0, 0, 1},
{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
0, 0, 2},
{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
@@ -835,10 +864,14 @@ static int __init aic94xx_init(void)
if (err)
goto out_release_transport;
- asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+ err = asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+ if (err)
+ goto out_unregister_pcidrv;
return err;
+ out_unregister_pcidrv:
+ pci_unregister_driver(&aic94xx_pci_driver);
out_release_transport:
sas_release_transport(aic94xx_transport_template);
out_destroy_caches:
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
index b79f45f3ad4..a11f4e6d8bd 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg_def.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -2000,7 +2000,7 @@
* The host accesses this scratch in a different manner from the
* central sequencer. The sequencer has to use CSEQ registers CSCRPAGE
* and CMnSCRPAGE to access the scratch memory. A flat mapping of the
- * scratch memory is avaliable for software convenience and to prevent
+ * scratch memory is available for software convenience and to prevent
* corruption while the sequencer is running. This memory is mapped
* onto addresses 800h - BFFh, total of 400h bytes.
*
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 64d23171234..9050e93bfd5 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -733,6 +733,7 @@ struct asd_phy {
struct sas_identify_frame *identify_frame;
struct asd_dma_tok *id_frm_tok;
+ struct asd_port *asd_port;
u8 frame_rcvd[ASD_EDB_SIZE];
};
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 7ee49b51b72..75ed6b0569d 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -25,6 +25,7 @@
*/
#include <linux/pci.h>
+#include <scsi/scsi_host.h>
#include "aic94xx.h"
#include "aic94xx_reg.h"
@@ -168,6 +169,70 @@ static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
}
}
+static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
+{
+ int i;
+ struct asd_port *free_port = NULL;
+ struct asd_port *port;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
+ if (!phy->asd_port) {
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ port = &asd_ha->asd_ports[i];
+
+ /* Check for wide port */
+ if (port->num_phys > 0 &&
+ memcmp(port->sas_addr, sas_phy->sas_addr,
+ SAS_ADDR_SIZE) == 0 &&
+ memcmp(port->attached_sas_addr,
+ sas_phy->attached_sas_addr,
+ SAS_ADDR_SIZE) == 0) {
+ break;
+ }
+
+ /* Find a free port */
+ if (port->num_phys == 0 && free_port == NULL) {
+ free_port = port;
+ }
+ }
+
+ /* Use a free port if this doesn't form a wide port */
+ if (i >= ASD_MAX_PHYS) {
+ port = free_port;
+ BUG_ON(!port);
+ memcpy(port->sas_addr, sas_phy->sas_addr,
+ SAS_ADDR_SIZE);
+ memcpy(port->attached_sas_addr,
+ sas_phy->attached_sas_addr,
+ SAS_ADDR_SIZE);
+ }
+ port->num_phys++;
+ port->phy_mask |= (1U << sas_phy->id);
+ phy->asd_port = port;
+ }
+ ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
+ __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
+ asd_update_port_links(asd_ha, phy);
+ spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
+}
+
+static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
+{
+ struct asd_port *port = phy->asd_port;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
+ if (port) {
+ port->num_phys--;
+ port->phy_mask &= ~(1U << sas_phy->id);
+ phy->asd_port = NULL;
+ }
+ spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
+}
+
static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
struct done_list_struct *dl,
int edb_id, int phy_id)
@@ -187,6 +252,7 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
asd_dump_frame_rcvd(phy, dl);
+ asd_form_port(ascb->ha, phy);
sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
}
@@ -197,6 +263,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
struct asd_ha_struct *asd_ha = ascb->ha;
struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
u8 lr_error = dl->status_block[1];
u8 retries_left = dl->status_block[2];
@@ -221,6 +288,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
asd_turn_led(asd_ha, phy_id, 0);
sas_phy_disconnected(sas_phy);
+ asd_deform_port(asd_ha, phy);
sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
if (retries_left == 0) {
@@ -248,6 +316,8 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
unsigned long flags;
struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
u8 reg = dl->status_block[1];
u32 cont = dl->status_block[2] << ((reg & 3)*8);
@@ -284,6 +354,7 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
phy_id);
/* The sequencer disables all phys on that port.
* We have to re-enable the phys ourselves. */
+ asd_deform_port(asd_ha, phy);
sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
break;
@@ -342,6 +413,40 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
}
}
+/* hard reset a phy later */
+static void do_phy_reset_later(struct work_struct *work)
+{
+ struct sas_phy *sas_phy =
+ container_of(work, struct sas_phy, reset_work);
+ int error;
+
+ ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
+ sas_phy->identify.phy_identifier);
+ /* Reset device port */
+ error = sas_phy_reset(sas_phy, 1);
+ if (error)
+ ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
+ __FUNCTION__, sas_phy->identify.phy_identifier, error);
+}
+
+static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
+{
+ INIT_WORK(&sas_phy->reset_work, do_phy_reset_later);
+ queue_work(shost->work_q, &sas_phy->reset_work);
+}
+
+/* start up the ABORT TASK tmf... */
+static void task_kill_later(struct asd_ascb *ascb)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_task *task = ascb->uldd_task;
+
+ INIT_WORK(&task->abort_work, sas_task_abort);
+ queue_work(shost->work_q, &task->abort_work);
+}
+
static void escb_tasklet_complete(struct asd_ascb *ascb,
struct done_list_struct *dl)
{
@@ -351,6 +456,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
u8 sb_opcode = dl->status_block[0];
int phy_id = sb_opcode & DL_PHY_MASK;
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
if (edb > 6 || edb < 0) {
ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
@@ -368,6 +474,74 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
ascb->scb->header.opcode);
}
+ /* Catch these before we mask off the sb_opcode bits */
+ switch (sb_opcode) {
+ case REQ_TASK_ABORT: {
+ struct asd_ascb *a, *b;
+ u16 tc_abort;
+
+ tc_abort = *((u16*)(&dl->status_block[1]));
+ tc_abort = le16_to_cpu(tc_abort);
+
+ ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
+ __FUNCTION__, dl->status_block[3]);
+
+ /* Find the pending task and abort it. */
+ list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
+ if (a->tc_index == tc_abort) {
+ task_kill_later(a);
+ break;
+ }
+ goto out;
+ }
+ case REQ_DEVICE_RESET: {
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_phy *dev_phy;
+ struct asd_ascb *a;
+ u16 conn_handle;
+
+ conn_handle = *((u16*)(&dl->status_block[1]));
+ conn_handle = le16_to_cpu(conn_handle);
+
+ ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
+ dl->status_block[3]);
+
+ /* Kill all pending tasks and reset the device */
+ dev_phy = NULL;
+ list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
+ struct sas_task *task;
+ struct domain_device *dev;
+ u16 x;
+
+ task = a->uldd_task;
+ if (!task)
+ continue;
+ dev = task->dev;
+
+ x = (unsigned long)dev->lldd_dev;
+ if (x == conn_handle) {
+ dev_phy = dev->port->phy;
+ task_kill_later(a);
+ }
+ }
+
+ /* Reset device port */
+ if (!dev_phy) {
+ ASD_DPRINTK("%s: No pending commands; can't reset.\n",
+ __FUNCTION__);
+ goto out;
+ }
+ phy_reset_later(dev_phy, shost);
+ goto out;
+ }
+ case SIGNAL_NCQ_ERROR:
+ ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
+ goto out;
+ case CLEAR_NCQ_ERROR:
+ ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
+ goto out;
+ }
+
sb_opcode &= ~DL_PHY_MASK;
switch (sb_opcode) {
@@ -395,24 +569,9 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
asd_turn_led(asd_ha, phy_id, 0);
/* the device is gone */
sas_phy_disconnected(sas_phy);
+ asd_deform_port(asd_ha, phy);
sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
break;
- case REQ_TASK_ABORT:
- ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
- phy_id);
- break;
- case REQ_DEVICE_RESET:
- ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
- phy_id);
- break;
- case SIGNAL_NCQ_ERROR:
- ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
- phy_id);
- break;
- case CLEAR_NCQ_ERROR:
- ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
- phy_id);
- break;
default:
ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
phy_id, sb_opcode);
@@ -432,7 +591,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
break;
}
-
+out:
asd_invalidate_edb(ascb, edb);
}
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index 83574b5b4e6..e5a0ec37e95 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -64,7 +64,7 @@ struct asd_ocm_dir {
#define OCM_INIT_DIR_ENTRIES 5
/***************************************************************************
-* OCM dircetory default
+* OCM directory default
***************************************************************************/
static struct asd_ocm_dir OCMDirInit =
{
@@ -73,7 +73,7 @@ static struct asd_ocm_dir OCMDirInit =
};
/***************************************************************************
-* OCM dircetory Entries default
+* OCM directory Entries default
***************************************************************************/
static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
{
@@ -630,10 +630,6 @@ static int asd_flash_getid(struct asd_ha_struct *asd_ha)
reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
- if (!(reg & FLASHEX)) {
- ASD_DPRINTK("flash doesn't exist\n");
- return -ENOENT;
- }
if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
&asd_ha->hw_prof.flash.bar)) {
asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 56e4b3ba6a0..845112539d0 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1369,10 +1369,9 @@ int asd_start_seqs(struct asd_ha_struct *asd_ha)
* port_map_by_links is also used as the conn_mask byte in the
* initiator/target port DDB.
*/
-void asd_update_port_links(struct asd_sas_phy *sas_phy)
+void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
{
- struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
- const u8 phy_mask = (u8) sas_phy->port->phy_mask;
+ const u8 phy_mask = (u8) phy->asd_port->phy_mask;
u8 phy_is_up;
u8 mask;
int i, err;
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
index 42281c36153..9e715e5496a 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.h
+++ b/drivers/scsi/aic94xx/aic94xx_seq.h
@@ -64,7 +64,7 @@ int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
int asd_init_seqs(struct asd_ha_struct *asd_ha);
int asd_start_seqs(struct asd_ha_struct *asd_ha);
-void asd_update_port_links(struct asd_sas_phy *phy);
+void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy);
#endif
#endif
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index 1b637592d5a..7cd63a99688 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -8,7 +8,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 475f978ff8f..086cc97eee8 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -147,8 +147,7 @@ static struct pci_driver arcmsr_pci_driver = {
.shutdown = arcmsr_shutdown
};
-static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
struct AdapterControlBlock *acb;
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 7621e3fa37b..9cf902b7a12 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -194,7 +194,8 @@
unsigned int sdtr_period = SDTR_PERIOD;
unsigned int sdtr_size = SDTR_SIZE;
-static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
+ unsigned int result);
static int acornscsi_reconnect_finish(AS_Host *host);
static void acornscsi_dma_cleanup(AS_Host *host);
static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
@@ -712,7 +713,7 @@ static
intr_ret_t acornscsi_kick(AS_Host *host)
{
int from_queue = 0;
- Scsi_Cmnd *SCpnt;
+ struct scsi_cmnd *SCpnt;
/* first check to see if a command is waiting to be executed */
SCpnt = host->origSCpnt;
@@ -796,15 +797,15 @@ intr_ret_t acornscsi_kick(AS_Host *host)
}
/*
- * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result)
* Purpose : complete processing for command
* Params : host - interface that completed
* result - driver byte of result
*/
-static
-void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
+ unsigned int result)
{
- Scsi_Cmnd *SCpnt = *SCpntp;
+ struct scsi_cmnd *SCpnt = *SCpntp;
/* clean up */
sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
@@ -1318,7 +1319,7 @@ acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int
static void
acornscsi_sendcommand(AS_Host *host)
{
- Scsi_Cmnd *SCpnt = host->SCpnt;
+ struct scsi_cmnd *SCpnt = host->SCpnt;
sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
sbic_arm_writenext(host->scsi.io_port, 0);
@@ -1693,7 +1694,7 @@ void acornscsi_message(AS_Host *host)
acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
} else {
- Scsi_Cmnd *SCpnt = host->SCpnt;
+ struct scsi_cmnd *SCpnt = host->SCpnt;
acornscsi_dma_cleanup(host);
@@ -2460,14 +2461,13 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
}
/*
- * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+ * Prototype: void acornscsi_intr(int irq, void *dev_id)
* Purpose : handle interrupts from Acorn SCSI card
* Params : irq - interrupt number
* dev_id - device specific data (AS_Host structure)
- * regs - processor registers when interrupt occurred
*/
static irqreturn_t
-acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+acornscsi_intr(int irq, void *dev_id)
{
AS_Host *host = (AS_Host *)dev_id;
intr_ret_t ret;
@@ -2509,13 +2509,14 @@ acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
*/
/*
- * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* Purpose : queues a SCSI command
* Params : cmd - SCSI command
* done - function called on completion, with pointer to command descriptor
* Returns : 0, or < 0 on error.
*/
-int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
@@ -2565,17 +2566,18 @@ int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
}
/*
- * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
* Params : SCpntp1 - pointer to command to return
* SCpntp2 - pointer to command to check
* result - result to pass back to mid-level done function
* Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
*/
-static inline
-void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1,
+ struct scsi_cmnd **SCpntp2,
+ int result)
{
- Scsi_Cmnd *SCpnt = *SCpntp1;
+ struct scsi_cmnd *SCpnt = *SCpntp1;
if (SCpnt) {
*SCpntp1 = NULL;
@@ -2591,13 +2593,12 @@ void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result
enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
/*
- * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
+ * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort a command on this host
* Params : SCpnt - command to abort
* Returns : our abort status
*/
-static enum res_abort
-acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
+static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt)
{
enum res_abort res = res_not_running;
@@ -2684,12 +2685,12 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
}
/*
- * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort a command on this host
* Params : SCpnt - command to abort
* Returns : one of SCSI_ABORT_ macros
*/
-int acornscsi_abort(Scsi_Cmnd *SCpnt)
+int acornscsi_abort(struct scsi_cmnd *SCpnt)
{
AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
int result;
@@ -2770,16 +2771,16 @@ int acornscsi_abort(Scsi_Cmnd *SCpnt)
}
/*
- * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
* Purpose : reset a command on this host/reset this host
* Params : SCpnt - command causing reset
* result - what type of reset to perform
* Returns : one of SCSI_RESET_ macros
*/
-int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
{
- AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
- Scsi_Cmnd *SCptr;
+ AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+ struct scsi_cmnd *SCptr;
host->stats.resets += 1;
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
index 2142290f840..d11424b89f4 100644
--- a/drivers/scsi/arm/acornscsi.h
+++ b/drivers/scsi/arm/acornscsi.h
@@ -277,8 +277,8 @@ struct status_entry {
typedef struct acornscsi_hostdata {
/* miscellaneous */
struct Scsi_Host *host; /* host */
- Scsi_Cmnd *SCpnt; /* currently processing command */
- Scsi_Cmnd *origSCpnt; /* original connecting command */
+ struct scsi_cmnd *SCpnt; /* currently processing command */
+ struct scsi_cmnd *origSCpnt; /* original connecting command */
/* driver information */
struct {
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index a2894015670..4385e9e3ded 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/drivers/scsi/arxescsi.c
+ * linux/drivers/scsi/arm/arxescsi.c
*
* Copyright (C) 1997-2000 Russell King, Stefan Hanske
*
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 719af0dcc0e..19edd9c853d 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -137,10 +137,9 @@ cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from Cumana SCSI 2 card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
static irqreturn_t
-cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
+cumanascsi_2_intr(int irq, void *dev_id)
{
struct cumanascsi2_info *info = dev_id;
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index dcbb4b2b3fe..3f876fb7546 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -138,10 +138,9 @@ eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from EESOX SCSI card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
static irqreturn_t
-eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+eesoxscsi_intr(int irq, void *dev_id)
{
struct eesoxscsi_info *info = dev_id;
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 4cf7afc31cc..e05f0c2fc91 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -297,8 +297,8 @@ fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
printk("scsi%d.%c: %s", info->host->host_no, target, buf);
}
-static void
-fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
+static void fas216_log_command(FAS216_Info *info, int level,
+ struct scsi_cmnd *SCpnt, char *fmt, ...)
{
va_list args;
@@ -1662,7 +1662,7 @@ irqreturn_t fas216_intr(FAS216_Info *info)
return handled;
}
-static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
int tot_msglen;
@@ -1754,7 +1754,7 @@ static int parity_test(FAS216_Info *info, int target)
return info->device[target].parity_check;
}
-static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
int disconnect_ok;
@@ -1808,7 +1808,7 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
__fas216_start_command(info, SCpnt);
}
-static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
#ifdef SCSI2_TAG
/*
@@ -1842,7 +1842,8 @@ static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
}
}
-static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_do_bus_device_reset(FAS216_Info *info,
+ struct scsi_cmnd *SCpnt)
{
struct message *msg;
@@ -1890,7 +1891,7 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
*/
static void fas216_kick(FAS216_Info *info)
{
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
#define TYPE_OTHER 0
#define TYPE_RESET 1
#define TYPE_QUEUE 2
@@ -1978,8 +1979,8 @@ static void fas216_kick(FAS216_Info *info)
/*
* Clean up from issuing a BUS DEVICE RESET message to a device.
*/
-static void
-fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
+ unsigned int result)
{
fas216_log(info, LOG_ERROR, "fas216 device reset complete");
@@ -1996,8 +1997,8 @@ fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result
*
* Finish processing automatic request sense command
*/
-static void
-fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
+ unsigned int result)
{
fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
"request sense complete, result=0x%04x%02x%02x",
@@ -2030,7 +2031,7 @@ fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
* Finish processing of standard command
*/
static void
-fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
{
info->stats.fins += 1;
@@ -2142,8 +2143,8 @@ request_sense:
*/
static void fas216_done(FAS216_Info *info, unsigned int result)
{
- void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
- Scsi_Cmnd *SCpnt;
+ void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int);
+ struct scsi_cmnd *SCpnt;
unsigned long flags;
fas216_checkmagic(info);
@@ -2182,7 +2183,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
info->device[SCpnt->device->id].parity_check = 0;
clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
- fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+ fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
fn(info, SCpnt, result);
if (info->scsi.irq != NO_IRQ) {
@@ -2207,7 +2208,8 @@ no_command:
* Returns: 0 on success, else error.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int fas216_queue_command(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
int result;
@@ -2254,7 +2256,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
*
* Trigger restart of a waiting thread in fas216_command
*/
-static void fas216_internal_done(Scsi_Cmnd *SCpnt)
+static void fas216_internal_done(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2271,7 +2273,8 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
* Returns: scsi result code.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2350,7 +2353,8 @@ enum res_find {
* Decide how to abort a command.
* Returns: abort status
*/
-static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static enum res_find fas216_find_command(FAS216_Info *info,
+ struct scsi_cmnd *SCpnt)
{
enum res_find res = res_failed;
@@ -2417,7 +2421,7 @@ static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
* Returns: FAILED if unable to abort
* Notes: io_request_lock is taken, and irqs are disabled
*/
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+int fas216_eh_abort(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
int result = FAILED;
@@ -2474,7 +2478,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
* Notes: We won't be re-entered, so we'll only have one device
* reset on the go at one time.
*/
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
unsigned long flags;
@@ -2555,7 +2559,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
* Returns: FAILED if unable to reset.
* Notes: Further commands are blocked.
*/
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
unsigned long flags;
@@ -2655,7 +2659,7 @@ static void fas216_init_chip(FAS216_Info *info)
* Returns: FAILED if unable to reset.
* Notes: io_request_lock is taken, and irqs are disabled
*/
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index 540914d6fd3..00e5f055afd 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -218,11 +218,11 @@ typedef struct {
unsigned long magic_start;
spinlock_t host_lock;
struct Scsi_Host *host; /* host */
- Scsi_Cmnd *SCpnt; /* currently processing command */
- Scsi_Cmnd *origSCpnt; /* original connecting command */
- Scsi_Cmnd *reqSCpnt; /* request sense command */
- Scsi_Cmnd *rstSCpnt; /* reset command */
- Scsi_Cmnd *pending_SCpnt[8]; /* per-device pending commands */
+ struct scsi_cmnd *SCpnt; /* currently processing command */
+ struct scsi_cmnd *origSCpnt; /* original connecting command */
+ struct scsi_cmnd *reqSCpnt; /* request sense command */
+ struct scsi_cmnd *rstSCpnt; /* reset command */
+ struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */
int next_pending; /* next pending device */
/*
@@ -328,21 +328,23 @@ extern int fas216_init (struct Scsi_Host *instance);
*/
extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
-/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* Purpose : queue a command for adapter to process.
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
*/
-extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int fas216_queue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
-/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* Purpose : queue a command for adapter to process, and process it to completion.
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
*/
-extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int fas216_noqueue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
* Purpose : handle interrupts from the interface to progress a command
@@ -363,32 +365,32 @@ 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);
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort this command
* Params : SCpnt - command to abort
* Returns : FAILED if unable to abort
*/
-extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_abort(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the device associated with this command
* Params : SCpnt - command specifing device to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the complete bus associated with this command
* Params : SCpnt - command specifing bus to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the host associated with this command
* Params : SCpnt - command specifing host to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt);
#endif /* FAS216_H */
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index b2c346a4705..ce159c15bc8 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -112,10 +112,8 @@ powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from Powertec SCSI card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
-static irqreturn_t
-powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t powertecscsi_intr(int irq, void *dev_id)
{
struct powertec_info *info = dev_id;
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
index 8caa5903ce3..cb11ccef54e 100644
--- a/drivers/scsi/arm/queue.c
+++ b/drivers/scsi/arm/queue.c
@@ -29,7 +29,7 @@
typedef struct queue_entry {
struct list_head list;
- Scsi_Cmnd *SCpnt;
+ struct scsi_cmnd *SCpnt;
#ifdef DEBUG
unsigned long magic;
#endif
@@ -96,14 +96,14 @@ void queue_free (Queue_t *queue)
/*
- * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
* Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
* Params : queue - destination queue
* SCpnt - command to add
* head - add command to head of queue
* Returns : 0 on error, !0 on success
*/
-int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
{
unsigned long flags;
struct list_head *l;
@@ -134,7 +134,7 @@ empty:
return ret;
}
-static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
+static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
{
QE_t *q;
@@ -152,17 +152,17 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
}
/*
- * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
+ * Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude)
* Purpose : remove a SCSI command from a queue
* Params : queue - queue to remove command from
* exclude - bit array of target&lun which is busy
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
+struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
{
unsigned long flags;
struct list_head *l;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
list_for_each(l, &queue->head) {
@@ -178,15 +178,15 @@ Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
}
/*
- * Function: Scsi_Cmnd *queue_remove (queue)
+ * Function: struct scsi_cmnd *queue_remove (queue)
* Purpose : removes first SCSI command from a queue
* Params : queue - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-Scsi_Cmnd *queue_remove(Queue_t *queue)
+struct scsi_cmnd *queue_remove(Queue_t *queue)
{
unsigned long flags;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
if (!list_empty(&queue->head))
@@ -197,19 +197,20 @@ Scsi_Cmnd *queue_remove(Queue_t *queue)
}
/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
* Params : queue - queue to remove command from
* target - target that we want
* lun - lun on device
* tag - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
*/
-Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
+struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun,
+ int tag)
{
unsigned long flags;
struct list_head *l;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
list_for_each(l, &queue->head) {
@@ -275,13 +276,13 @@ int queue_probetgtlun (Queue_t *queue, int target, int lun)
}
/*
- * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
* Purpose : remove a specific command from the queues
* Params : queue - queue to look in
* SCpnt - command to find
* Returns : 0 if not found
*/
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
{
unsigned long flags;
struct list_head *l;
diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
index 0c9dec4c171..3c519c9237b 100644
--- a/drivers/scsi/arm/queue.h
+++ b/drivers/scsi/arm/queue.h
@@ -32,46 +32,48 @@ extern int queue_initialise (Queue_t *queue);
extern void queue_free (Queue_t *queue);
/*
- * Function: Scsi_Cmnd *queue_remove (queue)
+ * Function: struct scsi_cmnd *queue_remove (queue)
* Purpose : removes first SCSI command from a queue
* Params : queue - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-extern Scsi_Cmnd *queue_remove (Queue_t *queue);
+extern struct scsi_cmnd *queue_remove (Queue_t *queue);
/*
- * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
+ * Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude)
* Purpose : remove a SCSI command from a queue
* Params : queue - queue to remove command from
* exclude - array of busy LUNs
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
+extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue,
+ unsigned long *exclude);
#define queue_add_cmd_ordered(queue,SCpnt) \
__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
#define queue_add_cmd_tail(queue,SCpnt) \
__queue_add(queue,SCpnt,0)
/*
- * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
* Purpose : Add a new command onto a queue
* Params : queue - destination queue
* SCpnt - command to add
* head - add command to head of queue
* Returns : 0 on error, !0 on success
*/
-extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
+extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head);
/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
* Params : queue - queue to remove command from
* target - target that we want
* lun - lun on device
* tag - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
*/
-extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
+extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target,
+ int lun, int tag);
/*
* Function: queue_remove_all_target(queue, target)
@@ -94,12 +96,12 @@ extern void queue_remove_all_target(Queue_t *queue, int target);
extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
/*
- * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt)
* Purpose : remove a specific command from the queues
* Params : queue - queue to look in
* SCpnt - command to find
* Returns : 0 if not found
*/
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
+int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt);
#endif /* QUEUE_H */
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 8c2600ffc6a..3a39579bd08 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -66,7 +66,7 @@ static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
SCp->this_residual -= 1;
}
-static inline void init_SCp(Scsi_Cmnd *SCpnt)
+static inline void init_SCp(struct scsi_cmnd *SCpnt)
{
memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index e397129c90d..0f920c84ac0 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1262,7 +1262,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance )
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr (int irq, void *dev_id)
{
struct Scsi_Host *instance = first_instance;
int done = 1, handled = 0;
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
index 8d5d2a5da96..cdc710ea00f 100644
--- a/drivers/scsi/atari_dma_emul.c
+++ b/drivers/scsi/atari_dma_emul.c
@@ -110,7 +110,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr)
}
/*
- * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+ * void hades_dma_emulator(int irq, void *dummy)
*
* This code emulates TT SCSI DMA on the Hades.
*
@@ -140,7 +140,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr)
* increased with one.
*/
-static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t hades_dma_emulator(int irq, void *dummy)
{
unsigned long dma_base;
register unsigned long dma_cnt asm ("d3");
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index e1be4a4387c..dfb1bcfae82 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -194,8 +194,8 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd );
static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
Scsi_Cmnd *cmd, int write_flag );
#endif
-static irqreturn_t scsi_tt_intr( int irq, void *dummy, struct pt_regs *fp);
-static irqreturn_t scsi_falcon_intr( int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_tt_intr( int irq, void *dummy);
+static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
hostdata );
static void falcon_get_lock( void );
@@ -285,7 +285,7 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
* to clear the DMA int pending bit before it allows other level 6 interrupts.
*/
-static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
+static void scsi_dma_buserr (int irq, void *dummy)
{
unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
@@ -314,7 +314,7 @@ static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
#endif
-static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_tt_intr (int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -406,7 +406,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
}
-static irqreturn_t scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 0ec41f34f46..fec58cc47f1 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -44,7 +44,7 @@ static void send_s870(struct atp_unit *dev,unsigned char c);
static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
static void tscam_885(void);
-static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
unsigned short int tmpcip, id;
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
index 7c9c0366cc0..ea3e4b2b922 100644
--- a/drivers/scsi/bvme6000.h
+++ b/drivers/scsi/bvme6000.h
@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index ff2b1796fa3..e95b367d09e 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1219,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
srb, srb->cmd, srb->cmd->pid,
srb->cmd->cmnd[0], srb->cmd->device->id,
srb->cmd->device->lun);
- printk(" sglist=%p cnt=%i idx=%i len=%i\n",
+ printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
srb->segment_x, srb->sg_count, srb->sg_index,
srb->total_xfer_length);
printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
@@ -1813,10 +1813,9 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
}
-static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
{
- struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
+ struct AdapterCtlBlk *acb = dev_id;
u16 scsi_status;
u8 dma_status;
irqreturn_t handled = IRQ_NONE;
@@ -4949,7 +4948,7 @@ static struct pci_driver dc395x_driver = {
**/
static int __init dc395x_module_init(void)
{
- return pci_module_init(&dc395x_driver);
+ return pci_register_driver(&dc395x_driver);
}
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index eb32062f7e6..c29ccbc4469 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -94,9 +94,9 @@ volatile unsigned char pmaz_cmd_buffer[16];
* via PIO.
*/
-static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *);
-static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *);
-static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *);
+static irqreturn_t scsi_dma_merr_int(int, void *);
+static irqreturn_t scsi_dma_err_int(int, void *);
+static irqreturn_t scsi_dma_int(int, void *);
static int dec_esp_detect(struct scsi_host_template * tpnt);
@@ -307,7 +307,7 @@ err_dealloc:
}
/************************************************************* DMA Functions */
-static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
{
printk("Got unexpected SCSI DMA Interrupt! < ");
printk("SCSI_DMA_MEMRDERR ");
@@ -316,14 +316,14 @@ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs
return IRQ_HANDLED;
}
-static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_err_int(int irq, void *dev_id)
{
/* empty */
return IRQ_HANDLED;
}
-static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_int(int irq, void *dev_id)
{
u32 scsi_next_ptr;
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 879a2665767..fa738ec8692 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -155,7 +155,7 @@ static struct pci_driver dmx3191d_pci_driver = {
static int __init dmx3191d_init(void)
{
- return pci_module_init(&dmx3191d_pci_driver);
+ return pci_register_driver(&dmx3191d_pci_driver);
}
static void __exit dmx3191d_exit(void)
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index d84a281ad94..5a49216fe4c 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -47,21 +47,11 @@
* I2O Interface Objects
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-
-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-
-typedef struct wait_queue *adpt_wait_queue_head_t;
-#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL
-typedef struct wait_queue adpt_wait_queue_t;
-#else
-
#include <linux/wait.h>
typedef wait_queue_head_t adpt_wait_queue_head_t;
-#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait)
+#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait)
typedef wait_queue_t adpt_wait_queue_t;
-#endif
/*
* message structures
*/
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 7b3bd34faf4..60b1b434eba 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1989,7 +1989,7 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
}
-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t adpt_isr(int irq, void *dev_id)
{
struct scsi_cmnd* cmd;
adpt_hba* pHba = dev_id;
@@ -2212,7 +2212,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
*/
host->io_port = 0;
host->n_io_port = 0;
- /* see comments in hosts.h */
+ /* see comments in scsi_host.h */
host->max_id = 16;
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 2ad2a89b5db..fd79068c586 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -44,7 +44,7 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
/*
- * struct scsi_host_template (see hosts.h)
+ * struct scsi_host_template (see scsi/scsi_host.h)
*/
#define DPT_DRIVER_NAME "Adaptec I2O RAID"
@@ -263,7 +263,7 @@ struct sg_simple_element {
static void adpt_i2o_sys_shutdown(void);
static int adpt_init(void);
static int adpt_i2o_build_sys_table(void);
-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t adpt_isr(int irq, void *dev_id);
#ifdef REBOOT_NOTIFIER
static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
#endif
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 0d5713dfa20..54756722dd5 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -82,7 +82,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "dtc.h"
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index a5ff43b1b26..2d38025861a 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -875,7 +875,7 @@ static unsigned long io_port[] = {
/* But transfer orientation from the 16 bit data register is Little Endian */
#define REG2H(x) le16_to_cpu(x)
-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_interrupt_handler(int, void *);
static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *,
unsigned int);
static int do_trace = 0;
@@ -2555,8 +2555,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
return IRQ_NONE;
}
-static irqreturn_t do_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs)
+static irqreturn_t do_interrupt_handler(int irq, void *shap)
{
struct Scsi_Host *shost;
unsigned int j;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index d312633db92..2dbb66d2f0a 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -194,22 +194,21 @@ static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
}
}
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id);
-static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
irqreturn_t ret;
spin_lock_irqsave(dev->host_lock, flags);
- ret = eata_pio_int_handler(irq, dev_id, regs);
+ ret = eata_pio_int_handler(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return ret;
}
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id)
{
unsigned int eata_stat = 0xfffff;
struct scsi_cmnd *cmd;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 5630868c1b2..2c2fe80bc42 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -184,7 +184,7 @@ enum {
};
/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+static irqreturn_t esp_intr(int irq, void *dev_id);
/* Debugging routines */
struct esp_cmdstrings {
@@ -4282,7 +4282,7 @@ state_machine:
}
/* Service only the ESP described by dev_id. */
-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+static irqreturn_t esp_intr(int irq, void *dev_id)
{
struct esp *esp = dev_id;
unsigned long flags;
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index dde3edf35c0..668569e8856 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -281,7 +281,7 @@ static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
@@ -294,6 +294,7 @@ static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
static int user_fifo_count = 0;
static int user_fifo_size = 0;
+#ifndef MODULE
static int __init fd_mcs_setup(char *str)
{
static int done_setup = 0;
@@ -311,6 +312,7 @@ static int __init fd_mcs_setup(char *str)
}
__setup("fd_mcs=", fd_mcs_setup);
+#endif /* !MODULE */
static void print_banner(struct Scsi_Host *shpnt)
{
@@ -617,7 +619,7 @@ static void my_done(struct Scsi_Host *shpnt, int error)
}
/* only my_done needs to be protected */
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
{
unsigned long flags;
int status;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index b0694dcce24..5d4ea6f7795 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -278,9 +278,9 @@
#include <linux/pci.h>
#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <scsi/scsicam.h>
-#include <asm/io.h>
#include <asm/system.h>
#include <scsi/scsi.h>
@@ -387,6 +387,7 @@ static void __iomem * bios_mem;
static int bios_major;
static int bios_minor;
static int PCI_bus;
+static struct pci_dev *PCI_dev;
static int Quantum; /* Quantum board variant */
static int interrupt_level;
static volatile int in_command;
@@ -403,8 +404,7 @@ static volatile int in_interrupt_flag;
static int FIFO_Size = 0x2000; /* 8k FIFO for
pre-tmc18c30 chips */
-static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id,
- struct pt_regs * regs );
+static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id );
/* Allow insmod parameters to be like LILO parameters. For example:
insmod fdomain fdomain=0x140,11 */
static char * fdomain = NULL;
@@ -813,9 +813,10 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_
PCI_DEVICE_ID_FD_36C70 );
#endif
- if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+ if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
return 0;
- if (pci_enable_device(pdev)) return 0;
+ if (pci_enable_device(pdev))
+ goto fail;
#if DEBUG_DETECT
printk( "scsi: <fdomain> TMC-3260 detect:"
@@ -832,7 +833,7 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_
pci_irq = pdev->irq;
if (!request_region( pci_base, 0x10, "fdomain" ))
- return 0;
+ goto fail;
/* Now we have the I/O base address and interrupt from the PCI
configuration registers. */
@@ -849,17 +850,22 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_
if (!fdomain_is_valid_port(pci_base)) {
printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
release_region(pci_base, 0x10);
- return 0;
+ goto fail;
}
/* Fill in a few global variables. Ugh. */
bios_major = bios_minor = -1;
PCI_bus = 1;
+ PCI_dev = pdev;
Quantum = 0;
bios_base = 0;
return 1;
+fail:
+ pci_dev_put(pdev);
+ return 0;
}
+
#endif
struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
@@ -910,8 +916,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
if (setup_called) {
printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
}
- release_region(port_base, 0x10);
- return NULL;
+ goto fail;
}
if (this_id) {
@@ -943,8 +948,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
/* Log IRQ with kernel */
if (!interrupt_level) {
printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
- release_region(port_base, 0x10);
- return NULL;
+ goto fail;
} else {
/* Register the IRQ with the kernel */
@@ -965,11 +969,14 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
printk(KERN_ERR " Send mail to faith@acm.org\n" );
}
printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
- release_region(port_base, 0x10);
- return NULL;
+ goto fail;
}
}
return shpnt;
+fail:
+ pci_dev_put(pdev);
+ release_region(port_base, 0x10);
+ return NULL;
}
static int fdomain_16x0_detect(struct scsi_host_template *tpnt)
@@ -1094,8 +1101,7 @@ static void my_done(int error)
#endif
}
-static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id,
- struct pt_regs * regs )
+static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
{
unsigned long flags;
int status;
@@ -1716,6 +1722,8 @@ static int fdomain_16x0_release(struct Scsi_Host *shpnt)
free_irq(shpnt->irq, shpnt);
if (shpnt->io_port && shpnt->n_io_port)
release_region(shpnt->io_port, shpnt->n_io_port);
+ if (PCI_bus)
+ pci_dev_put(PCI_dev);
return 0;
}
@@ -1738,6 +1746,15 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
+
+static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
+
#define driver_template fdomain_driver_template
#include "scsi_module.c"
+
#endif
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 43afd476e60..4c698a71f66 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -424,7 +424,7 @@
static void gdth_delay(int milliseconds);
static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
-static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gdth_interrupt(int irq, void *dev_id);
static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
static int gdth_async_event(int hanum);
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
@@ -724,7 +724,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
{
Scsi_Cmnd *scp;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int rval;
scp = kmalloc(sizeof(*scp), GFP_KERNEL);
@@ -764,7 +764,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
{
Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int rval;
if (!scp)
@@ -1804,7 +1804,7 @@ static int gdth_wait(int hanum,int index,ulong32 time)
gdth_from_wait = TRUE;
do {
- gdth_interrupt((int)ha->irq,ha,NULL);
+ gdth_interrupt((int)ha->irq,ha);
if (wait_hanum==hanum && wait_index==index) {
answer_found = TRUE;
break;
@@ -3406,7 +3406,7 @@ static void gdth_clear_events(void)
/* SCSI interface functions */
-static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+static irqreturn_t gdth_interrupt(int irq,void *dev_id)
{
gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
register gdth_ha_str *ha;
@@ -3531,7 +3531,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
IStatus &= ~0x80;
#ifdef INT_COAL
if (coalesced)
- ha->status = pcs->ext_status && 0xffff;
+ ha->status = pcs->ext_status & 0xffff;
else
#endif
ha->status = gdth_readw(&dp6m_ptr->i960r.status);
@@ -3543,7 +3543,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
if (coalesced) {
ha->info = pcs->info0;
ha->info2 = pcs->info1;
- ha->service = (pcs->ext_status >> 16) && 0xffff;
+ ha->service = (pcs->ext_status >> 16) & 0xffff;
} else
#endif
{
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 47eae029975..8c29eafd51c 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -936,18 +936,12 @@ typedef struct {
gdth_binfo_str binfo; /* controller info */
gdth_evt_data dvr; /* event structure */
spinlock_t smp_lock;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct pci_dev *pdev;
-#endif
char oem_name[8];
#ifdef GDTH_DMA_STATISTICS
ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct scsi_device *sdev;
-#else
- struct scsi_device sdev;
-#endif
} gdth_ha_str;
/* structure for scsi_register(), SCSI bus != 0 */
@@ -1029,10 +1023,6 @@ typedef struct {
/* function prototyping */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
-#else
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-#endif
#endif
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 18dbe5c27da..2f6c1137a6e 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -24,7 +24,7 @@
#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
-static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp)
+static irqreturn_t gvp11_intr (int irq, void *_instance)
{
unsigned long flags;
unsigned int status;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 68ef1636678..38c3a291efa 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -263,6 +263,10 @@ static void scsi_host_dev_release(struct device *dev)
kthread_stop(shost->ehandler);
if (shost->work_q)
destroy_workqueue(shost->work_q);
+ if (shost->uspace_req_q) {
+ kfree(shost->uspace_req_q->queuedata);
+ scsi_free_queue(shost->uspace_req_q);
+ }
scsi_destroy_command_freelist(shost);
if (shost->bqt)
@@ -301,8 +305,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
if (!shost)
return NULL;
- spin_lock_init(&shost->default_lock);
- scsi_assign_lock(shost, &shost->default_lock);
+ shost->host_lock = &shost->default_lock;
+ spin_lock_init(shost->host_lock);
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets);
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
deleted file mode 100644
index c27264bed5d..00000000000
--- a/drivers/scsi/hosts.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
-#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 28bfb8f9f81..bec83cbee59 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -431,7 +431,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
writel(tag, &hba->iop->outbound_queue);
}
-static irqreturn_t hptiop_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hptiop_intr(int irq, void *dev_id)
{
struct hptiop_hba *hba = dev_id;
int handled;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 2be1dc5d852..0e57fb6964d 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -497,8 +497,7 @@ static int option_setup(char *);
static int ldn_access_load(int, int);
static int ldn_access_total_read_write(int);
-static irqreturn_t interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t interrupt_handler(int irq, void *dev_id)
{
int host_index, ihost_index;
unsigned int intr_reg;
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index 4e247b6b870..6ac0633d545 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -3,3 +3,5 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
+
+obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 669ea4fff16..fbc1d5c3b0a 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1213,7 +1213,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
"ibmvscsi: Re-enabling adapter!\n");
purge_requests(hostdata, DID_REQUEUE);
if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
- hostdata) == 0) ||
+ hostdata)) ||
(ibmvscsi_send_crq(hostdata,
0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
new file mode 100644
index 00000000000..e28260f05d6
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -0,0 +1,960 @@
+/*
+ * IBM eServer i/pSeries Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ * Santiago Leon (santil@us.ibm.com) IBM Corp.
+ * Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2006 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/libsrp.h>
+#include <asm/hvcall.h>
+#include <asm/iommu.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+
+#include "ibmvscsi.h"
+
+#define INITIAL_SRP_LIMIT 16
+#define DEFAULT_MAX_SECTORS 512
+
+#define TGT_NAME "ibmvstgt"
+
+/*
+ * Hypervisor calls.
+ */
+#define h_copy_rdma(l, sa, sb, da, db) \
+ plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_send_crq(ua, l, h) \
+ plpar_hcall_norets(H_SEND_CRQ, ua, l, h)
+#define h_reg_crq(ua, tok, sz)\
+ plpar_hcall_norets(H_REG_CRQ, ua, tok, sz);
+#define h_free_crq(ua) \
+ plpar_hcall_norets(H_FREE_CRQ, ua);
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...) \
+do { \
+ printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
+} while (0)
+/* #define dprintk eprintk */
+#define dprintk(fmt, args...)
+
+struct vio_port {
+ struct vio_dev *dma_dev;
+
+ struct crq_queue crq_queue;
+ struct work_struct crq_work;
+
+ unsigned long liobn;
+ unsigned long riobn;
+ struct srp_target *target;
+};
+
+static struct workqueue_struct *vtgtd;
+
+/*
+ * These are fixed for the system and come from the Open Firmware device tree.
+ * We just store them here to save getting them every time.
+ */
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
+static struct vio_port *target_to_port(struct srp_target *target)
+{
+ return (struct vio_port *) target->ldata;
+}
+
+static inline union viosrp_iu *vio_iu(struct iu_entry *iue)
+{
+ return (union viosrp_iu *) (iue->sbuf->buf);
+}
+
+static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
+{
+ struct srp_target *target = iue->target;
+ struct vio_port *vport = target_to_port(target);
+ long rc, rc1;
+ union {
+ struct viosrp_crq cooked;
+ uint64_t raw[2];
+ } crq;
+
+ /* First copy the SRP */
+ rc = h_copy_rdma(length, vport->liobn, iue->sbuf->dma,
+ vport->riobn, iue->remote_token);
+
+ if (rc)
+ eprintk("Error %ld transferring data\n", rc);
+
+ crq.cooked.valid = 0x80;
+ crq.cooked.format = format;
+ crq.cooked.reserved = 0x00;
+ crq.cooked.timeout = 0x00;
+ crq.cooked.IU_length = length;
+ crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+
+ if (rc == 0)
+ crq.cooked.status = 0x99; /* Just needs to be non-zero */
+ else
+ crq.cooked.status = 0x00;
+
+ rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]);
+
+ if (rc1) {
+ eprintk("%ld sending response\n", rc1);
+ return rc1;
+ }
+
+ return rc;
+}
+
+#define SRP_RSP_SENSE_DATA_LEN 18
+
+static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
+ unsigned char status, unsigned char asc)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ uint64_t tag = iu->srp.rsp.tag;
+
+ /* If the linked bit is on and status is good */
+ if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE))
+ status = 0x10;
+
+ memset(iu, 0, sizeof(struct srp_rsp));
+ iu->srp.rsp.opcode = SRP_RSP;
+ iu->srp.rsp.req_lim_delta = 1;
+ iu->srp.rsp.tag = tag;
+
+ if (test_bit(V_DIOVER, &iue->flags))
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+
+ iu->srp.rsp.data_in_res_cnt = 0;
+ iu->srp.rsp.data_out_res_cnt = 0;
+
+ iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+ iu->srp.rsp.resp_data_len = 0;
+ iu->srp.rsp.status = status;
+ if (status) {
+ uint8_t *sense = iu->srp.rsp.data;
+
+ if (sc) {
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
+ memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ } else {
+ iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
+
+ /* Valid bit and 'current errors' */
+ sense[0] = (0x1 << 7 | 0x70);
+ /* Sense key */
+ sense[2] = status;
+ /* Additional sense length */
+ sense[7] = 0xa; /* 10 bytes */
+ /* Additional sense code */
+ sense[12] = asc;
+ }
+ }
+
+ send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN,
+ VIOSRP_SRP_FORMAT);
+
+ return 0;
+}
+
+static void handle_cmd_queue(struct srp_target *target)
+{
+ struct Scsi_Host *shost = target->shost;
+ struct iu_entry *iue;
+ struct srp_cmd *cmd;
+ unsigned long flags;
+ int err;
+
+retry:
+ spin_lock_irqsave(&target->lock, flags);
+
+ list_for_each_entry(iue, &target->cmd_queue, ilist) {
+ if (!test_and_set_bit(V_FLYING, &iue->flags)) {
+ spin_unlock_irqrestore(&target->lock, flags);
+ cmd = iue->sbuf->buf;
+ err = srp_cmd_queue(shost, cmd, iue, 0);
+ if (err) {
+ eprintk("cannot queue cmd %p %d\n", cmd, err);
+ srp_iu_put(iue);
+ }
+ goto retry;
+ }
+ }
+
+ spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+ struct srp_direct_buf *md, int nmd,
+ enum dma_data_direction dir, unsigned int rest)
+{
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+ struct vio_port *vport = target_to_port(target);
+ dma_addr_t token;
+ long err;
+ unsigned int done = 0;
+ int i, sidx, soff;
+
+ sidx = soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ for (i = 0; i < nmd && rest; i++) {
+ unsigned int mdone, mlen;
+
+ mlen = min(rest, md[i].len);
+ for (mdone = 0; mlen;) {
+ int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+
+ if (dir == DMA_TO_DEVICE)
+ err = h_copy_rdma(slen,
+ vport->riobn,
+ md[i].va + mdone,
+ vport->liobn,
+ token + soff);
+ else
+ err = h_copy_rdma(slen,
+ vport->liobn,
+ token + soff,
+ vport->riobn,
+ md[i].va + mdone);
+
+ if (err != H_SUCCESS) {
+ eprintk("rdma error %d %d\n", dir, slen);
+ goto out;
+ }
+
+ mlen -= slen;
+ mdone += slen;
+ soff += slen;
+ done += slen;
+
+ if (soff == sg_dma_len(sg + sidx)) {
+ sidx++;
+ soff = 0;
+ token = sg_dma_address(sg + sidx);
+
+ if (sidx > nsg) {
+ eprintk("out of sg %p %d %d\n",
+ iue, sidx, nsg);
+ goto out;
+ }
+ }
+ };
+
+ rest -= mlen;
+ }
+out:
+
+ return 0;
+}
+
+static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ int err;
+
+ err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
+
+ done(sc);
+
+ return err;
+}
+
+static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
+ void (*done)(struct scsi_cmnd *))
+{
+ unsigned long flags;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+
+ dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_del(&iue->ilist);
+ spin_unlock_irqrestore(&target->lock, flags);
+
+ if (sc->result != SAM_STAT_GOOD) {
+ eprintk("operation failed %p %d %x\n",
+ iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
+ send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
+ } else
+ send_rsp(iue, sc, NO_SENSE, 0x00);
+
+ done(sc);
+ srp_iu_put(iue);
+ return 0;
+}
+
+int send_adapter_info(struct iu_entry *iue,
+ dma_addr_t remote_buffer, uint16_t length)
+{
+ struct srp_target *target = iue->target;
+ struct vio_port *vport = target_to_port(target);
+ struct Scsi_Host *shost = target->shost;
+ dma_addr_t data_token;
+ struct mad_adapter_info_data *info;
+ int err;
+
+ info = dma_alloc_coherent(target->dev, sizeof(*info), &data_token,
+ GFP_KERNEL);
+ if (!info) {
+ eprintk("bad dma_alloc_coherent %p\n", target);
+ return 1;
+ }
+
+ /* Get remote info */
+ err = h_copy_rdma(sizeof(*info), vport->riobn, remote_buffer,
+ vport->liobn, data_token);
+ if (err == H_SUCCESS) {
+ dprintk("Client connect: %s (%d)\n",
+ info->partition_name, info->partition_number);
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ strcpy(info->srp_version, "16.a");
+ strncpy(info->partition_name, partition_name,
+ sizeof(info->partition_name));
+ info->partition_number = partition_number;
+ info->mad_version = 1;
+ info->os_type = 2;
+ info->port_max_txu[0] = shost->hostt->max_sectors << 9;
+
+ /* Send our info to remote */
+ err = h_copy_rdma(sizeof(*info), vport->liobn, data_token,
+ vport->riobn, remote_buffer);
+
+ dma_free_coherent(target->dev, sizeof(*info), info, data_token);
+
+ if (err != H_SUCCESS) {
+ eprintk("Error sending adapter info %d\n", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void process_login(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+ uint64_t tag = iu->srp.rsp.tag;
+
+ /* TODO handle case that requested size is wrong and
+ * buffer format is wrong
+ */
+ memset(iu, 0, sizeof(struct srp_login_rsp));
+ rsp->opcode = SRP_LOGIN_RSP;
+ rsp->req_lim_delta = INITIAL_SRP_LIMIT;
+ rsp->tag = tag;
+ rsp->max_it_iu_len = sizeof(union srp_iu);
+ rsp->max_ti_iu_len = sizeof(union srp_iu);
+ /* direct and indirect */
+ rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
+
+ send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static inline void queue_cmd(struct iu_entry *iue)
+{
+ struct srp_target *target = iue->target;
+ unsigned long flags;
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_add_tail(&iue->ilist, &target->cmd_queue);
+ spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static int process_tsk_mgmt(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ int fn;
+
+ dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+ switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+ case SRP_TSK_ABORT_TASK:
+ fn = ABORT_TASK;
+ break;
+ case SRP_TSK_ABORT_TASK_SET:
+ fn = ABORT_TASK_SET;
+ break;
+ case SRP_TSK_CLEAR_TASK_SET:
+ fn = CLEAR_TASK_SET;
+ break;
+ case SRP_TSK_LUN_RESET:
+ fn = LOGICAL_UNIT_RESET;
+ break;
+ case SRP_TSK_CLEAR_ACA:
+ fn = CLEAR_ACA;
+ break;
+ default:
+ fn = 0;
+ }
+ if (fn)
+ scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
+ iu->srp.tsk_mgmt.task_tag,
+ (struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
+ iue);
+ else
+ send_rsp(iue, NULL, ILLEGAL_REQUEST, 0x20);
+
+ return !fn;
+}
+
+static int process_mad_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ struct viosrp_adapter_info *info;
+ struct viosrp_host_config *conf;
+
+ switch (iu->mad.empty_iu.common.type) {
+ case VIOSRP_EMPTY_IU_TYPE:
+ eprintk("%s\n", "Unsupported EMPTY MAD IU");
+ break;
+ case VIOSRP_ERROR_LOG_TYPE:
+ eprintk("%s\n", "Unsupported ERROR LOG MAD IU");
+ iu->mad.error_log.common.status = 1;
+ send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_ADAPTER_INFO_TYPE:
+ info = &iu->mad.adapter_info;
+ info->common.status = send_adapter_info(iue, info->buffer,
+ info->common.length);
+ send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+ break;
+ case VIOSRP_HOST_CONFIG_TYPE:
+ conf = &iu->mad.host_config;
+ conf->common.status = 1;
+ send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+ break;
+ default:
+ eprintk("Unknown type %u\n", iu->srp.rsp.opcode);
+ }
+
+ return 1;
+}
+
+static int process_srp_iu(struct iu_entry *iue)
+{
+ union viosrp_iu *iu = vio_iu(iue);
+ int done = 1;
+ u8 opcode = iu->srp.rsp.opcode;
+
+ switch (opcode) {
+ case SRP_LOGIN_REQ:
+ process_login(iue);
+ break;
+ case SRP_TSK_MGMT:
+ done = process_tsk_mgmt(iue);
+ break;
+ case SRP_CMD:
+ queue_cmd(iue);
+ done = 0;
+ break;
+ case SRP_LOGIN_RSP:
+ case SRP_I_LOGOUT:
+ case SRP_T_LOGOUT:
+ case SRP_RSP:
+ case SRP_CRED_REQ:
+ case SRP_CRED_RSP:
+ case SRP_AER_REQ:
+ case SRP_AER_RSP:
+ eprintk("Unsupported type %u\n", opcode);
+ break;
+ default:
+ eprintk("Unknown type %u\n", opcode);
+ }
+
+ return done;
+}
+
+static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
+{
+ struct vio_port *vport = target_to_port(target);
+ struct iu_entry *iue;
+ long err, done;
+
+ iue = srp_iu_get(target);
+ if (!iue) {
+ eprintk("Error getting IU from pool, %p\n", target);
+ return;
+ }
+
+ iue->remote_token = crq->IU_data_ptr;
+
+ err = h_copy_rdma(crq->IU_length, vport->riobn,
+ iue->remote_token, vport->liobn, iue->sbuf->dma);
+
+ if (err != H_SUCCESS) {
+ eprintk("%ld transferring data error %p\n", err, iue);
+ done = 1;
+ goto out;
+ }
+
+ if (crq->format == VIOSRP_MAD_FORMAT)
+ done = process_mad_iu(iue);
+ else
+ done = process_srp_iu(iue);
+out:
+ if (done)
+ srp_iu_put(iue);
+}
+
+static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+{
+ struct srp_target *target = (struct srp_target *) data;
+ struct vio_port *vport = target_to_port(target);
+
+ vio_disable_interrupts(vport->dma_dev);
+ queue_work(vtgtd, &vport->crq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
+{
+ int err;
+ struct vio_port *vport = target_to_port(target);
+
+ queue->msgs = (struct viosrp_crq *) get_zeroed_page(GFP_KERNEL);
+ if (!queue->msgs)
+ goto malloc_failed;
+ queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+ queue->msg_token = dma_map_single(target->dev, queue->msgs,
+ queue->size * sizeof(*queue->msgs),
+ DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(queue->msg_token))
+ goto map_failed;
+
+ err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+
+ /* If the adapter was left active for some reason (like kexec)
+ * try freeing and re-registering
+ */
+ if (err == H_RESOURCE) {
+ do {
+ err = h_free_crq(vport->dma_dev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
+ PAGE_SIZE);
+ }
+
+ if (err != H_SUCCESS && err != 2) {
+ eprintk("Error 0x%x opening virtual adapter\n", err);
+ goto reg_crq_failed;
+ }
+
+ err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
+ SA_INTERRUPT, "ibmvstgt", target);
+ if (err)
+ goto req_irq_failed;
+
+ vio_enable_interrupts(vport->dma_dev);
+
+ h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0);
+
+ queue->cur = 0;
+ spin_lock_init(&queue->lock);
+
+ return 0;
+
+req_irq_failed:
+ do {
+ err = h_free_crq(vport->dma_dev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+reg_crq_failed:
+ dma_unmap_single(target->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+ free_page((unsigned long) queue->msgs);
+
+malloc_failed:
+ return -ENOMEM;
+}
+
+static void crq_queue_destroy(struct srp_target *target)
+{
+ struct vio_port *vport = target_to_port(target);
+ struct crq_queue *queue = &vport->crq_queue;
+ int err;
+
+ free_irq(vport->dma_dev->irq, target);
+ do {
+ err = h_free_crq(vport->dma_dev->unit_address);
+ } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+ dma_unmap_single(target->dev, queue->msg_token,
+ queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+
+ free_page((unsigned long) queue->msgs);
+}
+
+static void process_crq(struct viosrp_crq *crq, struct srp_target *target)
+{
+ struct vio_port *vport = target_to_port(target);
+ dprintk("%x %x\n", crq->valid, crq->format);
+
+ switch (crq->valid) {
+ case 0xC0:
+ /* initialization */
+ switch (crq->format) {
+ case 0x01:
+ h_send_crq(vport->dma_dev->unit_address,
+ 0xC002000000000000, 0);
+ break;
+ case 0x02:
+ break;
+ default:
+ eprintk("Unknown format %u\n", crq->format);
+ }
+ break;
+ case 0xFF:
+ /* transport event */
+ break;
+ case 0x80:
+ /* real payload */
+ switch (crq->format) {
+ case VIOSRP_SRP_FORMAT:
+ case VIOSRP_MAD_FORMAT:
+ process_iu(crq, target);
+ break;
+ case VIOSRP_OS400_FORMAT:
+ case VIOSRP_AIX_FORMAT:
+ case VIOSRP_LINUX_FORMAT:
+ case VIOSRP_INLINE_FORMAT:
+ eprintk("Unsupported format %u\n", crq->format);
+ break;
+ default:
+ eprintk("Unknown format %u\n", crq->format);
+ }
+ break;
+ default:
+ eprintk("unknown message type 0x%02x!?\n", crq->valid);
+ }
+}
+
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+ struct viosrp_crq *crq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ crq = &queue->msgs[queue->cur];
+ if (crq->valid & 0x80) {
+ if (++queue->cur == queue->size)
+ queue->cur = 0;
+ } else
+ crq = NULL;
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return crq;
+}
+
+static void handle_crq(struct work_struct *work)
+{
+ struct vio_port *vport = container_of(work, struct vio_port, crq_work);
+ struct srp_target *target = vport->target;
+ struct viosrp_crq *crq;
+ int done = 0;
+
+ while (!done) {
+ while ((crq = next_crq(&vport->crq_queue)) != NULL) {
+ process_crq(crq, target);
+ crq->valid = 0x00;
+ }
+
+ vio_enable_interrupts(vport->dma_dev);
+
+ crq = next_crq(&vport->crq_queue);
+ if (crq) {
+ vio_disable_interrupts(vport->dma_dev);
+ process_crq(crq, target);
+ crq->valid = 0x00;
+ } else
+ done = 1;
+ }
+
+ handle_cmd_queue(target);
+}
+
+
+static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
+{
+ unsigned long flags;
+ struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+ struct srp_target *target = iue->target;
+
+ dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+
+ spin_lock_irqsave(&target->lock, flags);
+ list_del(&iue->ilist);
+ spin_unlock_irqrestore(&target->lock, flags);
+
+ srp_iu_put(iue);
+
+ return 0;
+}
+
+static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
+{
+ struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
+ union viosrp_iu *iu = vio_iu(iue);
+ unsigned char status, asc;
+
+ eprintk("%p %d\n", iue, result);
+ status = NO_SENSE;
+ asc = 0;
+
+ switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+ case SRP_TSK_ABORT_TASK:
+ asc = 0x14;
+ if (result)
+ status = ABORTED_COMMAND;
+ break;
+ default:
+ break;
+ }
+
+ send_rsp(iue, NULL, status, asc);
+ srp_iu_put(iue);
+
+ return 0;
+}
+
+static ssize_t system_id_show(struct class_device *cdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
+
+static ssize_t partition_number_show(struct class_device *cdev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
+}
+
+static ssize_t unit_address_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct srp_target *target = host_to_srp_target(shost);
+ struct vio_port *vport = target_to_port(target);
+ return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address);
+}
+
+static CLASS_DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL);
+static CLASS_DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+static CLASS_DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct class_device_attribute *ibmvstgt_attrs[] = {
+ &class_device_attr_system_id,
+ &class_device_attr_partition_number,
+ &class_device_attr_unit_address,
+ NULL,
+};
+
+static struct scsi_host_template ibmvstgt_sht = {
+ .name = TGT_NAME,
+ .module = THIS_MODULE,
+ .can_queue = INITIAL_SRP_LIMIT,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = DISABLE_CLUSTERING,
+ .max_sectors = DEFAULT_MAX_SECTORS,
+ .transfer_response = ibmvstgt_cmd_done,
+ .transfer_data = ibmvstgt_transfer_data,
+ .eh_abort_handler = ibmvstgt_eh_abort_handler,
+ .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
+ .shost_attrs = ibmvstgt_attrs,
+ .proc_name = TGT_NAME,
+};
+
+static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+ struct Scsi_Host *shost;
+ struct srp_target *target;
+ struct vio_port *vport;
+ unsigned int *dma, dma_size;
+ int err = -ENOMEM;
+
+ vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL);
+ if (!vport)
+ return err;
+ shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
+ if (!shost)
+ goto free_vport;
+ err = scsi_tgt_alloc_queue(shost);
+ if (err)
+ goto put_host;
+
+ target = host_to_srp_target(shost);
+ target->shost = shost;
+ vport->dma_dev = dev;
+ target->ldata = vport;
+ vport->target = target;
+ err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT,
+ SRP_MAX_IU_LEN);
+ if (err)
+ goto put_host;
+
+ dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window",
+ &dma_size);
+ if (!dma || dma_size != 40) {
+ eprintk("Couldn't get window property %d\n", dma_size);
+ err = -EIO;
+ goto free_srp_target;
+ }
+ vport->liobn = dma[0];
+ vport->riobn = dma[5];
+
+ INIT_WORK(&vport->crq_work, handle_crq);
+
+ err = crq_queue_create(&vport->crq_queue, target);
+ if (err)
+ goto free_srp_target;
+
+ err = scsi_add_host(shost, target->dev);
+ if (err)
+ goto destroy_queue;
+ return 0;
+
+destroy_queue:
+ crq_queue_destroy(target);
+free_srp_target:
+ srp_target_free(target);
+put_host:
+ scsi_host_put(shost);
+free_vport:
+ kfree(vport);
+ return err;
+}
+
+static int ibmvstgt_remove(struct vio_dev *dev)
+{
+ struct srp_target *target = (struct srp_target *) dev->dev.driver_data;
+ struct Scsi_Host *shost = target->shost;
+ struct vio_port *vport = target->ldata;
+
+ crq_queue_destroy(target);
+ scsi_remove_host(shost);
+ scsi_tgt_free_queue(shost);
+ srp_target_free(target);
+ kfree(vport);
+ scsi_host_put(shost);
+ return 0;
+}
+
+static struct vio_device_id ibmvstgt_device_table[] __devinitdata = {
+ {"v-scsi-host", "IBM,v-scsi-host"},
+ {"",""}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvstgt_device_table);
+
+static struct vio_driver ibmvstgt_driver = {
+ .id_table = ibmvstgt_device_table,
+ .probe = ibmvstgt_probe,
+ .remove = ibmvstgt_remove,
+ .driver = {
+ .name = "ibmvscsis",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int get_system_info(void)
+{
+ struct device_node *rootdn;
+ const char *id, *model, *name;
+ unsigned int *num;
+
+ rootdn = find_path_device("/");
+ if (!rootdn)
+ return -ENOENT;
+
+ model = get_property(rootdn, "model", NULL);
+ id = get_property(rootdn, "system-id", NULL);
+ if (model && id)
+ snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+ name = get_property(rootdn, "ibm,partition-name", NULL);
+ if (name)
+ strncpy(partition_name, name, sizeof(partition_name));
+
+ num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+ if (num)
+ partition_number = *num;
+
+ return 0;
+}
+
+static int ibmvstgt_init(void)
+{
+ int err = -ENOMEM;
+
+ printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
+
+ vtgtd = create_workqueue("ibmvtgtd");
+ if (!vtgtd)
+ return err;
+
+ err = get_system_info();
+ if (err)
+ goto destroy_wq;
+
+ err = vio_register_driver(&ibmvstgt_driver);
+ if (err)
+ goto destroy_wq;
+
+ return 0;
+
+destroy_wq:
+ destroy_workqueue(vtgtd);
+ return err;
+}
+
+static void ibmvstgt_exit(void)
+{
+ printk("Unregister IBM virtual SCSI driver\n");
+
+ destroy_workqueue(vtgtd);
+ vio_unregister_driver(&ibmvstgt_driver);
+}
+
+MODULE_DESCRIPTION("IBM Virtual SCSI Target");
+MODULE_AUTHOR("Santiago Leon");
+MODULE_LICENSE("GPL");
+
+module_init(ibmvstgt_init);
+module_exit(ibmvstgt_exit);
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 01b8ac641eb..227c0f2f4d7 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -45,14 +45,11 @@ static unsigned int partition_number = -1;
* ibmvscsi_handle_event: - Interrupt handler for crq events
* @irq: number of irq to handle, not used
* @dev_instance: ibmvscsi_host_data of host that received interrupt
- * @regs: pt_regs with registers
*
* Disables interrupts and schedules srp_task
* Always returns IRQ_HANDLED
*/
-static irqreturn_t ibmvscsi_handle_event(int irq,
- void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
{
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)dev_instance;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 94d1de55607..8f6b5bf580f 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -110,6 +110,7 @@ typedef struct ide_scsi_obj {
} idescsi_scsi_t;
static DEFINE_MUTEX(idescsi_ref_mutex);
+static int idescsi_nocd; /* Set by module param to skip cd */
#define ide_scsi_g(disk) \
container_of((disk)->private_data, struct ide_scsi_obj, driver)
@@ -344,7 +345,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co
pc->buffer = buf;
pc->c[0] = REQUEST_SENSE;
pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE;
- rq->flags = REQ_SENSE;
+ rq->cmd_type = REQ_TYPE_SENSE;
pc->timeout = jiffies + WAIT_READY;
/* NOTE! Save the failed packet command in "rq->buffer" */
rq->buffer = (void *) failed_command->special;
@@ -398,12 +399,12 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
int errors = rq->errors;
unsigned long flags;
- if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) {
+ if (!blk_special_request(rq) && !blk_sense_request(rq)) {
ide_end_request(drive, uptodate, nrsecs);
return 0;
}
ide_end_drive_cmd (drive, 0, 0);
- if (rq->flags & REQ_SENSE) {
+ if (blk_sense_request(rq)) {
idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer;
if (log) {
printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);
@@ -708,11 +709,11 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
{
#if IDESCSI_DEBUG_LOG
- printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
+ printk (KERN_INFO "dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
#endif /* IDESCSI_DEBUG_LOG */
- if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) {
+ if (blk_sense_request(rq) || blk_special_request(rq)) {
return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
}
blk_dump_rq_flags(rq, "ide-scsi: unsup command");
@@ -938,7 +939,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
ide_init_drive_cmd (rq);
rq->special = (char *) pc;
- rq->flags = REQ_SPECIAL;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
spin_unlock_irq(host->host_lock);
rq->rq_disk = scsi->disk;
(void) ide_do_drive_cmd (drive, rq, ide_end);
@@ -992,7 +993,7 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
*/
printk (KERN_ERR "ide-scsi: cmd aborted!\n");
- if (scsi->pc->rq->flags & REQ_SENSE)
+ if (blk_sense_request(scsi->pc->rq))
kfree(scsi->pc->buffer);
kfree(scsi->pc->rq);
kfree(scsi->pc);
@@ -1042,7 +1043,7 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
/* kill current request */
blkdev_dequeue_request(req);
end_that_request_last(req, 0);
- if (req->flags & REQ_SENSE)
+ if (blk_sense_request(req))
kfree(scsi->pc->buffer);
kfree(scsi->pc);
scsi->pc = NULL;
@@ -1127,6 +1128,9 @@ static int ide_scsi_probe(ide_drive_t *drive)
warned = 1;
}
+ if (idescsi_nocd && drive->media == ide_cdrom)
+ return -ENODEV;
+
if (!strstr("ide-scsi", drive->driver_req) ||
!drive->present ||
drive->media == ide_disk ||
@@ -1187,6 +1191,8 @@ static void __exit exit_idescsi_module(void)
driver_unregister(&idescsi_driver.gen_driver);
}
+module_param(idescsi_nocd, int, 0600);
+MODULE_PARM_DESC(idescsi_nocd, "Disable handling of CD-ROMs so they may be driven by ide-cd");
module_init(init_idescsi_module);
module_exit(exit_idescsi_module);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 2d95ac9c32c..0464c182c57 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -36,7 +36,7 @@ typedef struct {
int base_hi; /* Hi Base address for ECP-ISA chipset */
int mode; /* Transfer mode */
struct scsi_cmnd *cur_cmd; /* Current queued command */
- struct work_struct imm_tq; /* Polling interrupt stuff */
+ struct delayed_work imm_tq; /* Polling interrupt stuff */
unsigned long jstart; /* Jiffies at start */
unsigned failed:1; /* Failure flag */
unsigned dp:1; /* Data phase present */
@@ -733,9 +733,9 @@ static int imm_completion(struct scsi_cmnd *cmd)
* the scheduler's task queue to generate a stream of call-backs and
* complete the request when the drive is ready.
*/
-static void imm_interrupt(void *data)
+static void imm_interrupt(struct work_struct *work)
{
- imm_struct *dev = (imm_struct *) data;
+ imm_struct *dev = container_of(work, imm_struct, imm_tq.work);
struct scsi_cmnd *cmd = dev->cur_cmd;
struct Scsi_Host *host = cmd->device->host;
unsigned long flags;
@@ -745,7 +745,6 @@ static void imm_interrupt(void *data)
return;
}
if (imm_engine(dev, cmd)) {
- INIT_WORK(&dev->imm_tq, imm_interrupt, (void *) dev);
schedule_delayed_work(&dev->imm_tq, 1);
return;
}
@@ -953,8 +952,7 @@ static int imm_queuecommand(struct scsi_cmnd *cmd,
cmd->result = DID_ERROR << 16; /* default return code */
cmd->SCp.phase = 0; /* bus free */
- INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
- schedule_work(&dev->imm_tq);
+ schedule_delayed_work(&dev->imm_tq, 0);
imm_pb_claim(dev);
@@ -1153,7 +1151,7 @@ static int __imm_attach(struct parport *pb)
{
struct Scsi_Host *host;
imm_struct *dev;
- DECLARE_WAIT_QUEUE_HEAD(waiting);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
int ports;
int modes, ppb;
@@ -1225,7 +1223,7 @@ static int __imm_attach(struct parport *pb)
else
ports = 8;
- INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
+ INIT_DELAYED_WORK(&dev->imm_tq, imm_interrupt);
err = -ENOMEM;
host = scsi_host_alloc(&imm_template, sizeof(imm_struct *));
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index ece936ac29c..8f6f32fc61f 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -66,7 +66,6 @@
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 59a4097f125..312190a6938 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -829,7 +829,7 @@ static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
* but it _does_ need to be able to compile and run in an SMP kernel.)
*/
-static irqreturn_t in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t in2000_intr(int irqnum, void *dev_id)
{
struct Scsi_Host *instance = dev_id;
struct IN2000_hostdata *hostdata;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 9e10dac61cf..f160357e37a 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -142,8 +142,6 @@
#define i91u_MAXQUEUE 2
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
-#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */
-#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */
#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
@@ -171,13 +169,16 @@ static int setup_debug = 0;
static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
-static const PCI_ID i91u_pci_devices[] = {
- { INI_VENDOR_ID, I950_DEVICE_ID },
- { INI_VENDOR_ID, I940_DEVICE_ID },
- { INI_VENDOR_ID, I935_DEVICE_ID },
- { INI_VENDOR_ID, I920_DEVICE_ID },
- { DMX_VENDOR_ID, I920_DEVICE_ID },
+/* PCI Devices supported by this driver */
+static struct pci_device_id i91u_pci_devices[] = {
+ { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
};
+MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
#define DEBUG_INTERRUPT 0
#define DEBUG_QUEUE 0
@@ -2748,7 +2749,7 @@ int tul_wait_done_disc(HCS * pCurHcb)
return (tul_bad_seq(pCurHcb));
}
-static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i91u_intr(int irqno, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
unsigned long flags;
@@ -2771,7 +2772,7 @@ static int tul_NewReturnNumberOfAdapters(void)
for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++)
{
- while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
+ while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) {
if (pci_enable_device(pDev))
continue;
pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 7ed4eef8347..b318500785e 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -70,6 +70,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/libata.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
@@ -96,7 +97,7 @@ static DEFINE_SPINLOCK(ipr_driver_lock);
/* This table describes the differences between DMA controller chips */
static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
- { /* Gemstone, Citrine, and Obsidian */
+ { /* Gemstone, Citrine, Obsidian, and Obsidian-E */
.mailbox = 0x0042C,
.cache_line_size = 0x20,
{
@@ -133,6 +134,7 @@ static const struct ipr_chip_t ipr_chip[] = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
};
@@ -199,6 +201,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"FFFA: Undefined device response recovered by the IOA"},
{0x014A0000, 1, 1,
"FFF6: Device bus error, message or command phase"},
+ {0x014A8000, 0, 1,
+ "FFFE: Task Management Function failed"},
{0x015D0000, 0, 1,
"FFF6: Failure prediction threshold exceeded"},
{0x015D9200, 0, 1,
@@ -261,6 +265,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"Device bus status error"},
{0x04448600, 0, 1,
"8157: IOA error requiring IOA reset to recover"},
+ {0x04448700, 0, 0,
+ "ATA device status error"},
{0x04490000, 0, 0,
"Message reject received from the device"},
{0x04449200, 0, 1,
@@ -273,6 +279,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"9082: IOA detected device error"},
{0x044A0000, 1, 1,
"3110: Device bus error, message or command phase"},
+ {0x044A8000, 1, 1,
+ "3110: SAS Command / Task Management Function failed"},
{0x04670400, 0, 1,
"9091: Incorrect hardware configuration change has been detected"},
{0x04678000, 0, 1,
@@ -453,7 +461,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
trace_entry->time = jiffies;
trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
trace_entry->type = type;
- trace_entry->cmd_index = ipr_cmd->cmd_index;
+ trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command;
+ trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
trace_entry->u.add_data = add_data;
}
@@ -480,8 +489,10 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
ioarcb->read_ioadl_len = 0;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
+ ioasa->u.gata.status = 0;
ipr_cmd->scsi_cmd = NULL;
+ ipr_cmd->qc = NULL;
ipr_cmd->sense_buffer[0] = 0;
ipr_cmd->dma_use_sg = 0;
}
@@ -626,6 +637,28 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
}
/**
+ * ipr_sata_eh_done - done function for aborted SATA commands
+ * @ipr_cmd: ipr command struct
+ *
+ * This function is invoked for ops generated to SATA
+ * devices which are being aborted.
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ata_queued_cmd *qc = ipr_cmd->qc;
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+
+ qc->err_mask |= AC_ERR_OTHER;
+ sata_port->ioasa.status |= ATA_BUSY;
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ ata_qc_complete(qc);
+}
+
+/**
* ipr_scsi_eh_done - mid-layer done function for aborted ops
* @ipr_cmd: ipr command struct
*
@@ -669,6 +702,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
+ else if (ipr_cmd->qc)
+ ipr_cmd->done = ipr_sata_eh_done;
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
del_timer(&ipr_cmd->timer);
@@ -825,6 +860,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res)
res->del_from_ml = 0;
res->resetting_device = 0;
res->sdev = NULL;
+ res->sata_port = NULL;
}
/**
@@ -1213,19 +1249,23 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg,
/**
* ipr_log_hex_data - Log additional hex IOA error data.
+ * @ioa_cfg: ioa config struct
* @data: IOA error data
* @len: data length
*
* Return value:
* none
**/
-static void ipr_log_hex_data(u32 *data, int len)
+static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len)
{
int i;
if (len == 0)
return;
+ if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL)
+ len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP);
+
for (i = 0; i < len / 4; i += 4) {
ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
be32_to_cpu(data[i]),
@@ -1254,7 +1294,7 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_err("%s\n", error->failure_reason);
ipr_err("Remote Adapter VPD:\n");
ipr_log_ext_vpd(&error->vpd);
- ipr_log_hex_data(error->data,
+ ipr_log_hex_data(ioa_cfg, error->data,
be32_to_cpu(hostrcb->hcam.length) -
(offsetof(struct ipr_hostrcb_error, u) +
offsetof(struct ipr_hostrcb_type_17_error, data)));
@@ -1279,12 +1319,225 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_err("%s\n", error->failure_reason);
ipr_err("Remote Adapter VPD:\n");
ipr_log_vpd(&error->vpd);
- ipr_log_hex_data(error->data,
+ ipr_log_hex_data(ioa_cfg, error->data,
be32_to_cpu(hostrcb->hcam.length) -
(offsetof(struct ipr_hostrcb_error, u) +
offsetof(struct ipr_hostrcb_type_07_error, data)));
}
+static const struct {
+ u8 active;
+ char *desc;
+} path_active_desc[] = {
+ { IPR_PATH_NO_INFO, "Path" },
+ { IPR_PATH_ACTIVE, "Active path" },
+ { IPR_PATH_NOT_ACTIVE, "Inactive path" }
+};
+
+static const struct {
+ u8 state;
+ char *desc;
+} path_state_desc[] = {
+ { IPR_PATH_STATE_NO_INFO, "has no path state information available" },
+ { IPR_PATH_HEALTHY, "is healthy" },
+ { IPR_PATH_DEGRADED, "is degraded" },
+ { IPR_PATH_FAILED, "is failed" }
+};
+
+/**
+ * ipr_log_fabric_path - Log a fabric path error
+ * @hostrcb: hostrcb struct
+ * @fabric: fabric descriptor
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
+ struct ipr_hostrcb_fabric_desc *fabric)
+{
+ int i, j;
+ u8 path_state = fabric->path_state;
+ u8 active = path_state & IPR_PATH_ACTIVE_MASK;
+ u8 state = path_state & IPR_PATH_STATE_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) {
+ if (path_active_desc[i].active != active)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) {
+ if (path_state_desc[j].state != state)
+ continue;
+
+ if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n",
+ path_active_desc[i].desc, path_state_desc[j].desc,
+ fabric->ioa_port);
+ } else if (fabric->cascaded_expander == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n",
+ path_active_desc[i].desc, path_state_desc[j].desc,
+ fabric->ioa_port, fabric->phy);
+ } else if (fabric->phy == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n",
+ path_active_desc[i].desc, path_state_desc[j].desc,
+ fabric->ioa_port, fabric->cascaded_expander);
+ } else {
+ ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n",
+ path_active_desc[i].desc, path_state_desc[j].desc,
+ fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+ }
+ return;
+ }
+ }
+
+ ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state,
+ fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+}
+
+static const struct {
+ u8 type;
+ char *desc;
+} path_type_desc[] = {
+ { IPR_PATH_CFG_IOA_PORT, "IOA port" },
+ { IPR_PATH_CFG_EXP_PORT, "Expander port" },
+ { IPR_PATH_CFG_DEVICE_PORT, "Device port" },
+ { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" }
+};
+
+static const struct {
+ u8 status;
+ char *desc;
+} path_status_desc[] = {
+ { IPR_PATH_CFG_NO_PROB, "Functional" },
+ { IPR_PATH_CFG_DEGRADED, "Degraded" },
+ { IPR_PATH_CFG_FAILED, "Failed" },
+ { IPR_PATH_CFG_SUSPECT, "Suspect" },
+ { IPR_PATH_NOT_DETECTED, "Missing" },
+ { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" }
+};
+
+static const char *link_rate[] = {
+ "unknown",
+ "disabled",
+ "phy reset problem",
+ "spinup hold",
+ "port selector",
+ "unknown",
+ "unknown",
+ "unknown",
+ "1.5Gbps",
+ "3.0Gbps",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown"
+};
+
+/**
+ * ipr_log_path_elem - Log a fabric path element.
+ * @hostrcb: hostrcb struct
+ * @cfg: fabric path element struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
+ struct ipr_hostrcb_config_element *cfg)
+{
+ int i, j;
+ u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
+ u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;
+
+ if (type == IPR_PATH_CFG_NOT_EXIST)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) {
+ if (path_type_desc[i].type != type)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) {
+ if (path_status_desc[j].status != status)
+ continue;
+
+ if (type == IPR_PATH_CFG_IOA_PORT) {
+ ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n",
+ path_status_desc[j].desc, path_type_desc[i].desc,
+ cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ } else {
+ if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n",
+ path_status_desc[j].desc, path_type_desc[i].desc,
+ link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ } else if (cfg->cascaded_expander == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, "
+ "WWN=%08X%08X\n", path_status_desc[j].desc,
+ path_type_desc[i].desc, cfg->phy,
+ link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ } else if (cfg->phy == 0xff) {
+ ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, "
+ "WWN=%08X%08X\n", path_status_desc[j].desc,
+ path_type_desc[i].desc, cfg->cascaded_expander,
+ link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ } else {
+ ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s "
+ "WWN=%08X%08X\n", path_status_desc[j].desc,
+ path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy,
+ link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+ }
+ }
+ return;
+ }
+ }
+
+ ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s "
+ "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy,
+ link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+ be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+}
+
+/**
+ * ipr_log_fabric_error - Log a fabric error.
+ * @ioa_cfg: ioa config struct
+ * @hostrcb: hostrcb struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
+ struct ipr_hostrcb *hostrcb)
+{
+ struct ipr_hostrcb_type_20_error *error;
+ struct ipr_hostrcb_fabric_desc *fabric;
+ struct ipr_hostrcb_config_element *cfg;
+ int i, add_len;
+
+ error = &hostrcb->hcam.u.error.u.type_20_error;
+ error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+ ipr_hcam_err(hostrcb, "%s\n", error->failure_reason);
+
+ add_len = be32_to_cpu(hostrcb->hcam.length) -
+ (offsetof(struct ipr_hostrcb_error, u) +
+ offsetof(struct ipr_hostrcb_type_20_error, desc));
+
+ for (i = 0, fabric = error->desc; i < error->num_entries; i++) {
+ ipr_log_fabric_path(hostrcb, fabric);
+ for_each_fabric_cfg(fabric, cfg)
+ ipr_log_path_elem(hostrcb, cfg);
+
+ add_len -= be16_to_cpu(fabric->length);
+ fabric = (struct ipr_hostrcb_fabric_desc *)
+ ((unsigned long)fabric + be16_to_cpu(fabric->length));
+ }
+
+ ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
+}
+
/**
* ipr_log_generic_error - Log an adapter error.
* @ioa_cfg: ioa config struct
@@ -1296,7 +1549,7 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
- ipr_log_hex_data(hostrcb->hcam.u.raw.data,
+ ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data,
be32_to_cpu(hostrcb->hcam.length));
}
@@ -1316,7 +1569,7 @@ static u32 ipr_get_error(u32 ioasc)
int i;
for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)
- if (ipr_error_table[i].ioasc == ioasc)
+ if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK))
return i;
return 0;
@@ -1358,13 +1611,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
if (!ipr_error_table[error_index].log_hcam)
return;
- if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
- ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
- "%s\n", ipr_error_table[error_index].error);
- } else {
- dev_err(&ioa_cfg->pdev->dev, "%s\n",
- ipr_error_table[error_index].error);
- }
+ ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error);
/* Set indication we have logged an error */
ioa_cfg->errors_logged++;
@@ -1401,6 +1648,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
case IPR_HOST_RCB_OVERLAY_ID_17:
ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb);
break;
+ case IPR_HOST_RCB_OVERLAY_ID_20:
+ ipr_log_fabric_error(ioa_cfg, hostrcb);
+ break;
case IPR_HOST_RCB_OVERLAY_ID_1:
case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
default:
@@ -2057,7 +2307,7 @@ static void ipr_release_dump(struct kref *kref)
/**
* ipr_worker_thread - Worker thread
- * @data: ioa config struct
+ * @work: ioa config struct
*
* Called at task level from a work thread. This function takes care
* of adding and removing device from the mid-layer as configuration
@@ -2066,13 +2316,14 @@ static void ipr_release_dump(struct kref *kref)
* Return value:
* nothing
**/
-static void ipr_worker_thread(void *data)
+static void ipr_worker_thread(struct work_struct *work)
{
unsigned long lock_flags;
struct ipr_resource_entry *res;
struct scsi_device *sdev;
struct ipr_dump *dump;
- struct ipr_ioa_cfg *ioa_cfg = data;
+ struct ipr_ioa_cfg *ioa_cfg =
+ container_of(work, struct ipr_ioa_cfg, work_q);
u8 bus, target, lun;
int did_work;
@@ -2933,7 +3184,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
struct ipr_dump *dump;
unsigned long lock_flags = 0;
- ENTER;
dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL);
if (!dump) {
@@ -2960,7 +3210,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- LEAVE;
return 0;
}
@@ -3051,6 +3300,17 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
**/
static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags = 0;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = (struct ipr_resource_entry *)sdev->hostdata;
+
+ if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN)
+ qdepth = IPR_MAX_CMD_PER_ATA_LUN;
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
return sdev->queue_depth;
}
@@ -3166,6 +3426,122 @@ static int ipr_biosparam(struct scsi_device *sdev,
}
/**
+ * ipr_find_starget - Find target based on bus/target.
+ * @starget: scsi target struct
+ *
+ * Return value:
+ * resource entry pointer if found / NULL if not found
+ **/
+static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
+ struct ipr_resource_entry *res;
+
+ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+ if ((res->cfgte.res_addr.bus == starget->channel) &&
+ (res->cfgte.res_addr.target == starget->id) &&
+ (res->cfgte.res_addr.lun == 0)) {
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ata_port_info sata_port_info;
+
+/**
+ * ipr_target_alloc - Prepare for commands to a SCSI target
+ * @starget: scsi target struct
+ *
+ * If the device is a SATA device, this function allocates an
+ * ATA port with libata, else it does nothing.
+ *
+ * Return value:
+ * 0 on success / non-0 on failure
+ **/
+static int ipr_target_alloc(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
+ struct ipr_sata_port *sata_port;
+ struct ata_port *ap;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = ipr_find_starget(starget);
+ starget->hostdata = NULL;
+
+ if (res && ipr_is_gata(res)) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL);
+ if (!sata_port)
+ return -ENOMEM;
+
+ ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost);
+ if (ap) {
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ sata_port->ioa_cfg = ioa_cfg;
+ sata_port->ap = ap;
+ sata_port->res = res;
+
+ res->sata_port = sata_port;
+ ap->private_data = sata_port;
+ starget->hostdata = sata_port;
+ } else {
+ kfree(sata_port);
+ return -ENOMEM;
+ }
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+ return 0;
+}
+
+/**
+ * ipr_target_destroy - Destroy a SCSI target
+ * @starget: scsi target struct
+ *
+ * If the device was a SATA device, this function frees the libata
+ * ATA port, else it does nothing.
+ *
+ **/
+static void ipr_target_destroy(struct scsi_target *starget)
+{
+ struct ipr_sata_port *sata_port = starget->hostdata;
+
+ if (sata_port) {
+ starget->hostdata = NULL;
+ ata_sas_port_destroy(sata_port->ap);
+ kfree(sata_port);
+ }
+}
+
+/**
+ * ipr_find_sdev - Find device based on bus/target/lun.
+ * @sdev: scsi device struct
+ *
+ * Return value:
+ * resource entry pointer if found / NULL if not found
+ **/
+static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
+{
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+ struct ipr_resource_entry *res;
+
+ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+ if ((res->cfgte.res_addr.bus == sdev->channel) &&
+ (res->cfgte.res_addr.target == sdev->id) &&
+ (res->cfgte.res_addr.lun == sdev->lun))
+ return res;
+ }
+
+ return NULL;
+}
+
+/**
* ipr_slave_destroy - Unconfigure a SCSI device
* @sdev: scsi device struct
*
@@ -3183,8 +3559,11 @@ static void ipr_slave_destroy(struct scsi_device *sdev)
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *) sdev->hostdata;
if (res) {
+ if (res->sata_port)
+ ata_port_disable(res->sata_port->ap);
sdev->hostdata = NULL;
res->sdev = NULL;
+ res->sata_port = NULL;
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
}
@@ -3219,13 +3598,45 @@ static int ipr_slave_configure(struct scsi_device *sdev)
}
if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
sdev->allow_restart = 1;
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ if (ipr_is_gata(res) && res->sata_port) {
+ scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
+ ata_sas_slave_configure(sdev, res->sata_port->ap);
+ } else {
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ }
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return 0;
}
/**
+ * ipr_ata_slave_alloc - Prepare for commands to a SATA device
+ * @sdev: scsi device struct
+ *
+ * This function initializes an ATA port so that future commands
+ * sent through queuecommand will work.
+ *
+ * Return value:
+ * 0 on success
+ **/
+static int ipr_ata_slave_alloc(struct scsi_device *sdev)
+{
+ struct ipr_sata_port *sata_port = NULL;
+ int rc = -ENXIO;
+
+ ENTER;
+ if (sdev->sdev_target)
+ sata_port = sdev->sdev_target->hostdata;
+ if (sata_port)
+ rc = ata_sas_port_init(sata_port->ap);
+ if (rc)
+ ipr_slave_destroy(sdev);
+
+ LEAVE;
+ return rc;
+}
+
+/**
* ipr_slave_alloc - Prepare for commands to a device.
* @sdev: scsi device struct
*
@@ -3248,18 +3659,18 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
- list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
- if ((res->cfgte.res_addr.bus == sdev->channel) &&
- (res->cfgte.res_addr.target == sdev->id) &&
- (res->cfgte.res_addr.lun == sdev->lun)) {
- res->sdev = sdev;
- res->add_to_ml = 0;
- res->in_erp = 0;
- sdev->hostdata = res;
- if (!ipr_is_naca_model(res))
- res->needs_sync_complete = 1;
- rc = 0;
- break;
+ res = ipr_find_sdev(sdev);
+ if (res) {
+ res->sdev = sdev;
+ res->add_to_ml = 0;
+ res->in_erp = 0;
+ sdev->hostdata = res;
+ if (!ipr_is_naca_model(res))
+ res->needs_sync_complete = 1;
+ rc = 0;
+ if (ipr_is_gata(res)) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return ipr_ata_slave_alloc(sdev);
}
}
@@ -3314,7 +3725,8 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd)
* This function issues a device reset to the affected device.
* If the device is a SCSI device, a LUN reset will be sent
* to the device first. If that does not work, a target reset
- * will be sent.
+ * will be sent. If the device is a SATA device, a PHY reset will
+ * be sent.
*
* Return value:
* 0 on success / non-zero on failure
@@ -3325,26 +3737,85 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_cmnd *ipr_cmd;
struct ipr_ioarcb *ioarcb;
struct ipr_cmd_pkt *cmd_pkt;
+ struct ipr_ioarcb_ata_regs *regs;
u32 ioasc;
ENTER;
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
cmd_pkt = &ioarcb->cmd_pkt;
+ regs = &ioarcb->add_data.u.regs;
ioarcb->res_handle = res->cfgte.res_handle;
cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
+ if (ipr_is_gata(res)) {
+ cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET;
+ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags));
+ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
+ }
ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET)
+ memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
+ sizeof(struct ipr_ioasa_gata));
LEAVE;
return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
}
/**
+ * ipr_sata_reset - Reset the SATA port
+ * @ap: SATA port to reset
+ * @classes: class of the attached device
+ *
+ * This function issues a SATA phy reset to the affected ATA port.
+ *
+ * Return value:
+ * 0 on success / non-zero on failure
+ **/
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags = 0;
+ int rc = -ENXIO;
+
+ ENTER;
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
+
+ res = sata_port->res;
+ if (res) {
+ rc = ipr_device_reset(ioa_cfg, res);
+ switch(res->cfgte.proto) {
+ case IPR_PROTO_SATA:
+ case IPR_PROTO_SAS_STP:
+ *classes = ATA_DEV_ATA;
+ break;
+ case IPR_PROTO_SATA_ATAPI:
+ case IPR_PROTO_SAS_STP_ATAPI:
+ *classes = ATA_DEV_ATAPI;
+ break;
+ default:
+ *classes = ATA_DEV_UNKNOWN;
+ break;
+ };
+ }
+
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ LEAVE;
+ return rc;
+}
+
+/**
* ipr_eh_dev_reset - Reset the device
* @scsi_cmd: scsi command struct
*
@@ -3360,7 +3831,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
struct ipr_cmnd *ipr_cmd;
struct ipr_ioa_cfg *ioa_cfg;
struct ipr_resource_entry *res;
- int rc;
+ struct ata_port *ap;
+ int rc = 0;
ENTER;
ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
@@ -3383,12 +3855,23 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
+ if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
+ ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
+ ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
+ }
}
}
res->resetting_device = 1;
scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
- rc = ipr_device_reset(ioa_cfg, res);
+
+ if (ipr_is_gata(res) && res->sata_port) {
+ ap = res->sata_port->ap;
+ spin_unlock_irq(scsi_cmd->device->host->host_lock);
+ ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
+ spin_lock_irq(scsi_cmd->device->host->host_lock);
+ } else
+ rc = ipr_device_reset(ioa_cfg, res);
res->resetting_device = 0;
LEAVE;
@@ -3510,7 +3993,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
*/
if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead)
return FAILED;
- if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+ if (!res || !ipr_is_gscsi(res))
return FAILED;
list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
@@ -3620,12 +4103,11 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
* ipr_isr - Interrupt service routine
* @irq: irq number
* @devp: pointer to ioa config struct
- * @regs: pt_regs struct
*
* Return value:
* IRQ_NONE / IRQ_HANDLED
**/
-static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t ipr_isr(int irq, void *devp)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
unsigned long lock_flags = 0;
@@ -4300,6 +4782,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
return 0;
}
+ if (ipr_is_gata(res) && res->sata_port)
+ return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
@@ -4345,6 +4830,26 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
}
/**
+ * ipr_ioctl - IOCTL handler
+ * @sdev: scsi device struct
+ * @cmd: IOCTL cmd
+ * @arg: IOCTL arg
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+ struct ipr_resource_entry *res;
+
+ res = (struct ipr_resource_entry *)sdev->hostdata;
+ if (res && ipr_is_gata(res))
+ return ata_scsi_ioctl(sdev, cmd, arg);
+
+ return -EINVAL;
+}
+
+/**
* ipr_info - Get information about the card/driver
* @scsi_host: scsi host struct
*
@@ -4370,6 +4875,7 @@ static struct scsi_host_template driver_template = {
.module = THIS_MODULE,
.name = "IPR",
.info = ipr_ioa_info,
+ .ioctl = ipr_ioctl,
.queuecommand = ipr_queuecommand,
.eh_abort_handler = ipr_eh_abort,
.eh_device_reset_handler = ipr_eh_dev_reset,
@@ -4377,6 +4883,8 @@ static struct scsi_host_template driver_template = {
.slave_alloc = ipr_slave_alloc,
.slave_configure = ipr_slave_configure,
.slave_destroy = ipr_slave_destroy,
+ .target_alloc = ipr_target_alloc,
+ .target_destroy = ipr_target_destroy,
.change_queue_depth = ipr_change_queue_depth,
.change_queue_type = ipr_change_queue_type,
.bios_param = ipr_biosparam,
@@ -4391,6 +4899,336 @@ static struct scsi_host_template driver_template = {
.proc_name = IPR_NAME
};
+/**
+ * ipr_ata_phy_reset - libata phy_reset handler
+ * @ap: ata port to reset
+ *
+ **/
+static void ipr_ata_phy_reset(struct ata_port *ap)
+{
+ unsigned long flags;
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ int rc;
+
+ ENTER;
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ }
+
+ if (!ioa_cfg->allow_cmds)
+ goto out_unlock;
+
+ rc = ipr_device_reset(ioa_cfg, res);
+
+ if (rc) {
+ ap->ops->port_disable(ap);
+ goto out_unlock;
+ }
+
+ switch(res->cfgte.proto) {
+ case IPR_PROTO_SATA:
+ case IPR_PROTO_SAS_STP:
+ ap->device[0].class = ATA_DEV_ATA;
+ break;
+ case IPR_PROTO_SATA_ATAPI:
+ case IPR_PROTO_SAS_STP_ATAPI:
+ ap->device[0].class = ATA_DEV_ATAPI;
+ break;
+ default:
+ ap->device[0].class = ATA_DEV_UNKNOWN;
+ ap->ops->port_disable(ap);
+ break;
+ };
+
+out_unlock:
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ LEAVE;
+}
+
+/**
+ * ipr_ata_post_internal - Cleanup after an internal command
+ * @qc: ATA queued command
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
+{
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_cmnd *ipr_cmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ }
+
+ list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+ if (ipr_cmd->qc == qc) {
+ ipr_device_reset(ioa_cfg, sata_port->res);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
+
+/**
+ * ipr_tf_read - Read the current ATA taskfile for the ATA port
+ * @ap: ATA port
+ * @tf: destination ATA taskfile
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_ioasa_gata *g = &sata_port->ioasa;
+
+ tf->feature = g->error;
+ tf->nsect = g->nsect;
+ tf->lbal = g->lbal;
+ tf->lbam = g->lbam;
+ tf->lbah = g->lbah;
+ tf->device = g->device;
+ tf->command = g->status;
+ tf->hob_nsect = g->hob_nsect;
+ tf->hob_lbal = g->hob_lbal;
+ tf->hob_lbam = g->hob_lbam;
+ tf->hob_lbah = g->hob_lbah;
+ tf->ctl = g->alt_status;
+}
+
+/**
+ * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure
+ * @regs: destination
+ * @tf: source ATA taskfile
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs,
+ struct ata_taskfile *tf)
+{
+ regs->feature = tf->feature;
+ regs->nsect = tf->nsect;
+ regs->lbal = tf->lbal;
+ regs->lbam = tf->lbam;
+ regs->lbah = tf->lbah;
+ regs->device = tf->device;
+ regs->command = tf->command;
+ regs->hob_feature = tf->hob_feature;
+ regs->hob_nsect = tf->hob_nsect;
+ regs->hob_lbal = tf->hob_lbal;
+ regs->hob_lbam = tf->hob_lbam;
+ regs->hob_lbah = tf->hob_lbah;
+ regs->ctl = tf->ctl;
+}
+
+/**
+ * ipr_sata_done - done function for SATA commands
+ * @ipr_cmd: ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer to SATA devices
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ata_queued_cmd *qc = ipr_cmd->qc;
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+ memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
+ sizeof(struct ipr_ioasa_gata));
+ ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+
+ if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
+ scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
+ res->cfgte.res_addr.target);
+
+ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
+ qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+ else
+ qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ ata_qc_complete(qc);
+}
+
+/**
+ * ipr_build_ata_ioadl - Build an ATA scatter/gather list
+ * @ipr_cmd: ipr command struct
+ * @qc: ATA queued command
+ *
+ **/
+static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
+ struct ata_queued_cmd *qc)
+{
+ u32 ioadl_flags = 0;
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+ int len = qc->nbytes + qc->pad_len;
+ struct scatterlist *sg;
+
+ if (len == 0)
+ return;
+
+ if (qc->dma_dir == DMA_TO_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+ ioarcb->write_data_transfer_length = cpu_to_be32(len);
+ ioarcb->write_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ } else if (qc->dma_dir == DMA_FROM_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_READ;
+ ioarcb->read_data_transfer_length = cpu_to_be32(len);
+ ioarcb->read_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ }
+
+ ata_for_each_sg(sg, qc) {
+ ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
+ ioadl->address = cpu_to_be32(sg_dma_address(sg));
+ if (ata_sg_is_last(sg, qc))
+ ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+ else
+ ioadl++;
+ }
+}
+
+/**
+ * ipr_qc_issue - Issue a SATA qc to a device
+ * @qc: queued command
+ *
+ * Return value:
+ * 0 if success
+ **/
+static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_cmnd *ipr_cmd;
+ struct ipr_ioarcb *ioarcb;
+ struct ipr_ioarcb_ata_regs *regs;
+
+ if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
+ return -EIO;
+
+ ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+ ioarcb = &ipr_cmd->ioarcb;
+ regs = &ioarcb->add_data.u.regs;
+
+ memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
+ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
+
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+ ipr_cmd->qc = qc;
+ ipr_cmd->done = ipr_sata_done;
+ ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+ ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
+ ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+
+ ipr_build_ata_ioadl(ipr_cmd, qc);
+ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
+ ipr_copy_sata_tf(regs, &qc->tf);
+ memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN);
+ ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NODATA:
+ case ATA_PROT_PIO:
+ break;
+
+ case ATA_PROT_DMA:
+ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ break;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ break;
+
+ default:
+ WARN_ON(1);
+ return -1;
+ }
+
+ mb();
+ writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
+ ioa_cfg->regs.ioarrin_reg);
+ return 0;
+}
+
+/**
+ * ipr_ata_check_status - Return last ATA status
+ * @ap: ATA port
+ *
+ * Return value:
+ * ATA status
+ **/
+static u8 ipr_ata_check_status(struct ata_port *ap)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ return sata_port->ioasa.status;
+}
+
+/**
+ * ipr_ata_check_altstatus - Return last ATA altstatus
+ * @ap: ATA port
+ *
+ * Return value:
+ * Alt ATA status
+ **/
+static u8 ipr_ata_check_altstatus(struct ata_port *ap)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ return sata_port->ioasa.alt_status;
+}
+
+static struct ata_port_operations ipr_sata_ops = {
+ .port_disable = ata_port_disable,
+ .check_status = ipr_ata_check_status,
+ .check_altstatus = ipr_ata_check_altstatus,
+ .dev_select = ata_noop_dev_select,
+ .phy_reset = ipr_ata_phy_reset,
+ .post_internal_cmd = ipr_ata_post_internal,
+ .tf_read = ipr_tf_read,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ipr_qc_issue,
+ .port_start = ata_sas_port_start,
+ .port_stop = ata_sas_port_stop
+};
+
+static struct ata_port_info sata_port_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ .pio_mask = 0x10, /* pio4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &ipr_sata_ops
+};
+
#ifdef CONFIG_PPC_PSERIES
static const u16 ipr_blocked_processors[] = {
PV_NORTHSTAR,
@@ -6102,7 +6940,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
return -ENOMEM;
for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
- ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, SLAB_KERNEL, &dma_addr);
+ ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
if (!ipr_cmd) {
ipr_free_cmd_blks(ioa_cfg);
@@ -6189,6 +7027,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
ioa_cfg->hostrcb[i]->hostrcb_dma =
ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
+ ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg;
list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
}
@@ -6283,7 +7122,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
INIT_LIST_HEAD(&ioa_cfg->free_res_q);
INIT_LIST_HEAD(&ioa_cfg->used_res_q);
- INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg);
+ INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
init_waitqueue_head(&ioa_cfg->reset_wait_q);
ioa_cfg->sdt_state = INACTIVE;
if (ipr_enable_cache)
@@ -6352,7 +7191,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
struct Scsi_Host *host;
unsigned long ipr_regs_pci;
void __iomem *ipr_regs;
- u32 rc = PCIBIOS_SUCCESSFUL;
+ int rc = PCIBIOS_SUCCESSFUL;
volatile u32 mask, uproc;
ENTER;
@@ -6374,6 +7213,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
+ ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
+ sata_port_info.flags, &ipr_sata_ops);
ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
@@ -6705,12 +7546,24 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+ 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+ 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
+ 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
+ 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
@@ -6720,6 +7573,9 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F,
0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+ { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F,
+ 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
@@ -6749,7 +7605,7 @@ static int __init ipr_init(void)
ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
- return pci_module_init(&ipr_driver);
+ return pci_register_driver(&ipr_driver);
}
/**
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 11eaff52432..9f62a1d4d51 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/completion.h>
+#include <linux/libata.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <scsi/scsi.h>
@@ -36,8 +37,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.1.4"
-#define IPR_DRIVER_DATE "(August 2, 2006)"
+#define IPR_DRIVER_VERSION "2.3.0"
+#define IPR_DRIVER_DATE "(November 8, 2006)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -53,6 +54,8 @@
*/
#define IPR_NUM_BASE_CMD_BLKS 100
+#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339
+
#define IPR_SUBS_DEV_ID_2780 0x0264
#define IPR_SUBS_DEV_ID_5702 0x0266
#define IPR_SUBS_DEV_ID_5703 0x0278
@@ -65,7 +68,11 @@
#define IPR_SUBS_DEV_ID_571F 0x02D5
#define IPR_SUBS_DEV_ID_572A 0x02C1
#define IPR_SUBS_DEV_ID_572B 0x02C2
+#define IPR_SUBS_DEV_ID_572F 0x02C3
#define IPR_SUBS_DEV_ID_575B 0x030D
+#define IPR_SUBS_DEV_ID_575C 0x0338
+#define IPR_SUBS_DEV_ID_57B7 0x0360
+#define IPR_SUBS_DEV_ID_57B8 0x02C2
#define IPR_NAME "ipr"
@@ -97,6 +104,7 @@
#define IPR_IOASC_IOA_WAS_RESET 0x10000001
#define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002
+#define IPR_DEFAULT_MAX_ERROR_DUMP 984
#define IPR_NUM_LOG_HCAMS 2
#define IPR_NUM_CFG_CHG_HCAMS 2
#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
@@ -730,6 +738,64 @@ struct ipr_hostrcb_type_17_error {
u32 data[476];
}__attribute__((packed, aligned (4)));
+struct ipr_hostrcb_config_element {
+ u8 type_status;
+#define IPR_PATH_CFG_TYPE_MASK 0xF0
+#define IPR_PATH_CFG_NOT_EXIST 0x00
+#define IPR_PATH_CFG_IOA_PORT 0x10
+#define IPR_PATH_CFG_EXP_PORT 0x20
+#define IPR_PATH_CFG_DEVICE_PORT 0x30
+#define IPR_PATH_CFG_DEVICE_LUN 0x40
+
+#define IPR_PATH_CFG_STATUS_MASK 0x0F
+#define IPR_PATH_CFG_NO_PROB 0x00
+#define IPR_PATH_CFG_DEGRADED 0x01
+#define IPR_PATH_CFG_FAILED 0x02
+#define IPR_PATH_CFG_SUSPECT 0x03
+#define IPR_PATH_NOT_DETECTED 0x04
+#define IPR_PATH_INCORRECT_CONN 0x05
+
+ u8 cascaded_expander;
+ u8 phy;
+ u8 link_rate;
+#define IPR_PHY_LINK_RATE_MASK 0x0F
+
+ __be32 wwid[2];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_fabric_desc {
+ __be16 length;
+ u8 ioa_port;
+ u8 cascaded_expander;
+ u8 phy;
+ u8 path_state;
+#define IPR_PATH_ACTIVE_MASK 0xC0
+#define IPR_PATH_NO_INFO 0x00
+#define IPR_PATH_ACTIVE 0x40
+#define IPR_PATH_NOT_ACTIVE 0x80
+
+#define IPR_PATH_STATE_MASK 0x0F
+#define IPR_PATH_STATE_NO_INFO 0x00
+#define IPR_PATH_HEALTHY 0x01
+#define IPR_PATH_DEGRADED 0x02
+#define IPR_PATH_FAILED 0x03
+
+ __be16 num_entries;
+ struct ipr_hostrcb_config_element elem[1];
+}__attribute__((packed, aligned (4)));
+
+#define for_each_fabric_cfg(fabric, cfg) \
+ for (cfg = (fabric)->elem; \
+ cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \
+ cfg++)
+
+struct ipr_hostrcb_type_20_error {
+ u8 failure_reason[64];
+ u8 reserved[3];
+ u8 num_entries;
+ struct ipr_hostrcb_fabric_desc desc[1];
+}__attribute__((packed, aligned (4)));
+
struct ipr_hostrcb_error {
__be32 failing_dev_ioasc;
struct ipr_res_addr failing_dev_res_addr;
@@ -746,6 +812,7 @@ struct ipr_hostrcb_error {
struct ipr_hostrcb_type_13_error type_13_error;
struct ipr_hostrcb_type_14_error type_14_error;
struct ipr_hostrcb_type_17_error type_17_error;
+ struct ipr_hostrcb_type_20_error type_20_error;
} u;
}__attribute__((packed, aligned (4)));
@@ -785,6 +852,7 @@ struct ipr_hcam {
#define IPR_HOST_RCB_OVERLAY_ID_14 0x14
#define IPR_HOST_RCB_OVERLAY_ID_16 0x16
#define IPR_HOST_RCB_OVERLAY_ID_17 0x17
+#define IPR_HOST_RCB_OVERLAY_ID_20 0x20
#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT 0xFF
u8 reserved1[3];
@@ -804,6 +872,7 @@ struct ipr_hostrcb {
struct ipr_hcam hcam;
dma_addr_t hostrcb_dma;
struct list_head queue;
+ struct ipr_ioa_cfg *ioa_cfg;
};
/* IPR smart dump table structures */
@@ -849,6 +918,13 @@ struct ipr_bus_attributes {
u32 max_xfer_rate;
};
+struct ipr_sata_port {
+ struct ipr_ioa_cfg *ioa_cfg;
+ struct ata_port *ap;
+ struct ipr_resource_entry *res;
+ struct ipr_ioasa_gata ioasa;
+};
+
struct ipr_resource_entry {
struct ipr_config_table_entry cfgte;
u8 needs_sync_complete:1;
@@ -858,6 +934,7 @@ struct ipr_resource_entry {
u8 resetting_device:1;
struct scsi_device *sdev;
+ struct ipr_sata_port *sata_port;
struct list_head queue;
};
@@ -928,10 +1005,11 @@ struct ipr_trace_entry {
u32 time;
u8 op_code;
+ u8 ata_op_code;
u8 type;
#define IPR_TRACE_START 0x00
#define IPR_TRACE_FINISH 0xff
- u16 cmd_index;
+ u8 cmd_index;
__be32 res_handle;
union {
@@ -1073,6 +1151,7 @@ struct ipr_ioa_cfg {
struct ipr_cmnd *reset_cmd;
+ struct ata_host ata_host;
char ipr_cmd_label[8];
#define IPR_CMD_LABEL "ipr_cmnd"
struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
@@ -1085,6 +1164,7 @@ struct ipr_cmnd {
struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
struct list_head queue;
struct scsi_cmnd *scsi_cmd;
+ struct ata_queued_cmd *qc;
struct completion completion;
struct timer_list timer;
void (*done) (struct ipr_cmnd *);
@@ -1271,6 +1351,17 @@ struct ipr_ucode_image_header {
} \
}
+#define ipr_hcam_err(hostrcb, fmt, ...) \
+{ \
+ if (ipr_is_device(&(hostrcb)->hcam.u.error.failing_dev_res_addr)) { \
+ ipr_ra_err((hostrcb)->ioa_cfg, \
+ (hostrcb)->hcam.u.error.failing_dev_res_addr, \
+ fmt, ##__VA_ARGS__); \
+ } else { \
+ dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, ##__VA_ARGS__); \
+ } \
+}
+
#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
__FILE__, __FUNCTION__, __LINE__)
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 3c639286ec1..8b704f73055 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -182,14 +182,8 @@
#include <linux/dma-mapping.h>
#include <scsi/sg.h>
-
#include "scsi.h"
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-#include "hosts.h"
-#else
#include <scsi/scsi_host.h>
-#endif
#include "ips.h"
@@ -250,11 +244,11 @@ module_param(ips, charp, 0);
*/
static int ips_detect(struct scsi_host_template *);
static int ips_release(struct Scsi_Host *);
-static int ips_eh_abort(Scsi_Cmnd *);
-static int ips_eh_reset(Scsi_Cmnd *);
-static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static int ips_eh_abort(struct scsi_cmnd *);
+static int ips_eh_reset(struct scsi_cmnd *);
+static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
static const char *ips_info(struct Scsi_Host *);
-static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
+static irqreturn_t do_ipsintr(int, void *);
static int ips_hainit(ips_ha_t *);
static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
@@ -325,24 +319,26 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
static uint32_t ips_statupd_morpheus(ips_ha_t *);
static ips_scb_t *ips_getscb(ips_ha_t *);
static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
-static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
+static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *);
static void ips_putq_copp_tail(ips_copp_queue_t *,
ips_copp_wait_item_t *);
static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
-static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
-static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
+static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *,
+ struct scsi_cmnd *);
static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
ips_copp_wait_item_t *);
static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
-static int ips_is_passthru(Scsi_Cmnd *);
-static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
+static int ips_is_passthru(struct scsi_cmnd *);
+static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
-static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
+static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
unsigned int count);
-static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
+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);
@@ -812,8 +808,7 @@ ips_halt(struct notifier_block *nb, ulong event, void *buf)
/* Abort a command (using the new error code stuff) */
/* Note: this routine is called under the io_request_lock */
/****************************************************************************/
-int
-ips_eh_abort(Scsi_Cmnd * SC)
+int ips_eh_abort(struct scsi_cmnd *SC)
{
ips_ha_t *ha;
ips_copp_wait_item_t *item;
@@ -871,8 +866,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
/* NOTE: this routine is called under the io_request_lock spinlock */
/* */
/****************************************************************************/
-static int
-__ips_eh_reset(Scsi_Cmnd * SC)
+static int __ips_eh_reset(struct scsi_cmnd *SC)
{
int ret;
int i;
@@ -968,7 +962,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
ret = (*ha->func.reset) (ha);
if (!ret) {
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
"Controller reset failed - controller now offline.\n");
@@ -997,7 +991,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
}
if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
"Controller reset failed - controller now offline.\n");
@@ -1059,8 +1053,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
}
-static int
-ips_eh_reset(Scsi_Cmnd * SC)
+static int ips_eh_reset(struct scsi_cmnd *SC)
{
int rc;
@@ -1083,8 +1076,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
/* Linux obtains io_request_lock before calling this function */
/* */
/****************************************************************************/
-static int
-ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
+static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
{
ips_ha_t *ha;
ips_passthru_t *pt;
@@ -1336,7 +1328,7 @@ ips_slave_configure(struct scsi_device * SDptr)
/* */
/****************************************************************************/
static irqreturn_t
-do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
+do_ipsintr(int irq, void *dev_id)
{
ips_ha_t *ha;
unsigned long cpu_flags;
@@ -1602,8 +1594,7 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
/* Determine if the specified SCSI command is really a passthru command */
/* */
/****************************************************************************/
-static int
-ips_is_passthru(Scsi_Cmnd * SC)
+static int ips_is_passthru(struct scsi_cmnd *SC)
{
unsigned long flags;
@@ -1685,7 +1676,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
/* */
/****************************************************************************/
static int
-ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
+ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
{
ips_passthru_t *pt;
int length = 0;
@@ -2734,9 +2725,9 @@ static void
ips_next(ips_ha_t * ha, int intr)
{
ips_scb_t *scb;
- Scsi_Cmnd *SC;
- Scsi_Cmnd *p;
- Scsi_Cmnd *q;
+ struct scsi_cmnd *SC;
+ struct scsi_cmnd *p;
+ struct scsi_cmnd *q;
ips_copp_wait_item_t *item;
int ret;
unsigned long cpu_flags = 0;
@@ -2847,7 +2838,7 @@ ips_next(ips_ha_t * ha, int intr)
dcdb_active[scmd_channel(p) -
1] & (1 << scmd_id(p)))) {
ips_freescb(ha, scb);
- p = (Scsi_Cmnd *) p->host_scribble;
+ p = (struct scsi_cmnd *) p->host_scribble;
continue;
}
@@ -2962,7 +2953,7 @@ ips_next(ips_ha_t * ha, int intr)
break;
} /* end case */
- p = (Scsi_Cmnd *) p->host_scribble;
+ p = (struct scsi_cmnd *) p->host_scribble;
} /* end while */
@@ -3090,8 +3081,7 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static void
-ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item)
{
METHOD_TRACE("ips_putq_wait_tail", 1);
@@ -3122,10 +3112,9 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static Scsi_Cmnd *
-ips_removeq_wait_head(ips_wait_queue_t * queue)
+static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue)
{
- Scsi_Cmnd *item;
+ struct scsi_cmnd *item;
METHOD_TRACE("ips_removeq_wait_head", 1);
@@ -3135,7 +3124,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
return (NULL);
}
- queue->head = (Scsi_Cmnd *) item->host_scribble;
+ queue->head = (struct scsi_cmnd *) item->host_scribble;
item->host_scribble = NULL;
if (queue->tail == item)
@@ -3157,10 +3146,10 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static Scsi_Cmnd *
-ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue,
+ struct scsi_cmnd *item)
{
- Scsi_Cmnd *p;
+ struct scsi_cmnd *p;
METHOD_TRACE("ips_removeq_wait", 1);
@@ -3173,8 +3162,8 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
p = queue->head;
- while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
- p = (Scsi_Cmnd *) p->host_scribble;
+ while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
+ p = (struct scsi_cmnd *) p->host_scribble;
if (p) {
/* found a match */
@@ -3659,11 +3648,10 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
/* Routine Name: ips_scmd_buf_write */
/* */
/* Routine Description: */
-/* Write data to Scsi_Cmnd request_buffer at proper offsets */
+/* Write data to struct scsi_cmnd request_buffer at proper offsets */
/****************************************************************************/
static void
-ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
- int count)
+ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
if (scmd->use_sg) {
int i;
@@ -3698,11 +3686,10 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
/* Routine Name: ips_scmd_buf_read */
/* */
/* Routine Description: */
-/* Copy data from a Scsi_Cmnd to a new, linear buffer */
+/* Copy data from a struct scsi_cmnd to a new, linear buffer */
/****************************************************************************/
static void
-ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
- int count)
+ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
if (scmd->use_sg) {
int i;
@@ -5014,7 +5001,7 @@ ips_init_copperhead(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 45)
@@ -5040,7 +5027,7 @@ ips_init_copperhead(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 240)
@@ -5058,7 +5045,7 @@ ips_init_copperhead(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 240)
@@ -5108,7 +5095,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 45)
@@ -5134,7 +5121,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (j >= 240)
@@ -5152,7 +5139,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 240)
@@ -5204,7 +5191,7 @@ ips_init_morpheus(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 45) {
@@ -5230,7 +5217,7 @@ ips_init_morpheus(ips_ha_t * ha)
if (Post != 0x4F00)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 120) {
@@ -5260,7 +5247,7 @@ ips_init_morpheus(ips_ha_t * ha)
break;
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
}
if (i >= 240) {
@@ -5320,12 +5307,12 @@ ips_reset_copperhead(ips_ha_t * ha)
outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
outb(0, ha->io_addr + IPS_REG_SCPR);
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
if ((*ha->func.init) (ha))
break;
@@ -5365,12 +5352,12 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
writeb(0, ha->mem_ptr + IPS_REG_SCPR);
/* Delay for 1 Second */
- msleep(IPS_ONE_SEC);
+ MDELAY(IPS_ONE_SEC);
if ((*ha->func.init) (ha))
break;
@@ -5411,7 +5398,7 @@ ips_reset_morpheus(ips_ha_t * ha)
writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
/* Delay for 5 Seconds */
- msleep(5 * IPS_ONE_SEC);
+ MDELAY(5 * IPS_ONE_SEC);
/* Do a PCI config read to wait for adapter */
pci_read_config_byte(ha->pcidev, 4, &junk);
@@ -7078,7 +7065,7 @@ ips_remove_device(struct pci_dev *pci_dev)
static int __init
ips_module_init(void)
{
- if (pci_module_init(&ips_pci_driver) < 0)
+ if (pci_register_driver(&ips_pci_driver) < 0)
return -ENODEV;
ips_driver_template.module = THIS_MODULE;
ips_order_controllers();
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index f46c382e559..b726dcc424b 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -6,7 +6,7 @@
/* David Jeffery, Adaptec, Inc. */
/* */
/* Copyright (C) 1999 IBM Corporation */
-/* Copyright (C) 2003 Adaptec, Inc. */
+/* Copyright (C) 2003 Adaptec, Inc. */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
@@ -51,6 +51,7 @@
#define _IPS_H_
#include <linux/version.h>
+#include <linux/nmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -116,9 +117,11 @@
dev_printk(level , &((pcidev)->dev) , format , ## arg)
#endif
- #ifndef MDELAY
- #define MDELAY mdelay
- #endif
+ #define MDELAY(n) \
+ do { \
+ mdelay(n); \
+ touch_nmi_watchdog(); \
+ } while (0)
#ifndef min
#define min(x,y) ((x) < (y) ? x : y)
@@ -1033,14 +1036,14 @@ typedef struct ips_scb_queue {
* Wait queue_format
*/
typedef struct ips_wait_queue {
- Scsi_Cmnd *head;
- Scsi_Cmnd *tail;
- int count;
+ struct scsi_cmnd *head;
+ struct scsi_cmnd *tail;
+ int count;
} ips_wait_queue_t;
typedef struct ips_copp_wait_item {
- Scsi_Cmnd *scsi_cmd;
- struct ips_copp_wait_item *next;
+ struct scsi_cmnd *scsi_cmd;
+ struct ips_copp_wait_item *next;
} ips_copp_wait_item_t;
typedef struct ips_copp_queue {
@@ -1149,7 +1152,7 @@ typedef struct ips_scb {
uint32_t flags;
uint32_t op_code;
IPS_SG_LIST sg_list;
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
struct ips_scb *q_next;
ips_scb_callback callback;
uint32_t sg_busaddr;
@@ -1175,7 +1178,7 @@ typedef struct ips_scb_pt {
uint32_t flags;
uint32_t op_code;
IPS_SG_LIST *sg_list;
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
struct ips_scb *q_next;
ips_scb_callback callback;
} ips_scb_pt_t;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 0a9dbc59663..d0b139cccbb 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -415,8 +415,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
iscsi_solicit_data_init(conn, ctask, r2t);
tcp_ctask->exp_r2tsn = r2tsn + 1;
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork);
@@ -1627,9 +1627,12 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- if (!tcp_ctask->r2t)
+ if (!tcp_ctask->r2t) {
+ spin_lock_bh(&session->lock);
__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
sizeof(void*));
+ spin_unlock_bh(&session->lock);
+ }
send_hdr:
r2t = tcp_ctask->r2t;
dtask = &r2t->dtask;
@@ -1816,21 +1819,14 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- int digest = 0;
-
- if (conn->hdrdgst_en || conn->datadgst_en)
- digest = 1;
iscsi_tcp_release_conn(conn);
iscsi_conn_teardown(cls_conn);
- /* now free tcp_conn */
- if (digest) {
- if (tcp_conn->tx_hash.tfm)
- crypto_free_hash(tcp_conn->tx_hash.tfm);
- if (tcp_conn->rx_hash.tfm)
- crypto_free_hash(tcp_conn->rx_hash.tfm);
- }
+ if (tcp_conn->tx_hash.tfm)
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
+ if (tcp_conn->rx_hash.tfm)
+ crypto_free_hash(tcp_conn->rx_hash.tfm);
kfree(tcp_conn);
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c542d0e95e6..e11b23c641e 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -481,8 +481,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
case ISCSI_OP_ASYNC_EVENT:
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- /* we need sth like iscsi_async_event_rsp() */
- rc = ISCSI_ERR_BAD_OPCODE;
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
@@ -578,6 +578,27 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
+static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+{
+ struct iscsi_hdr *hdr = conn->mtask->hdr;
+ int rc, was_logout = 0;
+
+ if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
+ conn->session->state = ISCSI_STATE_IN_RECOVERY;
+ iscsi_block_session(session_to_cls(conn->session));
+ was_logout = 1;
+ }
+ rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+ if (rc)
+ return rc;
+
+ if (was_logout) {
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ return -ENODATA;
+ }
+ return 0;
+}
+
/**
* iscsi_data_xmit - xmit any command into the scheduled connection
* @conn: iscsi connection
@@ -623,7 +644,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
conn->ctask = NULL;
}
if (conn->mtask) {
- rc = tt->xmit_mgmt_task(conn, conn->mtask);
+ rc = iscsi_xmit_imm_task(conn);
if (rc)
goto again;
/* done with this in-progress mtask */
@@ -638,7 +659,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
- rc = tt->xmit_mgmt_task(conn, conn->mtask);
+ rc = iscsi_xmit_imm_task(conn);
if (rc)
goto again;
}
@@ -661,8 +682,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
spin_unlock_bh(&conn->session->lock);
rc = tt->xmit_cmd_task(conn, conn->ctask);
- if (rc)
- goto again;
spin_lock_bh(&conn->session->lock);
__iscsi_put_ctask(conn->ctask);
@@ -700,9 +719,10 @@ again:
return rc;
}
-static void iscsi_xmitworker(void *data)
+static void iscsi_xmitworker(struct work_struct *work)
{
- struct iscsi_conn *conn = data;
+ struct iscsi_conn *conn =
+ container_of(work, struct iscsi_conn, xmitwork);
int rc;
/*
* serialize Xmit worker on a per-connection basis.
@@ -778,6 +798,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
}
conn = session->leadconn;
+ if (!conn) {
+ reason = FAILURE_SESSION_FREED;
+ goto fault;
+ }
if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
sizeof(void*))) {
@@ -952,13 +976,13 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
if (session->state == ISCSI_STATE_TERMINATE) {
failed:
debug_scsi("failing host reset: session terminated "
- "[CID %d age %d]", conn->id, session->age);
+ "[CID %d age %d]\n", conn->id, session->age);
spin_unlock_bh(&session->lock);
return FAILED;
}
if (sc->SCp.phase == session->age) {
- debug_scsi("failing connection CID %d due to SCSI host reset",
+ debug_scsi("failing connection CID %d due to SCSI host reset\n",
conn->id);
fail_session = 1;
}
@@ -1031,7 +1055,8 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
NULL, 0);
if (rc) {
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- debug_scsi("abort sent failure [itt 0x%x] %d", ctask->itt, rc);
+ debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt,
+ rc);
return rc;
}
@@ -1048,7 +1073,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
conn->tmabort_timer.function = iscsi_tmabort_timedout;
conn->tmabort_timer.data = (unsigned long)ctask;
add_timer(&conn->tmabort_timer);
- debug_scsi("abort set timeout [itt 0x%x]", ctask->itt);
+ debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
}
spin_unlock_bh(&session->lock);
mutex_unlock(&conn->xmitmutex);
@@ -1377,7 +1402,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
}
spin_lock_init(&session->lock);
- INIT_LIST_HEAD(&session->connections);
/* initialize immediate command pool */
if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max,
@@ -1489,7 +1513,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
goto mgmtqueue_alloc_fail;
- INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
+ INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
/* allocate login_mtask used for the login/text sequences */
spin_lock_bh(&session->lock);
@@ -1580,16 +1604,11 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
kfree(conn->persistent_address);
__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
sizeof(void*));
- list_del(&conn->item);
- if (list_empty(&session->connections))
+ if (session->leadconn == conn) {
session->leadconn = NULL;
- if (session->leadconn && session->leadconn == conn)
- session->leadconn = container_of(session->connections.next,
- struct iscsi_conn, item);
-
- if (session->leadconn == NULL)
/* no connections exits.. reset sequencing */
session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
+ }
spin_unlock_bh(&session->lock);
kfifo_free(conn->immqueue);
@@ -1777,32 +1796,12 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, int is_leading)
{
struct iscsi_session *session = class_to_transport_session(cls_session);
- struct iscsi_conn *tmp = ERR_PTR(-EEXIST), *conn = cls_conn->dd_data;
+ struct iscsi_conn *conn = cls_conn->dd_data;
- /* lookup for existing connection */
spin_lock_bh(&session->lock);
- list_for_each_entry(tmp, &session->connections, item) {
- if (tmp == conn) {
- if (conn->c_stage != ISCSI_CONN_STOPPED ||
- conn->stop_stage == STOP_CONN_TERM) {
- printk(KERN_ERR "iscsi: can't bind "
- "non-stopped connection (%d:%d)\n",
- conn->c_stage, conn->stop_stage);
- spin_unlock_bh(&session->lock);
- return -EIO;
- }
- break;
- }
- }
- if (tmp != conn) {
- /* bind new iSCSI connection to session */
- conn->session = session;
- list_add(&conn->item, &session->connections);
- }
- spin_unlock_bh(&session->lock);
-
if (is_leading)
session->leadconn = conn;
+ spin_unlock_bh(&session->lock);
/*
* Unblock xmitworker(), Login Phase will pass through.
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index d977bd492d8..fb7df7b7581 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -647,10 +647,12 @@ void sas_unregister_domain_devices(struct asd_sas_port *port)
* Discover process only interrogates devices in order to discover the
* domain.
*/
-static void sas_discover_domain(void *data)
+static void sas_discover_domain(struct work_struct *work)
{
int error = 0;
- struct asd_sas_port *port = data;
+ struct sas_discovery_event *ev =
+ container_of(work, struct sas_discovery_event, work);
+ struct asd_sas_port *port = ev->port;
sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
&port->disc.pending);
@@ -692,10 +694,12 @@ static void sas_discover_domain(void *data)
current->pid, error);
}
-static void sas_revalidate_domain(void *data)
+static void sas_revalidate_domain(struct work_struct *work)
{
int res = 0;
- struct asd_sas_port *port = data;
+ struct sas_discovery_event *ev =
+ container_of(work, struct sas_discovery_event, work);
+ struct asd_sas_port *port = ev->port;
sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
&port->disc.pending);
@@ -722,7 +726,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
BUG_ON(ev >= DISC_NUM_EVENTS);
sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
- &disc->disc_work[ev], port->ha->core.shost);
+ &disc->disc_work[ev].work, port->ha->core.shost);
return 0;
}
@@ -737,13 +741,15 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
{
int i;
- static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = {
+ static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
};
spin_lock_init(&disc->disc_event_lock);
disc->pending = 0;
- for (i = 0; i < DISC_NUM_EVENTS; i++)
- INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port);
+ for (i = 0; i < DISC_NUM_EVENTS; i++) {
+ INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
+ disc->disc_work[i].port = port;
+ }
}
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 19110ed1c89..d83392ee682 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
BUG_ON(event >= HA_NUM_EVENTS);
sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
- &sas_ha->ha_events[event], sas_ha->core.shost);
+ &sas_ha->ha_events[event].work, sas_ha->core.shost);
}
static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
@@ -41,7 +41,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
BUG_ON(event >= PORT_NUM_EVENTS);
sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
- &phy->port_events[event], ha->core.shost);
+ &phy->port_events[event].work, ha->core.shost);
}
static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
@@ -51,12 +51,12 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
BUG_ON(event >= PHY_NUM_EVENTS);
sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
- &phy->phy_events[event], ha->core.shost);
+ &phy->phy_events[event].work, ha->core.shost);
}
int sas_init_events(struct sas_ha_struct *sas_ha)
{
- static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = {
+ static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
[HAE_RESET] = sas_hae_reset,
};
@@ -64,8 +64,10 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
spin_lock_init(&sas_ha->event_lock);
- for (i = 0; i < HA_NUM_EVENTS; i++)
- INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha);
+ for (i = 0; i < HA_NUM_EVENTS; i++) {
+ INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
+ sas_ha->ha_events[i].ha = sas_ha;
+ }
sas_ha->notify_ha_event = notify_ha_event;
sas_ha->notify_port_event = notify_port_event;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 30b8014bcc7..d31e6fa466f 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -71,55 +71,65 @@ static void smp_task_done(struct sas_task *task)
static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
void *resp, int resp_size)
{
- int res;
- struct sas_task *task = sas_alloc_task(GFP_KERNEL);
+ int res, retry;
+ struct sas_task *task = NULL;
struct sas_internal *i =
to_sas_internal(dev->port->ha->core.shost->transportt);
- if (!task)
- return -ENOMEM;
-
- task->dev = dev;
- task->task_proto = dev->tproto;
- sg_init_one(&task->smp_task.smp_req, req, req_size);
- sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
+ for (retry = 0; retry < 3; retry++) {
+ task = sas_alloc_task(GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
- task->task_done = smp_task_done;
+ task->dev = dev;
+ task->task_proto = dev->tproto;
+ sg_init_one(&task->smp_task.smp_req, req, req_size);
+ sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
- task->timer.data = (unsigned long) task;
- task->timer.function = smp_task_timedout;
- task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
- add_timer(&task->timer);
+ task->task_done = smp_task_done;
- res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ task->timer.data = (unsigned long) task;
+ task->timer.function = smp_task_timedout;
+ task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+ add_timer(&task->timer);
- if (res) {
- del_timer(&task->timer);
- SAS_DPRINTK("executing SMP task failed:%d\n", res);
- goto ex_err;
- }
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
- wait_for_completion(&task->completion);
- res = -ETASK;
- if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
- SAS_DPRINTK("smp task timed out or aborted\n");
- i->dft->lldd_abort_task(task);
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
- SAS_DPRINTK("SMP task aborted and not done\n");
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SMP task failed:%d\n", res);
goto ex_err;
}
+
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ SAS_DPRINTK("smp task timed out or aborted\n");
+ i->dft->lldd_abort_task(task);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ SAS_DPRINTK("SMP task aborted and not done\n");
+ goto ex_err;
+ }
+ }
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_GOOD) {
+ res = 0;
+ break;
+ } else {
+ SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
+ "status 0x%x\n", __FUNCTION__,
+ SAS_ADDR(dev->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat);
+ sas_free_task(task);
+ task = NULL;
+ }
}
- if (task->task_status.resp == SAS_TASK_COMPLETE &&
- task->task_status.stat == SAM_GOOD)
- res = 0;
- else
- SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
- "status 0x%x\n", __FUNCTION__,
- SAS_ADDR(dev->sas_addr),
- task->task_status.resp,
- task->task_status.stat);
ex_err:
- sas_free_task(task);
+ BUG_ON(retry == 3 && task != NULL);
+ if (task != NULL) {
+ sas_free_task(task);
+ }
return res;
}
@@ -587,10 +597,15 @@ static struct domain_device *sas_ex_discover_end_dev(
child->iproto = phy->attached_iproto;
memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
- phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
- BUG_ON(!phy->port);
- /* FIXME: better error handling*/
- BUG_ON(sas_port_add(phy->port) != 0);
+ if (!phy->port) {
+ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
+ if (unlikely(!phy->port))
+ goto out_err;
+ if (unlikely(sas_port_add(phy->port) != 0)) {
+ sas_port_free(phy->port);
+ goto out_err;
+ }
+ }
sas_ex_get_linkrate(parent, child, phy);
if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
@@ -605,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
"0x%x\n", SAS_ADDR(parent->sas_addr),
phy_id, res);
- kfree(child);
- return NULL;
+ goto out_free;
}
memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
sizeof(struct dev_to_host_fis));
@@ -617,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev(
"%016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
- kfree(child);
- return NULL;
+ goto out_free;
}
} else if (phy->attached_tproto & SAS_PROTO_SSP) {
child->dev_type = SAS_END_DEV;
rphy = sas_end_device_alloc(phy->port);
/* FIXME: error handling */
- BUG_ON(!rphy);
+ if (unlikely(!rphy))
+ goto out_free;
child->tproto = phy->attached_tproto;
sas_init_dev(child);
@@ -641,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev(
"at %016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
- /* FIXME: this kfrees list elements without removing them */
- //kfree(child);
- return NULL;
+ goto out_list_del;
}
} else {
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
@@ -653,6 +665,16 @@ static struct domain_device *sas_ex_discover_end_dev(
list_add_tail(&child->siblings, &parent_ex->children);
return child;
+
+ out_list_del:
+ list_del(&child->dev_list_node);
+ sas_rphy_free(rphy);
+ out_free:
+ sas_port_delete(phy->port);
+ out_err:
+ phy->port = NULL;
+ kfree(child);
+ return NULL;
}
static struct domain_device *sas_ex_discover_expander(
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index c836a237fb7..2f0c07fc3f4 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -36,7 +36,7 @@
#include "../scsi_sas_internal.h"
-kmem_cache_t *sas_task_cache;
+struct kmem_cache *sas_task_cache;
/*------------ SAS addr hash -----------*/
void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
@@ -65,9 +65,11 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
/* ---------- HA events ---------- */
-void sas_hae_reset(void *data)
+void sas_hae_reset(struct work_struct *work)
{
- struct sas_ha_struct *ha = data;
+ struct sas_ha_event *ev =
+ container_of(work, struct sas_ha_event, work);
+ struct sas_ha_struct *ha = ev->ha;
sas_begin_event(HAE_RESET, &ha->event_lock,
&ha->pending);
@@ -112,6 +114,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
}
}
+ INIT_LIST_HEAD(&sas_ha->eh_done_q);
+
return 0;
Undo_ports:
@@ -142,7 +146,7 @@ static int sas_get_linkerrors(struct sas_phy *phy)
return sas_smp_get_phy_events(phy);
}
-static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
+int sas_phy_reset(struct sas_phy *phy, int hard_reset)
{
int ret;
enum phy_func reset_type;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index bffcee47492..137d7e496b6 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -60,11 +60,11 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
void sas_deform_port(struct asd_sas_phy *phy);
-void sas_porte_bytes_dmaed(void *);
-void sas_porte_broadcast_rcvd(void *);
-void sas_porte_link_reset_err(void *);
-void sas_porte_timer_event(void *);
-void sas_porte_hard_reset(void *);
+void sas_porte_bytes_dmaed(struct work_struct *work);
+void sas_porte_broadcast_rcvd(struct work_struct *work);
+void sas_porte_link_reset_err(struct work_struct *work);
+void sas_porte_timer_event(struct work_struct *work);
+void sas_porte_hard_reset(struct work_struct *work);
int sas_notify_lldd_dev_found(struct domain_device *);
void sas_notify_lldd_dev_gone(struct domain_device *);
@@ -75,7 +75,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy);
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
-void sas_hae_reset(void *);
+void sas_hae_reset(struct work_struct *work);
static inline void sas_queue_event(int event, spinlock_t *lock,
unsigned long *pending,
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 9340cdbae4a..b459c4b635b 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -30,9 +30,11 @@
/* ---------- Phy events ---------- */
-static void sas_phye_loss_of_signal(void *data)
+static void sas_phye_loss_of_signal(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
&phy->phy_events_pending);
@@ -40,18 +42,22 @@ static void sas_phye_loss_of_signal(void *data)
sas_deform_port(phy);
}
-static void sas_phye_oob_done(void *data)
+static void sas_phye_oob_done(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
&phy->phy_events_pending);
phy->error = 0;
}
-static void sas_phye_oob_error(void *data)
+static void sas_phye_oob_error(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
struct sas_ha_struct *sas_ha = phy->ha;
struct asd_sas_port *port = phy->port;
struct sas_internal *i =
@@ -80,9 +86,11 @@ static void sas_phye_oob_error(void *data)
}
}
-static void sas_phye_spinup_hold(void *data)
+static void sas_phye_spinup_hold(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
struct sas_ha_struct *sas_ha = phy->ha;
struct sas_internal *i =
to_sas_internal(sas_ha->core.shost->transportt);
@@ -100,14 +108,14 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
{
int i;
- static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = {
+ static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
[PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
[PHYE_OOB_DONE] = sas_phye_oob_done,
[PHYE_OOB_ERROR] = sas_phye_oob_error,
[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
};
- static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = {
+ static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
[PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
[PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
[PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
@@ -122,13 +130,18 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
phy->error = 0;
INIT_LIST_HEAD(&phy->port_phy_el);
- for (k = 0; k < PORT_NUM_EVENTS; k++)
- INIT_WORK(&phy->port_events[k], sas_port_event_fns[k],
- phy);
+ for (k = 0; k < PORT_NUM_EVENTS; k++) {
+ INIT_WORK(&phy->port_events[k].work,
+ sas_port_event_fns[k]);
+ phy->port_events[k].phy = phy;
+ }
+
+ for (k = 0; k < PHY_NUM_EVENTS; k++) {
+ INIT_WORK(&phy->phy_events[k].work,
+ sas_phy_event_fns[k]);
+ phy->phy_events[k].phy = phy;
+ }
- for (k = 0; k < PHY_NUM_EVENTS; k++)
- INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k],
- phy);
phy->port = NULL;
phy->ha = sas_ha;
spin_lock_init(&phy->frame_rcvd_lock);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 253cdcf306a..971c37ceecb 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -181,9 +181,11 @@ void sas_deform_port(struct asd_sas_phy *phy)
/* ---------- SAS port events ---------- */
-void sas_porte_bytes_dmaed(void *data)
+void sas_porte_bytes_dmaed(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
&phy->port_events_pending);
@@ -191,11 +193,13 @@ void sas_porte_bytes_dmaed(void *data)
sas_form_port(phy);
}
-void sas_porte_broadcast_rcvd(void *data)
+void sas_porte_broadcast_rcvd(struct work_struct *work)
{
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
unsigned long flags;
u32 prim;
- struct asd_sas_phy *phy = data;
sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
&phy->port_events_pending);
@@ -208,9 +212,11 @@ void sas_porte_broadcast_rcvd(void *data)
sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
}
-void sas_porte_link_reset_err(void *data)
+void sas_porte_link_reset_err(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
&phy->port_events_pending);
@@ -218,9 +224,11 @@ void sas_porte_link_reset_err(void *data)
sas_deform_port(phy);
}
-void sas_porte_timer_event(void *data)
+void sas_porte_timer_event(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
&phy->port_events_pending);
@@ -228,9 +236,11 @@ void sas_porte_timer_event(void *data)
sas_deform_port(phy);
}
-void sas_porte_hard_reset(void *data)
+void sas_porte_hard_reset(struct work_struct *work)
{
- struct asd_sas_phy *phy = data;
+ struct asd_sas_event *ev =
+ container_of(work, struct asd_sas_event, work);
+ struct asd_sas_phy *phy = ev->phy;
sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
&phy->port_events_pending);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7f9e89bcac7..22672d54aa2 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -29,9 +29,11 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_sas.h>
#include "../scsi_sas_internal.h"
+#include "../scsi_transport_api.h"
#include <linux/err.h>
#include <linux/blkdev.h>
@@ -46,6 +48,7 @@ static void sas_scsi_task_done(struct sas_task *task)
{
struct task_status_struct *ts = &task->task_status;
struct scsi_cmnd *sc = task->uldd_task;
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host);
unsigned ts_flags = task->task_state_flags;
int hs = 0, stat = 0;
@@ -116,7 +119,7 @@ static void sas_scsi_task_done(struct sas_task *task)
sas_free_task(task);
/* This is very ugly but this is how SCSI Core works. */
if (ts_flags & SAS_TASK_STATE_ABORTED)
- scsi_finish_command(sc);
+ scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q);
else
sc->scsi_done(sc);
}
@@ -126,7 +129,7 @@ static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
enum task_attribute ta = TASK_ATTR_SIMPLE;
if (cmd->request && blk_rq_tagged(cmd->request)) {
if (cmd->device->ordered_tags &&
- (cmd->request->flags & REQ_HARDBARRIER))
+ (cmd->request->cmd_flags & REQ_HARDBARRIER))
ta = TASK_ATTR_HOQ;
}
return ta;
@@ -307,6 +310,15 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
spin_unlock_irqrestore(&core->task_queue_lock, flags);
}
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("%s: task 0x%p already aborted\n",
+ __FUNCTION__, task);
+ return TASK_IS_ABORTED;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
for (i = 0; i < 5; i++) {
SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
res = si->dft->lldd_abort_task(task);
@@ -409,13 +421,16 @@ Again:
SAS_DPRINTK("going over list...\n");
list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
struct sas_task *task = TO_SAS_TASK(cmd);
+ list_del_init(&cmd->eh_entry);
+ if (!task) {
+ SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__);
+ continue;
+ }
SAS_DPRINTK("trying to find task 0x%p\n", task);
- list_del_init(&cmd->eh_entry);
res = sas_scsi_find_task(task);
cmd->eh_eflags = 0;
- shost->host_failed--;
switch (res) {
case TASK_IS_DONE:
@@ -491,6 +506,7 @@ Again:
}
}
out:
+ scsi_eh_flush_done_q(&ha->eh_done_q);
SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
return;
clear_q:
@@ -508,12 +524,18 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
unsigned long flags;
if (!task) {
- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+ SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n",
cmd, task);
return EH_HANDLED;
}
spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: "
+ "EH_NOT_HANDLED\n", cmd, task);
+ return EH_NOT_HANDLED;
+ }
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
@@ -777,6 +799,66 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
spin_unlock_irqrestore(&core->task_queue_lock, flags);
}
+static int do_sas_task_abort(struct sas_task *task)
+{
+ struct scsi_cmnd *sc = task->uldd_task;
+ struct sas_internal *si =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+ unsigned long flags;
+ int res;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__,
+ task);
+ return 0;
+ }
+
+ task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED;
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ if (!si->dft->lldd_abort_task)
+ return -ENODEV;
+
+ res = si->dft->lldd_abort_task(task);
+ if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
+ (res == TMF_RESP_FUNC_COMPLETE))
+ {
+ /* SMP commands don't have scsi_cmds(?) */
+ if (!sc) {
+ task->task_done(task);
+ return 0;
+ }
+ scsi_req_abort_cmd(sc);
+ scsi_schedule_eh(sc->device->host);
+ return 0;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED;
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ return -EAGAIN;
+}
+
+void sas_task_abort(struct work_struct *work)
+{
+ struct sas_task *task =
+ container_of(work, struct sas_task, abort_work);
+ int i;
+
+ for (i = 0; i < 5; i++)
+ if (!do_sas_task_abort(task))
+ return;
+
+ SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__);
+}
+
EXPORT_SYMBOL_GPL(sas_queuecommand);
EXPORT_SYMBOL_GPL(sas_target_alloc);
EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -784,3 +866,5 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy);
EXPORT_SYMBOL_GPL(sas_change_queue_depth);
EXPORT_SYMBOL_GPL(sas_change_queue_type);
EXPORT_SYMBOL_GPL(sas_bios_param);
+EXPORT_SYMBOL_GPL(sas_task_abort);
+EXPORT_SYMBOL_GPL(sas_phy_reset);
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
new file mode 100644
index 00000000000..89403b00e04
--- /dev/null
+++ b/drivers/scsi/libsrp.c
@@ -0,0 +1,441 @@
+/*
+ * SCSI RDAM Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/srp.h>
+#include <scsi/libsrp.h>
+
+enum srp_task_attributes {
+ SRP_SIMPLE_TASK = 0,
+ SRP_HEAD_TASK = 1,
+ SRP_ORDERED_TASK = 2,
+ SRP_ACA_TASK = 4
+};
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...) \
+do { \
+ printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
+} while (0)
+/* #define dprintk eprintk */
+#define dprintk(fmt, args...)
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+ struct srp_buf **ring)
+{
+ int i;
+ struct iu_entry *iue;
+
+ q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+ if (!q->pool)
+ return -ENOMEM;
+ q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+ if (!q->items)
+ goto free_pool;
+
+ spin_lock_init(&q->lock);
+ q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
+ GFP_KERNEL, &q->lock);
+ if (IS_ERR(q->queue))
+ goto free_item;
+
+ for (i = 0, iue = q->items; i < max; i++) {
+ __kfifo_put(q->queue, (void *) &iue, sizeof(void *));
+ iue->sbuf = ring[i];
+ iue++;
+ }
+ return 0;
+
+free_item:
+ kfree(q->items);
+free_pool:
+ kfree(q->pool);
+ return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+ kfree(q->items);
+ kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+ size_t max, size_t size)
+{
+ int i;
+ struct srp_buf **ring;
+
+ ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+ if (!ring)
+ return NULL;
+
+ for (i = 0; i < max; i++) {
+ ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
+ if (!ring[i])
+ goto out;
+ ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+ GFP_KERNEL);
+ if (!ring[i]->buf)
+ goto out;
+ }
+ return ring;
+
+out:
+ for (i = 0; i < max && ring[i]; i++) {
+ if (ring[i]->buf)
+ dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+ kfree(ring[i]);
+ }
+ kfree(ring);
+
+ return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
+ size_t size)
+{
+ int i;
+
+ for (i = 0; i < max; i++) {
+ dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+ kfree(ring[i]);
+ }
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+ size_t nr, size_t iu_size)
+{
+ int err;
+
+ spin_lock_init(&target->lock);
+ INIT_LIST_HEAD(&target->cmd_queue);
+
+ target->dev = dev;
+ target->dev->driver_data = target;
+
+ target->srp_iu_size = iu_size;
+ target->rx_ring_size = nr;
+ target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+ if (!target->rx_ring)
+ return -ENOMEM;
+ err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+ if (err)
+ goto free_ring;
+
+ return 0;
+
+free_ring:
+ srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(srp_target_alloc);
+
+void srp_target_free(struct srp_target *target)
+{
+ srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+ target->srp_iu_size);
+ srp_iu_pool_free(&target->iu_queue);
+}
+EXPORT_SYMBOL_GPL(srp_target_free);
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+ struct iu_entry *iue = NULL;
+
+ kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
+ if (!iue)
+ return iue;
+ iue->target = target;
+ INIT_LIST_HEAD(&iue->ilist);
+ iue->flags = 0;
+ return iue;
+}
+EXPORT_SYMBOL_GPL(srp_iu_get);
+
+void srp_iu_put(struct iu_entry *iue)
+{
+ kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
+}
+EXPORT_SYMBOL_GPL(srp_iu_put);
+
+static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
+ enum dma_data_direction dir, srp_rdma_t rdma_io,
+ int dma_map, int ext_desc)
+{
+ struct iu_entry *iue = NULL;
+ struct scatterlist *sg = NULL;
+ int err, nsg = 0, len;
+
+ if (dma_map) {
+ iue = (struct iu_entry *) sc->SCp.ptr;
+ sg = sc->request_buffer;
+
+ dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
+ md->len, sc->use_sg);
+
+ nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
+ DMA_BIDIRECTIONAL);
+ if (!nsg) {
+ printk("fail to map %p %d\n", iue, sc->use_sg);
+ return 0;
+ }
+ len = min(sc->request_bufflen, md->len);
+ } else
+ len = md->len;
+
+ err = rdma_io(sc, sg, nsg, md, 1, dir, len);
+
+ if (dma_map)
+ dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+ return err;
+}
+
+static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+ struct srp_indirect_buf *id,
+ enum dma_data_direction dir, srp_rdma_t rdma_io,
+ int dma_map, int ext_desc)
+{
+ struct iu_entry *iue = NULL;
+ struct srp_direct_buf *md = NULL;
+ struct scatterlist dummy, *sg = NULL;
+ dma_addr_t token = 0;
+ long err;
+ unsigned int done = 0;
+ int nmd, nsg = 0, len;
+
+ if (dma_map || ext_desc) {
+ iue = (struct iu_entry *) sc->SCp.ptr;
+ sg = sc->request_buffer;
+
+ dprintk("%p %u %u %d %d\n",
+ iue, sc->request_bufflen, id->len,
+ cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
+ }
+
+ nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
+
+ if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
+ (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
+ md = &id->desc_list[0];
+ goto rdma;
+ }
+
+ if (ext_desc && dma_map) {
+ md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
+ &token, GFP_KERNEL);
+ if (!md) {
+ eprintk("Can't get dma memory %u\n", id->table_desc.len);
+ return -ENOMEM;
+ }
+
+ sg_init_one(&dummy, md, id->table_desc.len);
+ sg_dma_address(&dummy) = token;
+ err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+ id->table_desc.len);
+ if (err < 0) {
+ eprintk("Error copying indirect table %ld\n", err);
+ goto free_mem;
+ }
+ } else {
+ eprintk("This command uses external indirect buffer\n");
+ return -EINVAL;
+ }
+
+rdma:
+ if (dma_map) {
+ nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
+ if (!nsg) {
+ eprintk("fail to map %p %d\n", iue, sc->use_sg);
+ goto free_mem;
+ }
+ len = min(sc->request_bufflen, id->len);
+ } else
+ len = id->len;
+
+ err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
+
+ if (dma_map)
+ dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+ if (token && dma_map)
+ dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
+
+ return done;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+ int size = 0;
+ u8 fmt = cmd->buf_fmt >> 4;
+
+ switch (fmt) {
+ case SRP_NO_DATA_DESC:
+ break;
+ case SRP_DATA_DESC_DIRECT:
+ size = sizeof(struct srp_direct_buf);
+ break;
+ case SRP_DATA_DESC_INDIRECT:
+ size = sizeof(struct srp_indirect_buf) +
+ sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+ break;
+ default:
+ eprintk("client error. Invalid data_out_format %x\n", fmt);
+ break;
+ }
+ return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+ srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+ struct srp_direct_buf *md;
+ struct srp_indirect_buf *id;
+ enum dma_data_direction dir;
+ int offset, err = 0;
+ u8 format;
+
+ offset = cmd->add_cdb_len * 4;
+
+ dir = srp_cmd_direction(cmd);
+ if (dir == DMA_FROM_DEVICE)
+ offset += data_out_desc_size(cmd);
+
+ if (dir == DMA_TO_DEVICE)
+ format = cmd->buf_fmt >> 4;
+ else
+ format = cmd->buf_fmt & ((1U << 4) - 1);
+
+ switch (format) {
+ case SRP_NO_DATA_DESC:
+ break;
+ case SRP_DATA_DESC_DIRECT:
+ md = (struct srp_direct_buf *)
+ (cmd->add_data + offset);
+ err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
+ break;
+ case SRP_DATA_DESC_INDIRECT:
+ id = (struct srp_indirect_buf *)
+ (cmd->add_data + offset);
+ err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
+ ext_desc);
+ break;
+ default:
+ eprintk("Unknown format %d %x\n", dir, format);
+ break;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(srp_transfer_data);
+
+static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+ struct srp_direct_buf *md;
+ struct srp_indirect_buf *id;
+ int len = 0, offset = cmd->add_cdb_len * 4;
+ u8 fmt;
+
+ if (dir == DMA_TO_DEVICE)
+ fmt = cmd->buf_fmt >> 4;
+ else {
+ fmt = cmd->buf_fmt & ((1U << 4) - 1);
+ offset += data_out_desc_size(cmd);
+ }
+
+ switch (fmt) {
+ case SRP_NO_DATA_DESC:
+ break;
+ case SRP_DATA_DESC_DIRECT:
+ md = (struct srp_direct_buf *) (cmd->add_data + offset);
+ len = md->len;
+ break;
+ case SRP_DATA_DESC_INDIRECT:
+ id = (struct srp_indirect_buf *) (cmd->add_data + offset);
+ len = id->len;
+ break;
+ default:
+ eprintk("invalid data format %x\n", fmt);
+ break;
+ }
+ return len;
+}
+
+int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
+ u64 addr)
+{
+ enum dma_data_direction dir;
+ struct scsi_cmnd *sc;
+ int tag, len, err;
+
+ switch (cmd->task_attr) {
+ case SRP_SIMPLE_TASK:
+ tag = MSG_SIMPLE_TAG;
+ break;
+ case SRP_ORDERED_TASK:
+ tag = MSG_ORDERED_TAG;
+ break;
+ case SRP_HEAD_TASK:
+ tag = MSG_HEAD_TAG;
+ break;
+ default:
+ eprintk("Task attribute %d not supported\n", cmd->task_attr);
+ tag = MSG_ORDERED_TAG;
+ }
+
+ dir = srp_cmd_direction(cmd);
+ len = vscsis_data_length(cmd, dir);
+
+ dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0],
+ cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
+
+ sc = scsi_host_get_command(shost, dir, GFP_KERNEL);
+ if (!sc)
+ return -ENOMEM;
+
+ sc->SCp.ptr = info;
+ memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
+ sc->request_bufflen = len;
+ sc->request_buffer = (void *) (unsigned long) addr;
+ sc->tag = tag;
+ err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+ if (err)
+ scsi_host_put_command(shost, sc);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(srp_cmd_queue);
+
+MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 3f7f5f8abd7..a7de0bca5bd 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -296,13 +296,17 @@ struct lpfc_hba {
uint32_t cfg_cr_delay;
uint32_t cfg_cr_count;
uint32_t cfg_multi_ring_support;
+ uint32_t cfg_multi_ring_rctl;
+ uint32_t cfg_multi_ring_type;
uint32_t cfg_fdmi_on;
uint32_t cfg_discovery_threads;
uint32_t cfg_max_luns;
uint32_t cfg_poll;
uint32_t cfg_poll_tmo;
+ uint32_t cfg_use_msi;
uint32_t cfg_sg_seg_cnt;
uint32_t cfg_sg_dma_buf_size;
+ uint64_t cfg_soft_wwnn;
uint64_t cfg_soft_wwpn;
uint32_t dev_loss_tmo_changed;
@@ -355,7 +359,7 @@ struct lpfc_hba {
#define VPD_PORT 0x8 /* valid vpd port data */
#define VPD_MASK 0xf /* mask for any vpd data */
- uint8_t soft_wwpn_enable;
+ uint8_t soft_wwn_enable;
struct timer_list fcp_poll_timer;
struct timer_list els_tmofunc;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 9496e87c135..f247e786af9 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -552,10 +552,10 @@ static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
-static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
+static char *lpfc_soft_wwn_key = "C99G71SL8032A";
static ssize_t
-lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
+lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf,
size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
@@ -579,22 +579,23 @@ lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
if (buf[cnt-1] == '\n')
cnt--;
- if ((cnt != strlen(lpfc_soft_wwpn_key)) ||
- (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0))
+ if ((cnt != strlen(lpfc_soft_wwn_key)) ||
+ (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0))
return -EINVAL;
- phba->soft_wwpn_enable = 1;
+ phba->soft_wwn_enable = 1;
return count;
}
-static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
- lpfc_soft_wwpn_enable_store);
+static CLASS_DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL,
+ lpfc_soft_wwn_enable_store);
static ssize_t
lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n", phba->cfg_soft_wwpn);
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ (unsigned long long)phba->cfg_soft_wwpn);
}
@@ -612,12 +613,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
if (buf[cnt-1] == '\n')
cnt--;
- if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
+ if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
((cnt == 17) && (*buf++ != 'x')) ||
((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
return -EINVAL;
- phba->soft_wwpn_enable = 0;
+ phba->soft_wwn_enable = 0;
memset(wwpn, 0, sizeof(wwpn));
@@ -638,6 +639,8 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
}
phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
fc_host_port_name(host) = phba->cfg_soft_wwpn;
+ if (phba->cfg_soft_wwnn)
+ fc_host_node_name(host) = phba->cfg_soft_wwnn;
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
"lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
@@ -663,6 +666,66 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
+static ssize_t
+lpfc_soft_wwnn_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ (unsigned long long)phba->cfg_soft_wwnn);
+}
+
+
+static ssize_t
+lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ unsigned int i, j, cnt=count;
+ u8 wwnn[8];
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
+ ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ /*
+ * Allow wwnn to be set many times, as long as the enable is set.
+ * However, once the wwpn is set, everything locks.
+ */
+
+ memset(wwnn, 0, sizeof(wwnn));
+
+ /* Validate and store the new name */
+ for (i=0, j=0; i < 16; i++) {
+ if ((*buf >= 'a') && (*buf <= 'f'))
+ j = ((j << 4) | ((*buf++ -'a') + 10));
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ j = ((j << 4) | ((*buf++ -'A') + 10));
+ else if ((*buf >= '0') && (*buf <= '9'))
+ j = ((j << 4) | (*buf++ -'0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwnn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ phba->cfg_soft_wwnn = wwn_to_u64(wwnn);
+
+ dev_printk(KERN_NOTICE, &phba->pcidev->dev,
+ "lpfc%d: soft_wwnn set. Value will take effect upon "
+ "setting of the soft_wwpn\n", phba->brd_no);
+
+ return count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\
+ lpfc_soft_wwnn_show, lpfc_soft_wwnn_store);
+
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
@@ -801,12 +864,11 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
# LOG_MBOX 0x4 Mailbox events
# LOG_INIT 0x8 Initialization events
# LOG_LINK_EVENT 0x10 Link events
-# LOG_IP 0x20 IP traffic history
# LOG_FCP 0x40 FCP traffic history
# LOG_NODE 0x80 Node table events
# LOG_MISC 0x400 Miscellaneous events
# LOG_SLI 0x800 SLI events
-# LOG_CHK_COND 0x1000 FCP Check condition flag
+# LOG_FCP_ERROR 0x1000 Only log FCP errors
# LOG_LIBDFC 0x2000 LIBDFC events
# LOG_ALL_MSG 0xffff LOG all messages
*/
@@ -915,6 +977,22 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
"SLI rings to spread IOCB entries across");
/*
+# lpfc_multi_ring_rctl: If lpfc_multi_ring_support is enabled, this
+# identifies what rctl value to configure the additional ring for.
+# Value range is [1,0xff]. Default value is 4 (Unsolicated Data).
+*/
+LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
+ 255, "Identifies RCTL for additional ring configuration");
+
+/*
+# lpfc_multi_ring_type: If lpfc_multi_ring_support is enabled, this
+# identifies what type value to configure the additional ring for.
+# Value range is [1,0xff]. Default value is 5 (LLC/SNAP).
+*/
+LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1,
+ 255, "Identifies TYPE for additional ring configuration");
+
+/*
# lpfc_fdmi_on: controls FDMI support.
# 0 = no FDMI support
# 1 = support FDMI without attribute of hostname
@@ -945,6 +1023,15 @@ LPFC_ATTR_R(max_luns, 255, 0, 65535,
LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
"Milliseconds driver will wait between polling FCP ring");
+/*
+# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
+# support this feature
+# 0 = MSI disabled (default)
+# 1 = MSI enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
+
struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_info,
@@ -973,6 +1060,8 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_cr_delay,
&class_device_attr_lpfc_cr_count,
&class_device_attr_lpfc_multi_ring_support,
+ &class_device_attr_lpfc_multi_ring_rctl,
+ &class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
@@ -981,8 +1070,10 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
+ &class_device_attr_lpfc_use_msi,
+ &class_device_attr_lpfc_soft_wwnn,
&class_device_attr_lpfc_soft_wwpn,
- &class_device_attr_lpfc_soft_wwpn_enable,
+ &class_device_attr_lpfc_soft_wwn_enable,
NULL,
};
@@ -1770,6 +1861,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_cr_delay_init(phba, lpfc_cr_delay);
lpfc_cr_count_init(phba, lpfc_cr_count);
lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
+ lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl);
+ lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
lpfc_fcp_class_init(phba, lpfc_fcp_class);
lpfc_use_adisc_init(phba, lpfc_use_adisc);
@@ -1781,9 +1874,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+ lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
phba->cfg_poll = lpfc_poll;
+ phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
/*
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 3d684496acd..1251788ce2a 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -120,7 +120,7 @@ int lpfc_sli_queue_setup(struct lpfc_hba *);
void lpfc_handle_eratt(struct lpfc_hba *);
void lpfc_handle_latt(struct lpfc_hba *);
-irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
+irqreturn_t lpfc_intr_handler(int, void *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index ae410645899..a51a41b7f15 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -188,7 +188,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
if (!mp->virt) {
kfree(mp);
- lpfc_free_ct_rsp(phba, mlist);
+ if (mlist)
+ lpfc_free_ct_rsp(phba, mlist);
return NULL;
}
@@ -557,6 +558,14 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
return;
}
+static void
+lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+ struct lpfc_iocbq * rspiocb)
+{
+ lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+ return;
+}
+
void
lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
{
@@ -628,6 +637,8 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSNN_NN)
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_RFF_ID)
+ bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
else
bpl->tus.f.bdeSize = 0;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
@@ -659,6 +670,17 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
cmpl = lpfc_cmpl_ct_cmd_rft_id;
break;
+ case SLI_CTNS_RFF_ID:
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_RFF_ID);
+ CtReq->un.rff.PortId = be32_to_cpu(phba->fc_myDID);
+ CtReq->un.rff.feature_res = 0;
+ CtReq->un.rff.feature_tgt = 0;
+ CtReq->un.rff.type_code = FC_FCP_DATA;
+ CtReq->un.rff.feature_init = 1;
+ cmpl = lpfc_cmpl_ct_cmd_rff_id;
+ break;
+
case SLI_CTNS_RNN_ID:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RNN_ID);
@@ -933,8 +955,9 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
sprintf(ae->un.OsNameVersion, "%s %s %s",
- system_utsname.sysname, system_utsname.release,
- system_utsname.version);
+ init_utsname()->sysname,
+ init_utsname()->release,
+ init_utsname()->version);
len = strlen(ae->un.OsNameVersion);
len += (len & 3) ? (4 - (len & 3)) : 4;
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
@@ -1052,7 +1075,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
size);
ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME);
sprintf(ae->un.HostName, "%s",
- system_utsname.nodename);
+ init_utsname()->nodename);
len = strlen(ae->un.HostName);
len += (len & 3) ? (4 - (len & 3)) : 4;
ae->ad.bits.AttrLen =
@@ -1140,7 +1163,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
if (ndlp) {
- if (system_utsname.nodename[0] != '\0') {
+ if (init_utsname()->nodename[0] != '\0') {
lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
} else {
mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 71864cdc6c7..a5f33a0dd4e 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -243,6 +243,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
struct serv_parm *sp, IOCB_t *irsp)
{
LPFC_MBOXQ_t *mbox;
+ struct lpfc_dmabuf *mp;
int rc;
spin_lock_irq(phba->host->host_lock);
@@ -307,10 +308,14 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
if (rc == MBX_NOT_FINISHED)
- goto fail_free_mbox;
+ goto fail_issue_reg_login;
return 0;
+ fail_issue_reg_login:
+ mp = (struct lpfc_dmabuf *) mbox->context1;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
fail_free_mbox:
mempool_free(mbox, phba->mbox_mem_pool);
fail:
@@ -657,6 +662,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
uint8_t name[sizeof (struct lpfc_name)];
uint32_t rc;
+ /* Fabric nodes can have the same WWPN so we don't bother searching
+ * by WWPN. Just return the ndlp that was given to us.
+ */
+ if (ndlp->nlp_type & NLP_FABRIC)
+ return ndlp;
+
lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
memset(name, 0, sizeof (struct lpfc_name));
@@ -1122,7 +1133,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
mempool_free(mbox,
phba->mbox_mem_pool);
lpfc_disc_flush_list(phba);
- psli->ring[(psli->ip_ring)].
+ psli->ring[(psli->extra_ring)].
flag &=
~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].
@@ -1851,6 +1862,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
LPFC_MBOXQ_t *mbox = NULL;
+ struct lpfc_dmabuf *mp;
irsp = &rspiocb->iocb;
@@ -1862,6 +1874,11 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
/* Check to see if link went down during discovery */
if ((lpfc_els_chk_latt(phba)) || !ndlp) {
if (mbox) {
+ mp = (struct lpfc_dmabuf *) mbox->context1;
+ if (mp) {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
mempool_free( mbox, phba->mbox_mem_pool);
}
goto out;
@@ -1893,9 +1910,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
/* NOTE: we should have messages for unsuccessful
reglogin */
- mempool_free( mbox, phba->mbox_mem_pool);
} else {
- mempool_free( mbox, phba->mbox_mem_pool);
/* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
@@ -1907,6 +1922,12 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
}
}
+ mp = (struct lpfc_dmabuf *) mbox->context1;
+ if (mp) {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ mempool_free(mbox, phba->mbox_mem_pool);
}
out:
if (ndlp) {
@@ -2644,6 +2665,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
ndlp->nlp_type |= NLP_FABRIC;
ndlp->nlp_prev_state = ndlp->nlp_state;
ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+ lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
lpfc_issue_els_plogi(phba, NameServer_DID, 0);
/* Wait for NameServer login cmpl before we can
continue */
@@ -3039,7 +3061,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
/* FARP-REQ received from DID <did> */
lpfc_printf_log(phba,
KERN_INFO,
- LOG_IP,
+ LOG_ELS,
"%d:0601 FARP-REQ received from DID x%x\n",
phba->brd_no, did);
@@ -3101,7 +3123,7 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba,
/* FARP-RSP received from DID <did> */
lpfc_printf_log(phba,
KERN_INFO,
- LOG_IP,
+ LOG_ELS,
"%d:0600 FARP-RSP received from DID x%x\n",
phba->brd_no, did);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index d586c3d3b0d..c39564e85e9 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -305,7 +305,7 @@ lpfc_do_work(void *p)
{
struct lpfc_hba *phba = p;
int rc;
- DECLARE_WAIT_QUEUE_HEAD(work_waitq);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq);
set_user_nice(current, -20);
phba->work_wait = &work_waitq;
@@ -525,7 +525,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
psli = &phba->sli;
mb = &pmb->mb;
/* Since we don't do discovery right now, turn these off here */
- psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
+ psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
@@ -641,7 +641,7 @@ out:
if (rc == MBX_NOT_FINISHED) {
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_disc_flush_list(phba);
- psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+ psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
phba->hba_state = LPFC_HBA_READY;
@@ -672,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
sizeof (struct serv_parm));
+ if (phba->cfg_soft_wwnn)
+ u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
memcpy((uint8_t *) & phba->fc_nodename,
@@ -696,7 +698,7 @@ out:
== MBX_NOT_FINISHED) {
mempool_free( pmb, phba->mbox_mem_pool);
lpfc_disc_flush_list(phba);
- psli->ring[(psli->ip_ring)].flag &=
+ psli->ring[(psli->extra_ring)].flag &=
~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &=
~LPFC_STOP_IOCB_EVENT;
@@ -715,6 +717,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
{
int i;
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+ struct lpfc_dmabuf *mp;
+ int rc;
+
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -793,16 +798,27 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
if (sparam_mbox) {
lpfc_read_sparam(phba, sparam_mbox);
sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
- lpfc_sli_issue_mbox(phba, sparam_mbox,
+ rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(sparam_mbox, phba->mbox_mem_pool);
+ if (cfglink_mbox)
+ mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+ return;
+ }
}
if (cfglink_mbox) {
phba->hba_state = LPFC_LOCAL_CFG_LINK;
lpfc_config_link(phba, cfglink_mbox);
cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
- lpfc_sli_issue_mbox(phba, cfglink_mbox,
+ rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED)
+ mempool_free(cfglink_mbox, phba->mbox_mem_pool);
}
}
@@ -1067,6 +1083,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID);
lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN);
lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID);
+ lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID);
}
phba->fc_ns_retry = 0;
@@ -1423,7 +1440,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
if (iocb->context1 == (uint8_t *) ndlp)
return 1;
}
- } else if (pring->ringno == psli->ip_ring) {
+ } else if (pring->ringno == psli->extra_ring) {
} else if (pring->ringno == psli->fcp_ring) {
/* Skip match check if waiting to relogin to FCP target */
@@ -1680,112 +1697,38 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
struct lpfc_nodelist *
lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
{
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_nodelist *ndlp;
+ struct list_head *lists[]={&phba->fc_nlpunmap_list,
+ &phba->fc_nlpmap_list,
+ &phba->fc_plogi_list,
+ &phba->fc_adisc_list,
+ &phba->fc_reglogin_list,
+ &phba->fc_prli_list,
+ &phba->fc_npr_list,
+ &phba->fc_unused_list};
+ uint32_t search[]={NLP_SEARCH_UNMAPPED,
+ NLP_SEARCH_MAPPED,
+ NLP_SEARCH_PLOGI,
+ NLP_SEARCH_ADISC,
+ NLP_SEARCH_REGLOGIN,
+ NLP_SEARCH_PRLI,
+ NLP_SEARCH_NPR,
+ NLP_SEARCH_UNUSED};
+ int i;
uint32_t data1;
spin_lock_irq(phba->host->host_lock);
- if (order & NLP_SEARCH_UNMAPPED) {
- list_for_each_entry_safe(ndlp, next_ndlp,
- &phba->fc_nlpunmap_list, nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* FIND node DID unmapped */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0929 FIND node DID unmapped"
- " Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_MAPPED) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* FIND node DID mapped */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0930 FIND node DID mapped "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_PLOGI) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to PLOGI */
- /* FIND node DID plogi */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0908 FIND node DID plogi "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_ADISC) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to ADISC */
- /* FIND node DID adisc */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID adisc "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_REGLOGIN) {
- list_for_each_entry_safe(ndlp, next_ndlp,
- &phba->fc_reglogin_list, nlp_listp) {
+ for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
+ if (!(order & search[i]))
+ continue;
+ list_for_each_entry(ndlp, lists[i], nlp_listp) {
if (lpfc_matchdid(phba, ndlp, did)) {
-
data1 = (((uint32_t) ndlp->nlp_state << 24) |
((uint32_t) ndlp->nlp_xri << 16) |
((uint32_t) ndlp->nlp_type << 8) |
((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to REGLOGIN */
- /* FIND node DID reglogin */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0901 FIND node DID reglogin"
+ "%d:0929 FIND node DID "
" Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1795,86 +1738,12 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
}
}
}
-
- if (order & NLP_SEARCH_PRLI) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to PRLI */
- /* FIND node DID prli */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0902 FIND node DID prli "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_NPR) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to NPR */
- /* FIND node DID npr */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0903 FIND node DID npr "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
- if (order & NLP_SEARCH_UNUSED) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
- nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
-
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- /* LOG change to UNUSED */
- /* FIND node DID unused */
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0905 FIND node DID unused "
- "Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
-
spin_unlock_irq(phba->host->host_lock);
/* FIND node did <did> NOT FOUND */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_NODE,
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
"%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
phba->brd_no, did, order);
-
- /* no match found */
return NULL;
}
@@ -2036,7 +1905,7 @@ lpfc_disc_start(struct lpfc_hba * phba)
if (rc == MBX_NOT_FINISHED) {
mempool_free( mbox, phba->mbox_mem_pool);
lpfc_disc_flush_list(phba);
- psli->ring[(psli->ip_ring)].flag &=
+ psli->ring[(psli->extra_ring)].flag &=
~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &=
~LPFC_STOP_IOCB_EVENT;
@@ -2415,7 +2284,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
if (clrlaerr) {
lpfc_disc_flush_list(phba);
- psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+ psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
phba->hba_state = LPFC_HBA_READY;
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index eedf9880136..f79cb613690 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -42,14 +42,14 @@
#define FCELSSIZE 1024 /* maximum ELS transfer size */
#define LPFC_FCP_RING 0 /* ring 0 for FCP initiator commands */
-#define LPFC_IP_RING 1 /* ring 1 for IP commands */
+#define LPFC_EXTRA_RING 1 /* ring 1 for other protocols */
#define LPFC_ELS_RING 2 /* ring 2 for ELS commands */
#define LPFC_FCP_NEXT_RING 3
#define SLI2_IOCB_CMD_R0_ENTRIES 172 /* SLI-2 FCP command ring entries */
#define SLI2_IOCB_RSP_R0_ENTRIES 134 /* SLI-2 FCP response ring entries */
-#define SLI2_IOCB_CMD_R1_ENTRIES 4 /* SLI-2 IP command ring entries */
-#define SLI2_IOCB_RSP_R1_ENTRIES 4 /* SLI-2 IP response ring entries */
+#define SLI2_IOCB_CMD_R1_ENTRIES 4 /* SLI-2 extra command ring entries */
+#define SLI2_IOCB_RSP_R1_ENTRIES 4 /* SLI-2 extra response ring entries */
#define SLI2_IOCB_CMD_R1XTRA_ENTRIES 36 /* SLI-2 extra FCP cmd ring entries */
#define SLI2_IOCB_RSP_R1XTRA_ENTRIES 52 /* SLI-2 extra FCP rsp ring entries */
#define SLI2_IOCB_CMD_R2_ENTRIES 20 /* SLI-2 ELS command ring entries */
@@ -121,6 +121,20 @@ struct lpfc_sli_ct_request {
uint32_t rsvd[7];
} rft;
+ struct rff {
+ uint32_t PortId;
+ uint8_t reserved[2];
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint8_t feature_res:6;
+ uint8_t feature_init:1;
+ uint8_t feature_tgt:1;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+ uint8_t feature_tgt:1;
+ uint8_t feature_init:1;
+ uint8_t feature_res:6;
+#endif
+ uint8_t type_code; /* type=8 for FCP */
+ } rff;
struct rnn {
uint32_t PortId; /* For RNN_ID requests */
uint8_t wwnn[8];
@@ -136,6 +150,7 @@ struct lpfc_sli_ct_request {
#define SLI_CT_REVISION 1
#define GID_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 260)
#define RFT_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 228)
+#define RFF_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 235)
#define RNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 252)
#define RSNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request))
@@ -225,6 +240,7 @@ struct lpfc_sli_ct_request {
#define SLI_CTNS_RNN_ID 0x0213
#define SLI_CTNS_RCS_ID 0x0214
#define SLI_CTNS_RFT_ID 0x0217
+#define SLI_CTNS_RFF_ID 0x021F
#define SLI_CTNS_RSPN_ID 0x0218
#define SLI_CTNS_RPT_ID 0x021A
#define SLI_CTNS_RIP_NN 0x0235
@@ -1089,12 +1105,6 @@ typedef struct {
#define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11
#define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12
-#define PCI_SUBSYSTEM_ID_LP11000S 0xfc11
-#define PCI_SUBSYSTEM_ID_LP11002S 0xfc12
-#define PCI_SUBSYSTEM_ID_LPE11000S 0xfc21
-#define PCI_SUBSYSTEM_ID_LPE11002S 0xfc22
-#define PCI_SUBSYSTEM_ID_LPE11010S 0xfc2A
-
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
#define SUPERFLY_JEDEC_ID 0x0020
@@ -1284,6 +1294,10 @@ typedef struct { /* FireFly BIU registers */
#define CMD_FCP_IREAD_CX 0x1B
#define CMD_FCP_ICMND_CR 0x1C
#define CMD_FCP_ICMND_CX 0x1D
+#define CMD_FCP_TSEND_CX 0x1F
+#define CMD_FCP_TRECEIVE_CX 0x21
+#define CMD_FCP_TRSP_CX 0x23
+#define CMD_FCP_AUTO_TRSP_CX 0x29
#define CMD_ADAPTER_MSG 0x20
#define CMD_ADAPTER_DUMP 0x22
@@ -1310,6 +1324,9 @@ typedef struct { /* FireFly BIU registers */
#define CMD_FCP_IREAD64_CX 0x9B
#define CMD_FCP_ICMND64_CR 0x9C
#define CMD_FCP_ICMND64_CX 0x9D
+#define CMD_FCP_TSEND64_CX 0x9F
+#define CMD_FCP_TRECEIVE64_CX 0xA1
+#define CMD_FCP_TRSP64_CX 0xA3
#define CMD_GEN_REQUEST64_CR 0xC2
#define CMD_GEN_REQUEST64_CX 0xC3
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4cdf3464267..afca45cdbce 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -268,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
kfree(mp);
pmb->context1 = NULL;
+ if (phba->cfg_soft_wwnn)
+ u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
@@ -349,8 +351,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
phba->hba_state = LPFC_LINK_DOWN;
/* Only process IOCBs on ring 0 till hba_state is READY */
- if (psli->ring[psli->ip_ring].cmdringaddr)
- psli->ring[psli->ip_ring].flag |= LPFC_STOP_IOCB_EVENT;
+ if (psli->ring[psli->extra_ring].cmdringaddr)
+ psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
if (psli->ring[psli->fcp_ring].cmdringaddr)
psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT;
if (psli->ring[psli->next_ring].cmdringaddr)
@@ -389,7 +391,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba,
KERN_ERR,
LOG_INIT,
@@ -406,7 +409,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
readl(phba->HAregaddr); /* flush */
phba->hba_state = LPFC_HBA_ERROR;
- mempool_free(pmb, phba->mbox_mem_pool);
+ if (rc != MBX_BUSY)
+ mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
/* MBOX buffer will be freed in mbox compl */
@@ -515,7 +519,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
struct lpfc_sli_ring *pring;
uint32_t event_data;
- if (phba->work_hs & HS_FFER6) {
+ if (phba->work_hs & HS_FFER6 ||
+ phba->work_hs & HS_FFER5) {
/* Re-establishing Link */
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"%d:1301 Re-establishing Link "
@@ -609,7 +614,7 @@ lpfc_handle_latt(struct lpfc_hba * phba)
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED)
- goto lpfc_handle_latt_free_mp;
+ goto lpfc_handle_latt_free_mbuf;
/* Clear Link Attention in HA REG */
spin_lock_irq(phba->host->host_lock);
@@ -619,6 +624,8 @@ lpfc_handle_latt(struct lpfc_hba * phba)
return;
+lpfc_handle_latt_free_mbuf:
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
lpfc_handle_latt_free_mp:
kfree(mp);
lpfc_handle_latt_free_pmb:
@@ -800,19 +807,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
{
lpfc_vpd_t *vp;
uint16_t dev_id = phba->pcidev->device;
- uint16_t dev_subid = phba->pcidev->subsystem_device;
- uint8_t hdrtype;
int max_speed;
- char * ports;
struct {
char * name;
int max_speed;
- char * ports;
char * bus;
- } m = {"<Unknown>", 0, "", ""};
+ } m = {"<Unknown>", 0, ""};
- pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
- ports = (hdrtype == 0x80) ? "2-port " : "";
if (mdp && mdp[0] != '\0'
&& descp && descp[0] != '\0')
return;
@@ -832,130 +833,93 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
switch (dev_id) {
case PCI_DEVICE_ID_FIREFLY:
- m = (typeof(m)){"LP6000", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP6000", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_SUPERFLY:
if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3)
- m = (typeof(m)){"LP7000", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP7000", max_speed, "PCI"};
else
- m = (typeof(m)){"LP7000E", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP7000E", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_DRAGONFLY:
- m = (typeof(m)){"LP8000", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP8000", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_CENTAUR:
if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID)
- m = (typeof(m)){"LP9002", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP9002", max_speed, "PCI"};
else
- m = (typeof(m)){"LP9000", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP9000", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_RFLY:
- m = (typeof(m)){"LP952", max_speed, "", "PCI"};
+ m = (typeof(m)){"LP952", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_PEGASUS:
- m = (typeof(m)){"LP9802", max_speed, "", "PCI-X"};
+ m = (typeof(m)){"LP9802", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_THOR:
- if (hdrtype == 0x80)
- m = (typeof(m)){"LP10000DC",
- max_speed, ports, "PCI-X"};
- else
- m = (typeof(m)){"LP10000",
- max_speed, ports, "PCI-X"};
+ m = (typeof(m)){"LP10000", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_VIPER:
- m = (typeof(m)){"LPX1000", max_speed, "", "PCI-X"};
+ m = (typeof(m)){"LPX1000", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_PFLY:
- m = (typeof(m)){"LP982", max_speed, "", "PCI-X"};
+ m = (typeof(m)){"LP982", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_TFLY:
- if (hdrtype == 0x80)
- m = (typeof(m)){"LP1050DC", max_speed, ports, "PCI-X"};
- else
- m = (typeof(m)){"LP1050", max_speed, ports, "PCI-X"};
+ m = (typeof(m)){"LP1050", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_HELIOS:
- if (hdrtype == 0x80)
- m = (typeof(m)){"LP11002", max_speed, ports, "PCI-X2"};
- else
- m = (typeof(m)){"LP11000", max_speed, ports, "PCI-X2"};
+ m = (typeof(m)){"LP11000", max_speed, "PCI-X2"};
break;
case PCI_DEVICE_ID_HELIOS_SCSP:
- m = (typeof(m)){"LP11000-SP", max_speed, ports, "PCI-X2"};
+ m = (typeof(m)){"LP11000-SP", max_speed, "PCI-X2"};
break;
case PCI_DEVICE_ID_HELIOS_DCSP:
- m = (typeof(m)){"LP11002-SP", max_speed, ports, "PCI-X2"};
+ m = (typeof(m)){"LP11002-SP", max_speed, "PCI-X2"};
break;
case PCI_DEVICE_ID_NEPTUNE:
- if (hdrtype == 0x80)
- m = (typeof(m)){"LPe1002", max_speed, ports, "PCIe"};
- else
- m = (typeof(m)){"LPe1000", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe1000", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_NEPTUNE_SCSP:
- m = (typeof(m)){"LPe1000-SP", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe1000-SP", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_NEPTUNE_DCSP:
- m = (typeof(m)){"LPe1002-SP", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe1002-SP", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_BMID:
- m = (typeof(m)){"LP1150", max_speed, ports, "PCI-X2"};
+ m = (typeof(m)){"LP1150", max_speed, "PCI-X2"};
break;
case PCI_DEVICE_ID_BSMB:
- m = (typeof(m)){"LP111", max_speed, ports, "PCI-X2"};
+ m = (typeof(m)){"LP111", max_speed, "PCI-X2"};
break;
case PCI_DEVICE_ID_ZEPHYR:
- if (hdrtype == 0x80)
- m = (typeof(m)){"LPe11002", max_speed, ports, "PCIe"};
- else
- m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_ZEPHYR_SCSP:
- m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_ZEPHYR_DCSP:
- m = (typeof(m)){"LPe11002-SP", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe11002-SP", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_ZMID:
- m = (typeof(m)){"LPe1150", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe1150", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_ZSMB:
- m = (typeof(m)){"LPe111", max_speed, ports, "PCIe"};
+ m = (typeof(m)){"LPe111", max_speed, "PCIe"};
break;
case PCI_DEVICE_ID_LP101:
- m = (typeof(m)){"LP101", max_speed, ports, "PCI-X"};
+ m = (typeof(m)){"LP101", max_speed, "PCI-X"};
break;
case PCI_DEVICE_ID_LP10000S:
- m = (typeof(m)){"LP10000-S", max_speed, ports, "PCI"};
+ m = (typeof(m)){"LP10000-S", max_speed, "PCI"};
break;
case PCI_DEVICE_ID_LP11000S:
+ m = (typeof(m)){"LP11000-S", max_speed,
+ "PCI-X2"};
+ break;
case PCI_DEVICE_ID_LPE11000S:
- switch (dev_subid) {
- case PCI_SUBSYSTEM_ID_LP11000S:
- m = (typeof(m)){"LP11000-S", max_speed,
- ports, "PCI-X2"};
- break;
- case PCI_SUBSYSTEM_ID_LP11002S:
- m = (typeof(m)){"LP11002-S", max_speed,
- ports, "PCI-X2"};
- break;
- case PCI_SUBSYSTEM_ID_LPE11000S:
- m = (typeof(m)){"LPe11000-S", max_speed,
- ports, "PCIe"};
- break;
- case PCI_SUBSYSTEM_ID_LPE11002S:
- m = (typeof(m)){"LPe11002-S", max_speed,
- ports, "PCIe"};
- break;
- case PCI_SUBSYSTEM_ID_LPE11010S:
- m = (typeof(m)){"LPe11010-S", max_speed,
- "10-port ", "PCIe"};
- break;
- default:
- m = (typeof(m)){ NULL };
- break;
- }
+ m = (typeof(m)){"LPe11000-S", max_speed,
+ "PCIe"};
break;
default:
m = (typeof(m)){ NULL };
@@ -966,8 +930,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
snprintf(mdp, 79,"%s", m.name);
if (descp && descp[0] == '\0')
snprintf(descp, 255,
- "Emulex %s %dGb %s%s Fibre Channel Adapter",
- m.name, m.max_speed, m.ports, m.bus);
+ "Emulex %s %dGb %s Fibre Channel Adapter",
+ m.name, m.max_speed, m.bus);
}
/**************************************************/
@@ -1649,6 +1613,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (error)
goto out_remove_host;
+ if (phba->cfg_use_msi) {
+ error = pci_enable_msi(phba->pcidev);
+ if (error)
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0452 "
+ "Enable MSI failed, continuing with "
+ "IRQ\n", phba->brd_no);
+ }
+
error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
LPFC_DRIVER_NAME, phba);
if (error) {
@@ -1728,6 +1700,7 @@ out_free_irq:
lpfc_stop_timer(phba);
phba->work_hba_events = 0;
free_irq(phba->pcidev->irq, phba);
+ pci_disable_msi(phba->pcidev);
out_free_sysfs_attr:
lpfc_free_sysfs_attr(phba);
out_remove_host:
@@ -1794,6 +1767,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
/* Release the irq reservation */
free_irq(phba->pcidev->irq, phba);
+ pci_disable_msi(phba->pcidev);
lpfc_cleanup(phba, 0);
lpfc_stop_timer(phba);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 62c8ca862e9..438cbcd9eb1 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -28,7 +28,7 @@
#define LOG_NODE 0x80 /* Node table events */
#define LOG_MISC 0x400 /* Miscellaneous events */
#define LOG_SLI 0x800 /* SLI events */
-#define LOG_CHK_COND 0x1000 /* FCP Check condition flag */
+#define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */
#define LOG_LIBDFC 0x2000 /* Libdfc events */
#define LOG_ALL_MSG 0xffff /* LOG all messages */
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index d5f415007db..0c7e731dc45 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -739,7 +739,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
- struct lpfc_dmabuf *pcmd, *prsp;
+ struct lpfc_dmabuf *pcmd, *prsp, *mp;
uint32_t *lp;
IOCB_t *irsp;
struct serv_parm *sp;
@@ -829,6 +829,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
NLP_REGLOGIN_LIST);
return ndlp->nlp_state;
}
+ mp = (struct lpfc_dmabuf *)mbox->context1;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
mempool_free(mbox, phba->mbox_mem_pool);
} else {
mempool_free(mbox, phba->mbox_mem_pool);
@@ -1620,8 +1623,8 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
* or discovery in progress for this node. Starting discovery
* here will affect the counting of discovery threads.
*/
- if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) &&
- (ndlp->nlp_flag & NLP_NPR_2B_DISC)){
+ if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 97ae98dc95d..c3e68e0d8f7 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -297,8 +297,10 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
uint32_t resp_info = fcprsp->rspStatus2;
uint32_t scsi_status = fcprsp->rspStatus3;
+ uint32_t *lp;
uint32_t host_status = DID_OK;
uint32_t rsplen = 0;
+ uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
/*
* If this is a task management command, there is no
@@ -310,10 +312,25 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
goto out;
}
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0730 FCP command failed: RSP "
- "Data: x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, resp_info, scsi_status,
+ if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
+ uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
+ if (snslen > SCSI_SENSE_BUFFERSIZE)
+ snslen = SCSI_SENSE_BUFFERSIZE;
+
+ if (resp_info & RSP_LEN_VALID)
+ rsplen = be32_to_cpu(fcprsp->rspRspLen);
+ memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen);
+ }
+ lp = (uint32_t *)cmnd->sense_buffer;
+
+ if (!scsi_status && (resp_info & RESID_UNDER))
+ logit = LOG_FCP;
+
+ lpfc_printf_log(phba, KERN_WARNING, logit,
+ "%d:0730 FCP command x%x failed: x%x SNS x%x x%x "
+ "Data: x%x x%x x%x x%x x%x\n",
+ phba->brd_no, cmnd->cmnd[0], scsi_status,
+ be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
be32_to_cpu(fcprsp->rspResId),
be32_to_cpu(fcprsp->rspSnsLen),
be32_to_cpu(fcprsp->rspRspLen),
@@ -328,14 +345,6 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
}
}
- if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
- uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
- if (snslen > SCSI_SENSE_BUFFERSIZE)
- snslen = SCSI_SENSE_BUFFERSIZE;
-
- memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen);
- }
-
cmnd->resid = 0;
if (resp_info & RESID_UNDER) {
cmnd->resid = be32_to_cpu(fcprsp->rspResId);
@@ -378,7 +387,7 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
*/
} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
"%d:0734 FCP Read Check Error Data: "
"x%x x%x x%x x%x\n", phba->brd_no,
be32_to_cpu(fcpcmd->fcpDl),
@@ -670,6 +679,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
struct lpfc_iocbq *iocbqrsp;
int ret;
+ if (!rdata->pnode)
+ return FAILED;
+
lpfc_cmd->rdata = rdata;
ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
FCP_TARGET_RESET);
@@ -976,20 +988,34 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
+ loopcnt = 0;
/*
* If target is not in a MAPPED state, delay the reset until
* target is rediscovered or devloss timeout expires.
*/
while ( 1 ) {
if (!pnode)
- break;
+ return FAILED;
if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
spin_lock_irq(phba->host->host_lock);
+ loopcnt++;
+ rdata = cmnd->device->hostdata;
+ if (!rdata ||
+ (loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "%d:0721 LUN Reset rport failure:"
+ " cnt x%x rdata x%p\n",
+ phba->brd_no, loopcnt, rdata);
+ goto out;
+ }
+ pnode = rdata->pnode;
+ if (!pnode)
+ return FAILED;
}
- if ((pnode) && (pnode->nlp_state == NLP_STE_MAPPED_NODE))
+ if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 70f4d5a1348..a4128e19338 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -117,6 +117,10 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case CMD_FCP_IREAD_CX:
case CMD_FCP_ICMND_CR:
case CMD_FCP_ICMND_CX:
+ case CMD_FCP_TSEND_CX:
+ case CMD_FCP_TRSP_CX:
+ case CMD_FCP_TRECEIVE_CX:
+ case CMD_FCP_AUTO_TRSP_CX:
case CMD_ADAPTER_MSG:
case CMD_ADAPTER_DUMP:
case CMD_XMIT_SEQUENCE64_CR:
@@ -131,6 +135,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case CMD_FCP_IREAD64_CX:
case CMD_FCP_ICMND64_CR:
case CMD_FCP_ICMND64_CX:
+ case CMD_FCP_TSEND64_CX:
+ case CMD_FCP_TRSP64_CX:
+ case CMD_FCP_TRECEIVE64_CX:
case CMD_GEN_REQUEST64_CR:
case CMD_GEN_REQUEST64_CX:
case CMD_XMIT_ELS_RSP64_CX:
@@ -1098,6 +1105,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
lpfc_sli_pcimem_bcopy((uint32_t *) entry,
(uint32_t *) &rspiocbq.iocb,
sizeof (IOCB_t));
+ INIT_LIST_HEAD(&(rspiocbq.list));
irsp = &rspiocbq.iocb;
type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
@@ -1149,6 +1157,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
}
}
break;
+ case LPFC_UNSOL_IOCB:
+ spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
+ spin_lock_irqsave(phba->host->host_lock, iflag);
+ break;
default:
if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
char adaptermsg[LPFC_MAX_ADPTMSG];
@@ -2472,13 +2485,17 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
psli = &phba->sli;
/* Adjust cmd/rsp ring iocb entries more evenly */
+
+ /* Take some away from the FCP ring */
pring = &psli->ring[psli->fcp_ring];
pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
- pring = &psli->ring[1];
+ /* and give them to the extra ring */
+ pring = &psli->ring[psli->extra_ring];
+
pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
@@ -2488,8 +2505,8 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
pring->iotag_max = 4096;
pring->num_mask = 1;
pring->prt[0].profile = 0; /* Mask 0 */
- pring->prt[0].rctl = FC_UNSOL_DATA;
- pring->prt[0].type = 5;
+ pring->prt[0].rctl = phba->cfg_multi_ring_rctl;
+ pring->prt[0].type = phba->cfg_multi_ring_type;
pring->prt[0].lpfc_sli_rcv_unsol_event = NULL;
return 0;
}
@@ -2505,7 +2522,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
psli->sli_flag = 0;
psli->fcp_ring = LPFC_FCP_RING;
psli->next_ring = LPFC_FCP_NEXT_RING;
- psli->ip_ring = LPFC_IP_RING;
+ psli->extra_ring = LPFC_EXTRA_RING;
psli->iocbq_lookup = NULL;
psli->iocbq_lookup_len = 0;
@@ -2528,7 +2545,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
pring->fast_iotag = pring->iotag_max;
pring->num_mask = 0;
break;
- case LPFC_IP_RING: /* ring 1 - IP */
+ case LPFC_EXTRA_RING: /* ring 1 - EXTRA */
/* numCiocb and numRiocb are used in config_port */
pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
@@ -2983,7 +3000,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
struct lpfc_iocbq * prspiocbq,
uint32_t timeout)
{
- DECLARE_WAIT_QUEUE_HEAD(done_q);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
@@ -3061,7 +3078,7 @@ int
lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
uint32_t timeout)
{
- DECLARE_WAIT_QUEUE_HEAD(done_q);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
DECLARE_WAITQUEUE(wq_entry, current);
uint32_t timeleft = 0;
int retval;
@@ -3119,7 +3136,7 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
}
irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
+lpfc_intr_handler(int irq, void *dev_id)
{
struct lpfc_hba *phba;
uint32_t ha_copy;
@@ -3238,6 +3255,21 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_FCP_RING],
status);
+
+ if (phba->cfg_multi_ring_support == 2) {
+ /*
+ * Process all events on extra ring. Take the optimized path
+ * for extra ring IO. Any other IO is slow path and is handled
+ * by the worker thread.
+ */
+ status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
+ status >>= (4*LPFC_EXTRA_RING);
+ if (status & HA_RXATT) {
+ lpfc_sli_handle_fast_ring_event(phba,
+ &phba->sli.ring[LPFC_EXTRA_RING],
+ status);
+ }
+ }
return IRQ_HANDLED;
} /* lpfc_intr_handler */
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index e26de680935..a43549959dc 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -198,7 +198,7 @@ struct lpfc_sli {
int fcp_ring; /* ring used for FCP initiator commands */
int next_ring;
- int ip_ring; /* ring used for IP network drv cmds */
+ int extra_ring; /* extra ring used for other protocols */
struct lpfc_sli_stat slistat; /* SLI statistical info */
struct list_head mboxq;
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index ac417908b40..a61ef3d1e7f 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.1.10"
+#define LPFC_DRIVER_VERSION "8.1.11"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 6422de72bf4..753d88306cd 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -60,8 +60,8 @@ struct fsc_state {
static void mac53c94_init(struct fsc_state *);
static void mac53c94_start(struct fsc_state *);
-static void mac53c94_interrupt(int, void *, struct pt_regs *);
-static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
+static void mac53c94_interrupt(int, void *);
+static irqreturn_t do_mac53c94_interrupt(int, void *);
static void cmd_done(struct fsc_state *, int result);
static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
@@ -177,18 +177,18 @@ static void mac53c94_start(struct fsc_state *state)
set_dma_cmds(state, cmd);
}
-static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
spin_lock_irqsave(dev->host_lock, flags);
- mac53c94_interrupt(irq, dev_id, ptregs);
+ mac53c94_interrupt(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void mac53c94_interrupt(int irq, void *dev_id)
{
struct fsc_state *state = (struct fsc_state *) dev_id;
struct mac53c94_regs __iomem *regs = state->regs;
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 118206d68c6..3586fac9be9 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -44,7 +44,7 @@
/* #define DEBUG_MAC_ESP */
extern void esp_handle(struct NCR_ESP *esp);
-extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+extern void mac_esp_intr(int irq, void *dev_id);
static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
@@ -88,7 +88,7 @@ static int setup_hostid = -1;
* set up properly!
*/
-void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+void mac_esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
int irq_p = 0;
@@ -122,24 +122,24 @@ void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
* acknowledge on the various machines
*/
-void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs)
+void scsi_esp_polled(int irq, void *dev_id)
{
if (esp_initialized == 0)
return;
- mac_esp_intr(irq, dev_id, pregs);
+ mac_esp_intr(irq, dev_id);
}
-void fake_intr(int irq, void *dev_id, struct pt_regs *pregs)
+void fake_intr(int irq, void *dev_id)
{
#ifdef DEBUG_MAC_ESP
printk("mac_esp: got irq\n");
#endif
- mac_esp_intr(irq, dev_id, pregs);
+ mac_esp_intr(irq, dev_id);
}
-irqreturn_t fake_drq(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t fake_drq(int irq, void *dev_id)
{
printk("mac_esp: got drq\n");
return IRQ_HANDLED;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index b87bef69ba0..77d9d3804cc 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -73,10 +73,10 @@ static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;
module_param(max_mbox_busy_wait, ushort, 0);
MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");
-#define RDINDOOR(adapter) readl((adapter)->base + 0x20)
-#define RDOUTDOOR(adapter) readl((adapter)->base + 0x2C)
-#define WRINDOOR(adapter,value) writel(value, (adapter)->base + 0x20)
-#define WROUTDOOR(adapter,value) writel(value, (adapter)->base + 0x2C)
+#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20)
+#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C)
+#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20)
+#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C)
/*
* Global variables
@@ -1256,14 +1256,13 @@ bug_blocked_mailbox:
* megaraid_isr_iomapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for io-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_iomapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
@@ -1333,14 +1332,13 @@ megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
* megaraid_isr_memmapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for memory-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_memmapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
@@ -1388,7 +1386,8 @@ megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
handled = 1;
- while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
+ while( RDINDOOR(adapter) & 0x02 )
+ cpu_relax();
mega_cmd_done(adapter, completed, nstatus, status);
@@ -4670,6 +4669,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->host_no, mega_baseport, irq);
adapter->base = mega_baseport;
+ if (flag & BOARD_MEMMAP)
+ adapter->mmio_base = (void __iomem *) mega_baseport;
INIT_LIST_HEAD(&adapter->free_list);
INIT_LIST_HEAD(&adapter->pending_list);
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4b75fe619d9..c6e74643abe 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -801,7 +801,8 @@ typedef struct {
clustering is available */
u32 flag;
- unsigned long base;
+ unsigned long base;
+ void __iomem *mmio_base;
/* mbox64 with mbox not aligned on 16-byte boundry */
mbox64_t *una_mbox64;
@@ -991,8 +992,8 @@ static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
static void __mega_runpendq(adapter_t *);
static int issue_scb_block(adapter_t *, u_char *);
-static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *);
-static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *);
+static irqreturn_t megaraid_isr_memmapped(int, void *);
+static irqreturn_t megaraid_isr_iomapped(int, void *);
static void mega_free_scb(adapter_t *, scb_t *);
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 8cd0bd1d0f7..b50e27e6602 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -175,7 +175,7 @@ typedef struct {
uint8_t max_lun;
uint32_t unique_id;
- uint8_t irq;
+ int irq;
uint8_t ito;
caddr_t ibuf;
dma_addr_t ibuf_dma_h;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 266b3910846..7bac86dda88 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -120,7 +120,7 @@ static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
struct scsi_cmnd *);
-static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
+static irqreturn_t megaraid_isr(int, void *);
static void megaraid_mbox_dpc(unsigned long);
@@ -884,7 +884,7 @@ megaraid_init_mbox(adapter_t *adapter)
if (((magic64 == HBA_SIGNATURE_64_BIT) &&
((adapter->pdev->subsystem_device !=
- PCI_SUBSYS_ID_MEGARAID_SATA_150_6) ||
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_6) &&
(adapter->pdev->subsystem_device !=
PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
(adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
@@ -2231,7 +2231,7 @@ megaraid_ack_sequence(adapter_t *adapter)
* Interrupt service routine for memory-mapped mailbox controllers.
*/
static irqreturn_t
-megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr(int irq, void *devp)
{
adapter_t *adapter = devp;
int handled;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 4cab5b534b2..046223b4ae5 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.01
+ * Version : v00.00.03.05
*
* Authors:
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -71,6 +71,8 @@ static struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
+static u32 megasas_dbg_lvl;
+
/**
* megasas_get_cmd - Get a command from the free pool
* @instance: Adapter soft state
@@ -135,6 +137,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_xscale -Disables interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0x1f;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_xscale - returns the current FW status value
* @regs: MFI register set
*/
@@ -185,6 +200,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
.fire_cmd = megasas_fire_cmd_xscale,
.enable_intr = megasas_enable_intr_xscale,
+ .disable_intr = megasas_disable_intr_xscale,
.clear_intr = megasas_clear_intr_xscale,
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
};
@@ -215,6 +231,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_ppc - Disable interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_ppc - returns the current FW status value
* @regs: MFI register set
*/
@@ -265,6 +294,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
.fire_cmd = megasas_fire_cmd_ppc,
.enable_intr = megasas_enable_intr_ppc,
+ .disable_intr = megasas_disable_intr_ppc,
.clear_intr = megasas_clear_intr_ppc,
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
};
@@ -275,25 +305,6 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
*/
/**
- * megasas_disable_intr - Disables interrupts
- * @regs: MFI register set
- */
-static inline void
-megasas_disable_intr(struct megasas_instance *instance)
-{
- u32 mask = 0x1f;
- struct megasas_register_set __iomem *regs = instance->reg_set;
-
- if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
- mask = 0xffffffff;
-
- writel(mask, &regs->outbound_intr_mask);
-
- /* Dummy readl to force pci flush */
- readl(&regs->outbound_intr_mask);
-}
-
-/**
* megasas_issue_polled - Issues a polling command
* @instance: Adapter soft state
* @cmd: Command packet to be issued
@@ -336,6 +347,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: Command to be issued
*
* This function waits on an event for the command to be returned from ISR.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
* Used to issue ioctl commands.
*/
static int
@@ -346,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
- wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+ wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
return 0;
}
@@ -358,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
*
* MFI firmware can abort previously issued AEN comamnd (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
- * cmd and blocks till it is completed.
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/
static int
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
@@ -392,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
/*
* Wait for this cmd to complete
*/
- wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+ wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
megasas_return_cmd(instance, cmd);
return 0;
@@ -495,6 +510,46 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
return sge_count;
}
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @sge_count : number of sg elements
+ *
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
+
+static u32 megasas_get_frame_count(u8 sge_count)
+{
+ int num_cnt;
+ int sge_bytes;
+ u32 sge_sz;
+ u32 frame_count=0;
+
+ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+ sizeof(struct megasas_sge32);
+
+ /*
+ * Main frame can contain 2 SGEs for 64-bit SGLs and
+ * 3 SGEs for 32-bit SGLs
+ */
+ if (IS_DMA64)
+ num_cnt = sge_count - 2;
+ else
+ num_cnt = sge_count - 3;
+
+ if(num_cnt>0){
+ sge_bytes = sge_sz * num_cnt;
+
+ frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+ ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
+ }
+ /* Main frame */
+ frame_count +=1;
+
+ if (frame_count > 7)
+ frame_count = 8;
+ return frame_count;
+}
+
/**
* megasas_build_dcdb - Prepares a direct cdb (DCDB) command
* @instance: Adapter soft state
@@ -508,8 +563,6 @@ static int
megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 is_logical;
u32 device_id;
u16 flags = 0;
@@ -544,9 +597,6 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
pthru->flags |= MFI_FRAME_SGL64;
pthru->sge_count = megasas_make_sgl64(instance, scp,
@@ -562,17 +612,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->sense_buf_phys_addr_hi = 0;
pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * pthru->sge_count;
-
/*
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
return cmd->frame_count;
}
@@ -589,8 +633,6 @@ static int
megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 device_id;
u8 sc = scp->cmnd[0];
u16 flags = 0;
@@ -605,7 +647,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
flags = MFI_FRAME_DIR_READ;
/*
- * Preare the Logical IO frame: 2nd bit is zero for all read cmds
+ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
*/
ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
ldio->cmd_status = 0x0;
@@ -674,9 +716,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
ldio->flags |= MFI_FRAME_SGL64;
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
@@ -690,13 +729,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
ldio->sense_buf_phys_addr_hi = 0;
ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * ldio->sge_count;
-
- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ /*
+ * Compute the total number of frames this command consumes. FW uses
+ * this number to pull sufficient number of frames from host memory.
+ */
+ cmd->frame_count = megasas_get_frame_count(ldio->sge_count);
return cmd->frame_count;
}
@@ -727,6 +764,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
}
}
+ /**
+ * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
+ * in FW
+ * @instance: Adapter soft state
+ */
+static inline void
+megasas_dump_pending_frames(struct megasas_instance *instance)
+{
+ struct megasas_cmd *cmd;
+ int i,n;
+ union megasas_sgl *mfi_sgl;
+ struct megasas_io_frame *ldio;
+ struct megasas_pthru_frame *pthru;
+ u32 sgcount;
+ u32 max_cmd = instance->max_fw_cmds;
+
+ printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+ printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+ if (IS_DMA64)
+ printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+ else
+ printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+
+ printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
+ for (i = 0; i < max_cmd; i++) {
+ cmd = instance->cmd_list[i];
+ if(!cmd->scmd)
+ continue;
+ printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+ if (megasas_is_ldio(cmd->scmd)){
+ ldio = (struct megasas_io_frame *)cmd->frame;
+ mfi_sgl = &ldio->sgl;
+ sgcount = ldio->sge_count;
+ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+ }
+ else {
+ pthru = (struct megasas_pthru_frame *) cmd->frame;
+ mfi_sgl = &pthru->sgl;
+ sgcount = pthru->sge_count;
+ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+ }
+ if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+ for (n = 0; n < sgcount; n++){
+ if (IS_DMA64)
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+ else
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+ }
+ }
+ printk(KERN_ERR "\n");
+ } /*for max_cmd*/
+ printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = instance->cmd_list[i];
+
+ if(cmd->sync_cmd == 1){
+ printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+ }
+ }
+ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+}
+
/**
* megasas_queue_command - Queue entry point
* @scmd: SCSI command to be queued
@@ -832,6 +932,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
if (atomic_read(&instance->fw_outstanding)) {
+ /*
+ * Send signal to FW to stop processing any pending cmds.
+ * The controller will be taken offline by the OS now.
+ */
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->inbound_doorbell);
+ megasas_dump_pending_frames(instance);
instance->hw_crit_error = 1;
return FAILED;
}
@@ -1168,11 +1275,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
static int
megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
{
- u32 producer;
- u32 consumer;
- u32 context;
- struct megasas_cmd *cmd;
-
/*
* Check if it is our interrupt
* Clear the interrupt
@@ -1180,23 +1282,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
if(instance->instancet->clear_intr(instance->reg_set))
return IRQ_NONE;
- producer = *instance->producer;
- consumer = *instance->consumer;
-
- while (consumer != producer) {
- context = instance->reply_queue[consumer];
-
- cmd = instance->cmd_list[context];
-
- megasas_complete_cmd(instance, cmd, alt_status);
-
- consumer++;
- if (consumer == (instance->max_fw_cmds + 1)) {
- consumer = 0;
- }
- }
-
- *instance->consumer = producer;
+ /*
+ * Schedule the tasklet for cmd completion
+ */
+ tasklet_schedule(&instance->isr_tasklet);
return IRQ_HANDLED;
}
@@ -1204,7 +1293,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
/**
* megasas_isr - isr entry point
*/
-static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t megasas_isr(int irq, void *devp)
{
return megasas_deplete_reply_queue((struct megasas_instance *)devp,
DID_OK);
@@ -1229,10 +1318,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state != MFI_STATE_READY)
+ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ " state\n");
+
while (fw_state != MFI_STATE_READY) {
- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
- " state\n");
switch (fw_state) {
case MFI_STATE_FAULT:
@@ -1244,19 +1335,27 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Set the CLR bit in inbound doorbell
*/
- writel(MFI_INIT_CLEAR_HANDSHAKE,
+ writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
max_wait = 2;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
+ case MFI_STATE_BOOT_MESSAGE_PENDING:
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+
+ max_wait = 10;
+ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+ break;
+
case MFI_STATE_OPERATIONAL:
/*
- * Bring it to READY state; assuming max wait 2 secs
+ * Bring it to READY state; assuming max wait 10 secs
*/
- megasas_disable_intr(instance);
- writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
+ instance->instancet->disable_intr(instance->reg_set);
+ writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
max_wait = 10;
cur_state = MFI_STATE_OPERATIONAL;
@@ -1323,6 +1422,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
return -ENODEV;
}
};
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
return 0;
}
@@ -1352,7 +1452,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
cmd->frame_phys_addr);
if (cmd->sense)
- pci_pool_free(instance->sense_dma_pool, cmd->frame,
+ pci_pool_free(instance->sense_dma_pool, cmd->sense,
cmd->sense_phys_addr);
}
@@ -1628,6 +1728,39 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
}
/**
+ * megasas_complete_cmd_dpc - Returns FW's controller structure
+ * @instance_addr: Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+ u32 producer;
+ u32 consumer;
+ u32 context;
+ struct megasas_cmd *cmd;
+ struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+
+ producer = *instance->producer;
+ consumer = *instance->consumer;
+
+ while (consumer != producer) {
+ context = instance->reply_queue[consumer];
+
+ cmd = instance->cmd_list[context];
+
+ megasas_complete_cmd(instance, cmd, DID_OK);
+
+ consumer++;
+ if (consumer == (instance->max_fw_cmds + 1)) {
+ consumer = 0;
+ }
+ }
+
+ *instance->consumer = producer;
+}
+
+/**
* megasas_init_mfi - Initializes the FW
* @instance: Adapter soft state
*
@@ -1690,6 +1823,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* Get various operational parameters from status register
*/
instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
0x10;
/*
@@ -1754,7 +1893,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
/*
* disable the intr before firing the init frame to FW
*/
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
/*
* Issue the init frame in polled mode
@@ -1791,6 +1930,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
kfree(ctrl_info);
+ /*
+ * Setup tasklet for cmd completion
+ */
+
+ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+ (unsigned long)instance);
return 0;
fail_fw_init:
@@ -2182,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+ megasas_dbg_lvl = 0;
+
/*
* Initialize MFI Firmware
*/
@@ -2234,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
megasas_mgmt_info.max_index--;
pci_set_drvdata(pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
megasas_release_mfi(instance);
@@ -2348,6 +2495,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance);
+ tasklet_kill(&instance->isr_tasklet);
/*
* Take the instance off the instance array. Note that we will not
@@ -2364,7 +2512,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_set_drvdata(instance->pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
@@ -2716,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
- clear_user(ioc, sizeof(*ioc));
+ if (clear_user(ioc, sizeof(*ioc)))
+ return -EFAULT;
if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
@@ -2808,6 +2957,26 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
NULL);
+static ssize_t
+megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf,"%u",megasas_dbg_lvl);
+}
+
+static ssize_t
+megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+{
+ int retval = count;
+ if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+ printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
+ megasas_sysfs_set_dbg_lvl);
+
/**
* megasas_init - Driver load entry point
*/
@@ -2842,14 +3011,33 @@ static int __init megasas_init(void)
if (rval) {
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
- }
-
- driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
- driver_create_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
+ goto err_pcidrv;
+ }
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_version);
+ if (rval)
+ goto err_dcf_attr_ver;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+ if (rval)
+ goto err_dcf_rel_date;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ if (rval)
+ goto err_dcf_dbg_lvl;
return rval;
+err_dcf_dbg_lvl:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+err_dcf_rel_date:
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+err_dcf_attr_ver:
+ pci_unregister_driver(&megasas_pci_driver);
+err_pcidrv:
+ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+ return rval;
}
/**
@@ -2857,9 +3045,11 @@ static int __init megasas_init(void)
*/
static void __exit megasas_exit(void)
{
- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
pci_unregister_driver(&megasas_pci_driver);
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 3531a14222a..55eddcf8eb1 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/**
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.01"
-#define MEGASAS_RELDATE "May 14, 2006"
-#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006"
+#define MEGASAS_VERSION "00.00.03.05"
+#define MEGASAS_RELDATE "Oct 02, 2006"
+#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006"
/*
* Device IDs
@@ -50,6 +50,7 @@
#define MFI_STATE_WAIT_HANDSHAKE 0x60000000
#define MFI_STATE_FW_INIT_2 0x70000000
#define MFI_STATE_DEVICE_SCAN 0x80000000
+#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
#define MFI_STATE_FLUSH_CACHE 0xA0000000
#define MFI_STATE_READY 0xB0000000
#define MFI_STATE_OPERATIONAL 0xC0000000
@@ -64,12 +65,18 @@
* READY : Move from OPERATIONAL to READY state; discard queue info
* MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??)
* CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver
+ * HOTPLUG : Resume from Hotplug
+ * MFI_STOP_ADP : Send signal to FW to stop processing
*/
-#define MFI_INIT_ABORT 0x00000000
+#define MFI_INIT_ABORT 0x00000001
#define MFI_INIT_READY 0x00000002
#define MFI_INIT_MFIMODE 0x00000004
#define MFI_INIT_CLEAR_HANDSHAKE 0x00000008
-#define MFI_RESET_FLAGS MFI_INIT_READY|MFI_INIT_MFIMODE
+#define MFI_INIT_HOTPLUG 0x00000010
+#define MFI_STOP_ADP 0x00000020
+#define MFI_RESET_FLAGS MFI_INIT_READY| \
+ MFI_INIT_MFIMODE| \
+ MFI_INIT_ABORT
/**
* MFI frame flags
@@ -530,6 +537,8 @@ struct megasas_ctrl_info {
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_DBG_LVL 1
+
/*
* When SCSI mid-layer calls driver's reset routine, driver waits for
* MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
@@ -538,6 +547,7 @@ struct megasas_ctrl_info {
* every MEGASAS_RESET_NOTICE_INTERVAL seconds
*/
#define MEGASAS_RESET_WAIT_TIME 180
+#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180
#define MEGASAS_RESET_NOTICE_INTERVAL 5
#define MEGASAS_IOCTL_CMD 0
@@ -1042,6 +1052,7 @@ struct megasas_evt_detail {
void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
void (*enable_intr)(struct megasas_register_set __iomem *) ;
+ void (*disable_intr)(struct megasas_register_set __iomem *);
int (*clear_intr)(struct megasas_register_set __iomem *);
@@ -1092,6 +1103,7 @@ struct megasas_instance {
u32 hw_crit_error;
struct megasas_instance_template *instancet;
+ struct tasklet_struct isr_tasklet;
};
#define MEGASAS_IS_LOGICAL(scp) \
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 683fc7ae4b8..1fd3c7590d3 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -185,7 +185,7 @@ struct mesh_state {
* Driver is too messy, we need a few prototypes...
*/
static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
+static void mesh_interrupt(int irq, void *dev_id);
static void cmd_complete(struct mesh_state *ms);
static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
static void halt_dma(struct mesh_state *ms);
@@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms, NULL);
+ mesh_interrupt(0, (void *)ms);
if (ms->phase != arbitrating)
return;
}
@@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms, NULL);
+ mesh_interrupt(0, (void *)ms);
if (ms->phase != arbitrating)
return;
dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1015,13 +1015,13 @@ static void handle_reset(struct mesh_state *ms)
out_8(&mr->sequence, SEQ_ENBRESEL);
}
-static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
spin_lock_irqsave(dev->host_lock, flags);
- mesh_interrupt(irq, dev_id, ptregs);
+ mesh_interrupt(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
@@ -1661,7 +1661,7 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* handler (do_mesh_interrupt) or by other functions in
* exceptional circumstances
*/
-static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void mesh_interrupt(int irq, void *dev_id)
{
struct mesh_state *ms = (struct mesh_state *) dev_id;
volatile struct mesh_regs __iomem *mr = ms->mesh;
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 9b991b746d1..1ddd7a11a95 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -20,7 +20,7 @@
static struct Scsi_Host *mvme147_host = NULL;
-static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t mvme147_intr (int irq, void *dummy)
{
if (irq == MVME147_IRQ_SCSI_PORT)
wd33c93_intr (mvme147_host);
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
index c7a12533fb2..73e33b37a3f 100644
--- a/drivers/scsi/mvme16x.h
+++ b/drivers/scsi/mvme16x.h
@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index b28712df0b7..bbf521cbc55 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -185,7 +185,7 @@ static inline struct list_head *ncr_list_pop(struct list_head *head)
** power of 2 cache line size.
** Enhanced in linux-2.3.44 to provide a memory pool
** per pcidev to support dynamic dma mapping. (I would
-** have preferred a real bus astraction, btw).
+** have preferred a real bus abstraction, btw).
**
**==========================================================
*/
@@ -589,10 +589,12 @@ static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
static struct ncr_driver_setup
driver_setup = SCSI_NCR_DRIVER_SETUP;
+#ifndef MODULE
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
static struct ncr_driver_setup
driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP;
#endif
+#endif /* !MODULE */
#define initverbose (driver_setup.verbose)
#define bootverbose (np->verbose)
@@ -641,6 +643,13 @@ static struct ncr_driver_setup
#define OPT_IARB 26
#endif
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+#ifndef MODULE
static char setup_token[] __initdata =
"tags:" "mpar:"
"spar:" "disc:"
@@ -660,12 +669,6 @@ static char setup_token[] __initdata =
#endif
; /* DONNOT REMOVE THIS ';' */
-#ifdef MODULE
-#define ARG_SEP ' '
-#else
-#define ARG_SEP ','
-#endif
-
static int __init get_setup_token(char *p)
{
char *cur = setup_token;
@@ -682,7 +685,6 @@ static int __init get_setup_token(char *p)
return 0;
}
-
static int __init sym53c8xx__setup(char *str)
{
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
@@ -804,6 +806,7 @@ static int __init sym53c8xx__setup(char *str)
#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
return 1;
}
+#endif /* !MODULE */
/*===================================================================
**
@@ -1438,7 +1441,7 @@ struct head {
** The first four bytes (scr_st[4]) are used inside the script by
** "COPY" commands.
** Because source and destination must have the same alignment
-** in a DWORD, the fields HAVE to be at the choosen offsets.
+** in a DWORD, the fields HAVE to be at the chosen offsets.
** xerr_st 0 (0x34) scratcha
** sync_st 1 (0x05) sxfer
** wide_st 3 (0x03) scntl3
@@ -1498,7 +1501,7 @@ struct head {
** the DSA (data structure address) register points
** to this substructure of the ccb.
** This substructure contains the header with
-** the script-processor-changable data and
+** the script-processor-changeable data and
** data blocks for the indirect move commands.
**
**----------------------------------------------------------
@@ -5107,7 +5110,7 @@ void ncr_complete (struct ncb *np, struct ccb *cp)
/*
** This CCB has been skipped by the NCR.
-** Queue it in the correponding unit queue.
+** Queue it in the corresponding unit queue.
*/
static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp)
{
@@ -5896,8 +5899,8 @@ static void ncr_log_hard_error(struct ncb *np, u16 sist, u_char dstat)
**
** In normal cases, interrupt conditions occur one at a
** time. The ncr is able to stack in some extra registers
-** other interrupts that will occurs after the first one.
-** But severall interrupts may occur at the same time.
+** other interrupts that will occur after the first one.
+** But, several interrupts may occur at the same time.
**
** We probably should only try to deal with the normal
** case, but it seems that multiple interrupts occur in
@@ -6796,7 +6799,7 @@ void ncr_int_sir (struct ncb *np)
** The host status field is set to HS_NEGOTIATE to mark this
** situation.
**
-** If the target doesn't answer this message immidiately
+** If the target doesn't answer this message immediately
** (as required by the standard), the SIR_NEGO_FAIL interrupt
** will be raised eventually.
** The handler removes the HS_NEGOTIATE status, and sets the
@@ -8111,7 +8114,7 @@ printk("ncr53c8xx : command successfully queued\n");
return sts;
}
-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *shost = (struct Scsi_Host *)dev_id;
@@ -8321,12 +8324,12 @@ char *ncr53c8xx; /* command line passed by insmod */
module_param(ncr53c8xx, charp, 0);
#endif
+#ifndef MODULE
static int __init ncr53c8xx_setup(char *str)
{
return sym53c8xx__setup(str);
}
-#ifndef MODULE
__setup("ncr53c8xx=", ncr53c8xx_setup);
#endif
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 78818b6684f..b39357d9af8 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -218,7 +218,7 @@
** Same as option 1, but also deal with
** misconfigured interrupts.
**
-** - Edge triggerred instead of level sensitive.
+** - Edge triggered instead of level sensitive.
** - No interrupt line connected.
** - IRQ number misconfigured.
**
@@ -549,7 +549,7 @@ struct ncr_driver_setup {
/*
** Initial setup.
-** Can be overriden at startup by a command line.
+** Can be overridden at startup by a command line.
*/
#define SCSI_NCR_DRIVER_SETUP \
{ \
@@ -1093,7 +1093,7 @@ struct scr_tblsel {
**-----------------------------------------------------------
** On 810A, 860, 825A, 875, 895 and 896 chips the content
** of SFBR register can be used as data (SCR_SFBR_DATA).
-** The 896 has additionnal IO registers starting at
+** The 896 has additional IO registers starting at
** offset 0x80. Bit 7 of register offset is stored in
** bit 7 of the SCRIPTS instruction first DWORD.
**-----------------------------------------------------------
@@ -1322,7 +1322,7 @@ struct ncr_device {
extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
extern int ncr53c8xx_release(struct Scsi_Host *host);
-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
extern int ncr53c8xx_init(void);
extern void ncr53c8xx_exit(void);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index bfb4f49e125..7c13f6f4a4c 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -256,7 +256,7 @@ static void nsp32_sack_negate (nsp32_hw_data *);
static void nsp32_do_bus_reset(nsp32_hw_data *);
/* hardware interrupt handler */
-static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);
+static irqreturn_t do_nsp32_isr(int, void *);
/* initialize hardware */
static int nsp32hw_init(nsp32_hw_data *);
@@ -1201,7 +1201,7 @@ static int nsp32hw_init(nsp32_hw_data *data)
/* interrupt routine */
-static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
{
nsp32_hw_data *data = dev_id;
unsigned int base = data->BaseAddress;
@@ -3581,7 +3581,7 @@ static struct pci_driver nsp32_driver = {
*/
static int __init init_nsp32(void) {
nsp32_msg(KERN_INFO, "loading...");
- return pci_module_init(&nsp32_driver);
+ return pci_register_driver(&nsp32_driver);
}
static void __exit exit_nsp32(void) {
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index 5addf9fb1e1..a976e8193d1 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -619,47 +619,5 @@ typedef struct _nsp32_hw_data {
#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion
or negation, 10000us == 10ms */
-/**************************************************************************
- * Compatibility functions
- */
-
-/* for Kernel 2.4 */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template)
-# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
-# define scsi_host_put(host) scsi_unregister(host)
-# define pci_name(pci_dev) ((pci_dev)->slot_name)
-
-typedef void irqreturn_t;
-# define IRQ_NONE /* */
-# define IRQ_HANDLED /* */
-# define IRQ_RETVAL(x) /* */
-
-/* This is ad-hoc version of scsi_host_get_next() */
-static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
-{
- if (host == NULL) {
- return scsi_hostlist;
- } else {
- return host->next;
- }
-}
-
-/* This is ad-hoc version of scsi_host_hn_get() */
-static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
-{
- struct Scsi_Host *host;
-
- for (host = scsi_host_get_next(NULL); host != NULL;
- host = scsi_host_get_next(host)) {
- if (host->host_no == hostno) {
- break;
- }
- }
-
- return host;
-}
-#endif
-
#endif /* _NSP32_H */
/* end */
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index dd67a68c5c2..c116a6ae3c5 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -72,12 +72,12 @@ static void dma_advance_sg(Scsi_Cmnd *);
static int oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x);
#ifdef USE_BOTTOM_HALF
-static void dma_commit(void *opaque);
+static void dma_commit(struct work_struct *unused);
long oktag_to_io(long *paddr, long *addr, long len);
long oktag_from_io(long *addr, long *paddr, long len);
-static DECLARE_WORK(tq_fake_dma, dma_commit, NULL);
+static DECLARE_WORK(tq_fake_dma, dma_commit);
#define DMA_MAXTRANSFER 0x8000
@@ -266,7 +266,7 @@ oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
*/
-static void dma_commit(void *opaque)
+static void dma_commit(struct work_struct *unused)
{
long wait,len2,pos;
struct NCR_ESP *esp;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 4a2fed350d4..824fe080d1d 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -4843,8 +4843,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
static int osst_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
- int i, cmd_nr, cmd_type, retval = 0;
- unsigned int blk;
+ int i, cmd_nr, cmd_type, blk, retval = 0;
struct st_modedef * STm;
struct st_partstat * STps;
struct osst_request * SRpnt = NULL;
@@ -5207,12 +5206,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d
priority = GFP_KERNEL;
i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
- tb = (struct osst_buffer *)kmalloc(i, priority);
+ tb = kzalloc(i, priority);
if (!tb) {
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
return NULL;
}
- memset(tb, 0, i);
+
tb->sg_segs = tb->orig_sg_segs = 0;
tb->use_sg = max_sg;
tb->in_use = 1;
@@ -5575,9 +5574,9 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
-static void osst_create_driverfs_files(struct device_driver *driverfs)
+static int osst_create_driverfs_files(struct device_driver *driverfs)
{
- driver_create_file(driverfs, &driver_attr_version);
+ return driver_create_file(driverfs, &driver_attr_version);
}
static void osst_remove_driverfs_files(struct device_driver *driverfs)
@@ -5663,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
static struct class *osst_sysfs_class;
-static int osst_sysfs_valid = 0;
-
-static void osst_sysfs_init(void)
+static int osst_sysfs_init(void)
{
osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
- if ( IS_ERR(osst_sysfs_class) )
- printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
- else
- osst_sysfs_valid = 1;
+ if (IS_ERR(osst_sysfs_class)) {
+ printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
+ return PTR_ERR(osst_sysfs_class);
+ }
+
+ return 0;
}
-static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
+static void osst_sysfs_destroy(dev_t dev)
{
- struct class_device *osst_class_member;
+ class_device_destroy(osst_sysfs_class, dev);
+}
- if (!osst_sysfs_valid) return;
+static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
+{
+ struct class_device *osst_class_member;
+ int err;
- osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name);
+ osst_class_member = class_device_create(osst_sysfs_class, NULL, dev,
+ device, "%s", name);
if (IS_ERR(osst_class_member)) {
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
- return;
+ return PTR_ERR(osst_class_member);
}
+
class_set_devdata(osst_class_member, STp);
- class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
- class_device_create_file(osst_class_member, &class_device_attr_media_version);
- class_device_create_file(osst_class_member, &class_device_attr_capacity);
- class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
- class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
- class_device_create_file(osst_class_member, &class_device_attr_file_count);
-}
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_ADR_rev);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_media_version);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_capacity);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_BOT_frame);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_EOD_frame);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_file_count);
+ if (err)
+ goto err_out;
-static void osst_sysfs_destroy(dev_t dev)
-{
- if (!osst_sysfs_valid) return;
+ return 0;
- class_device_destroy(osst_sysfs_class, dev);
+err_out:
+ osst_sysfs_destroy(dev);
+ return err;
}
static void osst_sysfs_cleanup(void)
{
- if (osst_sysfs_valid) {
- class_destroy(osst_sysfs_class);
- osst_sysfs_valid = 0;
- }
+ class_destroy(osst_sysfs_class);
}
/*
@@ -5721,7 +5740,7 @@ static int osst_probe(struct device *dev)
struct st_partstat * STps;
struct osst_buffer * buffer;
struct gendisk * drive;
- int i, dev_num;
+ int i, dev_num, err = -ENODEV;
if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return -ENODEV;
@@ -5849,13 +5868,20 @@ static int osst_probe(struct device *dev)
init_MUTEX(&tpnt->lock);
osst_nr_dev++;
write_unlock(&os_scsi_tapes_lock);
+
{
char name[8];
+
/* Rewind entry */
- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
+ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
+ if (err)
+ goto out_free_buffer;
+
/* No-rewind entry */
snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+ if (err)
+ goto out_free_sysfs1;
}
sdev_printk(KERN_INFO, SDp,
@@ -5864,9 +5890,13 @@ static int osst_probe(struct device *dev)
return 0;
+out_free_sysfs1:
+ osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
+out_free_buffer:
+ kfree(buffer);
out_put_disk:
put_disk(drive);
- return -ENODEV;
+ return err;
};
static int osst_remove(struct device *dev)
@@ -5903,19 +5933,39 @@ static int osst_remove(struct device *dev)
static int __init init_osst(void)
{
+ int err;
+
printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
validate_options();
- osst_sysfs_init();
- if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
+ err = osst_sysfs_init();
+ if (err)
+ return err;
+
+ err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
+ if (err < 0) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
- osst_sysfs_cleanup();
- return 1;
+ goto err_out;
}
- osst_create_driverfs_files(&osst_template.gendrv);
+
+ err = scsi_register_driver(&osst_template.gendrv);
+ if (err)
+ goto err_out_chrdev;
+
+ err = osst_create_driverfs_files(&osst_template.gendrv);
+ if (err)
+ goto err_out_scsidrv;
return 0;
+
+err_out_scsidrv:
+ scsi_unregister_driver(&osst_template.gendrv);
+err_out_chrdev:
+ unregister_chrdev(OSST_MAJOR, "osst");
+err_out:
+ osst_sysfs_cleanup();
+ return err;
}
static void __exit exit_osst (void)
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index ee449b29fc8..aad362ba02e 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -154,16 +154,11 @@ static int aha152x_config_cs(struct pcmcia_device *link)
DEBUG(0, "aha152x_config(0x%p)\n", link);
- tuple.DesiredTuple = CISTPL_CONFIG;
tuple.TupleData = tuple_data;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
- link->conf.ConfigBase = parse.config.base;
-
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple.Attributes = 0;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
while (1) {
if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 85f7ffac19a..a1c5f265069 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -136,14 +136,9 @@ static int fdomain_config(struct pcmcia_device *link)
DEBUG(0, "fdomain_config(0x%p)\n", link);
- tuple.DesiredTuple = CISTPL_CONFIG;
tuple.TupleData = tuple_data;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
- link->conf.ConfigBase = parse.config.base;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 0d4c04e1f3d..d72df5dae4e 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -80,7 +80,6 @@ static int free_ports = 0;
module_param(free_ports, bool, 0);
MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
-/* /usr/src/linux/drivers/scsi/hosts.h */
static struct scsi_host_template nsp_driver_template = {
.proc_name = "nsp_cs",
.proc_info = nsp_proc_info,
@@ -184,7 +183,7 @@ static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...
* Clenaup parameters and call done() functions.
* You must be set SCpnt->result before call this function.
*/
-static void nsp_scsi_done(Scsi_Cmnd *SCpnt)
+static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
{
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -193,7 +192,8 @@ static void nsp_scsi_done(Scsi_Cmnd *SCpnt)
SCpnt->scsi_done(SCpnt);
}
-static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
#ifdef NSP_DEBUG
/*unsigned int host_id = SCpnt->device->host->this_id;*/
@@ -366,7 +366,7 @@ static int nsphw_init(nsp_hw_data *data)
/*
* Start selection phase
*/
-static int nsphw_start_selection(Scsi_Cmnd *SCpnt)
+static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
{
unsigned int host_id = SCpnt->device->host->this_id;
unsigned int base = SCpnt->device->host->io_port;
@@ -447,7 +447,7 @@ static struct nsp_sync_table nsp_sync_table_20M[] = {
/*
* setup synchronous data transfer mode
*/
-static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt)
+static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
{
unsigned char target = scmd_id(SCpnt);
// unsigned char lun = SCpnt->device->lun;
@@ -505,7 +505,7 @@ static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt)
/*
* start ninja hardware timer
*/
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
+static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
{
unsigned int base = SCpnt->device->host->io_port;
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -518,7 +518,8 @@ static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
/*
* wait for bus phase change
*/
-static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
+static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
+ char *str)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned char reg;
@@ -545,9 +546,9 @@ static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
/*
* expect Ninja Irq
*/
-static int nsp_expect_signal(Scsi_Cmnd *SCpnt,
- unsigned char current_phase,
- unsigned char mask)
+static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
+ unsigned char current_phase,
+ unsigned char mask)
{
unsigned int base = SCpnt->device->host->io_port;
int time_out;
@@ -580,7 +581,7 @@ static int nsp_expect_signal(Scsi_Cmnd *SCpnt,
/*
* transfer SCSI message
*/
-static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
+static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
{
unsigned int base = SCpnt->device->host->io_port;
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -620,7 +621,7 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
/*
* get extra SCSI data from fifo
*/
-static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
+static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
{
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
unsigned int count;
@@ -652,7 +653,7 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
/*
* accept reselection
*/
-static int nsp_reselected(Scsi_Cmnd *SCpnt)
+static int nsp_reselected(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned int host_id = SCpnt->device->host->this_id;
@@ -691,7 +692,7 @@ static int nsp_reselected(Scsi_Cmnd *SCpnt)
/*
* count how many data transferd
*/
-static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
+static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned int count;
@@ -718,7 +719,7 @@ static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
/*
* read data in DATA IN phase
*/
-static void nsp_pio_read(Scsi_Cmnd *SCpnt)
+static void nsp_pio_read(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned long mmio_base = SCpnt->device->host->base;
@@ -813,7 +814,7 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt)
/*
* write data in DATA OUT phase
*/
-static void nsp_pio_write(Scsi_Cmnd *SCpnt)
+static void nsp_pio_write(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned long mmio_base = SCpnt->device->host->base;
@@ -906,7 +907,7 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt)
/*
* setup synchronous/asynchronous data transfer mode
*/
-static int nsp_nexus(Scsi_Cmnd *SCpnt)
+static int nsp_nexus(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
unsigned char target = scmd_id(SCpnt);
@@ -949,11 +950,11 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt)
/*
* interrupt handler
*/
-static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nspintr(int irq, void *dev_id)
{
unsigned int base;
unsigned char irq_status, irq_phase, phase;
- Scsi_Cmnd *tmpSC;
+ struct scsi_cmnd *tmpSC;
unsigned char target, lun;
unsigned int *sync_neg;
int i, tmp;
@@ -1531,7 +1532,7 @@ nsp_proc_info(
/*---------------------------------------------------------------*/
/*
-static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
+static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
{
nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
@@ -1559,7 +1560,7 @@ static int nsp_bus_reset(nsp_hw_data *data)
return SUCCESS;
}
-static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
{
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -1568,7 +1569,7 @@ static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
return nsp_bus_reset(data);
}
-static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
+static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
{
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -1684,16 +1685,10 @@ static int nsp_cs_config(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "in");
- tuple.DesiredTuple = CISTPL_CONFIG;
tuple.Attributes = 0;
tuple.TupleData = tuple_data;
tuple.TupleDataMax = sizeof(tuple_data);
tuple.TupleOffset = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
/* Look up the current Vcc */
CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 8908b8e5b78..625ca97da52 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -266,7 +266,7 @@ typedef struct _nsp_hw_data {
int TimerCount;
int SelectionTimeOut;
- Scsi_Cmnd *CurrentSC;
+ struct scsi_cmnd *CurrentSC;
//int CurrnetTarget;
int FifoCount;
@@ -319,34 +319,38 @@ static int nsp_proc_info (
int hostno,
#endif
int inout);
-static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *SCpnt));
+static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
+ void (* done)(struct scsi_cmnd *SCpnt));
/* Error handler */
-/*static int nsp_eh_abort (Scsi_Cmnd *SCpnt);*/
-/*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/
-static int nsp_eh_bus_reset (Scsi_Cmnd *SCpnt);
-static int nsp_eh_host_reset (Scsi_Cmnd *SCpnt);
+/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/
+/*static int nsp_eh_device_reset(struct scsi_cmnd *SCpnt);*/
+static int nsp_eh_bus_reset (struct scsi_cmnd *SCpnt);
+static int nsp_eh_host_reset (struct scsi_cmnd *SCpnt);
static int nsp_bus_reset (nsp_hw_data *data);
/* */
static int nsphw_init (nsp_hw_data *data);
-static int nsphw_start_selection(Scsi_Cmnd *SCpnt);
-static void nsp_start_timer (Scsi_Cmnd *SCpnt, int time);
-static int nsp_fifo_count (Scsi_Cmnd *SCpnt);
-static void nsp_pio_read (Scsi_Cmnd *SCpnt);
-static void nsp_pio_write (Scsi_Cmnd *SCpnt);
-static int nsp_nexus (Scsi_Cmnd *SCpnt);
-static void nsp_scsi_done (Scsi_Cmnd *SCpnt);
-static int nsp_analyze_sdtr (Scsi_Cmnd *SCpnt);
-static int nsp_negate_signal (Scsi_Cmnd *SCpnt, unsigned char mask, char *str);
-static int nsp_expect_signal (Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char mask);
-static int nsp_xfer (Scsi_Cmnd *SCpnt, int phase);
-static int nsp_dataphase_bypass (Scsi_Cmnd *SCpnt);
-static int nsp_reselected (Scsi_Cmnd *SCpnt);
+static int nsphw_start_selection(struct scsi_cmnd *SCpnt);
+static void nsp_start_timer (struct scsi_cmnd *SCpnt, int time);
+static int nsp_fifo_count (struct scsi_cmnd *SCpnt);
+static void nsp_pio_read (struct scsi_cmnd *SCpnt);
+static void nsp_pio_write (struct scsi_cmnd *SCpnt);
+static int nsp_nexus (struct scsi_cmnd *SCpnt);
+static void nsp_scsi_done (struct scsi_cmnd *SCpnt);
+static int nsp_analyze_sdtr (struct scsi_cmnd *SCpnt);
+static int nsp_negate_signal (struct scsi_cmnd *SCpnt,
+ unsigned char mask, char *str);
+static int nsp_expect_signal (struct scsi_cmnd *SCpnt,
+ unsigned char current_phase,
+ unsigned char mask);
+static int nsp_xfer (struct scsi_cmnd *SCpnt, int phase);
+static int nsp_dataphase_bypass (struct scsi_cmnd *SCpnt);
+static int nsp_reselected (struct scsi_cmnd *SCpnt);
static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
/* Interrupt handler */
-//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs);
+//static irqreturn_t nspintr(int irq, void *dev_id);
/* Module entry point*/
static int __init nsp_cs_init(void);
@@ -355,8 +359,8 @@ static void __exit nsp_cs_exit(void);
/* Debug */
#ifdef NSP_DEBUG
-static void show_command (Scsi_Cmnd *SCpnt);
-static void show_phase (Scsi_Cmnd *SCpnt);
+static void show_command (struct scsi_cmnd *SCpnt);
+static void show_phase (struct scsi_cmnd *SCpnt);
static void show_busphase(unsigned char stat);
static void show_message (nsp_hw_data *data);
#else
diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c
index 62e5c60067f..2f75fe6e35a 100644
--- a/drivers/scsi/pcmcia/nsp_debug.c
+++ b/drivers/scsi/pcmcia/nsp_debug.c
@@ -138,12 +138,12 @@ static void print_commandk (unsigned char *command)
printk("\n");
}
-static void show_command(Scsi_Cmnd *SCpnt)
+static void show_command(struct scsi_cmnd *SCpnt)
{
print_commandk(SCpnt->cmnd);
}
-static void show_phase(Scsi_Cmnd *SCpnt)
+static void show_phase(struct scsi_cmnd *SCpnt)
{
int i = SCpnt->SCp.phase;
diff --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c
index d7057737ff3..ef593b70d0f 100644
--- a/drivers/scsi/pcmcia/nsp_message.c
+++ b/drivers/scsi/pcmcia/nsp_message.c
@@ -8,7 +8,7 @@
/* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */
-static void nsp_message_in(Scsi_Cmnd *SCpnt)
+static void nsp_message_in(struct scsi_cmnd *SCpnt)
{
unsigned int base = SCpnt->device->host->io_port;
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
@@ -50,7 +50,7 @@ static void nsp_message_in(Scsi_Cmnd *SCpnt)
}
-static void nsp_message_out(Scsi_Cmnd *SCpnt)
+static void nsp_message_out(struct scsi_cmnd *SCpnt)
{
nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
int ret = 1;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 86c2ac6ae62..9d431fe7f47 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -208,18 +208,11 @@ static int qlogic_config(struct pcmcia_device * link)
DEBUG(0, "qlogic_config(0x%p)\n", link);
+ info->manf_id = link->manf_id;
+
tuple.TupleData = (cisdata_t *) tuple_data;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
- tuple.DesiredTuple = CISTPL_CONFIG;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
- link->conf.ConfigBase = parse.config.base;
-
- tuple.DesiredTuple = CISTPL_MANFID;
- if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS))
- info->manf_id = le16_to_cpu(tuple.TupleData[0]);
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 0b65099acb1..fb7acea6028 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -363,7 +363,7 @@ SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int
}
static irqreturn_t
-SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
+SYM53C500_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
@@ -722,19 +722,11 @@ SYM53C500_config(struct pcmcia_device *link)
DEBUG(0, "SYM53C500_config(0x%p)\n", link);
+ info->manf_id = link->manf_id;
+
tuple.TupleData = (cisdata_t *)tuple_data;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
- tuple.DesiredTuple = CISTPL_CONFIG;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
- link->conf.ConfigBase = parse.config.base;
-
- tuple.DesiredTuple = CISTPL_MANFID;
- if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) &&
- (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS))
- info->manf_id = le16_to_cpu(tuple.TupleData[0]);
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 0bd9c60e645..aa60a5f1fbc 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -67,7 +67,6 @@ static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
{
- SCpnt->request->rq_status = RQ_SCSI_DONE;
PLND(("Detect done %08lx\n", (long)SCpnt))
if (atomic_dec_and_test (&fcss))
up(&fc_sem);
@@ -166,7 +165,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
- SCpnt->request->rq_status = RQ_SCSI_BUSY;
+ SCpnt->request->cmd_flags &= ~REQ_STARTED;
SCpnt->done = pluto_detect_done;
SCpnt->request_bufflen = 256;
@@ -178,7 +177,8 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
for (retry = 0; retry < 5; retry++) {
for (i = 0; i < fcscount; i++) {
if (!fcs[i].fc) break;
- if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) {
+ if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) {
+ fcs[i].cmd.request->cmd_flags |= REQ_STARTED;
disable_irq(fcs[i].fc->irq);
PLND(("queuecommand %d %d\n", retry, i))
fcp_scsi_queuecommand (&(fcs[i].cmd),
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index b0eba39f208..584ba4d6e03 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -31,7 +31,7 @@ typedef struct {
int base; /* Actual port address */
int mode; /* Transfer mode */
struct scsi_cmnd *cur_cmd; /* Current queued command */
- struct work_struct ppa_tq; /* Polling interrupt stuff */
+ struct delayed_work ppa_tq; /* Polling interrupt stuff */
unsigned long jstart; /* Jiffies at start */
unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed:1; /* Failure flag */
@@ -627,9 +627,9 @@ static int ppa_completion(struct scsi_cmnd *cmd)
* the scheduler's task queue to generate a stream of call-backs and
* complete the request when the drive is ready.
*/
-static void ppa_interrupt(void *data)
+static void ppa_interrupt(struct work_struct *work)
{
- ppa_struct *dev = (ppa_struct *) data;
+ ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work);
struct scsi_cmnd *cmd = dev->cur_cmd;
if (!cmd) {
@@ -637,7 +637,6 @@ static void ppa_interrupt(void *data)
return;
}
if (ppa_engine(dev, cmd)) {
- dev->ppa_tq.data = (void *) dev;
schedule_delayed_work(&dev->ppa_tq, 1);
return;
}
@@ -822,8 +821,7 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd,
cmd->result = DID_ERROR << 16; /* default return code */
cmd->SCp.phase = 0; /* bus free */
- dev->ppa_tq.data = dev;
- schedule_work(&dev->ppa_tq);
+ schedule_delayed_work(&dev->ppa_tq, 0);
ppa_pb_claim(dev);
@@ -1012,7 +1010,7 @@ static LIST_HEAD(ppa_hosts);
static int __ppa_attach(struct parport *pb)
{
struct Scsi_Host *host;
- DECLARE_WAIT_QUEUE_HEAD(waiting);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
ppa_struct *dev;
int ports;
@@ -1086,7 +1084,7 @@ static int __ppa_attach(struct parport *pb)
else
ports = 8;
- INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev);
+ INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt);
err = -ENOMEM;
host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *));
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 7511df3588e..ba8021427b8 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -73,7 +73,6 @@
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index 5c2cdf523c3..899e89d6fe6 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -87,11 +87,11 @@ typedef struct
{
USHORT ports[13];
OUR_DEVICE device[8];
- Scsi_Cmnd *pSCmnd;
+ struct scsi_cmnd *pSCmnd;
IDE_STRUCT ide;
ULONG startSector;
USHORT sectorCount;
- Scsi_Cmnd *SCpnt;
+ struct scsi_cmnd *SCpnt;
VOID *buffer;
USHORT expectingIRQ;
} ADAPTER240I, *PADAPTER240I;
@@ -247,19 +247,18 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
*
* Parameters: irq - Hardware IRQ number.
* dev_id -
- * regs -
*
* Returns: TRUE if drive is not ready in time.
*
****************************************************************/
-static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+static void Irq_Handler (int irq, void *dev_id)
{
- struct Scsi_Host *shost; // Pointer to host data block
- PADAPTER240I padapter; // Pointer to adapter control structure
- USHORT *pports; // I/O port array
- Scsi_Cmnd *SCpnt;
- UCHAR status;
- int z;
+ struct Scsi_Host *shost; // Pointer to host data block
+ PADAPTER240I padapter; // Pointer to adapter control structure
+ USHORT *pports; // I/O port array
+ struct scsi_cmnd *SCpnt;
+ UCHAR status;
+ int z;
DEB(printk ("\npsi240i received interrupt\n"));
@@ -329,7 +328,7 @@ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
pinquiryData->AdditionalLength = 35 - 4;
// Fill in vendor identification fields.
- for ( z = 0; z < 20; z += 2 )
+ for ( z = 0; z < 8; z += 2 )
{
pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1];
pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
@@ -368,13 +367,13 @@ irqerror:;
SCpnt->scsi_done (SCpnt);
}
-static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- Irq_Handler(irq, dev_id, regs);
+ Irq_Handler(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
@@ -390,12 +389,17 @@ static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
* Returns: Status code.
*
****************************************************************/
-static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
- UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB
- PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); // Pointer to adapter control structure
- POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];// Pointer to device information
- UCHAR rc; // command return code
+ UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
+ // Pointer to SCSI CDB
+ PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
+ // Pointer to adapter control structure
+ POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
+ // Pointer to device information
+ UCHAR rc;
+ // command return code
SCpnt->scsi_done = done;
padapter->ide.ide.ides.spigot = pdev->spigot;
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
index 6a598766df5..21ebb921400 100644
--- a/drivers/scsi/psi240i.h
+++ b/drivers/scsi/psi240i.h
@@ -309,7 +309,7 @@ typedef struct _IDENTIFY_DATA2 {
#endif // PSI_EIDE_SCSIOP
// function prototypes
-int Psi240i_Command (Scsi_Cmnd *SCpnt);
-int Psi240i_Abort (Scsi_Cmnd *SCpnt);
-int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
+int Psi240i_Command(struct scsi_cmnd *SCpnt);
+int Psi240i_Abort(struct scsi_cmnd *SCpnt);
+int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
#endif
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 8953991462d..16af5b79e58 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -813,7 +813,7 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
uint16_t data;
unsigned char *handle;
int result, i;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
struct timer_list timer;
ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
@@ -931,11 +931,10 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
case BUS_RESET:
if (qla1280_verbose)
- printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS "
- "DEVICE RESET\n", ha->host_no, bus);
- if (qla1280_bus_reset(ha, bus == 0))
+ printk(KERN_INFO "qla1280(%ld:%d): Issued bus "
+ "reset.\n", ha->host_no, bus);
+ if (qla1280_bus_reset(ha, bus) == 0)
result = SUCCESS;
-
break;
case ADAPTER_RESET:
@@ -1113,7 +1112,7 @@ qla1280_enable_intrs(struct scsi_qla_host *ha)
* Handles the H/W interrupt
**************************************************************************/
static irqreturn_t
-qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla1280_intr_handler(int irq, void *dev_id)
{
struct scsi_qla_host *ha;
struct device_reg __iomem *reg;
@@ -2406,7 +2405,7 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
uint16_t *optr, *iptr;
uint16_t __iomem *mptr;
uint16_t data;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
struct timer_list timer;
ENTER("qla1280_mailbox_command");
@@ -2862,7 +2861,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(30);
+ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
@@ -3161,7 +3160,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(30);
+ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
@@ -4484,7 +4483,7 @@ qla1280_init(void)
qla1280_setup(qla1280);
#endif
- return pci_module_init(&qla1280_pci_driver);
+ return pci_register_driver(&qla1280_pci_driver);
}
static void __exit
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 87f90c4f08e..7b18a6c7b7e 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -379,21 +379,37 @@ static struct bin_attribute sysfs_sfp_attr = {
.read = qla2x00_sysfs_read_sfp,
};
+static struct sysfs_entry {
+ char *name;
+ struct bin_attribute *attr;
+ int is4GBp_only;
+} bin_file_entries[] = {
+ { "fw_dump", &sysfs_fw_dump_attr, },
+ { "nvram", &sysfs_nvram_attr, },
+ { "optrom", &sysfs_optrom_attr, },
+ { "optrom_ctl", &sysfs_optrom_ctl_attr, },
+ { "vpd", &sysfs_vpd_attr, 1 },
+ { "sfp", &sysfs_sfp_attr, 1 },
+ { NULL },
+};
+
void
qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
{
struct Scsi_Host *host = ha->host;
+ struct sysfs_entry *iter;
+ int ret;
- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj,
- &sysfs_optrom_ctl_attr);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- sysfs_create_bin_file(&host->shost_gendev.kobj,
- &sysfs_vpd_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj,
- &sysfs_sfp_attr);
+ for (iter = bin_file_entries; iter->name; iter++) {
+ if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ continue;
+
+ ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
+ iter->attr);
+ if (ret)
+ qla_printk(KERN_INFO, ha,
+ "Unable to create sysfs %s binary attribute "
+ "(%d).\n", iter->name, ret);
}
}
@@ -401,17 +417,14 @@ void
qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
{
struct Scsi_Host *host = ha->host;
+ struct sysfs_entry *iter;
+
+ for (iter = bin_file_entries; iter->name; iter++) {
+ if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ continue;
- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
- sysfs_remove_bin_file(&host->shost_gendev.kobj,
- &sysfs_optrom_ctl_attr);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- sysfs_remove_bin_file(&host->shost_gendev.kobj,
- &sysfs_vpd_attr);
sysfs_remove_bin_file(&host->shost_gendev.kobj,
- &sysfs_sfp_attr);
+ iter->attr);
}
if (ha->beacon_blink_led == 1)
@@ -691,13 +704,13 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
uint32_t speed = 0;
switch (ha->link_data_rate) {
- case LDR_1GB:
+ case PORT_SPEED_1GB:
speed = 1;
break;
- case LDR_2GB:
+ case PORT_SPEED_2GB:
speed = 2;
break;
- case LDR_4GB:
+ case PORT_SPEED_4GB:
speed = 4;
break;
}
@@ -849,6 +862,49 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
return pfc_host_stat;
}
+static void
+qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
+}
+
+static void
+qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
+}
+
+static void
+qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+ u64 node_name;
+
+ if (ha->device_flags & SWITCH_FOUND)
+ node_name = wwn_to_u64(ha->fabric_node_name);
+ else
+ node_name = wwn_to_u64(ha->node_name);
+
+ fc_host_fabric_name(shost) = node_name;
+}
+
+static void
+qla2x00_get_host_port_state(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ if (!ha->flags.online)
+ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+ else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
+ fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+ else
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+}
+
struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
@@ -861,6 +917,14 @@ struct fc_function_template qla2xxx_transport_functions = {
.show_host_speed = 1,
.get_host_port_type = qla2x00_get_host_port_type,
.show_host_port_type = 1,
+ .get_host_symbolic_name = qla2x00_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+ .set_host_system_hostname = qla2x00_set_host_system_hostname,
+ .show_host_system_hostname = 1,
+ .get_host_fabric_name = qla2x00_get_host_fabric_name,
+ .show_host_fabric_name = 1,
+ .get_host_port_state = qla2x00_get_host_port_state,
+ .show_host_port_state = 1,
.dd_fcrport_size = sizeof(struct fc_port *),
.show_rport_supported_classes = 1,
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 533425338e0..5b12278968e 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -38,7 +38,7 @@
* Macros use for debugging the driver.
*/
-#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG(x) do { if (ql2xextended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_1)
#define DEBUG1(x) do {x;} while (0)
@@ -46,12 +46,12 @@
#define DEBUG1(x) do {} while (0)
#endif
-#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_3(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
+#define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_3)
#define DEBUG3(x) do {x;} while (0)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0930260aec2..c4fc40f8e8c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -608,6 +608,7 @@ typedef struct {
*/
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
+#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
#define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */
#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */
#define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */
@@ -1497,6 +1498,9 @@ typedef struct {
port_id_t d_id;
uint8_t node_name[WWN_SIZE];
uint8_t port_name[WWN_SIZE];
+ uint8_t fabric_port_name[WWN_SIZE];
+ uint16_t fp_speeds;
+ uint16_t fp_speed;
} sw_info_t;
/*
@@ -1524,6 +1528,9 @@ typedef struct fc_port {
uint16_t loop_id;
uint16_t old_loop_id;
+ uint8_t fabric_port_name[WWN_SIZE];
+ uint16_t fp_speed;
+
fc_port_type_t port_type;
atomic_t state;
@@ -1538,6 +1545,9 @@ typedef struct fc_port {
spinlock_t rport_lock;
struct fc_rport *rport, *drport;
u32 supported_classes;
+
+ unsigned long last_queue_full;
+ unsigned long last_ramp_up;
} fc_port_t;
/*
@@ -1635,6 +1645,15 @@ typedef struct fc_port {
#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
#define RSNN_NN_RSP_SIZE 16
+#define GFPN_ID_CMD 0x11C
+#define GFPN_ID_REQ_SIZE (16 + 4)
+#define GFPN_ID_RSP_SIZE (16 + 8)
+
+#define GPSC_CMD 0x127
+#define GPSC_REQ_SIZE (16 + 8)
+#define GPSC_RSP_SIZE (16 + 2 + 2)
+
+
/*
* HBA attribute types.
*/
@@ -1748,7 +1767,7 @@ struct ct_sns_req {
uint8_t reserved[3];
union {
- /* GA_NXT, GPN_ID, GNN_ID, GFT_ID */
+ /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */
struct {
uint8_t reserved;
uint8_t port_id[3];
@@ -1823,6 +1842,10 @@ struct ct_sns_req {
struct {
uint8_t port_name[8];
} dpa;
+
+ struct {
+ uint8_t port_name[8];
+ } gpsc;
} req;
};
@@ -1886,6 +1909,15 @@ struct ct_sns_rsp {
uint8_t port_name[8];
struct ct_fdmi_hba_attributes attrs;
} ghat;
+
+ struct {
+ uint8_t port_name[8];
+ } gfpn_id;
+
+ struct {
+ uint16_t speeds;
+ uint16_t speed;
+ } gpsc;
} rsp;
};
@@ -1980,7 +2012,7 @@ struct isp_operations {
char * (*pci_info_str) (struct scsi_qla_host *, char *);
char * (*fw_version_str) (struct scsi_qla_host *, char *);
- irqreturn_t (*intr_handler) (int, void *, struct pt_regs *);
+ irq_handler_t intr_handler;
void (*enable_intrs) (struct scsi_qla_host *);
void (*disable_intrs) (struct scsi_qla_host *);
@@ -2182,11 +2214,11 @@ typedef struct scsi_qla_host {
uint16_t max_public_loop_ids;
uint16_t min_external_loopid; /* First external loop Id */
+#define PORT_SPEED_UNKNOWN 0xFFFF
+#define PORT_SPEED_1GB 0x00
+#define PORT_SPEED_2GB 0x01
+#define PORT_SPEED_4GB 0x03
uint16_t link_data_rate; /* F/W operating speed */
-#define LDR_1GB 0
-#define LDR_2GB 1
-#define LDR_4GB 3
-#define LDR_UNKNOWN 0xFFFF
uint8_t current_topology;
uint8_t prev_topology;
@@ -2226,6 +2258,7 @@ typedef struct scsi_qla_host {
uint16_t mgmt_svr_loop_id;
uint32_t login_retry_count;
+ int max_q_depth;
/* Fibre Channel Device List. */
struct list_head fcports;
@@ -2333,6 +2366,7 @@ typedef struct scsi_qla_host {
uint8_t *node_name;
uint8_t *port_name;
+ uint8_t fabric_node_name[WWN_SIZE];
uint32_t isp_abort_cnt;
/* Option ROM information. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 8311ac2b93a..32ebeec45ff 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -48,6 +48,7 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
+extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
/*
* Global Data in qla_os.c source file.
@@ -60,7 +61,8 @@ extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
extern int ql2xallocfwdump;
-extern int extended_error_logging;
+extern int ql2xextended_error_logging;
+extern int ql2xqfullrampup;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -208,12 +210,18 @@ qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
extern int
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+extern int
+qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
+
+extern int
+qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
-extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
-extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
-extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *);
+extern irqreturn_t qla2100_intr_handler(int, void *);
+extern irqreturn_t qla2300_intr_handler(int, void *);
+extern irqreturn_t qla24xx_intr_handler(int, void *);
extern void qla2x00_process_response_queue(struct scsi_qla_host *);
extern void qla24xx_process_response_queue(struct scsi_qla_host *);
@@ -279,6 +287,9 @@ extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
+extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
+extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
+extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
/*
* Global Function Prototypes in qla_attr.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 2ebf259fccb..97fbc62ec66 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -612,6 +612,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
return (rval);
}
+void
+qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn)
+{
+ 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);
+}
+
/**
* qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
* @ha: HA context
@@ -622,9 +630,6 @@ int
qla2x00_rsnn_nn(scsi_qla_host_t *ha)
{
int rval;
- uint8_t *snn;
- uint8_t version[20];
-
ms_iocb_entry_t *ms_pkt;
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
@@ -649,20 +654,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE);
/* Prepare the Symbolic Node Name */
- /* Board type */
- snn = ct_req->req.rsnn_nn.sym_node_name;
- strcpy(snn, ha->model_number);
- /* Firmware version */
- strcat(snn, " FW:v");
- sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
- ha->fw_minor_version, ha->fw_subminor_version);
- strcat(snn, version);
- /* Driver version */
- strcat(snn, " DVR:v");
- strcat(snn, qla2x00_version_str);
+ qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name);
/* Calculate SNN length */
- ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
+ ct_req->req.rsnn_nn.name_len =
+ (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
/* Update MS IOCB request */
ms_pkt->req_bytecount =
@@ -687,7 +683,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
return (rval);
}
-
/**
* qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
* @ha: HA context
@@ -1585,6 +1580,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
eiter->a.os_dev_name));
+ /* Hostname. */
+ if (strlen(fc_host_system_hostname(ha->host))) {
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
+ snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
+ "%s", fc_host_system_hostname(ha->host));
+ alen = strlen(eiter->a.host_name);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
+ ha->host_no, eiter->a.host_name));
+ }
+
/* Update MS request size. */
qla2x00_update_ms_fdmi_iocb(ha, size + 16);
@@ -1647,3 +1657,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
return rval;
}
+
+/**
+ * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+ int rval;
+ uint16_t i;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+ /* Issue GFPN_ID */
+ memset(list[i].fabric_port_name, 0, WWN_SIZE);
+
+ /* Prepare common MS IOCB */
+ ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+ GFPN_ID_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
+ GFPN_ID_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare CT arguments -- port_id */
+ ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+ ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+ ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
+ "failed (%d).\n", ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+ "GFPN_ID") != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* Save fabric portname */
+ memcpy(list[i].fabric_port_name,
+ ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
+ }
+
+ /* Last device exit. */
+ if (list[i].d_id.b.rsvd_1 != 0)
+ break;
+ }
+
+ return (rval);
+}
+
+static inline void *
+qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
+ uint32_t rsp_size)
+{
+ struct ct_entry_24xx *ct_pkt;
+
+ ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+ memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+ ct_pkt->entry_type = CT_IOCB_TYPE;
+ ct_pkt->entry_count = 1;
+ ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
+ ct_pkt->timeout = __constant_cpu_to_le16(59);
+ ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+ ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+
+ ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+
+ ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+
+ return ct_pkt;
+}
+
+
+static inline struct ct_sns_req *
+qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
+ uint16_t rsp_size)
+{
+ memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+
+ ct_req->header.revision = 0x01;
+ ct_req->header.gs_type = 0xFA;
+ ct_req->header.gs_subtype = 0x01;
+ ct_req->command = cpu_to_be16(cmd);
+ ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+
+ return ct_req;
+}
+
+/**
+ * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
+{
+ int rval;
+ uint16_t i;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ rval = qla2x00_mgmt_svr_login(ha);
+ if (rval)
+ return rval;
+
+ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+ /* Issue GFPN_ID */
+ list[i].fp_speeds = list[i].fp_speed = 0;
+
+ /* Prepare common MS IOCB */
+ ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
+ GPSC_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
+ GPSC_CMD, GPSC_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare CT arguments -- port_name */
+ memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
+ WWN_SIZE);
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
+ "failed (%d).\n", ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+ "GPSC") != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* Save portname */
+ list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
+ list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
+
+ DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
+ "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
+ "speed=%04x.\n", ha->host_no,
+ list[i].fabric_port_name[0],
+ list[i].fabric_port_name[1],
+ list[i].fabric_port_name[2],
+ list[i].fabric_port_name[3],
+ list[i].fabric_port_name[4],
+ list[i].fabric_port_name[5],
+ list[i].fabric_port_name[6],
+ list[i].fabric_port_name[7],
+ be16_to_cpu(list[i].fp_speeds),
+ be16_to_cpu(list[i].fp_speed)));
+ }
+
+ /* Last device exit. */
+ if (list[i].d_id.b.rsvd_1 != 0)
+ break;
+ }
+
+ return (rval);
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 859649160ca..a823f0bc519 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -59,9 +59,6 @@ int
qla2x00_initialize_adapter(scsi_qla_host_t *ha)
{
int rval;
- uint8_t restart_risc = 0;
- uint8_t retry;
- uint32_t wait_time;
/* Clear adapter flags. */
ha->flags.online = 0;
@@ -104,87 +101,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
- retry = 10;
- /*
- * Try to configure the loop.
- */
- do {
- restart_risc = 0;
-
- /* If firmware needs to be loaded */
- if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
- if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) {
- rval = qla2x00_setup_chip(ha);
- }
- }
-
- if (rval == QLA_SUCCESS &&
- (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
-check_fw_ready_again:
- /*
- * Wait for a successful LIP up to a maximum
- * of (in seconds): RISC login timeout value,
- * RISC retry count value, and port down retry
- * value OR a minimum of 4 seconds OR If no
- * cable, only 5 seconds.
- */
- rval = qla2x00_fw_ready(ha);
- if (rval == QLA_SUCCESS) {
- clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-
- /* Issue a marker after FW becomes ready. */
- qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-
- /*
- * Wait at most MAX_TARGET RSCNs for a stable
- * link.
- */
- wait_time = 256;
- do {
- clear_bit(LOOP_RESYNC_NEEDED,
- &ha->dpc_flags);
- rval = qla2x00_configure_loop(ha);
-
- if (test_and_clear_bit(ISP_ABORT_NEEDED,
- &ha->dpc_flags)) {
- restart_risc = 1;
- break;
- }
-
- /*
- * If loop state change while we were
- * discoverying devices then wait for
- * LIP to complete
- */
-
- if (atomic_read(&ha->loop_state) !=
- LOOP_READY && retry--) {
- goto check_fw_ready_again;
- }
- wait_time--;
- } while (!atomic_read(&ha->loop_down_timer) &&
- retry &&
- wait_time &&
- (test_bit(LOOP_RESYNC_NEEDED,
- &ha->dpc_flags)));
-
- if (wait_time == 0)
- rval = QLA_FUNCTION_FAILED;
- } else if (ha->device_flags & DFLG_NO_CABLE)
- /* If no cable, then all is good. */
- rval = QLA_SUCCESS;
- }
- } while (restart_risc && retry--);
-
- if (rval == QLA_SUCCESS) {
- clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
- qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
- ha->marker_needed = 0;
-
- ha->flags.online = 1;
- } else {
- DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+ if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+ rval = ha->isp_ops.chip_diag(ha);
+ if (rval)
+ return (rval);
+ rval = qla2x00_setup_chip(ha);
+ if (rval)
+ return (rval);
}
+ rval = qla2x00_init_rings(ha);
return (rval);
}
@@ -1644,7 +1569,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
* Set host adapter parameters.
*/
if (nv->host_p[0] & BIT_7)
- extended_error_logging = 1;
+ ql2xextended_error_logging = 1;
ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
/* Always load RISC code on non ISP2[12]00 chips. */
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
@@ -2074,6 +1999,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
}
+ /* Base iIDMA settings on HBA port speed. */
+ switch (ha->link_data_rate) {
+ case PORT_SPEED_1GB:
+ fcport->fp_speed = cpu_to_be16(BIT_15);
+ break;
+ case PORT_SPEED_2GB:
+ fcport->fp_speed = cpu_to_be16(BIT_14);
+ break;
+ case PORT_SPEED_4GB:
+ fcport->fp_speed = cpu_to_be16(BIT_13);
+ break;
+ }
+
qla2x00_update_fcport(ha, fcport);
found_devs++;
@@ -2109,6 +2047,62 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
}
}
+static void
+qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+#define LS_UNKNOWN 2
+ static char *link_speeds[5] = { "1", "2", "?", "4" };
+ int rval;
+ uint16_t port_speed, mb[6];
+
+ if (!IS_QLA24XX(ha))
+ return;
+
+ switch (be16_to_cpu(fcport->fp_speed)) {
+ case BIT_15:
+ port_speed = PORT_SPEED_1GB;
+ break;
+ case BIT_14:
+ port_speed = PORT_SPEED_2GB;
+ break;
+ case BIT_13:
+ port_speed = PORT_SPEED_4GB;
+ break;
+ default:
+ DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
+ "unsupported FM port operating speed (%04x).\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7],
+ be16_to_cpu(fcport->fp_speed)));
+ port_speed = PORT_SPEED_UNKNOWN;
+ break;
+ }
+ if (port_speed == PORT_SPEED_UNKNOWN)
+ return;
+
+ rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
+ "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7], rval,
+ port_speed, mb[0], mb[1]));
+ } else {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "iIDMA adjusted to %s GB/s on "
+ "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
+ link_speeds[port_speed], fcport->port_name[0],
+ fcport->port_name[1], fcport->port_name[2],
+ fcport->port_name[3], fcport->port_name[4],
+ fcport->port_name[5], fcport->port_name[6],
+ fcport->port_name[7]));
+ }
+}
+
/*
* qla2x00_update_fcport
* Updates device on list.
@@ -2135,10 +2129,11 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
+ qla2x00_iidma_fcport(ha, fcport);
+
atomic_set(&fcport->state, FCS_ONLINE);
- if (ha->flags.init_done)
- qla2x00_reg_remote_port(ha, fcport);
+ qla2x00_reg_remote_port(ha, fcport);
}
void
@@ -2209,7 +2204,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
- rval = qla2x00_get_port_name(ha, loop_id, NULL, 0);
+ rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
if (rval != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
"Port\n", ha->host_no));
@@ -2217,6 +2212,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
ha->device_flags &= ~SWITCH_FOUND;
return (QLA_SUCCESS);
}
+ ha->device_flags |= SWITCH_FOUND;
/* Mark devices that need re-synchronization. */
rval2 = qla2x00_device_resync(ha);
@@ -2416,6 +2412,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
kfree(swl);
swl = NULL;
+ } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+ qla2x00_gpsc(ha, swl);
}
}
swl_idx = 0;
@@ -2450,6 +2448,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
swl[swl_idx].node_name, WWN_SIZE);
memcpy(new_fcport->port_name,
swl[swl_idx].port_name, WWN_SIZE);
+ memcpy(new_fcport->fabric_port_name,
+ swl[swl_idx].fabric_port_name, WWN_SIZE);
+ new_fcport->fp_speed = swl[swl_idx].fp_speed;
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
@@ -2507,6 +2508,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
found++;
+ /* Update port state. */
+ memcpy(fcport->fabric_port_name,
+ new_fcport->fabric_port_name, WWN_SIZE);
+ fcport->fp_speed = new_fcport->fp_speed;
+
/*
* If address the same and state FCS_ONLINE, nothing
* changed.
@@ -3866,3 +3872,24 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
fail_fw_integrity:
return QLA_FUNCTION_FAILED;
}
+
+void
+qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
+{
+ int ret, retries;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return;
+
+ ret = qla2x00_stop_firmware(ha);
+ for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
+ qla2x00_reset_chip(ha);
+ if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
+ continue;
+ if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
+ continue;
+ qla_printk(KERN_INFO, ha,
+ "Attempting retry of stop-firmware command...\n");
+ ret = qla2x00_stop_firmware(ha);
+ }
+}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 45007ee5806..d3023338628 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi_qla_host_t *);
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
- ha->isp_ops.intr_handler(0, ha, NULL);
+ ha->isp_ops.intr_handler(0, ha);
}
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index de0613135f7..d3b6df4d55c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -6,6 +6,8 @@
*/
#include "qla_def.h"
+#include <scsi/scsi_tcq.h>
+
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
@@ -20,14 +22,13 @@ static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *);
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla2100_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_2xxx __iomem *reg;
@@ -100,14 +101,13 @@ qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
* qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla2300_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_2xxx __iomem *reg;
@@ -400,7 +400,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
case MBA_LOOP_UP: /* Loop Up Event */
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
link_speed = link_speeds[0];
- ha->link_data_rate = LDR_1GB;
+ ha->link_data_rate = PORT_SPEED_1GB;
} else {
link_speed = link_speeds[LS_UNKNOWN];
if (mb[1] < 5)
@@ -429,7 +429,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
}
ha->flags.management_server_logged_in = 0;
- ha->link_data_rate = LDR_UNKNOWN;
+ ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
break;
@@ -595,6 +595,67 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
}
}
+static void
+qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
+{
+ fc_port_t *fcport = data;
+
+ if (fcport->ha->max_q_depth <= sdev->queue_depth)
+ return;
+
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ sdev->queue_depth + 1);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+ sdev->queue_depth + 1);
+
+ fcport->last_ramp_up = jiffies;
+
+ DEBUG2(qla_printk(KERN_INFO, fcport->ha,
+ "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
+ fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
+ sdev->queue_depth));
+}
+
+static void
+qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
+{
+ fc_port_t *fcport = data;
+
+ if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
+ return;
+
+ DEBUG2(qla_printk(KERN_INFO, fcport->ha,
+ "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
+ fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
+ sdev->queue_depth));
+}
+
+static inline void
+qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
+{
+ fc_port_t *fcport;
+ struct scsi_device *sdev;
+
+ sdev = sp->cmd->device;
+ if (sdev->queue_depth >= ha->max_q_depth)
+ return;
+
+ fcport = sp->fcport;
+ if (time_before(jiffies,
+ fcport->last_ramp_up + ql2xqfullrampup * HZ))
+ return;
+ if (time_before(jiffies,
+ fcport->last_queue_full + ql2xqfullrampup * HZ))
+ return;
+
+ spin_unlock_irq(&ha->hardware_lock);
+ starget_for_each_device(sdev->sdev_target, fcport,
+ qla2x00_adjust_sdev_qdepth_up);
+ spin_lock_irq(&ha->hardware_lock);
+}
+
/**
* qla2x00_process_completed_request() - Process a Fast Post response.
* @ha: SCSI driver HA context
@@ -626,6 +687,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
/* Save ISP completion status */
sp->cmd->result = DID_OK << 16;
+
+ qla2x00_ramp_up_queue_depth(ha, sp);
qla2x00_sp_compl(ha, sp);
} else {
DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
@@ -825,6 +888,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
*/
switch (comp_status) {
case CS_COMPLETE:
+ case CS_QUEUE_FULL:
if (scsi_status == 0) {
cp->result = DID_OK << 16;
break;
@@ -851,6 +915,20 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
}
cp->result = DID_OK << 16 | lscsi_status;
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ DEBUG2(printk(KERN_INFO
+ "scsi(%ld): QUEUE FULL status detected "
+ "0x%x-0x%x.\n", ha->host_no, comp_status,
+ scsi_status));
+
+ /* Adjust queue depth for all luns on the port. */
+ fcport->last_queue_full = jiffies;
+ spin_unlock_irq(&ha->hardware_lock);
+ starget_for_each_device(cp->device->sdev_target,
+ fcport, qla2x00_adjust_sdev_qdepth_down);
+ spin_lock_irq(&ha->hardware_lock);
+ break;
+ }
if (lscsi_status != SS_CHECK_CONDITION)
break;
@@ -1068,17 +1146,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
qla2x00_mark_device_lost(ha, fcport, 1, 1);
break;
- case CS_QUEUE_FULL:
- DEBUG2(printk(KERN_INFO
- "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n",
- ha->host_no, comp_status, scsi_status));
-
- /* SCSI Mid-Layer handles device queue full */
-
- cp->result = DID_OK << 16 | lscsi_status;
-
- break;
-
default:
DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
"0x%x-0x%x.\n", ha->host_no, comp_status, scsi_status));
@@ -1338,14 +1405,13 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla24xx_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_24xx __iomem *reg;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 879f281e2ea..4cde76c85cb 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2540,3 +2540,89 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
return rval;
}
+
+int
+qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+ uint16_t *port_speed, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_PORT_PARAMS;
+ mcp->mb[1] = loop_id;
+ mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
+ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ /* Return mailbox statuses. */
+ if (mb != NULL) {
+ mb[0] = mcp->mb[0];
+ mb[1] = mcp->mb[1];
+ mb[3] = mcp->mb[3];
+ mb[4] = mcp->mb[4];
+ mb[5] = mcp->mb[5];
+ }
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ ha->host_no, rval));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ if (port_speed)
+ *port_speed = mcp->mb[3];
+ }
+
+ return rval;
+}
+
+int
+qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+ uint16_t port_speed, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_PORT_PARAMS;
+ mcp->mb[1] = loop_id;
+ mcp->mb[2] = BIT_0;
+ mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+ mcp->mb[4] = mcp->mb[5] = 0;
+ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ /* Return mailbox statuses. */
+ if (mb != NULL) {
+ mb[0] = mcp->mb[0];
+ mb[1] = mcp->mb[1];
+ mb[3] = mcp->mb[3];
+ mb[4] = mcp->mb[4];
+ mb[5] = mcp->mb[5];
+ }
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ ha->host_no, rval));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 65cbe2f5eea..d03523d3bf3 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -24,7 +24,7 @@ char qla2x00_version_str[40];
/*
* SRB allocation cache
*/
-static kmem_cache_t *srb_cachep;
+static struct kmem_cache *srb_cachep;
/*
* Ioctl related information.
@@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump,
"during HBA initialization. Memory allocation requirements "
"vary by ISP type. Default is 1 - allocate memory.");
-int extended_error_logging;
-module_param(extended_error_logging, int, S_IRUGO|S_IRUSR);
-MODULE_PARM_DESC(extended_error_logging,
+int ql2xextended_error_logging;
+module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging. 1 - log errors.");
@@ -77,11 +77,26 @@ MODULE_PARM_DESC(ql2xfdmienable,
"Enables FDMI registratons "
"Default is 0 - no FDMI. 1 - perfom FDMI.");
+#define MAX_Q_DEPTH 32
+static int ql2xmaxqdepth = MAX_Q_DEPTH;
+module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xmaxqdepth,
+ "Maximum queue depth to report for target devices.");
+
+int ql2xqfullrampup = 120;
+module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xqfullrampup,
+ "Number of seconds to wait to begin to ramp-up the queue "
+ "depth for a device after a queue-full condition has been "
+ "detected. Default is 120 seconds.");
+
/*
* SCSI host template entry points
*/
static int qla2xxx_slave_configure(struct scsi_device * device);
static int qla2xxx_slave_alloc(struct scsi_device *);
+static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
+static void qla2xxx_scan_start(struct Scsi_Host *);
static void qla2xxx_slave_destroy(struct scsi_device *);
static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
void (*fn)(struct scsi_cmnd *));
@@ -111,6 +126,8 @@ static struct scsi_host_template qla2x00_driver_template = {
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
@@ -274,7 +291,7 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
return str;
}
-char *
+static char *
qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
{
char un_str[10];
@@ -312,7 +329,7 @@ qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
return (str);
}
-char *
+static char *
qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
{
sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
@@ -589,6 +606,23 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
return (return_status);
}
+static void
+qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ msleep(1000);
+ spin_lock_irqsave(shost->host_lock, flags);
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return;
+}
+
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -604,7 +638,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
* Note:
* Only return FAILED if command not returned by firmware.
**************************************************************************/
-int
+static int
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -615,6 +649,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned long flags;
int wait = 0;
+ qla2x00_block_error_handler(cmd);
+
if (!CMD_SP(cmd))
return SUCCESS;
@@ -739,7 +775,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
* SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
-int
+static int
qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -748,6 +784,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -868,7 +906,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
* SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
-int
+static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -877,6 +915,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -927,7 +967,7 @@ eh_bus_reset_done:
*
* Note:
**************************************************************************/
-int
+static int
qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -936,6 +976,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -1079,9 +1121,9 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, 32);
+ scsi_activate_tcq(sdev, ha->max_q_depth);
else
- scsi_deactivate_tcq(sdev, 32);
+ scsi_deactivate_tcq(sdev, ha->max_q_depth);
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
@@ -1328,6 +1370,29 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+static void
+qla2xxx_scan_start(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ set_bit(RSCN_UPDATE, &ha->dpc_flags);
+}
+
+static int
+qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+ if (!ha->host)
+ return 1;
+ if (time > ha->loop_reset_delay * HZ)
+ return 1;
+
+ return atomic_read(&ha->loop_state) == LOOP_READY;
+}
+
/*
* PCI driver interface
*/
@@ -1339,10 +1404,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
struct Scsi_Host *host;
scsi_qla_host_t *ha;
unsigned long flags = 0;
- unsigned long wait_switch = 0;
char pci_info[20];
char fw_str[30];
- fc_port_t *fcport;
struct scsi_host_template *sht;
if (pci_enable_device(pdev))
@@ -1385,9 +1448,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
- ha->link_data_rate = LDR_UNKNOWN;
+ ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
+ ha->max_q_depth = MAX_Q_DEPTH;
+ if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
+ ha->max_q_depth = ql2xmaxqdepth;
+
/* Assign ISP specific operations. */
ha->isp_ops.pci_config = qla2100_pci_config;
ha->isp_ops.reset_chip = qla2x00_reset_chip;
@@ -1589,30 +1656,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->isp_ops.enable_intrs(ha);
- /* v2.19.5b6 */
- /*
- * Wait around max loop_reset_delay secs for the devices to come
- * on-line. We don't want Linux scanning before we are ready.
- *
- */
- for (wait_switch = jiffies + (ha->loop_reset_delay * HZ);
- time_before(jiffies,wait_switch) &&
- !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
- && (ha->device_flags & SWITCH_FOUND) ;) {
-
- qla2x00_check_fabric_devices(ha);
-
- msleep(10);
- }
-
pci_set_drvdata(pdev, ha);
+
ha->flags.init_done = 1;
+ ha->flags.online = 1;
+
num_hosts++;
ret = scsi_add_host(host, &pdev->dev);
if (ret)
goto probe_failed;
+ scsi_scan_host(host);
+
qla2x00_alloc_sysfs_attr(ha);
qla2x00_init_host_attr(ha);
@@ -1627,10 +1683,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
ha->isp_ops.fw_version_str(ha, fw_str));
- /* Go with fc_rport registration. */
- list_for_each_entry(fcport, &ha->fcports, list)
- qla2x00_reg_remote_port(ha, fcport);
-
return 0;
probe_failed:
@@ -1687,8 +1739,10 @@ qla2x00_free_device(scsi_qla_host_t *ha)
if (ha->eft)
qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+ ha->flags.online = 0;
+
/* Stop currently executing firmware. */
- qla2x00_stop_firmware(ha);
+ qla2x00_try_to_stop_firmware(ha);
/* turn-off interrupts on the card */
if (ha->interrupts_on)
@@ -1696,8 +1750,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
qla2x00_mem_free(ha);
- ha->flags.online = 0;
-
/* Detach interrupts */
if (ha->host->irq)
free_irq(ha->host->irq, ha);
@@ -2564,14 +2616,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
#define FW_ISP2322 3
#define FW_ISP24XX 4
+#define FW_FILE_ISP21XX "ql2100_fw.bin"
+#define FW_FILE_ISP22XX "ql2200_fw.bin"
+#define FW_FILE_ISP2300 "ql2300_fw.bin"
+#define FW_FILE_ISP2322 "ql2322_fw.bin"
+#define FW_FILE_ISP24XX "ql2400_fw.bin"
+
static DECLARE_MUTEX(qla_fw_lock);
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
- { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
- { .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
- { .name = "ql2400_fw.bin", },
+ { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
+ { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
+ { .name = FW_FILE_ISP24XX, },
};
struct fw_blob *
@@ -2666,7 +2724,7 @@ qla2x00_module_init(void)
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
- if (extended_error_logging)
+ if (ql2xextended_error_logging)
strcat(qla2x00_version_str, "-debug");
qla2xxx_transport_template =
@@ -2702,3 +2760,8 @@ MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+MODULE_FIRMWARE(FW_FILE_ISP21XX);
+MODULE_FIRMWARE(FW_FILE_ISP22XX);
+MODULE_FIRMWARE(FW_FILE_ISP2300);
+MODULE_FIRMWARE(FW_FILE_ISP2322);
+MODULE_FIRMWARE(FW_FILE_ISP24XX);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index c71dbd5bd54..15390ad8745 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -449,7 +449,7 @@ nvram_data_to_access_addr(uint32_t naddr)
return FARX_ACCESS_NVRAM_DATA | naddr;
}
-uint32_t
+static uint32_t
qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr)
{
int rval;
@@ -490,7 +490,7 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
return dwptr;
}
-int
+static int
qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
{
int rval;
@@ -512,7 +512,7 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
return rval;
}
-void
+static void
qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
uint8_t *flash_id)
{
@@ -537,7 +537,7 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
}
}
-int
+static int
qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 971259032ef..1fa0bce6b24 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k1"
+#define QLA2XXX_VERSION "8.01.07-k3"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
new file mode 100644
index 00000000000..69cbff3f57c
--- /dev/null
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -0,0 +1,7 @@
+config SCSI_QLA_ISCSI
+ tristate "QLogic ISP4XXX host adapter family support"
+ depends on PCI && SCSI && NET
+ select SCSI_ISCSI_ATTRS
+ ---help---
+ This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
+ adapter family.
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
new file mode 100644
index 00000000000..86ea37baa0f
--- /dev/null
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -0,0 +1,5 @@
+qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
+ ql4_nvram.o ql4_dbg.o
+
+obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
+
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
new file mode 100644
index 00000000000..7b4e077a39c
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -0,0 +1,197 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+#include <scsi/scsi_dbg.h>
+
+static void qla4xxx_print_srb_info(struct srb * srb)
+{
+ printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
+ printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
+ __func__, srb->cmd, (unsigned long) srb->dma_handle);
+ printk("%s: fw_ddb_index = %d, lun = %d\n",
+ __func__, srb->fw_ddb_index, srb->cmd->device->lun);
+ printk("%s: iocb_tov = %d\n",
+ __func__, srb->iocb_tov);
+ printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
+ __func__, srb->cc_stat, srb->r_start, srb->u_start);
+}
+
+void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
+{
+ printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
+ printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
+ cmd->device->channel, cmd->device->id, cmd->device->lun,
+ cmd->cmd_len);
+ scsi_print_command(cmd);
+ printk(" seg_cnt = %d\n", cmd->use_sg);
+ printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
+ cmd->request_buffer, cmd->request_bufflen);
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+ sg = (struct scatterlist *)cmd->request_buffer;
+ printk(" SG buffer: \n");
+ qla4xxx_dump_buffer((caddr_t) sg,
+ (cmd->use_sg * sizeof(*sg)));
+ }
+ printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
+ cmd->transfersize);
+ printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
+ printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
+ cmd->sc_data_direction);
+ printk(" Current time (jiffies) = 0x%lx, "
+ "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
+ qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
+}
+
+void __dump_registers(struct scsi_qla_host *ha)
+{
+ uint8_t i;
+ for (i = 0; i < MBOX_REG_COUNT; i++) {
+ printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
+ readw(&ha->reg->mailbox[i]));
+ }
+ printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_address),
+ readw(&ha->reg->flash_address));
+ printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_data),
+ readw(&ha->reg->flash_data));
+ printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, ctrl_status),
+ readw(&ha->reg->ctrl_status));
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
+ readw(&ha->reg->u1.isp4010.nvram));
+ }
+
+ else if (is_qla4022(ha) | is_qla4032(ha)) {
+ printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u1.isp4022.intr_mask),
+ readw(&ha->reg->u1.isp4022.intr_mask));
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
+ readw(&ha->reg->u1.isp4022.nvram));
+ printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u1.isp4022.semaphore),
+ readw(&ha->reg->u1.isp4022.semaphore));
+ }
+ printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, req_q_in),
+ readw(&ha->reg->req_q_in));
+ printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, rsp_q_out),
+ readw(&ha->reg->rsp_q_out));
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.ext_hw_conf),
+ readw(&ha->reg->u2.isp4010.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_ctrl),
+ readw(&ha->reg->u2.isp4010.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_status),
+ readw(&ha->reg->u2.isp4010.port_status));
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.req_q_out),
+ readw(&ha->reg->u2.isp4010.req_q_out));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
+ readw(&ha->reg->u2.isp4010.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
+ readw(&ha->reg->u2.isp4010.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_err_status),
+ readw(&ha->reg->u2.isp4010.port_err_status));
+ }
+
+ else if (is_qla4022(ha) | is_qla4032(ha)) {
+ printk(KERN_INFO "Page 0 Registers:\n");
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.ext_hw_conf),
+ readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_ctrl),
+ readw(&ha->reg->u2.isp4022.p0.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_status),
+ readw(&ha->reg->u2.isp4022.p0.port_status));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.gp_out),
+ readw(&ha->reg->u2.isp4022.p0.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
+ readw(&ha->reg->u2.isp4022.p0.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_err_status),
+ readw(&ha->reg->u2.isp4022.p0.port_err_status));
+ printk(KERN_INFO "Page 1 Registers:\n");
+ writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p1.req_q_out),
+ readw(&ha->reg->u2.isp4022.p1.req_q_out));
+ writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ }
+}
+
+void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ int i = 0;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 1; i < MBOX_REG_COUNT; i++)
+ printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
+ readw(&ha->reg->mailbox[i]));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void qla4xxx_dump_registers(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __dump_registers(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void qla4xxx_dump_buffer(void *b, uint32_t size)
+{
+ uint32_t cnt;
+ uint8_t *c = b;
+
+ printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
+ "Fh\n");
+ printk("------------------------------------------------------------"
+ "--\n");
+ for (cnt = 0; cnt < size; cnt++, c++) {
+ printk(KERN_DEBUG "%02x", *c);
+ if (!(cnt % 16))
+ printk(KERN_DEBUG "\n");
+
+ else
+ printk(KERN_DEBUG " ");
+ }
+ if (cnt % 16)
+ printk(KERN_DEBUG "\n");
+}
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
new file mode 100644
index 00000000000..d861c3b411c
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_dbg.h
@@ -0,0 +1,55 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+/*
+ * Driver debug definitions.
+ */
+/* #define QL_DEBUG */ /* DEBUG messages */
+/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
+/* #define QL_DEBUG_LEVEL_4 */
+/* #define QL_DEBUG_LEVEL_5 */
+/* #define QL_DEBUG_LEVEL_9 */
+
+#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
+#if defined(QL_DEBUG)
+#define DEBUG(x) do {x;} while (0);
+#else
+#define DEBUG(x) do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0);
+#define DEBUG2_3(x) do {x;} while (0);
+#else /* */
+#define DEBUG2(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_3)
+#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0);
+#else /* */
+#define DEBUG3(x) do {} while (0);
+#if !defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2_3(x) do {} while (0);
+#endif /* */
+#endif /* */
+#if defined(QL_DEBUG_LEVEL_4)
+#define DEBUG4(x) do {x;} while (0);
+#else /* */
+#define DEBUG4(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_5)
+#define DEBUG5(x) do {x;} while (0);
+#else /* */
+#define DEBUG5(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_9)
+#define DEBUG9(x) do {x;} while (0);
+#else /* */
+#define DEBUG9(x) do {} while (0);
+#endif /* */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
new file mode 100644
index 00000000000..4249e52a559
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -0,0 +1,595 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef __QL4_DEF_H
+#define __QL4_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
+#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022
+#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4032
+#define PCI_DEVICE_ID_QLOGIC_ISP4032 0x4032
+#endif
+
+#define QLA_SUCCESS 0
+#define QLA_ERROR 1
+
+/*
+ * Data bit definitions
+ */
+#define BIT_0 0x1
+#define BIT_1 0x2
+#define BIT_2 0x4
+#define BIT_3 0x8
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x100
+#define BIT_9 0x200
+#define BIT_10 0x400
+#define BIT_11 0x800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x10000
+#define BIT_17 0x20000
+#define BIT_18 0x40000
+#define BIT_19 0x80000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x1000000
+#define BIT_25 0x2000000
+#define BIT_26 0x4000000
+#define BIT_27 0x8000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+/*
+ * Host adapter default definitions
+ ***********************************/
+#define MAX_HBAS 16
+#define MAX_BUSES 1
+#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_LUNS 0xffff
+#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
+#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_PDU_ENTRIES 32
+#define INVALID_ENTRY 0xFFFF
+#define MAX_CMDS_TO_RISC 1024
+#define MAX_SRBS MAX_CMDS_TO_RISC
+#define MBOX_AEN_REG_COUNT 5
+#define MAX_INIT_RETRIES 5
+#define IOCB_HIWAT_CUSHION 16
+
+/*
+ * Buffer sizes
+ */
+#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC
+#define RESPONSE_QUEUE_DEPTH 64
+#define QUEUE_SIZE 64
+#define DMA_BUFFER_SIZE 512
+
+/*
+ * Misc
+ */
+#define MAC_ADDR_LEN 6 /* in bytes */
+#define IP_ADDR_LEN 4 /* in bytes */
+#define DRIVER_NAME "qla4xxx"
+
+#define MAX_LINKED_CMDS_PER_LUN 3
+#define MAX_REQS_SERVICED_PER_INTR 16
+
+#define ISCSI_IPADDR_SIZE 4 /* IP address size */
+#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
+#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
+ * usually a string */
+
+#define LSDW(x) ((u32)((u64)(x)))
+#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
+
+/*
+ * Retry & Timeout Values
+ */
+#define MBOX_TOV 60
+#define SOFT_RESET_TOV 30
+#define RESET_INTR_TOV 3
+#define SEMAPHORE_TOV 10
+#define ADAPTER_INIT_TOV 120
+#define ADAPTER_RESET_TOV 180
+#define EXTEND_CMD_TOV 60
+#define WAIT_CMD_TOV 30
+#define EH_WAIT_CMD_TOV 120
+#define FIRMWARE_UP_TOV 60
+#define RESET_FIRMWARE_TOV 30
+#define LOGOUT_TOV 10
+#define IOCB_TOV_MARGIN 10
+#define RELOGIN_TOV 18
+#define ISNS_DEREG_TOV 5
+
+#define MAX_RESET_HA_RETRIES 2
+
+/*
+ * SCSI Request Block structure (srb) that is placed
+ * on cmd->SCp location of every I/O [We have 22 bytes available]
+ */
+struct srb {
+ struct list_head list; /* (8) */
+ struct scsi_qla_host *ha; /* HA the SP is queued on */
+ struct ddb_entry *ddb;
+ uint16_t flags; /* (1) Status flags. */
+
+#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
+#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */
+ uint8_t state; /* (1) Status flags. */
+
+#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */
+#define SRB_FREE_STATE 1
+#define SRB_ACTIVE_STATE 3
+#define SRB_ACTIVE_TIMEOUT_STATE 4
+#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */
+
+ struct scsi_cmnd *cmd; /* (4) SCSI command block */
+ dma_addr_t dma_handle; /* (4) for unmap of single transfers */
+ atomic_t ref_count; /* reference count for this srb */
+ uint32_t fw_ddb_index;
+ uint8_t err_id; /* error id */
+#define SRB_ERR_PORT 1 /* Request failed because "port down" */
+#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
+#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */
+#define SRB_ERR_OTHER 4
+
+ uint16_t reserved;
+ uint16_t iocb_tov;
+ uint16_t iocb_cnt; /* Number of used iocbs */
+ uint16_t cc_stat;
+ u_long r_start; /* Time we recieve a cmd from OS */
+ u_long u_start; /* Time when we handed the cmd to F/W */
+};
+
+ /*
+ * Device Database (DDB) structure
+ */
+struct ddb_entry {
+ struct list_head list; /* ddb list */
+ struct scsi_qla_host *ha;
+ struct iscsi_cls_session *sess;
+ struct iscsi_cls_conn *conn;
+
+ atomic_t state; /* DDB State */
+
+ unsigned long flags; /* DDB Flags */
+
+ unsigned long dev_scan_wait_to_start_relogin;
+ unsigned long dev_scan_wait_to_complete_relogin;
+
+ uint16_t os_target_id; /* Target ID */
+ uint16_t fw_ddb_index; /* DDB firmware index */
+ uint8_t reserved[2];
+ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */
+
+ uint32_t CmdSn;
+ uint16_t target_session_id;
+ uint16_t connection_id;
+ uint16_t exe_throttle; /* Max mumber of cmds outstanding
+ * simultaneously */
+ uint16_t task_mgmt_timeout; /* Min time for task mgmt cmds to
+ * complete */
+ uint16_t default_relogin_timeout; /* Max time to wait for
+ * relogin to complete */
+ uint16_t tcp_source_port_num;
+ uint32_t default_time2wait; /* Default Min time between
+ * relogins (+aens) */
+
+ atomic_t port_down_timer; /* Device connection timer */
+ atomic_t retry_relogin_timer; /* Min Time between relogins
+ * (4000 only) */
+ atomic_t relogin_timer; /* Max Time to wait for relogin to complete */
+ atomic_t relogin_retry_count; /* Num of times relogin has been
+ * retried */
+
+ uint16_t port;
+ uint32_t tpgt;
+ uint8_t ip_addr[ISCSI_IPADDR_SIZE];
+ uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */
+ uint8_t iscsi_alias[0x20];
+};
+
+/*
+ * DDB states.
+ */
+#define DDB_STATE_DEAD 0 /* We can no longer talk to
+ * this device */
+#define DDB_STATE_ONLINE 1 /* Device ready to accept
+ * commands */
+#define DDB_STATE_MISSING 2 /* Device logged off, trying
+ * to re-login */
+
+/*
+ * DDB flags.
+ */
+#define DF_RELOGIN 0 /* Relogin to device */
+#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL
+ * logged it out */
+#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
+#define DF_FO_MASKED 3
+
+/*
+ * Asynchronous Event Queue structure
+ */
+struct aen {
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+};
+
+
+#include "ql4_fw.h"
+#include "ql4_nvram.h"
+
+/*
+ * Linux Host Adapter structure
+ */
+struct scsi_qla_host {
+ /* Linux adapter configuration data */
+ struct Scsi_Host *host; /* pointer to host data */
+ uint32_t tot_ddbs;
+ unsigned long flags;
+
+#define AF_ONLINE 0 /* 0x00000001 */
+#define AF_INIT_DONE 1 /* 0x00000002 */
+#define AF_MBOX_COMMAND 2 /* 0x00000004 */
+#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
+#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
+#define AF_LINK_UP 8 /* 0x00000100 */
+#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
+#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
+#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
+
+ unsigned long dpc_flags;
+
+#define DPC_RESET_HA 1 /* 0x00000002 */
+#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
+#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
+#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
+#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
+#define DPC_ISNS_RESTART 7 /* 0x00000080 */
+#define DPC_AEN 9 /* 0x00000200 */
+#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+
+ uint16_t iocb_cnt;
+ uint16_t iocb_hiwat;
+
+ /* SRB cache. */
+#define SRB_MIN_REQ 128
+ mempool_t *srb_mempool;
+
+ /* pci information */
+ struct pci_dev *pdev;
+
+ struct isp_reg __iomem *reg; /* Base I/O address */
+ unsigned long pio_address;
+ unsigned long pio_length;
+#define MIN_IOBASE_LEN 0x100
+
+ uint16_t req_q_count;
+ uint8_t marker_needed;
+ uint8_t rsvd1;
+
+ unsigned long host_no;
+
+ /* NVRAM registers */
+ struct eeprom_data *nvram;
+ spinlock_t hardware_lock ____cacheline_aligned;
+ uint32_t eeprom_cmd_data;
+
+ /* Counters for general statistics */
+ uint64_t isr_count;
+ uint64_t adapter_error_count;
+ uint64_t device_error_count;
+ uint64_t total_io_count;
+ uint64_t total_mbytes_xferred;
+ uint64_t link_failure_count;
+ uint64_t invalid_crc_count;
+ uint32_t bytes_xfered;
+ uint32_t spurious_int_count;
+ uint32_t aborted_io_count;
+ uint32_t io_timeout_count;
+ uint32_t mailbox_timeout_count;
+ uint32_t seconds_since_last_intr;
+ uint32_t seconds_since_last_heartbeat;
+ uint32_t mac_index;
+
+ /* Info Needed for Management App */
+ /* --- From GetFwVersion --- */
+ uint32_t firmware_version[2];
+ uint32_t patch_number;
+ uint32_t build_number;
+
+ /* --- From Init_FW --- */
+ /* init_cb_t *init_cb; */
+ uint16_t firmware_options;
+ uint16_t tcp_options;
+ uint8_t ip_address[IP_ADDR_LEN];
+ uint8_t subnet_mask[IP_ADDR_LEN];
+ uint8_t gateway[IP_ADDR_LEN];
+ uint8_t alias[32];
+ uint8_t name_string[256];
+ uint8_t heartbeat_interval;
+ uint8_t rsvd;
+
+ /* --- From FlashSysInfo --- */
+ uint8_t my_mac[MAC_ADDR_LEN];
+ uint8_t serial_number[16];
+
+ /* --- From GetFwState --- */
+ uint32_t firmware_state;
+ uint32_t board_id;
+ uint32_t addl_fw_state;
+
+ /* Linux kernel thread */
+ struct workqueue_struct *dpc_thread;
+ struct work_struct dpc_work;
+
+ /* Linux timer thread */
+ struct timer_list timer;
+ uint32_t timer_active;
+
+ /* Recovery Timers */
+ uint32_t port_down_retry_count;
+ uint32_t discovery_wait;
+ atomic_t check_relogin_timeouts;
+ uint32_t retry_reset_ha_cnt;
+ uint32_t isp_reset_timer; /* reset test timer */
+ uint32_t nic_reset_timer; /* simulated nic reset test timer */
+ int eh_start;
+ struct list_head free_srb_q;
+ uint16_t free_srb_q_count;
+ uint16_t num_srbs_allocated;
+
+ /* DMA Memory Block */
+ void *queues;
+ dma_addr_t queues_dma;
+ unsigned long queues_len;
+
+#define MEM_ALIGN_VALUE \
+ ((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \
+ sizeof(struct queue_entry))
+ /* request and response queue variables */
+ dma_addr_t request_dma;
+ struct queue_entry *request_ring;
+ struct queue_entry *request_ptr;
+ dma_addr_t response_dma;
+ struct queue_entry *response_ring;
+ struct queue_entry *response_ptr;
+ dma_addr_t shadow_regs_dma;
+ struct shadow_regs *shadow_regs;
+ uint16_t request_in; /* Current indexes. */
+ uint16_t request_out;
+ uint16_t response_in;
+ uint16_t response_out;
+
+ /* aen queue variables */
+ uint16_t aen_q_count; /* Number of available aen_q entries */
+ uint16_t aen_in; /* Current indexes */
+ uint16_t aen_out;
+ struct aen aen_q[MAX_AEN_ENTRIES];
+
+ /* This mutex protects several threads to do mailbox commands
+ * concurrently.
+ */
+ struct mutex mbox_sem;
+ wait_queue_head_t mailbox_wait_queue;
+
+ /* temporary mailbox status registers */
+ volatile uint8_t mbox_status_count;
+ volatile uint32_t mbox_status[MBOX_REG_COUNT];
+
+ /* local device database list (contains internal ddb entries) */
+ struct list_head ddb_list;
+
+ /* Map ddb_list entry by FW ddb index */
+ struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
+
+};
+
+static inline int is_qla4010(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
+}
+
+static inline int is_qla4022(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022;
+}
+
+static inline int is_qla4032(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032;
+}
+
+static inline int adapter_up(struct scsi_qla_host *ha)
+{
+ return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
+ (test_bit(AF_LINK_UP, &ha->flags) != 0);
+}
+
+static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
+{
+ return (struct scsi_qla_host *)shost->hostdata;
+}
+
+static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u1.isp4010.nvram :
+ &ha->reg->u1.isp4022.semaphore);
+}
+
+static inline void __iomem* isp_nvram(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u1.isp4010.nvram :
+ &ha->reg->u1.isp4022.nvram);
+}
+
+static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u2.isp4010.ext_hw_conf :
+ &ha->reg->u2.isp4022.p0.ext_hw_conf);
+}
+
+static inline void __iomem* isp_port_status(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u2.isp4010.port_status :
+ &ha->reg->u2.isp4022.p0.port_status);
+}
+
+static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u2.isp4010.port_ctrl :
+ &ha->reg->u2.isp4022.p0.port_ctrl);
+}
+
+static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u2.isp4010.port_err_status :
+ &ha->reg->u2.isp4022.p0.port_err_status);
+}
+
+static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ &ha->reg->u2.isp4010.gp_out :
+ &ha->reg->u2.isp4022.p0.gp_out);
+}
+
+static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
+{
+ return (is_qla4010(ha) ?
+ offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2 :
+ offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2);
+}
+
+int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
+void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask);
+int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
+
+static inline int ql4xxx_lock_flash(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
+ QL4010_FLASH_SEM_BITS);
+ else
+ return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 13);
+}
+
+static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
+}
+
+static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
+ QL4010_NVRAM_SEM_BITS);
+ else
+ return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 10);
+}
+
+static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
+}
+
+static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
+ QL4010_DRVR_SEM_BITS);
+ else
+ return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 1);
+}
+
+static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
+{
+ if (is_qla4010(a))
+ ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */
+#define PRESERVE_DDB_LIST 0
+#define REBUILD_DDB_LIST 1
+
+/* Defines for process_aen() */
+#define PROCESS_ALL_AENS 0
+#define FLUSH_DDB_CHANGED_AENS 1
+#define RELOGIN_DDB_CHANGED_AENS 2
+
+#include "ql4_version.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
+
+
+#endif /*_QLA4XXX_H */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
new file mode 100644
index 00000000000..4eea8c57191
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -0,0 +1,848 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef _QLA4X_FW_H
+#define _QLA4X_FW_H
+
+
+#define MAX_PRST_DEV_DB_ENTRIES 64
+#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES
+#define MAX_DEV_DB_ENTRIES 512
+
+/*************************************************************************
+ *
+ * ISP 4010 I/O Register Set Structure and Definitions
+ *
+ *************************************************************************/
+
+struct port_ctrl_stat_regs {
+ __le32 ext_hw_conf; /* 80 x50 R/W */
+ __le32 intChipConfiguration; /* 84 x54 */
+ __le32 port_ctrl; /* 88 x58 */
+ __le32 port_status; /* 92 x5c */
+ __le32 HostPrimMACHi; /* 96 x60 */
+ __le32 HostPrimMACLow; /* 100 x64 */
+ __le32 HostSecMACHi; /* 104 x68 */
+ __le32 HostSecMACLow; /* 108 x6c */
+ __le32 EPPrimMACHi; /* 112 x70 */
+ __le32 EPPrimMACLow; /* 116 x74 */
+ __le32 EPSecMACHi; /* 120 x78 */
+ __le32 EPSecMACLow; /* 124 x7c */
+ __le32 HostPrimIPHi; /* 128 x80 */
+ __le32 HostPrimIPMidHi; /* 132 x84 */
+ __le32 HostPrimIPMidLow; /* 136 x88 */
+ __le32 HostPrimIPLow; /* 140 x8c */
+ __le32 HostSecIPHi; /* 144 x90 */
+ __le32 HostSecIPMidHi; /* 148 x94 */
+ __le32 HostSecIPMidLow; /* 152 x98 */
+ __le32 HostSecIPLow; /* 156 x9c */
+ __le32 EPPrimIPHi; /* 160 xa0 */
+ __le32 EPPrimIPMidHi; /* 164 xa4 */
+ __le32 EPPrimIPMidLow; /* 168 xa8 */
+ __le32 EPPrimIPLow; /* 172 xac */
+ __le32 EPSecIPHi; /* 176 xb0 */
+ __le32 EPSecIPMidHi; /* 180 xb4 */
+ __le32 EPSecIPMidLow; /* 184 xb8 */
+ __le32 EPSecIPLow; /* 188 xbc */
+ __le32 IPReassemblyTimeout; /* 192 xc0 */
+ __le32 EthMaxFramePayload; /* 196 xc4 */
+ __le32 TCPMaxWindowSize; /* 200 xc8 */
+ __le32 TCPCurrentTimestampHi; /* 204 xcc */
+ __le32 TCPCurrentTimestampLow; /* 208 xd0 */
+ __le32 LocalRAMAddress; /* 212 xd4 */
+ __le32 LocalRAMData; /* 216 xd8 */
+ __le32 PCSReserved1; /* 220 xdc */
+ __le32 gp_out; /* 224 xe0 */
+ __le32 gp_in; /* 228 xe4 */
+ __le32 ProbeMuxAddr; /* 232 xe8 */
+ __le32 ProbeMuxData; /* 236 xec */
+ __le32 ERMQueueBaseAddr0; /* 240 xf0 */
+ __le32 ERMQueueBaseAddr1; /* 244 xf4 */
+ __le32 MACConfiguration; /* 248 xf8 */
+ __le32 port_err_status; /* 252 xfc COR */
+};
+
+struct host_mem_cfg_regs {
+ __le32 NetRequestQueueOut; /* 80 x50 */
+ __le32 NetRequestQueueOutAddrHi; /* 84 x54 */
+ __le32 NetRequestQueueOutAddrLow; /* 88 x58 */
+ __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
+ __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
+ __le32 NetRequestQueueLength; /* 100 x64 */
+ __le32 NetResponseQueueIn; /* 104 x68 */
+ __le32 NetResponseQueueInAddrHi; /* 108 x6c */
+ __le32 NetResponseQueueInAddrLow; /* 112 x70 */
+ __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
+ __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
+ __le32 NetResponseQueueLength; /* 124 x7c */
+ __le32 req_q_out; /* 128 x80 */
+ __le32 RequestQueueOutAddrHi; /* 132 x84 */
+ __le32 RequestQueueOutAddrLow; /* 136 x88 */
+ __le32 RequestQueueBaseAddrHi; /* 140 x8c */
+ __le32 RequestQueueBaseAddrLow; /* 144 x90 */
+ __le32 RequestQueueLength; /* 148 x94 */
+ __le32 ResponseQueueIn; /* 152 x98 */
+ __le32 ResponseQueueInAddrHi; /* 156 x9c */
+ __le32 ResponseQueueInAddrLow; /* 160 xa0 */
+ __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
+ __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
+ __le32 ResponseQueueLength; /* 172 xac */
+ __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
+ __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
+ __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
+ __le32 NetRxLargeBufferQueueLength; /* 188 xbc */
+ __le32 NetRxLargeBufferLength; /* 192 xc0 */
+ __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
+ __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
+ __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
+ __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
+ __le32 NetRxSmallBufferLength; /* 212 xd4 */
+ __le32 HMCReserved0[10]; /* 216 xd8 */
+};
+
+struct local_ram_cfg_regs {
+ __le32 BufletSize; /* 80 x50 */
+ __le32 BufletMaxCount; /* 84 x54 */
+ __le32 BufletCurrCount; /* 88 x58 */
+ __le32 BufletPauseThresholdCount; /* 92 x5c */
+ __le32 BufletTCPWinThresholdHi; /* 96 x60 */
+ __le32 BufletTCPWinThresholdLow; /* 100 x64 */
+ __le32 IPHashTableBaseAddr; /* 104 x68 */
+ __le32 IPHashTableSize; /* 108 x6c */
+ __le32 TCPHashTableBaseAddr; /* 112 x70 */
+ __le32 TCPHashTableSize; /* 116 x74 */
+ __le32 NCBAreaBaseAddr; /* 120 x78 */
+ __le32 NCBMaxCount; /* 124 x7c */
+ __le32 NCBCurrCount; /* 128 x80 */
+ __le32 DRBAreaBaseAddr; /* 132 x84 */
+ __le32 DRBMaxCount; /* 136 x88 */
+ __le32 DRBCurrCount; /* 140 x8c */
+ __le32 LRCReserved[28]; /* 144 x90 */
+};
+
+struct prot_stat_regs {
+ __le32 MACTxFrameCount; /* 80 x50 R */
+ __le32 MACTxByteCount; /* 84 x54 R */
+ __le32 MACRxFrameCount; /* 88 x58 R */
+ __le32 MACRxByteCount; /* 92 x5c R */
+ __le32 MACCRCErrCount; /* 96 x60 R */
+ __le32 MACEncErrCount; /* 100 x64 R */
+ __le32 MACRxLengthErrCount; /* 104 x68 R */
+ __le32 IPTxPacketCount; /* 108 x6c R */
+ __le32 IPTxByteCount; /* 112 x70 R */
+ __le32 IPTxFragmentCount; /* 116 x74 R */
+ __le32 IPRxPacketCount; /* 120 x78 R */
+ __le32 IPRxByteCount; /* 124 x7c R */
+ __le32 IPRxFragmentCount; /* 128 x80 R */
+ __le32 IPDatagramReassemblyCount; /* 132 x84 R */
+ __le32 IPV6RxPacketCount; /* 136 x88 R */
+ __le32 IPErrPacketCount; /* 140 x8c R */
+ __le32 IPReassemblyErrCount; /* 144 x90 R */
+ __le32 TCPTxSegmentCount; /* 148 x94 R */
+ __le32 TCPTxByteCount; /* 152 x98 R */
+ __le32 TCPRxSegmentCount; /* 156 x9c R */
+ __le32 TCPRxByteCount; /* 160 xa0 R */
+ __le32 TCPTimerExpCount; /* 164 xa4 R */
+ __le32 TCPRxAckCount; /* 168 xa8 R */
+ __le32 TCPTxAckCount; /* 172 xac R */
+ __le32 TCPRxErrOOOCount; /* 176 xb0 R */
+ __le32 PSReserved0; /* 180 xb4 */
+ __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
+ __le32 ECCErrCorrectionCount; /* 188 xbc R */
+ __le32 PSReserved1[16]; /* 192 xc0 */
+};
+
+
+/* remote register set (access via PCI memory read/write) */
+struct isp_reg {
+#define MBOX_REG_COUNT 8
+ __le32 mailbox[MBOX_REG_COUNT];
+
+ __le32 flash_address; /* 0x20 */
+ __le32 flash_data;
+ __le32 ctrl_status;
+
+ union {
+ struct {
+ __le32 nvram;
+ __le32 reserved1[2]; /* 0x30 */
+ } __attribute__ ((packed)) isp4010;
+ struct {
+ __le32 intr_mask;
+ __le32 nvram; /* 0x30 */
+ __le32 semaphore;
+ } __attribute__ ((packed)) isp4022;
+ } u1;
+
+ __le32 req_q_in; /* SCSI Request Queue Producer Index */
+ __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */
+
+ __le32 reserved2[4]; /* 0x40 */
+
+ union {
+ struct {
+ __le32 ext_hw_conf; /* 0x50 */
+ __le32 flow_ctrl;
+ __le32 port_ctrl;
+ __le32 port_status;
+
+ __le32 reserved3[8]; /* 0x60 */
+
+ __le32 req_q_out; /* 0x80 */
+
+ __le32 reserved4[23]; /* 0x84 */
+
+ __le32 gp_out; /* 0xe0 */
+ __le32 gp_in;
+
+ __le32 reserved5[5];
+
+ __le32 port_err_status; /* 0xfc */
+ } __attribute__ ((packed)) isp4010;
+ struct {
+ union {
+ struct port_ctrl_stat_regs p0;
+ struct host_mem_cfg_regs p1;
+ struct local_ram_cfg_regs p2;
+ struct prot_stat_regs p3;
+ __le32 r_union[44];
+ };
+
+ } __attribute__ ((packed)) isp4022;
+ } u2;
+}; /* 256 x100 */
+
+
+/* Semaphore Defines for 4010 */
+#define QL4010_DRVR_SEM_BITS 0x00000030
+#define QL4010_GPIO_SEM_BITS 0x000000c0
+#define QL4010_SDRAM_SEM_BITS 0x00000300
+#define QL4010_PHY_SEM_BITS 0x00000c00
+#define QL4010_NVRAM_SEM_BITS 0x00003000
+#define QL4010_FLASH_SEM_BITS 0x0000c000
+
+#define QL4010_DRVR_SEM_MASK 0x00300000
+#define QL4010_GPIO_SEM_MASK 0x00c00000
+#define QL4010_SDRAM_SEM_MASK 0x03000000
+#define QL4010_PHY_SEM_MASK 0x0c000000
+#define QL4010_NVRAM_SEM_MASK 0x30000000
+#define QL4010_FLASH_SEM_MASK 0xc0000000
+
+/* Semaphore Defines for 4022 */
+#define QL4022_RESOURCE_MASK_BASE_CODE 0x7
+#define QL4022_RESOURCE_BITS_BASE_CODE 0x4
+
+
+#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16))
+#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16))
+#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16))
+#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16))
+#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16))
+
+
+
+/* Page # defines for 4022 */
+#define PORT_CTRL_STAT_PAGE 0 /* 4022 */
+#define HOST_MEM_CFG_PAGE 1 /* 4022 */
+#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */
+#define PROT_STAT_PAGE 3 /* 4022 */
+
+/* Register Mask - sets corresponding mask bits in the upper word */
+static inline uint32_t set_rmask(uint32_t val)
+{
+ return (val & 0xffff) | (val << 16);
+}
+
+
+static inline uint32_t clr_rmask(uint32_t val)
+{
+ return 0 | (val << 16);
+}
+
+/* ctrl_status definitions */
+#define CSR_SCSI_PAGE_SELECT 0x00000003
+#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */
+#define CSR_SCSI_RESET_INTR 0x00000008
+#define CSR_SCSI_COMPLETION_INTR 0x00000010
+#define CSR_SCSI_PROCESSOR_INTR 0x00000020
+#define CSR_INTR_RISC 0x00000040
+#define CSR_BOOT_ENABLE 0x00000080
+#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */
+#define CSR_FUNC_NUM 0x00000700 /* 4022 */
+#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */
+#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */
+#define CSR_FATAL_ERROR 0x00004000
+#define CSR_SOFT_RESET 0x00008000
+#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM
+#define ISP_CONTROL_FN0_SCSI 0x0500
+#define ISP_CONTROL_FN1_SCSI 0x0700
+
+#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\
+ CSR_SCSI_PROCESSOR_INTR |\
+ CSR_SCSI_RESET_INTR)
+
+/* ISP InterruptMask definitions */
+#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */
+
+/* ISP 4022 nvram definitions */
+#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */
+
+/* ISP port_status definitions */
+
+/* ISP Semaphore definitions */
+
+/* ISP General Purpose Output definitions */
+
+/* shadow registers (DMA'd from HA to system memory. read only) */
+struct shadow_regs {
+ /* SCSI Request Queue Consumer Index */
+ __le32 req_q_out; /* 0 x0 R */
+
+ /* SCSI Completion Queue Producer Index */
+ __le32 rsp_q_in; /* 4 x4 R */
+}; /* 8 x8 */
+
+
+/* External hardware configuration register */
+union external_hw_config_reg {
+ struct {
+ /* FIXME: Do we even need this? All values are
+ * referred to by 16 bit quantities. Platform and
+ * endianess issues. */
+ __le32 bReserved0:1;
+ __le32 bSDRAMProtectionMethod:2;
+ __le32 bSDRAMBanks:1;
+ __le32 bSDRAMChipWidth:1;
+ __le32 bSDRAMChipSize:2;
+ __le32 bParityDisable:1;
+ __le32 bExternalMemoryType:1;
+ __le32 bFlashBIOSWriteEnable:1;
+ __le32 bFlashUpperBankSelect:1;
+ __le32 bWriteBurst:2;
+ __le32 bReserved1:3;
+ __le32 bMask:16;
+ };
+ uint32_t Asuint32_t;
+};
+
+/*************************************************************************
+ *
+ * Mailbox Commands Structures and Definitions
+ *
+ *************************************************************************/
+
+/* Mailbox command definitions */
+#define MBOX_CMD_ABOUT_FW 0x0009
+#define MBOX_CMD_LUN_RESET 0x0016
+#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
+#define MBOX_CMD_GET_FW_STATUS 0x001F
+#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
+#define ISNS_DISABLE 0
+#define ISNS_ENABLE 1
+#define MBOX_CMD_COPY_FLASH 0x0024
+#define MBOX_CMD_WRITE_FLASH 0x0025
+#define MBOX_CMD_READ_FLASH 0x0026
+#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
+#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
+#define LOGOUT_OPTION_CLOSE_SESSION 0x01
+#define LOGOUT_OPTION_RELOGIN 0x02
+#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A
+#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060
+#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061
+#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062
+#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063
+#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064
+#define DDB_DS_UNASSIGNED 0x00
+#define DDB_DS_NO_CONNECTION_ACTIVE 0x01
+#define DDB_DS_SESSION_ACTIVE 0x04
+#define DDB_DS_SESSION_FAILED 0x06
+#define DDB_DS_LOGIN_IN_PROCESS 0x07
+#define MBOX_CMD_GET_FW_STATE 0x0069
+#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
+#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087
+
+/* Mailbox 1 */
+#define FW_STATE_READY 0x0000
+#define FW_STATE_CONFIG_WAIT 0x0001
+#define FW_STATE_WAIT_LOGIN 0x0002
+#define FW_STATE_ERROR 0x0004
+#define FW_STATE_DHCP_IN_PROGRESS 0x0008
+
+/* Mailbox 3 */
+#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001
+#define FW_ADDSTATE_DHCP_ENABLED 0x0002
+#define FW_ADDSTATE_LINK_UP 0x0010
+#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020
+#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B
+#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074
+#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */
+#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
+
+/* Mailbox status definitions */
+#define MBOX_COMPLETION_STATUS 4
+#define MBOX_STS_BUSY 0x0007
+#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000
+#define MBOX_STS_COMMAND_COMPLETE 0x4000
+#define MBOX_STS_COMMAND_ERROR 0x4005
+
+#define MBOX_ASYNC_EVENT_STATUS 8
+#define MBOX_ASTS_SYSTEM_ERROR 0x8002
+#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003
+#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004
+#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005
+#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006
+#define MBOX_ASTS_LINK_UP 0x8010
+#define MBOX_ASTS_LINK_DOWN 0x8011
+#define MBOX_ASTS_DATABASE_CHANGED 0x8014
+#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015
+#define MBOX_ASTS_SELF_TEST_FAILED 0x8016
+#define MBOX_ASTS_LOGIN_FAILED 0x8017
+#define MBOX_ASTS_DNS 0x8018
+#define MBOX_ASTS_HEARTBEAT 0x8019
+#define MBOX_ASTS_NVRAM_INVALID 0x801A
+#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B
+#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C
+#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
+#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
+#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
+#define ISNS_EVENT_DATA_RECEIVED 0x0000
+#define ISNS_EVENT_CONNECTION_OPENED 0x0001
+#define ISNS_EVENT_CONNECTION_FAILED 0x0002
+#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
+#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+
+/*************************************************************************/
+
+/* Host Adapter Initialization Control Block (from host) */
+struct init_fw_ctrl_blk {
+ uint8_t Version; /* 00 */
+ uint8_t Control; /* 01 */
+
+ uint16_t FwOptions; /* 02-03 */
+#define FWOPT_HEARTBEAT_ENABLE 0x1000
+#define FWOPT_SESSION_MODE 0x0040
+#define FWOPT_INITIATOR_MODE 0x0020
+#define FWOPT_TARGET_MODE 0x0010
+
+ uint16_t ExecThrottle; /* 04-05 */
+ uint8_t RetryCount; /* 06 */
+ uint8_t RetryDelay; /* 07 */
+ uint16_t MaxEthFrPayloadSize; /* 08-09 */
+ uint16_t AddFwOptions; /* 0A-0B */
+
+ uint8_t HeartbeatInterval; /* 0C */
+ uint8_t InstanceNumber; /* 0D */
+ uint16_t RES2; /* 0E-0F */
+ uint16_t ReqQConsumerIndex; /* 10-11 */
+ uint16_t ComplQProducerIndex; /* 12-13 */
+ uint16_t ReqQLen; /* 14-15 */
+ uint16_t ComplQLen; /* 16-17 */
+ uint32_t ReqQAddrLo; /* 18-1B */
+ uint32_t ReqQAddrHi; /* 1C-1F */
+ uint32_t ComplQAddrLo; /* 20-23 */
+ uint32_t ComplQAddrHi; /* 24-27 */
+ uint32_t ShadowRegBufAddrLo; /* 28-2B */
+ uint32_t ShadowRegBufAddrHi; /* 2C-2F */
+
+ uint16_t iSCSIOptions; /* 30-31 */
+
+ uint16_t TCPOptions; /* 32-33 */
+
+ uint16_t IPOptions; /* 34-35 */
+
+ uint16_t MaxPDUSize; /* 36-37 */
+ uint16_t RcvMarkerInt; /* 38-39 */
+ uint16_t SndMarkerInt; /* 3A-3B */
+ uint16_t InitMarkerlessInt; /* 3C-3D */
+ uint16_t FirstBurstSize; /* 3E-3F */
+ uint16_t DefaultTime2Wait; /* 40-41 */
+ uint16_t DefaultTime2Retain; /* 42-43 */
+ uint16_t MaxOutStndngR2T; /* 44-45 */
+ uint16_t KeepAliveTimeout; /* 46-47 */
+ uint16_t PortNumber; /* 48-49 */
+ uint16_t MaxBurstSize; /* 4A-4B */
+ uint32_t RES4; /* 4C-4F */
+ uint8_t IPAddr[4]; /* 50-53 */
+ uint8_t RES5[12]; /* 54-5F */
+ uint8_t SubnetMask[4]; /* 60-63 */
+ uint8_t RES6[12]; /* 64-6F */
+ uint8_t GatewayIPAddr[4]; /* 70-73 */
+ uint8_t RES7[12]; /* 74-7F */
+ uint8_t PriDNSIPAddr[4]; /* 80-83 */
+ uint8_t SecDNSIPAddr[4]; /* 84-87 */
+ uint8_t RES8[8]; /* 88-8F */
+ uint8_t Alias[32]; /* 90-AF */
+ uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
+ uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
+ uint8_t EthernetMACAddr[6]; /* C0-C5 */
+ uint16_t TargetPortalGroup; /* C6-C7 */
+ uint8_t SendScale; /* C8 */
+ uint8_t RecvScale; /* C9 */
+ uint8_t TypeOfService; /* CA */
+ uint8_t Time2Live; /* CB */
+ uint16_t VLANPriority; /* CC-CD */
+ uint16_t Reserved8; /* CE-CF */
+ uint8_t SecIPAddr[4]; /* D0-D3 */
+ uint8_t Reserved9[12]; /* D4-DF */
+ uint8_t iSNSIPAddr[4]; /* E0-E3 */
+ uint16_t iSNSServerPortNumber; /* E4-E5 */
+ uint8_t Reserved10[10]; /* E6-EF */
+ uint8_t SLPDAIPAddr[4]; /* F0-F3 */
+ uint8_t Reserved11[12]; /* F4-FF */
+ uint8_t iSCSINameString[256]; /* 100-1FF */
+};
+
+/*************************************************************************/
+
+struct dev_db_entry {
+ uint8_t options; /* 00 */
+#define DDB_OPT_DISC_SESSION 0x10
+#define DDB_OPT_TARGET 0x02 /* device is a target */
+
+ uint8_t control; /* 01 */
+
+ uint16_t exeThrottle; /* 02-03 */
+ uint16_t exeCount; /* 04-05 */
+ uint8_t retryCount; /* 06 */
+ uint8_t retryDelay; /* 07 */
+ uint16_t iSCSIOptions; /* 08-09 */
+
+ uint16_t TCPOptions; /* 0A-0B */
+
+ uint16_t IPOptions; /* 0C-0D */
+
+ uint16_t maxPDUSize; /* 0E-0F */
+ uint16_t rcvMarkerInt; /* 10-11 */
+ uint16_t sndMarkerInt; /* 12-13 */
+ uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
+ uint16_t firstBurstSize; /* 16-17 */
+ uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
+ uint16_t maxTime2Retain; /* 1A-1B */
+ uint16_t maxOutstndngR2T; /* 1C-1D */
+ uint16_t keepAliveTimeout; /* 1E-1F */
+ uint8_t ISID[6]; /* 20-25 big-endian, must be converted
+ * to little-endian */
+ uint16_t TSID; /* 26-27 */
+ uint16_t portNumber; /* 28-29 */
+ uint16_t maxBurstSize; /* 2A-2B */
+ uint16_t taskMngmntTimeout; /* 2C-2D */
+ uint16_t reserved1; /* 2E-2F */
+ uint8_t ipAddr[0x10]; /* 30-3F */
+ uint8_t iSCSIAlias[0x20]; /* 40-5F */
+ uint8_t targetAddr[0x20]; /* 60-7F */
+ uint8_t userID[0x20]; /* 80-9F */
+ uint8_t password[0x20]; /* A0-BF */
+ uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
+ * pointer to a string so we
+ * don't have to reserve soooo
+ * much RAM */
+ uint16_t ddbLink; /* 1C0-1C1 */
+ uint16_t CHAPTableIndex; /* 1C2-1C3 */
+ uint16_t TargetPortalGroup; /* 1C4-1C5 */
+ uint16_t reserved2[2]; /* 1C6-1C7 */
+ uint32_t statSN; /* 1C8-1CB */
+ uint32_t expStatSN; /* 1CC-1CF */
+ uint16_t reserved3[0x2C]; /* 1D0-1FB */
+ uint16_t ddbValidCookie; /* 1FC-1FD */
+ uint16_t ddbValidSize; /* 1FE-1FF */
+};
+
+/*************************************************************************/
+
+/* Flash definitions */
+
+#define FLASH_OFFSET_SYS_INFO 0x02000000
+#define FLASH_DEFAULTBLOCKSIZE 0x20000
+#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes
+ * for EOF
+ * signature */
+
+struct sys_info_phys_addr {
+ uint8_t address[6]; /* 00-05 */
+ uint8_t filler[2]; /* 06-07 */
+};
+
+struct flash_sys_info {
+ uint32_t cookie; /* 00-03 */
+ uint32_t physAddrCount; /* 04-07 */
+ struct sys_info_phys_addr physAddr[4]; /* 08-27 */
+ uint8_t vendorId[128]; /* 28-A7 */
+ uint8_t productId[128]; /* A8-127 */
+ uint32_t serialNumber; /* 128-12B */
+
+ /* PCI Configuration values */
+ uint32_t pciDeviceVendor; /* 12C-12F */
+ uint32_t pciDeviceId; /* 130-133 */
+ uint32_t pciSubsysVendor; /* 134-137 */
+ uint32_t pciSubsysId; /* 138-13B */
+
+ /* This validates version 1. */
+ uint32_t crumbs; /* 13C-13F */
+
+ uint32_t enterpriseNumber; /* 140-143 */
+
+ uint32_t mtu; /* 144-147 */
+ uint32_t reserved0; /* 148-14b */
+ uint32_t crumbs2; /* 14c-14f */
+ uint8_t acSerialNumber[16]; /* 150-15f */
+ uint32_t crumbs3; /* 160-16f */
+
+ /* Leave this last in the struct so it is declared invalid if
+ * any new items are added.
+ */
+ uint32_t reserved1[39]; /* 170-1ff */
+}; /* 200 */
+
+struct crash_record {
+ uint16_t fw_major_version; /* 00 - 01 */
+ uint16_t fw_minor_version; /* 02 - 03 */
+ uint16_t fw_patch_version; /* 04 - 05 */
+ uint16_t fw_build_version; /* 06 - 07 */
+
+ uint8_t build_date[16]; /* 08 - 17 */
+ uint8_t build_time[16]; /* 18 - 27 */
+ uint8_t build_user[16]; /* 28 - 37 */
+ uint8_t card_serial_num[16]; /* 38 - 47 */
+
+ uint32_t time_of_crash_in_secs; /* 48 - 4B */
+ uint32_t time_of_crash_in_ms; /* 4C - 4F */
+
+ uint16_t out_RISC_sd_num_frames; /* 50 - 51 */
+ uint16_t OAP_sd_num_words; /* 52 - 53 */
+ uint16_t IAP_sd_num_frames; /* 54 - 55 */
+ uint16_t in_RISC_sd_num_words; /* 56 - 57 */
+
+ uint8_t reserved1[28]; /* 58 - 7F */
+
+ uint8_t out_RISC_reg_dump[256]; /* 80 -17F */
+ uint8_t in_RISC_reg_dump[256]; /*180 -27F */
+ uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */
+};
+
+struct conn_event_log_entry {
+#define MAX_CONN_EVENT_LOG_ENTRIES 100
+ uint32_t timestamp_sec; /* 00 - 03 seconds since boot */
+ uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */
+ uint16_t device_index; /* 08 - 09 */
+ uint16_t fw_conn_state; /* 0A - 0B */
+ uint8_t event_type; /* 0C - 0C */
+ uint8_t error_code; /* 0D - 0D */
+ uint16_t error_code_detail; /* 0E - 0F */
+ uint8_t num_consecutive_events; /* 10 - 10 */
+ uint8_t rsvd[3]; /* 11 - 13 */
+};
+
+/*************************************************************************
+ *
+ * IOCB Commands Structures and Definitions
+ *
+ *************************************************************************/
+#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
+#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
+
+/* IOCB header structure */
+struct qla4_header {
+ uint8_t entryType;
+#define ET_STATUS 0x03
+#define ET_MARKER 0x04
+#define ET_CONT_T1 0x0A
+#define ET_STATUS_CONTINUATION 0x10
+#define ET_CMND_T3 0x19
+#define ET_PASSTHRU0 0x3A
+#define ET_PASSTHRU_STATUS 0x3C
+
+ uint8_t entryStatus;
+ uint8_t systemDefined;
+ uint8_t entryCount;
+
+ /* SyetemDefined definition */
+};
+
+/* Generic queue entry structure*/
+struct queue_entry {
+ uint8_t data[60];
+ uint32_t signature;
+
+};
+
+/* 64 bit addressing segment counts*/
+
+#define COMMAND_SEG_A64 1
+#define CONTINUE_SEG_A64 5
+
+/* 64 bit addressing segment definition*/
+
+struct data_seg_a64 {
+ struct {
+ uint32_t addrLow;
+ uint32_t addrHigh;
+
+ } base;
+
+ uint32_t count;
+
+};
+
+/* Command Type 3 entry structure*/
+
+struct command_t3_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connection_id; /* 0A-0B */
+
+ uint8_t control_flags; /* 0C */
+
+ /* data direction (bits 5-6) */
+#define CF_WRITE 0x20
+#define CF_READ 0x40
+#define CF_NO_DATA 0x00
+
+ /* task attributes (bits 2-0) */
+#define CF_HEAD_TAG 0x03
+#define CF_ORDERED_TAG 0x02
+#define CF_SIMPLE_TAG 0x01
+
+ /* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS
+ * IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS
+ * CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET
+ * PROPERLY.
+ */
+ uint8_t state_flags; /* 0D */
+ uint8_t cmdRefNum; /* 0E */
+ uint8_t reserved1; /* 0F */
+ uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */
+ struct scsi_lun lun; /* FCP LUN (BE). */
+ uint32_t cmdSeqNum; /* 28-2B */
+ uint16_t timeout; /* 2C-2D */
+ uint16_t dataSegCnt; /* 2E-2F */
+ uint32_t ttlByteCnt; /* 30-33 */
+ struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */
+
+};
+
+
+/* Continuation Type 1 entry structure*/
+struct continuation_t1_entry {
+ struct qla4_header hdr;
+
+ struct data_seg_a64 dataseg[CONTINUE_SEG_A64];
+
+};
+
+/* Parameterize for 64 or 32 bits */
+#define COMMAND_SEG COMMAND_SEG_A64
+#define CONTINUE_SEG CONTINUE_SEG_A64
+
+#define ET_COMMAND ET_CMND_T3
+#define ET_CONTINUE ET_CONT_T1
+
+/* Marker entry structure*/
+struct marker_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t system_defined; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t modifier; /* 0A-0B */
+#define MM_LUN_RESET 0
+
+ uint16_t flags; /* 0C-0D */
+ uint16_t reserved1; /* 0E-0F */
+ struct scsi_lun lun; /* FCP LUN (BE). */
+ uint64_t reserved2; /* 18-1F */
+ uint64_t reserved3; /* 20-27 */
+ uint64_t reserved4; /* 28-2F */
+ uint64_t reserved5; /* 30-37 */
+ uint64_t reserved6; /* 38-3F */
+};
+
+/* Status entry structure*/
+struct status_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t handle; /* 04-07 */
+
+ uint8_t scsiStatus; /* 08 */
+#define SCSI_CHECK_CONDITION 0x02
+
+ uint8_t iscsiFlags; /* 09 */
+#define ISCSI_FLAG_RESIDUAL_UNDER 0x02
+#define ISCSI_FLAG_RESIDUAL_OVER 0x04
+
+ uint8_t iscsiResponse; /* 0A */
+
+ uint8_t completionStatus; /* 0B */
+#define SCS_COMPLETE 0x00
+#define SCS_INCOMPLETE 0x01
+#define SCS_RESET_OCCURRED 0x04
+#define SCS_ABORTED 0x05
+#define SCS_TIMEOUT 0x06
+#define SCS_DATA_OVERRUN 0x07
+#define SCS_DATA_UNDERRUN 0x15
+#define SCS_QUEUE_FULL 0x1C
+#define SCS_DEVICE_UNAVAILABLE 0x28
+#define SCS_DEVICE_LOGGED_OUT 0x29
+
+ uint8_t reserved1; /* 0C */
+
+ /* state_flags MUST be at the same location as state_flags in
+ * the Command_T3/4_Entry */
+ uint8_t state_flags; /* 0D */
+
+ uint16_t senseDataByteCnt; /* 0E-0F */
+ uint32_t residualByteCnt; /* 10-13 */
+ uint32_t bidiResidualByteCnt; /* 14-17 */
+ uint32_t expSeqNum; /* 18-1B */
+ uint32_t maxCmdSeqNum; /* 1C-1F */
+ uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */
+
+};
+
+struct passthru0 {
+ struct qla4_header hdr; /* 00-03 */
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connectionID; /* 0A-0B */
+#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000)
+
+ uint16_t controlFlags; /* 0C-0D */
+#define PT_FLAG_ETHERNET_FRAME 0x8000
+#define PT_FLAG_ISNS_PDU 0x8000
+#define PT_FLAG_SEND_BUFFER 0x0200
+#define PT_FLAG_WAIT_4_RESPONSE 0x0100
+
+ uint16_t timeout; /* 0E-0F */
+#define PT_DEFAULT_TIMEOUT 30 /* seconds */
+
+ struct data_seg_a64 outDataSeg64; /* 10-1B */
+ uint32_t res1; /* 1C-1F */
+ struct data_seg_a64 inDataSeg64; /* 20-2B */
+ uint8_t res2[20]; /* 2C-3F */
+};
+
+struct passthru_status {
+ struct qla4_header hdr; /* 00-03 */
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connectionID; /* 0A-0B */
+
+ uint8_t completionStatus; /* 0C */
+#define PASSTHRU_STATUS_COMPLETE 0x01
+
+ uint8_t residualFlags; /* 0D */
+
+ uint16_t timeout; /* 0E-0F */
+ uint16_t portNumber; /* 10-11 */
+ uint8_t res1[10]; /* 12-1B */
+ uint32_t outResidual; /* 1C-1F */
+ uint8_t res2[12]; /* 20-2B */
+ uint32_t inResidual; /* 2C-2F */
+ uint8_t res4[16]; /* 30-3F */
+};
+
+#endif /* _QLA4X_FW_H */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
new file mode 100644
index 00000000000..2122967bbf0
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -0,0 +1,79 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA4x_GBL_H
+#define __QLA4x_GBL_H
+
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
+int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
+int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
+ uint8_t renew_ddb_list);
+int qla4xxx_soft_reset(struct scsi_qla_host *ha);
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
+
+void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
+void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
+
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
+int qla4xxx_relogin_device(struct scsi_qla_host * ha,
+ struct ddb_entry * ddb_entry);
+int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+ int lun);
+int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+ uint32_t offset, uint32_t len);
+int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
+int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
+
+/* FIXME: Goodness! this really wants a small struct to hold the
+ * parameters. On x86 the args will get passed on the stack! */
+int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
+ uint16_t fw_ddb_index,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma,
+ uint32_t *num_valid_ddb_entries,
+ uint32_t *next_ddb_index,
+ uint32_t *fw_ddb_device_state,
+ uint32_t *conn_err_detail,
+ uint16_t *tcp_source_port_num,
+ uint16_t *connection_id);
+
+struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
+ uint32_t fw_ddb_index);
+int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
+ dma_addr_t fw_ddb_entry_dma);
+
+void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry);
+u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
+void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
+struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
+int qla4xxx_add_sess(struct ddb_entry *);
+void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
+int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index,
+ uint16_t connection_id,
+ uint16_t option);
+int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index);
+int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
+int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
+void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+ uint32_t intr_status);
+int qla4xxx_init_rings(struct scsi_qla_host * ha);
+void qla4xxx_dump_buffer(void *b, uint32_t size);
+struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
+void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
+int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
+int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
+ uint32_t fw_ddb_index, uint32_t state);
+
+extern int ql4xextended_error_logging;
+extern int ql4xdiscoverywait;
+extern int ql4xdontresethba;
+#endif /* _QLA4x_GBL_H */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
new file mode 100644
index 00000000000..cc210f297a7
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -0,0 +1,1315 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+/*
+ * QLogic ISP4xxx Hardware Support Function Prototypes.
+ */
+
+static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
+{
+ uint32_t value;
+ uint8_t func_number;
+ unsigned long flags;
+
+ /* Get the function number */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ value = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ func_number = (uint8_t) ((value >> 4) & 0x30);
+ switch (value & ISP_CONTROL_FN_MASK) {
+ case ISP_CONTROL_FN0_SCSI:
+ ha->mac_index = 1;
+ break;
+ case ISP_CONTROL_FN1_SCSI:
+ ha->mac_index = 3;
+ break;
+ default:
+ DEBUG2(printk("scsi%ld: %s: Invalid function number, "
+ "ispControlStatus = 0x%x\n", ha->host_no,
+ __func__, value));
+ break;
+ }
+ DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__,
+ ha->mac_index));
+}
+
+/**
+ * qla4xxx_free_ddb - deallocate ddb
+ * @ha: pointer to host adapter structure.
+ * @ddb_entry: pointer to device database entry
+ *
+ * This routine deallocates and unlinks the specified ddb_entry from the
+ * adapter's
+ **/
+void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
+{
+ /* Remove device entry from list */
+ list_del_init(&ddb_entry->list);
+
+ /* Remove device pointer from index mapping arrays */
+ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =
+ (struct ddb_entry *) INVALID_ENTRY;
+ ha->tot_ddbs--;
+
+ /* Free memory and scsi-ml struct for device entry */
+ qla4xxx_destroy_sess(ddb_entry);
+}
+
+/**
+ * qla4xxx_free_ddb_list - deallocate all ddbs
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine deallocates and removes all devices on the sppecified adapter.
+ **/
+void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
+{
+ struct list_head *ptr;
+ struct ddb_entry *ddb_entry;
+
+ while (!list_empty(&ha->ddb_list)) {
+ ptr = ha->ddb_list.next;
+ /* Free memory for device entry and remove */
+ ddb_entry = list_entry(ptr, struct ddb_entry, list);
+ qla4xxx_free_ddb(ha, ddb_entry);
+ }
+}
+
+/**
+ * qla4xxx_init_rings - initialize hw queues
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine initializes the internal queues for the specified adapter.
+ * The QLA4010 requires us to restart the queues at index 0.
+ * The QLA4000 doesn't care, so just default to QLA4010's requirement.
+ **/
+int qla4xxx_init_rings(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+
+ /* Initialize request queue. */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->request_out = 0;
+ ha->request_in = 0;
+ ha->request_ptr = &ha->request_ring[ha->request_in];
+ ha->req_q_count = REQUEST_QUEUE_DEPTH;
+
+ /* Initialize response queue. */
+ ha->response_in = 0;
+ ha->response_out = 0;
+ ha->response_ptr = &ha->response_ring[ha->response_out];
+
+ /*
+ * Initialize DMA Shadow registers. The firmware is really supposed to
+ * take care of this, but on some uniprocessor systems, the shadow
+ * registers aren't cleared-- causing the interrupt_handler to think
+ * there are responses to be processed when there aren't.
+ */
+ ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
+ ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
+ wmb();
+
+ writel(0, &ha->reg->req_q_in);
+ writel(0, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_validate_mac_address - validate adapter MAC address(es)
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
+{
+ struct flash_sys_info *sys_info;
+ dma_addr_t sys_info_dma;
+ int status = QLA_ERROR;
+
+ sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
+ &sys_info_dma, GFP_KERNEL);
+ if (sys_info == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+
+ goto exit_validate_mac_no_free;
+ }
+ memset(sys_info, 0, sizeof(*sys_info));
+
+ /* Get flash sys info */
+ if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO,
+ sizeof(*sys_info)) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
+ "failed\n", ha->host_no, __func__));
+
+ goto exit_validate_mac;
+ }
+
+ /* Save M.A.C. address & serial_number */
+ memcpy(ha->my_mac, &sys_info->physAddr[0].address[0],
+ min(sizeof(ha->my_mac),
+ sizeof(sys_info->physAddr[0].address)));
+ memcpy(ha->serial_number, &sys_info->acSerialNumber,
+ min(sizeof(ha->serial_number),
+ sizeof(sys_info->acSerialNumber)));
+
+ status = QLA_SUCCESS;
+
+ exit_validate_mac:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
+ sys_info_dma);
+
+ exit_validate_mac_no_free:
+ return status;
+}
+
+/**
+ * qla4xxx_init_local_data - initialize adapter specific local data
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
+{
+ /* Initilize aen queue */
+ ha->aen_q_count = MAX_AEN_ENTRIES;
+
+ return qla4xxx_get_firmware_status(ha);
+}
+
+static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
+{
+ uint32_t timeout_count;
+ int ready = 0;
+
+ DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));
+ for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;
+ timeout_count--) {
+ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
+ qla4xxx_get_dhcp_ip_address(ha);
+
+ /* Get firmware state. */
+ if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: unable to get firmware "
+ "state\n", ha->host_no, __func__));
+ break;
+
+ }
+
+ if (ha->firmware_state & FW_STATE_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: an unrecoverable error has"
+ " occurred\n", ha->host_no, __func__));
+ break;
+
+ }
+ if (ha->firmware_state & FW_STATE_CONFIG_WAIT) {
+ /*
+ * The firmware has not yet been issued an Initialize
+ * Firmware command, so issue it now.
+ */
+ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR)
+ break;
+
+ /* Go back and test for ready state - no wait. */
+ continue;
+ }
+
+ if (ha->firmware_state == FW_STATE_READY) {
+ DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));
+ /* The firmware is ready to process SCSI commands. */
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: MEDIA TYPE - %s\n",
+ ha->host_no,
+ __func__, (ha->addl_fw_state &
+ FW_ADDSTATE_OPTICAL_MEDIA)
+ != 0 ? "OPTICAL" : "COPPER"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: DHCP STATE Enabled "
+ "%s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_DHCP_ENABLED) != 0 ?
+ "YES" : "NO"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: LINK %s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_LINK_UP) != 0 ?
+ "UP" : "DOWN"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: iSNS Service "
+ "Started %s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?
+ "YES" : "NO"));
+
+ ready = 1;
+ break;
+ }
+ DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "
+ "seconds expired= %d\n", ha->host_no, __func__,
+ ha->firmware_state, ha->addl_fw_state,
+ timeout_count));
+ if (is_qla4032(ha) &&
+ !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&
+ (timeout_count < ADAPTER_INIT_TOV - 5)) {
+ break;
+ }
+
+ msleep(1000);
+ } /* end of for */
+
+ if (timeout_count == 0)
+ DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
+ ha->host_no, __func__));
+
+ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) {
+ DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"
+ " grab an IP address from DHCP server\n",
+ ha->host_no, __func__));
+ ready = 1;
+ }
+
+ return ready;
+}
+
+/**
+ * qla4xxx_init_firmware - initializes the firmware.
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
+{
+ int status = QLA_ERROR;
+
+ dev_info(&ha->pdev->dev, "Initializing firmware..\n");
+ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "
+ "control block\n", ha->host_no, __func__));
+ return status;
+ }
+ if (!qla4xxx_fw_ready(ha))
+ return status;
+
+ set_bit(AF_ONLINE, &ha->flags);
+ return qla4xxx_get_firmware_status(ha);
+}
+
+static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ struct ddb_entry *ddb_entry = NULL;
+ int found = 0;
+ uint32_t device_state;
+
+ /* Make sure the dma buffer is valid */
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+ return NULL;
+ }
+
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+ fw_ddb_entry_dma, NULL, NULL,
+ &device_state, NULL, NULL, NULL) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+ "fw_ddb_index %d\n", ha->host_no, __func__,
+ fw_ddb_index));
+ return NULL;
+ }
+
+ /* Allocate DDB if not already allocated. */
+ DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
+ __func__, fw_ddb_index));
+ list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
+ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName,
+ ISCSI_NAME_SIZE) == 0) {
+ found++;
+ break;
+ }
+ }
+
+ if (!found) {
+ DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
+ "new ddb\n", ha->host_no, __func__,
+ fw_ddb_index));
+ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+ }
+
+ /* if not found allocate new ddb */
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+ fw_ddb_entry_dma);
+
+ return ddb_entry;
+}
+
+/**
+ * qla4xxx_update_ddb_entry - update driver's internal ddb
+ * @ha: pointer to host adapter structure.
+ * @ddb_entry: pointer to device database structure to be filled
+ * @fw_ddb_index: index of the ddb entry in fw ddb table
+ *
+ * This routine updates the driver's internal device database entry
+ * with information retrieved from the firmware's device database
+ * entry for the specified device. The ddb_entry->fw_ddb_index field
+ * must be initialized prior to calling this routine
+ *
+ **/
+int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry,
+ uint32_t fw_ddb_index)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ int status = QLA_ERROR;
+
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
+ __func__));
+ goto exit_update_ddb;
+ }
+
+ /* Make sure the dma buffer is valid */
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+
+ goto exit_update_ddb;
+ }
+
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+ fw_ddb_entry_dma, NULL, NULL,
+ &ddb_entry->fw_ddb_device_state, NULL,
+ &ddb_entry->tcp_source_port_num,
+ &ddb_entry->connection_id) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+ "fw_ddb_index %d\n", ha->host_no, __func__,
+ fw_ddb_index));
+
+ goto exit_update_ddb;
+ }
+
+ status = QLA_SUCCESS;
+ ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID);
+ ddb_entry->task_mgmt_timeout =
+ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ ddb_entry->CmdSn = 0;
+ ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle);
+ ddb_entry->default_relogin_timeout =
+ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait);
+
+ /* Update index in case it changed */
+ ddb_entry->fw_ddb_index = fw_ddb_index;
+ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
+
+ ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber);
+ ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup);
+ memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0],
+ min(sizeof(ddb_entry->iscsi_name),
+ sizeof(fw_ddb_entry->iscsiName)));
+ memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0],
+ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr)));
+
+ DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
+ ha->host_no, __func__, fw_ddb_index,
+ ddb_entry->fw_ddb_device_state, status));
+
+ exit_update_ddb:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+
+ return status;
+}
+
+/**
+ * qla4xxx_alloc_ddb - allocate device database entry
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ *
+ * This routine allocates a ddb_entry, ititializes some values, and
+ * inserts it into the ddb list.
+ **/
+struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
+{
+ struct ddb_entry *ddb_entry;
+
+ DEBUG2(printk("scsi%ld: %s: fw_ddb_index [%d]\n", ha->host_no,
+ __func__, fw_ddb_index));
+
+ ddb_entry = qla4xxx_alloc_sess(ha);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
+ "to add fw_ddb_index [%d]\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return ddb_entry;
+ }
+
+ ddb_entry->fw_ddb_index = fw_ddb_index;
+ atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count);
+ atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ atomic_set(&ddb_entry->relogin_retry_count, 0);
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ list_add_tail(&ddb_entry->list, &ha->ddb_list);
+ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
+ ha->tot_ddbs++;
+
+ return ddb_entry;
+}
+
+/**
+ * qla4xxx_configure_ddbs - builds driver ddb list
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine searches for all valid firmware ddb entries and builds
+ * an internal ddb list. Ddbs that are considered valid are those with
+ * a device state of SESSION_ACTIVE.
+ **/
+static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+ uint32_t fw_ddb_index = 0;
+ uint32_t next_fw_ddb_index = 0;
+ uint32_t ddb_state;
+ uint32_t conn_err, err_code;
+ struct ddb_entry *ddb_entry;
+
+ dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
+ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
+ fw_ddb_index = next_fw_ddb_index) {
+ /* First, let's see if a device exists here */
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
+ &next_fw_ddb_index, &ddb_state,
+ &conn_err, NULL, NULL) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
+ "fw_ddb_index %d failed", ha->host_no,
+ __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+
+ DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
+ "next_fw_ddb_index=%d.\n", ha->host_no, __func__,
+ fw_ddb_index, ddb_state, next_fw_ddb_index));
+
+ /* Issue relogin, if necessary. */
+ if (ddb_state == DDB_DS_SESSION_FAILED ||
+ ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) {
+ /* Try and login to device */
+ DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
+ ha->host_no, __func__, fw_ddb_index));
+ err_code = ((conn_err & 0x00ff0000) >> 16);
+ if (err_code == 0x1c || err_code == 0x06) {
+ DEBUG2(printk("scsi%ld: %s send target "
+ "completed "
+ "or access denied failure\n",
+ ha->host_no, __func__));
+ } else
+ qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
+ }
+
+ if (ddb_state != DDB_DS_SESSION_ACTIVE)
+ goto next_one;
+ /*
+ * if fw_ddb with session active state found,
+ * add to ddb_list
+ */
+ DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n",
+ ha->host_no, __func__, fw_ddb_index));
+
+ /* Add DDB to internal our ddb list. */
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
+ "for device at fw_ddb_index %d\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+ /* Fill in the device structure */
+ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+ QLA_ERROR) {
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+
+
+ DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
+ "for fw_ddb_index %d.\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+
+next_one:
+ /* We know we've reached the last device when
+ * next_fw_ddb_index is 0 */
+ if (next_fw_ddb_index == 0)
+ break;
+ }
+
+ dev_info(&ha->pdev->dev, "DDB list done..\n");
+
+ return status;
+}
+
+struct qla4_relog_scan {
+ int halt_wait;
+ uint32_t conn_err;
+ uint32_t err_code;
+ uint32_t fw_ddb_index;
+ uint32_t next_fw_ddb_index;
+ uint32_t fw_ddb_device_state;
+};
+
+static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)
+{
+ struct ddb_entry *ddb_entry;
+
+ /*
+ * Don't want to do a relogin if connection
+ * error is 0x1c.
+ */
+ rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16);
+ if (rs->err_code == 0x1c || rs->err_code == 0x06) {
+ DEBUG2(printk(
+ "scsi%ld: %s send target"
+ " completed or "
+ "access denied failure\n",
+ ha->host_no, __func__));
+ } else {
+ /* We either have a device that is in
+ * the process of relogging in or a
+ * device that is waiting to be
+ * relogged in */
+ rs->halt_wait = 0;
+
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
+ rs->fw_ddb_index);
+ if (ddb_entry == NULL)
+ return QLA_ERROR;
+
+ if (ddb_entry->dev_scan_wait_to_start_relogin != 0
+ && time_after_eq(jiffies,
+ ddb_entry->
+ dev_scan_wait_to_start_relogin))
+ {
+ ddb_entry->dev_scan_wait_to_start_relogin = 0;
+ qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0);
+ }
+ }
+ return QLA_SUCCESS;
+}
+
+static int qla4_scan_for_relogin(struct scsi_qla_host *ha,
+ struct qla4_relog_scan *rs)
+{
+ int error;
+
+ /* scan for relogins
+ * ----------------- */
+ for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES;
+ rs->fw_ddb_index = rs->next_fw_ddb_index) {
+ if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0,
+ NULL, &rs->next_fw_ddb_index,
+ &rs->fw_ddb_device_state,
+ &rs->conn_err, NULL, NULL)
+ == QLA_ERROR)
+ return QLA_ERROR;
+
+ if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS)
+ rs->halt_wait = 0;
+
+ if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED ||
+ rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) {
+ error = qla4_test_rdy(ha, rs);
+ if (error)
+ return error;
+ }
+
+ /* We know we've reached the last device when
+ * next_fw_ddb_index is 0 */
+ if (rs->next_fw_ddb_index == 0)
+ break;
+ }
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_devices_ready - wait for target devices to be logged in
+ * @ha: pointer to adapter structure
+ *
+ * This routine waits up to ql4xdiscoverywait seconds
+ * F/W database during driver load time.
+ **/
+static int qla4xxx_devices_ready(struct scsi_qla_host *ha)
+{
+ int error;
+ unsigned long discovery_wtime;
+ struct qla4_relog_scan rs;
+
+ discovery_wtime = jiffies + (ql4xdiscoverywait * HZ);
+
+ DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait));
+ do {
+ /* poll for AEN. */
+ qla4xxx_get_firmware_state(ha);
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) {
+ /* Set time-between-relogin timer */
+ qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS);
+ }
+
+ /* if no relogins active or needed, halt discvery wait */
+ rs.halt_wait = 1;
+
+ error = qla4_scan_for_relogin(ha, &rs);
+
+ if (rs.halt_wait) {
+ DEBUG2(printk("scsi%ld: %s: Delay halted. Devices "
+ "Ready.\n", ha->host_no, __func__));
+ return QLA_SUCCESS;
+ }
+
+ msleep(2000);
+ } while (!time_after_eq(jiffies, discovery_wtime));
+
+ DEBUG3(qla4xxx_get_conn_event_log(ha));
+
+ return QLA_SUCCESS;
+}
+
+static void qla4xxx_flush_AENS(struct scsi_qla_host *ha)
+{
+ unsigned long wtime;
+
+ /* Flush the 0x8014 AEN from the firmware as a result of
+ * Auto connect. We are basically doing get_firmware_ddb()
+ * to determine whether we need to log back in or not.
+ * Trying to do a set ddb before we have processed 0x8014
+ * will result in another set_ddb() for the same ddb. In other
+ * words there will be stale entries in the aen_q.
+ */
+ wtime = jiffies + (2 * HZ);
+ do {
+ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS)
+ if (ha->firmware_state & (BIT_2 | BIT_0))
+ return;
+
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ msleep(1000);
+ } while (!time_after_eq(jiffies, wtime));
+
+}
+
+static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
+{
+ uint16_t fw_ddb_index;
+ int status = QLA_SUCCESS;
+
+ /* free the ddb list if is not empty */
+ if (!list_empty(&ha->ddb_list))
+ qla4xxx_free_ddb_list(ha);
+
+ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++)
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+
+ ha->tot_ddbs = 0;
+
+ qla4xxx_flush_AENS(ha);
+
+ /*
+ * First perform device discovery for active
+ * fw ddb indexes and build
+ * ddb list.
+ */
+ if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR)
+ return status;
+
+ /* Wait for an AEN */
+ qla4xxx_devices_ready(ha);
+
+ /*
+ * Targets can come online after the inital discovery, so processing
+ * the aens here will catch them.
+ */
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
+
+ return status;
+}
+
+/**
+ * qla4xxx_update_ddb_list - update the driver ddb list
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine obtains device information from the F/W database after
+ * firmware or adapter resets. The device table is preserved.
+ **/
+int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+ struct ddb_entry *ddb_entry, *detemp;
+
+ /* Update the device information for all devices. */
+ list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) {
+ qla4xxx_update_ddb_entry(ha, ddb_entry,
+ ddb_entry->fw_ddb_index);
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
+ "ONLINE\n", ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ }
+ return status;
+}
+
+/**
+ * qla4xxx_relogin_device - re-establish session
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ *
+ * This routine does a session relogin with the specified device.
+ * The ddb entry must be assigned prior to making this call.
+ **/
+int qla4xxx_relogin_device(struct scsi_qla_host *ha,
+ struct ddb_entry * ddb_entry)
+{
+ uint16_t relogin_timer;
+
+ relogin_timer = max(ddb_entry->default_relogin_timeout,
+ (uint16_t)RELOGIN_TOV);
+ atomic_set(&ddb_entry->relogin_timer, relogin_timer);
+
+ DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
+ ddb_entry->fw_ddb_index, relogin_timer));
+
+ qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
+
+ return QLA_SUCCESS;
+}
+
+static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+ union external_hw_config_reg extHwConfig;
+
+ DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no,
+ __func__));
+ if (ql4xxx_lock_flash(ha) != QLA_SUCCESS)
+ return (QLA_ERROR);
+ if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) {
+ ql4xxx_unlock_flash(ha);
+ return (QLA_ERROR);
+ }
+
+ /* Get EEPRom Parameters from NVRAM and validate */
+ dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n");
+ if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ extHwConfig.Asuint32_t =
+ rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ } else {
+ /*
+ * QLogic adapters should always have a valid NVRAM.
+ * If not valid, do not load.
+ */
+ dev_warn(&ha->pdev->dev,
+ "scsi%ld: %s: EEProm checksum invalid. "
+ "Please update your EEPROM\n", ha->host_no,
+ __func__);
+
+ /* set defaults */
+ if (is_qla4010(ha))
+ extHwConfig.Asuint32_t = 0x1912;
+ else if (is_qla4022(ha) | is_qla4032(ha))
+ extHwConfig.Asuint32_t = 0x0023;
+ }
+ DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n",
+ ha->host_no, __func__, extHwConfig.Asuint32_t));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha));
+ readl(isp_ext_hw_conf(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ ql4xxx_unlock_nvram(ha);
+ ql4xxx_unlock_flash(ha);
+
+ return (QLA_SUCCESS);
+}
+
+static void qla4x00_pci_config(struct scsi_qla_host *ha)
+{
+ uint16_t w, mwi;
+
+ dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
+
+ pci_set_master(ha->pdev);
+ mwi = 0;
+ if (pci_set_mwi(ha->pdev))
+ mwi = PCI_COMMAND_INVALIDATE;
+ /*
+ * We want to respect framework's setting of PCI configuration space
+ * command register and also want to make sure that all bits of
+ * interest to us are properly set in command register.
+ */
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+}
+
+static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
+{
+ int status = QLA_ERROR;
+ uint32_t max_wait_time;
+ unsigned long flags;
+ uint32_t mbox_status;
+
+ dev_info(&ha->pdev->dev, "Starting firmware ...\n");
+
+ /*
+ * Start firmware from flash ROM
+ *
+ * WORKAROUND: Stuff a non-constant value that the firmware can
+ * use as a seed for a random number generator in MB7 prior to
+ * setting BOOT_ENABLE. Fixes problem where the TCP
+ * connections use the same TCP ports after each reboot,
+ * causing some connections to not get re-established.
+ */
+ DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n",
+ ha->host_no, __func__));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(jiffies, &ha->reg->mailbox[7]);
+ if (is_qla4022(ha) | is_qla4032(ha))
+ writel(set_rmask(NVR_WRITE_ENABLE),
+ &ha->reg->u1.isp4022.nvram);
+
+ writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait for firmware to come UP. */
+ max_wait_time = FIRMWARE_UP_TOV * 4;
+ do {
+ uint32_t ctrl_status;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ mbox_status = readw(&ha->reg->mailbox[0]);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR))
+ break;
+ if (mbox_status == MBOX_STS_COMMAND_COMPLETE)
+ break;
+
+ DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to "
+ "complete... ctrl_sts=0x%x, remaining=%d\n",
+ ha->host_no, __func__, ctrl_status,
+ max_wait_time));
+
+ msleep(250);
+ } while ((max_wait_time--));
+
+ if (mbox_status == MBOX_STS_COMMAND_COMPLETE) {
+ DEBUG(printk("scsi%ld: %s: Firmware has started\n",
+ ha->host_no, __func__));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ status = QLA_SUCCESS;
+ } else {
+ printk(KERN_INFO "scsi%ld: %s: Boot firmware failed "
+ "- mbox status 0x%x\n", ha->host_no, __func__,
+ mbox_status);
+ status = QLA_ERROR;
+ }
+ return status;
+}
+
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
+{
+#define QL4_LOCK_DRVR_WAIT 300
+#define QL4_LOCK_DRVR_SLEEP 100
+
+ int drvr_wait = QL4_LOCK_DRVR_WAIT;
+ while (drvr_wait) {
+ if (ql4xxx_lock_drvr(a) == 0) {
+ msleep(QL4_LOCK_DRVR_SLEEP);
+ if (drvr_wait) {
+ DEBUG2(printk("scsi%ld: %s: Waiting for "
+ "Global Init Semaphore...n",
+ a->host_no,
+ __func__));
+ }
+ drvr_wait -= QL4_LOCK_DRVR_SLEEP;
+ } else {
+ DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
+ "acquired.n", a->host_no, __func__));
+ return QLA_SUCCESS;
+ }
+ }
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_start_firmware - starts qla4xxx firmware
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine performs the neccessary steps to start the firmware for
+ * the QLA4010 adapter.
+ **/
+static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ uint32_t mbox_status;
+ int status = QLA_ERROR;
+ int soft_reset = 1;
+ int config_chip = 0;
+
+ if (is_qla4022(ha) | is_qla4032(ha))
+ ql4xxx_set_mac_number(ha);
+
+ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no,
+ __func__, readw(isp_port_ctrl(ha))));
+ DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no,
+ __func__, readw(isp_port_status(ha))));
+
+ /* Is Hardware already initialized? */
+ if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) {
+ DEBUG(printk("scsi%ld: %s: Hardware has already been "
+ "initialized\n", ha->host_no, __func__));
+
+ /* Receive firmware boot acknowledgement */
+ mbox_status = readw(&ha->reg->mailbox[0]);
+
+ DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= "
+ "0x%x\n", ha->host_no, __func__, mbox_status));
+
+ /* Is firmware already booted? */
+ if (mbox_status == 0) {
+ /* F/W not running, must be config by net driver */
+ config_chip = 1;
+ soft_reset = 0;
+ } else {
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: Get firmware "
+ "state -- state = 0x%x\n",
+ ha->host_no,
+ __func__, ha->firmware_state));
+ /* F/W is running */
+ if (ha->firmware_state &
+ FW_STATE_CONFIG_WAIT) {
+ DEBUG2(printk("scsi%ld: %s: Firmware "
+ "in known state -- "
+ "config and "
+ "boot, state = 0x%x\n",
+ ha->host_no, __func__,
+ ha->firmware_state));
+ config_chip = 1;
+ soft_reset = 0;
+ }
+ } else {
+ DEBUG2(printk("scsi%ld: %s: Firmware in "
+ "unknown state -- resetting,"
+ " state = "
+ "0x%x\n", ha->host_no, __func__,
+ ha->firmware_state));
+ }
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ } else {
+ DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been "
+ "started - resetting\n", ha->host_no, __func__));
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ",
+ ha->host_no, __func__, soft_reset, config_chip));
+ if (soft_reset) {
+ DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no,
+ __func__));
+ status = qla4xxx_soft_reset(ha);
+ if (status == QLA_ERROR) {
+ DEBUG(printk("scsi%d: %s: Soft Reset failed!\n",
+ ha->host_no, __func__));
+ ql4xxx_unlock_drvr(ha);
+ return QLA_ERROR;
+ }
+ config_chip = 1;
+
+ /* Reset clears the semaphore, so aquire again */
+ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+ }
+
+ if (config_chip) {
+ if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS)
+ status = qla4xxx_start_firmware_from_flash(ha);
+ }
+
+ ql4xxx_unlock_drvr(ha);
+ if (status == QLA_SUCCESS) {
+ qla4xxx_get_fw_version(ha);
+ if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags))
+ qla4xxx_get_crash_record(ha);
+ } else {
+ DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n",
+ ha->host_no, __func__));
+ }
+ return status;
+}
+
+
+/**
+ * qla4xxx_initialize_adapter - initiailizes hba
+ * @ha: Pointer to host adapter structure.
+ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+ * after adapter recovery has completed.
+ * 0=preserve ddb list, 1=destroy and rebuild ddb list
+ *
+ * This routine parforms all of the steps necessary to initialize the adapter.
+ *
+ **/
+int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
+ uint8_t renew_ddb_list)
+{
+ int status = QLA_ERROR;
+ int8_t ip_address[IP_ADDR_LEN] = {0} ;
+
+ ha->eeprom_cmd_data = 0;
+
+ qla4x00_pci_config(ha);
+
+ qla4xxx_disable_intrs(ha);
+
+ /* Initialize the Host adapter request/response queues and firmware */
+ if (qla4xxx_start_firmware(ha) == QLA_ERROR)
+ return status;
+
+ if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
+ return status;
+
+ if (qla4xxx_init_local_data(ha) == QLA_ERROR)
+ return status;
+
+ status = qla4xxx_init_firmware(ha);
+ if (status == QLA_ERROR)
+ return status;
+
+ /*
+ * FW is waiting to get an IP address from DHCP server: Skip building
+ * the ddb_list and wait for DHCP lease acquired aen to come in
+ * followed by 0x8014 aen" to trigger the tgt discovery process.
+ */
+ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
+ return status;
+
+ /* Skip device discovery if ip and subnet is zero */
+ if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 ||
+ memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0)
+ return status;
+
+ if (renew_ddb_list == PRESERVE_DDB_LIST) {
+ /*
+ * We want to preserve lun states (i.e. suspended, etc.)
+ * for recovery initiated by the driver. So just update
+ * the device states for the existing ddb_list.
+ */
+ qla4xxx_reinitialize_ddb_list(ha);
+ } else if (renew_ddb_list == REBUILD_DDB_LIST) {
+ /*
+ * We want to build the ddb_list from scratch during
+ * driver initialization and recovery initiated by the
+ * INT_HBA_RESET IOCTL.
+ */
+ status = qla4xxx_initialize_ddb_list(ha);
+ if (status == QLA_ERROR) {
+ DEBUG2(printk("%s(%ld) Error occurred during build"
+ "ddb list\n", __func__, ha->host_no));
+ goto exit_init_hba;
+ }
+
+ }
+ if (!ha->tot_ddbs) {
+ DEBUG2(printk("scsi%ld: Failed to initialize devices or none "
+ "present in Firmware device database\n",
+ ha->host_no));
+ }
+
+ exit_init_hba:
+ return status;
+
+}
+
+/**
+ * qla4xxx_add_device_dynamically - ddb addition due to an AEN
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ *
+ * This routine processes adds a device as a result of an 8014h AEN.
+ **/
+static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
+{
+ struct ddb_entry * ddb_entry;
+
+ /* First allocate a device structure */
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Unable to allocate memory to add "
+ "fw_ddb_index %d\n", ha->host_no, fw_ddb_index));
+ return;
+ }
+
+ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+ QLA_ERROR) {
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: failed to add new device at index "
+ "[%d]\n Unable to retrieve fw ddb entry\n",
+ ha->host_no, fw_ddb_index));
+ qla4xxx_free_ddb(ha, ddb_entry);
+ return;
+ }
+
+ if (qla4xxx_add_sess(ddb_entry)) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: failed to add new device at index "
+ "[%d]\n Unable to add connection and session\n",
+ ha->host_no, fw_ddb_index));
+ qla4xxx_free_ddb(ha, ddb_entry);
+ }
+}
+
+/**
+ * qla4xxx_process_ddb_changed - process ddb state change
+ * @ha - Pointer to host adapter structure.
+ * @fw_ddb_index - Firmware's device database index
+ * @state - Device state
+ *
+ * This routine processes a Decive Database Changed AEN Event.
+ **/
+int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index, uint32_t state)
+{
+ struct ddb_entry * ddb_entry;
+ uint32_t old_fw_ddb_device_state;
+
+ /* check for out of range index */
+ if (fw_ddb_index >= MAX_DDB_ENTRIES)
+ return QLA_ERROR;
+
+ /* Get the corresponging ddb entry */
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);
+ /* Device does not currently exist in our database. */
+ if (ddb_entry == NULL) {
+ if (state == DDB_DS_SESSION_ACTIVE)
+ qla4xxx_add_device_dynamically(ha, fw_ddb_index);
+ return QLA_SUCCESS;
+ }
+
+ /* Device already exists in our database. */
+ old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state;
+ DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for "
+ "index [%d]\n", ha->host_no, __func__,
+ ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
+ if (old_fw_ddb_device_state == state &&
+ state == DDB_DS_SESSION_ACTIVE) {
+ /* Do nothing, state not changed. */
+ return QLA_SUCCESS;
+ }
+
+ ddb_entry->fw_ddb_device_state = state;
+ /* Device is back online. */
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+ atomic_set(&ddb_entry->port_down_timer,
+ ha->port_down_retry_count);
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ atomic_set(&ddb_entry->relogin_retry_count, 0);
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ clear_bit(DF_RELOGIN, &ddb_entry->flags);
+ clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
+ iscsi_if_create_session_done(ddb_entry->conn);
+ /*
+ * Change the lun state to READY in case the lun TIMEOUT before
+ * the device came back.
+ */
+ } else {
+ /* Device went away, try to relogin. */
+ /* Mark device missing */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ /*
+ * Relogin if device state changed to a not active state.
+ * However, do not relogin if this aen is a result of an IOCTL
+ * logout (DF_NO_RELOGIN) or if this is a discovered device.
+ */
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
+ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
+ !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
+ /*
+ * This triggers a relogin. After the relogin_timer
+ * expires, the relogin gets scheduled. We must wait a
+ * minimum amount of time since receiving an 0x8014 AEN
+ * with failed device_state or a logout response before
+ * we can issue another relogin.
+ */
+ /* Firmware padds this timeout: (time2wait +1).
+ * Driver retry to login should be longer than F/W.
+ * Otherwise F/W will fail
+ * set_ddb() mbx cmd with 0x4005 since it still
+ * counting down its time2wait.
+ */
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ atomic_set(&ddb_entry->retry_relogin_timer,
+ ddb_entry->default_time2wait + 4);
+ }
+ }
+
+ return QLA_SUCCESS;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
new file mode 100644
index 00000000000..6375eb017dd
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -0,0 +1,84 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+/*
+ *
+ * qla4xxx_lookup_ddb_by_fw_index
+ * This routine locates a device handle given the firmware device
+ * database index. If device doesn't exist, returns NULL.
+ *
+ * Input:
+ * ha - Pointer to host adapter structure.
+ * fw_ddb_index - Firmware's device database index
+ *
+ * Returns:
+ * Pointer to the corresponding internal device database structure
+ */
+static inline struct ddb_entry *
+qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
+{
+ struct ddb_entry *ddb_entry = NULL;
+
+ if ((fw_ddb_index < MAX_DDB_ENTRIES) &&
+ (ha->fw_ddb_index_map[fw_ddb_index] !=
+ (struct ddb_entry *) INVALID_ENTRY)) {
+ ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
+ }
+
+ DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
+ ha->host_no, __func__, fw_ddb_index, ddb_entry));
+
+ return ddb_entry;
+}
+
+static inline void
+__qla4xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+ if (is_qla4022(ha) | is_qla4032(ha)) {
+ writel(set_rmask(IMR_SCSI_INTR_ENABLE),
+ &ha->reg->u1.isp4022.intr_mask);
+ readl(&ha->reg->u1.isp4022.intr_mask);
+ } else {
+ writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ set_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+static inline void
+__qla4xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+ if (is_qla4022(ha) | is_qla4032(ha)) {
+ writel(clr_rmask(IMR_SCSI_INTR_ENABLE),
+ &ha->reg->u1.isp4022.intr_mask);
+ readl(&ha->reg->u1.isp4022.intr_mask);
+ } else {
+ writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ clear_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+static inline void
+qla4xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __qla4xxx_enable_intrs(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static inline void
+qla4xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __qla4xxx_disable_intrs(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
new file mode 100644
index 00000000000..d41ce380eed
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -0,0 +1,374 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+#include <scsi/scsi_tcq.h>
+
+/**
+ * qla4xxx_get_req_pkt - returns a valid entry in request queue.
+ * @ha: Pointer to host adapter structure.
+ * @queue_entry: Pointer to pointer to queue entry structure
+ *
+ * This routine performs the following tasks:
+ * - returns the current request_in pointer (if queue not full)
+ * - advances the request_in pointer
+ * - checks for queue full
+ **/
+int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+ struct queue_entry **queue_entry)
+{
+ uint16_t request_in;
+ uint8_t status = QLA_SUCCESS;
+
+ *queue_entry = ha->request_ptr;
+
+ /* get the latest request_in and request_out index */
+ request_in = ha->request_in;
+ ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+
+ /* Advance request queue pointer and check for queue full */
+ if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ request_in++;
+ ha->request_ptr++;
+ }
+
+ /* request queue is full, try again later */
+ if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
+ /* restore request pointer */
+ ha->request_ptr = *queue_entry;
+ status = QLA_ERROR;
+ } else {
+ ha->request_in = request_in;
+ memset(*queue_entry, 0, sizeof(**queue_entry));
+ }
+
+ return status;
+}
+
+/**
+ * qla4xxx_send_marker_iocb - issues marker iocb to HBA
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ * @lun: SCSI LUN
+ * @marker_type: marker identifier
+ *
+ * This routine issues a marker IOCB.
+ **/
+int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry, int lun)
+{
+ struct marker_entry *marker_entry;
+ unsigned long flags = 0;
+ uint8_t status = QLA_SUCCESS;
+
+ /* Acquire hardware specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Get pointer to the queue entry for the marker */
+ if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) !=
+ QLA_SUCCESS) {
+ status = QLA_ERROR;
+ goto exit_send_marker;
+ }
+
+ /* Put the marker in the request queue */
+ marker_entry->hdr.entryType = ET_MARKER;
+ marker_entry->hdr.entryCount = 1;
+ marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
+ marker_entry->modifier = cpu_to_le16(MM_LUN_RESET);
+ int_to_scsilun(lun, &marker_entry->lun);
+ wmb();
+
+ /* Tell ISP it's got a new I/O request */
+ writel(ha->request_in, &ha->reg->req_q_in);
+ readl(&ha->reg->req_q_in);
+
+exit_send_marker:
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return status;
+}
+
+struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+ struct scsi_qla_host *ha)
+{
+ struct continuation_t1_entry *cont_entry;
+
+ cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
+
+ /* Advance request queue pointer */
+ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ ha->request_in++;
+ ha->request_ptr++;
+ }
+
+ /* Load packet defaults */
+ cont_entry->hdr.entryType = ET_CONTINUE;
+ cont_entry->hdr.entryCount = 1;
+ cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in);
+
+ return cont_entry;
+}
+
+uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+{
+ uint16_t iocbs;
+
+ iocbs = 1;
+ if (dsds > COMMAND_SEG) {
+ iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG;
+ if ((dsds - COMMAND_SEG) % CONTINUE_SEG)
+ iocbs++;
+ }
+ return iocbs;
+}
+
+void qla4xxx_build_scsi_iocbs(struct srb *srb,
+ struct command_t3_entry *cmd_entry,
+ uint16_t tot_dsds)
+{
+ struct scsi_qla_host *ha;
+ uint16_t avail_dsds;
+ struct data_seg_a64 *cur_dsd;
+ struct scsi_cmnd *cmd;
+
+ cmd = srb->cmd;
+ ha = srb->ha;
+
+ if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ /* No data being transferred */
+ cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
+ return;
+ }
+
+ avail_dsds = COMMAND_SEG;
+ cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
+
+ /* Load data segments */
+ if (cmd->use_sg) {
+ struct scatterlist *cur_seg;
+ struct scatterlist *end_seg;
+
+ cur_seg = (struct scatterlist *)cmd->request_buffer;
+ end_seg = cur_seg + tot_dsds;
+ while (cur_seg < end_seg) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ struct continuation_t1_entry *cont_entry;
+
+ cont_entry = qla4xxx_alloc_cont_entry(ha);
+ cur_dsd =
+ (struct data_seg_a64 *)
+ &cont_entry->dataseg[0];
+ avail_dsds = CONTINUE_SEG;
+ }
+
+ sle_dma = sg_dma_address(cur_seg);
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
+ cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
+ avail_dsds--;
+
+ cur_dsd++;
+ cur_seg++;
+ }
+ } else {
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
+ cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
+ }
+}
+
+/**
+ * qla4xxx_send_command_to_isp - issues command to HBA
+ * @ha: pointer to host adapter structure.
+ * @srb: pointer to SCSI Request Block to be sent to ISP
+ *
+ * This routine is called by qla4xxx_queuecommand to build an ISP
+ * command and pass it to the ISP for execution.
+ **/
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+ struct ddb_entry *ddb_entry;
+ struct command_t3_entry *cmd_entry;
+ struct scatterlist *sg = NULL;
+
+ uint16_t tot_dsds;
+ uint16_t req_cnt;
+
+ unsigned long flags;
+ uint16_t cnt;
+ uint32_t index;
+ char tag[2];
+
+ /* Get real lun and adapter */
+ ddb_entry = srb->ddb;
+
+ /* Send marker(s) if needed. */
+ if (ha->marker_needed == 1) {
+ if (qla4xxx_send_marker_iocb(ha, ddb_entry,
+ cmd->device->lun) != QLA_SUCCESS)
+ return QLA_ERROR;
+
+ ha->marker_needed = 0;
+ }
+ tot_dsds = 0;
+
+ /* Acquire hardware specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ index = (uint32_t)cmd->request->tag;
+
+ /* Calculate the number of request entries needed. */
+ if (cmd->use_sg) {
+ sg = (struct scatterlist *)cmd->request_buffer;
+ tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+ cmd->sc_data_direction);
+ if (tot_dsds == 0)
+ goto queuing_error;
+ } else if (cmd->request_bufflen) {
+ dma_addr_t req_dma;
+
+ req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
+ cmd->request_bufflen,
+ cmd->sc_data_direction);
+ if (dma_mapping_error(req_dma))
+ goto queuing_error;
+
+ srb->dma_handle = req_dma;
+ tot_dsds = 1;
+ }
+ req_cnt = qla4xxx_calc_request_entries(tot_dsds);
+
+ if (ha->req_q_count < (req_cnt + 2)) {
+ cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+ if (ha->request_in < cnt)
+ ha->req_q_count = cnt - ha->request_in;
+ else
+ ha->req_q_count = REQUEST_QUEUE_DEPTH -
+ (ha->request_in - cnt);
+ }
+
+ if (ha->req_q_count < (req_cnt + 2))
+ goto queuing_error;
+
+ /* total iocbs active */
+ if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH)
+ goto queuing_error;
+
+ /* Build command packet */
+ cmd_entry = (struct command_t3_entry *) ha->request_ptr;
+ memset(cmd_entry, 0, sizeof(struct command_t3_entry));
+ cmd_entry->hdr.entryType = ET_COMMAND;
+ cmd_entry->handle = cpu_to_le32(index);
+ cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
+ cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id);
+
+ int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
+ cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
+ cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
+ memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
+ cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
+ cmd_entry->hdr.entryCount = req_cnt;
+
+ /* Set data transfer direction control flags
+ * NOTE: Look at data_direction bits iff there is data to be
+ * transferred, as the data direction bit is sometimed filled
+ * in when there is no data to be transferred */
+ cmd_entry->control_flags = CF_NO_DATA;
+ if (cmd->request_bufflen) {
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ cmd_entry->control_flags = CF_WRITE;
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ cmd_entry->control_flags = CF_READ;
+
+ ha->bytes_xfered += cmd->request_bufflen;
+ if (ha->bytes_xfered & ~0xFFFFF){
+ ha->total_mbytes_xferred += ha->bytes_xfered >> 20;
+ ha->bytes_xfered &= 0xFFFFF;
+ }
+ }
+
+ /* Set tagged queueing control flags */
+ cmd_entry->control_flags |= CF_SIMPLE_TAG;
+ if (scsi_populate_tag_msg(cmd, tag))
+ switch (tag[0]) {
+ case MSG_HEAD_TAG:
+ cmd_entry->control_flags |= CF_HEAD_TAG;
+ break;
+ case MSG_ORDERED_TAG:
+ cmd_entry->control_flags |= CF_ORDERED_TAG;
+ break;
+ }
+
+
+ /* Advance request queue pointer */
+ ha->request_in++;
+ if (ha->request_in == REQUEST_QUEUE_DEPTH) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else
+ ha->request_ptr++;
+
+
+ qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
+ wmb();
+
+ /*
+ * Check to see if adapter is online before placing request on
+ * request queue. If a reset occurs and a request is in the queue,
+ * the firmware will still attempt to process the request, retrieving
+ * garbage for pointers.
+ */
+ if (!test_bit(AF_ONLINE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
+ "Do not issue command.\n",
+ ha->host_no, __func__));
+ goto queuing_error;
+ }
+
+ srb->cmd->host_scribble = (unsigned char *)srb;
+
+ /* update counters */
+ srb->state = SRB_ACTIVE_STATE;
+ srb->flags |= SRB_DMA_VALID;
+
+ /* Track IOCB used */
+ ha->iocb_cnt += req_cnt;
+ srb->iocb_cnt = req_cnt;
+ ha->req_q_count -= req_cnt;
+
+ /* Debug print statements */
+ writel(ha->request_in, &ha->reg->req_q_in);
+ readl(&ha->reg->req_q_in);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
+
+queuing_error:
+
+ if (cmd->use_sg && tot_dsds) {
+ sg = (struct scatterlist *) cmd->request_buffer;
+ pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
+ cmd->sc_data_direction);
+ } else if (tot_dsds)
+ pci_unmap_single(ha->pdev, srb->dma_handle,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_ERROR;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
new file mode 100644
index 00000000000..ef975e0dc87
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -0,0 +1,797 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+/**
+ * qla2x00_process_completed_request() - Process a Fast Post response.
+ * @ha: SCSI driver HA context
+ * @index: SRB index
+ **/
+static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,
+ uint32_t index)
+{
+ struct srb *srb;
+
+ srb = qla4xxx_del_from_active_array(ha, index);
+ if (srb) {
+ /* Save ISP completion status */
+ srb->cmd->result = DID_OK << 16;
+ qla4xxx_srb_compl(ha, srb);
+ } else {
+ DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "
+ "%d\n", ha->host_no, index));
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+}
+
+/**
+ * qla4xxx_status_entry - processes status IOCBs
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ **/
+static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+ struct status_entry *sts_entry)
+{
+ uint8_t scsi_status;
+ struct scsi_cmnd *cmd;
+ struct srb *srb;
+ struct ddb_entry *ddb_entry;
+ uint32_t residual;
+ uint16_t sensebytecnt;
+
+ if (sts_entry->completionStatus == SCS_COMPLETE &&
+ sts_entry->scsiStatus == 0) {
+ qla4xxx_process_completed_request(ha,
+ le32_to_cpu(sts_entry->
+ handle));
+ return;
+ }
+
+ srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
+ if (!srb) {
+ /* FIXMEdg: Don't we need to reset ISP in this case??? */
+ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
+ "handle 0x%x, sp=%p. This cmd may have already "
+ "been completed.\n", ha->host_no, __func__,
+ le32_to_cpu(sts_entry->handle), srb));
+ return;
+ }
+
+ cmd = srb->cmd;
+ if (cmd == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Command already returned back to "
+ "OS pkt->handle=%d srb=%p srb->state:%d\n",
+ ha->host_no, __func__, sts_entry->handle,
+ srb, srb->state));
+ dev_warn(&ha->pdev->dev, "Command is NULL:"
+ " already returned to OS (srb=%p)\n", srb);
+ return;
+ }
+
+ ddb_entry = srb->ddb;
+ if (ddb_entry == NULL) {
+ cmd->result = DID_NO_CONNECT << 16;
+ goto status_entry_exit;
+ }
+
+ residual = le32_to_cpu(sts_entry->residualByteCnt);
+
+ /* Translate ISP error to a Linux SCSI error. */
+ scsi_status = sts_entry->scsiStatus;
+ switch (sts_entry->completionStatus) {
+ case SCS_COMPLETE:
+ if (scsi_status == 0) {
+ cmd->result = DID_OK << 16;
+ break;
+ }
+
+ if (sts_entry->iscsiFlags &
+ (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
+ cmd->resid = residual;
+
+ cmd->result = DID_OK << 16 | scsi_status;
+
+ if (scsi_status != SCSI_CHECK_CONDITION)
+ break;
+
+ /* Copy Sense Data into sense buffer. */
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+ sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sensebytecnt == 0)
+ break;
+
+ memcpy(cmd->sense_buffer, sts_entry->senseData,
+ min(sensebytecnt,
+ (uint16_t) sizeof(cmd->sense_buffer)));
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+
+ srb->flags |= SRB_GOT_SENSE;
+ break;
+
+ case SCS_INCOMPLETE:
+ /* Always set the status to DID_ERROR, since
+ * all conditions result in that status anyway */
+ cmd->result = DID_ERROR << 16;
+ break;
+
+ case SCS_RESET_OCCURRED:
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun, __func__));
+
+ cmd->result = DID_RESET << 16;
+ break;
+
+ case SCS_ABORTED:
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun, __func__));
+
+ cmd->result = DID_RESET << 16;
+ break;
+
+ case SCS_TIMEOUT:
+ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun));
+
+ cmd->result = DID_BUS_BUSY << 16;
+
+ /*
+ * Mark device missing so that we won't continue to send
+ * I/O to this device. We should get a ddb state change
+ * AEN soon.
+ */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ break;
+
+ case SCS_DATA_UNDERRUN:
+ case SCS_DATA_OVERRUN:
+ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__, residual));
+
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+ if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
+ /*
+ * Firmware detected a SCSI transport underrun
+ * condition
+ */
+ cmd->resid = residual;
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
+ "detected, xferlen = 0x%x, residual = "
+ "0x%x\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ cmd->request_bufflen,
+ residual));
+ }
+
+ /*
+ * If there is scsi_status, it takes precedense over
+ * underflow condition.
+ */
+ if (scsi_status != 0) {
+ cmd->result = DID_OK << 16 | scsi_status;
+
+ if (scsi_status != SCSI_CHECK_CONDITION)
+ break;
+
+ /* Copy Sense Data into sense buffer. */
+ memset(cmd->sense_buffer, 0,
+ sizeof(cmd->sense_buffer));
+
+ sensebytecnt =
+ le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sensebytecnt == 0)
+ break;
+
+ memcpy(cmd->sense_buffer, sts_entry->senseData,
+ min(sensebytecnt,
+ (uint16_t) sizeof(cmd->sense_buffer)));
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+ } else {
+ /*
+ * If RISC reports underrun and target does not
+ * report it then we must have a lost frame, so
+ * tell upper layer to retry it by reporting a
+ * bus busy.
+ */
+ if ((sts_entry->iscsiFlags &
+ ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
+ cmd->result = DID_BUS_BUSY << 16;
+ } else if ((cmd->request_bufflen - residual) <
+ cmd->underflow) {
+ /*
+ * Handle mid-layer underflow???
+ *
+ * For kernels less than 2.4, the driver must
+ * return an error if an underflow is detected.
+ * For kernels equal-to and above 2.4, the
+ * mid-layer will appearantly handle the
+ * underflow by detecting the residual count --
+ * unfortunately, we do not see where this is
+ * actually being done. In the interim, we
+ * will return DID_ERROR.
+ */
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+ "Mid-layer Data underrun, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ cmd->request_bufflen, residual));
+
+ cmd->result = DID_ERROR << 16;
+ } else {
+ cmd->result = DID_OK << 16;
+ }
+ }
+ break;
+
+ case SCS_DEVICE_LOGGED_OUT:
+ case SCS_DEVICE_UNAVAILABLE:
+ /*
+ * Mark device missing so that we won't continue to
+ * send I/O to this device. We should get a ddb
+ * state change AEN soon.
+ */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+
+ cmd->result = DID_BUS_BUSY << 16;
+ break;
+
+ case SCS_QUEUE_FULL:
+ /*
+ * SCSI Mid-Layer handles device queue full
+ */
+ cmd->result = DID_OK << 16 | sts_entry->scsiStatus;
+ DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected "
+ "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"
+ " iResp=%02x\n", ha->host_no, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->completionStatus,
+ sts_entry->scsiStatus, sts_entry->state_flags,
+ sts_entry->iscsiFlags,
+ sts_entry->iscsiResponse));
+ break;
+
+ default:
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+status_entry_exit:
+
+ /* complete the request */
+ srb->cc_stat = sts_entry->completionStatus;
+ qla4xxx_srb_compl(ha, srb);
+}
+
+/**
+ * qla4xxx_process_response_queue - process response queue completions
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine process response queue completions in interrupt context.
+ * Hardware_lock locked upon entry
+ **/
+static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
+{
+ uint32_t count = 0;
+ struct srb *srb = NULL;
+ struct status_entry *sts_entry;
+
+ /* Process all responses from response queue */
+ while ((ha->response_in =
+ (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
+ ha->response_out) {
+ sts_entry = (struct status_entry *) ha->response_ptr;
+ count++;
+
+ /* Advance pointers for next entry */
+ if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {
+ ha->response_out = 0;
+ ha->response_ptr = ha->response_ring;
+ } else {
+ ha->response_out++;
+ ha->response_ptr++;
+ }
+
+ /* process entry */
+ switch (sts_entry->hdr.entryType) {
+ case ET_STATUS:
+ /*
+ * Common status - Single completion posted in single
+ * IOSB.
+ */
+ qla4xxx_status_entry(ha, sts_entry);
+ break;
+
+ case ET_PASSTHRU_STATUS:
+ break;
+
+ case ET_STATUS_CONTINUATION:
+ /* Just throw away the status continuation entries */
+ DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
+ "- ignoring\n", ha->host_no, __func__));
+ break;
+
+ case ET_COMMAND:
+ /* ISP device queue is full. Command not
+ * accepted by ISP. Queue command for
+ * later */
+
+ srb = qla4xxx_del_from_active_array(ha,
+ le32_to_cpu(sts_entry->
+ handle));
+ if (srb == NULL)
+ goto exit_prq_invalid_handle;
+
+ DEBUG2(printk("scsi%ld: %s: FW device queue full, "
+ "srb %p\n", ha->host_no, __func__, srb));
+
+ /* ETRY normally by sending it back with
+ * DID_BUS_BUSY */
+ srb->cmd->result = DID_BUS_BUSY << 16;
+ qla4xxx_srb_compl(ha, srb);
+ break;
+
+ case ET_CONTINUE:
+ /* Just throw away the continuation entries */
+ DEBUG2(printk("scsi%ld: %s: Continuation entry - "
+ "ignoring\n", ha->host_no, __func__));
+ break;
+
+ default:
+ /*
+ * Invalid entry in response queue, reset RISC
+ * firmware.
+ */
+ DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "
+ "response queue \n", ha->host_no,
+ __func__,
+ sts_entry->hdr.entryType));
+ goto exit_prq_error;
+ }
+ }
+
+ /*
+ * Done with responses, update the ISP For QLA4010, this also clears
+ * the interrupt.
+ */
+ writel(ha->response_out, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ return;
+
+exit_prq_invalid_handle:
+ DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",
+ ha->host_no, __func__, srb, sts_entry->hdr.entryType,
+ sts_entry->completionStatus));
+
+exit_prq_error:
+ writel(ha->response_out, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+}
+
+/**
+ * qla4xxx_isr_decode_mailbox - decodes mailbox status
+ * @ha: Pointer to host adapter structure.
+ * @mailbox_status: Mailbox status.
+ *
+ * This routine decodes the mailbox status during the ISR.
+ * Hardware_lock locked upon entry. runs in interrupt context.
+ **/
+static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
+ uint32_t mbox_status)
+{
+ int i;
+
+ if ((mbox_status == MBOX_STS_BUSY) ||
+ (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
+ (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {
+ ha->mbox_status[0] = mbox_status;
+
+ if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
+ /*
+ * Copy all mailbox registers to a temporary
+ * location and set mailbox command done flag
+ */
+ for (i = 1; i < ha->mbox_status_count; i++)
+ ha->mbox_status[i] =
+ readl(&ha->reg->mailbox[i]);
+
+ set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ wake_up(&ha->mailbox_wait_queue);
+ }
+ } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
+ /* Immediately process the AENs that don't require much work.
+ * Only queue the database_changed AENs */
+ switch (mbox_status) {
+ case MBOX_ASTS_SYSTEM_ERROR:
+ /* Log Mailbox registers */
+ if (ql4xdontresethba) {
+ DEBUG2(printk("%s:Dont Reset HBA\n",
+ __func__));
+ } else {
+ set_bit(AF_GET_CRASH_RECORD, &ha->flags);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+ break;
+
+ case MBOX_ASTS_REQUEST_TRANSFER_ERROR:
+ case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:
+ case MBOX_ASTS_NVRAM_INVALID:
+ case MBOX_ASTS_IP_ADDRESS_CHANGED:
+ case MBOX_ASTS_DHCP_LEASE_EXPIRED:
+ DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
+ "Reset HA\n", ha->host_no, mbox_status));
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ break;
+
+ case MBOX_ASTS_LINK_UP:
+ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n",
+ ha->host_no, mbox_status));
+ set_bit(AF_LINK_UP, &ha->flags);
+ break;
+
+ case MBOX_ASTS_LINK_DOWN:
+ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n",
+ ha->host_no, mbox_status));
+ clear_bit(AF_LINK_UP, &ha->flags);
+ break;
+
+ case MBOX_ASTS_HEARTBEAT:
+ ha->seconds_since_last_heartbeat = 0;
+ break;
+
+ case MBOX_ASTS_DHCP_LEASE_ACQUIRED:
+ DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "
+ "ACQUIRED\n", ha->host_no, mbox_status));
+ set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+ break;
+
+ case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:
+ case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target
+ * mode
+ * only */
+ case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */
+ case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
+ case MBOX_ASTS_SUBNET_STATE_CHANGE:
+ /* No action */
+ DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
+ mbox_status));
+ break;
+
+ case MBOX_ASTS_MAC_ADDRESS_CHANGED:
+ case MBOX_ASTS_DNS:
+ /* No action */
+ DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
+ "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
+ ha->host_no, mbox_status,
+ readl(&ha->reg->mailbox[1]),
+ readl(&ha->reg->mailbox[2])));
+ break;
+
+ case MBOX_ASTS_SELF_TEST_FAILED:
+ case MBOX_ASTS_LOGIN_FAILED:
+ /* No action */
+ DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
+ "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
+ ha->host_no, mbox_status,
+ readl(&ha->reg->mailbox[1]),
+ readl(&ha->reg->mailbox[2]),
+ readl(&ha->reg->mailbox[3])));
+ break;
+
+ case MBOX_ASTS_DATABASE_CHANGED:
+ /* Queue AEN information and process it in the DPC
+ * routine */
+ if (ha->aen_q_count > 0) {
+ /* advance pointer */
+ if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
+ ha->aen_in = 0;
+ else
+ ha->aen_in++;
+
+ /* decrement available counter */
+ ha->aen_q_count--;
+
+ for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
+ ha->aen_q[ha->aen_in].mbox_sts[i] =
+ readl(&ha->reg->mailbox[i]);
+
+ ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
+
+ /* print debug message */
+ DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
+ " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
+ ha->host_no, ha->aen_in,
+ mbox_status,
+ ha->aen_q[ha->aen_in].mbox_sts[1],
+ ha->aen_q[ha->aen_in].mbox_sts[2],
+ ha->aen_q[ha->aen_in].mbox_sts[3],
+ ha->aen_q[ha->aen_in]. mbox_sts[4]));
+
+ /* The DPC routine will process the aen */
+ set_bit(DPC_AEN, &ha->dpc_flags);
+ } else {
+ DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
+ "overflowed! AEN LOST!!\n",
+ ha->host_no, __func__,
+ mbox_status));
+
+ DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
+ ha->host_no));
+
+ for (i = 0; i < MAX_AEN_ENTRIES; i++) {
+ DEBUG2(printk("AEN[%d] %04x %04x %04x "
+ "%04x\n", i,
+ ha->aen_q[i].mbox_sts[0],
+ ha->aen_q[i].mbox_sts[1],
+ ha->aen_q[i].mbox_sts[2],
+ ha->aen_q[i].mbox_sts[3]));
+ }
+ }
+ break;
+
+ default:
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: AEN %04x UNKNOWN\n",
+ ha->host_no, mbox_status));
+ break;
+ }
+ } else {
+ DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",
+ ha->host_no, mbox_status));
+
+ ha->mbox_status[0] = mbox_status;
+ }
+}
+
+/**
+ * qla4xxx_interrupt_service_routine - isr
+ * @ha: pointer to host adapter structure.
+ *
+ * This is the main interrupt service routine.
+ * hardware_lock locked upon entry. runs in interrupt context.
+ **/
+void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+ uint32_t intr_status)
+{
+ /* Process response queue interrupt. */
+ if (intr_status & CSR_SCSI_COMPLETION_INTR)
+ qla4xxx_process_response_queue(ha);
+
+ /* Process mailbox/asynch event interrupt.*/
+ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+ qla4xxx_isr_decode_mailbox(ha,
+ readl(&ha->reg->mailbox[0]));
+
+ /* Clear Mailbox Interrupt */
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+}
+
+/**
+ * qla4xxx_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ **/
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha;
+ uint32_t intr_status;
+ unsigned long flags = 0;
+ uint8_t reqs_count = 0;
+
+ ha = (struct scsi_qla_host *) dev_id;
+ if (!ha) {
+ DEBUG2(printk(KERN_INFO
+ "qla4xxx: Interrupt with NULL host ptr\n"));
+ return IRQ_NONE;
+ }
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ ha->isr_count++;
+ /*
+ * Repeatedly service interrupts up to a maximum of
+ * MAX_REQS_SERVICED_PER_INTR
+ */
+ while (1) {
+ /*
+ * Read interrupt status
+ */
+ if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
+ ha->response_out)
+ intr_status = CSR_SCSI_COMPLETION_INTR;
+ else
+ intr_status = readl(&ha->reg->ctrl_status);
+
+ if ((intr_status &
+ (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
+ 0) {
+ if (reqs_count == 0)
+ ha->spurious_int_count++;
+ break;
+ }
+
+ if (intr_status & CSR_FATAL_ERROR) {
+ DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, "
+ "Status 0x%04x\n", ha->host_no,
+ readl(isp_port_error_status (ha))));
+
+ /* Issue Soft Reset to clear this error condition.
+ * This will prevent the RISC from repeatedly
+ * interrupting the driver; thus, allowing the DPC to
+ * get scheduled to continue error recovery.
+ * NOTE: Disabling RISC interrupts does not work in
+ * this case, as CSR_FATAL_ERROR overrides
+ * CSR_SCSI_INTR_ENABLE */
+ if ((readl(&ha->reg->ctrl_status) &
+ CSR_SCSI_RESET_INTR) == 0) {
+ writel(set_rmask(CSR_SOFT_RESET),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+
+ writel(set_rmask(CSR_FATAL_ERROR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ __qla4xxx_disable_intrs(ha);
+
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+
+ break;
+ } else if (intr_status & CSR_SCSI_RESET_INTR) {
+ clear_bit(AF_ONLINE, &ha->flags);
+ __qla4xxx_disable_intrs(ha);
+
+ writel(set_rmask(CSR_SCSI_RESET_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+
+ break;
+ } else if (intr_status & INTR_PENDING) {
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ ha->total_io_count++;
+ if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+ break;
+
+ intr_status = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qla4xxx_process_aen - processes AENs generated by firmware
+ * @ha: pointer to host adapter structure.
+ * @process_aen: type of AENs to process
+ *
+ * Processes specific types of Asynchronous Events generated by firmware.
+ * The type of AENs to process is specified by process_aen and can be
+ * PROCESS_ALL_AENS 0
+ * FLUSH_DDB_CHANGED_AENS 1
+ * RELOGIN_DDB_CHANGED_AENS 2
+ **/
+void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
+{
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+ struct aen *aen;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while (ha->aen_out != ha->aen_in) {
+ /* Advance pointers for next entry */
+ if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
+ ha->aen_out = 0;
+ else
+ ha->aen_out++;
+
+ ha->aen_q_count++;
+ aen = &ha->aen_q[ha->aen_out];
+
+ /* copy aen information to local structure */
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+ mbox_sts[i] = aen->mbox_sts[i];
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
+ "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
+ mbox_sts[0], mbox_sts[2], mbox_sts[3],
+ mbox_sts[1], mbox_sts[4]));
+
+ switch (mbox_sts[0]) {
+ case MBOX_ASTS_DATABASE_CHANGED:
+ if (process_aen == FLUSH_DDB_CHANGED_AENS) {
+ DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
+ "[%d] state=%04x FLUSHED!\n",
+ ha->host_no, ha->aen_out,
+ mbox_sts[0], mbox_sts[2],
+ mbox_sts[3]));
+ break;
+ } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
+ /* for use during init time, we only want to
+ * relogin non-active ddbs */
+ struct ddb_entry *ddb_entry;
+
+ ddb_entry =
+ /* FIXME: name length? */
+ qla4xxx_lookup_ddb_by_fw_index(ha,
+ mbox_sts[2]);
+ if (!ddb_entry)
+ break;
+
+ ddb_entry->dev_scan_wait_to_complete_relogin =
+ 0;
+ ddb_entry->dev_scan_wait_to_start_relogin =
+ jiffies +
+ ((ddb_entry->default_time2wait +
+ 4) * HZ);
+
+ DEBUG2(printk("scsi%ld: ddb index [%d] initate"
+ " RELOGIN after %d seconds\n",
+ ha->host_no,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->default_time2wait +
+ 4));
+ break;
+ }
+
+ if (mbox_sts[1] == 0) { /* Global DB change. */
+ qla4xxx_reinitialize_ddb_list(ha);
+ } else if (mbox_sts[1] == 1) { /* Specific device. */
+ qla4xxx_process_ddb_changed(ha, mbox_sts[2],
+ mbox_sts[3]);
+ }
+ break;
+ }
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
new file mode 100644
index 00000000000..b721dc5dd71
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -0,0 +1,930 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+
+/**
+ * qla4xxx_mailbox_command - issues mailbox commands
+ * @ha: Pointer to host adapter structure.
+ * @inCount: number of mailbox registers to load.
+ * @outCount: number of mailbox registers to return.
+ * @mbx_cmd: data pointer for mailbox in registers.
+ * @mbx_sts: data pointer for mailbox out registers.
+ *
+ * This routine sssue mailbox commands and waits for completion.
+ * If outCount is 0, this routine completes successfully WITHOUT waiting
+ * for the mailbox command to complete.
+ **/
+int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+ uint8_t outCount, uint32_t *mbx_cmd,
+ uint32_t *mbx_sts)
+{
+ int status = QLA_ERROR;
+ uint8_t i;
+ u_long wait_count;
+ uint32_t intr_status;
+ unsigned long flags = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ mutex_lock(&ha->mbox_sem);
+
+ /* Mailbox code active */
+ set_bit(AF_MBOX_COMMAND, &ha->flags);
+
+ /* Make sure that pointers are valid */
+ if (!mbx_cmd || !mbx_sts) {
+ DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
+ "pointer\n", ha->host_no, __func__));
+ goto mbox_exit;
+ }
+
+ /* To prevent overwriting mailbox registers for a command that has
+ * not yet been serviced, check to see if a previously issued
+ * mailbox command is interrupting.
+ * -----------------------------------------------------------------
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+ /* Service existing interrupt */
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ }
+
+ /* Send the mailbox command to the firmware */
+ ha->mbox_status_count = outCount;
+ for (i = 0; i < outCount; i++)
+ ha->mbox_status[i] = 0;
+
+ /* Load all mailbox registers, except mailbox 0. */
+ for (i = 1; i < inCount; i++)
+ writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+
+ /* Wakeup firmware */
+ writel(mbx_cmd[0], &ha->reg->mailbox[0]);
+ readl(&ha->reg->mailbox[0]);
+ writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait for completion */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&ha->mailbox_wait_queue, &wait);
+
+ /*
+ * If we don't want status, don't wait for the mailbox command to
+ * complete. For example, MBOX_CMD_RESET_FW doesn't return status,
+ * you must poll the inbound Interrupt Mask for completion.
+ */
+ if (outCount == 0) {
+ status = QLA_SUCCESS;
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
+ goto mbox_exit;
+ }
+ /* Wait for command to complete */
+ wait_count = jiffies + MBOX_TOV * HZ;
+ while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+ if (time_after_eq(jiffies, wait_count))
+ break;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & INTR_PENDING) {
+ /*
+ * Service the interrupt.
+ * The ISR will save the mailbox status registers
+ * to a temporary storage location in the adapter
+ * structure.
+ */
+ ha->mbox_status_count = outCount;
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ msleep(10);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
+
+ /* Check for mailbox timeout. */
+ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
+ " Scheduling Adapter Reset\n", ha->host_no,
+ mbx_cmd[0]));
+ ha->mailbox_timeout_count++;
+ mbx_sts[0] = (-1);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ goto mbox_exit;
+ }
+
+ /*
+ * Copy the mailbox out registers to the caller's mailbox in/out
+ * structure.
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 0; i < outCount; i++)
+ mbx_sts[i] = ha->mbox_status[i];
+
+ /* Set return status and error flags (if applicable). */
+ switch (ha->mbox_status[0]) {
+ case MBOX_STS_COMMAND_COMPLETE:
+ status = QLA_SUCCESS;
+ break;
+
+ case MBOX_STS_INTERMEDIATE_COMPLETION:
+ status = QLA_SUCCESS;
+ break;
+
+ case MBOX_STS_BUSY:
+ DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
+ ha->host_no, __func__, mbx_cmd[0]));
+ ha->mailbox_timeout_count++;
+ break;
+
+ default:
+ DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
+ "sts = %08X ****\n", ha->host_no, __func__,
+ mbx_cmd[0], mbx_sts[0]));
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+mbox_exit:
+ clear_bit(AF_MBOX_COMMAND, &ha->flags);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ mutex_unlock(&ha->mbox_sem);
+
+ return status;
+}
+
+
+/**
+ * qla4xxx_issue_iocb - issue mailbox iocb command
+ * @ha: adapter state pointer.
+ * @buffer: buffer pointer.
+ * @phys_addr: physical address of buffer.
+ * @size: size of buffer.
+ *
+ * Issues iocbs via mailbox commands.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ **/
+int
+qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
+ dma_addr_t phys_addr, size_t size)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status;
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
+ mbox_cmd[1] = 0;
+ mbox_cmd[2] = LSDW(phys_addr);
+ mbox_cmd[3] = MSDW(phys_addr);
+ status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
+ return status;
+}
+
+int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index,
+ uint16_t connection_id,
+ uint16_t option)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
+ mbox_cmd[1] = fw_ddb_index;
+ mbox_cmd[2] = connection_id;
+ mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
+ if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
+ "option %04x failed sts %04X %04X",
+ ha->host_no, __func__,
+ option, mbox_sts[0], mbox_sts[1]));
+ if (mbox_sts[0] == 0x4005)
+ DEBUG2(printk("%s reason %04X\n", __func__,
+ mbox_sts[1]));
+ }
+ return QLA_SUCCESS;
+}
+
+int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
+ mbox_cmd[1] = fw_ddb_index;
+ if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ return QLA_ERROR;
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_initialize_fw_cb - initializes firmware control block.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
+{
+ struct init_fw_ctrl_blk *init_fw_cb;
+ dma_addr_t init_fw_cb_dma;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status = QLA_ERROR;
+
+ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ &init_fw_cb_dma, GFP_KERNEL);
+ if (init_fw_cb == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
+ ha->host_no, __func__));
+ return 10;
+ }
+ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
+
+ /* Get Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ dma_free_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+ return status;
+ }
+
+ /* Initialize request and response queues. */
+ qla4xxx_init_rings(ha);
+
+ /* Fill in the request and response queue information. */
+ init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
+ init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
+ init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
+ init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
+ init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
+ init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
+ init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
+ init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
+ init_fw_cb->ShadowRegBufAddrLo =
+ cpu_to_le32(LSDW(ha->shadow_regs_dma));
+ init_fw_cb->ShadowRegBufAddrHi =
+ cpu_to_le32(MSDW(ha->shadow_regs_dma));
+
+ /* Set up required options. */
+ init_fw_cb->FwOptions |=
+ __constant_cpu_to_le16(FWOPT_SESSION_MODE |
+ FWOPT_INITIATOR_MODE);
+ init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
+
+ /* Save some info in adapter structure. */
+ ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
+ ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
+ ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
+ memcpy(ha->ip_address, init_fw_cb->IPAddr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
+ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
+ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+ memcpy(ha->name_string, init_fw_cb->iSCSINameString,
+ min(sizeof(ha->name_string),
+ sizeof(init_fw_cb->iSCSINameString)));
+ memcpy(ha->alias, init_fw_cb->Alias,
+ min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
+
+ /* Save Command Line Paramater info */
+ ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
+ ha->discovery_wait = ql4xdiscoverywait;
+
+ /* Send Initialize Firmware Control Block. */
+ mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
+ mbox_cmd[1] = 0;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
+ QLA_SUCCESS)
+ status = QLA_SUCCESS;
+ else {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE "
+ "failed w/ status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ }
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+
+ return status;
+}
+
+/**
+ * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
+{
+ struct init_fw_ctrl_blk *init_fw_cb;
+ dma_addr_t init_fw_cb_dma;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ &init_fw_cb_dma, GFP_KERNEL);
+ if (init_fw_cb == NULL) {
+ printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
+ __func__);
+ return 10;
+ }
+
+ /* Get Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
+ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
+ ha->host_no, __func__));
+ dma_free_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+ return QLA_ERROR;
+ }
+
+ /* Save IP Address. */
+ memcpy(ha->ip_address, init_fw_cb->IPAddr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
+ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
+ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_firmware_state - gets firmware state of HBA
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
+ if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
+ "status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ ha->firmware_state = mbox_sts[1];
+ ha->board_id = mbox_sts[2];
+ ha->addl_fw_state = mbox_sts[3];
+ DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
+ ha->host_no, __func__, ha->firmware_state);)
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_firmware_status - retrieves firmware status
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
+ if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
+ "status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ return QLA_ERROR;
+ }
+
+ /* High-water mark of IOCBs */
+ ha->iocb_hiwat = mbox_sts[2];
+ if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
+ ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
+ else
+ dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
+ "firmare IOCBs available (%d).\n",
+ IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ * @fw_ddb_entry: Pointer to firmware's device database entry structure
+ * @num_valid_ddb_entries: Pointer to number of valid ddb entries
+ * @next_ddb_index: Pointer to next valid device database index
+ * @fw_ddb_device_state: Pointer to device state
+ **/
+int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
+ uint16_t fw_ddb_index,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma,
+ uint32_t *num_valid_ddb_entries,
+ uint32_t *next_ddb_index,
+ uint32_t *fw_ddb_device_state,
+ uint32_t *conn_err_detail,
+ uint16_t *tcp_source_port_num,
+ uint16_t *connection_id)
+{
+ int status = QLA_ERROR;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Make sure the device index is valid */
+ if (fw_ddb_index >= MAX_DDB_ENTRIES) {
+ DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
+ ha->host_no, __func__, fw_ddb_index));
+ goto exit_get_fwddb;
+ }
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
+ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
+ " with status 0x%04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ goto exit_get_fwddb;
+ }
+ if (fw_ddb_index != mbox_sts[1]) {
+ DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
+ ha->host_no, __func__, fw_ddb_index,
+ mbox_sts[1]));
+ goto exit_get_fwddb;
+ }
+ if (fw_ddb_entry) {
+ dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
+ "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
+ fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
+ mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
+ fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
+ fw_ddb_entry->ipAddr[3],
+ le16_to_cpu(fw_ddb_entry->portNumber),
+ fw_ddb_entry->iscsiName);
+ }
+ if (num_valid_ddb_entries)
+ *num_valid_ddb_entries = mbox_sts[2];
+ if (next_ddb_index)
+ *next_ddb_index = mbox_sts[3];
+ if (fw_ddb_device_state)
+ *fw_ddb_device_state = mbox_sts[4];
+
+ /*
+ * RA: This mailbox has been changed to pass connection error and
+ * details. Its true for ISP4010 as per Version E - Not sure when it
+ * was changed. Get the time2wait from the fw_dd_entry field :
+ * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY
+ * struct.
+ */
+ if (conn_err_detail)
+ *conn_err_detail = mbox_sts[5];
+ if (tcp_source_port_num)
+ *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16;
+ if (connection_id)
+ *connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
+ status = QLA_SUCCESS;
+
+exit_get_fwddb:
+ return status;
+}
+
+/**
+ * qla4xxx_set_fwddb_entry - sets a ddb entry.
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL.
+ *
+ * This routine initializes or updates the adapter's device database
+ * entry for the specified device. It also triggers a login for the
+ * specified device. Therefore, it may also be used as a secondary
+ * login routine when a NULL pointer is specified for the fw_ddb_entry.
+ **/
+int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
+ dma_addr_t fw_ddb_entry_dma)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Do not wait for completion. The firmware will send us an
+ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
+ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
+ return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
+}
+
+int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index)
+{
+ int status = QLA_ERROR;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Do not wait for completion. The firmware will send us an
+ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = 0;
+ mbox_cmd[3] = 0;
+ mbox_cmd[4] = 0;
+ status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
+ DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
+ __func__, fw_ddb_index, status, mbox_sts[0],
+ mbox_sts[1]);)
+
+ return status;
+}
+
+/**
+ * qla4xxx_get_crash_record - retrieves crash record.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine retrieves a crash record from the QLA4010 after an 8002h aen.
+ **/
+void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct crash_record *crash_record = NULL;
+ dma_addr_t crash_record_dma = 0;
+ uint32_t crash_record_size = 0;
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
+ /* Get size of crash record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
+ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
+ ha->host_no, __func__));
+ goto exit_get_crash_record;
+ }
+ crash_record_size = mbox_sts[4];
+ if (crash_record_size == 0) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n",
+ ha->host_no, __func__));
+ goto exit_get_crash_record;
+ }
+
+ /* Alloc Memory for Crash Record. */
+ crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size,
+ &crash_record_dma, GFP_KERNEL);
+ if (crash_record == NULL)
+ goto exit_get_crash_record;
+
+ /* Get Crash Record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
+ mbox_cmd[2] = LSDW(crash_record_dma);
+ mbox_cmd[3] = MSDW(crash_record_dma);
+ mbox_cmd[4] = crash_record_size;
+ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ goto exit_get_crash_record;
+
+ /* Dump Crash Record. */
+
+exit_get_crash_record:
+ if (crash_record)
+ dma_free_coherent(&ha->pdev->dev, crash_record_size,
+ crash_record, crash_record_dma);
+}
+
+/**
+ * qla4xxx_get_conn_event_log - retrieves connection event log
+ * @ha: Pointer to host adapter structure.
+ **/
+void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct conn_event_log_entry *event_log = NULL;
+ dma_addr_t event_log_dma = 0;
+ uint32_t event_log_size = 0;
+ uint32_t num_valid_entries;
+ uint32_t oldest_entry = 0;
+ uint32_t max_event_log_entries;
+ uint8_t i;
+
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
+ /* Get size of crash record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ goto exit_get_event_log;
+
+ event_log_size = mbox_sts[4];
+ if (event_log_size == 0)
+ goto exit_get_event_log;
+
+ /* Alloc Memory for Crash Record. */
+ event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size,
+ &event_log_dma, GFP_KERNEL);
+ if (event_log == NULL)
+ goto exit_get_event_log;
+
+ /* Get Crash Record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
+ mbox_cmd[2] = LSDW(event_log_dma);
+ mbox_cmd[3] = MSDW(event_log_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
+ "log!\n", ha->host_no, __func__));
+ goto exit_get_event_log;
+ }
+
+ /* Dump Event Log. */
+ num_valid_entries = mbox_sts[1];
+
+ max_event_log_entries = event_log_size /
+ sizeof(struct conn_event_log_entry);
+
+ if (num_valid_entries > max_event_log_entries)
+ oldest_entry = num_valid_entries % max_event_log_entries;
+
+ DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
+ ha->host_no, num_valid_entries));
+
+ if (ql4xextended_error_logging == 3) {
+ if (oldest_entry == 0) {
+ /* Circular Buffer has not wrapped around */
+ for (i=0; i < num_valid_entries; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ }
+ else {
+ /* Circular Buffer has wrapped around -
+ * display accordingly*/
+ for (i=oldest_entry; i < max_event_log_entries; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ for (i=0; i < oldest_entry; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ }
+ }
+
+exit_get_event_log:
+ if (event_log)
+ dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
+ event_log_dma);
+}
+
+/**
+ * qla4xxx_reset_lun - issues LUN Reset
+ * @ha: Pointer to host adapter structure.
+ * @db_entry: Pointer to device database entry
+ * @un_entry: Pointer to lun entry structure
+ *
+ * This routine performs a LUN RESET on the specified target/lun.
+ * The caller must ensure that the ddb_entry and lun_entry pointers
+ * are valid before calling this routine.
+ **/
+int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+ int lun)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status = QLA_SUCCESS;
+
+ DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
+ ddb_entry->os_target_id, lun));
+
+ /*
+ * Send lun reset command to ISP, so that the ISP will return all
+ * outstanding requests with RESET status
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_LUN_RESET;
+ mbox_cmd[1] = ddb_entry->fw_ddb_index;
+ mbox_cmd[2] = lun << 8;
+ mbox_cmd[5] = 0x01; /* Immediate Command Enable */
+ qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
+ if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
+ mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
+ status = QLA_ERROR;
+
+ return status;
+}
+
+
+int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+ uint32_t offset, uint32_t len)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_READ_FLASH;
+ mbox_cmd[1] = LSDW(dma_addr);
+ mbox_cmd[2] = MSDW(dma_addr);
+ mbox_cmd[3] = offset;
+ mbox_cmd[4] = len;
+ if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
+ "status %04X %04X, offset %08x, len %08x\n", ha->host_no,
+ __func__, mbox_sts[0], mbox_sts[1], offset, len));
+ return QLA_ERROR;
+ }
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_fw_version - gets firmware version
+ * @ha: Pointer to host adapter structure.
+ *
+ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
+ * hold an address for data. Make sure that we write 0 to those mailboxes,
+ * if unused.
+ **/
+int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
+ "status %04X\n", ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+
+ /* Save firmware version information. */
+ ha->firmware_version[0] = mbox_sts[1];
+ ha->firmware_version[1] = mbox_sts[2];
+ ha->patch_number = mbox_sts[3];
+ ha->build_number = mbox_sts[4];
+
+ return QLA_SUCCESS;
+}
+
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS;
+ mbox_cmd[2] = LSDW(dma_addr);
+ mbox_cmd[3] = MSDW(dma_addr);
+
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
+ ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ return QLA_SUCCESS;
+}
+
+int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
+ mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
+
+ if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
+ *ddb_index = mbox_sts[2];
+ } else {
+ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
+ ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ } else {
+ *ddb_index = MAX_PRST_DEV_DB_ENTRIES;
+ }
+
+ return QLA_SUCCESS;
+}
+
+
+int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
+{
+ struct dev_db_entry *fw_ddb_entry;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t ddb_index;
+ int ret_val = 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(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+ ret_val = QLA_ERROR;
+ goto qla4xxx_send_tgts_exit;
+ }
+
+ ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
+ if (ret_val != QLA_SUCCESS)
+ goto qla4xxx_send_tgts_exit;
+
+ ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
+ if (ret_val != QLA_SUCCESS)
+ goto qla4xxx_send_tgts_exit;
+
+ memset((void *)fw_ddb_entry->iSCSIAlias, 0,
+ sizeof(fw_ddb_entry->iSCSIAlias));
+
+ memset((void *)fw_ddb_entry->iscsiName, 0,
+ sizeof(fw_ddb_entry->iscsiName));
+
+ memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
+ memset((void *)fw_ddb_entry->targetAddr, 0,
+ sizeof(fw_ddb_entry->targetAddr));
+
+ fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
+ fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
+
+ fw_ddb_entry->ipAddr[0] = *ip;
+ fw_ddb_entry->ipAddr[1] = *(ip + 1);
+ fw_ddb_entry->ipAddr[2] = *(ip + 2);
+ fw_ddb_entry->ipAddr[3] = *(ip + 3);
+
+ ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
+
+qla4xxx_send_tgts_exit:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret_val;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
new file mode 100644
index 00000000000..58afd135aa1
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -0,0 +1,232 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha)
+{
+ writel(cmd, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ udelay(1);
+}
+
+static inline int eeprom_size(struct scsi_qla_host *ha)
+{
+ return is_qla4010(ha) ? FM93C66A_SIZE_16 : FM93C86A_SIZE_16;
+}
+
+static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha)
+{
+ return is_qla4010(ha) ? FM93C56A_NO_ADDR_BITS_16 :
+ FM93C86A_NO_ADDR_BITS_16 ;
+}
+
+static inline int eeprom_no_data_bits(struct scsi_qla_host *ha)
+{
+ return FM93C56A_DATA_BITS_16;
+}
+
+static int fm93c56a_select(struct scsi_qla_host * ha)
+{
+ DEBUG5(printk(KERN_ERR "fm93c56a_select:\n"));
+
+ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000;
+ eeprom_cmd(ha->eeprom_cmd_data, ha);
+ return 1;
+}
+
+static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
+{
+ int i;
+ int mask;
+ int dataBit;
+ int previousBit;
+
+ /* Clock in a zero, then do the start bit. */
+ eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, ha);
+
+ eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_RISE, ha);
+ eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_FALL, ha);
+
+ mask = 1 << (FM93C56A_CMD_BITS - 1);
+
+ /* Force the previous data bit to be different. */
+ previousBit = 0xffff;
+ for (i = 0; i < FM93C56A_CMD_BITS; i++) {
+ dataBit =
+ (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+
+ /*
+ * If the bit changed, then change the DO state to
+ * match.
+ */
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha);
+ previousBit = dataBit;
+ }
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE, ha);
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL, ha);
+
+ cmd = cmd << 1;
+ }
+ mask = 1 << (eeprom_no_addr_bits(ha) - 1);
+
+ /* Force the previous data bit to be different. */
+ previousBit = 0xffff;
+ for (i = 0; i < eeprom_no_addr_bits(ha); i++) {
+ dataBit = addr & mask ? AUBURN_EEPROM_DO_1 :
+ AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+ /*
+ * If the bit changed, then change the DO state to
+ * match.
+ */
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha);
+
+ previousBit = dataBit;
+ }
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE, ha);
+ eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL, ha);
+
+ addr = addr << 1;
+ }
+ return 1;
+}
+
+static int fm93c56a_deselect(struct scsi_qla_host * ha)
+{
+ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000;
+ eeprom_cmd(ha->eeprom_cmd_data, ha);
+ return 1;
+}
+
+static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value)
+{
+ int i;
+ int data = 0;
+ int dataBit;
+
+ /* Read the data bits
+ * The first bit is a dummy. Clock right over it. */
+ for (i = 0; i < eeprom_no_data_bits(ha); i++) {
+ eeprom_cmd(ha->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_RISE, ha);
+ eeprom_cmd(ha->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_FALL, ha);
+
+ dataBit = (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+
+ data = (data << 1) | dataBit;
+ }
+
+ *value = data;
+ return 1;
+}
+
+static int eeprom_readword(int eepromAddr, u16 * value,
+ struct scsi_qla_host * ha)
+{
+ fm93c56a_select(ha);
+ fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr);
+ fm93c56a_datain(ha, value);
+ fm93c56a_deselect(ha);
+ return 1;
+}
+
+/* Hardware_lock must be set before calling */
+u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
+{
+ u16 val;
+
+ /* NOTE: NVRAM uses half-word addresses */
+ eeprom_readword(offset, &val, ha);
+ return val;
+}
+
+int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha)
+{
+ int status = QLA_ERROR;
+ uint16_t checksum = 0;
+ uint32_t index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (index = 0; index < eeprom_size(ha); index++)
+ checksum += rd_nvram_word(ha, index);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (checksum == 0)
+ status = QLA_SUCCESS;
+
+ return status;
+}
+
+/*************************************************************************
+ *
+ * Hardware Semaphore routines
+ *
+ *************************************************************************/
+int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
+{
+ uint32_t value;
+ unsigned long flags;
+ unsigned int seconds = 30;
+
+ DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = "
+ "0x%x\n", ha->host_no, sem_mask, sem_bits));
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((sem_mask | sem_bits), isp_semaphore(ha));
+ value = readw(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if ((value & (sem_mask >> 16)) == sem_bits) {
+ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, "
+ "code = 0x%x\n", ha->host_no,
+ sem_mask, sem_bits));
+ return QLA_SUCCESS;
+ }
+ ssleep(1);
+ } while (--seconds);
+ return QLA_ERROR;
+}
+
+void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(sem_mask, isp_semaphore(ha));
+ readl(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no,
+ sem_mask));
+}
+
+int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
+{
+ uint32_t value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((sem_mask | sem_bits), isp_semaphore(ha));
+ value = readw(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if ((value & (sem_mask >> 16)) == sem_bits) {
+ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = "
+ "0x%x, sema code=0x%x\n", ha->host_no,
+ sem_mask, sem_bits, value));
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
new file mode 100644
index 00000000000..b47b4fc59d8
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -0,0 +1,254 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef _QL4XNVRM_H_
+#define _QL4XNVRM_H_
+
+/*
+ * AM29LV Flash definitions
+ */
+#define FM93C56A_SIZE_8 0x100
+#define FM93C56A_SIZE_16 0x80
+#define FM93C66A_SIZE_8 0x200
+#define FM93C66A_SIZE_16 0x100/* 4010 */
+#define FM93C86A_SIZE_16 0x400/* 4022 */
+
+#define FM93C56A_START 0x1
+
+// Commands
+#define FM93C56A_READ 0x2
+#define FM93C56A_WEN 0x0
+#define FM93C56A_WRITE 0x1
+#define FM93C56A_WRITE_ALL 0x0
+#define FM93C56A_WDS 0x0
+#define FM93C56A_ERASE 0x3
+#define FM93C56A_ERASE_ALL 0x0
+
+/* Command Extentions */
+#define FM93C56A_WEN_EXT 0x3
+#define FM93C56A_WRITE_ALL_EXT 0x1
+#define FM93C56A_WDS_EXT 0x0
+#define FM93C56A_ERASE_ALL_EXT 0x2
+
+/* Address Bits */
+#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */
+#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */
+#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */
+
+/* Data Bits */
+#define FM93C56A_DATA_BITS_16 16
+#define FM93C56A_DATA_BITS_8 8
+
+/* Special Bits */
+#define FM93C56A_READ_DUMMY_BITS 1
+#define FM93C56A_READY 0
+#define FM93C56A_BUSY 1
+#define FM93C56A_CMD_BITS 2
+
+/* Auburn Bits */
+#define AUBURN_EEPROM_DI 0x8
+#define AUBURN_EEPROM_DI_0 0x0
+#define AUBURN_EEPROM_DI_1 0x8
+#define AUBURN_EEPROM_DO 0x4
+#define AUBURN_EEPROM_DO_0 0x0
+#define AUBURN_EEPROM_DO_1 0x4
+#define AUBURN_EEPROM_CS 0x2
+#define AUBURN_EEPROM_CS_0 0x0
+#define AUBURN_EEPROM_CS_1 0x2
+#define AUBURN_EEPROM_CLK_RISE 0x1
+#define AUBURN_EEPROM_CLK_FALL 0x0
+
+/* */
+/* EEPROM format */
+/* */
+struct bios_params {
+ uint16_t SpinUpDelay:1;
+ uint16_t BIOSDisable:1;
+ uint16_t MMAPEnable:1;
+ uint16_t BootEnable:1;
+ uint16_t Reserved0:12;
+ uint8_t bootID0:7;
+ uint8_t bootID0Valid:1;
+ uint8_t bootLUN0[8];
+ uint8_t bootID1:7;
+ uint8_t bootID1Valid:1;
+ uint8_t bootLUN1[8];
+ uint16_t MaxLunsPerTarget;
+ uint8_t Reserved1[10];
+};
+
+struct eeprom_port_cfg {
+
+ /* MTU MAC 0 */
+ u16 etherMtu_mac;
+
+ /* Flow Control MAC 0 */
+ u16 pauseThreshold_mac;
+ u16 resumeThreshold_mac;
+ u16 reserved[13];
+};
+
+struct eeprom_function_cfg {
+ u8 reserved[30];
+
+ /* MAC ADDR */
+ u8 macAddress[6];
+ u8 macAddressSecondary[6];
+ u16 subsysVendorId;
+ u16 subsysDeviceId;
+};
+
+struct eeprom_data {
+ union {
+ struct { /* isp4010 */
+ u8 asic_id[4]; /* x00 */
+ u8 version; /* x04 */
+ u8 reserved; /* x05 */
+ u16 board_id; /* x06 */
+#define EEPROM_BOARDID_ELDORADO 1
+#define EEPROM_BOARDID_PLACER 2
+
+#define EEPROM_SERIAL_NUM_SIZE 16
+ u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */
+
+ /* ExtHwConfig: */
+ /* Offset = 24bytes
+ *
+ * | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | |
+ * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ u16 ext_hw_conf; /* x18 */
+ u8 mac0[6]; /* x1A */
+ u8 mac1[6]; /* x20 */
+ u8 mac2[6]; /* x26 */
+ u8 mac3[6]; /* x2C */
+ u16 etherMtu; /* x32 */
+ u16 macConfig; /* x34 */
+#define MAC_CONFIG_ENABLE_ANEG 0x0001
+#define MAC_CONFIG_ENABLE_PAUSE 0x0002
+ u16 phyConfig; /* x36 */
+#define PHY_CONFIG_PHY_ADDR_MASK 0x1f
+#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
+ u16 reserved_56; /* x38 */
+
+#define EEPROM_UNUSED_1_SIZE 2
+ u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
+ u16 bufletSize; /* x3C */
+ u16 bufletCount; /* x3E */
+ u16 bufletPauseThreshold; /* x40 */
+ u16 tcpWindowThreshold50; /* x42 */
+ u16 tcpWindowThreshold25; /* x44 */
+ u16 tcpWindowThreshold0; /* x46 */
+ u16 ipHashTableBaseHi; /* x48 */
+ u16 ipHashTableBaseLo; /* x4A */
+ u16 ipHashTableSize; /* x4C */
+ u16 tcpHashTableBaseHi; /* x4E */
+ u16 tcpHashTableBaseLo; /* x50 */
+ u16 tcpHashTableSize; /* x52 */
+ u16 ncbTableBaseHi; /* x54 */
+ u16 ncbTableBaseLo; /* x56 */
+ u16 ncbTableSize; /* x58 */
+ u16 drbTableBaseHi; /* x5A */
+ u16 drbTableBaseLo; /* x5C */
+ u16 drbTableSize; /* x5E */
+
+#define EEPROM_UNUSED_2_SIZE 4
+ u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */
+ u16 ipReassemblyTimeout; /* x64 */
+ u16 tcpMaxWindowSizeHi; /* x66 */
+ u16 tcpMaxWindowSizeLo; /* x68 */
+ u32 net_ip_addr0; /* x6A Added for TOE
+ * functionality. */
+ u32 net_ip_addr1; /* x6E */
+ u32 scsi_ip_addr0; /* x72 */
+ u32 scsi_ip_addr1; /* x76 */
+#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account
+ * for ip addresses */
+ u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */
+ u16 subsysVendorId_f0; /* xFA */
+ u16 subsysDeviceId_f0; /* xFC */
+
+ /* Address = 0x7F */
+#define FM93C56A_SIGNATURE 0x9356
+#define FM93C66A_SIGNATURE 0x9366
+ u16 signature; /* xFE */
+
+#define EEPROM_UNUSED_4_SIZE 250
+ u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */
+ u16 subsysVendorId_f1; /* x1FA */
+ u16 subsysDeviceId_f1; /* x1FC */
+ u16 checksum; /* x1FE */
+ } __attribute__ ((packed)) isp4010;
+ struct { /* isp4022 */
+ u8 asicId[4]; /* x00 */
+ u8 version; /* x04 */
+ u8 reserved_5; /* x05 */
+ u16 boardId; /* x06 */
+ u8 boardIdStr[16]; /* x08 */
+ u8 serialNumber[16]; /* x18 */
+
+ /* External Hardware Configuration */
+ u16 ext_hw_conf; /* x28 */
+
+ /* MAC 0 CONFIGURATION */
+ struct eeprom_port_cfg macCfg_port0; /* x2A */
+
+ /* MAC 1 CONFIGURATION */
+ struct eeprom_port_cfg macCfg_port1; /* x4A */
+
+ /* DDR SDRAM Configuration */
+ u16 bufletSize; /* x6A */
+ u16 bufletCount; /* x6C */
+ u16 tcpWindowThreshold50; /* x6E */
+ u16 tcpWindowThreshold25; /* x70 */
+ u16 tcpWindowThreshold0; /* x72 */
+ u16 ipHashTableBaseHi; /* x74 */
+ u16 ipHashTableBaseLo; /* x76 */
+ u16 ipHashTableSize; /* x78 */
+ u16 tcpHashTableBaseHi; /* x7A */
+ u16 tcpHashTableBaseLo; /* x7C */
+ u16 tcpHashTableSize; /* x7E */
+ u16 ncbTableBaseHi; /* x80 */
+ u16 ncbTableBaseLo; /* x82 */
+ u16 ncbTableSize; /* x84 */
+ u16 drbTableBaseHi; /* x86 */
+ u16 drbTableBaseLo; /* x88 */
+ u16 drbTableSize; /* x8A */
+ u16 reserved_142[4]; /* x8C */
+
+ /* TCP/IP Parameters */
+ u16 ipReassemblyTimeout; /* x94 */
+ u16 tcpMaxWindowSize; /* x96 */
+ u16 ipSecurity; /* x98 */
+ u8 reserved_156[294]; /* x9A */
+ u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */
+ struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */
+ u16 reserved_510; /* x1FE */
+
+ /* Address = 512 */
+ u8 oemSpace[432]; /* x200 */
+ struct bios_params sBIOSParams_fn1; /* x3B0 */
+ struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */
+ u16 reserved_1022; /* x3FE */
+
+ /* Address = 1024 */
+ u8 reserved_1024[464]; /* x400 */
+ struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */
+ u16 reserved_1534; /* x5FE */
+
+ /* Address = 1536 */
+ u8 reserved_1536[432]; /* x600 */
+ struct bios_params sBIOSParams_fn3; /* x7B0 */
+ struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */
+ u16 checksum; /* x7FE */
+ } __attribute__ ((packed)) isp4022;
+ };
+};
+
+
+#endif /* _QL4XNVRM_H_ */
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
new file mode 100644
index 00000000000..9ef693c8809
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -0,0 +1,1679 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+#include <linux/moduleparam.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+
+#include "ql4_def.h"
+
+/*
+ * Driver version
+ */
+char qla4xxx_version_str[40];
+
+/*
+ * SRB allocation cache
+ */
+static struct kmem_cache *srb_cachep;
+
+/*
+ * Module parameter information and variables
+ */
+int ql4xdiscoverywait = 60;
+module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");
+int ql4xdontresethba = 0;
+module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(ql4xdontresethba,
+ "Dont reset the HBA when the driver gets 0x8002 AEN "
+ " default it will reset hba :0"
+ " set to 1 to avoid resetting HBA");
+
+int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */
+module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(ql4xextended_error_logging,
+ "Option to enable extended error logging, "
+ "Default is 0 - no logging, 1 - debug logging");
+
+/*
+ * SCSI host template entry points
+ */
+
+void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+
+/*
+ * iSCSI template entry points
+ */
+static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
+ uint32_t enable, struct sockaddr *dst_addr);
+static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
+ enum iscsi_param param, char *buf);
+static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+ enum iscsi_param param, char *buf);
+static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);
+static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
+static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+
+/*
+ * SCSI host template entry points
+ */
+static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+ void (*done) (struct scsi_cmnd *));
+static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
+static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
+static int qla4xxx_slave_alloc(struct scsi_device *device);
+static int qla4xxx_slave_configure(struct scsi_device *device);
+static void qla4xxx_slave_destroy(struct scsi_device *sdev);
+
+static struct scsi_host_template qla4xxx_driver_template = {
+ .module = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .proc_name = DRIVER_NAME,
+ .queuecommand = qla4xxx_queuecommand,
+
+ .eh_device_reset_handler = qla4xxx_eh_device_reset,
+ .eh_host_reset_handler = qla4xxx_eh_host_reset,
+
+ .slave_configure = qla4xxx_slave_configure,
+ .slave_alloc = qla4xxx_slave_alloc,
+ .slave_destroy = qla4xxx_slave_destroy,
+
+ .this_id = -1,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .sg_tablesize = SG_ALL,
+
+ .max_sectors = 0xFFFF,
+};
+
+static struct iscsi_transport qla4xxx_iscsi_transport = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .param_mask = ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
+ .sessiondata_size = sizeof(struct ddb_entry),
+ .host_template = &qla4xxx_driver_template,
+
+ .tgt_dscvr = qla4xxx_tgt_dscvr,
+ .get_conn_param = qla4xxx_conn_get_param,
+ .get_session_param = qla4xxx_sess_get_param,
+ .start_conn = qla4xxx_conn_start,
+ .stop_conn = qla4xxx_conn_stop,
+ .session_recovery_timedout = qla4xxx_recovery_timedout,
+};
+
+static struct scsi_transport_template *qla4xxx_scsi_transport;
+
+static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
+{
+ struct ddb_entry *ddb_entry = session->dd_data;
+ struct scsi_qla_host *ha = ddb_entry->ha;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) "
+ "secs exhausted, marking device DEAD.\n", ha->host_no,
+ __func__, ddb_entry->fw_ddb_index,
+ ha->port_down_retry_count));
+
+ atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
+
+ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = "
+ "0x%lx\n", ha->host_no, __func__, ha->dpc_flags));
+ queue_work(ha->dpc_thread, &ha->dpc_work);
+}
+
+static int qla4xxx_conn_start(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n",
+ ddb_entry->ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ iscsi_unblock_session(session);
+ return 0;
+}
+
+static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n",
+ ddb_entry->ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ if (flag == STOP_CONN_RECOVER)
+ iscsi_block_session(session);
+ else
+ printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
+}
+
+static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+ enum iscsi_param param, char *buf)
+{
+ struct ddb_entry *ddb_entry = sess->dd_data;
+ int len;
+
+ switch (param) {
+ case ISCSI_PARAM_TARGET_NAME:
+ len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
+ ddb_entry->iscsi_name);
+ break;
+ case ISCSI_PARAM_TPGT:
+ len = sprintf(buf, "%u\n", ddb_entry->tpgt);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
+static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
+ enum iscsi_param param, char *buf)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+ int len;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ len = sprintf(buf, "%hu\n", ddb_entry->port);
+ break;
+ case ISCSI_PARAM_CONN_ADDRESS:
+ /* TODO: what are the ipv6 bits */
+ len = sprintf(buf, "%u.%u.%u.%u\n",
+ NIPQUAD(ddb_entry->ip_addr));
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
+static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
+ uint32_t enable, struct sockaddr *dst_addr)
+{
+ struct scsi_qla_host *ha;
+ struct Scsi_Host *shost;
+ struct sockaddr_in *addr;
+ struct sockaddr_in6 *addr6;
+ int ret = 0;
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %u\n", host_no);
+ return -ENODEV;
+ }
+
+ ha = (struct scsi_qla_host *) shost->hostdata;
+
+ switch (type) {
+ case ISCSI_TGT_DSCVR_SEND_TARGETS:
+ if (dst_addr->sa_family == AF_INET) {
+ addr = (struct sockaddr_in *)dst_addr;
+ if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr,
+ addr->sin_port) != QLA_SUCCESS)
+ ret = -EIO;
+ } else if (dst_addr->sa_family == AF_INET6) {
+ /*
+ * TODO: fix qla4xxx_send_tgts
+ */
+ addr6 = (struct sockaddr_in6 *)dst_addr;
+ if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr,
+ addr6->sin6_port) != QLA_SUCCESS)
+ ret = -EIO;
+ } else
+ ret = -ENOSYS;
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ scsi_host_put(shost);
+ return ret;
+}
+
+void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
+{
+ if (!ddb_entry->sess)
+ return;
+
+ if (ddb_entry->conn) {
+ iscsi_if_destroy_session_done(ddb_entry->conn);
+ iscsi_destroy_conn(ddb_entry->conn);
+ iscsi_remove_session(ddb_entry->sess);
+ }
+ iscsi_free_session(ddb_entry->sess);
+}
+
+int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
+{
+ int err;
+
+ err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
+ if (err) {
+ DEBUG2(printk(KERN_ERR "Could not add session.\n"));
+ return err;
+ }
+
+ ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0);
+ if (!ddb_entry->conn) {
+ iscsi_remove_session(ddb_entry->sess);
+ DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
+ return -ENOMEM;
+ }
+
+ ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
+ iscsi_if_create_session_done(ddb_entry->conn);
+ return 0;
+}
+
+struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
+{
+ struct ddb_entry *ddb_entry;
+ struct iscsi_cls_session *sess;
+
+ sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport);
+ if (!sess)
+ return NULL;
+
+ ddb_entry = sess->dd_data;
+ memset(ddb_entry, 0, sizeof(*ddb_entry));
+ ddb_entry->ha = ha;
+ ddb_entry->sess = sess;
+ return ddb_entry;
+}
+
+/*
+ * Timer routines
+ */
+
+static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
+ unsigned long interval)
+{
+ DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
+ __func__, ha->host->host_no));
+ init_timer(&ha->timer);
+ ha->timer.expires = jiffies + interval * HZ;
+ ha->timer.data = (unsigned long)ha;
+ ha->timer.function = (void (*)(unsigned long))func;
+ add_timer(&ha->timer);
+ ha->timer_active = 1;
+}
+
+static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
+{
+ del_timer_sync(&ha->timer);
+ ha->timer_active = 0;
+}
+
+/***
+ * qla4xxx_mark_device_missing - mark a device as missing.
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ *
+ * This routine marks a device missing and resets the relogin retry count.
+ **/
+void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
+{
+ atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
+ DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
+ ha->host_no, ddb_entry->bus, ddb_entry->target,
+ ddb_entry->fw_ddb_index));
+ iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
+}
+
+static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry,
+ struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct srb *srb;
+
+ srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
+ if (!srb)
+ return srb;
+
+ atomic_set(&srb->ref_count, 1);
+ srb->ha = ha;
+ srb->ddb = ddb_entry;
+ srb->cmd = cmd;
+ srb->flags = 0;
+ cmd->SCp.ptr = (void *)srb;
+ cmd->scsi_done = done;
+
+ return srb;
+}
+
+static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+
+ if (srb->flags & SRB_DMA_VALID) {
+ if (cmd->use_sg) {
+ pci_unmap_sg(ha->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ } else if (cmd->request_bufflen) {
+ pci_unmap_single(ha->pdev, srb->dma_handle,
+ cmd->request_bufflen,
+ cmd->sc_data_direction);
+ }
+ srb->flags &= ~SRB_DMA_VALID;
+ }
+ cmd->SCp.ptr = NULL;
+}
+
+void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+
+ qla4xxx_srb_free_dma(ha, srb);
+
+ mempool_free(srb, ha->srb_mempool);
+
+ cmd->scsi_done(cmd);
+}
+
+/**
+ * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
+ * @cmd: Pointer to Linux's SCSI command structure
+ * @done_fn: Function that the driver calls to notify the SCSI mid-layer
+ * that the command has been processed.
+ *
+ * Remarks:
+ * This routine is invoked by Linux to send a SCSI command to the driver.
+ * The mid-level driver tries to ensure that queuecommand never gets
+ * invoked concurrently with itself or the interrupt handler (although
+ * the interrupt handler may call this routine as part of request-
+ * completion handling). Unfortunely, it sometimes calls the scheduler
+ * in interrupt context which is a big NO! NO!.
+ **/
+static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
+ struct srb *srb;
+ int rval;
+
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {
+ cmd->result = DID_NO_CONNECT << 16;
+ goto qc_fail_command;
+ }
+ goto qc_host_busy;
+ }
+
+ spin_unlock_irq(ha->host->host_lock);
+
+ srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);
+ if (!srb)
+ goto qc_host_busy_lock;
+
+ rval = qla4xxx_send_command_to_isp(ha, srb);
+ if (rval != QLA_SUCCESS)
+ goto qc_host_busy_free_sp;
+
+ spin_lock_irq(ha->host->host_lock);
+ return 0;
+
+qc_host_busy_free_sp:
+ qla4xxx_srb_free_dma(ha, srb);
+ mempool_free(srb, ha->srb_mempool);
+
+qc_host_busy_lock:
+ spin_lock_irq(ha->host->host_lock);
+
+qc_host_busy:
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+qc_fail_command:
+ done(cmd);
+
+ return 0;
+}
+
+/**
+ * qla4xxx_mem_free - frees memory allocated to adapter
+ * @ha: Pointer to host adapter structure.
+ *
+ * Frees memory previously allocated by qla4xxx_mem_alloc
+ **/
+static void qla4xxx_mem_free(struct scsi_qla_host *ha)
+{
+ if (ha->queues)
+ dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
+ ha->queues_dma);
+
+ ha->queues_len = 0;
+ ha->queues = NULL;
+ ha->queues_dma = 0;
+ ha->request_ring = NULL;
+ ha->request_dma = 0;
+ ha->response_ring = NULL;
+ ha->response_dma = 0;
+ ha->shadow_regs = NULL;
+ ha->shadow_regs_dma = 0;
+
+ /* Free srb pool. */
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
+
+ ha->srb_mempool = NULL;
+
+ /* release io space registers */
+ if (ha->reg)
+ iounmap(ha->reg);
+ pci_release_regions(ha->pdev);
+}
+
+/**
+ * qla4xxx_mem_alloc - allocates memory for use by adapter.
+ * @ha: Pointer to host adapter structure
+ *
+ * Allocates DMA memory for request and response queues. Also allocates memory
+ * for srbs.
+ **/
+static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
+{
+ unsigned long align;
+
+ /* Allocate contiguous block of DMA memory for queues. */
+ ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
+ sizeof(struct shadow_regs) +
+ MEM_ALIGN_VALUE +
+ (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+ ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
+ &ha->queues_dma, GFP_KERNEL);
+ if (ha->queues == NULL) {
+ dev_warn(&ha->pdev->dev,
+ "Memory Allocation failed - queues.\n");
+
+ goto mem_alloc_error_exit;
+ }
+ memset(ha->queues, 0, ha->queues_len);
+
+ /*
+ * As per RISC alignment requirements -- the bus-address must be a
+ * multiple of the request-ring size (in bytes).
+ */
+ align = 0;
+ if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
+ align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
+ (MEM_ALIGN_VALUE - 1));
+
+ /* Update request and response queue pointers. */
+ ha->request_dma = ha->queues_dma + align;
+ ha->request_ring = (struct queue_entry *) (ha->queues + align);
+ ha->response_dma = ha->queues_dma + align +
+ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
+ ha->response_ring = (struct queue_entry *) (ha->queues + align +
+ (REQUEST_QUEUE_DEPTH *
+ QUEUE_SIZE));
+ ha->shadow_regs_dma = ha->queues_dma + align +
+ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
+ ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
+ (REQUEST_QUEUE_DEPTH *
+ QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH *
+ QUEUE_SIZE));
+
+ /* Allocate memory for srb pool. */
+ ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
+ mempool_free_slab, srb_cachep);
+ if (ha->srb_mempool == NULL) {
+ dev_warn(&ha->pdev->dev,
+ "Memory Allocation failed - SRB Pool.\n");
+
+ goto mem_alloc_error_exit;
+ }
+
+ return QLA_SUCCESS;
+
+mem_alloc_error_exit:
+ qla4xxx_mem_free(ha);
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_timer - checks every second for work to do.
+ * @ha: Pointer to host adapter structure.
+ **/
+static void qla4xxx_timer(struct scsi_qla_host *ha)
+{
+ struct ddb_entry *ddb_entry, *dtemp;
+ int start_dpc = 0;
+
+ /* Search for relogin's to time-out and port down retry. */
+ list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
+ /* Count down time between sending relogins */
+ if (adapter_up(ha) &&
+ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ if (atomic_read(&ddb_entry->retry_relogin_timer) !=
+ INVALID_ENTRY) {
+ if (atomic_read(&ddb_entry->retry_relogin_timer)
+ == 0) {
+ atomic_set(&ddb_entry->
+ retry_relogin_timer,
+ INVALID_ENTRY);
+ set_bit(DPC_RELOGIN_DEVICE,
+ &ha->dpc_flags);
+ set_bit(DF_RELOGIN, &ddb_entry->flags);
+ DEBUG2(printk("scsi%ld: %s: index [%d]"
+ " login device\n",
+ ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ } else
+ atomic_dec(&ddb_entry->
+ retry_relogin_timer);
+ }
+ }
+
+ /* Wait for relogin to timeout */
+ if (atomic_read(&ddb_entry->relogin_timer) &&
+ (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
+ /*
+ * If the relogin times out and the device is
+ * still NOT ONLINE then try and relogin again.
+ */
+ if (atomic_read(&ddb_entry->state) !=
+ DDB_STATE_ONLINE &&
+ ddb_entry->fw_ddb_device_state ==
+ DDB_DS_SESSION_FAILED) {
+ /* Reset retry relogin timer */
+ atomic_inc(&ddb_entry->relogin_retry_count);
+ DEBUG2(printk("scsi%ld: index[%d] relogin"
+ " timed out-retrying"
+ " relogin (%d)\n",
+ ha->host_no,
+ ddb_entry->fw_ddb_index,
+ atomic_read(&ddb_entry->
+ relogin_retry_count))
+ );
+ start_dpc++;
+ DEBUG(printk("scsi%ld:%d:%d: index [%d] "
+ "initate relogin after"
+ " %d seconds\n",
+ ha->host_no, ddb_entry->bus,
+ ddb_entry->target,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->default_time2wait + 4)
+ );
+
+ atomic_set(&ddb_entry->retry_relogin_timer,
+ ddb_entry->default_time2wait + 4);
+ }
+ }
+ }
+
+ /* Check for heartbeat interval. */
+ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
+ ha->heartbeat_interval != 0) {
+ ha->seconds_since_last_heartbeat++;
+ if (ha->seconds_since_last_heartbeat >
+ ha->heartbeat_interval + 2)
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+
+
+ /* Wakeup the dpc routine for this adapter, if needed. */
+ if ((start_dpc ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+ test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
+ test_bit(DPC_AEN, &ha->dpc_flags)) &&
+ ha->dpc_thread) {
+ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
+ " - dpc flags = 0x%lx\n",
+ ha->host_no, __func__, ha->dpc_flags));
+ queue_work(ha->dpc_thread, &ha->dpc_work);
+ }
+
+ /* Reschedule timer thread to call us back in one second */
+ mod_timer(&ha->timer, jiffies + HZ);
+
+ DEBUG2(ha->seconds_since_last_intr++);
+}
+
+/**
+ * qla4xxx_cmd_wait - waits for all outstanding commands to complete
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine stalls the driver until all outstanding commands are returned.
+ * Caller must release the Hardware Lock prior to calling this routine.
+ **/
+static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
+{
+ uint32_t index = 0;
+ int stat = QLA_SUCCESS;
+ unsigned long flags;
+ struct scsi_cmnd *cmd;
+ int wait_cnt = WAIT_CMD_TOV; /*
+ * Initialized for 30 seconds as we
+ * expect all commands to retuned
+ * ASAP.
+ */
+
+ while (wait_cnt) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ /* Find a command that hasn't completed. */
+ for (index = 0; index < ha->host->can_queue; index++) {
+ cmd = scsi_host_find_tag(ha->host, index);
+ if (cmd != NULL)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* If No Commands are pending, wait is complete */
+ if (index == ha->host->can_queue) {
+ break;
+ }
+
+ /* If we timed out on waiting for commands to come back
+ * return ERROR.
+ */
+ wait_cnt--;
+ if (wait_cnt == 0)
+ stat = QLA_ERROR;
+ else {
+ msleep(1000);
+ }
+ } /* End of While (wait_cnt) */
+
+ return stat;
+}
+
+/**
+ * qla4xxx_soft_reset - performs soft reset.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_soft_reset(struct scsi_qla_host *ha)
+{
+ uint32_t max_wait_time;
+ unsigned long flags = 0;
+ int status = QLA_ERROR;
+ uint32_t ctrl_status;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /*
+ * If the SCSI Reset Interrupt bit is set, clear it.
+ * Otherwise, the Soft Reset won't work.
+ */
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
+ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
+
+ /* Issue Soft Reset */
+ writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait until the Network Reset Intr bit is cleared */
+ max_wait_time = RESET_INTR_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
+ break;
+
+ msleep(1000);
+ } while ((--max_wait_time));
+
+ if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Network Reset Intr not cleared by "
+ "Network function, clearing it now!\n",
+ ha->host_no));
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
+
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = SOFT_RESET_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_SOFT_RESET) == 0) {
+ status = QLA_SUCCESS;
+ break;
+ }
+
+ msleep(1000);
+ } while ((--max_wait_time));
+
+ /*
+ * Also, make sure that the SCSI Reset Interrupt bit has been cleared
+ * after the soft reset has taken place.
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
+ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* If soft reset fails then most probably the bios on other
+ * function is also enabled.
+ * Since the initialization is sequential the other fn
+ * wont be able to acknowledge the soft reset.
+ * Issue a force soft reset to workaround this scenario.
+ */
+ if (max_wait_time == 0) {
+ /* Issue Force Soft Reset */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = SOFT_RESET_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
+ status = QLA_SUCCESS;
+ break;
+ }
+
+ msleep(1000);
+ } while ((--max_wait_time));
+ }
+
+ return status;
+}
+
+/**
+ * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine is called just prior to a HARD RESET to return all
+ * outstanding commands back to the Operating System.
+ * Caller should make sure that the following locks are released
+ * before this calling routine: Hardware lock, and io_request_lock.
+ **/
+static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+{
+ struct srb *srb;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 0; i < ha->host->can_queue; i++) {
+ srb = qla4xxx_del_from_active_array(ha, i);
+ if (srb != NULL) {
+ srb->cmd->result = DID_RESET << 16;
+ qla4xxx_srb_compl(ha, srb);
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+/**
+ * qla4xxx_recover_adapter - recovers adapter after a fatal error
+ * @ha: Pointer to host adapter structure.
+ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+ * after adapter recovery has completed.
+ * 0=preserve ddb list, 1=destroy and rebuild ddb list
+ **/
+static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+ uint8_t renew_ddb_list)
+{
+ int status;
+
+ /* Stall incoming I/O until we are done */
+ clear_bit(AF_ONLINE, &ha->flags);
+ DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
+ __func__));
+
+ /* Wait for outstanding commands to complete.
+ * Stalls the driver for max 30 secs
+ */
+ status = qla4xxx_cmd_wait(ha);
+
+ qla4xxx_disable_intrs(ha);
+
+ /* Flush any pending ddb changed AENs */
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ /* Reset the firmware. If successful, function
+ * returns with ISP interrupts enabled.
+ */
+ if (status == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
+ ha->host_no, __func__));
+ qla4xxx_flush_active_srbs(ha);
+ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+ status = qla4xxx_soft_reset(ha);
+ else
+ status = QLA_ERROR;
+ }
+
+ /* Flush any pending ddb changed AENs */
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ /* Re-initialize firmware. If successful, function returns
+ * with ISP interrupts enabled */
+ if (status == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n",
+ ha->host_no, __func__));
+
+ /* If successful, AF_ONLINE flag set in
+ * qla4xxx_initialize_adapter */
+ status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
+ }
+
+ /* Failed adapter initialization?
+ * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */
+ if ((test_bit(AF_ONLINE, &ha->flags) == 0) &&
+ (test_bit(DPC_RESET_HA, &ha->dpc_flags))) {
+ /* Adapter initialization failed, see if we can retry
+ * resetting the ha */
+ if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
+ ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
+ DEBUG2(printk("scsi%ld: recover adapter - retrying "
+ "(%d) more times\n", ha->host_no,
+ ha->retry_reset_ha_cnt));
+ set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ status = QLA_ERROR;
+ } else {
+ if (ha->retry_reset_ha_cnt > 0) {
+ /* Schedule another Reset HA--DPC will retry */
+ ha->retry_reset_ha_cnt--;
+ DEBUG2(printk("scsi%ld: recover adapter - "
+ "retry remaining %d\n",
+ ha->host_no,
+ ha->retry_reset_ha_cnt));
+ status = QLA_ERROR;
+ }
+
+ if (ha->retry_reset_ha_cnt == 0) {
+ /* Recover adapter retries have been exhausted.
+ * Adapter DEAD */
+ DEBUG2(printk("scsi%ld: recover adapter "
+ "failed - board disabled\n",
+ ha->host_no));
+ qla4xxx_flush_active_srbs(ha);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST,
+ &ha->dpc_flags);
+ status = QLA_ERROR;
+ }
+ }
+ } else {
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ }
+
+ ha->adapter_error_count++;
+
+ if (status == QLA_SUCCESS)
+ qla4xxx_enable_intrs(ha);
+
+ DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no));
+ return status;
+}
+
+/**
+ * qla4xxx_do_dpc - dpc routine
+ * @data: in our case pointer to adapter structure
+ *
+ * This routine is a task that is schedule by the interrupt handler
+ * to perform the background processing for interrupts. We put it
+ * on a task queue that is consumed whenever the scheduler runs; that's
+ * so you can do anything (i.e. put the process to sleep etc). In fact,
+ * the mid-level tries to sleep when it reaches the driver threshold
+ * "host->can_queue". This can cause a panic if we were in our interrupt code.
+ **/
+static void qla4xxx_do_dpc(struct work_struct *work)
+{
+ struct scsi_qla_host *ha =
+ container_of(work, struct scsi_qla_host, dpc_work);
+ struct ddb_entry *ddb_entry, *dtemp;
+
+ DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
+ "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->flags, ha->dpc_flags));
+
+ /* Initialization not yet finished. Don't do anything yet. */
+ if (!test_bit(AF_INIT_DONE, &ha->flags))
+ return;
+
+ if (adapter_up(ha) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
+ if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags))
+ qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
+
+ if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
+ uint8_t wait_time = RESET_INTR_TOV;
+ unsigned long flags = 0;
+
+ qla4xxx_flush_active_srbs(ha);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while ((readw(&ha->reg->ctrl_status) &
+ (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
+ if (--wait_time == 0)
+ break;
+
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ flags);
+
+ msleep(1000);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (wait_time == 0)
+ DEBUG2(printk("scsi%ld: %s: SR|FSR "
+ "bit not cleared-- resetting\n",
+ ha->host_no, __func__));
+ }
+ }
+
+ /* ---- process AEN? --- */
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
+
+ /* ---- Get DHCP IP Address? --- */
+ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
+ qla4xxx_get_dhcp_ip_address(ha);
+
+ /* ---- relogin device? --- */
+ if (adapter_up(ha) &&
+ test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
+ list_for_each_entry_safe(ddb_entry, dtemp,
+ &ha->ddb_list, list) {
+ if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
+ qla4xxx_relogin_device(ha, ddb_entry);
+
+ /*
+ * If mbx cmd times out there is no point
+ * in continuing further.
+ * With large no of targets this can hang
+ * the system.
+ */
+ if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ printk(KERN_WARNING "scsi%ld: %s: "
+ "need to reset hba\n",
+ ha->host_no, __func__);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * qla4xxx_free_adapter - release the adapter
+ * @ha: pointer to adapter structure
+ **/
+static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
+{
+
+ if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
+ /* Turn-off interrupts on the card. */
+ qla4xxx_disable_intrs(ha);
+ }
+
+ /* Kill the kernel thread for this host */
+ if (ha->dpc_thread)
+ destroy_workqueue(ha->dpc_thread);
+
+ /* Issue Soft Reset to put firmware in unknown state */
+ if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+ qla4xxx_soft_reset(ha);
+
+ /* Remove timer thread, if present */
+ if (ha->timer_active)
+ qla4xxx_stop_timer(ha);
+
+ /* free extra memory */
+ qla4xxx_mem_free(ha);
+
+ /* Detach interrupts */
+ if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
+ free_irq(ha->pdev->irq, ha);
+
+ pci_disable_device(ha->pdev);
+
+}
+
+/***
+ * qla4xxx_iospace_config - maps registers
+ * @ha: pointer to adapter structure
+ *
+ * This routines maps HBA's registers from the pci address space
+ * into the kernel virtual address space for memory mapped i/o.
+ **/
+static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
+{
+ unsigned long pio, pio_len, pio_flags;
+ unsigned long mmio, mmio_len, mmio_flags;
+
+ pio = pci_resource_start(ha->pdev, 0);
+ pio_len = pci_resource_len(ha->pdev, 0);
+ pio_flags = pci_resource_flags(ha->pdev, 0);
+ if (pio_flags & IORESOURCE_IO) {
+ if (pio_len < MIN_IOBASE_LEN) {
+ dev_warn(&ha->pdev->dev,
+ "Invalid PCI I/O region size\n");
+ pio = 0;
+ }
+ } else {
+ dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n");
+ pio = 0;
+ }
+
+ /* Use MMIO operations for all accesses. */
+ mmio = pci_resource_start(ha->pdev, 1);
+ mmio_len = pci_resource_len(ha->pdev, 1);
+ mmio_flags = pci_resource_flags(ha->pdev, 1);
+
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ dev_err(&ha->pdev->dev,
+ "region #0 not an MMIO resource, aborting\n");
+
+ goto iospace_error_exit;
+ }
+ if (mmio_len < MIN_IOBASE_LEN) {
+ dev_err(&ha->pdev->dev,
+ "Invalid PCI mem region size, aborting\n");
+ goto iospace_error_exit;
+ }
+
+ if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
+ dev_warn(&ha->pdev->dev,
+ "Failed to reserve PIO/MMIO regions\n");
+
+ goto iospace_error_exit;
+ }
+
+ ha->pio_address = pio;
+ ha->pio_length = pio_len;
+ ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
+ if (!ha->reg) {
+ dev_err(&ha->pdev->dev,
+ "cannot remap MMIO, aborting\n");
+
+ goto iospace_error_exit;
+ }
+
+ return 0;
+
+iospace_error_exit:
+ return -ENOMEM;
+}
+
+/**
+ * qla4xxx_probe_adapter - callback function to probe HBA
+ * @pdev: pointer to pci_dev structure
+ * @pci_device_id: pointer to pci_device entry
+ *
+ * This routine will probe for Qlogic 4xxx iSCSI host adapters.
+ * It returns zero if successful. It also initializes all data necessary for
+ * the driver.
+ **/
+static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret = -ENODEV, status;
+ struct Scsi_Host *host;
+ struct scsi_qla_host *ha;
+ struct ddb_entry *ddb_entry, *ddbtemp;
+ uint8_t init_retry_count = 0;
+ char buf[34];
+
+ if (pci_enable_device(pdev))
+ return -1;
+
+ host = scsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha));
+ if (host == NULL) {
+ printk(KERN_WARNING
+ "qla4xxx: Couldn't allocate host from scsi layer!\n");
+ goto probe_disable_device;
+ }
+
+ /* Clear our data area */
+ ha = (struct scsi_qla_host *) host->hostdata;
+ memset(ha, 0, sizeof(*ha));
+
+ /* Save the information from PCI BIOS. */
+ ha->pdev = pdev;
+ ha->host = host;
+ ha->host_no = host->host_no;
+
+ /* Configure PCI I/O space. */
+ ret = qla4xxx_iospace_config(ha);
+ if (ret)
+ goto probe_failed;
+
+ dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
+ pdev->device, pdev->irq, ha->reg);
+
+ qla4xxx_config_dma_addressing(ha);
+
+ /* Initialize lists and spinlocks. */
+ INIT_LIST_HEAD(&ha->ddb_list);
+ INIT_LIST_HEAD(&ha->free_srb_q);
+
+ mutex_init(&ha->mbox_sem);
+ init_waitqueue_head(&ha->mailbox_wait_queue);
+
+ spin_lock_init(&ha->hardware_lock);
+
+ /* Allocate dma buffers */
+ if (qla4xxx_mem_alloc(ha)) {
+ dev_warn(&ha->pdev->dev,
+ "[ERROR] Failed to allocate memory for adapter\n");
+
+ ret = -ENOMEM;
+ goto probe_failed;
+ }
+
+ /*
+ * Initialize the Host adapter request/response queues and
+ * firmware
+ * NOTE: interrupts enabled upon successful completion
+ */
+ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+ while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
+ DEBUG2(printk("scsi: %s: retrying adapter initialization "
+ "(%d)\n", __func__, init_retry_count));
+ qla4xxx_soft_reset(ha);
+ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+ }
+ if (status == QLA_ERROR) {
+ dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n");
+
+ ret = -ENODEV;
+ goto probe_failed;
+ }
+
+ host->cmd_per_lun = 3;
+ host->max_channel = 0;
+ host->max_lun = MAX_LUNS - 1;
+ host->max_id = MAX_TARGETS;
+ host->max_cmd_len = IOCB_MAX_CDB_LEN;
+ host->can_queue = MAX_SRBS ;
+ host->transportt = qla4xxx_scsi_transport;
+
+ ret = scsi_init_shared_tag_map(host, MAX_SRBS);
+ if (ret) {
+ dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed");
+ goto probe_failed;
+ }
+
+ /* Startup the kernel thread for this host adapter. */
+ DEBUG2(printk("scsi: %s: Starting kernel thread for "
+ "qla4xxx_dpc\n", __func__));
+ sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
+ ha->dpc_thread = create_singlethread_workqueue(buf);
+ if (!ha->dpc_thread) {
+ dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n");
+ ret = -ENODEV;
+ goto probe_failed;
+ }
+ INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
+
+ ret = request_irq(pdev->irq, qla4xxx_intr_handler,
+ SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha);
+ if (ret) {
+ dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
+ " already in use.\n", pdev->irq);
+ goto probe_failed;
+ }
+ set_bit(AF_IRQ_ATTACHED, &ha->flags);
+ host->irq = pdev->irq;
+ DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));
+
+ qla4xxx_enable_intrs(ha);
+
+ /* Start timer thread. */
+ qla4xxx_start_timer(ha, qla4xxx_timer, 1);
+
+ set_bit(AF_INIT_DONE, &ha->flags);
+
+ pci_set_drvdata(pdev, ha);
+
+ ret = scsi_add_host(host, &pdev->dev);
+ if (ret)
+ goto probe_failed;
+
+ /* Update transport device information for all devices. */
+ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
+ if (qla4xxx_add_sess(ddb_entry))
+ goto remove_host;
+ }
+
+ printk(KERN_INFO
+ " QLogic iSCSI HBA Driver version: %s\n"
+ " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
+ qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
+ ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
+ ha->patch_number, ha->build_number);
+
+ return 0;
+
+remove_host:
+ qla4xxx_free_ddb_list(ha);
+ scsi_remove_host(host);
+
+probe_failed:
+ qla4xxx_free_adapter(ha);
+ scsi_host_put(ha->host);
+
+probe_disable_device:
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+/**
+ * qla4xxx_remove_adapter - calback function to remove adapter.
+ * @pci_dev: PCI device pointer
+ **/
+static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
+{
+ struct scsi_qla_host *ha;
+
+ ha = pci_get_drvdata(pdev);
+
+ /* remove devs from iscsi_sessions to scsi_devices */
+ qla4xxx_free_ddb_list(ha);
+
+ scsi_remove_host(ha->host);
+
+ qla4xxx_free_adapter(ha);
+
+ scsi_host_put(ha->host);
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+/**
+ * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
+ * @ha: HA context
+ *
+ * At exit, the @ha's flags.enable_64bit_addressing set to indicated
+ * supported addressing method.
+ */
+void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+{
+ int retval;
+
+ /* Update our PCI device dma_mask for full 64 bit mask */
+ if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
+ if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
+ dev_dbg(&ha->pdev->dev,
+ "Failed to set 64 bit PCI consistent mask; "
+ "using 32 bit.\n");
+ retval = pci_set_consistent_dma_mask(ha->pdev,
+ DMA_32BIT_MASK);
+ }
+ } else
+ retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
+}
+
+static int qla4xxx_slave_alloc(struct scsi_device *sdev)
+{
+ struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target);
+ struct ddb_entry *ddb = sess->dd_data;
+
+ sdev->hostdata = ddb;
+ sdev->tagged_supported = 1;
+ scsi_activate_tcq(sdev, sdev->host->can_queue);
+ return 0;
+}
+
+static int qla4xxx_slave_configure(struct scsi_device *sdev)
+{
+ sdev->tagged_supported = 1;
+ return 0;
+}
+
+static void qla4xxx_slave_destroy(struct scsi_device *sdev)
+{
+ scsi_deactivate_tcq(sdev, 1);
+}
+
+/**
+ * qla4xxx_del_from_active_array - returns an active srb
+ * @ha: Pointer to host adapter structure.
+ * @index: index into to the active_array
+ *
+ * This routine removes and returns the srb at the specified index
+ **/
+struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
+{
+ struct srb *srb = NULL;
+ struct scsi_cmnd *cmd;
+
+ if (!(cmd = scsi_host_find_tag(ha->host, index)))
+ return srb;
+
+ if (!(srb = (struct srb *)cmd->host_scribble))
+ return srb;
+
+ /* 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 = NULL;
+ }
+ return srb;
+}
+
+/**
+ * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
+ * @ha: actual ha whose done queue will contain the comd returned by firmware.
+ * @cmd: Scsi Command to wait on.
+ *
+ * This routine waits for the command to be returned by the Firmware
+ * for some max time.
+ **/
+static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
+ struct scsi_cmnd *cmd)
+{
+ int done = 0;
+ struct srb *rp;
+ uint32_t max_wait_time = EH_WAIT_CMD_TOV;
+
+ do {
+ /* Checking to see if its returned to OS */
+ rp = (struct srb *) cmd->SCp.ptr;
+ if (rp == NULL) {
+ done++;
+ break;
+ }
+
+ msleep(2000);
+ } while (max_wait_time--);
+
+ return done;
+}
+
+/**
+ * qla4xxx_wait_for_hba_online - waits for HBA to come online
+ * @ha: Pointer to host adapter structure
+ **/
+static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
+{
+ unsigned long wait_online;
+
+ wait_online = jiffies + (30 * HZ);
+ while (time_before(jiffies, wait_online)) {
+
+ if (adapter_up(ha))
+ return QLA_SUCCESS;
+ else if (ha->retry_reset_ha_cnt == 0)
+ return QLA_ERROR;
+
+ msleep(2000);
+ }
+
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish.
+ * @ha: pointer to to HBA
+ * @t: target id
+ * @l: lun id
+ *
+ * This function waits for all outstanding commands to a lun to complete. It
+ * returns 0 if all pending commands are returned and 1 otherwise.
+ **/
+static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,
+ int t, int l)
+{
+ int cnt;
+ int status = 0;
+ struct scsi_cmnd *cmd;
+
+ /*
+ * Waiting for all commands for the designated target in the active
+ * array
+ */
+ for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
+ cmd = scsi_host_find_tag(ha->host, cnt);
+ if (cmd && cmd->device->id == t && cmd->device->lun == l) {
+ if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+ status++;
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * qla4xxx_eh_device_reset - callback for target reset.
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is called by the Linux OS to reset all luns on the
+ * specified target.
+ **/
+static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
+{
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
+ struct srb *sp;
+ int ret = FAILED, stat;
+
+ sp = (struct srb *) cmd->SCp.ptr;
+ if (!sp || !ddb_entry)
+ return ret;
+
+ dev_info(&ha->pdev->dev,
+ "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
+ cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+ DEBUG2(printk(KERN_INFO
+ "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
+ "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
+ cmd, jiffies, cmd->timeout_per_command / HZ,
+ ha->dpc_flags, cmd->result, cmd->allowed));
+
+ /* FIXME: wait for hba to go online */
+ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
+ if (stat != QLA_SUCCESS) {
+ dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
+ goto eh_dev_reset_done;
+ }
+
+ /* Send marker. */
+ ha->marker_needed = 1;
+
+ /*
+ * If we are coming down the EH path, wait for all commands to complete
+ * for the device.
+ */
+ if (cmd->device->host->shost_state == SHOST_RECOVERY) {
+ if (qla4xxx_eh_wait_for_active_target_commands(ha,
+ cmd->device->id,
+ cmd->device->lun)){
+ dev_info(&ha->pdev->dev,
+ "DEVICE RESET FAILED - waiting for "
+ "commands.\n");
+ goto eh_dev_reset_done;
+ }
+ }
+
+ dev_info(&ha->pdev->dev,
+ "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
+ ha->host_no, cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
+
+ ret = SUCCESS;
+
+eh_dev_reset_done:
+
+ return ret;
+}
+
+/**
+ * qla4xxx_eh_host_reset - kernel callback
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is invoked by the Linux kernel to perform fatal error
+ * recovery on the specified adapter.
+ **/
+static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
+{
+ int return_status = FAILED;
+ struct scsi_qla_host *ha;
+
+ ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
+
+ dev_info(&ha->pdev->dev,
+ "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+ cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+ if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter "
+ "DEAD.\n", ha->host_no, cmd->device->channel,
+ __func__));
+
+ return FAILED;
+ }
+
+ if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) {
+ return_status = SUCCESS;
+ }
+
+ dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
+ return_status == FAILED ? "FAILED" : "SUCCEDED");
+
+ return return_status;
+}
+
+
+static struct pci_device_id qla4xxx_pci_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP4010,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP4022,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP4032,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
+
+struct pci_driver qla4xxx_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = qla4xxx_pci_tbl,
+ .probe = qla4xxx_probe_adapter,
+ .remove = qla4xxx_remove_adapter,
+};
+
+static int __init qla4xxx_module_init(void)
+{
+ int ret;
+
+ /* Allocate cache for SRBs. */
+ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (srb_cachep == NULL) {
+ printk(KERN_ERR
+ "%s: Unable to allocate SRB cache..."
+ "Failing load!\n", DRIVER_NAME);
+ ret = -ENOMEM;
+ goto no_srp_cache;
+ }
+
+ /* Derive version string. */
+ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
+ if (ql4xextended_error_logging)
+ strcat(qla4xxx_version_str, "-debug");
+
+ qla4xxx_scsi_transport =
+ iscsi_register_transport(&qla4xxx_iscsi_transport);
+ if (!qla4xxx_scsi_transport){
+ ret = -ENODEV;
+ goto release_srb_cache;
+ }
+
+ ret = pci_register_driver(&qla4xxx_pci_driver);
+ if (ret)
+ goto unregister_transport;
+
+ printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
+ return 0;
+
+unregister_transport:
+ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
+release_srb_cache:
+ kmem_cache_destroy(srb_cachep);
+no_srp_cache:
+ return ret;
+}
+
+static void __exit qla4xxx_module_exit(void)
+{
+ pci_unregister_driver(&qla4xxx_pci_driver);
+ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
+ kmem_cache_destroy(srb_cachep);
+}
+
+module_init(qla4xxx_module_init);
+module_exit(qla4xxx_module_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
new file mode 100644
index 00000000000..454e19c8ad6
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -0,0 +1,8 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#define QLA4XXX_DRIVER_VERSION "5.00.07-k"
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 52fb2ec3da7..2e7db18f5ae 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -209,7 +209,7 @@ static int ql_wai(struct qlogicfas408_priv *priv)
* caller must hold host lock
*/
-static void ql_icmd(Scsi_Cmnd * cmd)
+static void ql_icmd(struct scsi_cmnd *cmd)
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
int qbase = priv->qbase;
@@ -256,7 +256,7 @@ static void ql_icmd(Scsi_Cmnd * cmd)
* Process scsi command - usually after interrupt
*/
-static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
+static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
{
unsigned int i, j;
unsigned long k;
@@ -405,10 +405,10 @@ static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
* Interrupt handler
*/
-static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+static void ql_ihandl(void *dev_id)
{
- Scsi_Cmnd *icmd;
- struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+ struct scsi_cmnd *icmd;
+ struct Scsi_Host *host = dev_id;
struct qlogicfas408_priv *priv = get_priv_by_host(host);
int qbase = priv->qbase;
REG0;
@@ -432,13 +432,13 @@ static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
(icmd->scsi_done) (icmd);
}
-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *host = dev_id;
spin_lock_irqsave(host->host_lock, flags);
- ql_ihandl(irq, dev_id, regs);
+ ql_ihandl(dev_id);
spin_unlock_irqrestore(host->host_lock, flags);
return IRQ_HANDLED;
}
@@ -447,7 +447,8 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
* Queued command
*/
-int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+int qlogicfas408_queuecommand(struct scsi_cmnd *cmd,
+ void (*done) (struct scsi_cmnd *))
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
if (scmd_id(cmd) == priv->qinitid) {
@@ -470,9 +471,8 @@ int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
* Return bios parameters
*/
-int qlogicfas408_biosparam(struct scsi_device * disk,
- struct block_device *dev,
- sector_t capacity, int ip[])
+int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
+ sector_t capacity, int ip[])
{
/* This should mimic the DOS Qlogic driver's behavior exactly */
ip[0] = 0x40;
@@ -494,7 +494,7 @@ int qlogicfas408_biosparam(struct scsi_device * disk,
* Abort a command in progress
*/
-int qlogicfas408_abort(Scsi_Cmnd * cmd)
+int qlogicfas408_abort(struct scsi_cmnd *cmd)
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
priv->qabort = 1;
@@ -508,7 +508,7 @@ int qlogicfas408_abort(Scsi_Cmnd * cmd)
* the PCMCIA qlogic_stub code. This wants fixing
*/
-int qlogicfas408_bus_reset(Scsi_Cmnd * cmd)
+int qlogicfas408_bus_reset(struct scsi_cmnd *cmd)
{
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
unsigned long flags;
diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h
index 4b3df200366..260626427a3 100644
--- a/drivers/scsi/qlogicfas408.h
+++ b/drivers/scsi/qlogicfas408.h
@@ -75,15 +75,15 @@
/*----------------------------------------------------------------*/
struct qlogicfas408_priv {
- int qbase; /* Port */
- int qinitid; /* initiator ID */
- int qabort; /* Flag to cause an abort */
- int qlirq; /* IRQ being used */
- int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */
- char qinfo[80]; /* description */
- Scsi_Cmnd *qlcmd; /* current command being processed */
- struct Scsi_Host *shost; /* pointer back to host */
- struct qlogicfas408_priv *next; /* next private struct */
+ int qbase; /* Port */
+ int qinitid; /* initiator ID */
+ int qabort; /* Flag to cause an abort */
+ int qlirq; /* IRQ being used */
+ int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */
+ char qinfo[80]; /* description */
+ struct scsi_cmnd *qlcmd; /* current command being processed */
+ struct Scsi_Host *shost; /* pointer back to host */
+ struct qlogicfas408_priv *next; /* next private struct */
};
/* The qlogic card uses two register maps - These macros select which one */
@@ -102,13 +102,14 @@ struct qlogicfas408_priv {
#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0])
#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs);
-int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
+int qlogicfas408_queuecommand(struct scsi_cmnd * cmd,
+ void (*done) (struct scsi_cmnd *));
int qlogicfas408_biosparam(struct scsi_device * disk,
- struct block_device *dev,
- sector_t capacity, int ip[]);
-int qlogicfas408_abort(Scsi_Cmnd * cmd);
-int qlogicfas408_bus_reset(Scsi_Cmnd * cmd);
+ struct block_device *dev,
+ sector_t capacity, int ip[]);
+int qlogicfas408_abort(struct scsi_cmnd * cmd);
+int qlogicfas408_bus_reset(struct scsi_cmnd * cmd);
const char *qlogicfas408_info(struct Scsi_Host *host);
int qlogicfas408_get_chip_type(int qbase, int int_type);
void qlogicfas408_setup(int qbase, int id, int int_type);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 5b2f0741a55..9b827ceec50 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
#define PTI_RESET_LIMIT 400
-static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
+static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti)
{
struct Scsi_Host *host = qpti->qhost;
unsigned short csum = 0;
@@ -649,7 +649,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
return 0;
}
-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t qpti_intr(int irq, void *dev_id);
static void __init qpti_chain_add(struct qlogicpti *qpti)
{
@@ -1297,7 +1297,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
return done_queue;
}
-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t qpti_intr(int irq, void *dev_id)
{
struct qlogicpti *qpti = dev_id;
unsigned long flags;
diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c
index 1545b30681b..19aa84f4601 100644
--- a/drivers/scsi/qlogicpti_asm.c
+++ b/drivers/scsi/qlogicpti_asm.c
@@ -1,5 +1,5 @@
/* Version 1.31.00 ISP1000 Initiator RISC firmware */
-unsigned short sbus_risc_code01[] __initdata = {
+unsigned short sbus_risc_code01[] __devinitdata = {
0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50,
0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
@@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __initdata = {
0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c,
0x92a7
};
-unsigned short sbus_risc_code_length01 = 0x2419;
+unsigned short __devinitdata sbus_risc_code_length01 = 0x2419;
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 327b33a57b0..86e13183c9b 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -215,18 +215,19 @@ static void raid_component_release(struct class_device *cdev)
kfree(rc);
}
-void raid_component_add(struct raid_template *r,struct device *raid_dev,
- struct device *component_dev)
+int raid_component_add(struct raid_template *r,struct device *raid_dev,
+ struct device *component_dev)
{
struct class_device *cdev =
attribute_container_find_class_device(&r->raid_attrs.ac,
raid_dev);
struct raid_component *rc;
struct raid_data *rd = class_get_devdata(cdev);
+ int err;
rc = kzalloc(sizeof(*rc), GFP_KERNEL);
if (!rc)
- return;
+ return -ENOMEM;
INIT_LIST_HEAD(&rc->node);
class_device_initialize(&rc->cdev);
@@ -239,7 +240,18 @@ void raid_component_add(struct raid_template *r,struct device *raid_dev,
list_add_tail(&rc->node, &rd->component_list);
rc->cdev.parent = cdev;
rc->cdev.class = &raid_class.class;
- class_device_add(&rc->cdev);
+ err = class_device_add(&rc->cdev);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ list_del(&rc->node);
+ rd->component_count--;
+ put_device(component_dev);
+ kfree(rc);
+ return err;
}
EXPORT_SYMBOL(raid_component_add);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 7a054f9d1ee..24cffd98ee6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -128,7 +128,7 @@ const char * scsi_device_type(unsigned type)
return "Well-known LUN ";
if (type == 0x1f)
return "No Device ";
- if (type > ARRAY_SIZE(scsi_device_types))
+ if (type >= ARRAY_SIZE(scsi_device_types))
return "Unknown ";
return scsi_device_types[type];
}
@@ -136,7 +136,7 @@ const char * scsi_device_type(unsigned type)
EXPORT_SYMBOL(scsi_device_type);
struct scsi_host_cmd_pool {
- kmem_cache_t *slab;
+ struct kmem_cache *slab;
unsigned int users;
char *name;
unsigned int slab_flags;
@@ -156,8 +156,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
static DEFINE_MUTEX(host_cmd_pool_mutex);
-static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
- gfp_t gfp_mask)
+struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
struct scsi_cmnd *cmd;
@@ -178,6 +177,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
return cmd;
}
+EXPORT_SYMBOL_GPL(__scsi_get_command);
/*
* Function: scsi_get_command()
@@ -214,9 +214,29 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
put_device(&dev->sdev_gendev);
return cmd;
-}
+}
EXPORT_SYMBOL(scsi_get_command);
+void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
+ struct device *dev)
+{
+ unsigned long flags;
+
+ /* changing locks here, don't need to restore the irq state */
+ spin_lock_irqsave(&shost->free_list_lock, flags);
+ if (unlikely(list_empty(&shost->free_list))) {
+ list_add(&cmd->list, &shost->free_list);
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+ if (likely(cmd != NULL))
+ kmem_cache_free(shost->cmd_pool->slab, cmd);
+
+ put_device(dev);
+}
+EXPORT_SYMBOL(__scsi_put_command);
+
/*
* Function: scsi_put_command()
*
@@ -231,26 +251,15 @@ EXPORT_SYMBOL(scsi_get_command);
void scsi_put_command(struct scsi_cmnd *cmd)
{
struct scsi_device *sdev = cmd->device;
- struct Scsi_Host *shost = sdev->host;
unsigned long flags;
-
+
/* serious error if the command hasn't come from a device list */
spin_lock_irqsave(&cmd->device->list_lock, flags);
BUG_ON(list_empty(&cmd->list));
list_del_init(&cmd->list);
- spin_unlock(&cmd->device->list_lock);
- /* changing locks here, don't need to restore the irq state */
- spin_lock(&shost->free_list_lock);
- if (unlikely(list_empty(&shost->free_list))) {
- list_add(&cmd->list, &shost->free_list);
- cmd = NULL;
- }
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
-
- if (likely(cmd != NULL))
- kmem_cache_free(shost->cmd_pool->slab, cmd);
+ spin_unlock_irqrestore(&cmd->device->list_lock, flags);
- put_device(&sdev->sdev_gendev);
+ __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
}
EXPORT_SYMBOL(scsi_put_command);
@@ -592,12 +601,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
return rtn;
}
-
-/*
- * Per-CPU I/O completion queue.
- */
-static DEFINE_PER_CPU(struct list_head, scsi_done_q);
-
/**
* scsi_req_abort_cmd -- Request command recovery for the specified command
* cmd: pointer to the SCSI command of interest
@@ -877,9 +880,9 @@ EXPORT_SYMBOL(scsi_device_get);
*/
void scsi_device_put(struct scsi_device *sdev)
{
+#ifdef CONFIG_MODULE_UNLOAD
struct module *module = sdev->host->hostt->module;
-#ifdef CONFIG_MODULE_UNLOAD
/* The module refcount will be zero if scsi_device_get()
* was called from a module removal routine */
if (module && module_refcount(module) != 0)
@@ -1065,7 +1068,7 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
- if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) {
+ if (scmd->request) {
/*
* If we are unable to remove the timer, it means
* that the command has already timed out or
@@ -1102,7 +1105,7 @@ MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels");
static int __init init_scsi(void)
{
- int error, i;
+ int error;
error = scsi_init_queue();
if (error)
@@ -1123,9 +1126,6 @@ static int __init init_scsi(void)
if (error)
goto cleanup_sysctl;
- for_each_possible_cpu(i)
- INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
-
scsi_netlink_init();
printk(KERN_NOTICE "SCSI subsystem initialized\n");
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9c0f35820e3..30ee3d72c02 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -52,7 +52,7 @@
#include "scsi_debug.h"
#define SCSI_DEBUG_VERSION "1.80"
-static const char * scsi_debug_version_date = "20060914";
+static const char * scsi_debug_version_date = "20061018";
/* Additional Sense Code (ASC) used */
#define NO_ADDITIONAL_SENSE 0x0
@@ -254,6 +254,8 @@ static int resp_requests(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
static int resp_start_stop(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip);
+static int resp_report_tgtpgs(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip);
static int resp_readcap(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
static int resp_readcap16(struct scsi_cmnd * SCpnt,
@@ -287,9 +289,9 @@ static void __init sdebug_build_parts(unsigned char * ramp);
static void __init init_all_queued(void);
static void stop_all_queued(void);
static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
- int dev_id_num, const char * dev_id_str,
- int dev_id_str_len);
+static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
+ int target_dev_id, int dev_id_num,
+ const char * dev_id_str, int dev_id_str_len);
static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
@@ -422,6 +424,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
}
errsts = resp_readcap16(SCpnt, devip);
break;
+ case MAINTENANCE_IN:
+ if (MI_REPORT_TARGET_PGS != cmd[1]) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+ errsts = resp_report_tgtpgs(SCpnt, devip);
+ break;
case READ_16:
case READ_12:
case READ_10:
@@ -665,8 +676,9 @@ static const char * inq_vendor_id = "Linux ";
static const char * inq_product_id = "scsi_debug ";
static const char * inq_product_rev = "0004";
-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
- int dev_id_num, const char * dev_id_str,
+static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
+ int target_dev_id, int dev_id_num,
+ const char * dev_id_str,
int dev_id_str_len)
{
int num, port_a;
@@ -720,6 +732,15 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
arr[num++] = (port_a >> 16) & 0xff;
arr[num++] = (port_a >> 8) & 0xff;
arr[num++] = port_a & 0xff;
+ /* NAA-5, Target port group identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x95; /* piv=1, target port group id */
+ arr[num++] = 0x0;
+ arr[num++] = 0x4;
+ arr[num++] = 0;
+ arr[num++] = 0;
+ arr[num++] = (port_group_id >> 8) & 0xff;
+ arr[num++] = port_group_id & 0xff;
/* NAA-5, Target device identifier */
arr[num++] = 0x61; /* proto=sas, binary */
arr[num++] = 0xa3; /* piv=1, target device, naa */
@@ -928,12 +949,12 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip)
{
unsigned char pq_pdt;
- unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+ unsigned char * arr;
unsigned char *cmd = (unsigned char *)scp->cmnd;
- int alloc_len, n;
+ int alloc_len, n, ret;
alloc_len = (cmd[3] << 8) + cmd[4];
- memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+ arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL);
if (devip->wlun)
pq_pdt = 0x1e; /* present, wlun */
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
@@ -944,12 +965,15 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
if (0x2 & cmd[1]) { /* CMDDT bit set */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
+ kfree(arr);
return check_condition_result;
} else if (0x1 & cmd[1]) { /* EVPD bit set */
- int lu_id_num, target_dev_id, len;
+ int lu_id_num, port_group_id, target_dev_id, len;
char lu_id_str[6];
int host_no = devip->sdbg_host->shost->host_no;
+ port_group_id = (((host_no + 1) & 0x7f) << 8) +
+ (devip->channel & 0x7f);
if (0 == scsi_debug_vpd_use_hostno)
host_no = 0;
lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
@@ -977,8 +1001,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
memcpy(&arr[4], lu_id_str, len);
} else if (0x83 == cmd[2]) { /* device identification */
arr[1] = cmd[2]; /*sanity */
- arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
- lu_id_num, lu_id_str, len);
+ arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
+ target_dev_id, lu_id_num,
+ lu_id_str, len);
} else if (0x84 == cmd[2]) { /* Software interface ident. */
arr[1] = cmd[2]; /*sanity */
arr[3] = inquiry_evpd_84(&arr[4]);
@@ -1012,17 +1037,22 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
/* Illegal request, invalid field in cdb */
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
+ kfree(arr);
return check_condition_result;
}
len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
- return fill_from_dev_buffer(scp, arr,
+ ret = fill_from_dev_buffer(scp, arr,
min(len, SDEBUG_MAX_INQ_ARR_SZ));
+ kfree(arr);
+ return ret;
}
/* drops through here for a standard inquiry */
arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
arr[2] = scsi_debug_scsi_level;
arr[3] = 2; /* response_data_format==2 */
arr[4] = SDEBUG_LONG_INQ_SZ - 5;
+ if (0 == scsi_debug_vpd_use_hostno)
+ arr[5] = 0x10; /* claim: implicit TGPS */
arr[6] = 0x10; /* claim: MultiP */
/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
arr[7] = 0xa; /* claim: LINKED + CMDQUE */
@@ -1039,8 +1069,10 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
}
arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
- return fill_from_dev_buffer(scp, arr,
+ ret = fill_from_dev_buffer(scp, arr,
min(alloc_len, SDEBUG_LONG_INQ_SZ));
+ kfree(arr);
+ return ret;
}
static int resp_requests(struct scsi_cmnd * scp,
@@ -1171,6 +1203,87 @@ static int resp_readcap16(struct scsi_cmnd * scp,
min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
}
+#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
+
+static int resp_report_tgtpgs(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+ unsigned char * arr;
+ int host_no = devip->sdbg_host->shost->host_no;
+ int n, ret, alen, rlen;
+ int port_group_a, port_group_b, port_a, port_b;
+
+ alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
+ + cmd[9]);
+
+ arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL);
+ /*
+ * EVPD page 0x88 states we have two ports, one
+ * real and a fake port with no device connected.
+ * So we create two port groups with one port each
+ * and set the group with port B to unavailable.
+ */
+ port_a = 0x1; /* relative port A */
+ port_b = 0x2; /* relative port B */
+ port_group_a = (((host_no + 1) & 0x7f) << 8) +
+ (devip->channel & 0x7f);
+ port_group_b = (((host_no + 1) & 0x7f) << 8) +
+ (devip->channel & 0x7f) + 0x80;
+
+ /*
+ * The asymmetric access state is cycled according to the host_id.
+ */
+ n = 4;
+ if (0 == scsi_debug_vpd_use_hostno) {
+ arr[n++] = host_no % 3; /* Asymm access state */
+ arr[n++] = 0x0F; /* claim: all states are supported */
+ } else {
+ arr[n++] = 0x0; /* Active/Optimized path */
+ arr[n++] = 0x01; /* claim: only support active/optimized paths */
+ }
+ arr[n++] = (port_group_a >> 8) & 0xff;
+ arr[n++] = port_group_a & 0xff;
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = 0; /* Status code */
+ arr[n++] = 0; /* Vendor unique */
+ arr[n++] = 0x1; /* One port per group */
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = (port_a >> 8) & 0xff;
+ arr[n++] = port_a & 0xff;
+ arr[n++] = 3; /* Port unavailable */
+ arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
+ arr[n++] = (port_group_b >> 8) & 0xff;
+ arr[n++] = port_group_b & 0xff;
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = 0; /* Status code */
+ arr[n++] = 0; /* Vendor unique */
+ arr[n++] = 0x1; /* One port per group */
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = 0; /* Reserved */
+ arr[n++] = (port_b >> 8) & 0xff;
+ arr[n++] = port_b & 0xff;
+
+ rlen = n - 4;
+ arr[0] = (rlen >> 24) & 0xff;
+ arr[1] = (rlen >> 16) & 0xff;
+ arr[2] = (rlen >> 8) & 0xff;
+ arr[3] = rlen & 0xff;
+
+ /*
+ * Return the smallest value of either
+ * - The allocated length
+ * - The constructed command length
+ * - The maximum array size
+ */
+ rlen = min(alen,n);
+ ret = fill_from_dev_buffer(scp, arr,
+ min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
+ kfree(arr);
+ return ret;
+}
+
/* <<Following mode page info copied from ST318451LW>> */
static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 3d0429bc14a..ce63044b1ec 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -150,6 +150,7 @@ static struct {
{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
{"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */
{"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */
+ {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
{"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -161,6 +162,11 @@ static struct {
{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
{"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
{"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
@@ -168,6 +174,14 @@ static struct {
{"HP", "C1557A", NULL, BLIST_FORCELUN},
{"HP", "C3323-300", "4269", BLIST_NOTQ},
{"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
+ {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
@@ -188,6 +202,7 @@ static struct {
{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -210,6 +225,7 @@ static struct {
{"SUN", "T300", "*", BLIST_SPARSELUN},
{"SUN", "T4", "*", BLIST_SPARSELUN},
{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+ {"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 3d355d05461..2ecb6ff4244 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -453,9 +453,18 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
}
/**
- * scsi_send_eh_cmnd - send a cmd to a device as part of error recovery.
- * @scmd: SCSI Cmd to send.
- * @timeout: Timeout for cmd.
+ * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * @scmd: SCSI command structure to hijack
+ * @cmnd: CDB to send
+ * @cmnd_size: size in bytes of @cmnd
+ * @timeout: timeout for this request
+ * @copy_sense: request sense data if set to 1
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process. If @copy_sense is 0 the command
+ * sent must be one that does not transfer any data. If @copy_sense is 1
+ * the command must be REQUEST_SENSE and this functions copies out the
+ * sense buffer it got into @scmd->sense_buffer.
*
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
@@ -469,6 +478,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
DECLARE_COMPLETION_ONSTACK(done);
unsigned long timeleft;
unsigned long flags;
+ struct scatterlist sgl;
unsigned char old_cmnd[MAX_COMMAND_SIZE];
enum dma_data_direction old_data_direction;
unsigned short old_use_sg;
@@ -495,24 +505,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
memcpy(scmd->cmnd, cmnd, cmnd_size);
if (copy_sense) {
- int gfp_mask = GFP_ATOMIC;
+ gfp_t gfp_mask = GFP_ATOMIC;
if (shost->hostt->unchecked_isa_dma)
gfp_mask |= __GFP_DMA;
- scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->request_bufflen = 252;
- scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask);
- if (!scmd->request_buffer)
+ sgl.page = alloc_page(gfp_mask);
+ if (!sgl.page)
return FAILED;
+ sgl.offset = 0;
+ sgl.length = 252;
+
+ scmd->sc_data_direction = DMA_FROM_DEVICE;
+ scmd->request_bufflen = sgl.length;
+ scmd->request_buffer = &sgl;
+ scmd->use_sg = 1;
} else {
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
scmd->sc_data_direction = DMA_NONE;
+ scmd->use_sg = 0;
}
scmd->underflow = 0;
- scmd->use_sg = 0;
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
if (sdev->scsi_level <= SCSI_2)
@@ -583,7 +598,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
memcpy(scmd->sense_buffer, scmd->request_buffer,
sizeof(scmd->sense_buffer));
}
- kfree(scmd->request_buffer);
+ __free_page(sgl.page);
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d6743b959a7..1748e27501c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -36,7 +36,7 @@
struct scsi_host_sg_pool {
size_t size;
char *name;
- kmem_cache_t *slab;
+ struct kmem_cache *slab;
mempool_t *pool;
};
@@ -82,7 +82,7 @@ static void scsi_unprep_request(struct request *req)
{
struct scsi_cmnd *cmd = req->special;
- req->flags &= ~REQ_DONTPREP;
+ req->cmd_flags &= ~REQ_DONTPREP;
req->special = NULL;
scsi_put_command(cmd);
@@ -196,7 +196,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
req->sense_len = 0;
req->retries = retries;
req->timeout = timeout;
- req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET;
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT;
/*
* head injection *required* here otherwise quiesce won't work
@@ -240,7 +241,7 @@ struct scsi_io_context {
char sense[SCSI_SENSE_BUFFERSIZE];
};
-static kmem_cache_t *scsi_io_context_cache;
+static struct kmem_cache *scsi_io_context_cache;
static void scsi_end_async(struct request *req, int uptodate)
{
@@ -397,7 +398,8 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
req = blk_get_request(sdev->request_queue, write, gfp);
if (!req)
goto free_sense;
- req->flags |= REQ_BLOCK_PC | REQ_QUIET;
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_QUIET;
if (use_sg)
err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp);
@@ -408,6 +410,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
goto free_req;
req->cmd_len = cmd_len;
+ memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
memcpy(req->cmd, cmd, req->cmd_len);
req->sense = sioc->sense;
req->sense_len = 0;
@@ -424,7 +427,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
free_req:
blk_put_request(req);
free_sense:
- kfree(sioc);
+ kmem_cache_free(scsi_io_context_cache, sioc);
return DRIVER_ERROR << 24;
}
EXPORT_SYMBOL_GPL(scsi_execute_async);
@@ -701,7 +704,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
return NULL;
}
-static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
{
struct scsi_host_sg_pool *sgp;
struct scatterlist *sgl;
@@ -742,7 +745,9 @@ static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_m
return sgl;
}
-static void scsi_free_sgtable(struct scatterlist *sgl, int index)
+EXPORT_SYMBOL(scsi_alloc_sgtable);
+
+void scsi_free_sgtable(struct scatterlist *sgl, int index)
{
struct scsi_host_sg_pool *sgp;
@@ -752,6 +757,8 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
mempool_free(sgl, sgp->pool);
}
+EXPORT_SYMBOL(scsi_free_sgtable);
+
/*
* Function: scsi_release_buffers()
*
@@ -933,7 +940,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break;
}
}
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"Device not ready: ");
scsi_print_sense_hdr("", &sshdr);
@@ -941,7 +948,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"Volume overflow, CDB: ");
__scsi_print_command(cmd->cmnd);
@@ -963,7 +970,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
return;
}
if (result) {
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"SCSI error: return code = 0x%08x\n",
result);
@@ -993,25 +1000,14 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
int count;
/*
- * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
- */
- if ((req->flags & REQ_BLOCK_PC) && !req->bio) {
- cmd->request_bufflen = req->data_len;
- cmd->request_buffer = req->data;
- req->buffer = req->data;
- cmd->use_sg = 0;
- return 0;
- }
-
- /*
- * we used to not use scatter-gather for single segment request,
+ * We used to not use scatter-gather for single segment request,
* but now we do (it makes highmem I/O easier to support without
* kmapping pages)
*/
cmd->use_sg = req->nr_phys_segments;
/*
- * if sg table allocation fails, requeue request later.
+ * If sg table allocation fails, requeue request later.
*/
sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
if (unlikely(!sgpnt)) {
@@ -1019,24 +1015,21 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
return BLKPREP_DEFER;
}
+ req->buffer = NULL;
cmd->request_buffer = (char *) sgpnt;
- cmd->request_bufflen = req->nr_sectors << 9;
if (blk_pc_request(req))
cmd->request_bufflen = req->data_len;
- req->buffer = NULL;
+ else
+ cmd->request_bufflen = req->nr_sectors << 9;
/*
* Next, walk the list, and fill in the addresses and sizes of
* each segment.
*/
count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-
- /*
- * mapped well, send it off
- */
if (likely(count <= cmd->use_sg)) {
cmd->use_sg = count;
- return 0;
+ return BLKPREP_OK;
}
printk(KERN_ERR "Incorrect number of segments after building list\n");
@@ -1066,6 +1059,27 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
return -EOPNOTSUPP;
}
+static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
+ struct request *req)
+{
+ struct scsi_cmnd *cmd;
+
+ if (!req->special) {
+ cmd = scsi_get_command(sdev, GFP_ATOMIC);
+ if (unlikely(!cmd))
+ return NULL;
+ req->special = cmd;
+ } else {
+ cmd = req->special;
+ }
+
+ /* pull a tag out of the request if we have one */
+ cmd->tag = req->tag;
+ cmd->request = req;
+
+ return cmd;
+}
+
static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
{
BUG_ON(!blk_pc_request(cmd->request));
@@ -1078,11 +1092,39 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
scsi_io_completion(cmd, cmd->request_bufflen);
}
-static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
{
- struct request *req = cmd->request;
+ struct scsi_cmnd *cmd;
+
+ cmd = scsi_get_cmd_from_req(sdev, req);
+ if (unlikely(!cmd))
+ return BLKPREP_DEFER;
- BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
+ /*
+ * BLOCK_PC requests may transfer data, in which case they must
+ * a bio attached to them. Or they might contain a SCSI command
+ * that does not transfer data, in which case they may optionally
+ * submit a request without an attached bio.
+ */
+ if (req->bio) {
+ int ret;
+
+ BUG_ON(!req->nr_phys_segments);
+
+ ret = scsi_init_io(cmd);
+ if (unlikely(ret))
+ return ret;
+ } else {
+ BUG_ON(req->data_len);
+ BUG_ON(req->data);
+
+ cmd->request_bufflen = 0;
+ cmd->request_buffer = NULL;
+ cmd->use_sg = 0;
+ req->buffer = NULL;
+ }
+
+ BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
cmd->cmd_len = req->cmd_len;
if (!req->data_len)
@@ -1096,156 +1138,138 @@ static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
cmd->allowed = req->retries;
cmd->timeout_per_command = req->timeout;
cmd->done = scsi_blk_pc_done;
+ return BLKPREP_OK;
}
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+/*
+ * Setup a REQ_TYPE_FS command. These are simple read/write request
+ * from filesystems that still need to be translated to SCSI CDBs from
+ * the ULD.
+ */
+static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
- struct scsi_device *sdev = q->queuedata;
struct scsi_cmnd *cmd;
- int specials_only = 0;
+ struct scsi_driver *drv;
+ int ret;
/*
- * Just check to see if the device is online. If it isn't, we
- * refuse to process any commands. The device must be brought
- * online before trying any recovery commands
+ * Filesystem requests must transfer data.
*/
- if (unlikely(!scsi_device_online(sdev))) {
- sdev_printk(KERN_ERR, sdev,
- "rejecting I/O to offline device\n");
- goto kill;
- }
- if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
- /* OK, we're not in a running state don't prep
- * user commands */
- if (sdev->sdev_state == SDEV_DEL) {
- /* Device is fully deleted, no commands
- * at all allowed down */
- sdev_printk(KERN_ERR, sdev,
- "rejecting I/O to dead device\n");
- goto kill;
- }
- /* OK, we only allow special commands (i.e. not
- * user initiated ones */
- specials_only = sdev->sdev_state;
- }
+ BUG_ON(!req->nr_phys_segments);
+
+ cmd = scsi_get_cmd_from_req(sdev, req);
+ if (unlikely(!cmd))
+ return BLKPREP_DEFER;
+
+ ret = scsi_init_io(cmd);
+ if (unlikely(ret))
+ return ret;
/*
- * Find the actual device driver associated with this command.
- * The SPECIAL requests are things like character device or
- * ioctls, which did not originate from ll_rw_blk. Note that
- * the special field is also used to indicate the cmd for
- * the remainder of a partially fulfilled request that can
- * come up when there is a medium error. We have to treat
- * these two cases differently. We differentiate by looking
- * at request->cmd, as this tells us the real story.
+ * Initialize the actual SCSI command for this request.
*/
- if (req->flags & REQ_SPECIAL && req->special) {
- cmd = req->special;
- } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+ drv = *(struct scsi_driver **)req->rq_disk->private_data;
+ if (unlikely(!drv->init_command(cmd))) {
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ return BLKPREP_KILL;
+ }
- if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
- if(specials_only == SDEV_QUIESCE ||
- specials_only == SDEV_BLOCK)
- goto defer;
-
+ return BLKPREP_OK;
+}
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+ struct scsi_device *sdev = q->queuedata;
+ int ret = BLKPREP_OK;
+
+ /*
+ * If the device is not in running state we will reject some
+ * or all commands.
+ */
+ if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
+ switch (sdev->sdev_state) {
+ case SDEV_OFFLINE:
+ /*
+ * If the device is offline we refuse to process any
+ * commands. The device must be brought online
+ * before trying any recovery commands.
+ */
sdev_printk(KERN_ERR, sdev,
- "rejecting I/O to device being removed\n");
- goto kill;
+ "rejecting I/O to offline device\n");
+ ret = BLKPREP_KILL;
+ break;
+ case SDEV_DEL:
+ /*
+ * If the device is fully deleted, we refuse to
+ * process any commands as well.
+ */
+ sdev_printk(KERN_ERR, sdev,
+ "rejecting I/O to dead device\n");
+ ret = BLKPREP_KILL;
+ break;
+ case SDEV_QUIESCE:
+ case SDEV_BLOCK:
+ /*
+ * If the devices is blocked we defer normal commands.
+ */
+ if (!(req->cmd_flags & REQ_PREEMPT))
+ ret = BLKPREP_DEFER;
+ break;
+ default:
+ /*
+ * For any other not fully online state we only allow
+ * special commands. In particular any user initiated
+ * command is not allowed.
+ */
+ if (!(req->cmd_flags & REQ_PREEMPT))
+ ret = BLKPREP_KILL;
+ break;
}
-
-
- /*
- * Now try and find a command block that we can use.
- */
- if (!req->special) {
- cmd = scsi_get_command(sdev, GFP_ATOMIC);
- if (unlikely(!cmd))
- goto defer;
- } else
- cmd = req->special;
-
- /* pull a tag out of the request if we have one */
- cmd->tag = req->tag;
- } else {
- blk_dump_rq_flags(req, "SCSI bad req");
- goto kill;
+
+ if (ret != BLKPREP_OK)
+ goto out;
}
-
- /* note the overloading of req->special. When the tag
- * is active it always means cmd. If the tag goes
- * back for re-queueing, it may be reset */
- req->special = cmd;
- cmd->request = req;
-
- /*
- * FIXME: drop the lock here because the functions below
- * expect to be called without the queue lock held. Also,
- * previously, we dequeued the request before dropping the
- * lock. We hope REQ_STARTED prevents anything untoward from
- * happening now.
- */
- if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
- int ret;
+ switch (req->cmd_type) {
+ case REQ_TYPE_BLOCK_PC:
+ ret = scsi_setup_blk_pc_cmnd(sdev, req);
+ break;
+ case REQ_TYPE_FS:
+ ret = scsi_setup_fs_cmnd(sdev, req);
+ break;
+ default:
/*
- * This will do a couple of things:
- * 1) Fill in the actual SCSI command.
- * 2) Fill in any other upper-level specific fields
- * (timeout).
+ * All other command types are not supported.
*
- * If this returns 0, it means that the request failed
- * (reading past end of disk, reading offline device,
- * etc). This won't actually talk to the device, but
- * some kinds of consistency checking may cause the
- * request to be rejected immediately.
+ * Note that these days the SCSI subsystem does not use
+ * REQ_TYPE_SPECIAL requests anymore. These are only used
+ * (directly or via blk_insert_request) by non-SCSI drivers.
*/
+ blk_dump_rq_flags(req, "SCSI bad req");
+ ret = BLKPREP_KILL;
+ break;
+ }
- /*
- * This sets up the scatter-gather table (allocating if
- * required).
- */
- ret = scsi_init_io(cmd);
- switch(ret) {
- /* For BLKPREP_KILL/DEFER the cmd was released */
- case BLKPREP_KILL:
- goto kill;
- case BLKPREP_DEFER:
- goto defer;
- }
-
+ out:
+ switch (ret) {
+ case BLKPREP_KILL:
+ req->errors = DID_NO_CONNECT << 16;
+ break;
+ case BLKPREP_DEFER:
/*
- * Initialize the actual SCSI command for this request.
+ * If we defer, the elv_next_request() returns NULL, but the
+ * queue must be restarted, so we plug here if no returning
+ * command will automatically do that.
*/
- if (req->flags & REQ_BLOCK_PC) {
- scsi_setup_blk_pc_cmnd(cmd);
- } else if (req->rq_disk) {
- struct scsi_driver *drv;
-
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- goto kill;
- }
- }
+ if (sdev->device_busy == 0)
+ blk_plug_device(q);
+ break;
+ default:
+ req->cmd_flags |= REQ_DONTPREP;
}
- /*
- * The request is now prepped, no need to come back here
- */
- req->flags |= REQ_DONTPREP;
- return BLKPREP_OK;
-
- defer:
- /* If we defer, the elv_next_request() returns NULL, but the
- * queue must be restarted, so we plug here if no returning
- * command will automatically do that. */
- if (sdev->device_busy == 0)
- blk_plug_device(q);
- return BLKPREP_DEFER;
- kill:
- req->errors = DID_NO_CONNECT << 16;
- return BLKPREP_KILL;
+ return ret;
}
/*
@@ -1454,8 +1478,9 @@ static void scsi_request_fn(struct request_queue *q)
if (unlikely(cmd == NULL)) {
printk(KERN_CRIT "impossible request in %s.\n"
"please mail a stack trace to "
- "linux-scsi@vger.kernel.org",
+ "linux-scsi@vger.kernel.org\n",
__FUNCTION__);
+ blk_dump_rq_flags(req, "foo");
BUG();
}
spin_lock(shost->host_lock);
@@ -1546,29 +1571,40 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
}
EXPORT_SYMBOL(scsi_calculate_bounce_limit);
-struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
+ request_fn_proc *request_fn)
{
- struct Scsi_Host *shost = sdev->host;
struct request_queue *q;
- q = blk_init_queue(scsi_request_fn, NULL);
+ q = blk_init_queue(request_fn, NULL);
if (!q)
return NULL;
- blk_queue_prep_rq(q, scsi_prep_fn);
-
blk_queue_max_hw_segments(q, shost->sg_tablesize);
blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
blk_queue_max_sectors(q, shost->max_sectors);
blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
blk_queue_segment_boundary(q, shost->dma_boundary);
- blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
- blk_queue_softirq_done(q, scsi_softirq_done);
if (!shost->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
return q;
}
+EXPORT_SYMBOL(__scsi_alloc_queue);
+
+struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+{
+ struct request_queue *q;
+
+ q = __scsi_alloc_queue(sdev->host, scsi_request_fn);
+ if (!q)
+ return NULL;
+
+ blk_queue_prep_rq(q, scsi_prep_fn);
+ blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+ blk_queue_softirq_done(q, scsi_softirq_done);
+ return q;
+}
void scsi_free_queue(struct request_queue *q)
{
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 5d023d44e5e..f458c2f686d 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -39,6 +39,9 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
{ };
#endif
+/* scsi_scan.c */
+int scsi_complete_async_scans(void);
+
/* scsi_devinfo.c */
extern int scsi_get_device_flags(struct scsi_device *sdev,
const unsigned char *vendor,
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index fd9e281c3bf..14e635aa44c 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -29,7 +29,9 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/spinlock.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -87,6 +89,17 @@ module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(max_luns,
"last scsi LUN (should be between 1 and 2^32-1)");
+#ifdef CONFIG_SCSI_SCAN_ASYNC
+#define SCSI_SCAN_TYPE_DEFAULT "async"
+#else
+#define SCSI_SCAN_TYPE_DEFAULT "sync"
+#endif
+
+static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;
+
+module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
+MODULE_PARM_DESC(scan, "sync, async or none");
+
/*
* max_scsi_report_luns: the maximum number of LUNS that will be
* returned from the REPORT LUNS command. 8 times this value must
@@ -108,6 +121,68 @@ MODULE_PARM_DESC(inq_timeout,
"Timeout (in seconds) waiting for devices to answer INQUIRY."
" Default is 5. Some non-compliant devices need more.");
+static DEFINE_SPINLOCK(async_scan_lock);
+static LIST_HEAD(scanning_hosts);
+
+struct async_scan_data {
+ struct list_head list;
+ struct Scsi_Host *shost;
+ struct completion prev_finished;
+};
+
+/**
+ * scsi_complete_async_scans - Wait for asynchronous scans to complete
+ *
+ * Asynchronous scans add themselves to the scanning_hosts list. Once
+ * that list is empty, we know that the scans are complete. Rather than
+ * waking up periodically to check the state of the list, we pretend to be
+ * a scanning task by adding ourselves at the end of the list and going to
+ * sleep. When the task before us wakes us up, we take ourselves off the
+ * list and return.
+ */
+int scsi_complete_async_scans(void)
+{
+ struct async_scan_data *data;
+
+ do {
+ if (list_empty(&scanning_hosts))
+ return 0;
+ /* If we can't get memory immediately, that's OK. Just
+ * sleep a little. Even if we never get memory, the async
+ * scans will finish eventually.
+ */
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ msleep(1);
+ } while (!data);
+
+ data->shost = NULL;
+ init_completion(&data->prev_finished);
+
+ spin_lock(&async_scan_lock);
+ /* Check that there's still somebody else on the list */
+ if (list_empty(&scanning_hosts))
+ goto done;
+ list_add_tail(&data->list, &scanning_hosts);
+ spin_unlock(&async_scan_lock);
+
+ printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");
+ wait_for_completion(&data->prev_finished);
+
+ spin_lock(&async_scan_lock);
+ list_del(&data->list);
+ done:
+ spin_unlock(&async_scan_lock);
+
+ kfree(data);
+ return 0;
+}
+
+#ifdef MODULE
+/* Only exported for the benefit of scsi_wait_scan */
+EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
+#endif
+
/**
* scsi_unlock_floptical - unlock device via a special MODE SENSE command
* @sdev: scsi device to send command to
@@ -362,9 +437,10 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
goto retry;
}
-static void scsi_target_reap_usercontext(void *data)
+static void scsi_target_reap_usercontext(struct work_struct *work)
{
- struct scsi_target *starget = data;
+ struct scsi_target *starget =
+ container_of(work, struct scsi_target, ew.work);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
@@ -400,7 +476,7 @@ void scsi_target_reap(struct scsi_target *starget)
starget->state = STARGET_DEL;
spin_unlock_irqrestore(shost->host_lock, flags);
execute_in_process_context(scsi_target_reap_usercontext,
- starget, &starget->ew);
+ &starget->ew);
return;
}
@@ -619,7 +695,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
* SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
**/
static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
- int *bflags)
+ int *bflags, int async)
{
/*
* XXX do not save the inquiry, since it can change underneath us,
@@ -631,12 +707,22 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
* scanning run at their own risk, or supply a user level program
* that can correctly scan.
*/
- sdev->inquiry = kmalloc(sdev->inquiry_len, GFP_ATOMIC);
- if (sdev->inquiry == NULL) {
+
+ /*
+ * Copy at least 36 bytes of INQUIRY data, so that we don't
+ * dereference unallocated memory when accessing the Vendor,
+ * Product, and Revision strings. Badly behaved devices may set
+ * the INQUIRY Additional Length byte to a small value, indicating
+ * these strings are invalid, but often they contain plausible data
+ * nonetheless. It doesn't matter if the device sent < 36 bytes
+ * total, since scsi_probe_lun() initializes inq_result with 0s.
+ */
+ sdev->inquiry = kmemdup(inq_result,
+ max_t(size_t, sdev->inquiry_len, 36),
+ GFP_ATOMIC);
+ if (sdev->inquiry == NULL)
return SCSI_SCAN_NO_RESPONSE;
- }
- memcpy(sdev->inquiry, inq_result, sdev->inquiry_len);
sdev->vendor = (char *) (sdev->inquiry + 8);
sdev->model = (char *) (sdev->inquiry + 16);
sdev->rev = (char *) (sdev->inquiry + 32);
@@ -795,7 +881,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
* register it and tell the rest of the kernel
* about it.
*/
- if (scsi_sysfs_add_sdev(sdev) != 0)
+ if (!async && scsi_sysfs_add_sdev(sdev) != 0)
return SCSI_SCAN_NO_RESPONSE;
return SCSI_SCAN_LUN_PRESENT;
@@ -964,7 +1050,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
goto out_free_result;
}
- res = scsi_add_lun(sdev, result, &bflags);
+ res = scsi_add_lun(sdev, result, &bflags, shost->async_scan);
if (res == SCSI_SCAN_LUN_PRESENT) {
if (bflags & BLIST_KEY) {
sdev->lockable = 0;
@@ -1464,6 +1550,12 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
{
struct Scsi_Host *shost = dev_to_shost(parent);
+ if (strncmp(scsi_scan_type, "none", 4) == 0)
+ return;
+
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
__scsi_scan_target(parent, channel, id, lun, rescan);
@@ -1509,6 +1601,9 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
"%s: <%u:%u:%u>\n",
__FUNCTION__, channel, id, lun));
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
@@ -1529,14 +1624,143 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
return 0;
}
+static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
+{
+ struct scsi_device *sdev;
+ shost_for_each_device(sdev, shost) {
+ if (scsi_sysfs_add_sdev(sdev) != 0)
+ scsi_destroy_sdev(sdev);
+ }
+}
+
+/**
+ * scsi_prep_async_scan - prepare for an async scan
+ * @shost: the host which will be scanned
+ * Returns: a cookie to be passed to scsi_finish_async_scan()
+ *
+ * Tells the midlayer this host is going to do an asynchronous scan.
+ * It reserves the host's position in the scanning list and ensures
+ * that other asynchronous scans started after this one won't affect the
+ * ordering of the discovered devices.
+ */
+static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
+{
+ struct async_scan_data *data;
+
+ if (strncmp(scsi_scan_type, "sync", 4) == 0)
+ return NULL;
+
+ if (shost->async_scan) {
+ printk("%s called twice for host %d", __FUNCTION__,
+ shost->host_no);
+ dump_stack();
+ return NULL;
+ }
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto err;
+ data->shost = scsi_host_get(shost);
+ if (!data->shost)
+ goto err;
+ init_completion(&data->prev_finished);
+
+ spin_lock(&async_scan_lock);
+ shost->async_scan = 1;
+ if (list_empty(&scanning_hosts))
+ complete(&data->prev_finished);
+ list_add_tail(&data->list, &scanning_hosts);
+ spin_unlock(&async_scan_lock);
+
+ return data;
+
+ err:
+ kfree(data);
+ return NULL;
+}
+
+/**
+ * scsi_finish_async_scan - asynchronous scan has finished
+ * @data: cookie returned from earlier call to scsi_prep_async_scan()
+ *
+ * All the devices currently attached to this host have been found.
+ * This function announces all the devices it has found to the rest
+ * of the system.
+ */
+static void scsi_finish_async_scan(struct async_scan_data *data)
+{
+ struct Scsi_Host *shost;
+
+ if (!data)
+ return;
+
+ shost = data->shost;
+ if (!shost->async_scan) {
+ printk("%s called twice for host %d", __FUNCTION__,
+ shost->host_no);
+ dump_stack();
+ return;
+ }
+
+ wait_for_completion(&data->prev_finished);
+
+ scsi_sysfs_add_devices(shost);
+
+ spin_lock(&async_scan_lock);
+ shost->async_scan = 0;
+ list_del(&data->list);
+ if (!list_empty(&scanning_hosts)) {
+ struct async_scan_data *next = list_entry(scanning_hosts.next,
+ struct async_scan_data, list);
+ complete(&next->prev_finished);
+ }
+ spin_unlock(&async_scan_lock);
+
+ scsi_host_put(shost);
+ kfree(data);
+}
+
+static void do_scsi_scan_host(struct Scsi_Host *shost)
+{
+ if (shost->hostt->scan_finished) {
+ unsigned long start = jiffies;
+ if (shost->hostt->scan_start)
+ shost->hostt->scan_start(shost);
+
+ while (!shost->hostt->scan_finished(shost, jiffies - start))
+ msleep(10);
+ } else {
+ scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+ SCAN_WILD_CARD, 0);
+ }
+}
+
+static int do_scan_async(void *_data)
+{
+ struct async_scan_data *data = _data;
+ do_scsi_scan_host(data->shost);
+ scsi_finish_async_scan(data);
+ return 0;
+}
+
/**
* scsi_scan_host - scan the given adapter
* @shost: adapter to scan
**/
void scsi_scan_host(struct Scsi_Host *shost)
{
- scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
- SCAN_WILD_CARD, 0);
+ struct async_scan_data *data;
+
+ if (strncmp(scsi_scan_type, "none", 4) == 0)
+ return;
+
+ data = scsi_prep_async_scan(shost);
+ if (!data) {
+ do_scsi_scan_host(shost);
+ return;
+ }
+
+ kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index e7fe565b96d..259c90cfa36 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -192,6 +192,7 @@ static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
+shost_rd_attr(can_queue, "%hd\n");
shost_rd_attr(sg_tablesize, "%hu\n");
shost_rd_attr(unchecked_isa_dma, "%d\n");
shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
@@ -200,6 +201,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_unique_id,
&class_device_attr_host_busy,
&class_device_attr_cmd_per_lun,
+ &class_device_attr_can_queue,
&class_device_attr_sg_tablesize,
&class_device_attr_unchecked_isa_dma,
&class_device_attr_proc_name,
@@ -216,16 +218,16 @@ static void scsi_device_cls_release(struct class_device *class_dev)
put_device(&sdev->sdev_gendev);
}
-static void scsi_device_dev_release_usercontext(void *data)
+static void scsi_device_dev_release_usercontext(struct work_struct *work)
{
- struct device *dev = data;
struct scsi_device *sdev;
struct device *parent;
struct scsi_target *starget;
unsigned long flags;
- parent = dev->parent;
- sdev = to_scsi_device(dev);
+ sdev = container_of(work, struct scsi_device, ew.work);
+
+ parent = sdev->sdev_gendev.parent;
starget = to_scsi_target(parent);
spin_lock_irqsave(sdev->host->host_lock, flags);
@@ -256,7 +258,7 @@ static void scsi_device_dev_release_usercontext(void *data)
static void scsi_device_dev_release(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
- execute_in_process_context(scsi_device_dev_release_usercontext, dev,
+ execute_in_process_context(scsi_device_dev_release_usercontext,
&sdp->ew);
}
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
new file mode 100644
index 00000000000..37bbfbdb870
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -0,0 +1,352 @@
+/*
+ * SCSI target kernel/user interface functions
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/miscdevice.h>
+#include <linux/file.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/scsi_tgt_if.h>
+
+#include <asm/cacheflush.h>
+
+#include "scsi_tgt_priv.h"
+
+struct tgt_ring {
+ u32 tr_idx;
+ unsigned long tr_pages[TGT_RING_PAGES];
+ spinlock_t tr_lock;
+};
+
+/* tx_ring : kernel->user, rx_ring : user->kernel */
+static struct tgt_ring tx_ring, rx_ring;
+static DECLARE_WAIT_QUEUE_HEAD(tgt_poll_wait);
+
+static inline void tgt_ring_idx_inc(struct tgt_ring *ring)
+{
+ if (ring->tr_idx == TGT_MAX_EVENTS - 1)
+ ring->tr_idx = 0;
+ else
+ ring->tr_idx++;
+}
+
+static struct tgt_event *tgt_head_event(struct tgt_ring *ring, u32 idx)
+{
+ u32 pidx, off;
+
+ pidx = idx / TGT_EVENT_PER_PAGE;
+ off = idx % TGT_EVENT_PER_PAGE;
+
+ return (struct tgt_event *)
+ (ring->tr_pages[pidx] + sizeof(struct tgt_event) * off);
+}
+
+static int tgt_uspace_send_event(u32 type, struct tgt_event *p)
+{
+ struct tgt_event *ev;
+ struct tgt_ring *ring = &tx_ring;
+ unsigned long flags;
+ int err = 0;
+
+ spin_lock_irqsave(&ring->tr_lock, flags);
+
+ ev = tgt_head_event(ring, ring->tr_idx);
+ if (!ev->hdr.status)
+ tgt_ring_idx_inc(ring);
+ else
+ err = -BUSY;
+
+ spin_unlock_irqrestore(&ring->tr_lock, flags);
+
+ if (err)
+ return err;
+
+ memcpy(ev, p, sizeof(*ev));
+ ev->hdr.type = type;
+ mb();
+ ev->hdr.status = 1;
+
+ flush_dcache_page(virt_to_page(ev));
+
+ wake_up_interruptible(&tgt_poll_wait);
+
+ return 0;
+}
+
+int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag)
+{
+ struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+ struct tgt_event ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.p.cmd_req.host_no = shost->host_no;
+ ev.p.cmd_req.data_len = cmd->request_bufflen;
+ memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
+ memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
+ ev.p.cmd_req.attribute = cmd->tag;
+ ev.p.cmd_req.tag = tag;
+
+ dprintk("%p %d %u %x %llx\n", cmd, shost->host_no,
+ ev.p.cmd_req.data_len, cmd->tag,
+ (unsigned long long) ev.p.cmd_req.tag);
+
+ err = tgt_uspace_send_event(TGT_KEVENT_CMD_REQ, &ev);
+ if (err)
+ eprintk("tx buf is full, could not send\n");
+
+ return err;
+}
+
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
+{
+ struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+ struct tgt_event ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.p.cmd_done.host_no = shost->host_no;
+ ev.p.cmd_done.tag = tag;
+ ev.p.cmd_done.result = cmd->result;
+
+ dprintk("%p %d %llu %u %x\n", cmd, shost->host_no,
+ (unsigned long long) ev.p.cmd_req.tag,
+ ev.p.cmd_req.data_len, cmd->tag);
+
+ err = tgt_uspace_send_event(TGT_KEVENT_CMD_DONE, &ev);
+ if (err)
+ eprintk("tx buf is full, could not send\n");
+
+ return err;
+}
+
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data)
+{
+ struct tgt_event ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.p.tsk_mgmt_req.host_no = host_no;
+ ev.p.tsk_mgmt_req.function = function;
+ ev.p.tsk_mgmt_req.tag = tag;
+ memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
+ ev.p.tsk_mgmt_req.mid = (u64) (unsigned long) data;
+
+ dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) tag,
+ (unsigned long long) ev.p.tsk_mgmt_req.mid);
+
+ err = tgt_uspace_send_event(TGT_KEVENT_TSK_MGMT_REQ, &ev);
+ if (err)
+ eprintk("tx buf is full, could not send\n");
+
+ return err;
+}
+
+static int event_recv_msg(struct tgt_event *ev)
+{
+ int err = 0;
+
+ switch (ev->hdr.type) {
+ case TGT_UEVENT_CMD_RSP:
+ err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
+ ev->p.cmd_rsp.tag,
+ ev->p.cmd_rsp.result,
+ ev->p.cmd_rsp.len,
+ ev->p.cmd_rsp.uaddr,
+ ev->p.cmd_rsp.rw);
+ break;
+ case TGT_UEVENT_TSK_MGMT_RSP:
+ err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
+ ev->p.tsk_mgmt_rsp.mid,
+ ev->p.tsk_mgmt_rsp.result);
+ break;
+ default:
+ eprintk("unknown type %d\n", ev->hdr.type);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static ssize_t tgt_write(struct file *file, const char __user * buffer,
+ size_t count, loff_t * ppos)
+{
+ struct tgt_event *ev;
+ struct tgt_ring *ring = &rx_ring;
+
+ while (1) {
+ ev = tgt_head_event(ring, ring->tr_idx);
+ /* do we need this? */
+ flush_dcache_page(virt_to_page(ev));
+
+ if (!ev->hdr.status)
+ break;
+
+ tgt_ring_idx_inc(ring);
+ event_recv_msg(ev);
+ ev->hdr.status = 0;
+ };
+
+ return count;
+}
+
+static unsigned int tgt_poll(struct file * file, struct poll_table_struct *wait)
+{
+ struct tgt_event *ev;
+ struct tgt_ring *ring = &tx_ring;
+ unsigned long flags;
+ unsigned int mask = 0;
+ u32 idx;
+
+ poll_wait(file, &tgt_poll_wait, wait);
+
+ spin_lock_irqsave(&ring->tr_lock, flags);
+
+ idx = ring->tr_idx ? ring->tr_idx - 1 : TGT_MAX_EVENTS - 1;
+ ev = tgt_head_event(ring, idx);
+ if (ev->hdr.status)
+ mask |= POLLIN | POLLRDNORM;
+
+ spin_unlock_irqrestore(&ring->tr_lock, flags);
+
+ return mask;
+}
+
+static int uspace_ring_map(struct vm_area_struct *vma, unsigned long addr,
+ struct tgt_ring *ring)
+{
+ int i, err;
+
+ for (i = 0; i < TGT_RING_PAGES; i++) {
+ struct page *page = virt_to_page(ring->tr_pages[i]);
+ err = vm_insert_page(vma, addr, page);
+ if (err)
+ return err;
+ addr += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static int tgt_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long addr;
+ int err;
+
+ if (vma->vm_pgoff)
+ return -EINVAL;
+
+ if (vma->vm_end - vma->vm_start != TGT_RING_SIZE * 2) {
+ eprintk("mmap size must be %lu, not %lu \n",
+ TGT_RING_SIZE * 2, vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ addr = vma->vm_start;
+ err = uspace_ring_map(vma, addr, &tx_ring);
+ if (err)
+ return err;
+ err = uspace_ring_map(vma, addr + TGT_RING_SIZE, &rx_ring);
+
+ return err;
+}
+
+static int tgt_open(struct inode *inode, struct file *file)
+{
+ tx_ring.tr_idx = rx_ring.tr_idx = 0;
+
+ return 0;
+}
+
+static struct file_operations tgt_fops = {
+ .owner = THIS_MODULE,
+ .open = tgt_open,
+ .poll = tgt_poll,
+ .write = tgt_write,
+ .mmap = tgt_mmap,
+};
+
+static struct miscdevice tgt_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "tgt",
+ .fops = &tgt_fops,
+};
+
+static void tgt_ring_exit(struct tgt_ring *ring)
+{
+ int i;
+
+ for (i = 0; i < TGT_RING_PAGES; i++)
+ free_page(ring->tr_pages[i]);
+}
+
+static int tgt_ring_init(struct tgt_ring *ring)
+{
+ int i;
+
+ spin_lock_init(&ring->tr_lock);
+
+ for (i = 0; i < TGT_RING_PAGES; i++) {
+ ring->tr_pages[i] = get_zeroed_page(GFP_KERNEL);
+ if (!ring->tr_pages[i]) {
+ eprintk("out of memory\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+void scsi_tgt_if_exit(void)
+{
+ tgt_ring_exit(&tx_ring);
+ tgt_ring_exit(&rx_ring);
+ misc_deregister(&tgt_miscdev);
+}
+
+int scsi_tgt_if_init(void)
+{
+ int err;
+
+ err = tgt_ring_init(&tx_ring);
+ if (err)
+ return err;
+
+ err = tgt_ring_init(&rx_ring);
+ if (err)
+ goto free_tx_ring;
+
+ err = misc_register(&tgt_miscdev);
+ if (err)
+ goto free_rx_ring;
+
+ return 0;
+free_rx_ring:
+ tgt_ring_exit(&rx_ring);
+free_tx_ring:
+ tgt_ring_exit(&tx_ring);
+
+ return err;
+}
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
new file mode 100644
index 00000000000..d402aff5f31
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -0,0 +1,745 @@
+/*
+ * SCSI target lib functions
+ *
+ * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/blkdev.h>
+#include <linux/hash.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <../drivers/md/dm-bio-list.h>
+
+#include "scsi_tgt_priv.h"
+
+static struct workqueue_struct *scsi_tgtd;
+static struct kmem_cache *scsi_tgt_cmd_cache;
+
+/*
+ * TODO: this struct will be killed when the block layer supports large bios
+ * and James's work struct code is in
+ */
+struct scsi_tgt_cmd {
+ /* TODO replace work with James b's code */
+ struct work_struct work;
+ /* TODO replace the lists with a large bio */
+ struct bio_list xfer_done_list;
+ struct bio_list xfer_list;
+
+ struct list_head hash_list;
+ struct request *rq;
+ u64 tag;
+
+ void *buffer;
+ unsigned bufflen;
+};
+
+#define TGT_HASH_ORDER 4
+#define cmd_hashfn(tag) hash_long((unsigned long) (tag), TGT_HASH_ORDER)
+
+struct scsi_tgt_queuedata {
+ struct Scsi_Host *shost;
+ struct list_head cmd_hash[1 << TGT_HASH_ORDER];
+ spinlock_t cmd_hash_lock;
+};
+
+/*
+ * Function: scsi_host_get_command()
+ *
+ * Purpose: Allocate and setup a scsi command block and blk request
+ *
+ * Arguments: shost - scsi host
+ * data_dir - dma data dir
+ * gfp_mask- allocator flags
+ *
+ * Returns: The allocated scsi command structure.
+ *
+ * This should be called by target LLDs to get a command.
+ */
+struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
+ enum dma_data_direction data_dir,
+ gfp_t gfp_mask)
+{
+ int write = (data_dir == DMA_TO_DEVICE);
+ struct request *rq;
+ struct scsi_cmnd *cmd;
+ struct scsi_tgt_cmd *tcmd;
+
+ /* Bail if we can't get a reference to the device */
+ if (!get_device(&shost->shost_gendev))
+ return NULL;
+
+ tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
+ if (!tcmd)
+ goto put_dev;
+
+ rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
+ if (!rq)
+ goto free_tcmd;
+
+ cmd = __scsi_get_command(shost, gfp_mask);
+ if (!cmd)
+ goto release_rq;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->sc_data_direction = data_dir;
+ cmd->jiffies_at_alloc = jiffies;
+ cmd->request = rq;
+
+ rq->special = cmd;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
+ rq->end_io_data = tcmd;
+
+ bio_list_init(&tcmd->xfer_list);
+ bio_list_init(&tcmd->xfer_done_list);
+ tcmd->rq = rq;
+
+ return cmd;
+
+release_rq:
+ blk_put_request(rq);
+free_tcmd:
+ kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
+put_dev:
+ put_device(&shost->shost_gendev);
+ return NULL;
+
+}
+EXPORT_SYMBOL_GPL(scsi_host_get_command);
+
+/*
+ * Function: scsi_host_put_command()
+ *
+ * Purpose: Free a scsi command block
+ *
+ * Arguments: shost - scsi host
+ * cmd - command block to free
+ *
+ * Returns: Nothing.
+ *
+ * Notes: The command must not belong to any lists.
+ */
+void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+ struct request_queue *q = shost->uspace_req_q;
+ struct request *rq = cmd->request;
+ struct scsi_tgt_cmd *tcmd = rq->end_io_data;
+ unsigned long flags;
+
+ kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ __blk_put_request(q, rq);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ __scsi_put_command(shost, cmd, &shost->shost_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_host_put_command);
+
+static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
+{
+ struct bio *bio;
+
+ /* must call bio_endio in case bio was bounced */
+ while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
+ bio_endio(bio, bio->bi_size, 0);
+ bio_unmap_user(bio);
+ }
+
+ while ((bio = bio_list_pop(&tcmd->xfer_list))) {
+ bio_endio(bio, bio->bi_size, 0);
+ bio_unmap_user(bio);
+ }
+}
+
+static void cmd_hashlist_del(struct scsi_cmnd *cmd)
+{
+ struct request_queue *q = cmd->request->q;
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
+ unsigned long flags;
+ struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_del(&tcmd->hash_list);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+}
+
+static void scsi_tgt_cmd_destroy(struct work_struct *work)
+{
+ struct scsi_tgt_cmd *tcmd =
+ container_of(work, struct scsi_tgt_cmd, work);
+ struct scsi_cmnd *cmd = tcmd->rq->special;
+
+ dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
+ rq_data_dir(cmd->request));
+ /*
+ * We fix rq->cmd_flags here since when we told bio_map_user
+ * to write vm for WRITE commands, blk_rq_bio_prep set
+ * rq_data_dir the flags to READ.
+ */
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ cmd->request->cmd_flags |= REQ_RW;
+ else
+ cmd->request->cmd_flags &= ~REQ_RW;
+
+ scsi_unmap_user_pages(tcmd);
+ scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
+}
+
+static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
+ u64 tag)
+{
+ struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
+ unsigned long flags;
+ struct list_head *head;
+
+ tcmd->tag = tag;
+ INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ head = &qdata->cmd_hash[cmd_hashfn(tag)];
+ list_add(&tcmd->hash_list, head);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+}
+
+/*
+ * scsi_tgt_alloc_queue - setup queue used for message passing
+ * shost: scsi host
+ *
+ * This should be called by the LLD after host allocation.
+ * And will be released when the host is released.
+ */
+int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
+{
+ struct scsi_tgt_queuedata *queuedata;
+ struct request_queue *q;
+ int err, i;
+
+ /*
+ * Do we need to send a netlink event or should uspace
+ * just respond to the hotplug event?
+ */
+ q = __scsi_alloc_queue(shost, NULL);
+ if (!q)
+ return -ENOMEM;
+
+ queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL);
+ if (!queuedata) {
+ err = -ENOMEM;
+ goto cleanup_queue;
+ }
+ queuedata->shost = shost;
+ q->queuedata = queuedata;
+
+ /*
+ * this is a silly hack. We should probably just queue as many
+ * command as is recvd to userspace. uspace can then make
+ * sure we do not overload the HBA
+ */
+ q->nr_requests = shost->hostt->can_queue;
+ /*
+ * We currently only support software LLDs so this does
+ * not matter for now. Do we need this for the cards we support?
+ * If so we should make it a host template value.
+ */
+ blk_queue_dma_alignment(q, 0);
+ shost->uspace_req_q = q;
+
+ for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++)
+ INIT_LIST_HEAD(&queuedata->cmd_hash[i]);
+ spin_lock_init(&queuedata->cmd_hash_lock);
+
+ return 0;
+
+cleanup_queue:
+ blk_cleanup_queue(q);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);
+
+void scsi_tgt_free_queue(struct Scsi_Host *shost)
+{
+ int i;
+ unsigned long flags;
+ struct request_queue *q = shost->uspace_req_q;
+ struct scsi_cmnd *cmd;
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
+ struct scsi_tgt_cmd *tcmd, *n;
+ LIST_HEAD(cmds);
+
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) {
+ list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i],
+ hash_list) {
+ list_del(&tcmd->hash_list);
+ list_add(&tcmd->hash_list, &cmds);
+ }
+ }
+
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+
+ while (!list_empty(&cmds)) {
+ tcmd = list_entry(cmds.next, struct scsi_tgt_cmd, hash_list);
+ list_del(&tcmd->hash_list);
+ cmd = tcmd->rq->special;
+
+ shost->hostt->eh_abort_handler(cmd);
+ scsi_tgt_cmd_destroy(&tcmd->work);
+ }
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_free_queue);
+
+struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd)
+{
+ struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata;
+ return queue->shost;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
+
+/*
+ * scsi_tgt_queue_command - queue command for userspace processing
+ * @cmd: scsi command
+ * @scsilun: scsi lun
+ * @tag: unique value to identify this command for tmf
+ */
+int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
+ u64 tag)
+{
+ struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+ int err;
+
+ init_scsi_tgt_cmd(cmd->request, tcmd, tag);
+ err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag);
+ if (err)
+ cmd_hashlist_del(cmd);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
+
+/*
+ * This is run from a interrpt handler normally and the unmap
+ * needs process context so we must queue
+ */
+static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
+{
+ struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+
+ dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+
+ scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+ queue_work(scsi_tgtd, &tcmd->work);
+}
+
+static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
+ int err;
+
+ dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+
+ err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
+ switch (err) {
+ case SCSI_MLQUEUE_HOST_BUSY:
+ case SCSI_MLQUEUE_DEVICE_BUSY:
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+{
+ struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+ int err;
+
+ err = __scsi_tgt_transfer_response(cmd);
+ if (!err)
+ return;
+
+ cmd->result = DID_BUS_BUSY << 16;
+ err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+ if (err <= 0)
+ /* the eh will have to pick this up */
+ printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+}
+
+static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+ struct request *rq = cmd->request;
+ struct scsi_tgt_cmd *tcmd = rq->end_io_data;
+ int count;
+
+ cmd->use_sg = rq->nr_phys_segments;
+ cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask);
+ if (!cmd->request_buffer)
+ return -ENOMEM;
+
+ cmd->request_bufflen = rq->data_len;
+
+ dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
+ rq_data_dir(rq));
+ count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
+ if (likely(count <= cmd->use_sg)) {
+ cmd->use_sg = count;
+ return 0;
+ }
+
+ eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
+ scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+ return -EINVAL;
+}
+
+/* TODO: test this crap and replace bio_map_user with new interface maybe */
+static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
+ int rw)
+{
+ struct request_queue *q = cmd->request->q;
+ struct request *rq = cmd->request;
+ void *uaddr = tcmd->buffer;
+ unsigned int len = tcmd->bufflen;
+ struct bio *bio;
+ int err;
+
+ while (len > 0) {
+ dprintk("%lx %u\n", (unsigned long) uaddr, len);
+ bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
+ if (IS_ERR(bio)) {
+ err = PTR_ERR(bio);
+ dprintk("fail to map %lx %u %d %x\n",
+ (unsigned long) uaddr, len, err, cmd->cmnd[0]);
+ goto unmap_bios;
+ }
+
+ uaddr += bio->bi_size;
+ len -= bio->bi_size;
+
+ /*
+ * The first bio is added and merged. We could probably
+ * try to add others using scsi_merge_bio() but for now
+ * we keep it simple. The first bio should be pretty large
+ * (either hitting the 1 MB bio pages limit or a queue limit)
+ * already but for really large IO we may want to try and
+ * merge these.
+ */
+ if (!rq->bio) {
+ blk_rq_bio_prep(q, rq, bio);
+ rq->data_len = bio->bi_size;
+ } else
+ /* put list of bios to transfer in next go around */
+ bio_list_add(&tcmd->xfer_list, bio);
+ }
+
+ cmd->offset = 0;
+ err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
+ if (err)
+ goto unmap_bios;
+
+ return 0;
+
+unmap_bios:
+ if (rq->bio) {
+ bio_unmap_user(rq->bio);
+ while ((bio = bio_list_pop(&tcmd->xfer_list)))
+ bio_unmap_user(bio);
+ }
+
+ return err;
+}
+
+static int scsi_tgt_transfer_data(struct scsi_cmnd *);
+
+static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
+{
+ struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+ struct bio *bio;
+ int err;
+
+ /* should we free resources here on error ? */
+ if (cmd->result) {
+send_uspace_err:
+ err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+ if (err <= 0)
+ /* the tgt uspace eh will have to pick this up */
+ printk(KERN_ERR "Could not send cmd %p status\n", cmd);
+ return;
+ }
+
+ dprintk("cmd %p request_bufflen %u bufflen %u\n",
+ cmd, cmd->request_bufflen, tcmd->bufflen);
+
+ scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+ bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
+
+ tcmd->buffer += cmd->request_bufflen;
+ cmd->offset += cmd->request_bufflen;
+
+ if (!tcmd->xfer_list.head) {
+ scsi_tgt_transfer_response(cmd);
+ return;
+ }
+
+ dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
+ cmd, cmd->request_bufflen, tcmd->bufflen);
+
+ bio = bio_list_pop(&tcmd->xfer_list);
+ BUG_ON(!bio);
+
+ blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
+ cmd->request->data_len = bio->bi_size;
+ err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
+ if (err) {
+ cmd->result = DID_ERROR << 16;
+ goto send_uspace_err;
+ }
+
+ if (scsi_tgt_transfer_data(cmd)) {
+ cmd->result = DID_NO_CONNECT << 16;
+ goto send_uspace_err;
+ }
+}
+
+static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
+{
+ int err;
+ struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
+
+ err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
+ switch (err) {
+ case SCSI_MLQUEUE_HOST_BUSY:
+ case SCSI_MLQUEUE_DEVICE_BUSY:
+ return -EAGAIN;
+ default:
+ return 0;
+ }
+}
+
+static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
+ unsigned len)
+{
+ char __user *p = (char __user *) uaddr;
+
+ if (copy_from_user(cmd->sense_buffer, p,
+ min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) {
+ printk(KERN_ERR "Could not copy the sense buffer\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int scsi_tgt_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+ struct scsi_tgt_cmd *tcmd;
+ int err;
+
+ err = shost->hostt->eh_abort_handler(cmd);
+ if (err)
+ eprintk("fail to abort %p\n", cmd);
+
+ tcmd = cmd->request->end_io_data;
+ scsi_tgt_cmd_destroy(&tcmd->work);
+ return err;
+}
+
+static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
+{
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
+ struct request *rq = NULL;
+ struct list_head *head;
+ struct scsi_tgt_cmd *tcmd;
+ unsigned long flags;
+
+ head = &qdata->cmd_hash[cmd_hashfn(tag)];
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_for_each_entry(tcmd, head, hash_list) {
+ if (tcmd->tag == tag) {
+ rq = tcmd->rq;
+ list_del(&tcmd->hash_list);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+
+ return rq;
+}
+
+int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
+ unsigned long uaddr, u8 rw)
+{
+ struct Scsi_Host *shost;
+ struct scsi_cmnd *cmd;
+ struct request *rq;
+ struct scsi_tgt_cmd *tcmd;
+ int err = 0;
+
+ dprintk("%d %llu %d %u %lx %u\n", host_no, (unsigned long long) tag,
+ result, len, uaddr, rw);
+
+ /* TODO: replace with a O(1) alg */
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %d\n", host_no);
+ return -EINVAL;
+ }
+
+ if (!shost->uspace_req_q) {
+ printk(KERN_ERR "Not target scsi host %d\n", host_no);
+ goto done;
+ }
+
+ rq = tgt_cmd_hash_lookup(shost->uspace_req_q, tag);
+ if (!rq) {
+ printk(KERN_ERR "Could not find tag %llu\n",
+ (unsigned long long) tag);
+ err = -EINVAL;
+ goto done;
+ }
+ cmd = rq->special;
+
+ dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
+ result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+
+ if (result == TASK_ABORTED) {
+ scsi_tgt_abort_cmd(shost, cmd);
+ goto done;
+ }
+ /*
+ * store the userspace values here, the working values are
+ * in the request_* values
+ */
+ tcmd = cmd->request->end_io_data;
+ tcmd->buffer = (void *)uaddr;
+ tcmd->bufflen = len;
+ cmd->result = result;
+
+ if (!tcmd->bufflen || cmd->request_buffer) {
+ err = __scsi_tgt_transfer_response(cmd);
+ goto done;
+ }
+
+ /*
+ * TODO: Do we need to handle case where request does not
+ * align with LLD.
+ */
+ err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
+ if (err) {
+ eprintk("%p %d\n", cmd, err);
+ err = -EAGAIN;
+ goto done;
+ }
+
+ /* userspace failure */
+ if (cmd->result) {
+ if (status_byte(cmd->result) == CHECK_CONDITION)
+ scsi_tgt_copy_sense(cmd, uaddr, len);
+ err = __scsi_tgt_transfer_response(cmd);
+ goto done;
+ }
+ /* ask the target LLD to transfer the data to the buffer */
+ err = scsi_tgt_transfer_data(cmd);
+
+done:
+ scsi_host_put(shost);
+ return err;
+}
+
+int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
+ tag, scsilun, data);
+ if (err < 0)
+ eprintk("The task management request lost!\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
+
+int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
+{
+ struct Scsi_Host *shost;
+ int err = -EINVAL;
+
+ dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %d\n", host_no);
+ return err;
+ }
+
+ if (!shost->uspace_req_q) {
+ printk(KERN_ERR "Not target scsi host %d\n", host_no);
+ goto done;
+ }
+
+ err = shost->hostt->tsk_mgmt_response(mid, result);
+done:
+ scsi_host_put(shost);
+ return err;
+}
+
+static int __init scsi_tgt_init(void)
+{
+ int err;
+
+ scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
+ sizeof(struct scsi_tgt_cmd),
+ 0, 0, NULL, NULL);
+ if (!scsi_tgt_cmd_cache)
+ return -ENOMEM;
+
+ scsi_tgtd = create_workqueue("scsi_tgtd");
+ if (!scsi_tgtd) {
+ err = -ENOMEM;
+ goto free_kmemcache;
+ }
+
+ err = scsi_tgt_if_init();
+ if (err)
+ goto destroy_wq;
+
+ return 0;
+
+destroy_wq:
+ destroy_workqueue(scsi_tgtd);
+free_kmemcache:
+ kmem_cache_destroy(scsi_tgt_cmd_cache);
+ return err;
+}
+
+static void __exit scsi_tgt_exit(void)
+{
+ destroy_workqueue(scsi_tgtd);
+ scsi_tgt_if_exit();
+ kmem_cache_destroy(scsi_tgt_cmd_cache);
+}
+
+module_init(scsi_tgt_init);
+module_exit(scsi_tgt_exit);
+
+MODULE_DESCRIPTION("SCSI target core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
new file mode 100644
index 00000000000..84488c51ff6
--- /dev/null
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -0,0 +1,25 @@
+struct scsi_cmnd;
+struct scsi_lun;
+struct Scsi_Host;
+struct task_struct;
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...) \
+do { \
+ printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
+} while (0)
+
+#define dprintk(fmt, args...)
+/* #define dprintk eprintk */
+
+extern void scsi_tgt_if_exit(void);
+extern int scsi_tgt_if_init(void);
+
+extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
+ u64 tag);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
+extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
+ unsigned long uaddr, u8 rw);
+extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data);
+extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 38c215a78f6..3571ce8934e 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -241,9 +241,9 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
#define FC_MGMTSRVR_PORTID 0x00000a
-static void fc_timeout_deleted_rport(void *data);
-static void fc_timeout_fail_rport_io(void *data);
-static void fc_scsi_scan_rport(void *data);
+static void fc_timeout_deleted_rport(struct work_struct *work);
+static void fc_timeout_fail_rport_io(struct work_struct *work);
+static void fc_scsi_scan_rport(struct work_struct *work);
/*
* Attribute counts pre object type...
@@ -1613,7 +1613,7 @@ fc_flush_work(struct Scsi_Host *shost)
* 1 on success / 0 already queued / < 0 for error
**/
static int
-fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
+fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
unsigned long delay)
{
if (unlikely(!fc_host_devloss_work_q(shost))) {
@@ -1625,9 +1625,6 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
return -EINVAL;
}
- if (delay == 0)
- return queue_work(fc_host_devloss_work_q(shost), work);
-
return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
}
@@ -1712,12 +1709,13 @@ EXPORT_SYMBOL(fc_remove_host);
* fc_starget_delete - called to delete the scsi decendents of an rport
* (target and all sdevs)
*
- * @data: remote port to be operated on.
+ * @work: remote port to be operated on.
**/
static void
-fc_starget_delete(void *data)
+fc_starget_delete(struct work_struct *work)
{
- struct fc_rport *rport = (struct fc_rport *)data;
+ struct fc_rport *rport =
+ container_of(work, struct fc_rport, stgt_delete_work);
struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
struct fc_internal *i = to_fc_internal(shost->transportt);
@@ -1751,12 +1749,13 @@ fc_starget_delete(void *data)
/**
* fc_rport_final_delete - finish rport termination and delete it.
*
- * @data: remote port to be deleted.
+ * @work: remote port to be deleted.
**/
static void
-fc_rport_final_delete(void *data)
+fc_rport_final_delete(struct work_struct *work)
{
- struct fc_rport *rport = (struct fc_rport *)data;
+ struct fc_rport *rport =
+ container_of(work, struct fc_rport, rport_delete_work);
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
@@ -1770,7 +1769,7 @@ fc_rport_final_delete(void *data)
/* Delete SCSI target and sdevs */
if (rport->scsi_target_id != -1)
- fc_starget_delete(data);
+ fc_starget_delete(&rport->stgt_delete_work);
else if (i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
else if (i->f->terminate_rport_io)
@@ -1829,11 +1828,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
rport->channel = channel;
rport->fast_io_fail_tmo = -1;
- INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
- INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport);
- INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
- INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
- INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
+ INIT_DELAYED_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport);
+ INIT_DELAYED_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io);
+ INIT_WORK(&rport->scan_work, fc_scsi_scan_rport);
+ INIT_WORK(&rport->stgt_delete_work, fc_starget_delete);
+ INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete);
spin_lock_irqsave(shost->host_lock, flags);
@@ -1963,7 +1962,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
}
if (match) {
- struct work_struct *work =
+ struct delayed_work *work =
&rport->dev_loss_work;
memcpy(&rport->node_name, &ids->node_name,
@@ -2267,12 +2266,13 @@ EXPORT_SYMBOL(fc_remote_port_rolechg);
* was a SCSI target (thus was blocked), and failed
* to return in the alloted time.
*
- * @data: rport target that failed to reappear in the alloted time.
+ * @work: rport target that failed to reappear in the alloted time.
**/
static void
-fc_timeout_deleted_rport(void *data)
+fc_timeout_deleted_rport(struct work_struct *work)
{
- struct fc_rport *rport = (struct fc_rport *)data;
+ struct fc_rport *rport =
+ container_of(work, struct fc_rport, dev_loss_work.work);
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
@@ -2366,15 +2366,16 @@ fc_timeout_deleted_rport(void *data)
* fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
* disconnected SCSI target.
*
- * @data: rport to terminate io on.
+ * @work: rport to terminate io on.
*
* Notes: Only requests the failure of the io, not that all are flushed
* prior to returning.
**/
static void
-fc_timeout_fail_rport_io(void *data)
+fc_timeout_fail_rport_io(struct work_struct *work)
{
- struct fc_rport *rport = (struct fc_rport *)data;
+ struct fc_rport *rport =
+ container_of(work, struct fc_rport, fail_io_work.work);
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
@@ -2387,12 +2388,13 @@ fc_timeout_fail_rport_io(void *data)
/**
* fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
*
- * @data: remote port to be scanned.
+ * @work: remote port to be scanned.
**/
static void
-fc_scsi_scan_rport(void *data)
+fc_scsi_scan_rport(struct work_struct *work)
{
- struct fc_rport *rport = (struct fc_rport *)data;
+ struct fc_rport *rport =
+ container_of(work, struct fc_rport, scan_work);
struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 7b0019cccce..9c22f134271 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -21,7 +21,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
-#include <linux/mempool.h>
#include <linux/mutex.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
@@ -34,7 +33,7 @@
#define ISCSI_SESSION_ATTRS 11
#define ISCSI_CONN_ATTRS 11
#define ISCSI_HOST_ATTRS 0
-#define ISCSI_TRANSPORT_VERSION "2.0-685"
+#define ISCSI_TRANSPORT_VERSION "2.0-724"
struct iscsi_internal {
int daemon_pid;
@@ -149,30 +148,6 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
static struct sock *nls;
static DEFINE_MUTEX(rx_queue_mutex);
-struct mempool_zone {
- mempool_t *pool;
- atomic_t allocated;
- int size;
- int hiwat;
- struct list_head freequeue;
- spinlock_t freelock;
-};
-
-static struct mempool_zone *z_reply;
-
-/*
- * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
- * Z_HIWAT_* - zone's high watermark when if_error bit will be set to -ENOMEM
- * so daemon will notice OOM on NETLINK tranposrt level and will
- * be able to predict or change operational behavior
- */
-#define Z_MAX_REPLY 8
-#define Z_HIWAT_REPLY 6
-#define Z_MAX_PDU 8
-#define Z_HIWAT_PDU 6
-#define Z_MAX_ERROR 16
-#define Z_HIWAT_ERROR 12
-
static LIST_HEAD(sesslist);
static DEFINE_SPINLOCK(sesslock);
static LIST_HEAD(connlist);
@@ -259,9 +234,11 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
return 0;
}
-static void session_recovery_timedout(void *data)
+static void session_recovery_timedout(struct work_struct *work)
{
- struct iscsi_cls_session *session = data;
+ struct iscsi_cls_session *session =
+ container_of(work, struct iscsi_cls_session,
+ recovery_work.work);
dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
"out after %d secs\n", session->recovery_tmo);
@@ -301,7 +278,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
session->transport = transport;
session->recovery_tmo = 120;
- INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
+ INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
INIT_LIST_HEAD(&session->host_list);
INIT_LIST_HEAD(&session->sess_list);
@@ -414,59 +391,11 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
}
EXPORT_SYMBOL_GPL(iscsi_destroy_session);
-static void mempool_zone_destroy(struct mempool_zone *zp)
-{
- mempool_destroy(zp->pool);
- kfree(zp);
-}
-
-static void*
-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
-{
- struct mempool_zone *zone = pool_data;
-
- return alloc_skb(zone->size, gfp_mask);
-}
-
-static void
-mempool_zone_free_skb(void *element, void *pool_data)
-{
- kfree_skb(element);
-}
-
-static struct mempool_zone *
-mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
-{
- struct mempool_zone *zp;
-
- zp = kzalloc(sizeof(*zp), GFP_KERNEL);
- if (!zp)
- return NULL;
-
- zp->size = size;
- zp->hiwat = hiwat;
- INIT_LIST_HEAD(&zp->freequeue);
- spin_lock_init(&zp->freelock);
- atomic_set(&zp->allocated, 0);
-
- zp->pool = mempool_create(max, mempool_zone_alloc_skb,
- mempool_zone_free_skb, zp);
- if (!zp->pool) {
- kfree(zp);
- return NULL;
- }
-
- return zp;
-}
-
static void iscsi_conn_release(struct device *dev)
{
struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
struct device *parent = conn->dev.parent;
- mempool_zone_destroy(conn->z_pdu);
- mempool_zone_destroy(conn->z_error);
-
kfree(conn);
put_device(parent);
}
@@ -476,31 +405,6 @@ static int iscsi_is_conn_dev(const struct device *dev)
return dev->release == iscsi_conn_release;
}
-static int iscsi_create_event_pools(struct iscsi_cls_conn *conn)
-{
- conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
- NLMSG_SPACE(sizeof(struct iscsi_uevent) +
- sizeof(struct iscsi_hdr) +
- DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
- Z_HIWAT_PDU);
- if (!conn->z_pdu) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
- "pdu zone for new conn\n");
- return -ENOMEM;
- }
-
- conn->z_error = mempool_zone_init(Z_MAX_ERROR,
- NLMSG_SPACE(sizeof(struct iscsi_uevent)),
- Z_HIWAT_ERROR);
- if (!conn->z_error) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
- "error zone for new conn\n");
- mempool_zone_destroy(conn->z_pdu);
- return -ENOMEM;
- }
- return 0;
-}
-
/**
* iscsi_create_conn - create iscsi class connection
* @session: iscsi cls session
@@ -533,12 +437,9 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
conn->transport = transport;
conn->cid = cid;
- if (iscsi_create_event_pools(conn))
- goto free_conn;
-
/* this is released in the dev's release function */
if (!get_device(&session->dev))
- goto free_conn_pools;
+ goto free_conn;
snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
session->sid, cid);
@@ -555,8 +456,6 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
release_parent_ref:
put_device(&session->dev);
-free_conn_pools:
-
free_conn:
kfree(conn);
return NULL;
@@ -599,81 +498,31 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt)
return NULL;
}
-static inline struct list_head *skb_to_lh(struct sk_buff *skb)
-{
- return (struct list_head *)&skb->cb;
-}
-
-static void
-mempool_zone_complete(struct mempool_zone *zone)
-{
- unsigned long flags;
- struct list_head *lh, *n;
-
- spin_lock_irqsave(&zone->freelock, flags);
- list_for_each_safe(lh, n, &zone->freequeue) {
- struct sk_buff *skb = (struct sk_buff *)((char *)lh -
- offsetof(struct sk_buff, cb));
- if (!skb_shared(skb)) {
- list_del(skb_to_lh(skb));
- mempool_free(skb, zone->pool);
- atomic_dec(&zone->allocated);
- }
- }
- spin_unlock_irqrestore(&zone->freelock, flags);
-}
-
-static struct sk_buff*
-mempool_zone_get_skb(struct mempool_zone *zone)
-{
- struct sk_buff *skb;
-
- skb = mempool_alloc(zone->pool, GFP_ATOMIC);
- if (skb)
- atomic_inc(&zone->allocated);
- return skb;
-}
-
static int
-iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp)
+iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp)
{
- unsigned long flags;
int rc;
- skb_get(skb);
rc = netlink_broadcast(nls, skb, 0, 1, gfp);
if (rc < 0) {
- mempool_free(skb, zone->pool);
printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc);
return rc;
}
- spin_lock_irqsave(&zone->freelock, flags);
- INIT_LIST_HEAD(skb_to_lh(skb));
- list_add(skb_to_lh(skb), &zone->freequeue);
- spin_unlock_irqrestore(&zone->freelock, flags);
return 0;
}
static int
-iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid)
+iscsi_unicast_skb(struct sk_buff *skb, int pid)
{
- unsigned long flags;
int rc;
- skb_get(skb);
rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT);
if (rc < 0) {
- mempool_free(skb, zone->pool);
printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc);
return rc;
}
- spin_lock_irqsave(&zone->freelock, flags);
- INIT_LIST_HEAD(skb_to_lh(skb));
- list_add(skb_to_lh(skb), &zone->freequeue);
- spin_unlock_irqrestore(&zone->freelock, flags);
-
return 0;
}
@@ -692,9 +541,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
if (!priv)
return -EINVAL;
- mempool_zone_complete(conn->z_pdu);
-
- skb = mempool_zone_get_skb(conn->z_pdu);
+ skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED);
dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
@@ -707,15 +554,13 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
memset(ev, 0, sizeof(*ev));
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_RECV_PDU;
- if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
- ev->iferror = -ENOMEM;
ev->r.recv_req.cid = conn->cid;
ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
pdu = (char*)ev + sizeof(*ev);
memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
- return iscsi_unicast_skb(conn->z_pdu, skb, priv->daemon_pid);
+ return iscsi_unicast_skb(skb, priv->daemon_pid);
}
EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
@@ -731,9 +576,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
if (!priv)
return;
- mempool_zone_complete(conn->z_error);
-
- skb = mempool_zone_get_skb(conn->z_error);
+ skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
"conn error (%d)\n", error);
@@ -744,13 +587,11 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
ev = NLMSG_DATA(nlh);
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_CONN_ERROR;
- if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
- ev->iferror = -ENOMEM;
ev->r.connerror.error = error;
ev->r.connerror.cid = conn->cid;
ev->r.connerror.sid = iscsi_conn_get_sid(conn);
- iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC);
+ iscsi_broadcast_skb(skb, GFP_ATOMIC);
dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
error);
@@ -767,9 +608,7 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
int flags = multi ? NLM_F_MULTI : 0;
int t = done ? NLMSG_DONE : type;
- mempool_zone_complete(z_reply);
-
- skb = mempool_zone_get_skb(z_reply);
+ skb = alloc_skb(len, GFP_ATOMIC);
/*
* FIXME:
* user is supposed to react on iferror == -ENOMEM;
@@ -780,7 +619,7 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
nlh->nlmsg_flags = flags;
memcpy(NLMSG_DATA(nlh), payload, size);
- return iscsi_unicast_skb(z_reply, skb, pid);
+ return iscsi_unicast_skb(skb, pid);
}
static int
@@ -810,9 +649,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
do {
int actual_size;
- mempool_zone_complete(conn->z_pdu);
-
- skbstat = mempool_zone_get_skb(conn->z_pdu);
+ skbstat = alloc_skb(len, GFP_ATOMIC);
if (!skbstat) {
dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
"deliver stats: OOM\n");
@@ -825,8 +662,6 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
memset(evstat, 0, sizeof(*evstat));
evstat->transport_handle = iscsi_handle(conn->transport);
evstat->type = nlh->nlmsg_type;
- if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
- evstat->iferror = -ENOMEM;
evstat->u.get_stats.cid =
ev->u.get_stats.cid;
evstat->u.get_stats.sid =
@@ -845,7 +680,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
skb_trim(skbstat, NLMSG_ALIGN(actual_size));
nlhstat->nlmsg_len = actual_size;
- err = iscsi_unicast_skb(conn->z_pdu, skbstat, priv->daemon_pid);
+ err = iscsi_unicast_skb(skbstat, priv->daemon_pid);
} while (err < 0 && err != -ECONNREFUSED);
return err;
@@ -876,9 +711,7 @@ int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
session = iscsi_dev_to_session(conn->dev.parent);
shost = iscsi_session_to_shost(session);
- mempool_zone_complete(conn->z_pdu);
-
- skb = mempool_zone_get_skb(conn->z_pdu);
+ skb = alloc_skb(len, GFP_KERNEL);
if (!skb) {
dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
"session creation event\n");
@@ -896,7 +729,7 @@ int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
* this will occur if the daemon is not up, so we just warn
* the user and when the daemon is restarted it will handle it
*/
- rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
+ rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
if (rc < 0)
dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
"session destruction event. Check iscsi daemon\n");
@@ -939,9 +772,7 @@ int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
session = iscsi_dev_to_session(conn->dev.parent);
shost = iscsi_session_to_shost(session);
- mempool_zone_complete(conn->z_pdu);
-
- skb = mempool_zone_get_skb(conn->z_pdu);
+ skb = alloc_skb(len, GFP_KERNEL);
if (!skb) {
dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
"session creation event\n");
@@ -959,7 +790,7 @@ int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
* this will occur if the daemon is not up, so we just warn
* the user and when the daemon is restarted it will handle it
*/
- rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
+ rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
if (rc < 0)
dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
"session creation event. Check iscsi daemon\n");
@@ -1278,9 +1109,6 @@ iscsi_if_rx(struct sock *sk, int len)
err = iscsi_if_send_reply(
NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
- if (atomic_read(&z_reply->allocated) >=
- z_reply->hiwat)
- ev->iferror = -ENOMEM;
} while (err < 0 && err != -ECONNREFUSED);
skb_pull(skb, rlen);
}
@@ -1584,32 +1412,6 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
}
EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
-static int
-iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
- struct netlink_notify *n = ptr;
-
- if (event == NETLINK_URELEASE &&
- n->protocol == NETLINK_ISCSI && n->pid) {
- struct iscsi_cls_conn *conn;
- unsigned long flags;
-
- mempool_zone_complete(z_reply);
- spin_lock_irqsave(&connlock, flags);
- list_for_each_entry(conn, &connlist, conn_list) {
- mempool_zone_complete(conn->z_error);
- mempool_zone_complete(conn->z_pdu);
- }
- spin_unlock_irqrestore(&connlock, flags);
- }
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block iscsi_nl_notifier = {
- .notifier_call = iscsi_rcv_nl_event,
-};
-
static __init int iscsi_transport_init(void)
{
int err;
@@ -1633,25 +1435,15 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
- err = netlink_register_notifier(&iscsi_nl_notifier);
- if (err)
- goto unregister_session_class;
-
nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
THIS_MODULE);
if (!nls) {
err = -ENOBUFS;
- goto unregister_notifier;
+ goto unregister_session_class;
}
- z_reply = mempool_zone_init(Z_MAX_REPLY,
- NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
- if (z_reply)
- return 0;
+ return 0;
- sock_release(nls->sk_socket);
-unregister_notifier:
- netlink_unregister_notifier(&iscsi_nl_notifier);
unregister_session_class:
transport_class_unregister(&iscsi_session_class);
unregister_conn_class:
@@ -1665,9 +1457,7 @@ unregister_transport_class:
static void __exit iscsi_transport_exit(void)
{
- mempool_zone_destroy(z_reply);
sock_release(nls->sk_socket);
- netlink_unregister_notifier(&iscsi_nl_notifier);
transport_class_unregister(&iscsi_connection_class);
transport_class_unregister(&iscsi_session_class);
transport_class_unregister(&iscsi_host_class);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index b5b0c2cba96..5c0b75bbfa1 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/jiffies.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 9f070f0d0f2..3fded483146 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -964,9 +964,10 @@ struct work_queue_wrapper {
};
static void
-spi_dv_device_work_wrapper(void *data)
+spi_dv_device_work_wrapper(struct work_struct *work)
{
- struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+ struct work_queue_wrapper *wqw =
+ container_of(work, struct work_queue_wrapper, work);
struct scsi_device *sdev = wqw->sdev;
kfree(wqw);
@@ -1006,7 +1007,7 @@ spi_schedule_dv_device(struct scsi_device *sdev)
return;
}
- INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw);
+ INIT_WORK(&wqw->work, spi_dv_device_work_wrapper);
wqw->sdev = sdev;
schedule_work(&wqw->work);
diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c
new file mode 100644
index 00000000000..8a636103083
--- /dev/null
+++ b/drivers/scsi/scsi_wait_scan.c
@@ -0,0 +1,31 @@
+/*
+ * scsi_wait_scan.c
+ *
+ * Copyright (C) 2006 James Bottomley <James.Bottomley@SteelEye.com>
+ *
+ * This is a simple module to wait until all the async scans are
+ * complete. The idea is to use it in initrd/initramfs scripts. You
+ * modprobe it after all the modprobes of the root SCSI drivers and it
+ * will wait until they have all finished scanning their busses before
+ * allowing the boot to proceed
+ */
+
+#include <linux/module.h>
+#include "scsi_priv.h"
+
+static int __init wait_scan_init(void)
+{
+ scsi_complete_async_scans();
+ return 0;
+}
+
+static void __exit wait_scan_exit(void)
+{
+}
+
+MODULE_DESCRIPTION("SCSI wait for scans");
+MODULE_AUTHOR("James Bottomley");
+MODULE_LICENSE("GPL");
+
+late_initcall(wait_scan_init);
+module_exit(wait_scan_exit);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 638cff41d43..978bfc1e0c6 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -443,8 +443,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags);
-/* overkill panic("Unknown sd command %lx\n", rq->flags); */
+ printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags);
return 0;
}
@@ -840,7 +839,7 @@ static int sd_issue_flush(struct device *dev, sector_t *error_sector)
static void sd_prepare_flush(request_queue_t *q, struct request *rq)
{
memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = SD_TIMEOUT;
rq->cmd[0] = SYNCHRONIZE_CACHE;
rq->cmd_len = 10;
@@ -864,7 +863,7 @@ static void sd_rescan(struct device *dev)
*/
static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct scsi_device *sdev = scsi_disk(disk)->device;
@@ -1052,6 +1051,14 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
&sshdr, SD_TIMEOUT,
SD_MAX_RETRIES);
+ /*
+ * If the drive has indicated to us that it
+ * doesn't have any media in it, don't bother
+ * with any more polling.
+ */
+ if (media_not_present(sdkp, &sshdr))
+ return;
+
if (the_result)
sense_valid = scsi_sense_valid(&sshdr);
retries++;
@@ -1060,14 +1067,6 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
((driver_byte(the_result) & DRIVER_SENSE) &&
sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
- /*
- * If the drive has indicated to us that it doesn't have
- * any media in it, don't bother with any of the rest of
- * this crap.
- */
- if (media_not_present(sdkp, &sshdr))
- return;
-
if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
/* no sense, TUR either succeeded or failed
* with a status error */
@@ -1468,7 +1467,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
if (scsi_status_is_good(res)) {
- int ct = 0;
int offset = data.header_length + data.block_descriptor_length;
if (offset >= SD_BUF_SIZE - 2) {
@@ -1497,11 +1495,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
sdkp->DPOFUA = 0;
}
- ct = sdkp->RCD + 2*sdkp->WCE;
-
- printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n",
- diskname, sd_cache_types[ct],
- sdkp->DPOFUA ? " w/ FUA" : "");
+ printk(KERN_NOTICE "SCSI device %s: "
+ "write cache: %s, read cache: %s, %s\n",
+ diskname,
+ sdkp->WCE ? "enabled" : "disabled",
+ sdkp->RCD ? "disabled" : "enabled",
+ sdkp->DPOFUA ? "supports DPO and FUA"
+ : "doesn't support DPO or FUA");
return;
}
@@ -1795,7 +1795,7 @@ static void sd_shutdown(struct device *dev)
**/
static int __init init_sd(void)
{
- int majors = 0, i;
+ int majors = 0, i, err;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
@@ -1806,9 +1806,22 @@ static int __init init_sd(void)
if (!majors)
return -ENODEV;
- class_register(&sd_disk_class);
+ err = class_register(&sd_disk_class);
+ if (err)
+ goto err_out;
- return scsi_register_driver(&sd_template.gendrv);
+ err = scsi_register_driver(&sd_template.gendrv);
+ if (err)
+ goto err_out_class;
+
+ return 0;
+
+err_out_class:
+ class_unregister(&sd_disk_class);
+err_out:
+ for (i = 0; i < SD_MAJORS; i++)
+ unregister_blkdev(sd_major(i), "sd");
+ return err;
}
/**
@@ -1823,10 +1836,10 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
scsi_unregister_driver(&sd_template.gendrv);
+ class_unregister(&sd_disk_class);
+
for (i = 0; i < SD_MAJORS; i++)
unregister_blkdev(sd_major(i), "sd");
-
- class_unregister(&sd_disk_class);
}
module_init(init_sd);
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 2679ea8bff1..5ffec2721b2 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -94,21 +94,21 @@
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include "scsi.h"
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_host.h>
-#include "seagate.h"
-#include <scsi/scsi_ioctl.h>
#ifdef DEBUG
#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
@@ -320,8 +320,9 @@ static Signature __initdata signatures[] = {
*/
static int hostno = -1;
-static void seagate_reconnect_intr (int, void *, struct pt_regs *);
-static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *);
+static void seagate_reconnect_intr (int, void *);
+static irqreturn_t do_seagate_reconnect_intr (int, void *);
+static int seagate_st0x_bus_reset(struct scsi_cmnd *);
#ifdef FAST
static int fast = 1;
@@ -585,8 +586,8 @@ static int linked_connected = 0;
static unsigned char linked_target, linked_lun;
#endif
-static void (*done_fn) (Scsi_Cmnd *) = NULL;
-static Scsi_Cmnd *SCint = NULL;
+static void (*done_fn) (struct scsi_cmnd *) = NULL;
+static struct scsi_cmnd *SCint = NULL;
/*
* These control whether or not disconnect / reconnect will be attempted,
@@ -618,22 +619,21 @@ static int should_reconnect = 0;
* asserting SEL.
*/
-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave (dev->host_lock, flags);
- seagate_reconnect_intr (irq, dev_id, regs);
+ seagate_reconnect_intr (irq, dev_id);
spin_unlock_irqrestore (dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
+static void seagate_reconnect_intr (int irq, void *dev_id)
{
int temp;
- Scsi_Cmnd *SCtmp;
+ struct scsi_cmnd *SCtmp;
DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
@@ -675,10 +675,11 @@ static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
static int recursion_depth = 0;
-static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
+ void (*done) (struct scsi_cmnd *))
{
int result, reconnect;
- Scsi_Cmnd *SCtmp;
+ struct scsi_cmnd *SCtmp;
DANY ("seagate: que_command");
done_fn = done;
@@ -1609,7 +1610,7 @@ connect_loop:
return retcode (st0x_aborted);
} /* end of internal_command */
-static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
+static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
{
st0x_aborted = DID_ABORT;
return SUCCESS;
@@ -1624,7 +1625,7 @@ static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
* May be called with SCpnt = NULL
*/
-static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
+static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
{
/* No timeouts - this command is going to fail because it was reset. */
DANY ("scsi%d: Reseting bus... ", hostno);
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
deleted file mode 100644
index fb5f380fa4b..00000000000
--- a/drivers/scsi/seagate.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * seagate.h Copyright (C) 1992 Drew Eckhardt
- * low level scsi driver header for ST01/ST02 by
- * Drew Eckhardt
- *
- * <drew@colorado.edu>
- */
-
-#ifndef _SEAGATE_H
-#define SEAGATE_H
-
-static int seagate_st0x_detect(struct scsi_host_template *);
-static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-static int seagate_st0x_abort(Scsi_Cmnd *);
-static const char *seagate_st0x_info(struct Scsi_Host *);
-static int seagate_st0x_bus_reset(Scsi_Cmnd *);
-
-#endif /* _SEAGATE_H */
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 34f9343ed0a..81e3bc7b02a 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
-static char *sg_version_date = "20060818";
+static char *sg_version_date = "20061027";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE;
static int def_reserved_size = -1; /* picks up init parameter */
static int sg_allow_dio = SG_ALLOW_DIO_DEF;
+static int scatter_elem_sz = SG_SCATTER_SZ;
+static int scatter_elem_sz_prev = SG_SCATTER_SZ;
+
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -707,12 +710,12 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
(int) cmnd[0], (int) hp->cmd_len));
if ((k = sg_start_req(srp))) {
- SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k));
+ SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k));
sg_finish_rem_req(srp);
return k; /* probably out of space --> ENOMEM */
}
if ((k = sg_write_xfer(srp))) {
- SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n"));
+ SCSI_LOG_TIMEOUT(1, printk("sg_common_write: write_xfer, bad address\n"));
sg_finish_rem_req(srp);
return k;
}
@@ -743,7 +746,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
hp->dxfer_len, srp->data.k_use_sg, timeout,
SG_DEFAULT_RETRIES, srp, sg_cmd_done,
GFP_ATOMIC)) {
- SCSI_LOG_TIMEOUT(1, printk("sg_write: scsi_execute_async failed\n"));
+ SCSI_LOG_TIMEOUT(1, printk("sg_common_write: scsi_execute_async failed\n"));
/*
* most likely out of mem, but could also be a bad map
*/
@@ -1280,7 +1283,7 @@ sg_cmd_done(void *data, char *sense, int result, int resid)
sg_finish_rem_req(srp);
srp = NULL;
if (NULL == sfp->headrp) {
- SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n"));
+ SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n"));
if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
scsi_device_put(sdp->device);
}
@@ -1509,12 +1512,12 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
POLL_HUP);
}
}
- SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k));
if (NULL == sdp->headfp) {
sg_dev_arr[k] = NULL;
}
} else { /* nothing active, simple case */
- SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k));
sg_dev_arr[k] = NULL;
}
sg_nr_dev--;
@@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
msleep(10); /* dirty detach so delay device destruction */
}
-/* Set 'perm' (4th argument) to 0 to disable module_param's definition
- * of sysfs parameters (which module_param doesn't yet support).
- * Sysfs parameters defined explicitly below.
- */
-module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO);
+module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
+module_param_named(def_reserved_size, def_reserved_size, int,
+ S_IRUGO | S_IWUSR);
module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
MODULE_AUTHOR("Douglas Gilbert");
@@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(SG_VERSION_STR);
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
+MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
+ "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
@@ -1558,8 +1561,14 @@ init_sg(void)
{
int rc;
+ if (scatter_elem_sz < PAGE_SIZE) {
+ scatter_elem_sz = PAGE_SIZE;
+ scatter_elem_sz_prev = scatter_elem_sz;
+ }
if (def_reserved_size >= 0)
sg_big_buff = def_reserved_size;
+ else
+ def_reserved_size = sg_big_buff;
rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
SG_MAX_DEVS, "sg");
@@ -1842,24 +1851,40 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
if (mx_sc_elems < 0)
return mx_sc_elems; /* most likely -ENOMEM */
+ num = scatter_elem_sz;
+ if (unlikely(num != scatter_elem_sz_prev)) {
+ if (num < PAGE_SIZE) {
+ scatter_elem_sz = PAGE_SIZE;
+ scatter_elem_sz_prev = PAGE_SIZE;
+ } else
+ scatter_elem_sz_prev = num;
+ }
for (k = 0, sg = schp->buffer, rem_sz = blk_size;
(rem_sz > 0) && (k < mx_sc_elems);
++k, rem_sz -= ret_sz, ++sg) {
- num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
+ num = (rem_sz > scatter_elem_sz_prev) ?
+ scatter_elem_sz_prev : rem_sz;
p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
if (!p)
return -ENOMEM;
+ if (num == scatter_elem_sz_prev) {
+ if (unlikely(ret_sz > scatter_elem_sz_prev)) {
+ scatter_elem_sz = ret_sz;
+ scatter_elem_sz_prev = ret_sz;
+ }
+ }
sg->page = p;
- sg->length = ret_sz;
+ sg->length = (ret_sz > num) ? num : ret_sz;
- SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n",
- k, p, ret_sz));
+ SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, "
+ "ret_sz=%d\n", k, num, ret_sz));
} /* end of for loop */
schp->k_use_sg = k;
- SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));
+ SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, "
+ "rem_sz=%d\n", k, rem_sz));
schp->bufflen = blk_size;
if (rem_sz > 0) /* must have failed */
@@ -1990,7 +2015,7 @@ sg_remove_scat(Sg_scatter_hold * schp)
for (k = 0; (k < schp->k_use_sg) && sg->page;
++k, ++sg) {
SCSI_LOG_TIMEOUT(5, printk(
- "sg_remove_scat: k=%d, a=0x%p, len=%d\n",
+ "sg_remove_scat: k=%d, pg=0x%p, len=%d\n",
k, sg->page, sg->length));
sg_page_free(sg->page, sg->length);
}
@@ -2341,6 +2366,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
}
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
+ if (unlikely(sg_big_buff != def_reserved_size))
+ sg_big_buff = def_reserved_size;
+
sg_build_reserve(sfp, sg_big_buff);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
@@ -2437,16 +2465,16 @@ sg_res_in_use(Sg_fd * sfp)
return srp ? 1 : 0;
}
-/* If retSzp==NULL want exact size or fail */
+/* The size fetched (value output via retSzp) set when non-NULL return */
static struct page *
sg_page_malloc(int rqSz, int lowDma, int *retSzp)
{
struct page *resp = NULL;
gfp_t page_mask;
int order, a_size;
- int resSz = rqSz;
+ int resSz;
- if (rqSz <= 0)
+ if ((rqSz <= 0) || (NULL == retSzp))
return resp;
if (lowDma)
@@ -2456,8 +2484,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
order++, a_size <<= 1) ;
+ resSz = a_size; /* rounded up if necessary */
resp = alloc_pages(page_mask, order);
- while ((!resp) && order && retSzp) {
+ while ((!resp) && order) {
--order;
a_size >>= 1; /* divide by 2, until PAGE_SIZE */
resp = alloc_pages(page_mask, order); /* try half */
@@ -2466,8 +2495,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
if (resp) {
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
memset(page_address(resp), 0, resSz);
- if (retSzp)
- *retSzp = resSz;
+ *retSzp = resSz;
}
return resp;
}
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 4f1db6f2aae..e81f97a35bc 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -84,7 +84,7 @@ static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
return value;
}
-static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
{
struct Scsi_Host * host = (struct Scsi_Host *) dev_id;
unsigned long flags;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index b27e85428da..551baccec52 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -282,6 +282,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
{ "HWP0C80" },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
static __init int
sim710_eisa_probe(struct device *dev)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 7f669b60067..e016e0906e1 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2005 Kai Makisara
+ Copyright 1992 - 2006 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20050830";
+static const char *verstr = "20061107";
#include <linux/module.h>
@@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
-static void do_create_driverfs_files(void);
+static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
-static void do_create_class_files(struct scsi_tape *, int, int);
+static int do_create_class_files(struct scsi_tape *, int, int);
static struct scsi_driver st_template = {
.owner = THIS_MODULE,
@@ -922,7 +922,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
struct st_modedef *STm;
struct st_partstat *STps;
char *name = tape_name(STp);
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int mode = TAPE_MODE(inode);
STp->ready = ST_READY;
@@ -999,7 +999,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
STp->min_block = ((STp->buffer)->b_data[4] << 8) |
(STp->buffer)->b_data[5];
if ( DEB( debugging || ) !STp->inited)
- printk(KERN_WARNING
+ printk(KERN_INFO
"%s: Block limits %d - %d bytes.\n", name,
STp->min_block, STp->max_block);
} else {
@@ -1177,7 +1177,10 @@ static int st_open(struct inode *inode, struct file *filp)
goto err_out;
if ((filp->f_flags & O_NONBLOCK) == 0 &&
retval != CHKRES_READY) {
- retval = (-EIO);
+ if (STp->ready == NO_TAPE)
+ retval = (-ENOMEDIUM);
+ else
+ retval = (-EIO);
goto err_out;
}
return 0;
@@ -1221,7 +1224,7 @@ static int st_flush(struct file *filp, fl_owner_t id)
}
DEBC( if (STp->nbr_requests)
- printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
+ printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
if (STps->rw == ST_WRITING && !STp->pos_unknown) {
@@ -4048,14 +4051,16 @@ static int st_probe(struct device *dev)
STm->cdevs[j] = cdev;
}
- do_create_class_files(tpnt, dev_num, mode);
+ error = do_create_class_files(tpnt, dev_num, mode);
+ if (error)
+ goto out_free_tape;
}
- sdev_printk(KERN_WARNING, SDp,
+ sdev_printk(KERN_NOTICE, SDp,
"Attached scsi tape %s\n", tape_name(tpnt));
- printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n",
- tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
- queue_dma_alignment(SDp->request_queue) + 1);
+ sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n",
+ tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
+ queue_dma_alignment(SDp->request_queue) + 1);
return 0;
@@ -4157,32 +4162,45 @@ static void scsi_tape_release(struct kref *kref)
static int __init init_st(void)
{
+ int err;
+
validate_options();
- printk(KERN_INFO
- "st: Version %s, fixed bufsize %d, s/g segs %d\n",
+ printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs);
st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
if (IS_ERR(st_sysfs_class)) {
- st_sysfs_class = NULL;
printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
- return 1;
+ return PTR_ERR(st_sysfs_class);
}
- if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
- ST_MAX_TAPE_ENTRIES, "st")) {
- if (scsi_register_driver(&st_template.gendrv) == 0) {
- do_create_driverfs_files();
- return 0;
- }
- unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
- ST_MAX_TAPE_ENTRIES);
+ err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+ ST_MAX_TAPE_ENTRIES, "st");
+ if (err) {
+ printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
+ SCSI_TAPE_MAJOR);
+ goto err_class;
}
- class_destroy(st_sysfs_class);
- printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
- return 1;
+ err = scsi_register_driver(&st_template.gendrv);
+ if (err)
+ goto err_chrdev;
+
+ err = do_create_driverfs_files();
+ if (err)
+ goto err_scsidrv;
+
+ return 0;
+
+err_scsidrv:
+ scsi_unregister_driver(&st_template.gendrv);
+err_chrdev:
+ unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+ ST_MAX_TAPE_ENTRIES);
+err_class:
+ class_destroy(st_sysfs_class);
+ return err;
}
static void __exit exit_st(void)
@@ -4225,14 +4243,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf)
}
static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
-static void do_create_driverfs_files(void)
+static int do_create_driverfs_files(void)
{
struct device_driver *driverfs = &st_template.gendrv;
+ int err;
+
+ err = driver_create_file(driverfs, &driver_attr_try_direct_io);
+ if (err)
+ return err;
+ err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+ if (err)
+ goto err_try_direct_io;
+ err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
+ if (err)
+ goto err_attr_fixed_buf;
+ err = driver_create_file(driverfs, &driver_attr_version);
+ if (err)
+ goto err_attr_max_sg;
- driver_create_file(driverfs, &driver_attr_try_direct_io);
- driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
- driver_create_file(driverfs, &driver_attr_max_sg_segs);
- driver_create_file(driverfs, &driver_attr_version);
+ return 0;
+
+err_attr_max_sg:
+ driver_remove_file(driverfs, &driver_attr_max_sg_segs);
+err_attr_fixed_buf:
+ driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
+err_try_direct_io:
+ driver_remove_file(driverfs, &driver_attr_try_direct_io);
+ return err;
}
static void do_remove_driverfs_files(void)
@@ -4293,15 +4330,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
-static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
+static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
{
int i, rew, error;
char name[10];
struct class_device *st_class_member;
- if (!st_sysfs_class)
- return;
-
for (rew=0; rew < 2; rew++) {
/* Make sure that the minor numbers corresponding to the four
first modes always get the same names */
@@ -4316,18 +4350,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
if (IS_ERR(st_class_member)) {
printk(KERN_WARNING "st%d: class_device_create failed\n",
dev_num);
+ error = PTR_ERR(st_class_member);
goto out;
}
class_set_devdata(st_class_member, &STp->modes[mode]);
- class_device_create_file(st_class_member,
- &class_device_attr_defined);
- class_device_create_file(st_class_member,
- &class_device_attr_default_blksize);
- class_device_create_file(st_class_member,
- &class_device_attr_default_density);
- class_device_create_file(st_class_member,
- &class_device_attr_default_compression);
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_defined);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_blksize);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_density);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_compression);
+ if (error) goto out;
+
if (mode == 0 && rew == 0) {
error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
&st_class_member->kobj,
@@ -4336,11 +4376,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
printk(KERN_ERR
"st%d: Can't create sysfs link from SCSI device.\n",
dev_num);
+ goto out;
}
}
}
- out:
- return;
+
+ return 0;
+
+out:
+ return error;
}
/* The following functions may be useful for a larger audience. */
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 3cf3106a29b..ba6bcdaf2a6 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -11,8 +11,6 @@
* Written By:
* Ed Lin <promise_linux@promise.com>
*
- * Version: 2.9.0.13
- *
*/
#include <linux/init.h>
@@ -37,11 +35,11 @@
#include <scsi/scsi_tcq.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "2.9.0.13"
-#define ST_VER_MAJOR 2
-#define ST_VER_MINOR 9
+#define ST_DRIVER_VERSION "3.1.0.1"
+#define ST_VER_MAJOR 3
+#define ST_VER_MINOR 1
#define ST_OEM 0
-#define ST_BUILD_VER 13
+#define ST_BUILD_VER 1
enum {
/* MU register offset */
@@ -76,8 +74,10 @@ enum {
MU_STATE_STARTED = 4,
MU_STATE_RESETTING = 5,
- MU_MAX_DELAY_TIME = 240000,
+ MU_MAX_DELAY = 120,
MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
+ MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000,
+ MU_HARD_RESET_WAIT = 30000,
HMU_PARTNER_TYPE = 2,
/* firmware returned values */
@@ -120,12 +120,19 @@ enum {
st_shasta = 0,
st_vsc = 1,
+ st_vsc1 = 2,
+ st_yosemite = 3,
PASSTHRU_REQ_TYPE = 0x00000001,
PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
ST_INTERNAL_TIMEOUT = 30,
+ ST_TO_CMD = 0,
+ ST_FROM_CMD = 1,
+
/* vendor specific commands of Promise */
+ MGT_CMD = 0xd8,
+ SINBAND_MGT_CMD = 0xd9,
ARRAY_CMD = 0xe0,
CONTROLLER_CMD = 0xe1,
DEBUGGING_CMD = 0xe2,
@@ -133,14 +140,50 @@ enum {
PASSTHRU_GET_ADAPTER = 0x05,
PASSTHRU_GET_DRVVER = 0x10,
+
+ CTLR_CONFIG_CMD = 0x03,
+ CTLR_SHUTDOWN = 0x0d,
+
CTLR_POWER_STATE_CHANGE = 0x0e,
CTLR_POWER_SAVING = 0x01,
PASSTHRU_SIGNATURE = 0x4e415041,
+ MGT_CMD_SIGNATURE = 0xba,
INQUIRY_EVPD = 0x01,
+
+ ST_ADDITIONAL_MEM = 0x200000,
};
+/* SCSI inquiry data */
+typedef struct st_inq {
+ u8 DeviceType :5;
+ u8 DeviceTypeQualifier :3;
+ u8 DeviceTypeModifier :7;
+ u8 RemovableMedia :1;
+ u8 Versions;
+ u8 ResponseDataFormat :4;
+ u8 HiSupport :1;
+ u8 NormACA :1;
+ u8 ReservedBit :1;
+ u8 AERC :1;
+ u8 AdditionalLength;
+ u8 Reserved[2];
+ u8 SoftReset :1;
+ u8 CommandQueue :1;
+ u8 Reserved2 :1;
+ u8 LinkedCommands :1;
+ u8 Synchronous :1;
+ u8 Wide16Bit :1;
+ u8 Wide32Bit :1;
+ u8 RelativeAddressing :1;
+ u8 VendorId[8];
+ u8 ProductId[16];
+ u8 ProductRevisionLevel[4];
+ u8 VendorSpecific[20];
+ u8 Reserved3[40];
+} ST_INQ;
+
struct st_sgitem {
u8 ctrl; /* SG_CF_xxx */
u8 reserved[3];
@@ -171,7 +214,9 @@ struct handshake_frame {
__le32 partner_ver_minor;
__le32 partner_ver_oem;
__le32 partner_ver_build;
- u32 reserved1[4];
+ __le32 extra_offset; /* NEW */
+ __le32 extra_size; /* NEW */
+ u32 reserved1[2];
};
struct req_msg {
@@ -181,7 +226,7 @@ struct req_msg {
u8 task_attr;
u8 task_manage;
u8 prd_entry;
- u8 payload_sz; /* payload size in 4-byte */
+ u8 payload_sz; /* payload size in 4-byte, not used */
u8 cdb[STEX_CDB_LENGTH];
u8 variable[REQ_VARIABLE_LEN];
};
@@ -242,7 +287,8 @@ struct st_drvver {
#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
-#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame))
+#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ))
+#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
struct st_ccb {
struct req_msg *req;
@@ -261,6 +307,7 @@ struct st_hba {
void __iomem *mmio_base; /* iomapped PCI memory space */
void *dma_mem;
dma_addr_t dma_handle;
+ size_t dma_size;
struct Scsi_Host *host;
struct pci_dev *pdev;
@@ -403,7 +450,7 @@ static int stex_map_sg(struct st_hba *hba,
}
static void stex_internal_copy(struct scsi_cmnd *cmd,
- const void *src, size_t *count, int sg_count)
+ const void *src, size_t *count, int sg_count, int direction)
{
size_t lcount;
size_t len;
@@ -427,7 +474,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
} else
d = cmd->request_buffer;
- memcpy(d, s, len);
+ if (direction == ST_TO_CMD)
+ memcpy(d, s, len);
+ else
+ memcpy(s, d, len);
lcount -= len;
if (cmd->use_sg)
@@ -449,7 +499,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd,
return 0;
}
- stex_internal_copy(cmd, src, &cp_len, n_elem);
+ stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
if (cmd->use_sg)
pci_unmap_sg(hba->pdev, cmd->request_buffer,
@@ -463,6 +513,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
size_t count = sizeof(struct st_frame);
p = hba->copy_buffer;
+ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_FROM_CMD);
memset(p->base, 0, sizeof(u32)*6);
*(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
p->rom_addr = 0;
@@ -480,7 +531,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
p->subid =
hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
- stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
+ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
}
static void
@@ -489,7 +540,6 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
req->tag = cpu_to_le16(tag);
req->task_attr = TASK_ATTRIBUTE_SIMPLE;
req->task_manage = 0; /* not supported yet */
- req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32));
hba->ccb[tag].req = req;
hba->out_req_cnt++;
@@ -595,8 +645,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
return SCSI_MLQUEUE_HOST_BUSY;
req = stex_alloc_req(hba);
- req->lun = lun;
- req->target = id;
+
+ if (hba->cardtype == st_yosemite) {
+ req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
+ req->target = 0;
+ } else {
+ req->lun = lun;
+ req->target = id;
+ }
/* cdb */
memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
@@ -680,7 +736,51 @@ static void stex_copy_data(struct st_ccb *ccb,
if (ccb->cmd == NULL)
return;
- stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
+ stex_internal_copy(ccb->cmd,
+ resp->variable, &count, ccb->sg_count, ST_TO_CMD);
+}
+
+static void stex_ys_commands(struct st_hba *hba,
+ struct st_ccb *ccb, struct status_msg *resp)
+{
+ size_t count;
+
+ if (ccb->cmd->cmnd[0] == MGT_CMD &&
+ resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
+ ccb->cmd->request_bufflen =
+ le32_to_cpu(*(__le32 *)&resp->variable[0]);
+ return;
+ }
+
+ if (resp->srb_status != 0)
+ return;
+
+ /* determine inquiry command status by DeviceTypeQualifier */
+ if (ccb->cmd->cmnd[0] == INQUIRY &&
+ resp->scsi_status == SAM_STAT_GOOD) {
+ ST_INQ *inq_data;
+
+ count = STEX_EXTRA_SIZE;
+ stex_internal_copy(ccb->cmd, hba->copy_buffer,
+ &count, ccb->sg_count, ST_FROM_CMD);
+ inq_data = (ST_INQ *)hba->copy_buffer;
+ if (inq_data->DeviceTypeQualifier != 0)
+ ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
+ else
+ ccb->srb_status = SRB_STATUS_SUCCESS;
+ } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
+ u8 *report_lun_data = (u8 *)hba->copy_buffer;
+
+ count = STEX_EXTRA_SIZE;
+ stex_internal_copy(ccb->cmd, report_lun_data,
+ &count, ccb->sg_count, ST_FROM_CMD);
+ if (report_lun_data[2] || report_lun_data[3]) {
+ report_lun_data[2] = 0x00;
+ report_lun_data[3] = 0x08;
+ stex_internal_copy(ccb->cmd, report_lun_data,
+ &count, ccb->sg_count, ST_TO_CMD);
+ }
+ }
}
static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
@@ -702,8 +802,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
return;
}
- if (unlikely(hba->mu_status != MU_STATE_STARTED ||
- hba->out_req_cnt <= 0)) {
+ /*
+ * it's not a valid status payload if:
+ * 1. there are no pending requests(e.g. during init stage)
+ * 2. there are some pending requests, but the controller is in
+ * reset status, and its type is not st_yosemite
+ * firmware of st_yosemite in reset status will return pending requests
+ * to driver, so we allow it to pass
+ */
+ if (unlikely(hba->out_req_cnt <= 0 ||
+ (hba->mu_status == MU_STATE_RESETTING &&
+ hba->cardtype != st_yosemite))) {
hba->status_tail = hba->status_head;
goto update_status;
}
@@ -723,6 +832,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
if (unlikely(ccb->req == NULL)) {
printk(KERN_WARNING DRV_NAME
"(%s): lagging req\n", pci_name(hba->pdev));
+ hba->out_req_cnt--;
continue;
}
@@ -741,9 +851,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
ccb->scsi_status = resp->scsi_status;
if (likely(ccb->cmd != NULL)) {
+ if (hba->cardtype == st_yosemite)
+ stex_ys_commands(hba, ccb, resp);
+
if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
stex_controller_info(hba, ccb);
+
stex_unmap_sg(hba, ccb->cmd);
stex_scsi_done(ccb);
hba->out_req_cnt--;
@@ -764,7 +878,7 @@ update_status:
readl(base + IMR1); /* flush */
}
-static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs)
+static irqreturn_t stex_intr(int irq, void *__hba)
{
struct st_hba *hba = __hba;
void __iomem *base = hba->mmio_base;
@@ -794,27 +908,34 @@ static int stex_handshake(struct st_hba *hba)
void __iomem *base = hba->mmio_base;
struct handshake_frame *h;
dma_addr_t status_phys;
- int i;
+ u32 data;
+ unsigned long before;
if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
readl(base + IDBL);
- for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
- && i < MU_MAX_DELAY_TIME; i++) {
+ before = jiffies;
+ while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
+ if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+ printk(KERN_ERR DRV_NAME
+ "(%s): no handshake signature\n",
+ pci_name(hba->pdev));
+ return -1;
+ }
rmb();
msleep(1);
}
-
- if (i == MU_MAX_DELAY_TIME) {
- printk(KERN_ERR DRV_NAME
- "(%s): no handshake signature\n",
- pci_name(hba->pdev));
- return -1;
- }
}
udelay(10);
+ data = readl(base + OMR1);
+ if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) {
+ data &= 0x0000ffff;
+ if (hba->host->can_queue > data)
+ hba->host->can_queue = data;
+ }
+
h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
h->rb_phy = cpu_to_le32(hba->dma_handle);
h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16);
@@ -824,6 +945,11 @@ static int stex_handshake(struct st_hba *hba)
h->status_cnt = cpu_to_le16(MU_STATUS_COUNT);
stex_gettime(&h->hosttime);
h->partner_type = HMU_PARTNER_TYPE;
+ if (hba->dma_size > STEX_BUFFER_SIZE) {
+ h->extra_offset = cpu_to_le32(STEX_BUFFER_SIZE);
+ h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM);
+ } else
+ h->extra_offset = h->extra_size = 0;
status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE;
writel(status_phys, base + IMR0);
@@ -837,19 +963,18 @@ static int stex_handshake(struct st_hba *hba)
readl(base + IDBL); /* flush */
udelay(10);
- for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
- && i < MU_MAX_DELAY_TIME; i++) {
+ before = jiffies;
+ while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
+ if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+ printk(KERN_ERR DRV_NAME
+ "(%s): no signature after handshake frame\n",
+ pci_name(hba->pdev));
+ return -1;
+ }
rmb();
msleep(1);
}
- if (i == MU_MAX_DELAY_TIME) {
- printk(KERN_ERR DRV_NAME
- "(%s): no signature after handshake frame\n",
- pci_name(hba->pdev));
- return -1;
- }
-
writel(0, base + IMR0);
readl(base + IMR0);
writel(0, base + OMR0);
@@ -931,9 +1056,9 @@ static void stex_hard_reset(struct st_hba *hba)
pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
- for (i = 0; i < MU_MAX_DELAY_TIME; i++) {
+ for (i = 0; i < MU_HARD_RESET_WAIT; i++) {
pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);
- if (pci_cmd & PCI_COMMAND_MASTER)
+ if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER))
break;
msleep(1);
}
@@ -948,6 +1073,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
{
struct st_hba *hba;
unsigned long flags;
+ unsigned long before;
hba = (struct st_hba *) &cmd->device->host->hostdata[0];
hba->mu_status = MU_STATE_RESETTING;
@@ -955,38 +1081,55 @@ static int stex_reset(struct scsi_cmnd *cmd)
if (hba->cardtype == st_shasta)
stex_hard_reset(hba);
- if (stex_handshake(hba)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): resetting: handshake failed\n",
- pci_name(hba->pdev));
- return FAILED;
+ if (hba->cardtype != st_yosemite) {
+ if (stex_handshake(hba)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): resetting: handshake failed\n",
+ pci_name(hba->pdev));
+ return FAILED;
+ }
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->req_head = 0;
+ hba->req_tail = 0;
+ hba->status_head = 0;
+ hba->status_tail = 0;
+ hba->out_req_cnt = 0;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return SUCCESS;
+ }
+
+ /* st_yosemite */
+ writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
+ readl(hba->mmio_base + IDBL); /* flush */
+ before = jiffies;
+ while (hba->out_req_cnt > 0) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): reset timeout\n", pci_name(hba->pdev));
+ return FAILED;
+ }
+ msleep(1);
}
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->req_head = 0;
- hba->req_tail = 0;
- hba->status_head = 0;
- hba->status_tail = 0;
- hba->out_req_cnt = 0;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ hba->mu_status = MU_STATE_STARTED;
return SUCCESS;
}
static int stex_biosparam(struct scsi_device *sdev,
struct block_device *bdev, sector_t capacity, int geom[])
{
- int heads = 255, sectors = 63, cylinders;
+ int heads = 255, sectors = 63;
if (capacity < 0x200000) {
heads = 64;
sectors = 32;
}
- cylinders = sector_div(capacity, heads * sectors);
+ sector_div(capacity, heads * sectors);
geom[0] = heads;
geom[1] = sectors;
- geom[2] = cylinders;
+ geom[2] = capacity;
return 0;
}
@@ -1068,8 +1211,13 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_iounmap;
}
+ hba->cardtype = (unsigned int) id->driver_data;
+ if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1)
+ hba->cardtype = st_vsc1;
+ hba->dma_size = (hba->cardtype == st_vsc1) ?
+ (STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE);
hba->dma_mem = dma_alloc_coherent(&pdev->dev,
- STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL);
+ hba->dma_size, &hba->dma_handle, GFP_KERNEL);
if (!hba->dma_mem) {
err = -ENOMEM;
printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
@@ -1082,8 +1230,6 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE;
hba->mu_status = MU_STATE_STARTING;
- hba->cardtype = (unsigned int) id->driver_data;
-
/* firmware uses id/lun pair for a logical drive, but lun would be
always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use
channel to map lun here */
@@ -1108,7 +1254,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto out_free_irq;
- err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
+ err = scsi_init_shared_tag_map(host, host->can_queue);
if (err) {
printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
pci_name(pdev));
@@ -1131,7 +1277,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_free_irq:
free_irq(pdev->irq, hba);
out_pci_free:
- dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE,
+ dma_free_coherent(&pdev->dev, hba->dma_size,
hba->dma_mem, hba->dma_handle);
out_iounmap:
iounmap(hba->mmio_base);
@@ -1156,9 +1302,16 @@ static void stex_hba_stop(struct st_hba *hba)
req = stex_alloc_req(hba);
memset(req->cdb, 0, STEX_CDB_LENGTH);
- req->cdb[0] = CONTROLLER_CMD;
- req->cdb[1] = CTLR_POWER_STATE_CHANGE;
- req->cdb[2] = CTLR_POWER_SAVING;
+ if (hba->cardtype == st_yosemite) {
+ req->cdb[0] = MGT_CMD;
+ req->cdb[1] = MGT_CMD_SIGNATURE;
+ req->cdb[2] = CTLR_CONFIG_CMD;
+ req->cdb[3] = CTLR_SHUTDOWN;
+ } else {
+ req->cdb[0] = CONTROLLER_CMD;
+ req->cdb[1] = CTLR_POWER_STATE_CHANGE;
+ req->cdb[2] = CTLR_POWER_SAVING;
+ }
hba->ccb[tag].cmd = NULL;
hba->ccb[tag].sg_count = 0;
@@ -1185,7 +1338,7 @@ static void stex_hba_free(struct st_hba *hba)
pci_release_regions(hba->pdev);
- dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE,
+ dma_free_coherent(&hba->pdev->dev, hba->dma_size,
hba->dma_mem, hba->dma_handle);
}
@@ -1214,14 +1367,32 @@ static void stex_shutdown(struct pci_dev *pdev)
}
static struct pci_device_id stex_pci_tbl[] = {
- { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0xf350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
- { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
+ /* st_shasta */
+ { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */
+ { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ st_shasta }, /* SuperTrak EX12350 */
+ { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ st_shasta }, /* SuperTrak EX4350 */
+ { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ st_shasta }, /* SuperTrak EX24350 */
+
+ /* st_vsc */
+ { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
+
+ /* st_yosemite */
+ { 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0,
+ st_yosemite }, /* SuperTrak EX4650 */
+ { 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0,
+ st_yosemite }, /* SuperTrak EX4650o */
+ { 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0,
+ st_yosemite }, /* SuperTrak EX8650EL */
+ { 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0,
+ st_yosemite }, /* SuperTrak EX8650 */
+ { 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0,
+ st_yosemite }, /* SuperTrak EX8654 */
+ { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ st_yosemite }, /* generic st_yosemite */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 2f8073b73bf..43f5b6aa7dc 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -266,8 +266,8 @@ static struct scsi_host_template *the_template = NULL;
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+#define NEXT(cmd) ((struct scsi_cmnd *)((cmd)->host_scribble))
+#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble))
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
@@ -360,7 +360,7 @@ static void __init init_tags( void )
* conditions.
*/
-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
{
SETUP_HOSTDATA(cmd->device->host);
@@ -384,7 +384,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
* untagged.
*/
-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
{
SETUP_HOSTDATA(cmd->device->host);
@@ -416,7 +416,7 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
* unlock the LUN.
*/
-static void cmd_free_tag( Scsi_Cmnd *cmd )
+static void cmd_free_tag(struct scsi_cmnd *cmd)
{
SETUP_HOSTDATA(cmd->device->host);
@@ -460,18 +460,18 @@ static void free_all_tags( void )
/*
- * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ * Function: void merge_contiguous_buffers(struct scsi_cmnd *cmd)
*
* Purpose: Try to merge several scatter-gather requests into one DMA
* transfer. This is possible if the scatter buffers lie on
* physical contiguous addresses.
*
- * Parameters: Scsi_Cmnd *cmd
+ * Parameters: struct scsi_cmnd *cmd
* The command to work on. The first scatter buffer's data are
* assumed to be already transfered into ptr/this_residual.
*/
-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
{
unsigned long endaddr;
#if (NDEBUG & NDEBUG_MERGING)
@@ -501,15 +501,15 @@ static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
}
/*
- * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ * Function : void initialize_SCp(struct scsi_cmnd *cmd)
*
* Purpose : initialize the saved data pointers for cmd to point to the
* start of the buffer.
*
- * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ * Inputs : cmd - struct scsi_cmnd structure to have pointers reset.
*/
-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
{
/*
* Initialize the Scsi Pointer field so that all of the commands in the
@@ -753,14 +753,15 @@ static void NCR5380_print_status (struct Scsi_Host *instance)
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);
+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 int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
+ char **start, off_t offset, int length, int inout)
{
char *pos = buffer;
struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
+ struct scsi_cmnd *ptr;
unsigned long flags;
off_t begin = 0;
#define check_offset() \
@@ -784,18 +785,19 @@ static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **s
if (!hostdata->connected)
SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
else
- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+ pos = lprint_Scsi_Cmnd ((struct 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)) {
+ 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 = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
ptr = NEXT(ptr)) {
pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
check_offset();
@@ -810,8 +812,8 @@ static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **s
return length;
}
-static char *
-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer,
+ int length)
{
int i, s;
unsigned char *command;
@@ -888,8 +890,8 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags)
}
/*
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
+ * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd,
+ * void (*done)(struct scsi_cmnd *))
*
* Purpose : enqueues a SCSI command
*
@@ -906,10 +908,11 @@ static int NCR5380_init (struct Scsi_Host *instance, int flags)
*/
/* Only make static if a wrapper function is used */
-static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
{
SETUP_HOSTDATA(cmd->device->host);
- Scsi_Cmnd *tmp;
+ struct scsi_cmnd *tmp;
unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
@@ -990,7 +993,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
NEXT(cmd) = hostdata->issue_queue;
hostdata->issue_queue = cmd;
} else {
- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
NEXT(tmp); tmp = NEXT(tmp))
;
LIST(cmd, tmp);
@@ -1030,7 +1033,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
static void NCR5380_main (void *bl)
{
- Scsi_Cmnd *tmp, *prev;
+ struct scsi_cmnd *tmp, *prev;
struct Scsi_Host *instance = first_instance;
struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
int done;
@@ -1073,12 +1076,12 @@ static void NCR5380_main (void *bl)
* for a target that's not busy.
*/
#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
;
if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
#endif
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
#if (NDEBUG & NDEBUG_LISTS)
@@ -1252,7 +1255,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance )
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr (int irq, void *dev_id)
{
struct Scsi_Host *instance = first_instance;
int done = 1, handled = 0;
@@ -1268,7 +1271,7 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
NCR_PRINT(NDEBUG_INTR);
if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
done = 0;
- ENABLE_IRQ();
+// ENABLE_IRQ();
INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
NCR5380_reselect(instance);
(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
@@ -1301,7 +1304,7 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
NCR5380_dma_complete( instance );
done = 0;
- ENABLE_IRQ();
+// ENABLE_IRQ();
} else
#endif /* REAL_DMA */
{
@@ -1339,7 +1342,8 @@ static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
}
#ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+static void collect_stats(struct NCR5380_hostdata *hostdata,
+ struct scsi_cmnd *cmd)
{
# ifdef NCR5380_STAT_LIMIT
if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
@@ -1365,8 +1369,8 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
#endif
/*
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
- * int tag);
+ * Function : int NCR5380_select(struct Scsi_Host *instance,
+ * struct scsi_cmnd *cmd, int tag);
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
* including ARBITRATION, SELECTION, and initial message out for
@@ -1395,7 +1399,8 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
* cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd,
+ int tag)
{
SETUP_HOSTDATA(instance);
unsigned char tmp[3], phase;
@@ -1985,7 +1990,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
@@ -2017,7 +2022,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
!= cmd))
{
- if(cmd->request->flags & REQ_CMD) {
+ if(blk_fs_request(cmd->request)) {
sun3scsi_dma_setup(d, count,
rq_data_dir(cmd->request));
sun3_dma_setup_done = cmd;
@@ -2272,7 +2277,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
NEXT(cmd) = hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ hostdata->issue_queue = (struct scsi_cmnd *) cmd;
local_irq_restore(flags);
QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
@@ -2502,7 +2507,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * field to point to the struct scsi_cmnd for which the I_T_L or I_T_L_Q
* nexus has been reestablished,
*
* Inputs : instance - this instance of the NCR5380.
@@ -2521,7 +2526,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
unsigned char tag;
#endif
unsigned char msg[3];
- Scsi_Cmnd *tmp = NULL, *prev;
+ struct scsi_cmnd *tmp = NULL, *prev;
/* unsigned long flags; */
/*
@@ -2577,7 +2582,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
* just reestablished, and remove it from the disconnected queue.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
tmp; prev = tmp, tmp = NEXT(tmp) ) {
if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
@@ -2668,11 +2673,11 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
/*
- * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_abort(struct scsi_cmnd *cmd)
*
* Purpose : abort a command
*
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * Inputs : cmd - the struct scsi_cmnd to abort, code - code to set the
* host byte of the result field to, if zero DID_ABORTED is
* used.
*
@@ -2684,11 +2689,11 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
* called where the loop started in NCR5380_main().
*/
-static int NCR5380_abort (Scsi_Cmnd *cmd)
+static int NCR5380_abort(struct scsi_cmnd *cmd)
{
struct Scsi_Host *instance = cmd->device->host;
SETUP_HOSTDATA(instance);
- Scsi_Cmnd *tmp, **prev;
+ struct scsi_cmnd *tmp, **prev;
unsigned long flags;
printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
@@ -2753,9 +2758,9 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
* Case 2 : If the command hasn't been issued yet, we simply remove it
* from the issue queue.
*/
- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+ for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue),
+ tmp = (struct scsi_cmnd *) hostdata->issue_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp))
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
(*prev) = NEXT(tmp);
@@ -2812,7 +2817,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
* it from the disconnected queue.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp))
if (cmd == tmp) {
local_irq_restore(flags);
@@ -2826,8 +2831,8 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
do_abort (instance);
local_irq_save(flags);
- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+ for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue),
+ tmp = (struct scsi_cmnd *) hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
@@ -2868,7 +2873,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
/*
- * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_bus_reset(struct scsi_cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2876,13 +2881,13 @@ static int NCR5380_abort (Scsi_Cmnd *cmd)
*
*/
-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
SETUP_HOSTDATA(cmd->device->host);
int i;
unsigned long flags;
#if 1
- Scsi_Cmnd *connected, *disconnected_queue;
+ struct scsi_cmnd *connected, *disconnected_queue;
#endif
@@ -2914,9 +2919,9 @@ static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
* remembered in local variables first.
*/
local_irq_save(flags);
- connected = (Scsi_Cmnd *)hostdata->connected;
+ connected = (struct scsi_cmnd *)hostdata->connected;
hostdata->connected = NULL;
- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ disconnected_queue = (struct scsi_cmnd *)hostdata->disconnected_queue;
hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
free_all_tags();
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 837173415d4..69ee3e4a820 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -75,9 +75,9 @@
#define REAL_DMA
#include "scsi.h"
+#include "initio.h"
#include <scsi/scsi_host.h>
#include "sun3_scsi.h"
-#include "NCR5380.h"
static void NCR5380_print(struct Scsi_Host *instance);
@@ -102,7 +102,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
static inline unsigned char sun3scsi_read(int reg);
static inline void sun3scsi_write(int reg, int value);
@@ -119,7 +119,7 @@ module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-static Scsi_Cmnd *sun3_dma_setup_done = NULL;
+static struct scsi_cmnd *sun3_dma_setup_done = NULL;
#define AFTER_RESET_DELAY (HZ/2)
@@ -371,7 +371,7 @@ const char * sun3scsi_info (struct Scsi_Host *spnt) {
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
{
unsigned short csr = dregs->csr;
int handled = 0;
@@ -388,7 +388,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy, fp);
+ NCR5380_intr(irq, dummy);
handled = 1;
}
@@ -521,10 +521,11 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
return last_residual;
}
-static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
- int write_flag)
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
+ struct scsi_cmnd *cmd,
+ int write_flag)
{
- if(cmd->request->flags & REQ_CMD)
+ if(blk_fs_request(cmd->request))
return wanted;
else
return 0;
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index 834dab42801..b29a9d661ca 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -47,11 +47,12 @@
#define IOBASE_SUN3_VMESCSI 0xff200000
-static int sun3scsi_abort (Scsi_Cmnd *);
+static int sun3scsi_abort(struct scsi_cmnd *);
static int sun3scsi_detect (struct scsi_host_template *);
static const char *sun3scsi_info (struct Scsi_Host *);
-static int sun3scsi_bus_reset(Scsi_Cmnd *);
-static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sun3scsi_bus_reset(struct scsi_cmnd *);
+static int sun3scsi_queue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
static int sun3scsi_release (struct Scsi_Host *);
#ifndef CMD_PER_LUN
@@ -220,7 +221,7 @@ struct sun3_udc_regs {
*
*/
-
+#include "NCR5380.h"
#if NDEBUG & NDEBUG_ARBITRATION
#define ARB_PRINTK(format, args...) \
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index 008a82ab852..bb0c9fd99e6 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -41,9 +41,9 @@
#define REAL_DMA
#include "scsi.h"
+#include "initio.h"
#include <scsi/scsi_host.h>
#include "sun3_scsi.h"
-#include "NCR5380.h"
extern int sun3_map_test(unsigned long, char *);
@@ -67,7 +67,7 @@ extern int sun3_map_test(unsigned long, char *);
#define ENABLE_IRQ()
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
static inline unsigned char sun3scsi_read(int reg);
static inline void sun3scsi_write(int reg, int value);
@@ -84,7 +84,7 @@ module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-static Scsi_Cmnd *sun3_dma_setup_done = NULL;
+static struct scsi_cmnd *sun3_dma_setup_done = NULL;
#define AFTER_RESET_DELAY (HZ/2)
@@ -340,7 +340,7 @@ static const char * sun3scsi_info (struct Scsi_Host *spnt) {
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
{
unsigned short csr = dregs->csr;
int handled = 0;
@@ -371,7 +371,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy, fp);
+ NCR5380_intr(irq, dummy);
handled = 1;
}
@@ -455,10 +455,11 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
return last_residual;
}
-static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
- int write_flag)
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
+ struct scsi_cmnd *cmd,
+ int write_flag)
{
- if(cmd->request->flags & REQ_CMD)
+ if(blk_fs_request(cmd->request))
return wanted;
else
return 0;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 8640253d621..32c883f1efa 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -326,8 +326,7 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
return orig_len - len;
}
-static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
int base = 0;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 739d3ef46a4..4d78c7e87cc 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -652,7 +652,7 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
/*
* Linux entry point of the interrupt handler.
*/
-static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
struct sym_hcb *np = (struct sym_hcb *)dev_id;
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 2df6747cb76..0b7a70f61e0 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -109,7 +109,7 @@
#include <asm/system.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 646e840266e..76a069b7ac0 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -8,20 +8,20 @@
* drew@colorado.edu
* +1 (303) 440-4894
*
- * DISTRIBUTION RELEASE 3.
+ * DISTRIBUTION RELEASE 3.
*
- * For more information, please consult
+ * For more information, please consult
*
* Trantor Systems, Ltd.
* T128/T128F/T228 SCSI Host Adapter
* Hardware Specifications
- *
- * Trantor Systems, Ltd.
+ *
+ * Trantor Systems, Ltd.
* 5415 Randall Place
* Fremont, CA 94538
* 1+ (415) 770-1400, FAX 1+ (415) 770-9910
- *
- * and
+ *
+ * and
*
* NCR 5380 Family
* SCSI Protocol Controller
@@ -48,15 +48,15 @@
#define TDEBUG_TRANSFER 0x2
/*
- * The trantor boards are memory mapped. They use an NCR5380 or
+ * The trantor boards are memory mapped. They use an NCR5380 or
* equivalent (my sample board had part second sourced from ZILOG).
- * NCR's recommended "Pseudo-DMA" architecture is used, where
+ * NCR's recommended "Pseudo-DMA" architecture is used, where
* a PAL drives the DMA signals on the 5380 allowing fast, blind
- * transfers with proper handshaking.
+ * transfers with proper handshaking.
*/
/*
- * Note : a boot switch is provided for the purpose of informing the
+ * Note : a boot switch is provided for the purpose of informing the
* firmware to boot or not boot from attached SCSI devices. So, I imagine
* there are fewer people who've yanked the ROM like they do on the Seagate
* to make bootup faster, and I'll probably use this for autodetection.
@@ -92,19 +92,20 @@
#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
#ifndef ASM
-static int t128_abort(Scsi_Cmnd *);
+static int t128_abort(struct scsi_cmnd *);
static int t128_biosparam(struct scsi_device *, struct block_device *,
sector_t, int*);
static int t128_detect(struct scsi_host_template *);
-static int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int t128_bus_reset(Scsi_Cmnd *);
+static int t128_queue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
+static int t128_bus_reset(struct scsi_cmnd *);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
#endif
#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
+#define CAN_QUEUE 32
#endif
#ifndef HOSTS_C
@@ -120,7 +121,7 @@ static int t128_bus_reset(Scsi_Cmnd *);
#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
-#if !(TDEBUG & TDEBUG_TRANSFER)
+#if !(TDEBUG & TDEBUG_TRANSFER)
#define NCR5380_read(reg) readb(T128_address(reg))
#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
#else
@@ -129,7 +130,7 @@ static int t128_bus_reset(Scsi_Cmnd *);
, instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
#define NCR5380_write(reg, value) { \
- printk("scsi%d : write %02x to register %d at address %08x\n", \
+ printk("scsi%d : write %02x to register %d at address %08x\n", \
instance->hostno, (value), (reg), T128_address(reg)); \
writeb((value), (T128_address(reg))); \
}
@@ -142,10 +143,10 @@ static int t128_bus_reset(Scsi_Cmnd *);
#define NCR5380_bus_reset t128_bus_reset
#define NCR5380_proc_info t128_proc_info
-/* 15 14 12 10 7 5 3
+/* 15 14 12 10 7 5 3
1101 0100 1010 1000 */
-
-#define T128_IRQS 0xc4a8
+
+#define T128_IRQS 0xc4a8
#endif /* else def HOSTS_C */
#endif /* ndef ASM */
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 9404ff3d4c7..fa5382e354b 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -279,6 +279,10 @@ static void dc390_ResetDevParam(struct dc390_acb* pACB);
static u32 dc390_laststatus = 0;
static u8 dc390_adapterCnt = 0;
+static int disable_clustering;
+module_param(disable_clustering, int, S_IRUGO);
+MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1");
+
/* Startup values, to be overriden on the commandline */
static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
@@ -696,9 +700,9 @@ dc390_InvalidCmd(struct dc390_acb* pACB)
static irqreturn_t __inline__
-DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
+DC390_Interrupt(void *dev_id)
{
- struct dc390_acb *pACB = (struct dc390_acb*)dev_id;
+ struct dc390_acb *pACB = dev_id;
struct dc390_dcb *pDCB;
struct dc390_srb *pSRB;
u8 sstatus=0;
@@ -807,12 +811,12 @@ DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
{
irqreturn_t ret;
DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
/* Locking is done in DC390_Interrupt */
- ret = DC390_Interrupt(irq, dev_id, regs);
+ ret = DC390_Interrupt(dev_id);
DEBUG1(printk (".. IRQ returned\n"));
return ret;
}
@@ -2299,7 +2303,8 @@ static struct scsi_host_template driver_template = {
.this_id = 7,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
- .use_clustering = DISABLE_CLUSTERING,
+ .use_clustering = ENABLE_CLUSTERING,
+ .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */
};
/***********************************************************************
@@ -2525,6 +2530,8 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
pci_set_master(pdev);
error = -ENOMEM;
+ if (disable_clustering)
+ driver_template.use_clustering = DISABLE_CLUSTERING;
shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
if (!shost)
goto out_disable_device;
@@ -2660,6 +2667,10 @@ static struct pci_driver dc390_driver = {
static int __init dc390_module_init(void)
{
+ if (!disable_clustering)
+ printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
+ "\twith \"disable_clustering=1\" and report to maintainers\n");
+
if (tmscsim[0] == -1 || tmscsim[0] > 15) {
tmscsim[0] = 7;
tmscsim[1] = 4;
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 57449611e71..3de08a15de4 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -634,7 +634,7 @@ static unsigned long io_port[] = {
#define H2DEV(x) cpu_to_le32(x)
#define DEV2H(x) le32_to_cpu(x)
-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_interrupt_handler(int, void *);
static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
@@ -1932,8 +1932,7 @@ none:
return IRQ_NONE;
}
-static irqreturn_t do_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs) {
+static irqreturn_t do_interrupt_handler(int irq, void *shap) {
unsigned int j;
unsigned long spin_flags;
irqreturn_t ret;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 0372aa9fa19..56906aba5ee 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -287,8 +287,8 @@ static const unsigned short ultrastor_ports_14f[] = {
};
#endif
-static void ultrastor_interrupt(int, void *, struct pt_regs *);
-static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
+static void ultrastor_interrupt(void *);
+static irqreturn_t do_ultrastor_interrupt(int, void *);
static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
@@ -893,7 +893,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt)
spin_lock_irqsave(host->host_lock, flags);
/* FIXME: Ewww... need to think about passing host around properly */
- ultrastor_interrupt(0, NULL, NULL);
+ ultrastor_interrupt(NULL);
spin_unlock_irqrestore(host->host_lock, flags);
return SUCCESS;
}
@@ -1039,7 +1039,7 @@ int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
-static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void ultrastor_interrupt(void *dev_id)
{
unsigned int status;
#if ULTRASTOR_MAX_CMDS > 1
@@ -1171,14 +1171,13 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
}
-static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- ultrastor_interrupt(irq, dev_id, regs);
+ ultrastor_interrupt(dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index a0b61af48f1..30be76514c4 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -178,10 +178,10 @@
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/stat.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <asm/dma.h>
-#include <asm/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -998,7 +998,7 @@ static int make_code(unsigned hosterr, unsigned scsierr)
#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
-static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wd7000_intr(int irq, void *dev_id)
{
Adapter *host = (Adapter *) dev_id;
int flag, icmb, errstatus, icmb_status;