summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.c2
-rw-r--r--drivers/scsi/53c700.c57
-rw-r--r--drivers/scsi/53c700.h34
-rw-r--r--drivers/scsi/53c7xx.c13
-rw-r--r--drivers/scsi/BusLogic.c64
-rw-r--r--drivers/scsi/BusLogic.h1
-rw-r--r--drivers/scsi/FlashPoint.c1
-rw-r--r--drivers/scsi/Kconfig174
-rw-r--r--drivers/scsi/Makefile22
-rw-r--r--drivers/scsi/NCR5380.c4
-rw-r--r--drivers/scsi/NCR53C9x.c19
-rw-r--r--drivers/scsi/NCR53C9x.h1
-rw-r--r--drivers/scsi/NCR_D700.c16
-rw-r--r--drivers/scsi/NCR_Q720.c2
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/a2091.c8
-rw-r--r--drivers/scsi/a2091.h4
-rw-r--r--drivers/scsi/a3000.c10
-rw-r--r--drivers/scsi/a3000.h4
-rw-r--r--drivers/scsi/aacraid/aachba.c60
-rw-r--r--drivers/scsi/aacraid/aacraid.h20
-rw-r--r--drivers/scsi/aacraid/commctrl.c25
-rw-r--r--drivers/scsi/aacraid/comminit.c36
-rw-r--r--drivers/scsi/aacraid/commsup.c280
-rw-r--r--drivers/scsi/aacraid/dpcsup.c10
-rw-r--r--drivers/scsi/aacraid/linit.c35
-rw-r--r--drivers/scsi/aacraid/rkt.c446
-rw-r--r--drivers/scsi/aacraid/rx.c119
-rw-r--r--drivers/scsi/aacraid/sa.c23
-rw-r--r--drivers/scsi/advansys.c117
-rw-r--r--drivers/scsi/aha152x.c100
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aha1740.c3
-rw-r--r--drivers/scsi/ahci.c1472
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c26
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c87
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h13
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c19
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c24
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aicasm/Makefile2
-rw-r--r--drivers/scsi/aic7xxx_old.c15
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx_proc.c1
-rw-r--r--drivers/scsi/aic94xx/Kconfig41
-rw-r--r--drivers/scsi/aic94xx/Makefile39
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h114
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c353
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c959
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.h52
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c1376
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h397
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c866
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.c332
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.h302
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h2398
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h785
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c758
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c1089
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c1404
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.h70
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c642
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c636
-rw-r--r--drivers/scsi/amiga7xx.c1
-rw-r--r--drivers/scsi/arcmsr/Makefile6
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h472
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c381
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c1496
-rw-r--r--drivers/scsi/arm/Kconfig3
-rw-r--r--drivers/scsi/arm/acornscsi.c3
-rw-r--r--drivers/scsi/arm/cumana_1.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c2
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/arm/powertec.c2
-rw-r--r--drivers/scsi/arm/scsi.h2
-rw-r--r--drivers/scsi/ata_piix.c904
-rw-r--r--drivers/scsi/atari_NCR5380.c3
-rw-r--r--drivers/scsi/atari_scsi.c1
-rw-r--r--drivers/scsi/atp870u.c163
-rw-r--r--drivers/scsi/blz1230.c2
-rw-r--r--drivers/scsi/blz2060.c2
-rw-r--r--drivers/scsi/ch.c1
-rw-r--r--drivers/scsi/constants.c127
-rw-r--r--drivers/scsi/cyberstorm.c2
-rw-r--r--drivers/scsi/cyberstormII.c2
-rw-r--r--drivers/scsi/dc395x.c4
-rw-r--r--drivers/scsi/dec_esp.c10
-rw-r--r--drivers/scsi/dmx3191d.c2
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h1
-rw-r--r--drivers/scsi/dpt_i2o.c9
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c3
-rw-r--r--drivers/scsi/eata_generic.h1
-rw-r--r--drivers/scsi/eata_pio.c132
-rw-r--r--drivers/scsi/esp.c335
-rw-r--r--drivers/scsi/esp.h4
-rw-r--r--drivers/scsi/fastlane.c2
-rw-r--r--drivers/scsi/fcal.c4
-rw-r--r--drivers/scsi/fd_mcs.c2
-rw-r--r--drivers/scsi/fdomain.c3
-rw-r--r--drivers/scsi/g_NCR5380.c6
-rw-r--r--drivers/scsi/g_NCR5380.h1
-rw-r--r--drivers/scsi/gdth.c6
-rw-r--r--drivers/scsi/gvp11.c10
-rw-r--r--drivers/scsi/gvp11.h4
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/hptiop.c571
-rw-r--r--drivers/scsi/ibmmca.c15
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c64
-rw-r--r--drivers/scsi/ibmvscsi/iseries_vscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c17
-rw-r--r--drivers/scsi/ide-scsi.c3
-rw-r--r--drivers/scsi/imm.c4
-rw-r--r--drivers/scsi/imm.h2
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c3
-rw-r--r--drivers/scsi/initio.h13
-rw-r--r--drivers/scsi/ipr.c37
-rw-r--r--drivers/scsi/ipr.h82
-rw-r--r--drivers/scsi/ips.c9
-rw-r--r--drivers/scsi/iscsi_tcp.c1134
-rw-r--r--drivers/scsi/iscsi_tcp.h46
-rw-r--r--drivers/scsi/jazz_esp.c4
-rw-r--r--drivers/scsi/lasi700.c2
-rw-r--r--drivers/scsi/libata-bmdma.c1150
-rw-r--r--drivers/scsi/libata-core.c5916
-rw-r--r--drivers/scsi/libata-eh.c1907
-rw-r--r--drivers/scsi/libata-scsi.c3052
-rw-r--r--drivers/scsi/libata.h115
-rw-r--r--drivers/scsi/libiscsi.c533
-rw-r--r--drivers/scsi/libsas/Kconfig39
-rw-r--r--drivers/scsi/libsas/Makefile36
-rw-r--r--drivers/scsi/libsas/sas_discover.c749
-rw-r--r--drivers/scsi/libsas/sas_dump.c76
-rw-r--r--drivers/scsi/libsas/sas_dump.h42
-rw-r--r--drivers/scsi/libsas/sas_event.c75
-rw-r--r--drivers/scsi/libsas/sas_expander.c1855
-rw-r--r--drivers/scsi/libsas/sas_init.c267
-rw-r--r--drivers/scsi/libsas/sas_internal.h146
-rw-r--r--drivers/scsi/libsas/sas_phy.c158
-rw-r--r--drivers/scsi/libsas/sas_port.c279
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c786
-rw-r--r--drivers/scsi/lpfc/lpfc.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c475
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c38
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c97
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c205
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c87
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c16
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c37
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c115
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c112
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac53c94.c4
-rw-r--r--drivers/scsi/mac_esp.c7
-rw-r--r--drivers/scsi/mac_scsi.c7
-rw-r--r--drivers/scsi/megaraid.c11
-rw-r--r--drivers/scsi/megaraid/mega_common.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_ioctl.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c62
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c52
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h21
-rw-r--r--drivers/scsi/mesh.c23
-rw-r--r--drivers/scsi/mvme147.c6
-rw-r--r--drivers/scsi/mvme147.h4
-rw-r--r--drivers/scsi/ncr53c8xx.c3
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/nsp32.c12
-rw-r--r--drivers/scsi/oktagon_esp.c3
-rw-r--r--drivers/scsi/oktagon_io.S1
-rw-r--r--drivers/scsi/osst.h1
-rw-r--r--drivers/scsi/pas16.c2
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c2
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c2
-rw-r--r--drivers/scsi/pdc_adma.c739
-rw-r--r--drivers/scsi/pluto.c3
-rw-r--r--drivers/scsi/ppa.c3
-rw-r--r--drivers/scsi/ppa.h2
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c120
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c925
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h151
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h22
-rw-r--r--drivers/scsi/qla2xxx/qla_devtbl.h17
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h26
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c157
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c29
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c280
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c142
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qlogicpti.c367
-rw-r--r--drivers/scsi/sata_mv.c2468
-rw-r--r--drivers/scsi/sata_nv.c596
-rw-r--r--drivers/scsi/sata_promise.c837
-rw-r--r--drivers/scsi/sata_promise.h157
-rw-r--r--drivers/scsi/sata_qstor.c730
-rw-r--r--drivers/scsi/sata_sil.c683
-rw-r--r--drivers/scsi/sata_sil24.c1181
-rw-r--r--drivers/scsi/sata_sis.c348
-rw-r--r--drivers/scsi/sata_svw.c509
-rw-r--r--drivers/scsi/sata_sx4.c1502
-rw-r--r--drivers/scsi/sata_uli.c301
-rw-r--r--drivers/scsi/sata_via.c394
-rw-r--r--drivers/scsi/sata_vsc.c486
-rw-r--r--drivers/scsi/scsi.c61
-rw-r--r--drivers/scsi/scsi.h2
-rw-r--r--drivers/scsi/scsi_debug.c1456
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/scsi/scsi_error.c242
-rw-r--r--drivers/scsi/scsi_ioctl.c5
-rw-r--r--drivers/scsi/scsi_lib.c220
-rw-r--r--drivers/scsi/scsi_logging.h1
-rw-r--r--drivers/scsi/scsi_netlink.c199
-rw-r--r--drivers/scsi/scsi_priv.h15
-rw-r--r--drivers/scsi/scsi_proc.c4
-rw-r--r--drivers/scsi/scsi_sas_internal.h10
-rw-r--r--drivers/scsi/scsi_scan.c148
-rw-r--r--drivers/scsi/scsi_sysfs.c1
-rw-r--r--drivers/scsi/scsi_transport_fc.c408
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c663
-rw-r--r--drivers/scsi/scsi_transport_sas.c510
-rw-r--r--drivers/scsi/scsi_transport_spi.c31
-rw-r--r--drivers/scsi/scsicam.c3
-rw-r--r--drivers/scsi/sd.c175
-rw-r--r--drivers/scsi/seagate.c4
-rw-r--r--drivers/scsi/sg.c19
-rw-r--r--drivers/scsi/sgiwd93.c8
-rw-r--r--drivers/scsi/sim710.c4
-rw-r--r--drivers/scsi/sr.c7
-rw-r--r--drivers/scsi/sr_vendor.c1
-rw-r--r--drivers/scsi/st.c10
-rw-r--r--drivers/scsi/st.h1
-rw-r--r--drivers/scsi/stex.c1252
-rw-r--r--drivers/scsi/sun3_NCR5380.c3
-rw-r--r--drivers/scsi/sun3x_esp.c12
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c4
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h1
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/tmscsim.c3
-rw-r--r--drivers/scsi/tmscsim.h1
-rw-r--r--drivers/scsi/u14-34f.c3
-rw-r--r--drivers/scsi/ultrastor.c23
-rw-r--r--drivers/scsi/ultrastor.h12
-rw-r--r--drivers/scsi/wd33c93.c3
-rw-r--r--drivers/scsi/wd33c93.h1
-rw-r--r--drivers/scsi/wd7000.c4
-rw-r--r--drivers/scsi/zalon.c2
261 files changed, 28159 insertions, 31373 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b003baf8d40..5a9475e56d0 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -2122,7 +2122,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
/* Now setup the interrupt handler */
- retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev);
+ retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
if (retval) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
goto out_remove_host;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 17dbd4ac869..f3a5f422a8e 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2397,7 +2397,7 @@ static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *
printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq);
/* Now setup the interrupt handler */
- retval = request_irq(pdev->irq, tw_interrupt, SA_SHIRQ, "3w-xxxx", tw_dev);
+ retval = request_irq(pdev->irq, tw_interrupt, IRQF_SHARED, "3w-xxxx", tw_dev);
if (retval) {
printk(KERN_WARNING "3w-xxxx: Error requesting IRQ.");
goto out_remove_host;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 3c683dc2354..657a3ab7539 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -114,7 +114,6 @@
* */
#define NCR_700_VERSION "2.8"
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -174,6 +173,7 @@ STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
+STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
@@ -183,10 +183,6 @@ STATIC struct device_attribute *NCR_700_dev_attrs[];
STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
-struct NCR_700_sense {
- unsigned char cmnd[MAX_COMMAND_SIZE];
-};
-
static char *NCR_700_phase[] = {
"",
"after selection",
@@ -334,6 +330,7 @@ NCR_700_detect(struct scsi_host_template *tpnt,
tpnt->use_clustering = ENABLE_CLUSTERING;
tpnt->slave_configure = NCR_700_slave_configure;
tpnt->slave_destroy = NCR_700_slave_destroy;
+ tpnt->slave_alloc = NCR_700_slave_alloc;
tpnt->change_queue_depth = NCR_700_change_queue_depth;
tpnt->change_queue_type = NCR_700_change_queue_type;
@@ -612,9 +609,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
- NCR_700_unmap(hostdata, SCp, slot);
+ dma_unmap_single(hostdata->dev, slot->pCmd,
+ sizeof(SCp->cmnd), DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
- struct NCR_700_sense *sense = SCp->device->hostdata;
+ char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_700_DEBUG
printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
SCp, SCp->cmnd[7], result);
@@ -625,10 +623,9 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
/* restore the old result if the request sense was
* successful */
if(result == 0)
- result = sense->cmnd[7];
+ result = cmnd[7];
} else
- dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ NCR_700_unmap(hostdata, SCp, slot);
free_slot(slot, hostdata);
#ifdef NCR_700_DEBUG
@@ -970,14 +967,15 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
- if(SCp->cmnd[0] == REQUEST_SENSE) {
+ if(slot->flags == NCR_700_FLAG_AUTOSENSE) {
/* OOPS: bad device, returning another
* contingent allegiance condition */
scmd_printk(KERN_ERR, SCp,
"broken device is looping in contingent allegiance: ignoring\n");
NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
} else {
- struct NCR_700_sense *sense = SCp->device->hostdata;
+ char *cmnd =
+ NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_DEBUG
scsi_print_command(SCp);
printk(" cmd %p has status %d, requesting sense\n",
@@ -995,21 +993,21 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
sizeof(SCp->cmnd),
DMA_TO_DEVICE);
- sense->cmnd[0] = REQUEST_SENSE;
- sense->cmnd[1] = (SCp->device->lun & 0x7) << 5;
- sense->cmnd[2] = 0;
- sense->cmnd[3] = 0;
- sense->cmnd[4] = sizeof(SCp->sense_buffer);
- sense->cmnd[5] = 0;
+ cmnd[0] = REQUEST_SENSE;
+ cmnd[1] = (SCp->device->lun & 0x7) << 5;
+ cmnd[2] = 0;
+ cmnd[3] = 0;
+ cmnd[4] = sizeof(SCp->sense_buffer);
+ cmnd[5] = 0;
/* Here's a quiet hack: the
* REQUEST_SENSE command is six bytes,
* so store a flag indicating that
* this was an internal sense request
* and the original status at the end
* of the command */
- sense->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
- sense->cmnd[7] = hostdata->status[0];
- slot->pCmd = dma_map_single(hostdata->dev, sense->cmnd, sizeof(sense->cmnd), DMA_TO_DEVICE);
+ cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
+ cmnd[7] = hostdata->status[0];
+ 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));
slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
@@ -1531,7 +1529,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
/* clear all the negotiated parameters */
__shost_for_each_device(SDp, host)
- SDp->hostdata = NULL;
+ NCR_700_clear_flag(SDp, ~0);
/* clear all the slots and their pending commands */
for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
@@ -2036,7 +2034,17 @@ NCR_700_set_offset(struct scsi_target *STp, int offset)
spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
}
+STATIC int
+NCR_700_slave_alloc(struct scsi_device *SDp)
+{
+ SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters),
+ GFP_KERNEL);
+ if (!SDp->hostdata)
+ return -ENOMEM;
+
+ return 0;
+}
STATIC int
NCR_700_slave_configure(struct scsi_device *SDp)
@@ -2044,11 +2052,6 @@ NCR_700_slave_configure(struct scsi_device *SDp)
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
- SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense));
-
- if (!SDp->hostdata)
- return -ENOMEM;
-
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 7f22a06fe5e..97ebe71b701 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -12,7 +12,7 @@
#include <asm/io.h>
#include <scsi/scsi_device.h>
-
+#include <scsi/scsi_cmnd.h>
/* Turn on for general debugging---too verbose for normal use */
#undef NCR_700_DEBUG
@@ -76,11 +76,16 @@ struct NCR_700_SG_List {
#define SCRIPT_RETURN 0x90080000
};
-/* We use device->hostdata to store negotiated parameters. This is
- * supposed to be a pointer to a device private area, but we cannot
- * really use it as such since it will never be freed, so just use the
- * 32 bits to cram the information. The SYNC negotiation sequence looks
- * like:
+struct NCR_700_Device_Parameters {
+ /* space for creating a request sense command. Really, except
+ * for the annoying SCSI-2 requirement for LUN information in
+ * cmnd[1], this could be in static storage */
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ __u8 depth;
+};
+
+
+/* The SYNC negotiation sequence looks like:
*
* If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the
* initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION
@@ -98,19 +103,26 @@ struct NCR_700_SG_List {
#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17)
#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
+static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp)
+{
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
+
+ return hostdata->cmnd;
+}
+
static inline void
NCR_700_set_depth(struct scsi_device *SDp, __u8 depth)
{
- long l = (long)SDp->hostdata;
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
- l &= 0xffff00ff;
- l |= 0xff00 & (depth << 8);
- SDp->hostdata = (void *)l;
+ hostdata->depth = depth;
}
static inline __u8
NCR_700_get_depth(struct scsi_device *SDp)
{
- return ((((unsigned long)SDp->hostdata) & 0xff00)>>8);
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
+
+ return hostdata->depth;
}
static inline int
NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag)
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 765769a629e..acf292736b4 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -232,7 +232,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/setup.h>
@@ -1071,7 +1070,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_driver_init (host);
- if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7xx", host))
+ if (request_irq(host->irq, NCR53c7x0_intr, IRQF_SHARED, "53c7xx", host))
{
printk("scsi%d : IRQ%d not free, detaching\n",
host->host_no, host->irq);
@@ -3452,12 +3451,12 @@ create_cmd (Scsi_Cmnd *cmd) {
for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
cmd_dataout += 4, ++i) {
u32 vbuf = cmd->use_sg
- ? (u32)page_address(((struct scatterlist *)cmd->buffer)[i].page)+
- ((struct scatterlist *)cmd->buffer)[i].offset
+ ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+
+ ((struct scatterlist *)cmd->request_buffer)[i].offset
: (u32)(cmd->request_buffer);
u32 bbuf = virt_to_bus((void *)vbuf);
u32 count = cmd->use_sg ?
- ((struct scatterlist *)cmd->buffer)[i].length :
+ ((struct scatterlist *)cmd->request_buffer)[i].length :
cmd->request_bufflen;
/*
@@ -4233,7 +4232,7 @@ restart:
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
* the same IRQ line.
*
- * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ * Inputs : Since we're using the IRQF_DISABLED interrupt handler
* semantics, irq indicates the interrupt which invoked
* this handler.
*
@@ -5418,7 +5417,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
if ((buffers = cmd->use_sg)) {
for (offset = 0,
- segment = (struct scatterlist *) cmd->buffer;
+ segment = (struct scatterlist *) cmd->request_buffer;
buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) &&
(ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
--buffers, offset += segment->length, ++segment)
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index bde3d5834ad..4ea49fd7965 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -29,7 +29,6 @@
#define BusLogic_DriverVersion "2.1.16"
#define BusLogic_DriverDate "18 July 2002"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -663,7 +662,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
particular standard ISA I/O Address need not be probed.
*/
PrimaryProbeInfo->IO_Address = 0;
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation;
enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest;
@@ -763,7 +762,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
PrimaryProbeInfo->Bus = Bus;
PrimaryProbeInfo->Device = Device;
PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
- PrimaryProbeInfo->PCI_Device = PCI_Device;
+ PrimaryProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
PCIMultiMasterCount++;
} else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) {
struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
@@ -774,7 +773,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
NonPrimaryPCIMultiMasterCount++;
PCIMultiMasterCount++;
} else
@@ -824,7 +823,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
noting the PCI bus location and assigned IRQ Channel.
*/
PCI_Device = NULL;
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
unsigned char Bus;
unsigned char Device;
unsigned int IRQ_Channel;
@@ -851,7 +850,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
break;
}
}
@@ -875,7 +874,7 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda
/*
Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
*/
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
unsigned char Bus;
unsigned char Device;
unsigned int IRQ_Channel;
@@ -924,7 +923,7 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
FlashPointCount++;
} else
BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL);
@@ -1845,7 +1844,7 @@ static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *Hos
/*
Acquire shared access to the IRQ Channel.
*/
- if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) {
+ if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, IRQF_SHARED, HostAdapter->FullModelName, HostAdapter) < 0) {
BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel);
return false;
}
@@ -1891,6 +1890,7 @@ static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter)
*/
if (HostAdapter->MailboxSpace)
pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle);
+ pci_dev_put(HostAdapter->PCI_Device);
HostAdapter->MailboxSpace = NULL;
HostAdapter->MailboxSpaceHandle = 0;
HostAdapter->MailboxSize = 0;
@@ -2177,6 +2177,7 @@ static int __init BusLogic_init(void)
{
int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
struct BusLogic_HostAdapter *PrototypeHostAdapter;
+ int ret = 0;
#ifdef MODULE
if (BusLogic)
@@ -2283,25 +2284,49 @@ static int __init BusLogic_init(void)
perform Target Device Inquiry.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
- BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) {
+ BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
+ BusLogic_AcquireResources(HostAdapter) &&
+ BusLogic_CreateInitialCCBs(HostAdapter) &&
+ BusLogic_InitializeHostAdapter(HostAdapter) &&
+ BusLogic_TargetDeviceInquiry(HostAdapter)) {
/*
Initialization has been completed successfully. Release and
re-register usage of the I/O Address range so that the Model
Name of the Host Adapter will appear, and initialize the SCSI
Host structure.
*/
- release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
- if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) {
- printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address);
+ release_region(HostAdapter->IO_Address,
+ HostAdapter->AddressCount);
+ if (!request_region(HostAdapter->IO_Address,
+ HostAdapter->AddressCount,
+ HostAdapter->FullModelName)) {
+ printk(KERN_WARNING
+ "BusLogic: Release and re-register of "
+ "port 0x%04lx failed \n",
+ (unsigned long)HostAdapter->IO_Address);
BusLogic_DestroyCCBs(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
+ ret = -ENOMEM;
} else {
- BusLogic_InitializeHostStructure(HostAdapter, Host);
- scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
- scsi_scan_host(Host);
- BusLogicHostAdapterCount++;
+ BusLogic_InitializeHostStructure(HostAdapter,
+ Host);
+ if (scsi_add_host(Host, HostAdapter->PCI_Device
+ ? &HostAdapter->PCI_Device->dev
+ : NULL)) {
+ printk(KERN_WARNING
+ "BusLogic: scsi_add_host()"
+ "failed!\n");
+ BusLogic_DestroyCCBs(HostAdapter);
+ BusLogic_ReleaseResources(HostAdapter);
+ list_del(&HostAdapter->host_list);
+ scsi_host_put(Host);
+ ret = -ENODEV;
+ } else {
+ scsi_scan_host(Host);
+ BusLogicHostAdapterCount++;
+ }
}
} else {
/*
@@ -2316,12 +2341,13 @@ static int __init BusLogic_init(void)
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
+ ret = -ENODEV;
}
}
kfree(PrototypeHostAdapter);
kfree(BusLogic_ProbeInfoList);
BusLogic_ProbeInfoList = NULL;
- return 0;
+ return ret;
}
@@ -2955,6 +2981,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
}
+#if 0
/*
BusLogic_AbortCommand aborts Command if possible.
*/
@@ -3025,6 +3052,7 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command)
return SUCCESS;
}
+#endif
/*
BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
currently executing SCSI Commands as having been Reset.
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 1aaa6569eda..9792e5af525 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -28,7 +28,6 @@
#ifndef _BUSLOGIC_H
#define _BUSLOGIC_H
-#include <linux/config.h>
#ifndef PACKED
#define PACKED __attribute__((packed))
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 8e3d949b711..7c006804958 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -15,7 +15,6 @@
*/
-#include <linux/config.h>
#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 44728ae3fe7..c4dfcc91ddd 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -27,6 +27,11 @@ 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_NETLINK
+ bool
+ default n
+ select NET
+
config SCSI_PROC_FS
bool "legacy /proc/scsi/ support"
depends on SCSI && PROC_FS
@@ -209,7 +214,7 @@ config SCSI_LOGGING
there should be no noticeable performance impact as long as you have
logging turned off.
-menu "SCSI Transport Attributes"
+menu "SCSI Transports"
depends on SCSI
config SCSI_SPI_ATTRS
@@ -222,6 +227,7 @@ config SCSI_SPI_ATTRS
config SCSI_FC_ATTRS
tristate "FiberChannel Transport Attributes"
depends on SCSI
+ select SCSI_NETLINK
help
If you wish to export transport-specific information about
each attached FiberChannel device to sysfs, say Y.
@@ -242,6 +248,8 @@ config SCSI_SAS_ATTRS
If you wish to export transport-specific information about
each attached SAS device to sysfs, say Y.
+source "drivers/scsi/libsas/Kconfig"
+
endmenu
menu "SCSI low-level drivers"
@@ -431,6 +439,7 @@ config SCSI_AIC7XXX_OLD
module will be called aic7xxx_old.
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
+source "drivers/scsi/aic94xx/Kconfig"
# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
@@ -469,68 +478,21 @@ config SCSI_IN2000
To compile this driver as a module, choose M here: the
module will be called in2000.
-source "drivers/scsi/megaraid/Kconfig.megaraid"
-
-config SCSI_SATA
- tristate "Serial ATA (SATA) support"
- depends on SCSI
- help
- This driver family supports Serial ATA host controllers
- and devices.
-
- If unsure, say N.
-
-config SCSI_SATA_AHCI
- tristate "AHCI SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for AHCI Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SVW
- tristate "ServerWorks Frodo / Apple K2 SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Broadcom/Serverworks/Apple K2
- SATA support.
-
- If unsure, say N.
-
-config SCSI_ATA_PIIX
- tristate "Intel PIIX/ICH SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for ICH5 Serial ATA.
- If PATA support was enabled previously, this enables
- support for select Intel PIIX/ICH PATA host controllers.
-
- If unsure, say N.
-
-config SCSI_SATA_MV
- tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for the Marvell Serial ATA family.
- Currently supports 88SX[56]0[48][01] chips.
-
- If unsure, say N.
-
-config SCSI_SATA_NV
- tristate "NVIDIA SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
+config SCSI_ARCMSR
+ tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+ depends on PCI && SCSI
help
- This option enables support for NVIDIA Serial ATA.
+ This driver supports all of ARECA's SATA RAID controller cards.
+ This is an ARECA-maintained driver by Erich Chen.
+ If you have any problems, please mail to: < erich@areca.com.tw >
+ Areca supports Linux RAID config tools.
- If unsure, say N.
+ < http://www.areca.com.tw >
-config SCSI_PDC_ADMA
- tristate "Pacific Digital ADMA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Pacific Digital ADMA controllers
+ To compile this driver as a module, choose M here: the
+ module will be called arcmsr (modprobe arcmsr).
- If unsure, say N.
+source "drivers/scsi/megaraid/Kconfig.megaraid"
config SCSI_HPTIOP
tristate "HighPoint RocketRAID 3xxx Controller support"
@@ -542,83 +504,6 @@ config SCSI_HPTIOP
To compile this driver as a module, choose M here; the module
will be called hptiop. If unsure, say N.
-config SCSI_SATA_QSTOR
- tristate "Pacific Digital SATA QStor support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Pacific Digital Serial ATA QStor.
-
- If unsure, say N.
-
-config SCSI_SATA_PROMISE
- tristate "Promise SATA TX2/TX4 support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Promise Serial ATA TX2/TX4.
-
- If unsure, say N.
-
-config SCSI_SATA_SX4
- tristate "Promise SATA SX4 support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Promise Serial ATA SX4.
-
- If unsure, say N.
-
-config SCSI_SATA_SIL
- tristate "Silicon Image SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Silicon Image Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SIL24
- tristate "Silicon Image 3124/3132 SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Silicon Image 3124/3132 Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SIS
- tristate "SiS 964/180 SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for SiS Serial ATA 964/180.
-
- If unsure, say N.
-
-config SCSI_SATA_ULI
- tristate "ULi Electronics SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for ULi Electronics SATA.
-
- If unsure, say N.
-
-config SCSI_SATA_VIA
- tristate "VIA SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for VIA Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_VITESSE
- tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_INTEL_COMBINED
- bool
- depends on IDE=y && !BLK_DEV_IDE_SATA && (SCSI_SATA_AHCI || SCSI_ATA_PIIX)
- default y
-
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
@@ -1053,6 +938,13 @@ config 53C700_LE_ON_BE
depends on SCSI_LASI700
default y
+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.
+
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
depends on PCI && SCSI
@@ -1169,7 +1061,7 @@ config SCSI_NCR_Q720
you do not have this SCSI card, so say N.
config SCSI_NCR53C8XX_DEFAULT_TAGS
- int " default tagged command queue depth"
+ int "default tagged command queue depth"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "8"
---help---
@@ -1195,7 +1087,7 @@ config SCSI_NCR53C8XX_DEFAULT_TAGS
There is no safe option other than using good SCSI devices.
config SCSI_NCR53C8XX_MAX_TAGS
- int " maximum number of queued commands"
+ int "maximum number of queued commands"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "32"
---help---
@@ -1212,7 +1104,7 @@ config SCSI_NCR53C8XX_MAX_TAGS
There is no safe option and the default answer is recommended.
config SCSI_NCR53C8XX_SYNC
- int " synchronous transfers frequency in MHz"
+ int "synchronous transfers frequency in MHz"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "20"
---help---
@@ -1246,7 +1138,7 @@ config SCSI_NCR53C8XX_SYNC
terminations and SCSI conformant devices.
config SCSI_NCR53C8XX_PROFILE
- bool " enable profiling"
+ bool "enable profiling"
depends on SCSI_ZALON || SCSI_NCR_Q720
help
This option allows you to enable profiling information gathering.
@@ -1257,7 +1149,7 @@ config SCSI_NCR53C8XX_PROFILE
The normal answer therefore is N.
config SCSI_NCR53C8XX_NO_DISCONNECT
- bool " not allow targets to disconnect"
+ bool "not allow targets to disconnect"
depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
help
This option is only provided for safety if you suspect some SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 84d546323dc..1ef951be7a5 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -32,8 +32,10 @@ obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
+obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
+obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
@@ -58,6 +60,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
+obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/
obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
@@ -66,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/
obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/
obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
@@ -121,22 +125,8 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_IPR) += ipr.o
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
-obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o
-obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
-obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
-obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
-obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o
-obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
-obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o
-obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
-obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o
-obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
-obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o
-obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o
-obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
-obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
-obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
+obj-$(CONFIG_SCSI_STEX) += stex.o
obj-$(CONFIG_ARM) += arm/
@@ -154,6 +144,7 @@ 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 \
scsi_devinfo.o
+scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
@@ -165,7 +156,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
zalon7xx-objs := zalon.o ncr53c8xx.o
NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
-libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index fa57e0b4a5f..616810ad17d 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -500,7 +500,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
/*
* Function : int should_disconnect (unsigned char cmd)
*
- * Purpose : decide weather a command would normally disconnect or
+ * Purpose : decide whether a command would normally disconnect or
* not, since if it won't disconnect we should go to sleep.
*
* Input : cmd - opcode of SCSI command
@@ -585,7 +585,7 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
NCR5380_setup(instance);
for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
- if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0))
+ if ((mask & possible) && (request_irq(i, &probe_intr, IRQF_DISABLED, "NCR-probe", NULL) == 0))
trying_irqs |= mask;
timeout = jiffies + (250 * HZ / 1000);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index c7dd0154d01..bdc6bb262bc 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
@@ -912,7 +911,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
sp->SCp.ptr =
(char *) virt_to_phys(sp->request_buffer);
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sp->use_sg - 1;
sp->SCp.this_residual = sp->SCp.buffer->length;
if (esp->dma_mmu_get_scsi_sgl)
@@ -2153,29 +2152,23 @@ static int esp_do_data_finale(struct NCR_ESP *esp,
*/
static int esp_should_clear_sync(Scsi_Cmnd *sp)
{
- unchar cmd1 = sp->cmnd[0];
- unchar cmd2 = sp->data_cmnd[0];
+ unchar cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if(cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if(cmd == START_STOP)
return 0;
- if(cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if(cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
* this is what is used to probe the device for
* completion of a rewind or tape load operation.
*/
- if(sp->device->type == TYPE_TAPE) {
- if(cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
- return 0;
- }
+ if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE)
+ return 0;
return 1;
}
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 65a9b377a41..481653c977c 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -13,7 +13,6 @@
#ifndef NCR53C9X_H
#define NCR53C9X_H
-#include <linux/config.h>
#include <linux/interrupt.h>
/* djweis for mac driver */
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 577e6349977..d05681f9d81 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -114,7 +114,7 @@ MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
MODULE_LICENSE("GPL");
module_param(NCR_D700, charp, 0);
-static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
{ [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
#ifdef MODULE
@@ -173,7 +173,7 @@ struct NCR_D700_private {
char pad;
};
-static int
+static int __devinit
NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
int slot, u32 region, int differential)
{
@@ -243,7 +243,7 @@ NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
* essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one
* adapter with two channels */
-static int
+static int __devinit
NCR_D700_probe(struct device *dev)
{
struct NCR_D700_private *p;
@@ -320,7 +320,7 @@ NCR_D700_probe(struct device *dev)
memset(p, '\0', sizeof(*p));
p->dev = dev;
snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
- if (request_irq(irq, NCR_D700_intr, SA_SHIRQ, p->name, p)) {
+ if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
printk(KERN_ERR "D700: request_irq failed\n");
kfree(p);
return -EBUSY;
@@ -329,7 +329,7 @@ NCR_D700_probe(struct device *dev)
for (i = 0; i < 2; i++) {
int err;
- if ((err = NCR_D700_probe_one(p, i, slot, irq,
+ if ((err = NCR_D700_probe_one(p, i, irq, slot,
offset_addr + (0x80 * i),
differential)) != 0)
printk("D700: SIOP%d: probe failed, error = %d\n",
@@ -349,7 +349,7 @@ NCR_D700_probe(struct device *dev)
return 0;
}
-static void
+static void __devexit
NCR_D700_remove_one(struct Scsi_Host *host)
{
scsi_remove_host(host);
@@ -359,7 +359,7 @@ NCR_D700_remove_one(struct Scsi_Host *host)
release_region(host->base, 64);
}
-static int
+static int __devexit
NCR_D700_remove(struct device *dev)
{
struct NCR_D700_private *p = dev_get_drvdata(dev);
@@ -380,7 +380,7 @@ static struct mca_driver NCR_D700_driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
- .remove = NCR_D700_remove,
+ .remove = __devexit_p(NCR_D700_remove),
},
};
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index 9d18ec90510..c39ffbb86e3 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -265,7 +265,7 @@ NCR_Q720_probe(struct device *dev)
p->irq = irq;
p->siops = siops;
- if (request_irq(irq, NCR_Q720_intr, SA_SHIRQ, "NCR_Q720", p)) {
+ if (request_irq(irq, NCR_Q720_intr, IRQF_SHARED, "NCR_Q720", p)) {
printk(KERN_ERR "NCR_Q720: request irq %d failed\n", irq);
goto out_release;
}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 3dce21c7873..d7e9fab54c6 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1120,7 +1120,7 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
shost->sg_tablesize = TOTAL_SG_ENTRY;
/* Initial orc chip */
- error = request_irq(pdev->irq, inia100_intr, SA_SHIRQ,
+ error = request_irq(pdev->irq, inia100_intr, IRQF_SHARED,
"inia100", shost);
if (error < 0) {
printk(KERN_WARNING "inia100: unable to get irq %d\n",
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 54996eaae97..08540692860 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -40,7 +40,7 @@ static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -115,7 +115,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
/* disable SCSI interrupts */
@@ -208,7 +208,7 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
regs.SASR = &(DMA(instance)->SASR);
regs.SCMD = &(DMA(instance)->SCMD);
wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
- request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
+ request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
instance);
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
num_a2091++;
@@ -217,7 +217,7 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
return num_a2091;
}
-static int a2091_bus_reset(Scsi_Cmnd *cmd)
+static int a2091_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
index 22d6a13dd8b..fe809bc88d7 100644
--- a/drivers/scsi/a2091.h
+++ b/drivers/scsi/a2091.h
@@ -13,10 +13,6 @@
int a2091_detect(struct scsi_host_template *);
int a2091_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index f425d424bf0..7bf46d40b56 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -44,7 +44,7 @@ static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
return IRQ_NONE;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -110,8 +110,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
- int status)
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
{
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD;
@@ -190,7 +190,7 @@ int __init a3000_detect(struct scsi_host_template *tpnt)
regs.SASR = &(DMA(a3000_host)->SASR);
regs.SCMD = &(DMA(a3000_host)->SCMD);
wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
- if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, SA_SHIRQ, "A3000 SCSI",
+ if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
a3000_intr))
goto fail_irq;
DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
@@ -205,7 +205,7 @@ fail_register:
return 0;
}
-static int a3000_bus_reset(Scsi_Cmnd *cmd)
+static int a3000_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
index 5535a65150a..44a4ec7b465 100644
--- a/drivers/scsi/a3000.h
+++ b/drivers/scsi/a3000.h
@@ -13,10 +13,6 @@
int a3000_detect(struct scsi_host_template *);
int a3000_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 83b5c7d085f..ac108f9e267 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -169,13 +169,17 @@ MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control block
int acbsize = -1;
module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+
+int expose_physicals = 0;
+module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on");
/**
* aac_get_config_status - check the adapter configuration
* @common: adapter to query
*
* Query config status, and commit the configuration if needed.
*/
-int aac_get_config_status(struct aac_dev *dev)
+int aac_get_config_status(struct aac_dev *dev, int commit_flag)
{
int status = 0;
struct fib * fibptr;
@@ -219,7 +223,7 @@ int aac_get_config_status(struct aac_dev *dev)
aac_fib_complete(fibptr);
/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
if (status >= 0) {
- if (commit == 1) {
+ if ((commit == 1) || commit_flag) {
struct aac_commit_config * dinfo;
aac_fib_init(fibptr);
dinfo = (struct aac_commit_config *) fib_data(fibptr);
@@ -489,6 +493,8 @@ int aac_probe_container(struct aac_dev *dev, int cid)
unsigned instance;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -ENOMEM;
instance = dev->scsi_host_ptr->unique_id;
if (!(fibptr = aac_fib_alloc(dev)))
@@ -782,8 +788,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
}
- tmp = le32_to_cpu(dev->adapter_info.kernelrev);
- printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
+ if (!dev->in_reset) {
+ tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+ printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
dev->name,
dev->id,
tmp>>24,
@@ -792,20 +799,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
le32_to_cpu(dev->adapter_info.kernelbuild),
(int)sizeof(dev->supplement_adapter_info.BuildDate),
dev->supplement_adapter_info.BuildDate);
- tmp = le32_to_cpu(dev->adapter_info.monitorrev);
- printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
+ tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+ printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.monitorbuild));
- tmp = le32_to_cpu(dev->adapter_info.biosrev);
- printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
+ tmp = le32_to_cpu(dev->adapter_info.biosrev);
+ printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.biosbuild));
- if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- printk(KERN_INFO "%s%d: serial %x\n",
- dev->name, dev->id,
- le32_to_cpu(dev->adapter_info.serial[0]));
+ if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+ printk(KERN_INFO "%s%d: serial %x\n",
+ dev->name, dev->id,
+ le32_to_cpu(dev->adapter_info.serial[0]));
+ }
dev->nondasd_support = 0;
dev->raid_scsi_mode = 0;
@@ -1392,6 +1400,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
struct scsi_cmnd *cmd;
struct scsi_device *sdev = scsicmd->device;
int active = 0;
+ struct aac_dev *aac;
unsigned long flags;
/*
@@ -1413,11 +1422,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
if (active)
return SCSI_MLQUEUE_DEVICE_BUSY;
+ aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+ if (aac->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
/*
* Allocate and initialize a Fib
*/
- if (!(cmd_fibcontext =
- aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata)))
+ if (!(cmd_fibcontext = aac_fib_alloc(aac)))
return SCSI_MLQUEUE_HOST_BUSY;
aac_fib_init(cmd_fibcontext);
@@ -1470,6 +1482,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
+ if (fsa_dev_ptr == NULL)
+ return -1;
/*
* If the bus, id or lun is out of range, return fail
* Test does not apply to ID 16, the pseudo id for the controller
@@ -1499,6 +1513,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case INQUIRY:
case READ_CAPACITY:
case TEST_UNIT_READY:
+ if (dev->in_reset)
+ return -1;
spin_unlock_irq(host->host_lock);
aac_probe_container(dev, cid);
if ((fsa_dev_ptr[cid].valid & 1) == 0)
@@ -1523,7 +1539,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
return 0;
}
} else { /* check for physical non-dasd devices */
- if(dev->nondasd_support == 1){
+ if ((dev->nondasd_support == 1) || expose_physicals) {
+ if (dev->in_reset)
+ return -1;
return aac_send_srb_fib(scsicmd);
} else {
scsicmd->result = DID_NO_CONNECT << 16;
@@ -1579,6 +1597,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsicmd->scsi_done(scsicmd);
return 0;
}
+ if (dev->in_reset)
+ return -1;
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
@@ -1734,6 +1754,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case READ_10:
case READ_12:
case READ_16:
+ if (dev->in_reset)
+ return -1;
/*
* Hack to keep track of ordinal number of the device that
* corresponds to a container. Needed to convert
@@ -1752,6 +1774,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case WRITE_10:
case WRITE_12:
case WRITE_16:
+ if (dev->in_reset)
+ return -1;
return aac_write(scsicmd, cid);
case SYNCHRONIZE_CACHE:
@@ -1782,6 +1806,8 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
return -EFAULT;
if (qd.cnum == -1)
@@ -1820,6 +1846,8 @@ static int force_delete_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
return -EFAULT;
@@ -1843,6 +1871,8 @@ static int delete_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
return -EFAULT;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index d0eecd4bec8..eb3ed91bac7 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -494,6 +494,7 @@ struct adapter_ops
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
int (*adapter_send)(struct fib * fib);
+ int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
};
/*
@@ -682,14 +683,6 @@ struct rx_inbound {
__le32 Mailbox[8];
};
-#define InboundMailbox0 IndexRegs.Mailbox[0]
-#define InboundMailbox1 IndexRegs.Mailbox[1]
-#define InboundMailbox2 IndexRegs.Mailbox[2]
-#define InboundMailbox3 IndexRegs.Mailbox[3]
-#define InboundMailbox4 IndexRegs.Mailbox[4]
-#define InboundMailbox5 IndexRegs.Mailbox[5]
-#define InboundMailbox6 IndexRegs.Mailbox[6]
-
#define INBOUNDDOORBELL_0 0x00000001
#define INBOUNDDOORBELL_1 0x00000002
#define INBOUNDDOORBELL_2 0x00000004
@@ -1010,6 +1003,8 @@ struct aac_dev
struct rx_registers __iomem *rx;
struct rkt_registers __iomem *rkt;
} regs;
+ volatile void __iomem *base;
+ volatile struct rx_inbound __iomem *IndexRegs;
u32 OIMR; /* Mask Register Cache */
/*
* AIF thread states
@@ -1029,6 +1024,7 @@ struct aac_dev
init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
u8 raw_io_64;
u8 printf_enabled;
+ u8 in_reset;
};
#define aac_adapter_interrupt(dev) \
@@ -1049,6 +1045,9 @@ struct aac_dev
#define aac_adapter_send(fib) \
((fib)->dev)->a_ops.adapter_send(fib)
+#define aac_adapter_ioremap(dev, size) \
+ (dev)->a_ops.adapter_ioremap(dev, size)
+
#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
/*
@@ -1524,7 +1523,6 @@ struct aac_get_name {
__le32 count; /* sizeof(((struct aac_get_name_resp *)NULL)->data) */
};
-#define CT_OK 218
struct aac_get_name_resp {
__le32 dummy0;
__le32 dummy1;
@@ -1670,6 +1668,7 @@ extern struct aac_common aac_config;
#define RCV_TEMP_READINGS 0x00000025
#define GET_COMM_PREFERRED_SETTINGS 0x00000026
#define IOP_RESET 0x00001000
+#define IOP_RESET_ALWAYS 0x00001001
#define RE_INIT_ADAPTER 0x000000ee
/*
@@ -1788,7 +1787,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
-int aac_get_config_status(struct aac_dev *dev);
+int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
@@ -1799,6 +1798,7 @@ int aac_sa_init(struct aac_dev *dev);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 255421de9d1..da1d3a9212f 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -38,7 +38,7 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
+#include <linux/delay.h> /* ssleep prototype */
#include <linux/kthread.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -140,7 +140,8 @@ cleanup:
fibptr->hw_fib_pa = hw_fib_pa;
fibptr->hw_fib = hw_fib;
}
- aac_fib_free(fibptr);
+ if (retval != -EINTR)
+ aac_fib_free(fibptr);
return retval;
}
@@ -297,7 +298,7 @@ return_fib:
spin_unlock_irqrestore(&dev->fib_lock, flags);
/* If someone killed the AIF aacraid thread, restart it */
status = !dev->aif_thread;
- if (status && dev->queues && dev->fsa_dev) {
+ if (status && !dev->in_reset && dev->queues && dev->fsa_dev) {
/* Be paranoid, be very paranoid! */
kthread_stop(dev->thread);
ssleep(1);
@@ -621,7 +622,13 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
+ dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+ "Raw SRB command calculated fibsize=%d "
+ "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
+ "issued fibsize=%d\n",
+ actual_fibsize, user_srbcmd->sg.count,
+ sizeof(struct aac_srb), sizeof(struct sgentry),
+ fibsize));
rcode = -EINVAL;
goto cleanup;
}
@@ -663,6 +670,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
}
+ if (status == -EINTR) {
+ rcode = -EINTR;
+ goto cleanup;
+ }
if (status != 0){
dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
@@ -696,8 +707,10 @@ cleanup:
for(i=0; i <= sg_indx; i++){
kfree(sg_list[i]);
}
- aac_fib_complete(srbfib);
- aac_fib_free(srbfib);
+ if (rcode != -EINTR) {
+ aac_fib_complete(srbfib);
+ aac_fib_free(srbfib);
+ }
return rcode;
}
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 35b0a6ebd3f..d5cf8b91a0e 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -92,28 +92,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
init->AdapterFibsSize = cpu_to_le32(fibsize);
init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
- /*
- * number of 4k pages of host physical memory. The aacraid fw needs
- * this number to be less than 4gb worth of pages. num_physpages is in
- * system page units. New firmware doesn't have any issues with the
- * mapping system, but older Firmware did, and had *troubles* dealing
- * with the math overloading past 32 bits, thus we must limit this
- * field.
- *
- * This assumes the memory is mapped zero->n, which isnt
- * always true on real computers. It also has some slight problems
- * with the GART on x86-64. I've btw never tried DMA from PCI space
- * on this platform but don't be surprised if its problematic.
- */
-#ifndef CONFIG_GART_IOMMU
- if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
- init->HostPhysMemPages =
- cpu_to_le32(num_physpages << (PAGE_SHIFT-12));
- } else
-#endif
- {
- init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
- }
+ init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
init->InitFlags = 0;
if (dev->new_comm_interface) {
@@ -201,7 +180,7 @@ int aac_send_shutdown(struct aac_dev * dev)
-2 /* Timeout silently */, 1,
NULL, NULL);
- if (status == 0)
+ if (status >= 0)
aac_fib_complete(fibctx);
aac_fib_free(fibctx);
return status;
@@ -328,17 +307,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
if (status[1] & AAC_OPT_NEW_COMM)
dev->new_comm_interface = dev->a_ops.adapter_send != 0;
if (dev->new_comm_interface && (status[2] > dev->base_size)) {
- iounmap(dev->regs.sa);
+ aac_adapter_ioremap(dev, 0);
dev->base_size = status[2];
- dprintk((KERN_DEBUG "ioremap(%lx,%d)\n",
- host->base, status[2]));
- dev->regs.sa = ioremap(host->base, status[2]);
- if (dev->regs.sa == NULL) {
+ if (aac_adapter_ioremap(dev, status[2])) {
/* remap failed, go back ... */
dev->new_comm_interface = 0;
- dev->regs.sa = ioremap(host->base,
- AAC_MIN_FOOTPRINT_SIZE);
- if (dev->regs.sa == NULL) {
+ if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) {
printk(KERN_WARNING
"aacraid: unable to map adapter.\n");
return NULL;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 3f27419c66a..19e42ac07cb 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -40,8 +40,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
#include <asm/semaphore.h>
#include "aacraid.h"
@@ -464,6 +467,8 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
+ if (!dev->queues)
+ return -EBUSY;
q = &dev->queues->queue[AdapNormCmdQueue];
if(wait)
@@ -527,8 +532,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else
- down(&fibptr->event_wait);
+ } else if (down_interruptible(&fibptr->event_wait)) {
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 0) {
+ fibptr->done = 2; /* Tell interrupt we aborted */
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return -EINTR;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ }
BUG_ON(fibptr->done == 0);
if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
@@ -795,7 +807,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
/* Sniff for container changes */
- if (!dev)
+ if (!dev || !dev->fsa_dev)
return;
container = (u32)-1;
@@ -1022,13 +1034,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (device) {
switch (device_config_needed) {
case DELETE:
- scsi_remove_device(device);
- break;
case CHANGE:
- if (!dev->fsa_dev[container].valid) {
- scsi_remove_device(device);
- break;
- }
scsi_rescan_device(&device->sdev_gendev);
default:
@@ -1045,6 +1051,262 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
+static int _aac_reset_adapter(struct aac_dev *aac)
+{
+ int index, quirks;
+ u32 ret;
+ int retval;
+ struct Scsi_Host *host;
+ struct scsi_device *dev;
+ struct scsi_cmnd *command;
+ struct scsi_cmnd *command_list;
+
+ /*
+ * Assumptions:
+ * - host is locked.
+ * - in_reset is asserted, so no new i/o is getting to the
+ * card.
+ * - The card is dead.
+ */
+ host = aac->scsi_host_ptr;
+ scsi_block_requests(host);
+ aac_adapter_disable_int(aac);
+ spin_unlock_irq(host->host_lock);
+ kthread_stop(aac->thread);
+
+ /*
+ * If a positive health, means in a known DEAD PANIC
+ * state and the adapter could be reset to `try again'.
+ */
+ retval = aac_adapter_check_health(aac);
+ if (retval == 0)
+ retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+ if (retval)
+ retval = aac_adapter_sync_cmd(aac, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+
+ if (retval)
+ goto out;
+ if (ret != 0x00000001) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ index = aac->cardtype;
+
+ /*
+ * Re-initialize the adapter, first free resources, then carefully
+ * apply the initialization sequence to come back again. Only risk
+ * is a change in Firmware dropping cache, it is assumed the caller
+ * will ensure that i/o is queisced and the card is flushed in that
+ * case.
+ */
+ aac_fib_map_free(aac);
+ aac->hw_fib_va = NULL;
+ aac->hw_fib_pa = 0;
+ pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+ aac->comm_addr = NULL;
+ aac->comm_phys = 0;
+ kfree(aac->queues);
+ aac->queues = NULL;
+ free_irq(aac->pdev->irq, aac);
+ kfree(aac->fsa_dev);
+ aac->fsa_dev = NULL;
+ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+ goto out;
+ } else {
+ if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+ goto out;
+ }
+ if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
+ goto out;
+ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
+ if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
+ goto out;
+ aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+ if (IS_ERR(aac->thread)) {
+ retval = PTR_ERR(aac->thread);
+ goto out;
+ }
+ (void)aac_get_adapter_info(aac);
+ quirks = aac_get_driver_ident(index)->quirks;
+ if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
+ host->sg_tablesize = 34;
+ host->max_sectors = (host->sg_tablesize * 8) + 112;
+ }
+ if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
+ host->sg_tablesize = 17;
+ host->max_sectors = (host->sg_tablesize * 8) + 112;
+ }
+ aac_get_config_status(aac, 1);
+ aac_get_containers(aac);
+ /*
+ * This is where the assumption that the Adapter is quiesced
+ * is important.
+ */
+ command_list = NULL;
+ __shost_for_each_device(dev, host) {
+ unsigned long flags;
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_for_each_entry(command, &dev->cmd_list, list)
+ if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+ command->SCp.buffer = (struct scatterlist *)command_list;
+ command_list = command;
+ }
+ spin_unlock_irqrestore(&dev->list_lock, flags);
+ }
+ while ((command = command_list)) {
+ command_list = (struct scsi_cmnd *)command->SCp.buffer;
+ command->SCp.buffer = NULL;
+ command->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8
+ | SAM_STAT_TASK_SET_FULL;
+ command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ command->scsi_done(command);
+ }
+ retval = 0;
+
+out:
+ aac->in_reset = 0;
+ scsi_unblock_requests(host);
+ spin_lock_irq(host->host_lock);
+ return retval;
+}
+
+int aac_check_health(struct aac_dev * aac)
+{
+ int BlinkLED;
+ unsigned long time_now, flagv = 0;
+ struct list_head * entry;
+ struct Scsi_Host * host;
+
+ /* Extending the scope of fib_lock slightly to protect aac->in_reset */
+ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+ return 0;
+
+ if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) {
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+ return 0; /* OK */
+ }
+
+ aac->in_reset = 1;
+
+ /* Fake up an AIF:
+ * aac_aifcmd.command = AifCmdEventNotify = 1
+ * aac_aifcmd.seqnum = 0xFFFFFFFF
+ * aac_aifcmd.data[0] = AifEnExpEvent = 23
+ * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3
+ * aac.aifcmd.data[2] = AifHighPriority = 3
+ * aac.aifcmd.data[3] = BlinkLED
+ */
+
+ time_now = jiffies/HZ;
+ entry = aac->fib_list.next;
+
+ /*
+ * For each Context that is on the
+ * fibctxList, make a copy of the
+ * fib, and then set the event to wake up the
+ * thread that is waiting for it.
+ */
+ while (entry != &aac->fib_list) {
+ /*
+ * Extract the fibctx
+ */
+ struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next);
+ struct hw_fib * hw_fib;
+ struct fib * fib;
+ /*
+ * Check if the queue is getting
+ * backlogged
+ */
+ if (fibctx->count > 20) {
+ /*
+ * It's *not* jiffies folks,
+ * but jiffies / HZ, so do not
+ * panic ...
+ */
+ u32 time_last = fibctx->jiffies;
+ /*
+ * Has it been > 2 minutes
+ * since the last read off
+ * the queue?
+ */
+ if ((time_now - time_last) > aif_timeout) {
+ entry = entry->next;
+ aac_close_fib_context(aac, fibctx);
+ continue;
+ }
+ }
+ /*
+ * Warning: no sleep allowed while
+ * holding spinlock
+ */
+ hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+ fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+ if (fib && hw_fib) {
+ struct aac_aifcmd * aif;
+
+ memset(hw_fib, 0, sizeof(struct hw_fib));
+ memset(fib, 0, sizeof(struct fib));
+ fib->hw_fib = hw_fib;
+ fib->dev = aac;
+ aac_fib_init(fib);
+ fib->type = FSAFS_NTC_FIB_CONTEXT;
+ fib->size = sizeof (struct fib);
+ fib->data = hw_fib->data;
+ aif = (struct aac_aifcmd *)hw_fib->data;
+ aif->command = cpu_to_le32(AifCmdEventNotify);
+ aif->seqnum = cpu_to_le32(0xFFFFFFFF);
+ aif->data[0] = cpu_to_le32(AifEnExpEvent);
+ aif->data[1] = cpu_to_le32(AifExeFirmwarePanic);
+ aif->data[2] = cpu_to_le32(AifHighPriority);
+ aif->data[3] = cpu_to_le32(BlinkLED);
+
+ /*
+ * Put the FIB onto the
+ * fibctx's fibs
+ */
+ list_add_tail(&fib->fiblink, &fibctx->fib_list);
+ fibctx->count++;
+ /*
+ * Set the event to wake up the
+ * thread that will waiting.
+ */
+ up(&fibctx->wait_sem);
+ } else {
+ printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+ kfree(fib);
+ kfree(hw_fib);
+ }
+ entry = entry->next;
+ }
+
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+ if (BlinkLED < 0) {
+ printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED);
+ goto out;
+ }
+
+ printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+
+ host = aac->scsi_host_ptr;
+ spin_lock_irqsave(host->host_lock, flagv);
+ BlinkLED = _aac_reset_adapter(aac);
+ spin_unlock_irqrestore(host->host_lock, flagv);
+ return BlinkLED;
+
+out:
+ aac->in_reset = 0;
+ return BlinkLED;
+}
+
+
/**
* aac_command_thread - command processing thread
* @dev: Adapter to monitor
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index b2a5c7262f3..8335f07b772 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -124,10 +124,15 @@ unsigned int aac_response_normal(struct aac_queue * q)
} else {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
+ if (!fib->done)
+ fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+ if (fib->done == 2) {
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ }
}
consumed++;
spin_lock_irqsave(q->lock, flags);
@@ -316,7 +321,8 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n"));
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
+ if (!fib->done)
+ fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index e42a479ce64..359e7ddfdb4 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -82,6 +82,8 @@ static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
+extern int expose_physicals;
+
/*
* Because of the way Linux names scsi devices, the order in this table has
* become important. Check for on-board Raid first, add-in cards second.
@@ -394,6 +396,7 @@ static int aac_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_3f = 1;
}
if ((sdev->type == TYPE_DISK) &&
+ !expose_physicals &&
(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
@@ -454,17 +457,17 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
AAC_DRIVERNAME);
aac = (struct aac_dev *)host->hostdata;
- if (aac_adapter_check_health(aac)) {
- printk(KERN_ERR "%s: Host adapter appears dead\n",
- AAC_DRIVERNAME);
- return -ENODEV;
- }
+
+ if ((count = aac_check_health(aac)))
+ return count;
/*
* Wait for all commands to complete to this specific
* target (block maximum 60 seconds).
*/
for (count = 60; count; --count) {
- int active = 0;
+ int active = aac->in_reset;
+
+ if (active == 0)
__shost_for_each_device(dev, host) {
spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(command, &dev->cmd_list, list) {
@@ -864,13 +867,6 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* Map in the registers from the adapter.
*/
aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
- if ((aac->regs.sa = ioremap(
- (unsigned long)aac->scsi_host_ptr->base, AAC_MIN_FOOTPRINT_SIZE))
- == NULL) {
- printk(KERN_WARNING "%s: unable to map adapter.\n",
- AAC_DRIVERNAME);
- goto out_free_fibs;
- }
if ((*aac_drivers[index].init)(aac))
goto out_unmap;
@@ -928,12 +924,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
* physical channels are address by their actual physical number+1
*/
- if (aac->nondasd_support == 1)
+ if ((aac->nondasd_support == 1) || expose_physicals)
shost->max_channel = aac->maximum_num_channels;
else
shost->max_channel = 0;
- aac_get_config_status(aac);
+ aac_get_config_status(aac, 0);
aac_get_containers(aac);
list_add(&aac->entry, insert);
@@ -969,8 +965,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
aac_fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
kfree(aac->queues);
- iounmap(aac->regs.sa);
- out_free_fibs:
+ aac_adapter_ioremap(aac, 0);
kfree(aac->fibs);
kfree(aac->fsa_dev);
out_free_host:
@@ -1005,7 +1000,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
kfree(aac->queues);
free_irq(pdev->irq, aac);
- iounmap(aac->regs.sa);
+ aac_adapter_ioremap(aac, 0);
kfree(aac->fibs);
kfree(aac->fsa_dev);
@@ -1013,6 +1008,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
list_del(&aac->entry);
scsi_host_put(shost);
pci_disable_device(pdev);
+ if (list_empty(&aac_devices)) {
+ unregister_chrdev(aac_cfg_major, "aac");
+ aac_cfg_major = -1;
+ }
}
static struct pci_driver aac_pci_driver = {
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 5b52966bbbf..643f23b5ded 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -28,370 +28,27 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <asm/semaphore.h>
#include <scsi/scsi_host.h>
#include "aacraid.h"
-static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct aac_dev *dev = dev_id;
-
- if (dev->new_comm_interface) {
- u32 Index = rkt_readl(dev, MUnit.OutboundQueue);
- if (Index == 0xFFFFFFFFL)
- Index = rkt_readl(dev, MUnit.OutboundQueue);
- if (Index != 0xFFFFFFFFL) {
- do {
- if (aac_intr_normal(dev, Index)) {
- rkt_writel(dev, MUnit.OutboundQueue, Index);
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
- }
- Index = rkt_readl(dev, MUnit.OutboundQueue);
- } while (Index != 0xFFFFFFFFL);
- return IRQ_HANDLED;
- }
- } else {
- unsigned long bellbits;
- u8 intstat;
- intstat = rkt_readb(dev, MUnit.OISR);
- /*
- * Read mask and invert because drawbridge is reversed.
- * This allows us to only service interrupts that have
- * been enabled.
- * Check to see if this is our interrupt. If it isn't just return
- */
- if (intstat & ~(dev->OIMR))
- {
- bellbits = rkt_readl(dev, OutboundDoorbellReg);
- if (bellbits & DoorBellPrintfReady) {
- aac_printf(dev, rkt_readl (dev, IndexRegs.Mailbox[5]));
- rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
- rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
- }
- else if (bellbits & DoorBellAdapterNormCmdReady) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
- aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
-// rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
- }
- else if (bellbits & DoorBellAdapterNormRespReady) {
- rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
- aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
- }
- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- }
- else if (bellbits & DoorBellAdapterNormRespNotFull) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
- }
- return IRQ_HANDLED;
- }
- }
- return IRQ_NONE;
-}
-
-/**
- * aac_rkt_disable_interrupt - Disable interrupts
- * @dev: Adapter
- */
-
-static void aac_rkt_disable_interrupt(struct aac_dev *dev)
-{
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
-}
-
/**
- * rkt_sync_cmd - send a command and wait
- * @dev: Adapter
- * @command: Command to execute
- * @p1: first parameter
- * @ret: adapter status
+ * aac_rkt_ioremap
+ * @size: mapping resize request
*
- * This routine will send a synchronous command to the adapter and wait
- * for its completion.
*/
-
-static int rkt_sync_cmd(struct aac_dev *dev, u32 command,
- u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
- u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
+static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
{
- unsigned long start;
- int ok;
- /*
- * Write the command into Mailbox 0
- */
- rkt_writel(dev, InboundMailbox0, command);
- /*
- * Write the parameters into Mailboxes 1 - 6
- */
- rkt_writel(dev, InboundMailbox1, p1);
- rkt_writel(dev, InboundMailbox2, p2);
- rkt_writel(dev, InboundMailbox3, p3);
- rkt_writel(dev, InboundMailbox4, p4);
- /*
- * Clear the synch command doorbell to start on a clean slate.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- /*
- * Disable doorbell interrupts
- */
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
- /*
- * Force the completion of the mask register write before issuing
- * the interrupt.
- */
- rkt_readb (dev, MUnit.OIMR);
- /*
- * Signal that there is a new synch command
- */
- rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
-
- ok = 0;
- start = jiffies;
-
- /*
- * Wait up to 30 seconds
- */
- while (time_before(jiffies, start+30*HZ))
- {
- udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
- /*
- * Mon960 will set doorbell0 bit when it has completed the command.
- */
- if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
- /*
- * Clear the doorbell.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- ok = 1;
- break;
- }
- /*
- * Yield the processor in case we are slow
- */
- msleep(1);
+ if (!size) {
+ iounmap(dev->regs.rkt);
+ return 0;
}
- if (ok != 1) {
- /*
- * Restore interrupt mask even though we timed out
- */
- if (dev->new_comm_interface)
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
- return -ETIMEDOUT;
- }
- /*
- * Pull the synch status from Mailbox 0.
- */
- if (status)
- *status = rkt_readl(dev, IndexRegs.Mailbox[0]);
- if (r1)
- *r1 = rkt_readl(dev, IndexRegs.Mailbox[1]);
- if (r2)
- *r2 = rkt_readl(dev, IndexRegs.Mailbox[2]);
- if (r3)
- *r3 = rkt_readl(dev, IndexRegs.Mailbox[3]);
- if (r4)
- *r4 = rkt_readl(dev, IndexRegs.Mailbox[4]);
- /*
- * Clear the synch command doorbell.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- /*
- * Restore interrupt mask
- */
- if (dev->new_comm_interface)
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
- return 0;
-
-}
-
-/**
- * aac_rkt_interrupt_adapter - interrupt adapter
- * @dev: Adapter
- *
- * Send an interrupt to the i960 and breakpoint it.
- */
-
-static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
-{
- rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL, NULL);
-}
-
-/**
- * aac_rkt_notify_adapter - send an event to the adapter
- * @dev: Adapter
- * @event: Event to send
- *
- * Notify the i960 that something it probably cares about has
- * happened.
- */
-
-static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
-{
- switch (event) {
-
- case AdapNormCmdQue:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
- break;
- case HostNormRespNotFull:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
- break;
- case AdapNormRespQue:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
- break;
- case HostNormCmdNotFull:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
- break;
- case HostShutdown:
-// rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
-// NULL, NULL, NULL, NULL, NULL);
- break;
- case FastIo:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
- break;
- case AdapPrintfDone:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
- break;
- default:
- BUG();
- break;
- }
-}
-
-/**
- * aac_rkt_start_adapter - activate adapter
- * @dev: Adapter
- *
- * Start up processing on an i960 based AAC adapter
- */
-
-static void aac_rkt_start_adapter(struct aac_dev *dev)
-{
- struct aac_init *init;
-
- init = dev->init;
- init->HostElapsedSeconds = cpu_to_le32(get_seconds());
- // We can only use a 32 bit address here
- rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
- 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
-}
-
-/**
- * aac_rkt_check_health
- * @dev: device to check if healthy
- *
- * Will attempt to determine if the specified adapter is alive and
- * capable of handling requests, returning 0 if alive.
- */
-static int aac_rkt_check_health(struct aac_dev *dev)
-{
- u32 status = rkt_readl(dev, MUnit.OMRx[0]);
-
- /*
- * Check to see if the board failed any self tests.
- */
- if (status & SELF_TEST_FAILED)
+ dev->base = dev->regs.rkt = ioremap(dev->scsi_host_ptr->base, size);
+ if (dev->base == NULL)
return -1;
- /*
- * Check to see if the board panic'd.
- */
- if (status & KERNEL_PANIC) {
- char * buffer;
- struct POSTSTATUS {
- __le32 Post_Command;
- __le32 Post_Address;
- } * post;
- dma_addr_t paddr, baddr;
- int ret;
-
- if ((status & 0xFF000000L) == 0xBC000000L)
- return (status >> 16) & 0xFF;
- buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
- ret = -2;
- if (buffer == NULL)
- return ret;
- post = pci_alloc_consistent(dev->pdev,
- sizeof(struct POSTSTATUS), &paddr);
- if (post == NULL) {
- pci_free_consistent(dev->pdev, 512, buffer, baddr);
- return ret;
- }
- memset(buffer, 0, 512);
- post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
- post->Post_Address = cpu_to_le32(baddr);
- rkt_writel(dev, MUnit.IMRx[0], paddr);
- rkt_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL, NULL);
- pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
- post, paddr);
- if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
- ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
- ret <<= 4;
- ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
- }
- pci_free_consistent(dev->pdev, 512, buffer, baddr);
- return ret;
- }
- /*
- * Wait for the adapter to be up and running.
- */
- if (!(status & KERNEL_UP_AND_RUNNING))
- return -3;
- /*
- * Everything is OK
- */
- return 0;
-}
-
-/**
- * aac_rkt_send
- * @fib: fib to issue
- *
- * Will send a fib, returning 0 if successful.
- */
-static int aac_rkt_send(struct fib * fib)
-{
- u64 addr = fib->hw_fib_pa;
- struct aac_dev *dev = fib->dev;
- volatile void __iomem *device = dev->regs.rkt;
- u32 Index;
-
- dprintk((KERN_DEBUG "%p->aac_rkt_send(%p->%llx)\n", dev, fib, addr));
- Index = rkt_readl(dev, MUnit.InboundQueue);
- if (Index == 0xFFFFFFFFL)
- Index = rkt_readl(dev, MUnit.InboundQueue);
- dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
- if (Index == 0xFFFFFFFFL)
- return Index;
- device += Index;
- dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
- (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
- writel((u32)(addr & 0xffffffff), device);
- device += sizeof(u32);
- writel((u32)(addr >> 32), device);
- device += sizeof(u32);
- writel(le16_to_cpu(fib->hw_fib->header.Size), device);
- rkt_writel(dev, MUnit.InboundQueue, Index);
- dprintk((KERN_DEBUG "aac_rkt_send - return 0\n"));
+ dev->IndexRegs = &dev->regs.rkt->IndexRegs;
return 0;
}
@@ -406,78 +63,18 @@ static int aac_rkt_send(struct fib * fib)
int aac_rkt_init(struct aac_dev *dev)
{
- unsigned long start;
- unsigned long status;
- int instance;
- const char * name;
-
- instance = dev->id;
- name = dev->name;
+ int retval;
+ extern int _aac_rx_init(struct aac_dev *dev);
+ extern void aac_rx_start_adapter(struct aac_dev *dev);
/*
- * Check to see if the board panic'd while booting.
- */
- /*
- * Check to see if the board failed any self tests.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
- printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
- * Check to see if the monitor panic'd while booting.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
- printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
- * Check to see if the board panic'd while booting.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
- printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
- goto error_iounmap;
- }
- start = jiffies;
- /*
- * Wait for the adapter to be up and running. Wait up to 3 minutes
- */
- while (!(rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING))
- {
- if(time_after(jiffies, start+startup_timeout*HZ))
- {
- status = rkt_readl(dev, MUnit.OMRx[0]);
- printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
- dev->name, instance, status);
- goto error_iounmap;
- }
- msleep(1);
- }
- if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0)
- {
- printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
- goto error_iounmap;
- }
- /*
* Fill in the function dispatch table.
*/
- dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
- dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
- dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
- dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
- dev->a_ops.adapter_check_health = aac_rkt_check_health;
- dev->a_ops.adapter_send = aac_rkt_send;
-
- /*
- * First clear out all interrupts. Then enable the one's that we
- * can handle.
- */
- rkt_writeb(dev, MUnit.OIMR, 0xff);
- rkt_writel(dev, MUnit.ODR, 0xffffffff);
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+ dev->a_ops.adapter_ioremap = aac_rkt_ioremap;
- if (aac_init_adapter(dev) == NULL)
- goto error_irq;
+ retval = _aac_rx_init(dev);
+ if (retval)
+ return retval;
if (dev->new_comm_interface) {
/*
* FIB Setup has already been done, but we can minimize the
@@ -494,20 +91,11 @@ int aac_rkt_init(struct aac_dev *dev)
dev->init->MaxIoCommands = cpu_to_le32(246);
dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB;
}
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
}
/*
* Tell the adapter that all is configured, and it can start
* accepting requests
*/
- aac_rkt_start_adapter(dev);
+ aac_rx_start_adapter(dev);
return 0;
-
-error_irq:
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
- free_irq(dev->scsi_host_ptr->irq, (void *)dev);
-
-error_iounmap:
-
- return -1;
}
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 9dadfb28b3f..a1d214d770e 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -79,7 +79,7 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
{
bellbits = rx_readl(dev, OutboundDoorbellReg);
if (bellbits & DoorBellPrintfReady) {
- aac_printf(dev, rx_readl (dev, IndexRegs.Mailbox[5]));
+ aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
@@ -134,14 +134,14 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
/*
* Write the command into Mailbox 0
*/
- rx_writel(dev, InboundMailbox0, command);
+ writel(command, &dev->IndexRegs->Mailbox[0]);
/*
* Write the parameters into Mailboxes 1 - 6
*/
- rx_writel(dev, InboundMailbox1, p1);
- rx_writel(dev, InboundMailbox2, p2);
- rx_writel(dev, InboundMailbox3, p3);
- rx_writel(dev, InboundMailbox4, p4);
+ writel(p1, &dev->IndexRegs->Mailbox[1]);
+ writel(p2, &dev->IndexRegs->Mailbox[2]);
+ writel(p3, &dev->IndexRegs->Mailbox[3]);
+ writel(p4, &dev->IndexRegs->Mailbox[4]);
/*
* Clear the synch command doorbell to start on a clean slate.
*/
@@ -199,15 +199,15 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
* Pull the synch status from Mailbox 0.
*/
if (status)
- *status = rx_readl(dev, IndexRegs.Mailbox[0]);
+ *status = readl(&dev->IndexRegs->Mailbox[0]);
if (r1)
- *r1 = rx_readl(dev, IndexRegs.Mailbox[1]);
+ *r1 = readl(&dev->IndexRegs->Mailbox[1]);
if (r2)
- *r2 = rx_readl(dev, IndexRegs.Mailbox[2]);
+ *r2 = readl(&dev->IndexRegs->Mailbox[2]);
if (r3)
- *r3 = rx_readl(dev, IndexRegs.Mailbox[3]);
+ *r3 = readl(&dev->IndexRegs->Mailbox[3]);
if (r4)
- *r4 = rx_readl(dev, IndexRegs.Mailbox[4]);
+ *r4 = readl(&dev->IndexRegs->Mailbox[4]);
/*
* Clear the synch command doorbell.
*/
@@ -261,8 +261,6 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
break;
case HostShutdown:
-// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
-// NULL, NULL, NULL, NULL, NULL);
break;
case FastIo:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
@@ -283,7 +281,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
* Start up processing on an i960 based AAC adapter
*/
-static void aac_rx_start_adapter(struct aac_dev *dev)
+void aac_rx_start_adapter(struct aac_dev *dev)
{
struct aac_init *init;
@@ -381,7 +379,7 @@ static int aac_rx_send(struct fib * fib)
dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
if (Index == 0xFFFFFFFFL)
return Index;
- device += Index;
+ device = dev->base + Index;
dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
(u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
writel((u32)(addr & 0xffffffff), device);
@@ -395,6 +393,43 @@ static int aac_rx_send(struct fib * fib)
}
/**
+ * aac_rx_ioremap
+ * @size: mapping resize request
+ *
+ */
+static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
+{
+ if (!size) {
+ iounmap(dev->regs.rx);
+ return 0;
+ }
+ dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size);
+ if (dev->base == NULL)
+ return -1;
+ dev->IndexRegs = &dev->regs.rx->IndexRegs;
+ return 0;
+}
+
+static int aac_rx_restart_adapter(struct aac_dev *dev)
+{
+ u32 var;
+
+ printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
+ dev->name, dev->id);
+
+ if (aac_rx_check_health(dev) <= 0)
+ return 1;
+ if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
+ &var, NULL, NULL, NULL, NULL))
+ return 1;
+ if (var != 0x00000001)
+ return 1;
+ if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
+ return 1;
+ return 0;
+}
+
+/**
* aac_rx_init - initialize an i960 based AAC card
* @dev: device to configure
*
@@ -403,7 +438,7 @@ static int aac_rx_send(struct fib * fib)
* to the comm region.
*/
-int aac_rx_init(struct aac_dev *dev)
+int _aac_rx_init(struct aac_dev *dev)
{
unsigned long start;
unsigned long status;
@@ -413,27 +448,30 @@ int aac_rx_init(struct aac_dev *dev)
instance = dev->id;
name = dev->name;
+ if (aac_adapter_ioremap(dev, dev->base_size)) {
+ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+ goto error_iounmap;
+ }
+
/*
* Check to see if the board panic'd while booting.
*/
+ status = rx_readl(dev, MUnit.OMRx[0]);
+ if (status & KERNEL_PANIC)
+ if (aac_rx_restart_adapter(dev))
+ goto error_iounmap;
/*
* Check to see if the board failed any self tests.
*/
- if (rx_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+ status = rx_readl(dev, MUnit.OMRx[0]);
+ if (status & SELF_TEST_FAILED) {
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
goto error_iounmap;
}
/*
- * Check to see if the board panic'd while booting.
- */
- if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
- printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
* Check to see if the monitor panic'd while booting.
*/
- if (rx_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+ if (status & MONITOR_PANIC) {
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
goto error_iounmap;
}
@@ -441,19 +479,17 @@ int aac_rx_init(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
*/
- while ((!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
- || (!(rx_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING)))
+ while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
{
if(time_after(jiffies, start+startup_timeout*HZ))
{
- status = rx_readl(dev, IndexRegs.Mailbox[7]);
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
dev->name, instance, status);
goto error_iounmap;
}
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0)
+ if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0)
{
printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
goto error_iounmap;
@@ -481,11 +517,6 @@ int aac_rx_init(struct aac_dev *dev)
if (dev->new_comm_interface)
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- /*
- * Tell the adapter that all is configured, and it can start
- * accepting requests
- */
- aac_rx_start_adapter(dev);
return 0;
error_irq:
@@ -496,3 +527,23 @@ error_iounmap:
return -1;
}
+
+int aac_rx_init(struct aac_dev *dev)
+{
+ int retval;
+
+ /*
+ * Fill in the function dispatch table.
+ */
+ dev->a_ops.adapter_ioremap = aac_rx_ioremap;
+
+ retval = _aac_rx_init(dev);
+ if (!retval) {
+ /*
+ * Tell the adapter that all is configured, and it can
+ * start accepting requests
+ */
+ aac_rx_start_adapter(dev);
+ }
+ return retval;
+}
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 88d400fccc9..f906ead239d 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -281,6 +281,21 @@ static int aac_sa_check_health(struct aac_dev *dev)
}
/**
+ * aac_sa_ioremap
+ * @size: mapping resize request
+ *
+ */
+static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
+{
+ if (!size) {
+ iounmap(dev->regs.sa);
+ return 0;
+ }
+ dev->base = dev->regs.sa = ioremap(dev->scsi_host_ptr->base, size);
+ return (dev->base == NULL) ? -1 : 0;
+}
+
+/**
* aac_sa_init - initialize an ARM based AAC card
* @dev: device to configure
*
@@ -299,6 +314,11 @@ int aac_sa_init(struct aac_dev *dev)
instance = dev->id;
name = dev->name;
+ if (aac_sa_ioremap(dev, dev->base_size)) {
+ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+ goto error_iounmap;
+ }
+
/*
* Check to see if the board failed any self tests.
*/
@@ -327,7 +347,7 @@ int aac_sa_init(struct aac_dev *dev)
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
+ if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev ) < 0) {
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
goto error_iounmap;
}
@@ -341,6 +361,7 @@ int aac_sa_init(struct aac_dev *dev)
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
+ dev->a_ops.adapter_ioremap = aac_sa_ioremap;
/*
* First clear out all interrupts. Then enable the one's that
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2a419634b25..773f02e3b10 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -371,7 +371,7 @@
1.5 (8/8/96):
1. Add support for ABP-940U (PCI Ultra) adapter.
- 2. Add support for IRQ sharing by setting the SA_SHIRQ flag for
+ 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
request_irq and supplying a dev_id pointer to both request_irq()
and free_irq().
3. In AscSearchIOPortAddr11() restore a call to check_region() which
@@ -504,9 +504,9 @@
3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
access functions.
4. Update board serial number printing.
- 5. Try allocating an IRQ both with and without the SA_INTERRUPT
+ 5. Try allocating an IRQ both with and without the IRQF_DISABLED
flag set to allow IRQ sharing with drivers that do not set
- the SA_INTERRUPT flag. Also display a more descriptive error
+ the IRQF_DISABLED flag. Also display a more descriptive error
message if request_irq() fails.
6. Update to latest Asc and Adv Libraries.
@@ -754,7 +754,6 @@
* --- Linux Include Files
*/
-#include <linux/config.h>
#include <linux/module.h>
#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
@@ -889,10 +888,6 @@ typedef unsigned char uchar;
#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
-#define ASC_PCI_VENDORID 0x10CD
-#define ASC_PCI_DEVICEID_1200A 0x1100
-#define ASC_PCI_DEVICEID_1200B 0x1200
-#define ASC_PCI_DEVICEID_ULTRA 0x1300
#define ASC_PCI_REVISION_3150 0x02
#define ASC_PCI_REVISION_3050 0x03
@@ -900,6 +895,14 @@ typedef unsigned char uchar;
#define ASC_DVCLIB_CALL_FAILED (0)
#define ASC_DVCLIB_CALL_ERROR (-1)
+#define PCI_VENDOR_ID_ASP 0x10cd
+#define PCI_DEVICE_ID_ASP_1200A 0x1100
+#define PCI_DEVICE_ID_ASP_ABP940 0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
+#define PCI_DEVICE_ID_38C0800_REV1 0x2500
+#define PCI_DEVICE_ID_38C1600_REV1 0x2700
+
/*
* Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
* The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
@@ -1493,8 +1496,6 @@ typedef struct asc_dvc_cfg {
#define ASC_INIT_STATE_END_INQUIRY 0x0080
#define ASC_INIT_RESET_SCSI_DONE 0x0100
#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
-#define ASC_PCI_DEVICE_ID_REV_A 0x1100
-#define ASC_PCI_DEVICE_ID_REV_B 0x1200
#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
@@ -2101,12 +2102,6 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
#define ADV_NUM_PAGE_CROSSING \
((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
-/* a_condor.h */
-#define ADV_PCI_VENDOR_ID 0x10CD
-#define ADV_PCI_DEVICE_ID_REV_A 0x2300
-#define ADV_PCI_DEVID_38C0800_REV1 0x2500
-#define ADV_PCI_DEVID_38C1600_REV1 0x2700
-
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
@@ -3570,14 +3565,7 @@ typedef struct scsi_cmnd REQ, *REQP;
#define PCI_MAX_SLOT 0x1F
#define PCI_MAX_BUS 0xFF
#define PCI_IOADDRESS_MASK 0xFFFE
-#define ASC_PCI_VENDORID 0x10CD
#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
-#define ASC_PCI_DEVICE_ID_1100 0x1100
-#define ASC_PCI_DEVICE_ID_1200 0x1200
-#define ASC_PCI_DEVICE_ID_1300 0x1300
-#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */
-#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */
-#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */
#ifndef ADVANSYS_STATS
#define ASC_STATS(shp, counter)
@@ -4331,12 +4319,12 @@ advansys_detect(struct scsi_host_template *tpnt)
struct pci_dev *pci_devp = NULL;
int pci_device_id_cnt = 0;
unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
- ASC_PCI_DEVICE_ID_1100,
- ASC_PCI_DEVICE_ID_1200,
- ASC_PCI_DEVICE_ID_1300,
- ASC_PCI_DEVICE_ID_2300,
- ASC_PCI_DEVICE_ID_2500,
- ASC_PCI_DEVICE_ID_2700
+ PCI_DEVICE_ID_ASP_1200A,
+ PCI_DEVICE_ID_ASP_ABP940,
+ PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_DEVICE_ID_38C0800_REV1,
+ PCI_DEVICE_ID_38C1600_REV1
};
ADV_PADDR pci_memory_address;
#endif /* CONFIG_PCI */
@@ -4472,7 +4460,7 @@ advansys_detect(struct scsi_host_template *tpnt)
/* Find all PCI cards. */
while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
- if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+ if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
pci_device_id[pci_device_id_cnt], pci_devp)) ==
NULL) {
pci_device_id_cnt++;
@@ -4576,9 +4564,9 @@ advansys_detect(struct scsi_host_template *tpnt)
*/
#ifdef CONFIG_PCI
if (asc_bus[bus] == ASC_IS_PCI &&
- (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
- pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
- pci_devp->device == ASC_PCI_DEVICE_ID_2700))
+ (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+ pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
+ pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
{
boardp->flags |= ASC_IS_WIDE_BOARD;
}
@@ -4601,11 +4589,11 @@ advansys_detect(struct scsi_host_template *tpnt)
adv_dvc_varp->isr_callback = adv_isr_callback;
adv_dvc_varp->async_callback = adv_async_callback;
#ifdef CONFIG_PCI
- if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+ if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
{
ASC_DBG(1, "advansys_detect: ASC-3550\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
- } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
+ } else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
{
ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
@@ -5203,19 +5191,19 @@ advansys_detect(struct scsi_host_template *tpnt)
/* Register IRQ Number. */
ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
/*
- * If request_irq() fails with the SA_INTERRUPT flag set,
- * then try again without the SA_INTERRUPT flag set. This
+ * If request_irq() fails with the IRQF_DISABLED flag set,
+ * then try again without the IRQF_DISABLED flag set. This
* allows IRQ sharing to work even with other drivers that
- * do not set the SA_INTERRUPT flag.
+ * do not set the IRQF_DISABLED flag.
*
- * If SA_INTERRUPT is not set, then interrupts are enabled
+ * If IRQF_DISABLED is not set, then interrupts are enabled
* before the driver interrupt function is called.
*/
if (((ret = request_irq(shp->irq, advansys_interrupt,
- SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+ IRQF_DISABLED | (share_irq == TRUE ? IRQF_SHARED : 0),
"advansys", boardp)) != 0) &&
((ret = request_irq(shp->irq, advansys_interrupt,
- (share_irq == TRUE ? SA_SHIRQ : 0),
+ (share_irq == TRUE ? IRQF_SHARED : 0),
"advansys", boardp)) != 0))
{
if (ret == -EBUSY) {
@@ -11923,7 +11911,7 @@ AscInitGetConfig(
PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigRevisionIDRegister);
- if (PCIVendorID != ASC_PCI_VENDORID) {
+ if (PCIVendorID != PCI_VENDOR_ID_ASP) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
@@ -11943,15 +11931,15 @@ AscInitGetConfig(
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
}
- if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
- (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
+ if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
+ (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
DvcWritePCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer, 0x00);
if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
!= 0x00) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
- } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
+ } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
if (DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer) < 0x20) {
DvcWritePCIConfigByte(asc_dvc,
@@ -12038,8 +12026,8 @@ AscInitFromAscDvcVar(
AscSetChipCfgMsw(iop_base, cfg_msw);
if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
} else {
- if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
- (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
+ if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
+ (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
}
@@ -12374,7 +12362,7 @@ AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
ASC_PRINT1(
"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
} else {
- ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM.");
+ ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
}
}
return (warn_code);
@@ -14276,8 +14264,8 @@ Default_38C0800_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
- ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
@@ -14406,8 +14394,8 @@ Default_38C1600_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
- ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
@@ -17316,7 +17304,7 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
ushort *wbuf;
@@ -17383,7 +17371,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C0800_CONFIG *cfg_buf)
{
@@ -17451,7 +17439,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C1600_CONFIG *cfg_buf)
{
@@ -18226,3 +18214,22 @@ AdvInquiryHandling(
}
}
MODULE_LICENSE("Dual BSD/GPL");
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
+
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index de80cdfb5b9..fb6a476eb87 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -253,6 +253,7 @@
#include <linux/isapnp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/list.h>
#include <asm/semaphore.h>
#include <scsi/scsicam.h>
@@ -262,6 +263,8 @@
#include <scsi/scsi_transport_spi.h>
#include "aha152x.h"
+static LIST_HEAD(aha152x_host_list);
+
/* DEFINES */
@@ -423,8 +426,6 @@ MODULE_DEVICE_TABLE(isapnp, id_table);
#endif /* !PCMCIA */
-static int registered_count=0;
-static struct Scsi_Host *aha152x_host[2];
static struct scsi_host_template aha152x_driver_template;
/*
@@ -541,6 +542,7 @@ struct aha152x_hostdata {
#ifdef __ISAPNP__
struct pnp_dev *pnpdev;
#endif
+ struct list_head host_list;
};
@@ -551,6 +553,11 @@ struct aha152x_hostdata {
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
struct semaphore *sem; /* semaphore to block on */
+ unsigned char cmd_len;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned short use_sg;
+ unsigned request_bufflen;
+ void *request_buffer;
};
@@ -750,20 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
return ptr;
}
-static inline struct Scsi_Host *lookup_irq(int irqno)
-{
- int i;
-
- for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
- if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
- return aha152x_host[i];
-
- return NULL;
-}
-
static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
{
- struct Scsi_Host *shpnt = lookup_irq(irqno);
+ struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
if (!shpnt) {
printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
@@ -786,10 +782,11 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
return NULL;
}
- /* need to have host registered before triggering any interrupt */
- aha152x_host[registered_count] = shpnt;
-
memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
+ INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
+
+ /* need to have host registered before triggering any interrupt */
+ list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
shpnt->io_port = setup->io_port;
shpnt->n_io_port = IO_RANGE;
@@ -855,7 +852,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+ if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -889,7 +886,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+ if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -902,12 +899,10 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
scsi_scan_host(shpnt);
- registered_count++;
-
return shpnt;
out_host_put:
- aha152x_host[registered_count]=NULL;
+ list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
return NULL;
@@ -932,6 +927,7 @@ void aha152x_release(struct Scsi_Host *shpnt)
#endif
scsi_remove_host(shpnt);
+ list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
}
@@ -1006,11 +1002,20 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
return FAILED;
}
} else {
+ struct aha152x_scdata *sc;
+
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
if(SCpnt->host_scribble==0) {
printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
return FAILED;
}
+
+ sc = SCDATA(SCpnt);
+ memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd));
+ sc->request_buffer = SCpnt->request_buffer;
+ sc->request_bufflen = SCpnt->request_bufflen;
+ sc->use_sg = SCpnt->use_sg;
+ sc->cmd_len = SCpnt->cmd_len;
}
SCNEXT(SCpnt) = NULL;
@@ -1165,6 +1170,10 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
DECLARE_MUTEX_LOCKED(sem);
struct timer_list timer;
int ret, issued, disconnected;
+ unsigned char old_cmd_len = SCpnt->cmd_len;
+ unsigned short old_use_sg = SCpnt->use_sg;
+ void *old_buffer = SCpnt->request_buffer;
+ unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
#if defined(AHA152X_DEBUG)
@@ -1198,11 +1207,11 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
add_timer(&timer);
down(&sem);
del_timer(&timer);
-
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->request_buffer = SCpnt->buffer;
- SCpnt->request_bufflen = SCpnt->bufflen;
+
+ SCpnt->cmd_len = old_cmd_len;
+ SCpnt->use_sg = old_use_sg;
+ SCpnt->request_buffer = old_buffer;
+ SCpnt->request_bufflen = old_bufflen;
DO_LOCK(flags);
@@ -1441,9 +1450,12 @@ static struct work_struct aha152x_tq;
*/
static void run(void)
{
- int i;
- for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
- is_complete(aha152x_host[i]);
+ struct aha152x_hostdata *hd;
+
+ list_for_each_entry(hd, &aha152x_host_list, host_list) {
+ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
+
+ is_complete(shost);
}
}
@@ -1453,7 +1465,7 @@ static void run(void)
*/
static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
{
- struct Scsi_Host *shpnt = lookup_irq(irqno);
+ struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
unsigned long flags;
unsigned char rev, dmacntrl0;
@@ -1565,6 +1577,9 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
if(DONE_SC->SCp.phase & check_condition) {
+ struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
+ struct aha152x_scdata *sc = SCDATA(cmd);
+
#if 0
if(HOSTDATA(shpnt)->debug & debug_eh) {
printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
@@ -1573,13 +1588,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
/* restore old command */
- memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
- DONE_SC->request_buffer = DONE_SC->buffer;
- DONE_SC->request_bufflen = DONE_SC->bufflen;
- DONE_SC->use_sg = DONE_SC->old_use_sg;
- DONE_SC->cmd_len = DONE_SC->old_cmd_len;
+ memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd));
+ cmd->request_buffer = sc->request_buffer;
+ cmd->request_bufflen = sc->request_bufflen;
+ cmd->use_sg = sc->use_sg;
+ cmd->cmd_len = sc->cmd_len;
- DONE_SC->SCp.Status = 0x02;
+ cmd->SCp.Status = 0x02;
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
@@ -3932,16 +3947,17 @@ static int __init aha152x_init(void)
#endif
}
- return registered_count>0;
+ return 1;
}
static void __exit aha152x_exit(void)
{
- int i;
+ struct aha152x_hostdata *hd;
+
+ list_for_each_entry(hd, &aha152x_host_list, host_list) {
+ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
- for(i=0; i<ARRAY_SIZE(setup); i++) {
- aha152x_release(aha152x_host[i]);
- aha152x_host[i]=NULL;
+ aha152x_release(shost);
}
}
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 86c6bd23459..24f0f546179 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -25,7 +25,6 @@
* Added proper detection of the AHA-1640 (MCA version of AHA-1540)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 4b8c6a54392..6b35ed8301e 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -634,7 +634,7 @@ static int aha1740_probe (struct device *dev)
}
DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
- if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : SA_SHIRQ,
+ if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
"aha1740",shpnt)) {
printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
irq_level);
@@ -681,6 +681,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/ahci.c b/drivers/scsi/ahci.c
deleted file mode 100644
index 4bb77f62b3b..00000000000
--- a/drivers/scsi/ahci.c
+++ /dev/null
@@ -1,1472 +0,0 @@
-/*
- * ahci.c - AHCI SATA support
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2004-2005 Red Hat, 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * AHCI hardware documentation:
- * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
- * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-
-#define DRV_NAME "ahci"
-#define DRV_VERSION "1.3"
-
-
-enum {
- AHCI_PCI_BAR = 5,
- AHCI_MAX_SG = 168, /* hardware max is 64K */
- AHCI_DMA_BOUNDARY = 0xffffffff,
- AHCI_USE_CLUSTERING = 0,
- AHCI_MAX_CMDS = 32,
- AHCI_CMD_SZ = 32,
- AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
- AHCI_RX_FIS_SZ = 256,
- AHCI_CMD_TBL_CDB = 0x40,
- AHCI_CMD_TBL_HDR_SZ = 0x80,
- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
- AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
- AHCI_RX_FIS_SZ,
- AHCI_IRQ_ON_SG = (1 << 31),
- AHCI_CMD_ATAPI = (1 << 5),
- AHCI_CMD_WRITE = (1 << 6),
- AHCI_CMD_PREFETCH = (1 << 7),
- AHCI_CMD_RESET = (1 << 8),
- AHCI_CMD_CLR_BUSY = (1 << 10),
-
- RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
- RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
-
- board_ahci = 0,
- board_ahci_vt8251 = 1,
-
- /* global controller registers */
- HOST_CAP = 0x00, /* host capabilities */
- HOST_CTL = 0x04, /* global host control */
- HOST_IRQ_STAT = 0x08, /* interrupt status */
- HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
- HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
-
- /* HOST_CTL bits */
- HOST_RESET = (1 << 0), /* reset controller; self-clear */
- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
-
- /* HOST_CAP bits */
- HOST_CAP_CLO = (1 << 24), /* Command List Override support */
- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
-
- /* registers for each SATA port */
- PORT_LST_ADDR = 0x00, /* command list DMA addr */
- PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
- PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
- PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
- PORT_IRQ_STAT = 0x10, /* interrupt status */
- PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
- PORT_CMD = 0x18, /* port command */
- PORT_TFDATA = 0x20, /* taskfile data */
- PORT_SIG = 0x24, /* device TF signature */
- PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR = 0x28, /* SATA phy register block */
- PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
- PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
- PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
- PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
-
- /* PORT_IRQ_{STAT,MASK} bits */
- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
-
- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
-
- PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
- PORT_IRQ_IF_ERR |
- PORT_IRQ_CONNECT |
- PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS,
- PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
- PORT_IRQ_TF_ERR |
- PORT_IRQ_HBUS_DATA_ERR,
- DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
-
- /* PORT_CMD bits */
- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
- PORT_CMD_CLO = (1 << 3), /* Command list override */
- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
-
- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
-
- /* hpriv->flags bits */
- AHCI_FLAG_MSI = (1 << 0),
-
- /* ap->flags bits */
- AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
- AHCI_FLAG_NO_NCQ = (1 << 25),
-};
-
-struct ahci_cmd_hdr {
- u32 opts;
- u32 status;
- u32 tbl_addr;
- u32 tbl_addr_hi;
- u32 reserved[4];
-};
-
-struct ahci_sg {
- u32 addr;
- u32 addr_hi;
- u32 reserved;
- u32 flags_size;
-};
-
-struct ahci_host_priv {
- unsigned long flags;
- u32 cap; /* cache of HOST_CAP register */
- u32 port_map; /* cache of HOST_PORTS_IMPL reg */
-};
-
-struct ahci_port_priv {
- struct ahci_cmd_hdr *cmd_slot;
- dma_addr_t cmd_slot_dma;
- void *cmd_tbl;
- dma_addr_t cmd_tbl_dma;
- void *rx_fis;
- dma_addr_t rx_fis_dma;
-};
-
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void ahci_irq_clear(struct ata_port *ap);
-static int ahci_port_start(struct ata_port *ap);
-static void ahci_port_stop(struct ata_port *ap);
-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static void ahci_qc_prep(struct ata_queued_cmd *qc);
-static u8 ahci_check_status(struct ata_port *ap);
-static void ahci_freeze(struct ata_port *ap);
-static void ahci_thaw(struct ata_port *ap);
-static void ahci_error_handler(struct ata_port *ap);
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
-static void ahci_remove_one (struct pci_dev *pdev);
-
-static struct scsi_host_template ahci_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .change_queue_depth = ata_scsi_change_queue_depth,
- .can_queue = AHCI_MAX_CMDS - 1,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = AHCI_MAX_SG,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = AHCI_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = AHCI_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations ahci_ops = {
- .port_disable = ata_port_disable,
-
- .check_status = ahci_check_status,
- .check_altstatus = ahci_check_status,
- .dev_select = ata_noop_dev_select,
-
- .tf_read = ahci_tf_read,
-
- .qc_prep = ahci_qc_prep,
- .qc_issue = ahci_qc_issue,
-
- .irq_handler = ahci_interrupt,
- .irq_clear = ahci_irq_clear,
-
- .scr_read = ahci_scr_read,
- .scr_write = ahci_scr_write,
-
- .freeze = ahci_freeze,
- .thaw = ahci_thaw,
-
- .error_handler = ahci_error_handler,
- .post_internal_cmd = ahci_post_internal_cmd,
-
- .port_start = ahci_port_start,
- .port_stop = ahci_port_stop,
-};
-
-static const struct ata_port_info ahci_port_info[] = {
- /* board_ahci */
- {
- .sht = &ahci_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &ahci_ops,
- },
- /* board_ahci_vt8251 */
- {
- .sht = &ahci_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &ahci_ops,
- },
-};
-
-static const struct pci_device_id ahci_pci_tbl[] = {
- /* Intel */
- { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6 */
- { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6M */
- { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7 */
- { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7M */
- { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7R */
- { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ULi M5288 */
- { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7-M DH */
- { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
- { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
-
- /* JMicron */
- { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB360 */
- { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB361 */
- { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB363 */
- { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB365 */
- { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB366 */
-
- /* ATI */
- { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 non-raid */
- { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 raid */
-
- /* VIA */
- { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci_vt8251 }, /* VIA VT8251 */
-
- /* NVIDIA */
- { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
-
- { } /* terminate list */
-};
-
-
-static struct pci_driver ahci_pci_driver = {
- .name = DRV_NAME,
- .id_table = ahci_pci_tbl,
- .probe = ahci_init_one,
- .remove = ahci_remove_one,
-};
-
-
-static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
-{
- return base + 0x100 + (port * 0x80);
-}
-
-static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
-{
- return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
-}
-
-static int ahci_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct ahci_host_priv *hpriv = ap->host_set->private_data;
- struct ahci_port_priv *pp;
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- void *mem;
- dma_addr_t mem_dma;
- int rc;
-
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp)
- return -ENOMEM;
- memset(pp, 0, sizeof(*pp));
-
- rc = ata_pad_alloc(ap, dev);
- if (rc) {
- kfree(pp);
- return rc;
- }
-
- mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
- if (!mem) {
- ata_pad_free(ap, dev);
- kfree(pp);
- return -ENOMEM;
- }
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
-
- /*
- * First item in chunk of DMA memory: 32-slot command table,
- * 32 bytes each in size
- */
- pp->cmd_slot = mem;
- pp->cmd_slot_dma = mem_dma;
-
- mem += AHCI_CMD_SLOT_SZ;
- mem_dma += AHCI_CMD_SLOT_SZ;
-
- /*
- * Second item: Received-FIS area
- */
- pp->rx_fis = mem;
- pp->rx_fis_dma = mem_dma;
-
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
-
- /*
- * Third item: data area for storing a single command
- * and its scatter-gather table
- */
- pp->cmd_tbl = mem;
- pp->cmd_tbl_dma = mem_dma;
-
- ap->private_data = pp;
-
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
- writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
- readl(port_mmio + PORT_LST_ADDR); /* flush */
-
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
- writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
- readl(port_mmio + PORT_FIS_ADDR); /* flush */
-
- writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
- PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
- PORT_CMD_START, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- return 0;
-}
-
-
-static void ahci_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
- * this is slightly incorrect.
- */
- msleep(500);
-
- ap->private_data = NULL;
- dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
- pp->cmd_slot, pp->cmd_slot_dma);
- ata_pad_free(ap, dev);
- kfree(pp);
-}
-
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
-{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return 0xffffffffU;
- }
-
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
-{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return;
- }
-
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-static int ahci_stop_engine(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- int work;
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for engine to stop. TODO: this could be
- * as long as 500 msec
- */
- work = 1000;
- while (work-- > 0) {
- tmp = readl(port_mmio + PORT_CMD);
- if ((tmp & PORT_CMD_LIST_ON) == 0)
- return 0;
- udelay(10);
- }
-
- return -EIO;
-}
-
-static void ahci_start_engine(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-}
-
-static unsigned int ahci_dev_classify(struct ata_port *ap)
-{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- struct ata_taskfile tf;
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_SIG);
- tf.lbah = (tmp >> 24) & 0xff;
- tf.lbam = (tmp >> 16) & 0xff;
- tf.lbal = (tmp >> 8) & 0xff;
- tf.nsect = (tmp) & 0xff;
-
- return ata_dev_classify(&tf);
-}
-
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts)
-{
- dma_addr_t cmd_tbl_dma;
-
- cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
-
- pp->cmd_slot[tag].opts = cpu_to_le32(opts);
- pp->cmd_slot[tag].status = 0;
- pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
-}
-
-static int ahci_clo(struct ata_port *ap)
-{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- struct ahci_host_priv *hpriv = ap->host_set->private_data;
- u32 tmp;
-
- if (!(hpriv->cap & HOST_CAP_CLO))
- return -EOPNOTSUPP;
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_CLO;
- writel(tmp, port_mmio + PORT_CMD);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
- if (tmp & PORT_CMD_CLO)
- return -EIO;
-
- return 0;
-}
-
-static int ahci_prereset(struct ata_port *ap)
-{
- if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
- (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
- /* ATA_BUSY hasn't cleared, so send a CLO */
- ahci_clo(ap);
- }
-
- return ata_std_prereset(ap);
-}
-
-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
-{
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- const u32 cmd_fis_len = 5; /* five dwords */
- const char *reason = NULL;
- struct ata_taskfile tf;
- u32 tmp;
- u8 *fis;
- int rc;
-
- DPRINTK("ENTER\n");
-
- if (ata_port_offline(ap)) {
- DPRINTK("PHY reports no device\n");
- *class = ATA_DEV_NONE;
- return 0;
- }
-
- /* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
- if (rc) {
- reason = "failed to stop engine";
- goto fail_restart;
- }
-
- /* check BUSY/DRQ, perform Command List Override if necessary */
- ahci_tf_read(ap, &tf);
- if (tf.command & (ATA_BUSY | ATA_DRQ)) {
- rc = ahci_clo(ap);
-
- if (rc == -EOPNOTSUPP) {
- reason = "port busy but CLO unavailable";
- goto fail_restart;
- } else if (rc) {
- reason = "port busy but CLO failed";
- goto fail_restart;
- }
- }
-
- /* restart engine */
- ahci_start_engine(ap);
-
- ata_tf_init(ap->device, &tf);
- fis = pp->cmd_tbl;
-
- /* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0,
- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
-
- tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
- if (tmp & 0x1) {
- rc = -EIO;
- reason = "1st FIS failed";
- goto fail;
- }
-
- /* spec says at least 5us, but be generous and sleep for 1ms */
- msleep(1);
-
- /* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
- tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
-
- /* spec mandates ">= 2ms" before checking status.
- * We wait 150ms, because that was the magic delay used for
- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- */
- msleep(150);
-
- *class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- rc = -EIO;
- reason = "device not ready";
- goto fail;
- }
- *class = ahci_dev_classify(ap);
- }
-
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
-
- fail_restart:
- ahci_start_engine(ap);
- fail:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
- return rc;
-}
-
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
-{
- struct ahci_port_priv *pp = ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
- struct ata_taskfile tf;
- int rc;
-
- DPRINTK("ENTER\n");
-
- ahci_stop_engine(ap);
-
- /* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(ap->device, &tf);
- tf.command = 0xff;
- ata_tf_to_fis(&tf, d2h_fis, 0);
-
- rc = sata_std_hardreset(ap, class);
-
- ahci_start_engine(ap);
-
- if (rc == 0 && ata_port_online(ap))
- *class = ahci_dev_classify(ap);
- if (*class == ATA_DEV_UNKNOWN)
- *class = ATA_DEV_NONE;
-
- DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
- return rc;
-}
-
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
-{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- u32 new_tmp, tmp;
-
- ata_std_postreset(ap, class);
-
- /* Make sure port's ATAPI bit is set appropriately */
- new_tmp = tmp = readl(port_mmio + PORT_CMD);
- if (*class == ATA_DEV_ATAPI)
- new_tmp |= PORT_CMD_ATAPI;
- else
- new_tmp &= ~PORT_CMD_ATAPI;
- if (new_tmp != tmp) {
- writel(new_tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
- }
-}
-
-static u8 ahci_check_status(struct ata_port *ap)
-{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
-
- return readl(mmio + PORT_TFDATA) & 0xFF;
-}
-
-static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ahci_port_priv *pp = ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-
- ata_tf_from_fis(d2h_fis, tf);
-}
-
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
-{
- struct scatterlist *sg;
- struct ahci_sg *ahci_sg;
- unsigned int n_sg = 0;
-
- VPRINTK("ENTER\n");
-
- /*
- * Next, the S/G list.
- */
- ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
- ata_for_each_sg(sg, qc) {
- dma_addr_t addr = sg_dma_address(sg);
- u32 sg_len = sg_dma_len(sg);
-
- ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
- ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
- ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
-
- ahci_sg++;
- n_sg++;
- }
-
- return n_sg;
-}
-
-static void ahci_qc_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ahci_port_priv *pp = ap->private_data;
- int is_atapi = is_atapi_taskfile(&qc->tf);
- void *cmd_tbl;
- u32 opts;
- const u32 cmd_fis_len = 5; /* five dwords */
- unsigned int n_elem;
-
- /*
- * Fill in command table information. First, the header,
- * a SATA Register - Host to Device command FIS.
- */
- cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
-
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
- if (is_atapi) {
- memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
- }
-
- n_elem = 0;
- if (qc->flags & ATA_QCFLAG_DMAMAP)
- n_elem = ahci_fill_sg(qc, cmd_tbl);
-
- /*
- * Fill in command slot information.
- */
- opts = cmd_fis_len | n_elem << 16;
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- opts |= AHCI_CMD_WRITE;
- if (is_atapi)
- opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
-
- ahci_fill_cmd_slot(pp, qc->tag, opts);
-}
-
-static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
-{
- struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- u32 serror;
-
- ata_ehi_clear_desc(ehi);
-
- /* AHCI needs SError cleared; otherwise, it might lock up */
- serror = ahci_scr_read(ap, SCR_ERROR);
- ahci_scr_write(ap, SCR_ERROR, serror);
-
- /* analyze @irq_stat */
- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
-
- if (irq_stat & PORT_IRQ_TF_ERR)
- err_mask |= AC_ERR_DEV;
-
- if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- err_mask |= AC_ERR_HOST_BUS;
- action |= ATA_EH_SOFTRESET;
- }
-
- if (irq_stat & PORT_IRQ_IF_ERR) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", interface fatal error");
- }
-
- if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
- "connection status changed" : "PHY RDY changed");
- }
-
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- err_mask |= AC_ERR_HSM;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
- unk[0], unk[1], unk[2], unk[3]);
- }
-
- /* okay, let's hand over to EH */
- ehi->serror |= serror;
- ehi->action |= action;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc)
- qc->err_mask |= err_mask;
- else
- ehi->err_mask |= err_mask;
-
- if (irq_stat & PORT_IRQ_FREEZE)
- ata_port_freeze(ap);
- else
- ata_port_abort(ap);
-}
-
-static void ahci_host_intr(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- struct ata_eh_info *ehi = &ap->eh_info;
- u32 status, qc_active;
- int rc;
-
- status = readl(port_mmio + PORT_IRQ_STAT);
- writel(status, port_mmio + PORT_IRQ_STAT);
-
- if (unlikely(status & PORT_IRQ_ERROR)) {
- ahci_error_intr(ap, status);
- return;
- }
-
- if (ap->sactive)
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- else
- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
-
- rc = ata_qc_complete_multiple(ap, qc_active, NULL);
- if (rc > 0)
- return;
- if (rc < 0) {
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_SOFTRESET;
- ata_port_freeze(ap);
- return;
- }
-
- /* hmmm... a spurious interupt */
-
- /* some devices send D2H reg with I bit set during NCQ command phase */
- if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
- return;
-
- /* ignore interim PIO setup fis interrupts */
- if (ata_tag_valid(ap->active_tag)) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->active_tag);
-
- if (qc && qc->tf.protocol == ATA_PROT_PIO &&
- (status & PORT_IRQ_PIOS_FIS))
- return;
- }
-
- if (ata_ratelimit())
- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
- status, ap->active_tag, ap->sactive);
-}
-
-static void ahci_irq_clear(struct ata_port *ap)
-{
- /* TODO */
-}
-
-static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct ahci_host_priv *hpriv;
- unsigned int i, handled = 0;
- void __iomem *mmio;
- u32 irq_stat, irq_ack = 0;
-
- VPRINTK("ENTER\n");
-
- hpriv = host_set->private_data;
- mmio = host_set->mmio_base;
-
- /* sigh. 0xffffffff is a valid return from h/w */
- irq_stat = readl(mmio + HOST_IRQ_STAT);
- irq_stat &= hpriv->port_map;
- if (!irq_stat)
- return IRQ_NONE;
-
- spin_lock(&host_set->lock);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap;
-
- if (!(irq_stat & (1 << i)))
- continue;
-
- ap = host_set->ports[i];
- if (ap) {
- ahci_host_intr(ap);
- VPRINTK("port %u\n", i);
- } else {
- VPRINTK("port %u (no irq)\n", i);
- if (ata_ratelimit())
- dev_printk(KERN_WARNING, host_set->dev,
- "interrupt on disabled port %u\n", i);
- }
-
- irq_ack |= (1 << i);
- }
-
- if (irq_ack) {
- writel(irq_ack, mmio + HOST_IRQ_STAT);
- handled = 1;
- }
-
- spin_unlock(&host_set->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
-
- if (qc->tf.protocol == ATA_PROT_NCQ)
- writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
- writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
-
- return 0;
-}
-
-static void ahci_freeze(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
- /* turn IRQ off */
- writel(0, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_thaw(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- u32 tmp;
-
- /* clear IRQ */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- writel(tmp, port_mmio + PORT_IRQ_STAT);
- writel(1 << ap->id, mmio + HOST_IRQ_STAT);
-
- /* turn IRQ back on */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_error_handler(struct ata_port *ap)
-{
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
- /* restart engine */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
-
- /* perform recovery */
- ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
- ahci_postreset);
-}
-
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
- if (qc->err_mask) {
- /* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
-}
-
-static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
- unsigned int port_idx)
-{
- VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
- base = ahci_port_base_ul(base, port_idx);
- VPRINTK("base now==0x%lx\n", base);
-
- port->cmd_addr = base;
- port->scr_addr = base + PORT_SCR;
-
- VPRINTK("EXIT\n");
-}
-
-static int ahci_host_init(struct ata_probe_ent *probe_ent)
-{
- struct ahci_host_priv *hpriv = probe_ent->private_data;
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
- u32 tmp, cap_save;
- unsigned int i, j, using_dac;
- int rc;
- void __iomem *port_mmio;
-
- cap_save = readl(mmio + HOST_CAP);
- cap_save &= ( (1<<28) | (1<<17) );
- cap_save |= (1 << 27);
-
- /* global controller reset */
- tmp = readl(mmio + HOST_CTL);
- if ((tmp & HOST_RESET) == 0) {
- writel(tmp | HOST_RESET, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
- }
-
- /* reset must complete within 1 second, or
- * the hardware should be considered fried.
- */
- ssleep(1);
-
- tmp = readl(mmio + HOST_CTL);
- if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, &pdev->dev,
- "controller reset failed (0x%x)\n", tmp);
- return -EIO;
- }
-
- writel(HOST_AHCI_EN, mmio + HOST_CTL);
- (void) readl(mmio + HOST_CTL); /* flush */
- writel(cap_save, mmio + HOST_CAP);
- writel(0xf, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
-
- if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
- u16 tmp16;
-
- pci_read_config_word(pdev, 0x92, &tmp16);
- tmp16 |= 0xf;
- pci_write_config_word(pdev, 0x92, tmp16);
- }
-
- hpriv->cap = readl(mmio + HOST_CAP);
- hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
- probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
-
- VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
- hpriv->cap, hpriv->port_map, probe_ent->n_ports);
-
- using_dac = hpriv->cap & HOST_CAP_64;
- if (using_dac &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
- return rc;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- return rc;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
- }
-
- for (i = 0; i < probe_ent->n_ports; i++) {
-#if 0 /* BIOSen initialize this incorrectly */
- if (!(hpriv->port_map & (1 << i)))
- continue;
-#endif
-
- port_mmio = ahci_port_base(mmio, i);
- VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio);
-
- ahci_setup_port(&probe_ent->port[i],
- (unsigned long) mmio, i);
-
- /* make sure port is not active */
- tmp = readl(port_mmio + PORT_CMD);
- VPRINTK("PORT_CMD 0x%x\n", tmp);
- if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
- PORT_CMD_FIS_RX | PORT_CMD_START)) {
- tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
- PORT_CMD_FIS_RX | PORT_CMD_START);
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- /* spec says 500 msecs for each bit, so
- * this is slightly incorrect.
- */
- msleep(500);
- }
-
- writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
-
- j = 0;
- while (j < 100) {
- msleep(10);
- tmp = readl(port_mmio + PORT_SCR_STAT);
- if ((tmp & 0xf) == 0x3)
- break;
- j++;
- }
-
- tmp = readl(port_mmio + PORT_SCR_ERR);
- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
- writel(tmp, port_mmio + PORT_SCR_ERR);
-
- /* ack any pending irq events for this port */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
- if (tmp)
- writel(tmp, port_mmio + PORT_IRQ_STAT);
-
- writel(1 << i, mmio + HOST_IRQ_STAT);
- }
-
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
- writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
-
- pci_set_master(pdev);
-
- return 0;
-}
-
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
-{
- struct ahci_host_priv *hpriv = probe_ent->private_data;
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
- u32 vers, cap, impl, speed;
- const char *speed_s;
- u16 cc;
- const char *scc_s;
-
- vers = readl(mmio + HOST_VERSION);
- cap = hpriv->cap;
- impl = hpriv->port_map;
-
- speed = (cap >> 20) & 0xf;
- if (speed == 1)
- speed_s = "1.5";
- else if (speed == 2)
- speed_s = "3";
- else
- speed_s = "?";
-
- pci_read_config_word(pdev, 0x0a, &cc);
- if (cc == 0x0101)
- scc_s = "IDE";
- else if (cc == 0x0106)
- scc_s = "SATA";
- else if (cc == 0x0104)
- scc_s = "RAID";
- else
- scc_s = "unknown";
-
- dev_printk(KERN_INFO, &pdev->dev,
- "AHCI %02x%02x.%02x%02x "
- "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
- ,
-
- (vers >> 24) & 0xff,
- (vers >> 16) & 0xff,
- (vers >> 8) & 0xff,
- vers & 0xff,
-
- ((cap >> 8) & 0x1f) + 1,
- (cap & 0x1f) + 1,
- speed_s,
- impl,
- scc_s);
-
- dev_printk(KERN_INFO, &pdev->dev,
- "flags: "
- "%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
- ,
-
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : ""
- );
-}
-
-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- struct ahci_host_priv *hpriv;
- unsigned long base;
- void __iomem *mmio_base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int have_msi, pci_dev_busy = 0;
- int rc;
-
- VPRINTK("ENTER\n");
-
- WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- if (pci_enable_msi(pdev) == 0)
- have_msi = 1;
- else {
- pci_intx(pdev, 1);
- have_msi = 0;
- }
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_msi;
- }
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- probe_ent->sht = ahci_port_info[board_idx].sht;
- probe_ent->host_flags = ahci_port_info[board_idx].host_flags;
- probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
- probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
- probe_ent->private_data = hpriv;
-
- if (have_msi)
- hpriv->flags |= AHCI_FLAG_MSI;
-
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- if (pdev->vendor == 0x197b)
- pci_write_config_byte(pdev, 0x41, 0xa1);
-
- /* initialize adapter */
- rc = ahci_host_init(probe_ent);
- if (rc)
- goto err_out_hpriv;
-
- if (!(probe_ent->host_flags & AHCI_FLAG_NO_NCQ) &&
- (hpriv->cap & HOST_CAP_NCQ))
- probe_ent->host_flags |= ATA_FLAG_NCQ;
-
- ahci_print_info(probe_ent);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_msi:
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-static void ahci_remove_one (struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host_set *host_set = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host_set->private_data;
- unsigned int i;
- int have_msi;
-
- for (i = 0; i < host_set->n_ports; i++)
- ata_port_detach(host_set->ports[i]);
-
- have_msi = hpriv->flags & AHCI_FLAG_MSI;
- free_irq(host_set->irq, host_set);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
-
- ata_scsi_release(ap->host);
- scsi_host_put(ap->host);
- }
-
- kfree(hpriv);
- pci_iounmap(pdev, host_set->mmio_base);
- kfree(host_set);
-
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
-}
-
-static int __init ahci_init(void)
-{
- return pci_module_init(&ahci_pci_driver);
-}
-
-static void __exit ahci_exit(void)
-{
- pci_unregister_driver(&ahci_pci_driver);
-}
-
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("AHCI SATA low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(ahci_init);
-module_exit(ahci_exit);
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index d754b326786..1ac119733ba 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -65,7 +65,7 @@ aic7770_map_int(struct ahc_softc *ahc, u_int irq)
shared = 0;
if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
- shared = SA_SHIRQ;
+ shared = IRQF_SHARED;
error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc);
if (error == 0)
@@ -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 eb774569268..df3346b5caf 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1487,6 +1487,7 @@ typedef enum {
} ahd_queue_alg;
void ahd_set_tags(struct ahd_softc *ahd,
+ struct scsi_cmnd *cmd,
struct ahd_devinfo *devinfo,
ahd_queue_alg alg);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 801fc81d0b2..653818d2f80 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -1090,7 +1090,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
/* Notify XPT */
ahd_send_async(ahd, devinfo.channel, devinfo.target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR);
/*
* Allow the sequencer to continue with
@@ -3062,7 +3062,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
tinfo->curr.ppr_options = ppr_options;
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
if (offset != 0) {
int options;
@@ -3184,7 +3184,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
tinfo->curr.width = width;
ahd_send_async(ahd, 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",
ahd_name(ahd), devinfo->target,
@@ -3211,12 +3211,14 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
* Update the current state of tagged queuing for a given target.
*/
void
-ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
- ahd_queue_alg alg)
+ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+ struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{
- ahd_platform_set_tags(ahd, devinfo, alg);
+ struct scsi_device *sdev = cmd->device;
+
+ ahd_platform_set_tags(ahd, sdev, devinfo, alg);
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- devinfo->lun, AC_TRANSFER_NEG, &alg);
+ devinfo->lun, AC_TRANSFER_NEG);
}
static void
@@ -4746,7 +4748,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
printf("(%s:%c:%d:%d): refuses tagged commands. "
"Performing non-tagged I/O\n", ahd_name(ahd),
devinfo->channel, devinfo->target, devinfo->lun);
- ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE);
+ ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE);
mask = ~0x23;
} else {
printf("(%s:%c:%d:%d): refuses %s tagged commands. "
@@ -4754,7 +4756,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
ahd_name(ahd), devinfo->channel, devinfo->target,
devinfo->lun, tag_type == MSG_ORDERED_TASK
? "ordered" : "head of queue");
- ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC);
+ ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC);
mask = ~0x03;
}
@@ -5098,7 +5100,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
if (status != CAM_SEL_TIMEOUT)
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR);
if (message != NULL && bootverbose)
printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
@@ -7287,7 +7289,7 @@ ahd_reset_cmds_pending(struct ahd_softc *ahd)
ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
}
-void
+static void
ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
{
cam_status ostat;
@@ -7952,7 +7954,7 @@ 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, NULL);
+ CAM_LUN_WILDCARD, AC_BUS_RESET);
/*
* Revert to async/narrow transfers until we renegotiate.
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index e0ccdf36220..c7eeaced324 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -243,25 +243,6 @@ ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
static uint32_t aic79xx_no_reset;
/*
- * Certain PCI motherboards will scan PCI devices from highest to lowest,
- * others scan from lowest to highest, and they tend to do all kinds of
- * strange things when they come into contact with PCI bridge chips. The
- * net result of all this is that the PCI card that is actually used to boot
- * the machine is very hard to detect. Most motherboards go from lowest
- * PCI slot number to highest, and the first SCSI controller found is the
- * one you boot from. The only exceptions to this are when a controller
- * has its BIOS disabled. So, we by default sort all of our SCSI controllers
- * from lowest PCI slot number to highest PCI slot number. We also force
- * all controllers with their BIOS disabled to the end of the list. This
- * works on *almost* all computers. Where it doesn't work, we have this
- * option. Setting this option to non-0 will reverse the order of the sort
- * to highest first, then lowest, but will still leave cards with their BIOS
- * disabled at the very end. That should fix everyone up unless there are
- * really strange cirumstances.
- */
-static uint32_t aic79xx_reverse_scan;
-
-/*
* Should we force EXTENDED translation on a controller.
* 0 == Use whatever is in the SEEPROM or default to off
* 1 == Use whatever is in the SEEPROM or default to on
@@ -340,7 +321,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
module_param(aic79xx, charp, 0444);
MODULE_PARM_DESC(aic79xx,
-"period delimited, options string.\n"
+"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
@@ -350,7 +331,6 @@ MODULE_PARM_DESC(aic79xx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" or drives/RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for all targets on all buses\n"
" slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
@@ -366,7 +346,7 @@ MODULE_PARM_DESC(aic79xx,
" Shorten the selection timeout to 128ms\n"
"\n"
" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
-"\n");
+);
static void ahd_linux_handle_scsi_status(struct ahd_softc *,
struct scsi_device *,
@@ -484,7 +464,6 @@ ahd_linux_target_alloc(struct scsi_target *starget)
struct seeprom_config *sc = ahd->seep_config;
unsigned long flags;
struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);
- struct ahd_linux_target *targ = scsi_transport_target_data(starget);
struct ahd_devinfo devinfo;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
@@ -495,7 +474,6 @@ ahd_linux_target_alloc(struct scsi_target *starget)
BUG_ON(*ahd_targp != NULL);
*ahd_targp = starget;
- memset(targ, 0, sizeof(*targ));
if (sc) {
int flags = sc->device_flags[starget->id];
@@ -551,15 +529,11 @@ ahd_linux_slave_alloc(struct scsi_device *sdev)
{
struct ahd_softc *ahd =
*((struct ahd_softc **)sdev->host->hostdata);
- struct scsi_target *starget = sdev->sdev_target;
- struct ahd_linux_target *targ = scsi_transport_target_data(starget);
struct ahd_linux_device *dev;
if (bootverbose)
printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
- BUG_ON(targ->sdev[sdev->lun] != NULL);
-
dev = scsi_transport_device_data(sdev);
memset(dev, 0, sizeof(*dev));
@@ -576,8 +550,6 @@ ahd_linux_slave_alloc(struct scsi_device *sdev)
*/
dev->maxtags = 0;
- targ->sdev[sdev->lun] = sdev;
-
return (0);
}
@@ -599,23 +571,6 @@ ahd_linux_slave_configure(struct scsi_device *sdev)
return 0;
}
-static void
-ahd_linux_slave_destroy(struct scsi_device *sdev)
-{
- struct ahd_softc *ahd;
- struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
- struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
-
- ahd = *((struct ahd_softc **)sdev->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id);
-
- BUG_ON(dev->active);
-
- targ->sdev[sdev->lun] = NULL;
-
-}
-
#if defined(__i386__)
/*
* Return the disk geometry for the given SCSI device.
@@ -822,7 +777,6 @@ struct scsi_host_template aic79xx_driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.slave_alloc = ahd_linux_slave_alloc,
.slave_configure = ahd_linux_slave_configure,
- .slave_destroy = ahd_linux_slave_destroy,
.target_alloc = ahd_linux_target_alloc,
.target_destroy = ahd_linux_target_destroy,
};
@@ -1057,7 +1011,6 @@ aic79xx_setup(char *s)
#ifdef AHD_DEBUG
{ "debug", &ahd_debug },
#endif
- { "reverse_scan", &aic79xx_reverse_scan },
{ "periodic_otag", &aic79xx_periodic_otag },
{ "pci_parity", &aic79xx_pci_parity },
{ "seltime", &aic79xx_seltime },
@@ -1249,20 +1202,13 @@ void
ahd_platform_free(struct ahd_softc *ahd)
{
struct scsi_target *starget;
- int i, j;
+ int i;
if (ahd->platform_data != NULL) {
/* destroy all of the device and target objects */
for (i = 0; i < AHD_NUM_TARGETS; i++) {
starget = ahd->platform_data->starget[i];
if (starget != NULL) {
- for (j = 0; j < AHD_NUM_LUNS; j++) {
- struct ahd_linux_target *targ =
- scsi_transport_target_data(starget);
- if (targ->sdev[j] == NULL)
- continue;
- targ->sdev[j] = NULL;
- }
ahd->platform_data->starget[i] = NULL;
}
}
@@ -1318,20 +1264,13 @@ ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
}
void
-ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
- ahd_queue_alg alg)
+ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
+ struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{
- struct scsi_target *starget;
- struct ahd_linux_target *targ;
struct ahd_linux_device *dev;
- struct scsi_device *sdev;
int was_queuing;
int now_queuing;
- starget = ahd->platform_data->starget[devinfo->target];
- targ = scsi_transport_target_data(starget);
- BUG_ON(targ == NULL);
- sdev = targ->sdev[devinfo->lun];
if (sdev == NULL)
return;
@@ -1467,11 +1406,15 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev)
tags = ahd_linux_user_tagdepth(ahd, &devinfo);
if (tags != 0 && sdev->tagged_supported != 0) {
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
+ ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED);
+ ahd_send_async(ahd, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
ahd_print_devinfo(ahd, &devinfo);
printf("Tagged Queuing enabled. Depth %d\n", tags);
} else {
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
+ ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE);
+ ahd_send_async(ahd, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
}
}
@@ -1629,7 +1572,7 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
void
ahd_send_async(struct ahd_softc *ahd, 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:
@@ -1956,7 +1899,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
}
ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
ahd_set_scsi_status(scb, SCSI_STATUS_OK);
- ahd_platform_set_tags(ahd, &devinfo,
+ ahd_platform_set_tags(ahd, sdev, &devinfo,
(dev->flags & AHD_DEV_Q_BASIC)
? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
break;
@@ -1966,7 +1909,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
* as if the target returned BUSY SCSI status.
*/
dev->openings = 1;
- ahd_platform_set_tags(ahd, &devinfo,
+ ahd_platform_set_tags(ahd, sdev, &devinfo,
(dev->flags & AHD_DEV_Q_BASIC)
? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
@@ -2778,8 +2721,6 @@ ahd_linux_init(void)
if (!ahd_linux_transport_template)
return -ENODEV;
- scsi_transport_reserve_target(ahd_linux_transport_template,
- sizeof(struct ahd_linux_target));
scsi_transport_reserve_device(ahd_linux_transport_template,
sizeof(struct ahd_linux_device));
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 2b8331649ee..601340d8441 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -42,7 +42,6 @@
#ifndef _AIC79XX_LINUX_H_
#define _AIC79XX_LINUX_H_
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -94,7 +93,6 @@
#endif
/********************************** Misc Macros *******************************/
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
#define powerof2(x) ((((x)-1)&(x))==0)
/************************* Forward Declarations *******************************/
@@ -263,7 +261,6 @@ typedef enum {
AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
} ahd_linux_dev_flags;
-struct ahd_linux_target;
struct ahd_linux_device {
TAILQ_ENTRY(ahd_linux_device) links;
@@ -343,12 +340,6 @@ struct ahd_linux_device {
#define AHD_OTAG_THRESH 500
};
-struct ahd_linux_target {
- struct scsi_device *sdev[AHD_NUM_LUNS];
- struct ahd_transinfo last_tinfo;
- struct ahd_softc *ahd;
-};
-
/********************* Definitions Required by the Core ***********************/
/*
* Number of SG segments we require. So long as the S/G segments for
@@ -865,7 +856,7 @@ ahd_freeze_scb(struct scb *scb)
}
}
-void ahd_platform_set_tags(struct ahd_softc *ahd,
+void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
struct ahd_devinfo *devinfo, ahd_queue_alg);
int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
@@ -874,7 +865,7 @@ irqreturn_t
ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
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, void *);
+ u_int target, u_int lun, ac_code);
void ahd_print_path(struct ahd_softc *, struct scb *);
#ifdef CONFIG_PCI
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index ebbf7e4ff4c..50a41eda580 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -342,7 +342,7 @@ ahd_pci_map_int(struct ahd_softc *ahd)
int error;
error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
- SA_SHIRQ, "aic79xx", ahd);
+ IRQF_SHARED, "aic79xx", ahd);
if (!error)
ahd->platform_data->irq = ahd->dev_softc->irq;
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 24fd59a230b..c5f0ee59150 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -47,7 +47,7 @@ static int copy_info(struct info_str *info, char *fmt, ...);
static void ahd_dump_target_state(struct ahd_softc *ahd,
struct info_str *info,
u_int our_id, char channel,
- u_int target_id, u_int target_offset);
+ u_int target_id);
static void ahd_dump_device_state(struct info_str *info,
struct scsi_device *sdev);
static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
@@ -204,10 +204,8 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
static void
ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
- u_int our_id, char channel, u_int target_id,
- u_int target_offset)
+ u_int our_id, char channel, u_int target_id)
{
- struct ahd_linux_target *targ;
struct scsi_target *starget;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
@@ -218,10 +216,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
copy_info(info, "Target %d Negotiation Settings\n", target_id);
copy_info(info, "\tUser: ");
ahd_format_transinfo(info, &tinfo->user);
- starget = ahd->platform_data->starget[target_offset];
+ starget = ahd->platform_data->starget[target_id];
if (starget == NULL)
return;
- targ = scsi_transport_target_data(starget);
copy_info(info, "\tGoal: ");
ahd_format_transinfo(info, &tinfo->goal);
@@ -231,7 +228,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
struct scsi_device *dev;
- dev = targ->sdev[lun];
+ dev = scsi_device_lookup_by_target(starget, lun);
if (dev == NULL)
continue;
@@ -355,7 +352,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
ahd->scb_data.numscbs, AHD_NSEG);
- max_targ = 15;
+ max_targ = 16;
if (ahd->seep_config == NULL)
copy_info(&info, "No Serial EEPROM\n");
@@ -373,12 +370,12 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
copy_info(&info, "\n");
if ((ahd->features & AHD_WIDE) == 0)
- max_targ = 7;
+ max_targ = 8;
- for (i = 0; i <= max_targ; i++) {
+ for (i = 0; i < max_targ; i++) {
ahd_dump_target_state(ahd, &info, ahd->our_id, 'A',
- /*target_id*/i, /*target_offset*/i);
+ /*target_id*/i);
}
retval = info.pos > info.offset ? info.pos - info.offset : 0;
done:
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index debf3e2a079..64c8b88a429 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -341,7 +341,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
module_param(aic7xxx, charp, 0444);
MODULE_PARM_DESC(aic7xxx,
-"period delimited, options string.\n"
+"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
@@ -353,7 +353,6 @@ MODULE_PARM_DESC(aic7xxx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" drives or RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for every target\n"
" on every bus\n"
@@ -2540,15 +2539,28 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
static void ahc_linux_get_signalling(struct Scsi_Host *shost)
{
struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata;
- u8 mode = ahc_inb(ahc, SBLKCTL);
+ unsigned long flags;
+ u8 mode;
- if (mode & ENAB40)
- spi_signalling(shost) = SPI_SIGNAL_LVD;
- else if (mode & ENAB20)
+ if (!(ahc->features & AHC_ULTRA2)) {
+ /* non-LVD chipset, may not have SBLKCTL reg */
spi_signalling(shost) =
ahc->features & AHC_HVD ?
SPI_SIGNAL_HVD :
SPI_SIGNAL_SE;
+ return;
+ }
+
+ ahc_lock(ahc, &flags);
+ ahc_pause(ahc);
+ mode = ahc_inb(ahc, SBLKCTL);
+ ahc_unpause(ahc);
+ ahc_unlock(ahc, &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;
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index a20b08c9ff1..d42a71ee076 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -59,7 +59,6 @@
#ifndef _AIC7XXX_LINUX_H_
#define _AIC7XXX_LINUX_H_
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 0c9c2f400bf..7e42f07a27f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -375,7 +375,7 @@ ahc_pci_map_int(struct ahc_softc *ahc)
int error;
error = request_irq(ahc->dev_softc->irq, ahc_linux_isr,
- SA_SHIRQ, "aic7xxx", ahc);
+ IRQF_SHARED, "aic7xxx", ahc);
if (error == 0)
ahc->platform_data->irq = ahc->dev_softc->irq;
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile
index 8c91fda6482..b98c5c1056c 100644
--- a/drivers/scsi/aic7xxx/aicasm/Makefile
+++ b/drivers/scsi/aic7xxx/aicasm/Makefile
@@ -14,6 +14,8 @@ LIBS= -ldb
clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG)
# Override default kernel CFLAGS. This is a userland app.
AICASM_CFLAGS:= -I/usr/include -I.
+LEX= flex
+YACC= bison
YFLAGS= -d
NOMAN= noman
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 5dba1c63122..5dcef48d414 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -249,8 +249,6 @@
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
-#include <linux/config.h> /* for CONFIG_PCI */
-
#define AIC7XXX_C_VERSION "5.2.6"
#define ALL_TARGETS -1
@@ -8322,11 +8320,11 @@ aic7xxx_register(struct scsi_host_template *template, struct aic7xxx_host *p,
}
else
{
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+ result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_SHARED,
"aic7xxx", p));
if (result < 0)
{
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+ result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_DISABLED | IRQF_SHARED,
"aic7xxx", p));
}
}
@@ -9196,7 +9194,7 @@ aic7xxx_detect(struct scsi_host_template *template)
for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++)
{
pdev = NULL;
- while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
+ while ((pdev = pci_get_device(aic_pdevs[i].vendor_id,
aic_pdevs[i].device_id,
pdev))) {
if (pci_enable_device(pdev))
@@ -9653,6 +9651,9 @@ aic7xxx_detect(struct scsi_host_template *template)
*/
aic7xxx_configure_bugs(temp_p);
+ /* Hold a pci device reference */
+ pci_dev_get(temp_p->pdev);
+
if ( list_p == NULL )
{
list_p = current_p = temp_p;
@@ -10989,8 +10990,10 @@ aic7xxx_release(struct Scsi_Host *host)
if(!p->pdev)
release_region(p->base, MAXREG - MINREG);
#ifdef CONFIG_PCI
- else
+ else {
pci_release_regions(p->pdev);
+ pci_dev_put(p->pdev);
+ }
#endif
prev = NULL;
next = first_aic7xxx;
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
index 3bf334931a8..b07e4f04fd0 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
@@ -29,7 +29,6 @@
* $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
-#include <linux/config.h>
#define BLS (&aic7xxx_buffer[size])
#define HDRB \
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
new file mode 100644
index 00000000000..0ed391d8ee8
--- /dev/null
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -0,0 +1,41 @@
+#
+# Kernel configuration file for aic94xx SAS/SATA driver.
+#
+# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the aic94xx driver.
+#
+# The aic94xx driver 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; version 2 of the
+# License.
+#
+# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#
+
+config SCSI_AIC94XX
+ tristate "Adaptec AIC94xx SAS/SATA support"
+ depends on PCI
+ select SCSI_SAS_LIBSAS
+ help
+ This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
+ AIC94xx chip based host adapters.
+
+config AIC94XX_DEBUG
+ bool "Compile in debug mode"
+ default y
+ depends on SCSI_AIC94XX
+ help
+ Compiles the aic94xx driver in debug mode. In debug mode,
+ the driver prints some messages to the console.
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
new file mode 100644
index 00000000000..e6b70123940
--- /dev/null
+++ b/drivers/scsi/aic94xx/Makefile
@@ -0,0 +1,39 @@
+#
+# Makefile for Adaptec aic94xx SAS/SATA driver.
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the the aic94xx driver.
+#
+# The aic94xx driver 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; version 2 of the
+# License.
+#
+# The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ifeq ($(CONFIG_AIC94XX_DEBUG),y)
+ EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
+endif
+
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
+aic94xx-y += aic94xx_init.o \
+ aic94xx_hwi.o \
+ aic94xx_reg.o \
+ aic94xx_sds.o \
+ aic94xx_seq.o \
+ aic94xx_dump.o \
+ aic94xx_scb.o \
+ aic94xx_dev.o \
+ aic94xx_tmf.o \
+ aic94xx_task.o
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
new file mode 100644
index 00000000000..71a031df7a3
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -0,0 +1,114 @@
+/*
+ * Aic94xx SAS/SATA driver header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx.h#31 $
+ */
+
+#ifndef _AIC94XX_H_
+#define _AIC94XX_H_
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <scsi/libsas.h>
+
+#define ASD_DRIVER_NAME "aic94xx"
+#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver"
+
+#define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
+
+#ifdef ASD_ENTER_EXIT
+#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
+ __FUNCTION__)
+#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
+ __FUNCTION__)
+#else
+#define ENTER
+#define EXIT
+#endif
+
+#ifdef ASD_DEBUG
+#define ASD_DPRINTK asd_printk
+#else
+#define ASD_DPRINTK(fmt, ...)
+#endif
+
+/* 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 char sas_addr_str[2*SAS_ADDR_SIZE + 1];
+
+static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
+{
+ int i;
+ for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
+ snprintf(p, 3, "%02X", sas_addr[i]);
+ *p = '\0';
+}
+
+static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
+{
+ int i;
+ for (i = 0; i < SAS_ADDR_SIZE; i++) {
+ u8 h, l;
+ if (!*p)
+ break;
+ h = isdigit(*p) ? *p-'0' : *p-'A'+10;
+ p++;
+ l = isdigit(*p) ? *p-'0' : *p-'A'+10;
+ p++;
+ sas_addr[i] = (h<<4) | l;
+ }
+}
+
+struct asd_ha_struct;
+struct asd_ascb;
+
+int asd_read_ocm(struct asd_ha_struct *asd_ha);
+int asd_read_flash(struct asd_ha_struct *asd_ha);
+
+int asd_dev_found(struct domain_device *dev);
+void asd_dev_gone(struct domain_device *dev);
+
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
+
+int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
+
+/* ---------- TMFs ---------- */
+int asd_abort_task(struct sas_task *);
+int asd_abort_task_set(struct domain_device *, u8 *lun);
+int asd_clear_aca(struct domain_device *, u8 *lun);
+int asd_clear_task_set(struct domain_device *, u8 *lun);
+int asd_lu_reset(struct domain_device *, u8 *lun);
+int asd_query_task(struct sas_task *);
+
+/* ---------- Adapter and Port management ---------- */
+int asd_clear_nexus_port(struct asd_sas_port *port);
+int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
+
+/* ---------- Phy Management ---------- */
+int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
new file mode 100644
index 00000000000..6f8901b748f
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -0,0 +1,353 @@
+/*
+ * Aic94xx SAS/SATA DDB management
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_dev.c#21 $
+ */
+
+#include "aic94xx.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_sas.h"
+
+#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
+ (_ha)->hw_prof.max_ddbs)
+#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+
+static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
+{
+ unsigned long flags;
+ int ddb, i;
+
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+ ddb = FIND_FREE_DDB(asd_ha);
+ if (ddb >= asd_ha->hw_prof.max_ddbs) {
+ ddb = -ENOMEM;
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+ goto out;
+ }
+ SET_DDB(ddb, asd_ha);
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
+ for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
+ asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
+out:
+ return ddb;
+}
+
+#define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
+#define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
+#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
+#define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
+#define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
+#define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags)
+#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
+#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
+#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
+#define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
+#define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
+#define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
+#define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
+#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
+#define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
+#define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
+#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
+#define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
+
+static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
+{
+ unsigned long flags;
+
+ if (!ddb || ddb >= 0xFFFF)
+ return;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+ CLEAR_DDB(ddb, asd_ha);
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+}
+
+static inline void asd_set_ddb_type(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb = (int) (unsigned long) dev->lldd_dev;
+
+ if (dev->dev_type == SATA_PM_PORT)
+ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
+ else if (dev->tproto)
+ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
+ else
+ asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
+}
+
+static int asd_init_sata_tag_ddb(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb, i;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
+ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+ SISTER_DDB, ddb);
+ return 0;
+}
+
+static inline int asd_init_sata(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb = (int) (unsigned long) dev->lldd_dev;
+ u32 qdepth = 0;
+ int res = 0;
+
+ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+ if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
+ dev->sata_dev.identify_device &&
+ dev->sata_dev.identify_device[10] != 0) {
+ u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
+ u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
+
+ if (w76 & 0x100) /* NCQ? */
+ qdepth = (w75 & 0x1F) + 1;
+ asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
+ (1<<qdepth)-1);
+ asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
+ }
+ if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
+ dev->dev_type == SATA_PM_PORT) {
+ struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
+ dev->frame_rcvd;
+ asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
+ }
+ asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
+ if (qdepth > 0)
+ res = asd_init_sata_tag_ddb(dev);
+ return res;
+}
+
+static int asd_init_target_ddb(struct domain_device *dev)
+{
+ int ddb, i;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ u8 flags = 0;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ dev->lldd_dev = (void *) (unsigned long) ddb;
+
+ asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
+ asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
+ asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
+ for (i = 0; i < SAS_ADDR_SIZE; i++)
+ asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
+ dev->sas_addr[i]);
+ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
+ asd_set_ddb_type(dev);
+ asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ flags |= OPEN_REQUIRED;
+ if ((dev->dev_type == SATA_DEV) ||
+ (dev->tproto & SAS_PROTO_STP)) {
+ struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
+ if (rps_resp->frame_type == SMP_RESPONSE &&
+ rps_resp->function == SMP_REPORT_PHY_SATA &&
+ rps_resp->result == SMP_RESP_FUNC_ACC) {
+ if (rps_resp->rps.affil_valid)
+ flags |= STP_AFFIL_POL;
+ if (rps_resp->rps.affil_supp)
+ flags |= SUPPORTS_AFFIL;
+ }
+ } else {
+ flags |= CONCURRENT_CONN_SUPP;
+ if (!dev->parent &&
+ (dev->dev_type == EDGE_DEV ||
+ dev->dev_type == FANOUT_DEV))
+ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+ 4);
+ else
+ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+ dev->pathways);
+ asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
+ }
+ }
+ if (dev->dev_type == SATA_PM)
+ flags |= SATA_MULTIPORT;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
+
+ flags = 0;
+ if (dev->tproto & SAS_PROTO_STP)
+ flags |= STP_CL_POL_NO_TX;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+
+ asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+
+ if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+ i = asd_init_sata(dev);
+ if (i < 0) {
+ asd_free_ddb(asd_ha, ddb);
+ return i;
+ }
+ }
+
+ if (dev->dev_type == SAS_END_DEV) {
+ struct sas_end_device *rdev = rphy_to_end_device(dev->rphy);
+ if (rdev->I_T_nexus_loss_timeout > 0)
+ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+ min(rdev->I_T_nexus_loss_timeout,
+ (u16)ITNL_TIMEOUT_CONST));
+ else
+ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+ (u16)ITNL_TIMEOUT_CONST);
+ }
+ return 0;
+}
+
+static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb, i;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ for (i = 0; i < 32; i += 2)
+ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+ SISTER_DDB, ddb);
+
+ return 0;
+}
+
+#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
+#define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
+
+/**
+ * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
+ * dev: pointer to domain device
+ *
+ * For SATA Port Multiplier Ports we need to allocate one SATA Port
+ * Multiplier Port DDB and depending on whether the target on it
+ * supports SATA II NCQ, one SATA Tag DDB.
+ */
+static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
+{
+ int ddb, i, parent_ddb, pmtable_ddb;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ u8 flags;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ asd_set_ddb_type(dev);
+ flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
+ asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
+ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+ asd_init_sata(dev);
+
+ parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
+ asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
+ pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
+ asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
+
+ if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
+ i = asd_init_sata_tag_ddb(dev);
+ if (i < 0) {
+ asd_free_ddb(asd_ha, ddb);
+ return i;
+ }
+ }
+ return 0;
+}
+
+static int asd_init_initiator_ddb(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+/**
+ * asd_init_sata_pm_ddb -- SATA Port Multiplier
+ * dev: pointer to domain device
+ *
+ * For STP and direct-attached SATA Port Multipliers we need
+ * one target port DDB entry and one SATA PM table DDB entry.
+ */
+static int asd_init_sata_pm_ddb(struct domain_device *dev)
+{
+ int res = 0;
+
+ res = asd_init_target_ddb(dev);
+ if (res)
+ goto out;
+ res = asd_init_sata_pm_table_ddb(dev);
+ if (res)
+ asd_free_ddb(dev->port->ha->lldd_ha,
+ (int) (unsigned long) dev->lldd_dev);
+out:
+ return res;
+}
+
+int asd_dev_found(struct domain_device *dev)
+{
+ int res = 0;
+
+ switch (dev->dev_type) {
+ case SATA_PM:
+ res = asd_init_sata_pm_ddb(dev);
+ break;
+ case SATA_PM_PORT:
+ res = asd_init_sata_pm_port_ddb(dev);
+ break;
+ default:
+ if (dev->tproto)
+ res = asd_init_target_ddb(dev);
+ else
+ res = asd_init_initiator_ddb(dev);
+ }
+ return res;
+}
+
+void asd_dev_gone(struct domain_device *dev)
+{
+ int ddb, sister_ddb;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+
+ ddb = (int) (unsigned long) dev->lldd_dev;
+ sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
+
+ if (sister_ddb != 0xFFFF)
+ asd_free_ddb(asd_ha, sister_ddb);
+ asd_free_ddb(asd_ha, ddb);
+ dev->lldd_dev = NULL;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
new file mode 100644
index 00000000000..e6ade5996d9
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -0,0 +1,959 @@
+/*
+ * Aic94xx SAS/SATA driver dump interface.
+ *
+ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * 2005/07/14/LT Complete overhaul of this file. Update pages, register
+ * locations, names, etc. Make use of macros. Print more information.
+ * Print all cseq and lseq mip and mdp.
+ *
+ */
+
+#include "linux/pci.h"
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_reg_def.h"
+#include "aic94xx_sas.h"
+
+#include "aic94xx_dump.h"
+
+#ifdef ASD_DEBUG
+
+#define MD(x) (1 << (x))
+#define MODE_COMMON (1 << 31)
+#define MODE_0_7 (0xFF)
+
+static const struct lseq_cio_regs {
+ char *name;
+ u32 offs;
+ u8 width;
+ u32 mode;
+} LSEQmCIOREGS[] = {
+ {"LmMnSCBPTR", 0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+ {"LmMnDDBPTR", 0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+ {"LmREQMBX", 0x30, 32, MODE_COMMON },
+ {"LmRSPMBX", 0x34, 32, MODE_COMMON },
+ {"LmMnINT", 0x38, 32, MODE_0_7 },
+ {"LmMnINTEN", 0x3C, 32, MODE_0_7 },
+ {"LmXMTPRIMD", 0x40, 32, MODE_COMMON },
+ {"LmXMTPRIMCS", 0x44, 8, MODE_COMMON },
+ {"LmCONSTAT", 0x45, 8, MODE_COMMON },
+ {"LmMnDMAERRS", 0x46, 8, MD(0)|MD(1) },
+ {"LmMnSGDMAERRS", 0x47, 8, MD(0)|MD(1) },
+ {"LmMnEXPHDRP", 0x48, 8, MD(0) },
+ {"LmMnSASAALIGN", 0x48, 8, MD(1) },
+ {"LmMnMSKHDRP", 0x49, 8, MD(0) },
+ {"LmMnSTPALIGN", 0x49, 8, MD(1) },
+ {"LmMnRCVHDRP", 0x4A, 8, MD(0) },
+ {"LmMnXMTHDRP", 0x4A, 8, MD(1) },
+ {"LmALIGNMODE", 0x4B, 8, MD(1) },
+ {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) },
+ {"LmMnXMTCNT", 0x4C, 32, MD(1) },
+ {"LmMnCURRTAG", 0x54, 16, MD(0) },
+ {"LmMnPREVTAG", 0x56, 16, MD(0) },
+ {"LmMnACKOFS", 0x58, 8, MD(1) },
+ {"LmMnXFRLVL", 0x59, 8, MD(0)|MD(1) },
+ {"LmMnSGDMACTL", 0x5A, 8, MD(0)|MD(1) },
+ {"LmMnSGDMASTAT", 0x5B, 8, MD(0)|MD(1) },
+ {"LmMnDDMACTL", 0x5C, 8, MD(0)|MD(1) },
+ {"LmMnDDMASTAT", 0x5D, 8, MD(0)|MD(1) },
+ {"LmMnDDMAMODE", 0x5E, 16, MD(0)|MD(1) },
+ {"LmMnPIPECTL", 0x61, 8, MD(0)|MD(1) },
+ {"LmMnACTSCB", 0x62, 16, MD(0)|MD(1) },
+ {"LmMnSGBHADR", 0x64, 8, MD(0)|MD(1) },
+ {"LmMnSGBADR", 0x65, 8, MD(0)|MD(1) },
+ {"LmMnSGDCNT", 0x66, 8, MD(0)|MD(1) },
+ {"LmMnSGDMADR", 0x68, 32, MD(0)|MD(1) },
+ {"LmMnSGDMADR", 0x6C, 32, MD(0)|MD(1) },
+ {"LmMnXFRCNT", 0x70, 32, MD(0)|MD(1) },
+ {"LmMnXMTCRC", 0x74, 32, MD(1) },
+ {"LmCURRTAG", 0x74, 16, MD(0) },
+ {"LmPREVTAG", 0x76, 16, MD(0) },
+ {"LmMnDPSEL", 0x7B, 8, MD(0)|MD(1) },
+ {"LmDPTHSTAT", 0x7C, 8, MODE_COMMON },
+ {"LmMnHOLDLVL", 0x7D, 8, MD(0) },
+ {"LmMnSATAFS", 0x7E, 8, MD(1) },
+ {"LmMnCMPLTSTAT", 0x7F, 8, MD(0)|MD(1) },
+ {"LmPRMSTAT0", 0x80, 32, MODE_COMMON },
+ {"LmPRMSTAT1", 0x84, 32, MODE_COMMON },
+ {"LmGPRMINT", 0x88, 8, MODE_COMMON },
+ {"LmMnCURRSCB", 0x8A, 16, MD(0) },
+ {"LmPRMICODE", 0x8C, 32, MODE_COMMON },
+ {"LmMnRCVCNT", 0x90, 16, MD(0) },
+ {"LmMnBUFSTAT", 0x92, 16, MD(0) },
+ {"LmMnXMTHDRSIZE",0x92, 8, MD(1) },
+ {"LmMnXMTSIZE", 0x93, 8, MD(1) },
+ {"LmMnTGTXFRCNT", 0x94, 32, MD(0) },
+ {"LmMnEXPROFS", 0x98, 32, MD(0) },
+ {"LmMnXMTROFS", 0x98, 32, MD(1) },
+ {"LmMnRCVROFS", 0x9C, 32, MD(0) },
+ {"LmCONCTL", 0xA0, 16, MODE_COMMON },
+ {"LmBITLTIMER", 0xA2, 16, MODE_COMMON },
+ {"LmWWNLOW", 0xA8, 32, MODE_COMMON },
+ {"LmWWNHIGH", 0xAC, 32, MODE_COMMON },
+ {"LmMnFRMERR", 0xB0, 32, MD(0) },
+ {"LmMnFRMERREN", 0xB4, 32, MD(0) },
+ {"LmAWTIMER", 0xB8, 16, MODE_COMMON },
+ {"LmAWTCTL", 0xBA, 8, MODE_COMMON },
+ {"LmMnHDRCMPS", 0xC0, 32, MD(0) },
+ {"LmMnXMTSTAT", 0xC4, 8, MD(1) },
+ {"LmHWTSTATEN", 0xC5, 8, MODE_COMMON },
+ {"LmMnRRDYRC", 0xC6, 8, MD(0) },
+ {"LmMnRRDYTC", 0xC6, 8, MD(1) },
+ {"LmHWTSTAT", 0xC7, 8, MODE_COMMON },
+ {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) },
+ {"LmDWSSTATUS", 0xCB, 8, MODE_COMMON },
+ {"LmMnACTSTAT", 0xCE, 16, MD(0)|MD(1) },
+ {"LmMnREQSCB", 0xD2, 16, MD(0)|MD(1) },
+ {"LmXXXPRIM", 0xD4, 32, MODE_COMMON },
+ {"LmRCVASTAT", 0xD9, 8, MODE_COMMON },
+ {"LmINTDIS1", 0xDA, 8, MODE_COMMON },
+ {"LmPSTORESEL", 0xDB, 8, MODE_COMMON },
+ {"LmPSTORE", 0xDC, 32, MODE_COMMON },
+ {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON },
+ {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON },
+ {"LmDONETCTL", 0xF2, 16, MODE_COMMON },
+ {NULL, 0, 0, 0 }
+};
+/*
+static struct lseq_cio_regs LSEQmOOBREGS[] = {
+ {"OOB_BFLTR" ,0x100, 8, MD(5)},
+ {"OOB_INIT_MIN" ,0x102,16, MD(5)},
+ {"OOB_INIT_MAX" ,0x104,16, MD(5)},
+ {"OOB_INIT_NEG" ,0x106,16, MD(5)},
+ {"OOB_SAS_MIN" ,0x108,16, MD(5)},
+ {"OOB_SAS_MAX" ,0x10A,16, MD(5)},
+ {"OOB_SAS_NEG" ,0x10C,16, MD(5)},
+ {"OOB_WAKE_MIN" ,0x10E,16, MD(5)},
+ {"OOB_WAKE_MAX" ,0x110,16, MD(5)},
+ {"OOB_WAKE_NEG" ,0x112,16, MD(5)},
+ {"OOB_IDLE_MAX" ,0x114,16, MD(5)},
+ {"OOB_BURST_MAX" ,0x116,16, MD(5)},
+ {"OOB_XMIT_BURST" ,0x118, 8, MD(5)},
+ {"OOB_SEND_PAIRS" ,0x119, 8, MD(5)},
+ {"OOB_INIT_IDLE" ,0x11A, 8, MD(5)},
+ {"OOB_INIT_NEGO" ,0x11C, 8, MD(5)},
+ {"OOB_SAS_IDLE" ,0x11E, 8, MD(5)},
+ {"OOB_SAS_NEGO" ,0x120, 8, MD(5)},
+ {"OOB_WAKE_IDLE" ,0x122, 8, MD(5)},
+ {"OOB_WAKE_NEGO" ,0x124, 8, MD(5)},
+ {"OOB_DATA_KBITS" ,0x126, 8, MD(5)},
+ {"OOB_BURST_DATA" ,0x128,32, MD(5)},
+ {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)},
+ {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)},
+ {"OOB_SYNC_DATA" ,0x134,32, MD(5)},
+ {"OOB_D10_2_DATA" ,0x138,32, MD(5)},
+ {"OOB_PHY_RST_CNT" ,0x13C,32, MD(5)},
+ {"OOB_SIG_GEN" ,0x140, 8, MD(5)},
+ {"OOB_XMIT" ,0x141, 8, MD(5)},
+ {"FUNCTION_MAKS" ,0x142, 8, MD(5)},
+ {"OOB_MODE" ,0x143, 8, MD(5)},
+ {"CURRENT_STATUS" ,0x144, 8, MD(5)},
+ {"SPEED_MASK" ,0x145, 8, MD(5)},
+ {"PRIM_COUNT" ,0x146, 8, MD(5)},
+ {"OOB_SIGNALS" ,0x148, 8, MD(5)},
+ {"OOB_DATA_DET" ,0x149, 8, MD(5)},
+ {"OOB_TIME_OUT" ,0x14C, 8, MD(5)},
+ {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)},
+ {"OOB_STATUS" ,0x14E, 8, MD(5)},
+ {"HOT_PLUG_DELAY" ,0x150, 8, MD(5)},
+ {"RCD_DELAY" ,0x151, 8, MD(5)},
+ {"COMSAS_TIMER" ,0x152, 8, MD(5)},
+ {"SNTT_DELAY" ,0x153, 8, MD(5)},
+ {"SPD_CHNG_DELAY" ,0x154, 8, MD(5)},
+ {"SNLT_DELAY" ,0x155, 8, MD(5)},
+ {"SNWT_DELAY" ,0x156, 8, MD(5)},
+ {"ALIGN_DELAY" ,0x157, 8, MD(5)},
+ {"INT_ENABLE_0" ,0x158, 8, MD(5)},
+ {"INT_ENABLE_1" ,0x159, 8, MD(5)},
+ {"INT_ENABLE_2" ,0x15A, 8, MD(5)},
+ {"INT_ENABLE_3" ,0x15B, 8, MD(5)},
+ {"OOB_TEST_REG" ,0x15C, 8, MD(5)},
+ {"PHY_CONTROL_0" ,0x160, 8, MD(5)},
+ {"PHY_CONTROL_1" ,0x161, 8, MD(5)},
+ {"PHY_CONTROL_2" ,0x162, 8, MD(5)},
+ {"PHY_CONTROL_3" ,0x163, 8, MD(5)},
+ {"PHY_OOB_CAL_TX" ,0x164, 8, MD(5)},
+ {"PHY_OOB_CAL_RX" ,0x165, 8, MD(5)},
+ {"OOB_PHY_CAL_TX" ,0x166, 8, MD(5)},
+ {"OOB_PHY_CAL_RX" ,0x167, 8, MD(5)},
+ {"PHY_CONTROL_4" ,0x168, 8, MD(5)},
+ {"PHY_TEST" ,0x169, 8, MD(5)},
+ {"PHY_PWR_CTL" ,0x16A, 8, MD(5)},
+ {"PHY_PWR_DELAY" ,0x16B, 8, MD(5)},
+ {"OOB_SM_CON" ,0x16C, 8, MD(5)},
+ {"ADDR_TRAP_1" ,0x16D, 8, MD(5)},
+ {"ADDR_NEXT_1" ,0x16E, 8, MD(5)},
+ {"NEXT_ST_1" ,0x16F, 8, MD(5)},
+ {"OOB_SM_STATE" ,0x170, 8, MD(5)},
+ {"ADDR_TRAP_2" ,0x171, 8, MD(5)},
+ {"ADDR_NEXT_2" ,0x172, 8, MD(5)},
+ {"NEXT_ST_2" ,0x173, 8, MD(5)},
+ {NULL, 0, 0, 0 }
+};
+*/
+#define STR_8BIT " %30s[0x%04x]:0x%02x\n"
+#define STR_16BIT " %30s[0x%04x]:0x%04x\n"
+#define STR_32BIT " %30s[0x%04x]:0x%08x\n"
+#define STR_64BIT " %30s[0x%04x]:0x%llx\n"
+
+#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n, \
+ asd_read_reg_byte(_ha, _r))
+#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n, \
+ asd_read_reg_word(_ha, _r))
+#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n, \
+ asd_read_reg_dword(_ha, _r))
+
+#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n, \
+ asd_read_reg_byte(_ha, C##_n))
+#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n, \
+ asd_read_reg_word(_ha, C##_n))
+#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n, \
+ asd_read_reg_dword(_ha, C##_n))
+
+#define MSTR_8BIT " Mode:%02d %30s[0x%04x]:0x%02x\n"
+#define MSTR_16BIT " Mode:%02d %30s[0x%04x]:0x%04x\n"
+#define MSTR_32BIT " Mode:%02d %30s[0x%04x]:0x%08x\n"
+
+#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n, \
+ asd_read_reg_byte(_ha, _r))
+#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \
+ asd_read_reg_word(_ha, _r))
+#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \
+ asd_read_reg_dword(_ha, _r))
+
+/* can also be used for MD when the register is mode aware already */
+#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_byte(_ha, CSEQ_##_n))
+#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_word(_ha, CSEQ_##_n))
+#define PRINT_MIS_dword(_ha, _n) \
+ asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_dword(_ha, CSEQ_##_n))
+#define PRINT_MIS_qword(_ha, _n) \
+ asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR, \
+ (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n)) \
+ | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32)))
+
+#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n)
+#define PRINT_CMDP_word(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+ #_n, \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 7)))
+
+#define PRINT_CMDP_byte(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+ #_n, \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 7)))
+
+static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha)
+{
+ int mode;
+
+ asd_printk("CSEQ STATE\n");
+
+ asd_printk("ARP2 REGISTERS\n");
+
+ PRINT_CREG_32bit(asd_ha, ARP2CTL);
+ PRINT_CREG_32bit(asd_ha, ARP2INT);
+ PRINT_CREG_32bit(asd_ha, ARP2INTEN);
+ PRINT_CREG_8bit(asd_ha, MODEPTR);
+ PRINT_CREG_8bit(asd_ha, ALTMODE);
+ PRINT_CREG_8bit(asd_ha, FLAG);
+ PRINT_CREG_8bit(asd_ha, ARP2INTCTL);
+ PRINT_CREG_16bit(asd_ha, STACK);
+ PRINT_CREG_16bit(asd_ha, PRGMCNT);
+ PRINT_CREG_16bit(asd_ha, ACCUM);
+ PRINT_CREG_16bit(asd_ha, SINDEX);
+ PRINT_CREG_16bit(asd_ha, DINDEX);
+ PRINT_CREG_8bit(asd_ha, SINDIR);
+ PRINT_CREG_8bit(asd_ha, DINDIR);
+ PRINT_CREG_8bit(asd_ha, JUMLDIR);
+ PRINT_CREG_8bit(asd_ha, ARP2HALTCODE);
+ PRINT_CREG_16bit(asd_ha, CURRADDR);
+ PRINT_CREG_16bit(asd_ha, LASTADDR);
+ PRINT_CREG_16bit(asd_ha, NXTLADDR);
+
+ asd_printk("IOP REGISTERS\n");
+
+ PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL);
+ PRINT_CREG_32bit(asd_ha, MAPPEDSCR);
+
+ asd_printk("CIO REGISTERS\n");
+
+ for (mode = 0; mode < 9; mode++)
+ PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode));
+ PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15));
+
+ for (mode = 0; mode < 9; mode++)
+ PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode));
+ PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15));
+
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode));
+
+ PRINT_CREG_8bit(asd_ha, SCRATCHPAGE);
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE,
+ CMnSCRATCHPAGE(mode));
+
+ PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON);
+ PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK);
+ PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST);
+ PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE);
+ PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC);
+ PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS);
+
+ asd_printk("SCRATCH MEMORY\n");
+
+ asd_printk("MIP 4 >>>>>\n");
+ PRINT_MIS_word(asd_ha, Q_EXE_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EXE_TAIL);
+ PRINT_MIS_word(asd_ha, Q_DONE_HEAD);
+ PRINT_MIS_word(asd_ha, Q_DONE_TAIL);
+ PRINT_MIS_word(asd_ha, Q_SEND_HEAD);
+ PRINT_MIS_word(asd_ha, Q_SEND_TAIL);
+ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD);
+ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL);
+ PRINT_MIS_word(asd_ha, Q_COPY_HEAD);
+ PRINT_MIS_word(asd_ha, Q_COPY_TAIL);
+ PRINT_MIS_word(asd_ha, REG0);
+ PRINT_MIS_word(asd_ha, REG1);
+ PRINT_MIS_dword(asd_ha, REG2);
+ PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP);
+ PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE);
+ PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT);
+
+ asd_printk("MIP 5 >>>>\n");
+ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE);
+ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT);
+ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL);
+ PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET);
+
+ asd_printk("MIP 6 >>>>\n");
+ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0);
+ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1);
+ PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR);
+ PRINT_MIS_byte(asd_ha, INT_ROUT_MODE);
+ PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS);
+ PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX);
+ PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX);
+ PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD);
+ PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL);
+ PRINT_MIS_byte(asd_ha, FREE_SCB_MASK);
+ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD);
+ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL);
+ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD);
+ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL);
+
+ asd_printk("MIP 7 >>>>\n");
+ PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE);
+ PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT);
+ PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL);
+ PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB);
+ PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD);
+ PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL);
+ PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET);
+ PRINT_MIS_word(asd_ha, PRIMITIVE_DATA);
+ PRINT_MIS_dword(asd_ha, TIMEOUT_CONST);
+
+ asd_printk("MDP 0 >>>>\n");
+ asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7");
+ PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX);
+ PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR);
+ PRINT_CMDP_word(asd_ha, Q_LINK_HEAD);
+ PRINT_CMDP_word(asd_ha, Q_LINK_TAIL);
+ PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE);
+
+ asd_printk("MDP 0 Mode 8 >>>>\n");
+ PRINT_MIS_word(asd_ha, RET_ADDR);
+ PRINT_MIS_word(asd_ha, RET_SCBPTR);
+ PRINT_MIS_word(asd_ha, SAVE_SCBPTR);
+ PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX);
+ PRINT_MIS_word(asd_ha, RESP_LEN);
+ PRINT_MIS_word(asd_ha, TMF_SCBPTR);
+ PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB);
+ PRINT_MIS_word(asd_ha, GLOBAL_HEAD);
+ PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD);
+ PRINT_MIS_byte(asd_ha, TMF_OPCODE);
+ PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS);
+ PRINT_MIS_word(asd_ha, HSB_SITE);
+ PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE);
+ PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE);
+
+ asd_printk("MDP 1 Mode 8 >>>>\n");
+ PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR);
+ PRINT_MIS_qword(asd_ha, LUN_TO_CHECK);
+
+ asd_printk("MDP 2 Mode 8 >>>>\n");
+ PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER);
+ PRINT_MIS_qword(asd_ha, HQ_DONE_BASE);
+ PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER);
+ PRINT_MIS_byte(asd_ha, HQ_DONE_PASS);
+}
+
+#define PRINT_LREG_8bit(_h, _lseq, _n) \
+ asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_16bit(_h, _lseq, _n) \
+ asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_32bit(_h, _lseq, _n) \
+ asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq)))
+
+#define PRINT_LMIP_byte(_h, _lseq, _n) \
+ asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_byte(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_word(_h, _lseq, _n) \
+ asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_word(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_dword(_h, _lseq, _n) \
+ asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_qword(_h, _lseq, _n) \
+ asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ (unsigned long long)(((unsigned long long) \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \
+ | (((unsigned long long) \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32)))
+
+static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha,
+ u32 lseq_cio_addr, int i)
+{
+ switch (LSEQmCIOREGS[i].width) {
+ case 8:
+ asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_byte(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+
+ break;
+ case 16:
+ asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_word(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+
+ break;
+ case 32:
+ asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_dword(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+ break;
+ }
+}
+
+static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 moffs;
+ int mode;
+
+ asd_printk("LSEQ %d STATE\n", lseq);
+
+ asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2INT);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN);
+ PRINT_LREG_8bit(asd_ha, lseq, MODEPTR);
+ PRINT_LREG_8bit(asd_ha, lseq, ALTMODE);
+ PRINT_LREG_8bit(asd_ha, lseq, FLAG);
+ PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL);
+ PRINT_LREG_16bit(asd_ha, lseq, STACK);
+ PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT);
+ PRINT_LREG_16bit(asd_ha, lseq, ACCUM);
+ PRINT_LREG_16bit(asd_ha, lseq, SINDEX);
+ PRINT_LREG_16bit(asd_ha, lseq, DINDEX);
+ PRINT_LREG_8bit(asd_ha, lseq, SINDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, DINDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE);
+ PRINT_LREG_16bit(asd_ha, lseq, CURRADDR);
+ PRINT_LREG_16bit(asd_ha, lseq, LASTADDR);
+ PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR);
+
+ asd_printk("LSEQ%d: IOP REGISTERS\n", lseq);
+
+ PRINT_LREG_32bit(asd_ha, lseq, MODECTL);
+ PRINT_LREG_32bit(asd_ha, lseq, DBGMODE);
+ PRINT_LREG_32bit(asd_ha, lseq, CONTROL);
+ PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq));
+ PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq));
+
+ asd_printk("LSEQ%d: CIO REGISTERS\n", lseq);
+ asd_printk("Mode common:\n");
+
+ for (mode = 0; mode < 8; mode++) {
+ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+ int i;
+
+ for (i = 0; LSEQmCIOREGS[i].name; i++)
+ if (LSEQmCIOREGS[i].mode == MODE_COMMON)
+ asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i);
+ }
+
+ asd_printk("Mode unique:\n");
+ for (mode = 0; mode < 8; mode++) {
+ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+ int i;
+
+ asd_printk("Mode %d\n", mode);
+ for (i = 0; LSEQmCIOREGS[i].name; i++) {
+ if (!(LSEQmCIOREGS[i].mode & (1 << mode)))
+ continue;
+ asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i);
+ }
+ }
+
+ asd_printk("SCRATCH MEMORY\n");
+
+ asd_printk("LSEQ%d MIP 0 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD);
+ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
+ PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
+ PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
+ PRINT_LMIP_word(asd_ha, lseq, CONCTL);
+ PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
+ PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
+ PRINT_LMIP_word(asd_ha, lseq, REG1_ISR);
+ PRINT_LMIP_word(asd_ha, lseq, REG2_ISR);
+ PRINT_LMIP_word(asd_ha, lseq, REG3_ISR);
+ PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR);
+
+ asd_printk("LSEQ%d MIP 1 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL);
+ PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST);
+ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX);
+ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX);
+
+ asd_printk("LSEQ%d MIP 2 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL);
+
+ asd_printk("LSEQ%d MIP 3 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST);
+ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT);
+
+ for (mode = 0; mode < 3; mode++) {
+ asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode);
+ moffs = mode * LSEQ_MODE_SCRATCH_SIZE;
+
+ asd_printk(STR_16BIT, "RET_ADDR", 0,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "REG0_MODE", 2,
+ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)
+ + moffs));
+ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)
+ + moffs));
+ }
+
+ asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq);
+ moffs = LSEQ_MODE5_PAGE0_OFFSET;
+ asd_printk(STR_16BIT, "RET_ADDR", 0,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs));
+ asd_printk(STR_16BIT, "REG0_MODE", 2,
+ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs));
+ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs));
+ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs));
+ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs));
+
+ asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX);
+ PRINT_LMIP_word(asd_ha, lseq, RESP_LEN);
+ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE);
+ PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL);
+ PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR);
+
+ asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD);
+ PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX);
+ PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG);
+ PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE);
+ PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE);
+ PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR);
+
+ asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER);
+ PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR);
+ PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE);
+ PRINT_LMIP_word(asd_ha, lseq, IP_BITL);
+ PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG);
+ PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH);
+
+ asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE);
+ PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS);
+ PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT);
+ PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES);
+ PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES);
+ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT);
+ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT);
+
+ asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0);
+ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1);
+
+ asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0);
+ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1);
+
+ asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT);
+ PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT);
+ PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT);
+
+ asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK);
+ PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT);
+ PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK);
+ PRINT_LMIP_word(asd_ha, lseq, TAG_MASK);
+ PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG);
+ PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET);
+
+ asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS);
+ PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_DDB);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG);
+
+ asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME);
+ PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL);
+
+ asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS);
+
+ asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS);
+}
+
+/**
+ * asd_dump_ddb_site -- dump a CSEQ DDB site
+ * @asd_ha: pointer to host adapter structure
+ * @site_no: site number of interest
+ */
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+ if (site_no >= asd_ha->hw_prof.max_ddbs)
+ return;
+
+#define DDB_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+#define DDB2_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, site_no, \
+ offsetof(struct asd_ddb_stp_sata_target_port, __name))
+#define DDB_FIELDW(__name) \
+ asd_ddbsite_read_word(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+#define DDB_FIELDD(__name) \
+ asd_ddbsite_read_dword(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+ asd_printk("DDB: 0x%02x\n", site_no);
+ asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type));
+ asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate));
+ asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag)));
+ asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head)));
+ asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended));
+ asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type));
+ asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def));
+ asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features));
+ asd_printk("Pathway Blocked Count: 0x%02x\n",
+ DDB_FIELDB(pathway_blocked_count));
+ asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time));
+ asd_printk("more_compat_features: 0x%08x\n",
+ DDB_FIELDD(more_compat_features));
+ asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask));
+ asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags));
+ asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2));
+ asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail));
+ asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail));
+ asd_printk("Active Task Count: 0x%04x\n",
+ DDB_FIELDW(active_task_count));
+ asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason));
+ asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout));
+ asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp));
+}
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha)
+{
+#define DDB0_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name))
+#define DDB0_FIELDW(__name) \
+ asd_ddbsite_read_word(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDD(__name) \
+ asd_ddbsite_read_dword(asd_ha,0 , \
+ offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDA(__name, _o) \
+ asd_ddbsite_read_byte(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name)+_o)
+
+
+ asd_printk("DDB: 0\n");
+ asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head));
+ asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail));
+ asd_printk("q_free_ddb_cnt:%04x\n", DDB0_FIELDW(q_free_ddb_cnt));
+ asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head));
+ asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail));
+ asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock));
+ asd_printk("smp_conn_tag:%04x\n", DDB0_FIELDW(smp_conn_tag));
+ asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt));
+ asd_printk("est_nexus_buf_thresh:%04x\n",
+ DDB0_FIELDW(est_nexus_buf_thresh));
+ asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active));
+ asd_printk("phy_is_up:%02x\n", DDB0_FIELDB(phy_is_up));
+ asd_printk("port_map_by_links:%02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n",
+ DDB0_FIELDA(port_map_by_links, 0),
+ DDB0_FIELDA(port_map_by_links, 1),
+ DDB0_FIELDA(port_map_by_links, 2),
+ DDB0_FIELDA(port_map_by_links, 3),
+ DDB0_FIELDA(port_map_by_links, 4),
+ DDB0_FIELDA(port_map_by_links, 5),
+ DDB0_FIELDA(port_map_by_links, 6),
+ DDB0_FIELDA(port_map_by_links, 7));
+}
+
+static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+
+#define SCB_FIELDB(__name) \
+ asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDW(__name) \
+ asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDD(__name) \
+ asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+
+ asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len));
+ asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type));
+ asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag));
+ asd_printk("Target Port Xfer Tag: 0x%04x.\n",
+ SCB_FIELDW(ssp_frame.tptt));
+ asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs));
+ asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count));
+}
+
+/**
+ * asd_dump_scb_sites -- dump currently used CSEQ SCB sites
+ * @asd_ha: pointer to host adapter struct
+ */
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha)
+{
+ u16 site_no;
+
+ for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) {
+ u8 opcode;
+
+ if (!SCB_SITE_VALID(site_no))
+ continue;
+
+ /* We are only interested in SCB sites currently used.
+ */
+ opcode = asd_scbsite_read_byte(asd_ha, site_no,
+ offsetof(struct scb_header,
+ opcode));
+ if (opcode == 0xFF)
+ continue;
+
+ asd_printk("\nSCB: 0x%x\n", site_no);
+ asd_dump_scb_site(asd_ha, site_no);
+ }
+}
+
+/**
+ * ads_dump_seq_state -- dump CSEQ and LSEQ states
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of LSEQs of interest
+ */
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+
+ asd_dump_cseq_state(asd_ha);
+
+ if (lseq_mask != 0)
+ for_each_sequencer(lseq_mask, lseq_mask, lseq)
+ asd_dump_lseq_state(asd_ha, lseq);
+}
+
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl)
+{
+ unsigned long flags;
+ int i;
+
+ switch ((dl->status_block[1] & 0x70) >> 3) {
+ case SAS_PROTO_STP:
+ ASD_DPRINTK("STP proto device-to-host FIS:\n");
+ break;
+ default:
+ case SAS_PROTO_SSP:
+ ASD_DPRINTK("SAS proto IDENTIFY:\n");
+ break;
+ }
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4)
+ ASD_DPRINTK("%02x: %02x %02x %02x %02x\n",
+ i,
+ phy->frame_rcvd[i],
+ phy->frame_rcvd[i+1],
+ phy->frame_rcvd[i+2],
+ phy->frame_rcvd[i+3]);
+ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+}
+
+static inline void asd_dump_scb(struct asd_ascb *ascb, int ind)
+{
+ asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ind, ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+}
+
+void asd_dump_scb_list(struct asd_ascb *ascb, int num)
+{
+ int i = 0;
+
+ asd_printk("dumping %d scbs:\n", num);
+
+ asd_dump_scb(ascb, i++);
+ --num;
+
+ if (num > 0 && !list_empty(&ascb->list)) {
+ struct list_head *el;
+
+ list_for_each(el, &ascb->list) {
+ struct asd_ascb *s = list_entry(el, struct asd_ascb,
+ list);
+ asd_dump_scb(s, i++);
+ if (--num <= 0)
+ break;
+ }
+ }
+}
+
+#endif /* ASD_DEBUG */
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h
new file mode 100644
index 00000000000..0c388e7da6b
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dump.h
@@ -0,0 +1,52 @@
+/*
+ * Aic94xx SAS/SATA driver dump header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_DUMP_H_
+#define _AIC94XX_DUMP_H_
+
+#ifdef ASD_DEBUG
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl);
+void asd_dump_scb_list(struct asd_ascb *ascb, int num);
+#else /* ASD_DEBUG */
+
+static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
+ u16 site_no) { }
+static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
+ u8 lseq_mask) { }
+static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl) { }
+static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
+#endif /* ASD_DEBUG */
+
+#endif /* _AIC94XX_DUMP_H_ */
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
new file mode 100644
index 00000000000..1d8c5e5f442
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -0,0 +1,1376 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+u32 MBAR0_SWB_SIZE;
+
+/* ---------- Initialization ---------- */
+
+static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
+{
+ extern char sas_addr_str[];
+ /* If the user has specified a WWN it overrides other settings
+ */
+ if (sas_addr_str[0] != '\0')
+ asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,
+ sas_addr_str);
+ else if (asd_ha->hw_prof.sas_addr[0] != 0)
+ asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);
+}
+
+static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
+ continue;
+ /* Set a phy's address only if it has none.
+ */
+ ASD_DPRINTK("setting phy%d addr to %llx\n", i,
+ SAS_ADDR(asd_ha->hw_prof.sas_addr));
+ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
+ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+ }
+}
+
+/* ---------- PHY initialization ---------- */
+
+static void asd_init_phy_identify(struct asd_phy *phy)
+{
+ phy->identify_frame = phy->id_frm_tok->vaddr;
+
+ memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
+
+ phy->identify_frame->dev_type = SAS_END_DEV;
+ if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
+ phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
+ if (phy->sas_phy.role & PHY_ROLE_TARGET)
+ phy->identify_frame->target_bits = phy->sas_phy.tproto;
+ memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
+ SAS_ADDR_SIZE);
+ phy->identify_frame->phy_id = phy->sas_phy.id;
+}
+
+static int asd_init_phy(struct asd_phy *phy)
+{
+ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ sas_phy->enabled = 1;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTO_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ phy->id_frm_tok = asd_alloc_coherent(asd_ha,
+ sizeof(*phy->identify_frame),
+ GFP_KERNEL);
+ if (!phy->id_frm_tok) {
+ asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
+ return -ENOMEM;
+ } else
+ asd_init_phy_identify(phy);
+
+ memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
+
+ return 0;
+}
+
+static int asd_init_phys(struct asd_ha_struct *asd_ha)
+{
+ u8 i;
+ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ struct asd_phy *phy = &asd_ha->phys[i];
+
+ phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
+
+ phy->sas_phy.enabled = 0;
+ phy->sas_phy.id = i;
+ phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
+ phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
+ phy->sas_phy.ha = &asd_ha->sas_ha;
+ phy->sas_phy.lldd_phy = phy;
+ }
+
+ /* Now enable and initialize only the enabled phys. */
+ for_each_phy(phy_mask, phy_mask, i) {
+ int err = asd_init_phy(&asd_ha->phys[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* ---------- Sliding windows ---------- */
+
+static int asd_init_sw(struct asd_ha_struct *asd_ha)
+{
+ struct pci_dev *pcidev = asd_ha->pcidev;
+ int err;
+ u32 v;
+
+ /* Unlock MBARs */
+ err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
+ if (err) {
+ asd_printk("couldn't access conf. space of %s\n",
+ pci_name(pcidev));
+ goto Err;
+ }
+ if (v)
+ err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
+ if (err) {
+ asd_printk("couldn't write to MBAR_KEY of %s\n",
+ pci_name(pcidev));
+ goto Err;
+ }
+
+ /* Set sliding windows A, B and C to point to proper internal
+ * memory regions.
+ */
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
+ REG_BASE_ADDR_CSEQCIO);
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
+ asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
+ asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
+ asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
+ MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
+ if (!asd_ha->iospace) {
+ /* MBAR1 will point to OCM (On Chip Memory) */
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
+ asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
+ }
+ spin_lock_init(&asd_ha->iolock);
+Err:
+ return err;
+}
+
+/* ---------- SCB initialization ---------- */
+
+/**
+ * asd_init_scbs - manually allocate the first SCB.
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This allocates the very first SCB which would be sent to the
+ * sequencer for execution. Its bus address is written to
+ * CSEQ_Q_NEW_POINTER, mode page 2, mode 8. Since the bus address of
+ * the _next_ scb to be DMA-ed to the host adapter is read from the last
+ * SCB DMA-ed to the host adapter, we have to always stay one step
+ * ahead of the sequencer and keep one SCB already allocated.
+ */
+static int asd_init_scbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int bitmap_bytes;
+
+ /* allocate the index array and bitmap */
+ asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
+ asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
+ sizeof(void *), GFP_KERNEL);
+ if (!asd_ha->seq.tc_index_array)
+ return -ENOMEM;
+
+ bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
+ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+ asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+ if (!asd_ha->seq.tc_index_bitmap)
+ return -ENOMEM;
+
+ spin_lock_init(&seq->tc_index_lock);
+
+ seq->next_scb.size = sizeof(struct scb);
+ seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
+ &seq->next_scb.dma_handle);
+ if (!seq->next_scb.vaddr) {
+ kfree(asd_ha->seq.tc_index_bitmap);
+ kfree(asd_ha->seq.tc_index_array);
+ asd_ha->seq.tc_index_bitmap = NULL;
+ asd_ha->seq.tc_index_array = NULL;
+ return -ENOMEM;
+ }
+
+ seq->pending = 0;
+ spin_lock_init(&seq->pend_q_lock);
+ INIT_LIST_HEAD(&seq->pend_q);
+
+ return 0;
+}
+
+static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
+ asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
+ ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
+ asd_ha->hw_prof.max_scbs,
+ asd_ha->hw_prof.max_ddbs);
+}
+
+/* ---------- Done List initialization ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long);
+
+static int asd_init_dl(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->seq.actual_dl
+ = asd_alloc_coherent(asd_ha,
+ ASD_DL_SIZE * sizeof(struct done_list_struct),
+ GFP_KERNEL);
+ if (!asd_ha->seq.actual_dl)
+ return -ENOMEM;
+ asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
+ asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
+ asd_ha->seq.dl_next = 0;
+ tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
+ (unsigned long) asd_ha);
+
+ return 0;
+}
+
+/* ---------- EDB and ESCB init ---------- */
+
+static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
+ if (!seq->edb_arr)
+ return -ENOMEM;
+
+ for (i = 0; i < seq->num_edbs; i++) {
+ seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
+ gfp_flags);
+ if (!seq->edb_arr[i])
+ goto Err_unroll;
+ memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
+ }
+
+ ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
+
+ return 0;
+
+Err_unroll:
+ for (i-- ; i >= 0; i--)
+ asd_free_coherent(asd_ha, seq->edb_arr[i]);
+ kfree(seq->edb_arr);
+ seq->edb_arr = NULL;
+
+ return -ENOMEM;
+}
+
+static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
+ gfp_t gfp_flags)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *escb;
+ int i, escbs;
+
+ seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
+ gfp_flags);
+ if (!seq->escb_arr)
+ return -ENOMEM;
+
+ escbs = seq->num_escbs;
+ escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
+ if (!escb) {
+ asd_printk("couldn't allocate list of escbs\n");
+ goto Err;
+ }
+ seq->num_escbs -= escbs; /* subtract what was not allocated */
+ ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
+
+ for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
+ struct asd_ascb,
+ list)) {
+ seq->escb_arr[i] = escb;
+ escb->scb->header.opcode = EMPTY_SCB;
+ }
+
+ return 0;
+Err:
+ kfree(seq->escb_arr);
+ seq->escb_arr = NULL;
+ return -ENOMEM;
+
+}
+
+static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i, k, z = 0;
+
+ for (i = 0; i < seq->num_escbs; i++) {
+ struct asd_ascb *ascb = seq->escb_arr[i];
+ struct empty_scb *escb = &ascb->scb->escb;
+
+ ascb->edb_index = z;
+
+ escb->num_valid = ASD_EDBS_PER_SCB;
+
+ for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
+ struct sg_el *eb = &escb->eb[k];
+ struct asd_dma_tok *edb = seq->edb_arr[z++];
+
+ memset(eb, 0, sizeof(*eb));
+ eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
+ eb->size = cpu_to_le32(((u32) edb->size));
+ }
+ }
+}
+
+/**
+ * asd_init_escbs -- allocate and initialize empty scbs
+ * @asd_ha: pointer to host adapter structure
+ *
+ * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
+ * They transport sense data, etc.
+ */
+static int asd_init_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int err = 0;
+
+ /* Allocate two empty data buffers (edb) per sequencer. */
+ int edbs = 2*(1+asd_ha->hw_prof.num_phys);
+
+ seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
+ seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
+
+ err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
+ if (err) {
+ asd_printk("couldn't allocate edbs\n");
+ return err;
+ }
+
+ err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
+ if (err) {
+ asd_printk("couldn't allocate escbs\n");
+ return err;
+ }
+
+ asd_assign_edbs2escbs(asd_ha);
+ /* In order to insure that normal SCBs do not overfill sequencer
+ * memory and leave no space for escbs (halting condition),
+ * we increment pending here by the number of escbs. However,
+ * escbs are never pending.
+ */
+ seq->pending = seq->num_escbs;
+ seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
+
+ return 0;
+}
+
+/* ---------- HW initialization ---------- */
+
+/**
+ * asd_chip_hardrst -- hard reset the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This takes 16 cycles and is synchronous to CFCLK, which runs
+ * at 200 MHz, so this should take at most 80 nanoseconds.
+ */
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ int count = 100;
+ u32 reg;
+
+ for (i = 0 ; i < 4 ; i++) {
+ asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
+ }
+
+ do {
+ udelay(1);
+ reg = asd_read_reg_dword(asd_ha, CHIMINT);
+ if (reg & HARDRSTDET) {
+ asd_write_reg_dword(asd_ha, CHIMINT,
+ HARDRSTDET|PORRSTDET);
+ return 0;
+ }
+ } while (--count > 0);
+
+ return -ENODEV;
+}
+
+/**
+ * asd_init_chip -- initialize the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Hard resets the chip, disables HA interrupts, downloads the sequnecer
+ * microcode and starts the sequencers. The caller has to explicitly
+ * enable HA interrupts with asd_enable_ints(asd_ha).
+ */
+static int asd_init_chip(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_chip_hardrst(asd_ha);
+ if (err) {
+ asd_printk("couldn't hard reset %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+
+ asd_disable_ints(asd_ha);
+
+ err = asd_init_seqs(asd_ha);
+ if (err) {
+ asd_printk("couldn't init seqs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+
+ err = asd_start_seqs(asd_ha);
+ if (err) {
+ asd_printk("coudln't start seqs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+out:
+ return err;
+}
+
+#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
+
+static int max_devs = 0;
+module_param_named(max_devs, max_devs, int, S_IRUGO);
+MODULE_PARM_DESC(max_devs, "\n"
+ "\tMaximum number of SAS devices to support (not LUs).\n"
+ "\tDefault: 2176, Maximum: 65663.\n");
+
+static int max_cmnds = 0;
+module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
+MODULE_PARM_DESC(max_cmnds, "\n"
+ "\tMaximum number of commands queuable.\n"
+ "\tDefault: 512, Maximum: 66047.\n");
+
+static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
+{
+ unsigned long dma_addr = OCM_BASE_ADDR;
+ u32 d;
+
+ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+ asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d |= 4;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+ asd_ha->hw_prof.max_ddbs += MAX_DEVS;
+}
+
+static int asd_extend_devctx(struct asd_ha_struct *asd_ha)
+{
+ dma_addr_t dma_handle;
+ unsigned long dma_addr;
+ u32 d;
+ int size;
+
+ asd_extend_devctx_ocm(asd_ha);
+
+ asd_ha->hw_prof.ddb_ext = NULL;
+ if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
+ max_devs = asd_ha->hw_prof.max_ddbs;
+ return 0;
+ }
+
+ size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
+
+ asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ddb_ext) {
+ asd_printk("couldn't allocate memory for %d devices\n",
+ max_devs);
+ max_devs = asd_ha->hw_prof.max_ddbs;
+ return -ENOMEM;
+ }
+ dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
+ dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
+ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+ dma_handle = (dma_addr_t) dma_addr;
+ asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d &= ~4;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+ asd_ha->hw_prof.max_ddbs = max_devs;
+
+ return 0;
+}
+
+static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
+{
+ dma_addr_t dma_handle;
+ unsigned long dma_addr;
+ u32 d;
+ int size;
+
+ asd_ha->hw_prof.scb_ext = NULL;
+ if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
+ max_cmnds = asd_ha->hw_prof.max_scbs;
+ return 0;
+ }
+
+ size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
+
+ asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.scb_ext) {
+ asd_printk("couldn't allocate memory for %d commands\n",
+ max_cmnds);
+ max_cmnds = asd_ha->hw_prof.max_scbs;
+ return -ENOMEM;
+ }
+ dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
+ dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
+ dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
+ dma_handle = (dma_addr_t) dma_addr;
+ asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d &= ~1;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+ asd_ha->hw_prof.max_scbs = max_cmnds;
+
+ return 0;
+}
+
+/**
+ * asd_init_ctxmem -- initialize context memory
+ * asd_ha: pointer to host adapter structure
+ *
+ * This function sets the maximum number of SCBs and
+ * DDBs which can be used by the sequencer. This is normally
+ * 512 and 128 respectively. If support for more SCBs or more DDBs
+ * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
+ * initialized here to extend context memory to point to host memory,
+ * thus allowing unlimited support for SCBs and DDBs -- only limited
+ * by host memory.
+ */
+static int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
+{
+ int bitmap_bytes;
+
+ asd_get_max_scb_ddb(asd_ha);
+ asd_extend_devctx(asd_ha);
+ asd_extend_cmdctx(asd_ha);
+
+ /* The kernel wants bitmaps to be unsigned long sized. */
+ bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
+ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+ asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ddb_bitmap)
+ return -ENOMEM;
+ spin_lock_init(&asd_ha->hw_prof.ddb_lock);
+
+ return 0;
+}
+
+int asd_init_hw(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u32 v;
+
+ err = asd_init_sw(asd_ha);
+ if (err)
+ return err;
+
+ err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);
+ if (err) {
+ asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+ pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
+ v | SC_TMR_DIS);
+ if (err) {
+ asd_printk("couldn't disable split completion timer of %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ err = asd_read_ocm(asd_ha);
+ if (err) {
+ asd_printk("couldn't read ocm(%d)\n", err);
+ /* While suspicios, it is not an error that we
+ * couldn't read the OCM. */
+ }
+
+ err = asd_read_flash(asd_ha);
+ if (err) {
+ asd_printk("couldn't read flash(%d)\n", err);
+ /* While suspicios, it is not an error that we
+ * couldn't read FLASH memory.
+ */
+ }
+
+ asd_init_ctxmem(asd_ha);
+
+ asd_get_user_sas_addr(asd_ha);
+ if (!asd_ha->hw_prof.sas_addr[0]) {
+ asd_printk("No SAS Address provided for %s\n",
+ pci_name(asd_ha->pcidev));
+ err = -ENODEV;
+ goto Out;
+ }
+
+ asd_propagate_sas_addr(asd_ha);
+
+ err = asd_init_phys(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize phys for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Out;
+ }
+
+ err = asd_init_scbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize scbs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Out;
+ }
+
+ err = asd_init_dl(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize the done list:%d\n",
+ err);
+ goto Out;
+ }
+
+ err = asd_init_escbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize escbs\n");
+ goto Out;
+ }
+
+ err = asd_init_chip(asd_ha);
+ if (err) {
+ asd_printk("couldn't init the chip\n");
+ goto Out;
+ }
+Out:
+ return err;
+}
+
+/* ---------- Chip reset ---------- */
+
+/**
+ * asd_chip_reset -- reset the host adapter, etc
+ * @asd_ha: pointer to host adapter structure of interest
+ *
+ * Called from the ISR. Hard reset the chip. Let everything
+ * timeout. This should be no different than hot-unplugging the
+ * host adapter. Once everything times out we'll init the chip with
+ * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
+ * XXX finish.
+ */
+static void asd_chip_reset(struct asd_ha_struct *asd_ha)
+{
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+
+ ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
+ asd_chip_hardrst(asd_ha);
+ sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+}
+
+/* ---------- Done List Routines ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long data)
+{
+ struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
+ struct asd_seq_data *seq = &asd_ha->seq;
+ unsigned long flags;
+
+ while (1) {
+ struct done_list_struct *dl = &seq->dl[seq->dl_next];
+ struct asd_ascb *ascb;
+
+ if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
+ break;
+
+ /* find the aSCB */
+ spin_lock_irqsave(&seq->tc_index_lock, flags);
+ ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
+ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+ if (unlikely(!ascb)) {
+ ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
+ goto next_1;
+ } else if (ascb->scb->header.opcode == EMPTY_SCB) {
+ goto out;
+ } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
+ goto next_1;
+ }
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ list_del_init(&ascb->list);
+ seq->pending--;
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+ out:
+ ascb->tasklet_complete(ascb, dl);
+
+ next_1:
+ seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
+ if (!seq->dl_next)
+ seq->dl_toggle ^= DL_TOGGLE_MASK;
+ }
+}
+
+/* ---------- Interrupt Service Routines ---------- */
+
+/**
+ * asd_process_donelist_isr -- schedule processing of done list entries
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
+{
+ tasklet_schedule(&asd_ha->seq.dl_tasklet);
+}
+
+/**
+ * asd_com_sas_isr -- process device communication interrupt (COMINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
+
+ /* clear COMSTAT int */
+ asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
+
+ if (comstat & CSBUFPERR) {
+ asd_printk("%s: command/status buffer dma parity error\n",
+ pci_name(asd_ha->pcidev));
+ } else if (comstat & CSERR) {
+ int i;
+ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+ dmaerr &= 0xFF;
+ asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
+ "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
+ pci_name(asd_ha->pcidev),
+ dmaerr,
+ asd_read_reg_dword(asd_ha, CSDMAADR),
+ asd_read_reg_dword(asd_ha, CSDMAADR+4));
+ asd_printk("CSBUFFER:\n");
+ for (i = 0; i < 8; i++) {
+ asd_printk("%08x %08x %08x %08x\n",
+ asd_read_reg_dword(asd_ha, CSBUFFER),
+ asd_read_reg_dword(asd_ha, CSBUFFER+4),
+ asd_read_reg_dword(asd_ha, CSBUFFER+8),
+ asd_read_reg_dword(asd_ha, CSBUFFER+12));
+ }
+ asd_dump_seq_state(asd_ha, 0);
+ } else if (comstat & OVLYERR) {
+ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+ dmaerr = (dmaerr >> 8) & 0xFF;
+ asd_printk("%s: overlay dma error:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ dmaerr);
+ }
+ asd_chip_reset(asd_ha);
+}
+
+static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
+{
+ static const char *halt_code[256] = {
+ "UNEXPECTED_INTERRUPT0",
+ "UNEXPECTED_INTERRUPT1",
+ "UNEXPECTED_INTERRUPT2",
+ "UNEXPECTED_INTERRUPT3",
+ "UNEXPECTED_INTERRUPT4",
+ "UNEXPECTED_INTERRUPT5",
+ "UNEXPECTED_INTERRUPT6",
+ "UNEXPECTED_INTERRUPT7",
+ "UNEXPECTED_INTERRUPT8",
+ "UNEXPECTED_INTERRUPT9",
+ "UNEXPECTED_INTERRUPT10",
+ [11 ... 19] = "unknown[11,19]",
+ "NO_FREE_SCB_AVAILABLE",
+ "INVALID_SCB_OPCODE",
+ "INVALID_MBX_OPCODE",
+ "INVALID_ATA_STATE",
+ "ATA_QUEUE_FULL",
+ "ATA_TAG_TABLE_FAULT",
+ "ATA_TAG_MASK_FAULT",
+ "BAD_LINK_QUEUE_STATE",
+ "DMA2CHIM_QUEUE_ERROR",
+ "EMPTY_SCB_LIST_FULL",
+ "unknown[30]",
+ "IN_USE_SCB_ON_FREE_LIST",
+ "BAD_OPEN_WAIT_STATE",
+ "INVALID_STP_AFFILIATION",
+ "unknown[34]",
+ "EXEC_QUEUE_ERROR",
+ "TOO_MANY_EMPTIES_NEEDED",
+ "EMPTY_REQ_QUEUE_ERROR",
+ "Q_MONIRTT_MGMT_ERROR",
+ "TARGET_MODE_FLOW_ERROR",
+ "DEVICE_QUEUE_NOT_FOUND",
+ "START_IRTT_TIMER_ERROR",
+ "ABORT_TASK_ILLEGAL_REQ",
+ [43 ... 255] = "unknown[43,255]"
+ };
+
+ if (dchstatus & CSEQINT) {
+ u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
+
+ if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
+ asd_printk("%s: CSEQ arp2int:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ arp2int);
+ } else if (arp2int & ARP2HALTC)
+ asd_printk("%s: CSEQ halted: %s\n",
+ pci_name(asd_ha->pcidev),
+ halt_code[(arp2int>>16)&0xFF]);
+ else
+ asd_printk("%s: CARP2INT:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ arp2int);
+ }
+ if (dchstatus & LSEQINT_MASK) {
+ int lseq;
+ u8 lseq_mask = dchstatus & LSEQINT_MASK;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ u32 arp2int = asd_read_reg_dword(asd_ha,
+ LmARP2INT(lseq));
+ if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
+ | ARP2CIOPERR)) {
+ asd_printk("%s: LSEQ%d arp2int:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ lseq, arp2int);
+ /* XXX we should only do lseq reset */
+ } else if (arp2int & ARP2HALTC)
+ asd_printk("%s: LSEQ%d halted: %s\n",
+ pci_name(asd_ha->pcidev),
+ lseq,halt_code[(arp2int>>16)&0xFF]);
+ else
+ asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
+ pci_name(asd_ha->pcidev), lseq,
+ arp2int);
+ }
+ }
+ asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
+
+ if (dchstatus & CFIFTOERR) {
+ asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
+ asd_chip_reset(asd_ha);
+ } else
+ asd_arp2_err(asd_ha, dchstatus);
+}
+
+/**
+ * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
+
+ if (!(stat0r & ASIERR)) {
+ asd_printk("hmm, EXSI interrupted but no error?\n");
+ return;
+ }
+
+ if (stat0r & ASIFMTERR) {
+ asd_printk("ASI SEEPROM format error for %s\n",
+ pci_name(asd_ha->pcidev));
+ } else if (stat0r & ASISEECHKERR) {
+ u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
+ asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
+ stat1r & CHECKSUM_MASK,
+ pci_name(asd_ha->pcidev));
+ } else {
+ u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
+
+ if (!(statr & CPI2ASIMSTERR_MASK)) {
+ ASD_DPRINTK("hmm, ASIERR?\n");
+ return;
+ } else {
+ u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
+ u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
+
+ asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
+ "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
+ "master id: 0x%x, master err: 0x%x\n",
+ pci_name(asd_ha->pcidev),
+ addr, data,
+ (statr & CPI2ASIBYTECNT_MASK) >> 16,
+ (statr & CPI2ASIBYTEEN_MASK) >> 12,
+ (statr & CPI2ASITARGERR_MASK) >> 8,
+ (statr & CPI2ASITARGMID_MASK) >> 4,
+ (statr & CPI2ASIMSTERR_MASK));
+ }
+ }
+ asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hst_pcix_isr -- process host interface interrupts
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Asserted on PCIX errors: target abort, etc.
+ */
+static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
+{
+ u16 status;
+ u32 pcix_status;
+ u32 ecc_status;
+
+ pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
+ pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
+ pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
+
+ if (status & PCI_STATUS_DETECTED_PARITY)
+ asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_REC_MASTER_ABORT)
+ asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_REC_TARGET_ABORT)
+ asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_PARITY)
+ asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
+ else if (pcix_status & RCV_SCE) {
+ asd_printk("received split completion error for %s\n",
+ pci_name(asd_ha->pcidev));
+ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+ /* XXX: Abort task? */
+ return;
+ } else if (pcix_status & UNEXP_SC) {
+ asd_printk("unexpected split completion for %s\n",
+ pci_name(asd_ha->pcidev));
+ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+ /* ignore */
+ return;
+ } else if (pcix_status & SC_DISCARD)
+ asd_printk("split completion discarded for %s\n",
+ pci_name(asd_ha->pcidev));
+ else if (ecc_status & UNCOR_ECCERR)
+ asd_printk("uncorrectable ECC error for %s\n",
+ pci_name(asd_ha->pcidev));
+ asd_chip_reset(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)
+{
+ struct asd_ha_struct *asd_ha = dev_id;
+ u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
+
+ if (!chimint)
+ return IRQ_NONE;
+
+ asd_write_reg_dword(asd_ha, CHIMINT, chimint);
+ (void) asd_read_reg_dword(asd_ha, CHIMINT);
+
+ if (chimint & DLAVAIL)
+ asd_process_donelist_isr(asd_ha);
+ if (chimint & COMINT)
+ asd_com_sas_isr(asd_ha);
+ if (chimint & DEVINT)
+ asd_dch_sas_isr(asd_ha);
+ if (chimint & INITERR)
+ asd_rbi_exsi_isr(asd_ha);
+ if (chimint & HOSTERR)
+ asd_hst_pcix_isr(asd_ha);
+
+ return IRQ_HANDLED;
+}
+
+/* ---------- SCB handling ---------- */
+
+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;
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *ascb;
+ unsigned long flags;
+
+ ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
+
+ if (ascb) {
+ memset(ascb, 0, sizeof(*ascb));
+ ascb->dma_scb.size = sizeof(struct scb);
+ ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
+ gfp_flags,
+ &ascb->dma_scb.dma_handle);
+ if (!ascb->dma_scb.vaddr) {
+ kmem_cache_free(asd_ascb_cache, ascb);
+ return NULL;
+ }
+ memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
+ asd_init_ascb(asd_ha, ascb);
+
+ spin_lock_irqsave(&seq->tc_index_lock, flags);
+ ascb->tc_index = asd_tc_index_get(seq, ascb);
+ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+ if (ascb->tc_index == -1)
+ goto undo;
+
+ ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
+ }
+
+ return ascb;
+undo:
+ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+ ascb->dma_scb.dma_handle);
+ kmem_cache_free(asd_ascb_cache, ascb);
+ ASD_DPRINTK("no index for ascb\n");
+ return NULL;
+}
+
+/**
+ * asd_ascb_alloc_list -- allocate a list of aSCBs
+ * @asd_ha: pointer to host adapter structure
+ * @num: pointer to integer number of aSCBs
+ * @gfp_flags: GFP_ flags.
+ *
+ * This is the only function which is used to allocate aSCBs.
+ * It can allocate one or many. If more than one, then they form
+ * a linked list in two ways: by their list field of the ascb struct
+ * and by the next_scb field of the scb_header.
+ *
+ * Returns NULL if no memory was available, else pointer to a list
+ * of ascbs. When this function returns, @num would be the number
+ * of SCBs which were not able to be allocated, 0 if all requested
+ * were able to be allocated.
+ */
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+ *asd_ha, int *num,
+ gfp_t gfp_flags)
+{
+ struct asd_ascb *first = NULL;
+
+ for ( ; *num > 0; --*num) {
+ struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
+
+ if (!ascb)
+ break;
+ else if (!first)
+ first = ascb;
+ else {
+ struct asd_ascb *last = list_entry(first->list.prev,
+ struct asd_ascb,
+ list);
+ list_add_tail(&ascb->list, &first->list);
+ last->scb->header.next_scb =
+ cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
+ }
+ }
+
+ return first;
+}
+
+/**
+ * asd_swap_head_scb -- swap the head scb
+ * @asd_ha: pointer to host adapter structure
+ * @ascb: pointer to the head of an ascb list
+ *
+ * The sequencer knows the DMA address of the next SCB to be DMAed to
+ * the host adapter, from initialization or from the last list DMAed.
+ * seq->next_scb keeps the address of this SCB. The sequencer will
+ * DMA to the host adapter this list of SCBs. But the head (first
+ * element) of this list is not known to the sequencer. Here we swap
+ * the head of the list with the known SCB (memcpy()).
+ * Only one memcpy() is required per list so it is in our interest
+ * to keep the list of SCB as long as possible so that the ratio
+ * of number of memcpy calls to the number of SCB DMA-ed is as small
+ * as possible.
+ *
+ * LOCKING: called with the pending list lock held.
+ */
+static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
+ struct asd_ascb *ascb)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *last = list_entry(ascb->list.prev,
+ struct asd_ascb,
+ list);
+ struct asd_dma_tok t = ascb->dma_scb;
+
+ memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
+ ascb->dma_scb = seq->next_scb;
+ ascb->scb = ascb->dma_scb.vaddr;
+ seq->next_scb = t;
+ last->scb->header.next_scb =
+ cpu_to_le64(((u64)seq->next_scb.dma_handle));
+}
+
+/**
+ * asd_start_timers -- (add and) start timers of SCBs
+ * @list: pointer to struct list_head of the scbs
+ * @to: timeout in jiffies
+ *
+ * If an SCB in the @list has no timer function, assign the default
+ * one, then start the timer of the SCB. This function is
+ * intended to be called from asd_post_ascb_list(), just prior to
+ * posting the SCBs to the sequencer.
+ */
+static inline void asd_start_scb_timers(struct list_head *list)
+{
+ struct asd_ascb *ascb;
+ list_for_each_entry(ascb, list, list) {
+ if (!ascb->uldd_timer) {
+ ascb->timer.data = (unsigned long) ascb;
+ ascb->timer.function = asd_ascb_timedout;
+ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+ add_timer(&ascb->timer);
+ }
+ }
+}
+
+/**
+ * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first aSCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * See queueing comment in asd_post_escb_list().
+ *
+ * Additional note on queuing: In order to minimize the ratio of memcpy()
+ * to the number of ascbs sent, we try to batch-send as many ascbs as possible
+ * in one go.
+ * Two cases are possible:
+ * A) can_queue >= num,
+ * B) can_queue < num.
+ * Case A: we can send the whole batch at once. Increment "pending"
+ * in the beginning of this function, when it is checked, in order to
+ * eliminate races when this function is called by multiple processes.
+ * Case B: should never happen if the managing layer considers
+ * lldd_queue_size.
+ */
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num)
+{
+ unsigned long flags;
+ LIST_HEAD(list);
+ int can_queue;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
+ if (can_queue >= num)
+ asd_ha->seq.pending += num;
+ else
+ can_queue = 0;
+
+ if (!can_queue) {
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+ asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
+ return -SAS_QUEUE_FULL;
+ }
+
+ asd_swap_head_scb(asd_ha, ascb);
+
+ __list_add(&list, ascb->list.prev, &ascb->list);
+
+ asd_start_scb_timers(&list);
+
+ asd_ha->seq.scbpro += num;
+ list_splice_init(&list, asd_ha->seq.pend_q.prev);
+ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return 0;
+}
+
+/**
+ * asd_post_escb_list -- post a list of 1 or more empty scb
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first empty SCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * This is essentially the same as asd_post_ascb_list, but we do not
+ * increment pending, add those to the pending list or get indexes.
+ * See asd_init_escbs() and asd_init_post_escbs().
+ *
+ * Since sending a list of ascbs is a superset of sending a single
+ * ascb, this function exists to generalize this. More specifically,
+ * when sending a list of those, we want to do only a _single_
+ * memcpy() at swap head, as opposed to for each ascb sent (in the
+ * case of sending them one by one). That is, we want to minimize the
+ * ratio of memcpy() operations to the number of ascbs sent. The same
+ * logic applies to asd_post_ascb_list().
+ */
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_swap_head_scb(asd_ha, ascb);
+ asd_ha->seq.scbpro += num;
+ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return 0;
+}
+
+/* ---------- LED ---------- */
+
+/**
+ * asd_turn_led -- turn on/off an LED
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: the PHY id whose LED we want to manupulate
+ * @op: 1 to turn on, 0 to turn off
+ */
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+ if (phy_id < ASD_MAX_PHYS) {
+ u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
+ if (op)
+ v |= LEDPOL;
+ else
+ v &= ~LEDPOL;
+ asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
+ }
+}
+
+/**
+ * asd_control_led -- enable/disable an LED on the board
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: integer, the phy id
+ * @op: integer, 1 to enable, 0 to disable the LED
+ *
+ * First we output enable the LED, then we set the source
+ * to be an external module.
+ */
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+ if (phy_id < ASD_MAX_PHYS) {
+ u32 v;
+
+ v = asd_read_reg_dword(asd_ha, GPIOOER);
+ if (op)
+ v |= (1 << phy_id);
+ else
+ v &= ~(1 << phy_id);
+ asd_write_reg_dword(asd_ha, GPIOOER, v);
+
+ v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
+ if (op)
+ v |= (1 << phy_id);
+ else
+ v &= ~(1 << phy_id);
+ asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
+ }
+}
+
+/* ---------- PHY enable ---------- */
+
+static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
+{
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
+ HOTPLUG_DELAY_TIMEOUT);
+
+ /* Get defaults from manuf. sector */
+ /* XXX we need defaults for those in case MS is broken. */
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
+ phy->phy_desc->phy_control_0);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
+ phy->phy_desc->phy_control_1);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
+ phy->phy_desc->phy_control_2);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
+ phy->phy_desc->phy_control_3);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
+ ASD_COMINIT_TIMEOUT);
+
+ asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
+ phy->id_frm_tok->dma_handle);
+
+ asd_control_led(asd_ha, phy_id, 1);
+
+ return 0;
+}
+
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
+{
+ u8 phy_m;
+ u8 i;
+ int num = 0, k;
+ struct asd_ascb *ascb;
+ struct asd_ascb *ascb_list;
+
+ if (!phy_mask) {
+ asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+ return 0;
+ }
+
+ for_each_phy(phy_mask, phy_m, i) {
+ num++;
+ asd_enable_phy(asd_ha, i);
+ }
+
+ k = num;
+ ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
+ if (!ascb_list) {
+ asd_printk("no memory for control phy ascb list\n");
+ return -ENOMEM;
+ }
+ num -= k;
+
+ ascb = ascb_list;
+ for_each_phy(phy_mask, phy_m, i) {
+ asd_build_control_phy(ascb, i, ENABLE_PHY);
+ ascb = list_entry(ascb->list.next, struct asd_ascb, list);
+ }
+ ASD_DPRINTK("posting %d control phy scbs\n", num);
+ k = asd_post_ascb_list(asd_ha, ascb_list, num);
+ if (k)
+ asd_ascb_free_list(ascb_list);
+
+ return k;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
new file mode 100644
index 00000000000..8498144aa5e
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -0,0 +1,397 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_HWI_H_
+#define _AIC94XX_HWI_H_
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <scsi/libsas.h>
+
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+
+/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
+#define ASD_MAX_PHYS 8
+#define ASD_PCBA_SN_SIZE 12
+
+/* Those are to be further named properly, the "RAZORx" part, and
+ * subsequently included in include/linux/pci_ids.h.
+ */
+#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_RAZOR30 0x430
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
+
+struct asd_ha_addrspace {
+ void __iomem *addr;
+ unsigned long start; /* pci resource start */
+ unsigned long len; /* pci resource len */
+ unsigned long flags; /* pci resource flags */
+
+ /* addresses internal to the host adapter */
+ u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
+ u32 swb_base;
+ u32 swc_base;
+};
+
+struct bios_struct {
+ int present;
+ u8 maj;
+ u8 min;
+ u32 bld;
+};
+
+struct unit_element_struct {
+ u16 num;
+ u16 size;
+ void *area;
+};
+
+struct flash_struct {
+ u32 bar;
+ int present;
+ int wide;
+ u8 manuf;
+ u8 dev_id;
+ u8 sec_prot;
+
+ u32 dir_offs;
+};
+
+struct asd_phy_desc {
+ /* From CTRL-A settings, then set to what is appropriate */
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 max_sas_lrate;
+ u8 min_sas_lrate;
+ u8 max_sata_lrate;
+ u8 min_sata_lrate;
+ u8 flags;
+#define ASD_CRC_DIS 1
+#define ASD_SATA_SPINUP_HOLD 2
+
+ u8 phy_control_0; /* mode 5 reg 0x160 */
+ u8 phy_control_1; /* mode 5 reg 0x161 */
+ u8 phy_control_2; /* mode 5 reg 0x162 */
+ u8 phy_control_3; /* mode 5 reg 0x163 */
+};
+
+struct asd_dma_tok {
+ void *vaddr;
+ dma_addr_t dma_handle;
+ size_t size;
+};
+
+struct hw_profile {
+ struct bios_struct bios;
+ struct unit_element_struct ue;
+ struct flash_struct flash;
+
+ u8 sas_addr[SAS_ADDR_SIZE];
+ char pcba_sn[ASD_PCBA_SN_SIZE+1];
+
+ u8 enabled_phys; /* mask of enabled phys */
+ struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
+ u32 max_scbs; /* absolute sequencer scb queue size */
+ struct asd_dma_tok *scb_ext;
+ u32 max_ddbs;
+ struct asd_dma_tok *ddb_ext;
+
+ spinlock_t ddb_lock;
+ void *ddb_bitmap;
+
+ int num_phys; /* ENABLEABLE */
+ int max_phys; /* REPORTED + ENABLEABLE */
+
+ unsigned addr_range; /* max # of addrs; max # of possible ports */
+ unsigned port_name_base;
+ unsigned dev_name_base;
+ unsigned sata_name_base;
+};
+
+struct asd_ascb {
+ struct list_head list;
+ struct asd_ha_struct *ha;
+
+ struct scb *scb; /* equals dma_scb->vaddr */
+ struct asd_dma_tok dma_scb;
+ struct asd_dma_tok *sg_arr;
+
+ void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+ u8 uldd_timer:1;
+
+ /* internally generated command */
+ struct timer_list timer;
+ struct completion completion;
+ u8 tag_valid:1;
+ __be16 tag; /* error recovery only */
+
+ /* If this is an Empty SCB, index of first edb in seq->edb_arr. */
+ int edb_index;
+
+ /* Used by the timer timeout function. */
+ int tc_index;
+
+ void *uldd_task;
+};
+
+#define ASD_DL_SIZE_BITS 0x8
+#define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS))
+#define ASD_DEF_DL_TOGGLE 0x01
+
+struct asd_seq_data {
+ spinlock_t pend_q_lock;
+ u16 scbpro;
+ int pending;
+ struct list_head pend_q;
+ int can_queue; /* per adapter */
+ struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
+
+ spinlock_t tc_index_lock;
+ void **tc_index_array;
+ void *tc_index_bitmap;
+ int tc_index_bitmap_bits;
+
+ struct tasklet_struct dl_tasklet;
+ struct done_list_struct *dl; /* array of done list entries, equals */
+ struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
+ int dl_toggle;
+ int dl_next;
+
+ int num_edbs;
+ struct asd_dma_tok **edb_arr;
+ int num_escbs;
+ struct asd_ascb **escb_arr; /* array of pointers to escbs */
+};
+
+/* This is the Host Adapter structure. It describes the hardware
+ * SAS adapter.
+ */
+struct asd_ha_struct {
+ struct pci_dev *pcidev;
+ const char *name;
+
+ struct sas_ha_struct sas_ha;
+
+ u8 revision_id;
+
+ int iospace;
+ spinlock_t iolock;
+ struct asd_ha_addrspace io_handle[2];
+
+ struct hw_profile hw_prof;
+
+ struct asd_phy phys[ASD_MAX_PHYS];
+ struct asd_sas_port ports[ASD_MAX_PHYS];
+
+ struct dma_pool *scb_pool;
+
+ struct asd_seq_data seq; /* sequencer related */
+};
+
+/* ---------- Common macros ---------- */
+
+#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
+#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \
+ ? ((u32)((__dma_handle) >> 32)) \
+ : ((u32)0))
+
+#define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev))
+#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \
+ && ((__site_no) & 0xF0FF) > 0x001F)
+/* For each bit set in __lseq_mask, set __lseq to equal the bit
+ * position of the set bit and execute the statement following.
+ * __mc is the temporary mask, used as a mask "counter".
+ */
+#define for_each_sequencer(__lseq_mask, __mc, __lseq) \
+ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+ if (((__mc) & 1))
+#define for_each_phy(__lseq_mask, __mc, __lseq) \
+ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+ if (((__mc) & 1))
+
+#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
+
+/* ---------- DMA allocs ---------- */
+
+static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags)
+{
+ return kmem_cache_alloc(asd_dma_token_cache, flags);
+}
+
+static inline void asd_dmatok_free(struct asd_dma_tok *token)
+{
+ kmem_cache_free(asd_dma_token_cache, token);
+}
+
+static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
+ asd_ha, size_t size,
+ gfp_t flags)
+{
+ struct asd_dma_tok *token = asd_dmatok_alloc(flags);
+ if (token) {
+ token->size = size;
+ token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
+ token->size,
+ &token->dma_handle,
+ flags);
+ if (!token->vaddr) {
+ asd_dmatok_free(token);
+ token = NULL;
+ }
+ }
+ return token;
+}
+
+static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
+ struct asd_dma_tok *token)
+{
+ if (token) {
+ dma_free_coherent(&asd_ha->pcidev->dev, token->size,
+ token->vaddr, token->dma_handle);
+ asd_dmatok_free(token);
+ }
+}
+
+static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
+ struct asd_ascb *ascb)
+{
+ INIT_LIST_HEAD(&ascb->list);
+ ascb->scb = ascb->dma_scb.vaddr;
+ ascb->ha = asd_ha;
+ ascb->timer.function = NULL;
+ init_timer(&ascb->timer);
+ ascb->tc_index = -1;
+ init_completion(&ascb->completion);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
+{
+ seq->tc_index_array[index] = NULL;
+ clear_bit(index, seq->tc_index_bitmap);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
+{
+ int index;
+
+ index = find_first_zero_bit(seq->tc_index_bitmap,
+ seq->tc_index_bitmap_bits);
+ if (index == seq->tc_index_bitmap_bits)
+ return -1;
+
+ seq->tc_index_array[index] = ptr;
+ set_bit(index, seq->tc_index_bitmap);
+
+ return index;
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
+{
+ return seq->tc_index_array[index];
+}
+
+/**
+ * asd_ascb_free -- free a single aSCB after is has completed
+ * @ascb: pointer to the aSCB of interest
+ *
+ * This frees an aSCB after it has been executed/completed by
+ * the sequencer.
+ */
+static inline void asd_ascb_free(struct asd_ascb *ascb)
+{
+ if (ascb) {
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ unsigned long flags;
+
+ BUG_ON(!list_empty(&ascb->list));
+ spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
+ asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
+ spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
+ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+ ascb->dma_scb.dma_handle);
+ kmem_cache_free(asd_ascb_cache, ascb);
+ }
+}
+
+/**
+ * asd_ascb_list_free -- free a list of ascbs
+ * @ascb_list: a list of ascbs
+ *
+ * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
+ * It is used when say the scb queueing function returned QUEUE_FULL,
+ * and we do not need the ascbs any more.
+ */
+static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
+{
+ LIST_HEAD(list);
+ struct list_head *n, *pos;
+
+ __list_add(&list, ascb_list->list.prev, &ascb_list->list);
+ list_for_each_safe(pos, n, &list) {
+ list_del_init(pos);
+ asd_ascb_free(list_entry(pos, struct asd_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);
+
+
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+ *asd_ha, int *num,
+ gfp_t gfp_mask);
+
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num);
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num);
+
+int asd_init_post_escbs(struct asd_ha_struct *asd_ha);
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+ u8 subfunc);
+
+void asd_ascb_timedout(unsigned long data);
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
new file mode 100644
index 00000000000..ee2ccad7048
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -0,0 +1,866 @@
+/*
+ * Aic94xx SAS/SATA driver initialization.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+/* The format is "version.release.patchlevel" */
+#define ASD_DRIVER_VERSION "1.0.2"
+
+static int use_msi = 0;
+module_param_named(use_msi, use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "\n"
+ "\tEnable(1) or disable(0) using PCI MSI.\n"
+ "\tDefault: 0");
+
+static int lldd_max_execute_num = 0;
+module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
+MODULE_PARM_DESC(collector, "\n"
+ "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
+ "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
+ "\tThe aic94xx SAS LLDD supports both modes.\n"
+ "\tDefault: 0 (Direct Mode).\n");
+
+char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
+
+static struct scsi_transport_template *aic94xx_transport_template;
+
+static struct scsi_host_template aic94xx_sht = {
+ .module = THIS_MODULE,
+ /* .name is initialized */
+ .name = "aic94xx",
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+ struct asd_ha_addrspace *io_handle;
+
+ asd_ha->iospace = 0;
+ for (i = 0; i < 3; i += 2) {
+ io_handle = &asd_ha->io_handle[i==0?0:1];
+ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
+ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+ err = -ENODEV;
+ if (!io_handle->start || !io_handle->len) {
+ asd_printk("MBAR%d start or length for %s is 0.\n",
+ i==0?0:1, pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+ if (err) {
+ asd_printk("couldn't reserve memory region for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ if (io_handle->flags & IORESOURCE_CACHEABLE)
+ io_handle->addr = ioremap(io_handle->start,
+ io_handle->len);
+ else
+ io_handle->addr = ioremap_nocache(io_handle->start,
+ io_handle->len);
+ if (!io_handle->addr) {
+ asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,
+ pci_name(asd_ha->pcidev));
+ goto Err_unreq;
+ }
+ }
+
+ return 0;
+Err_unreq:
+ pci_release_region(asd_ha->pcidev, i);
+Err:
+ if (i > 0) {
+ io_handle = &asd_ha->io_handle[0];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 0);
+ }
+ return err;
+}
+
+static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+{
+ struct asd_ha_addrspace *io_handle;
+
+ io_handle = &asd_ha->io_handle[1];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 2);
+
+ io_handle = &asd_ha->io_handle[0];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 0);
+}
+
+static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+{
+ int i = PCI_IOBAR_OFFSET, err;
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
+
+ asd_ha->iospace = 1;
+ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
+ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+ io_handle->addr = (void __iomem *) io_handle->start;
+ if (!io_handle->start || !io_handle->len) {
+ asd_printk("couldn't get IO ports for %s\n",
+ pci_name(asd_ha->pcidev));
+ return -ENODEV;
+ }
+ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+ if (err) {
+ asd_printk("couldn't reserve io space for %s\n",
+ pci_name(asd_ha->pcidev));
+ }
+
+ return err;
+}
+
+static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+{
+ pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
+}
+
+static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u16 cmd_reg;
+
+ err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);
+ if (err) {
+ asd_printk("couldn't read command register of %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+
+ err = -ENODEV;
+ if (cmd_reg & PCI_COMMAND_MEMORY) {
+ if ((err = asd_map_memio(asd_ha)))
+ goto Err;
+ } else if (cmd_reg & PCI_COMMAND_IO) {
+ if ((err = asd_map_ioport(asd_ha)))
+ goto Err;
+ asd_printk("%s ioport mapped -- upgrade your hardware\n",
+ pci_name(asd_ha->pcidev));
+ } else {
+ asd_printk("no proper device access to %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+
+ return 0;
+Err:
+ return err;
+}
+
+static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+{
+ if (asd_ha->iospace)
+ asd_unmap_ioport(asd_ha);
+ else
+ asd_unmap_memio(asd_ha);
+}
+
+static const char *asd_dev_rev[30] = {
+ [0] = "A0",
+ [1] = "A1",
+ [8] = "B0",
+};
+
+static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+
+ err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
+ &asd_ha->revision_id);
+ if (err) {
+ asd_printk("couldn't read REVISION ID register of %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ err = -ENODEV;
+ if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
+ asd_printk("%s is revision %s (%X), which is not supported\n",
+ pci_name(asd_ha->pcidev),
+ asd_dev_rev[asd_ha->revision_id],
+ asd_ha->revision_id);
+ goto Err;
+ }
+ /* Provide some sane default values. */
+ asd_ha->hw_prof.max_scbs = 512;
+ asd_ha->hw_prof.max_ddbs = 128;
+ asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
+ /* All phys are enabled, by default. */
+ asd_ha->hw_prof.enabled_phys = 0xFF;
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
+ SAS_LINK_RATE_3_0_GBPS;
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ }
+
+ return 0;
+Err:
+ return err;
+}
+
+static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+{
+ int err = asd_common_setup(asd_ha);
+
+ if (err)
+ return err;
+
+ asd_ha->hw_prof.addr_range = 8;
+ asd_ha->hw_prof.port_name_base = 0;
+ asd_ha->hw_prof.dev_name_base = 8;
+ asd_ha->hw_prof.sata_name_base = 16;
+
+ return 0;
+}
+
+static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+{
+ int err = asd_common_setup(asd_ha);
+
+ if (err)
+ return err;
+
+ asd_ha->hw_prof.addr_range = 4;
+ asd_ha->hw_prof.port_name_base = 0;
+ asd_ha->hw_prof.dev_name_base = 4;
+ asd_ha->hw_prof.sata_name_base = 8;
+
+ return 0;
+}
+
+static ssize_t asd_show_dev_rev(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ asd_dev_rev[asd_ha->revision_id]);
+}
+static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);
+
+static ssize_t asd_show_dev_bios_build(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);
+}
+static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);
+
+static ssize_t asd_show_dev_pcba_sn(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);
+}
+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)
+{
+ 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);
+}
+
+static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+/* The first entry, 0, is used for dynamic ids, the rest for devices
+ * we know about.
+ */
+static struct asd_pcidev_struct {
+ const char * name;
+ int (*setup)(struct asd_ha_struct *asd_ha);
+} asd_pcidev_data[] = {
+ /* Id 0 is used for dynamic ids. */
+ { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
+ .setup = asd_aic9410_setup
+ },
+ { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter",
+ .setup = asd_aic9410_setup
+ },
+ { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter",
+ .setup = asd_aic9405_setup
+ },
+};
+
+static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
+ &asd_ha->pcidev->dev,
+ sizeof(struct scb),
+ 8, 0);
+ if (!asd_ha->scb_pool) {
+ asd_printk("couldn't create scb pool\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * asd_free_edbs -- free empty data buffers
+ * asd_ha: pointer to host adapter structure
+ */
+static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_edbs; i++)
+ asd_free_coherent(asd_ha, seq->edb_arr[i]);
+ kfree(seq->edb_arr);
+ seq->edb_arr = NULL;
+}
+
+static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_escbs; i++) {
+ if (!list_empty(&seq->escb_arr[i]->list))
+ list_del_init(&seq->escb_arr[i]->list);
+
+ asd_ascb_free(seq->escb_arr[i]);
+ }
+ kfree(seq->escb_arr);
+ seq->escb_arr = NULL;
+}
+
+static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ if (asd_ha->hw_prof.ddb_ext)
+ asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);
+ if (asd_ha->hw_prof.scb_ext)
+ asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);
+
+ if (asd_ha->hw_prof.ddb_bitmap)
+ kfree(asd_ha->hw_prof.ddb_bitmap);
+ asd_ha->hw_prof.ddb_bitmap = NULL;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ struct asd_phy *phy = &asd_ha->phys[i];
+
+ asd_free_coherent(asd_ha, phy->id_frm_tok);
+ }
+ if (asd_ha->seq.escb_arr)
+ asd_free_escbs(asd_ha);
+ if (asd_ha->seq.edb_arr)
+ asd_free_edbs(asd_ha);
+ if (asd_ha->hw_prof.ue.area) {
+ kfree(asd_ha->hw_prof.ue.area);
+ asd_ha->hw_prof.ue.area = NULL;
+ }
+ if (asd_ha->seq.tc_index_array) {
+ kfree(asd_ha->seq.tc_index_array);
+ kfree(asd_ha->seq.tc_index_bitmap);
+ asd_ha->seq.tc_index_array = NULL;
+ asd_ha->seq.tc_index_bitmap = NULL;
+ }
+ if (asd_ha->seq.actual_dl) {
+ asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);
+ asd_ha->seq.actual_dl = NULL;
+ asd_ha->seq.dl = NULL;
+ }
+ if (asd_ha->seq.next_scb.vaddr) {
+ dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,
+ asd_ha->seq.next_scb.dma_handle);
+ asd_ha->seq.next_scb.vaddr = NULL;
+ }
+ dma_pool_destroy(asd_ha->scb_pool);
+ asd_ha->scb_pool = NULL;
+}
+
+kmem_cache_t *asd_dma_token_cache;
+kmem_cache_t *asd_ascb_cache;
+
+static int asd_create_global_caches(void)
+{
+ if (!asd_dma_token_cache) {
+ asd_dma_token_cache
+ = kmem_cache_create(ASD_DRIVER_NAME "_dma_token",
+ sizeof(struct asd_dma_tok),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!asd_dma_token_cache) {
+ asd_printk("couldn't create dma token cache\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (!asd_ascb_cache) {
+ asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb",
+ sizeof(struct asd_ascb),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!asd_ascb_cache) {
+ asd_printk("couldn't create ascb cache\n");
+ goto Err;
+ }
+ }
+
+ return 0;
+Err:
+ kmem_cache_destroy(asd_dma_token_cache);
+ asd_dma_token_cache = NULL;
+ return -ENOMEM;
+}
+
+static void asd_destroy_global_caches(void)
+{
+ if (asd_dma_token_cache)
+ kmem_cache_destroy(asd_dma_token_cache);
+ asd_dma_token_cache = NULL;
+
+ if (asd_ascb_cache)
+ kmem_cache_destroy(asd_ascb_cache);
+ asd_ascb_cache = NULL;
+}
+
+static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ struct asd_sas_phy **sas_phys =
+ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL);
+ struct asd_sas_port **sas_ports =
+ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL);
+
+ if (!sas_phys || !sas_ports) {
+ kfree(sas_phys);
+ kfree(sas_ports);
+ return -ENOMEM;
+ }
+
+ asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name;
+ asd_ha->sas_ha.lldd_module = THIS_MODULE;
+ asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0];
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ sas_phys[i] = &asd_ha->phys[i].sas_phy;
+ sas_ports[i] = &asd_ha->ports[i];
+ }
+
+ asd_ha->sas_ha.sas_phy = sas_phys;
+ asd_ha->sas_ha.sas_port= sas_ports;
+ asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
+
+ asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+
+ return sas_register_ha(&asd_ha->sas_ha);
+}
+
+static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = sas_unregister_ha(&asd_ha->sas_ha);
+
+ sas_remove_host(asd_ha->sas_ha.core.shost);
+ scsi_remove_host(asd_ha->sas_ha.core.shost);
+ scsi_host_put(asd_ha->sas_ha.core.shost);
+
+ kfree(asd_ha->sas_ha.sas_phy);
+ kfree(asd_ha->sas_ha.sas_port);
+
+ return err;
+}
+
+static int __devinit asd_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct asd_pcidev_struct *asd_dev;
+ unsigned asd_id = (unsigned) id->driver_data;
+ struct asd_ha_struct *asd_ha;
+ struct Scsi_Host *shost;
+ int err;
+
+ if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) {
+ asd_printk("wrong driver_data in PCI table\n");
+ return -ENODEV;
+ }
+
+ if ((err = pci_enable_device(dev))) {
+ asd_printk("couldn't enable device %s\n", pci_name(dev));
+ return err;
+ }
+
+ pci_set_master(dev);
+
+ err = -ENOMEM;
+
+ shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *));
+ if (!shost)
+ goto Err;
+
+ asd_dev = &asd_pcidev_data[asd_id];
+
+ asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
+ if (!asd_ha) {
+ asd_printk("out of memory\n");
+ goto Err;
+ }
+ asd_ha->pcidev = dev;
+ asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+ asd_ha->sas_ha.lldd_ha = asd_ha;
+
+ asd_ha->name = asd_dev->name;
+ asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
+
+ SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha;
+ asd_ha->sas_ha.core.shost = shost;
+ shost->transportt = aic94xx_transport_template;
+ shost->max_id = ~0;
+ shost->max_lun = ~0;
+ shost->max_cmd_len = 16;
+
+ err = scsi_add_host(shost, &dev->dev);
+ if (err) {
+ scsi_host_put(shost);
+ goto Err_free;
+ }
+
+
+
+ err = asd_dev->setup(asd_ha);
+ if (err)
+ goto Err_free;
+
+ err = -ENODEV;
+ if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
+ && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
+ ;
+ else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
+ && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
+ ;
+ else {
+ asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
+ goto Err_free;
+ }
+
+ pci_set_drvdata(dev, asd_ha);
+
+ err = asd_map_ha(asd_ha);
+ if (err)
+ goto Err_free;
+
+ err = asd_create_ha_caches(asd_ha);
+ if (err)
+ goto Err_unmap;
+
+ err = asd_init_hw(asd_ha);
+ if (err)
+ goto Err_free_cache;
+
+ asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled "
+ "phys, flash %s, BIOS %s%d\n",
+ pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr),
+ asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys,
+ asd_ha->hw_prof.num_phys,
+ asd_ha->hw_prof.flash.present ? "present" : "not present",
+ asd_ha->hw_prof.bios.present ? "build " : "not present",
+ asd_ha->hw_prof.bios.bld);
+
+ shost->can_queue = asd_ha->seq.can_queue;
+
+ if (use_msi)
+ pci_enable_msi(asd_ha->pcidev);
+
+ err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+ ASD_DRIVER_NAME, asd_ha);
+ if (err) {
+ asd_printk("couldn't get irq %d for %s\n",
+ asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
+ goto Err_irq;
+ }
+ asd_enable_ints(asd_ha);
+
+ err = asd_init_post_escbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't post escbs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err_escbs;
+ }
+ ASD_DPRINTK("escbs posted\n");
+
+ asd_create_dev_attrs(asd_ha);
+
+ err = asd_register_sas_ha(asd_ha);
+ if (err)
+ goto Err_reg_sas;
+
+ err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+ if (err) {
+ asd_printk("coudln't enable phys, err:%d\n", err);
+ goto Err_en_phys;
+ }
+ ASD_DPRINTK("enabled phys\n");
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ ssleep(1);
+ /* Wait for discovery to finish */
+ scsi_flush_work(asd_ha->sas_ha.core.shost);
+
+ return 0;
+Err_en_phys:
+ asd_unregister_sas_ha(asd_ha);
+Err_reg_sas:
+ asd_remove_dev_attrs(asd_ha);
+Err_escbs:
+ asd_disable_ints(asd_ha);
+ free_irq(dev->irq, asd_ha);
+Err_irq:
+ if (use_msi)
+ pci_disable_msi(dev);
+ asd_chip_hardrst(asd_ha);
+Err_free_cache:
+ asd_destroy_ha_caches(asd_ha);
+Err_unmap:
+ asd_unmap_ha(asd_ha);
+Err_free:
+ kfree(asd_ha);
+ scsi_remove_host(shost);
+Err:
+ pci_disable_device(dev);
+ return err;
+}
+
+static void asd_free_queues(struct asd_ha_struct *asd_ha)
+{
+ unsigned long flags;
+ LIST_HEAD(pending);
+ struct list_head *n, *pos;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_ha->seq.pending = 0;
+ list_splice_init(&asd_ha->seq.pend_q, &pending);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ if (!list_empty(&pending))
+ ASD_DPRINTK("Uh-oh! Pending is not empty!\n");
+
+ list_for_each_safe(pos, n, &pending) {
+ struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+ list_del_init(pos);
+ ASD_DPRINTK("freeing from pending\n");
+ asd_ascb_free(ascb);
+ }
+}
+
+static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
+{
+ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+ u8 i;
+
+ for_each_phy(phy_mask, phy_mask, i) {
+ asd_turn_led(asd_ha, i, 0);
+ asd_control_led(asd_ha, i, 0);
+ }
+}
+
+static void __devexit asd_pci_remove(struct pci_dev *dev)
+{
+ struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
+
+ if (!asd_ha)
+ return;
+
+ asd_unregister_sas_ha(asd_ha);
+
+ asd_disable_ints(asd_ha);
+
+ asd_remove_dev_attrs(asd_ha);
+
+ /* XXX more here as needed */
+
+ free_irq(dev->irq, asd_ha);
+ if (use_msi)
+ pci_disable_msi(asd_ha->pcidev);
+ asd_turn_off_leds(asd_ha);
+ asd_chip_hardrst(asd_ha);
+ asd_free_queues(asd_ha);
+ asd_destroy_ha_caches(asd_ha);
+ asd_unmap_ha(asd_ha);
+ kfree(asd_ha);
+ pci_disable_device(dev);
+ return;
+}
+
+static ssize_t asd_version_show(struct device_driver *driver, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
+}
+static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
+
+static void asd_create_driver_attrs(struct device_driver *driver)
+{
+ driver_create_file(driver, &driver_attr_version);
+}
+
+static void asd_remove_driver_attrs(struct device_driver *driver)
+{
+ driver_remove_file(driver, &driver_attr_version);
+}
+
+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,
+
+ .lldd_execute_task = asd_execute_task,
+
+ .lldd_abort_task = asd_abort_task,
+ .lldd_abort_task_set = asd_abort_task_set,
+ .lldd_clear_aca = asd_clear_aca,
+ .lldd_clear_task_set = asd_clear_task_set,
+ .lldd_I_T_nexus_reset = NULL,
+ .lldd_lu_reset = asd_lu_reset,
+ .lldd_query_task = asd_query_task,
+
+ .lldd_clear_nexus_port = asd_clear_nexus_port,
+ .lldd_clear_nexus_ha = asd_clear_nexus_ha,
+
+ .lldd_control_phy = asd_control_phy,
+};
+
+static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
+ 0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
+ 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_RAZOR30),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
+ 0, 0, 2},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);
+
+static struct pci_driver aic94xx_pci_driver = {
+ .name = ASD_DRIVER_NAME,
+ .id_table = aic94xx_pci_table,
+ .probe = asd_pci_probe,
+ .remove = __devexit_p(asd_pci_remove),
+};
+
+static int __init aic94xx_init(void)
+{
+ int err;
+
+
+ asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION,
+ ASD_DRIVER_VERSION);
+
+ err = asd_create_global_caches();
+ if (err)
+ return err;
+
+ aic94xx_transport_template =
+ sas_domain_attach_transport(&aic94xx_transport_functions);
+ if (!aic94xx_transport_template)
+ goto out_destroy_caches;
+
+ err = pci_register_driver(&aic94xx_pci_driver);
+ if (err)
+ goto out_release_transport;
+
+ asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+
+ return err;
+
+ out_release_transport:
+ sas_release_transport(aic94xx_transport_template);
+ out_destroy_caches:
+ asd_destroy_global_caches();
+
+ return err;
+}
+
+static void __exit aic94xx_exit(void)
+{
+ asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
+ pci_unregister_driver(&aic94xx_pci_driver);
+ sas_release_transport(aic94xx_transport_template);
+ asd_destroy_global_caches();
+ asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
+ ASD_DRIVER_VERSION);
+}
+
+module_init(aic94xx_init);
+module_exit(aic94xx_exit);
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ASD_DRIVER_VERSION);
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c
new file mode 100644
index 00000000000..f210dac3203
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg.c
@@ -0,0 +1,332 @@
+/*
+ * Aic94xx SAS/SATA driver register access.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include "aic94xx_reg.h"
+#include "aic94xx.h"
+
+/* Writing to device address space.
+ * Offset comes before value to remind that the operation of
+ * this function is *offs = val.
+ */
+static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u8 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outb(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writeb(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+static inline void asd_write_word(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u16 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outw(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writew(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u32 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outl(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writel(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+/* Reading from device address space.
+ */
+static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u8 val;
+ if (unlikely(asd_ha->iospace))
+ val = inb((unsigned long) asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readb(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u16 val;
+ if (unlikely(asd_ha->iospace))
+ val = inw((unsigned long)asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readw(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u32 val;
+ if (unlikely(asd_ha->iospace))
+ val = inl((unsigned long) asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readl(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u32 asd_mem_offs_swa(void)
+{
+ return 0;
+}
+
+static inline u32 asd_mem_offs_swc(void)
+{
+ return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
+}
+
+static inline u32 asd_mem_offs_swb(void)
+{
+ return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
+}
+
+/* We know that the register wanted is in the range
+ * of the sliding window.
+ */
+#define ASD_READ_SW(ww, type, ord) \
+static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+ u32 reg) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
+ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+ return asd_read_##ord (asd_ha, (unsigned long) map_offs); \
+}
+
+#define ASD_WRITE_SW(ww, type, ord) \
+static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+ u32 reg, type val) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
+ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+ asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \
+}
+
+ASD_READ_SW(swa, u8, byte);
+ASD_READ_SW(swa, u16, word);
+ASD_READ_SW(swa, u32, dword);
+
+ASD_READ_SW(swb, u8, byte);
+ASD_READ_SW(swb, u16, word);
+ASD_READ_SW(swb, u32, dword);
+
+ASD_READ_SW(swc, u8, byte);
+ASD_READ_SW(swc, u16, word);
+ASD_READ_SW(swc, u32, dword);
+
+ASD_WRITE_SW(swa, u8, byte);
+ASD_WRITE_SW(swa, u16, word);
+ASD_WRITE_SW(swa, u32, dword);
+
+ASD_WRITE_SW(swb, u8, byte);
+ASD_WRITE_SW(swb, u16, word);
+ASD_WRITE_SW(swb, u32, dword);
+
+ASD_WRITE_SW(swc, u8, byte);
+ASD_WRITE_SW(swc, u16, word);
+ASD_WRITE_SW(swc, u32, dword);
+
+/*
+ * A word about sliding windows:
+ * MBAR0 is divided into sliding windows A, C and B, in that order.
+ * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
+ * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
+ * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
+ * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
+ * See asd_init_sw() in aic94xx_hwi.c
+ *
+ * We map the most common registers we'd access of the internal 4GB
+ * host adapter memory space. If a register/internal memory location
+ * is wanted which is not mapped, we slide SWB, by paging it,
+ * see asd_move_swb() in aic94xx_reg.c.
+ */
+
+/**
+ * asd_move_swb -- move sliding window B
+ * @asd_ha: pointer to host adapter structure
+ * @reg: register desired to be within range of the new window
+ */
+static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
+{
+ u32 base = reg & ~(MBAR0_SWB_SIZE-1);
+ pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
+ asd_ha->io_handle[0].swb_base = base;
+}
+
+static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
+{
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+ if (io_handle->swa_base <= reg
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+ asd_write_swa_byte (asd_ha, reg,val);
+ else if (io_handle->swb_base <= reg
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+ asd_write_swb_byte (asd_ha, reg, val);
+ else if (io_handle->swc_base <= reg
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+ asd_write_swc_byte (asd_ha, reg, val);
+ else {
+ /* Ok, we have to move SWB */
+ asd_move_swb(asd_ha, reg);
+ asd_write_swb_byte (asd_ha, reg, val);
+ }
+}
+
+#define ASD_WRITE_REG(type, ord) \
+void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
+{ \
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+ unsigned long flags; \
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
+ spin_lock_irqsave(&asd_ha->iolock, flags); \
+ if (io_handle->swa_base <= reg \
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
+ asd_write_swa_##ord (asd_ha, reg,val); \
+ else if (io_handle->swb_base <= reg \
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
+ asd_write_swb_##ord (asd_ha, reg, val); \
+ else if (io_handle->swc_base <= reg \
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
+ asd_write_swc_##ord (asd_ha, reg, val); \
+ else { \
+ /* Ok, we have to move SWB */ \
+ asd_move_swb(asd_ha, reg); \
+ asd_write_swb_##ord (asd_ha, reg, val); \
+ } \
+ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
+}
+
+ASD_WRITE_REG(u8, byte);
+ASD_WRITE_REG(u16,word);
+ASD_WRITE_REG(u32,dword);
+
+static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
+{
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+ u8 val;
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+ if (io_handle->swa_base <= reg
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+ val = asd_read_swa_byte (asd_ha, reg);
+ else if (io_handle->swb_base <= reg
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+ val = asd_read_swb_byte (asd_ha, reg);
+ else if (io_handle->swc_base <= reg
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+ val = asd_read_swc_byte (asd_ha, reg);
+ else {
+ /* Ok, we have to move SWB */
+ asd_move_swb(asd_ha, reg);
+ val = asd_read_swb_byte (asd_ha, reg);
+ }
+ return val;
+}
+
+#define ASD_READ_REG(type, ord) \
+type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
+{ \
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+ type val; \
+ unsigned long flags; \
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
+ spin_lock_irqsave(&asd_ha->iolock, flags); \
+ if (io_handle->swa_base <= reg \
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
+ val = asd_read_swa_##ord (asd_ha, reg); \
+ else if (io_handle->swb_base <= reg \
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
+ val = asd_read_swb_##ord (asd_ha, reg); \
+ else if (io_handle->swc_base <= reg \
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
+ val = asd_read_swc_##ord (asd_ha, reg); \
+ else { \
+ /* Ok, we have to move SWB */ \
+ asd_move_swb(asd_ha, reg); \
+ val = asd_read_swb_##ord (asd_ha, reg); \
+ } \
+ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
+ return val; \
+}
+
+ASD_READ_REG(u8, byte);
+ASD_READ_REG(u16,word);
+ASD_READ_REG(u32,dword);
+
+/**
+ * asd_read_reg_string -- read a string of bytes from io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @dst: pointer to a destination buffer where data will be written to
+ * @offs: start offset (register) to read from
+ * @count: number of bytes to read
+ */
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+ u32 offs, int count)
+{
+ u8 *p = dst;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->iolock, flags);
+ for ( ; count > 0; count--, offs++, p++)
+ *p = __asd_read_reg_byte(asd_ha, offs);
+ spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
+
+/**
+ * asd_write_reg_string -- write a string of bytes to io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @src: pointer to source buffer where data will be read from
+ * @offs: start offset (register) to write to
+ * @count: number of bytes to write
+ */
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+ u32 offs, int count)
+{
+ u8 *p = src;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->iolock, flags);
+ for ( ; count > 0; count--, offs++, p++)
+ __asd_write_reg_byte(asd_ha, offs, *p);
+ spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h
new file mode 100644
index 00000000000..2279307fd27
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg.h
@@ -0,0 +1,302 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers definitions.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_REG_H_
+#define _AIC94XX_REG_H_
+
+#include <asm/io.h>
+#include "aic94xx_hwi.h"
+
+/* Values */
+#define AIC9410_DEV_REV_B0 0x8
+
+/* MBAR0, SWA, SWB, SWC, internal memory space addresses */
+#define REG_BASE_ADDR 0xB8000000
+#define REG_BASE_ADDR_CSEQCIO 0xB8002000
+#define REG_BASE_ADDR_EXSI 0xB8042800
+
+#define MBAR0_SWA_SIZE 0x58
+extern u32 MBAR0_SWB_SIZE;
+#define MBAR0_SWC_SIZE 0x8
+
+/* MBAR1, points to On Chip Memory */
+#define OCM_BASE_ADDR 0xA0000000
+#define OCM_MAX_SIZE 0x20000
+
+/* Smallest address possible to reference */
+#define ALL_BASE_ADDR OCM_BASE_ADDR
+
+/* PCI configuration space registers */
+#define PCI_IOBAR_OFFSET 4
+
+#define PCI_CONF_MBAR1 0x6C
+#define PCI_CONF_MBAR0_SWA 0x70
+#define PCI_CONF_MBAR0_SWB 0x74
+#define PCI_CONF_MBAR0_SWC 0x78
+#define PCI_CONF_MBAR_KEY 0x7C
+#define PCI_CONF_FLSH_BAR 0xB8
+
+#include "aic94xx_reg_def.h"
+
+u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg);
+u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg);
+u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg);
+
+void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val);
+void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val);
+void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val);
+
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+ u32 offs, int count);
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+ u32 offs, int count);
+
+#define ASD_READ_OCM(type, ord, S) \
+static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \
+ u32 offs) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
+ type val = read##S (io_handle->addr + (unsigned long) offs); \
+ rmb(); \
+ return val; \
+}
+
+ASD_READ_OCM(u8, byte, b);
+ASD_READ_OCM(u16,word, w);
+ASD_READ_OCM(u32,dword,l);
+
+#define ASD_WRITE_OCM(type, ord, S) \
+static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \
+ u32 offs, type val) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
+ write##S (val, io_handle->addr + (unsigned long) offs); \
+ return; \
+}
+
+ASD_WRITE_OCM(u8, byte, b);
+ASD_WRITE_OCM(u16,word, w);
+ASD_WRITE_OCM(u32,dword,l);
+
+#define ASD_DDBSITE_READ(type, ord) \
+static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \
+ u16 ddb_site_no, \
+ u16 offs) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
+ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
+}
+
+ASD_DDBSITE_READ(u32, dword);
+ASD_DDBSITE_READ(u16, word);
+
+static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no,
+ u16 offs)
+{
+ if (offs & 1)
+ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+ offs & ~1) >> 8;
+ else
+ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+ offs) & 0xFF;
+}
+
+
+#define ASD_DDBSITE_WRITE(type, ord) \
+static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \
+ u16 ddb_site_no, \
+ u16 offs, type val) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
+ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
+}
+
+ASD_DDBSITE_WRITE(u32, dword);
+ASD_DDBSITE_WRITE(u16, word);
+
+static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no,
+ u16 offs, u8 val)
+{
+ u16 base = offs & ~1;
+ u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+ if (offs & 1)
+ rval = (val << 8) | (rval & 0xFF);
+ else
+ rval = (rval & 0xFF00) | val;
+ asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval);
+}
+
+
+#define ASD_SCBSITE_READ(type, ord) \
+static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \
+ u16 scb_site_no, \
+ u16 offs) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
+ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
+}
+
+ASD_SCBSITE_READ(u32, dword);
+ASD_SCBSITE_READ(u16, word);
+
+static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha,
+ u16 scb_site_no,
+ u16 offs)
+{
+ if (offs & 1)
+ return asd_scbsite_read_word(asd_ha, scb_site_no,
+ offs & ~1) >> 8;
+ else
+ return asd_scbsite_read_word(asd_ha, scb_site_no,
+ offs) & 0xFF;
+}
+
+
+#define ASD_SCBSITE_WRITE(type, ord) \
+static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \
+ u16 scb_site_no, \
+ u16 offs, type val) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
+ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
+}
+
+ASD_SCBSITE_WRITE(u32, dword);
+ASD_SCBSITE_WRITE(u16, word);
+
+static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha,
+ u16 scb_site_no,
+ u16 offs, u8 val)
+{
+ u16 base = offs & ~1;
+ u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base);
+ if (offs & 1)
+ rval = (val << 8) | (rval & 0xFF);
+ else
+ rval = (rval & 0xFF00) | val;
+ asd_scbsite_write_word(asd_ha, scb_site_no, base, rval);
+}
+
+/**
+ * asd_ddbsite_update_word -- atomically update a word in a ddb site
+ * @asd_ha: pointer to host adapter structure
+ * @ddb_site_no: the DDB site number
+ * @offs: the offset into the DDB
+ * @oldval: old value found in that offset
+ * @newval: the new value to replace it
+ *
+ * This function is used when the sequencers are running and we need to
+ * update a DDB site atomically without expensive pausing and upausing
+ * of the sequencers and accessing the DDB site through the CIO bus.
+ *
+ * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value
+ * is different than the current value at that offset.
+ */
+static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no, u16 offs,
+ u16 oldval, u16 newval)
+{
+ u8 done;
+ u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs);
+ if (oval != oldval)
+ return -EAGAIN;
+ asd_write_reg_word(asd_ha, AOLDDATA, oldval);
+ asd_write_reg_word(asd_ha, ANEWDATA, newval);
+ do {
+ done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL);
+ } while (!(done & ATOMICDONE));
+ if (done & ATOMICERR)
+ return -EFAULT; /* parity error */
+ else if (done & ATOMICWIN)
+ return 0; /* success */
+ else
+ return -EAGAIN; /* oldval different than current value */
+}
+
+static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no, u16 offs,
+ u8 _oldval, u8 _newval)
+{
+ u16 base = offs & ~1;
+ u16 oval;
+ u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+ if (offs & 1) {
+ if ((nval >> 8) != _oldval)
+ return -EAGAIN;
+ nval = (_newval << 8) | (nval & 0xFF);
+ oval = (_oldval << 8) | (nval & 0xFF);
+ } else {
+ if ((nval & 0xFF) != _oldval)
+ return -EAGAIN;
+ nval = (nval & 0xFF00) | _newval;
+ oval = (nval & 0xFF00) | _oldval;
+ }
+ return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval);
+}
+
+static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg,
+ dma_addr_t dma_handle)
+{
+ asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle));
+ asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle));
+}
+
+static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha)
+{
+ /* DCHREVISION returns 0, possibly broken */
+ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+ return ctxmemsize ? 65536 : 32768;
+}
+
+static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha)
+{
+ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+ return ctxmemsize ? 8192 : 4096;
+}
+
+static inline void asd_disable_ints(struct asd_ha_struct *asd_ha)
+{
+ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+}
+
+static inline void asd_enable_ints(struct asd_ha_struct *asd_ha)
+{
+ /* Enable COM SAS interrupt on errors, COMSTAT */
+ asd_write_reg_dword(asd_ha, COMSTATEN,
+ EN_CSBUFPERR | EN_CSERR | EN_OVLYERR);
+ /* Enable DCH SAS CFIFTOERR */
+ asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR);
+ /* Enable Host Device interrupts */
+ asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN);
+}
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
new file mode 100644
index 00000000000..b79f45f3ad4
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -0,0 +1,2398 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers defintions.
+ *
+ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Luben Tuikov: Some register value updates to make it work with the window
+ * agnostic register r/w functions. Some register corrections, sizes,
+ * etc.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
+ *
+ */
+
+#ifndef _ADP94XX_REG_DEF_H_
+#define _ADP94XX_REG_DEF_H_
+
+/*
+ * Common definitions.
+ */
+#define CSEQ_MODE_PAGE_SIZE 0x200 /* CSEQ mode page size */
+#define LmSEQ_MODE_PAGE_SIZE 0x200 /* LmSEQ mode page size */
+#define LmSEQ_HOST_REG_SIZE 0x4000 /* LmSEQ Host Register size */
+
+/********************* COM_SAS registers definition *************************/
+
+/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h.
+ */
+
+/*
+ * CHIM Registers, Address Range : (0x00-0xFF)
+ */
+#define COMBIST (REG_BASE_ADDR + 0x00)
+
+/* bits 31:24 */
+#define L7BLKRST 0x80000000
+#define L6BLKRST 0x40000000
+#define L5BLKRST 0x20000000
+#define L4BLKRST 0x10000000
+#define L3BLKRST 0x08000000
+#define L2BLKRST 0x04000000
+#define L1BLKRST 0x02000000
+#define L0BLKRST 0x01000000
+#define LmBLKRST 0xFF000000
+#define LmBLKRST_COMBIST(phyid) (1 << (24 + phyid))
+
+#define OCMBLKRST 0x00400000
+#define CTXMEMBLKRST 0x00200000
+#define CSEQBLKRST 0x00100000
+#define EXSIBLKRST 0x00040000
+#define DPIBLKRST 0x00020000
+#define DFIFBLKRST 0x00010000
+#define HARDRST 0x00000200
+#define COMBLKRST 0x00000100
+#define FRCDFPERR 0x00000080
+#define FRCCIOPERR 0x00000020
+#define FRCBISTERR 0x00000010
+#define COMBISTEN 0x00000004
+#define COMBISTDONE 0x00000002 /* ro */
+#define COMBISTFAIL 0x00000001 /* ro */
+
+#define COMSTAT (REG_BASE_ADDR + 0x04)
+
+#define REQMBXREAD 0x00000040
+#define RSPMBXAVAIL 0x00000020
+#define CSBUFPERR 0x00000008
+#define OVLYERR 0x00000004
+#define CSERR 0x00000002
+#define OVLYDMADONE 0x00000001
+
+#define COMSTAT_MASK (REQMBXREAD | RSPMBXAVAIL | \
+ CSBUFPERR | OVLYERR | CSERR |\
+ OVLYDMADONE)
+
+#define COMSTATEN (REG_BASE_ADDR + 0x08)
+
+#define EN_REQMBXREAD 0x00000040
+#define EN_RSPMBXAVAIL 0x00000020
+#define EN_CSBUFPERR 0x00000008
+#define EN_OVLYERR 0x00000004
+#define EN_CSERR 0x00000002
+#define EN_OVLYDONE 0x00000001
+
+#define SCBPRO (REG_BASE_ADDR + 0x0C)
+
+#define SCBCONS_MASK 0xFFFF0000
+#define SCBPRO_MASK 0x0000FFFF
+
+#define CHIMREQMBX (REG_BASE_ADDR + 0x10)
+
+#define CHIMRSPMBX (REG_BASE_ADDR + 0x14)
+
+#define CHIMINT (REG_BASE_ADDR + 0x18)
+
+#define EXT_INT0 0x00000800
+#define EXT_INT1 0x00000400
+#define PORRSTDET 0x00000200
+#define HARDRSTDET 0x00000100
+#define DLAVAILQ 0x00000080 /* ro */
+#define HOSTERR 0x00000040
+#define INITERR 0x00000020
+#define DEVINT 0x00000010
+#define COMINT 0x00000008
+#define DEVTIMER2 0x00000004
+#define DEVTIMER1 0x00000002
+#define DLAVAIL 0x00000001
+
+#define CHIMINT_MASK (HOSTERR | INITERR | DEVINT | COMINT |\
+ DEVTIMER2 | DEVTIMER1 | DLAVAIL)
+
+#define DEVEXCEPT_MASK (HOSTERR | INITERR | DEVINT | COMINT)
+
+#define CHIMINTEN (REG_BASE_ADDR + 0x1C)
+
+#define RST_EN_EXT_INT1 0x01000000
+#define RST_EN_EXT_INT0 0x00800000
+#define RST_EN_HOSTERR 0x00400000
+#define RST_EN_INITERR 0x00200000
+#define RST_EN_DEVINT 0x00100000
+#define RST_EN_COMINT 0x00080000
+#define RST_EN_DEVTIMER2 0x00040000
+#define RST_EN_DEVTIMER1 0x00020000
+#define RST_EN_DLAVAIL 0x00010000
+#define SET_EN_EXT_INT1 0x00000100
+#define SET_EN_EXT_INT0 0x00000080
+#define SET_EN_HOSTERR 0x00000040
+#define SET_EN_INITERR 0x00000020
+#define SET_EN_DEVINT 0x00000010
+#define SET_EN_COMINT 0x00000008
+#define SET_EN_DEVTIMER2 0x00000004
+#define SET_EN_DEVTIMER1 0x00000002
+#define SET_EN_DLAVAIL 0x00000001
+
+#define RST_CHIMINTEN (RST_EN_HOSTERR | RST_EN_INITERR | \
+ RST_EN_DEVINT | RST_EN_COMINT | \
+ RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\
+ RST_EN_DLAVAIL)
+
+#define SET_CHIMINTEN (SET_EN_HOSTERR | SET_EN_INITERR |\
+ SET_EN_DEVINT | SET_EN_COMINT |\
+ SET_EN_DLAVAIL)
+
+#define OVLYDMACTL (REG_BASE_ADDR + 0x20)
+
+#define OVLYADR_MASK 0x07FF0000
+#define OVLYLSEQ_MASK 0x0000FF00
+#define OVLYCSEQ 0x00000080
+#define OVLYHALTERR 0x00000040
+#define PIOCMODE 0x00000020
+#define RESETOVLYDMA 0x00000008 /* wo */
+#define STARTOVLYDMA 0x00000004
+#define STOPOVLYDMA 0x00000002 /* wo */
+#define OVLYDMAACT 0x00000001 /* ro */
+
+#define OVLYDMACNT (REG_BASE_ADDR + 0x24)
+
+#define OVLYDOMAIN1 0x20000000 /* ro */
+#define OVLYDOMAIN0 0x10000000
+#define OVLYBUFADR_MASK 0x007F0000
+#define OVLYDMACNT_MASK 0x00003FFF
+
+#define OVLYDMAADR (REG_BASE_ADDR + 0x28)
+
+#define DMAERR (REG_BASE_ADDR + 0x30)
+
+#define OVLYERRSTAT_MASK 0x0000FF00 /* ro */
+#define CSERRSTAT_MASK 0x000000FF /* ro */
+
+#define SPIODATA (REG_BASE_ADDR + 0x34)
+
+/* 0x38 - 0x3C are reserved */
+
+#define T1CNTRLR (REG_BASE_ADDR + 0x40)
+
+#define T1DONE 0x00010000 /* ro */
+#define TIMER64 0x00000400
+#define T1ENABLE 0x00000200
+#define T1RELOAD 0x00000100
+#define T1PRESCALER_MASK 0x00000003
+
+#define T1CMPR (REG_BASE_ADDR + 0x44)
+
+#define T1CNTR (REG_BASE_ADDR + 0x48)
+
+#define T2CNTRLR (REG_BASE_ADDR + 0x4C)
+
+#define T2DONE 0x00010000 /* ro */
+#define T2ENABLE 0x00000200
+#define T2RELOAD 0x00000100
+#define T2PRESCALER_MASK 0x00000003
+
+#define T2CMPR (REG_BASE_ADDR + 0x50)
+
+#define T2CNTR (REG_BASE_ADDR + 0x54)
+
+/* 0x58h - 0xFCh are reserved */
+
+/*
+ * DCH_SAS Registers, Address Range : (0x800-0xFFF)
+ */
+#define CMDCTXBASE (REG_BASE_ADDR + 0x800)
+
+#define DEVCTXBASE (REG_BASE_ADDR + 0x808)
+
+#define CTXDOMAIN (REG_BASE_ADDR + 0x810)
+
+#define DEVCTXDOMAIN1 0x00000008 /* ro */
+#define DEVCTXDOMAIN0 0x00000004
+#define CMDCTXDOMAIN1 0x00000002 /* ro */
+#define CMDCTXDOMAIN0 0x00000001
+
+#define DCHCTL (REG_BASE_ADDR + 0x814)
+
+#define OCMBISTREPAIR 0x00080000
+#define OCMBISTEN 0x00040000
+#define OCMBISTDN 0x00020000 /* ro */
+#define OCMBISTFAIL 0x00010000 /* ro */
+#define DDBBISTEN 0x00004000
+#define DDBBISTDN 0x00002000 /* ro */
+#define DDBBISTFAIL 0x00001000 /* ro */
+#define SCBBISTEN 0x00000400
+#define SCBBISTDN 0x00000200 /* ro */
+#define SCBBISTFAIL 0x00000100 /* ro */
+
+#define MEMSEL_MASK 0x000000E0
+#define MEMSEL_CCM_LSEQ 0x00000000
+#define MEMSEL_CCM_IOP 0x00000020
+#define MEMSEL_CCM_SASCTL 0x00000040
+#define MEMSEL_DCM_LSEQ 0x00000060
+#define MEMSEL_DCM_IOP 0x00000080
+#define MEMSEL_OCM 0x000000A0
+
+#define FRCERR 0x00000010
+#define AUTORLS 0x00000001
+
+#define DCHREVISION (REG_BASE_ADDR + 0x818)
+
+#define DCHREVISION_MASK 0x000000FF
+
+#define DCHSTATUS (REG_BASE_ADDR + 0x81C)
+
+#define EN_CFIFTOERR 0x00020000
+#define CFIFTOERR 0x00000200
+#define CSEQINT 0x00000100 /* ro */
+#define LSEQ7INT 0x00000080 /* ro */
+#define LSEQ6INT 0x00000040 /* ro */
+#define LSEQ5INT 0x00000020 /* ro */
+#define LSEQ4INT 0x00000010 /* ro */
+#define LSEQ3INT 0x00000008 /* ro */
+#define LSEQ2INT 0x00000004 /* ro */
+#define LSEQ1INT 0x00000002 /* ro */
+#define LSEQ0INT 0x00000001 /* ro */
+
+#define LSEQINT_MASK (LSEQ7INT | LSEQ6INT | LSEQ5INT |\
+ LSEQ4INT | LSEQ3INT | LSEQ2INT |\
+ LSEQ1INT | LSEQ0INT)
+
+#define DCHDFIFDEBUG (REG_BASE_ADDR + 0x820)
+#define ENFAIRMST 0x00FF0000
+#define DISWRMST9 0x00000200
+#define DISWRMST8 0x00000100
+#define DISRDMST 0x000000FF
+
+#define ATOMICSTATCTL (REG_BASE_ADDR + 0x824)
+/* 8 bit wide */
+#define AUTOINC 0x80
+#define ATOMICERR 0x04
+#define ATOMICWIN 0x02
+#define ATOMICDONE 0x01
+
+
+#define ALTCIOADR (REG_BASE_ADDR + 0x828)
+/* 16 bit; bits 8:0 define CIO addr space of CSEQ */
+
+#define ASCBPTR (REG_BASE_ADDR + 0x82C)
+/* 16 bit wide */
+
+#define ADDBPTR (REG_BASE_ADDR + 0x82E)
+/* 16 bit wide */
+
+#define ANEWDATA (REG_BASE_ADDR + 0x830)
+/* 16 bit */
+
+#define AOLDDATA (REG_BASE_ADDR + 0x834)
+/* 16 bit */
+
+#define CTXACCESS (REG_BASE_ADDR + 0x838)
+/* 32 bit */
+
+/* 0x83Ch - 0xFFCh are reserved */
+
+/*
+ * ARP2 External Processor Registers, Address Range : (0x00-0x1F)
+ */
+#define ARP2CTL 0x00
+
+#define FRCSCRPERR 0x00040000
+#define FRCARP2PERR 0x00020000
+#define FRCARP2ILLOPC 0x00010000
+#define ENWAITTO 0x00008000
+#define PERRORDIS 0x00004000
+#define FAILDIS 0x00002000
+#define CIOPERRDIS 0x00001000
+#define BREAKEN3 0x00000800
+#define BREAKEN2 0x00000400
+#define BREAKEN1 0x00000200
+#define BREAKEN0 0x00000100
+#define EPAUSE 0x00000008
+#define PAUSED 0x00000004 /* ro */
+#define STEP 0x00000002
+#define ARP2RESET 0x00000001 /* wo */
+
+#define ARP2INT 0x04
+
+#define HALTCODE_MASK 0x00FF0000 /* ro */
+#define ARP2WAITTO 0x00000100
+#define ARP2HALTC 0x00000080
+#define ARP2ILLOPC 0x00000040
+#define ARP2PERR 0x00000020
+#define ARP2CIOPERR 0x00000010
+#define ARP2BREAK3 0x00000008
+#define ARP2BREAK2 0x00000004
+#define ARP2BREAK1 0x00000002
+#define ARP2BREAK0 0x00000001
+
+#define ARP2INTEN 0x08
+
+#define EN_ARP2WAITTO 0x00000100
+#define EN_ARP2HALTC 0x00000080
+#define EN_ARP2ILLOPC 0x00000040
+#define EN_ARP2PERR 0x00000020
+#define EN_ARP2CIOPERR 0x00000010
+#define EN_ARP2BREAK3 0x00000008
+#define EN_ARP2BREAK2 0x00000004
+#define EN_ARP2BREAK1 0x00000002
+#define EN_ARP2BREAK0 0x00000001
+
+#define ARP2BREAKADR01 0x0C
+
+#define BREAKADR1_MASK 0x0FFF0000
+#define BREAKADR0_MASK 0x00000FFF
+
+#define ARP2BREAKADR23 0x10
+
+#define BREAKADR3_MASK 0x0FFF0000
+#define BREAKADR2_MASK 0x00000FFF
+
+/* 0x14h - 0x1Ch are reserved */
+
+/*
+ * ARP2 Registers, Address Range : (0x00-0x1F)
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MODEPTR 0x00
+
+#define DSTMODE 0xF0
+#define SRCMODE 0x0F
+
+#define ALTMODE 0x01
+
+#define ALTDMODE 0xF0
+#define ALTSMODE 0x0F
+
+#define ATOMICXCHG 0x02
+
+#define FLAG 0x04
+
+#define INTCODE_MASK 0xF0
+#define ALTMODEV2 0x04
+#define CARRY_INT 0x02
+#define CARRY 0x01
+
+#define ARP2INTCTL 0x05
+
+#define PAUSEDIS 0x80
+#define RSTINTCTL 0x40
+#define POPALTMODE 0x08
+#define ALTMODEV 0x04
+#define INTMASK 0x02
+#define IRET 0x01
+
+#define STACK 0x06
+
+#define FUNCTION1 0x07
+
+#define PRGMCNT 0x08
+
+#define ACCUM 0x0A
+
+#define SINDEX 0x0C
+
+#define DINDEX 0x0E
+
+#define ALLONES 0x10
+
+#define ALLZEROS 0x11
+
+#define SINDIR 0x12
+
+#define DINDIR 0x13
+
+#define JUMLDIR 0x14
+
+#define ARP2HALTCODE 0x15
+
+#define CURRADDR 0x16
+
+#define LASTADDR 0x18
+
+#define NXTLADDR 0x1A
+
+#define DBGPORTPTR 0x1C
+
+#define DBGPORT 0x1D
+
+/*
+ * CIO Registers.
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MnSCBPTR 0x20
+
+#define MnDDBPTR 0x22
+
+#define SCRATCHPAGE 0x24
+
+#define MnSCRATCHPAGE 0x25
+
+#define SCRATCHPAGESV 0x26
+
+#define MnSCRATCHPAGESV 0x27
+
+#define MnDMAERRS 0x46
+
+#define MnSGDMAERRS 0x47
+
+#define MnSGBUF 0x53
+
+#define MnSGDMASTAT 0x5b
+
+#define MnDDMACTL 0x5c /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMASTAT 0x5d /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMAMODE 0x5e /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDMAENG 0x60
+
+#define MnPIPECTL 0x61
+
+#define MnSGBADR 0x65
+
+#define MnSCB_SITE 0x100
+
+#define MnDDB_SITE 0x180
+
+/*
+ * The common definitions below have the same address offset for both
+ * CSEQ and LmSEQ.
+ */
+#define BISTCTL0 0x4C
+
+#define BISTCTL1 0x50
+
+#define MAPPEDSCR 0x800
+
+/*
+ * CSEQ Host Register, Address Range : (0x000-0xFFC)
+ */
+#define CSEQ_HOST_REG_BASE_ADR 0xB8001000
+
+#define CARP2CTL (CSEQ_HOST_REG_BASE_ADR + ARP2CTL)
+
+#define CARP2INT (CSEQ_HOST_REG_BASE_ADR + ARP2INT)
+
+#define CARP2INTEN (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN)
+
+#define CARP2BREAKADR01 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01)
+
+#define CARP2BREAKADR23 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23)
+
+#define CBISTCTL (CSEQ_HOST_REG_BASE_ADR + BISTCTL1)
+
+#define CSEQRAMBISTEN 0x00000040
+#define CSEQRAMBISTDN 0x00000020 /* ro */
+#define CSEQRAMBISTFAIL 0x00000010 /* ro */
+#define CSEQSCRBISTEN 0x00000004
+#define CSEQSCRBISTDN 0x00000002 /* ro */
+#define CSEQSCRBISTFAIL 0x00000001 /* ro */
+
+#define CMAPPEDSCR (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR)
+
+/*
+ * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC)
+ * 16 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define CSEQ_CIO_REG_BASE_ADR REG_BASE_ADDR_CSEQCIO
+
+#define CSEQm_CIO_REG(Mode, Reg) \
+ (CSEQ_CIO_REG_BASE_ADR + \
+ ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg))
+
+#define CMODEPTR (CSEQ_CIO_REG_BASE_ADR + MODEPTR)
+
+#define CALTMODE (CSEQ_CIO_REG_BASE_ADR + ALTMODE)
+
+#define CATOMICXCHG (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG)
+
+#define CFLAG (CSEQ_CIO_REG_BASE_ADR + FLAG)
+
+#define CARP2INTCTL (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL)
+
+#define CSTACK (CSEQ_CIO_REG_BASE_ADR + STACK)
+
+#define CFUNCTION1 (CSEQ_CIO_REG_BASE_ADR + FUNCTION1)
+
+#define CPRGMCNT (CSEQ_CIO_REG_BASE_ADR + PRGMCNT)
+
+#define CACCUM (CSEQ_CIO_REG_BASE_ADR + ACCUM)
+
+#define CSINDEX (CSEQ_CIO_REG_BASE_ADR + SINDEX)
+
+#define CDINDEX (CSEQ_CIO_REG_BASE_ADR + DINDEX)
+
+#define CALLONES (CSEQ_CIO_REG_BASE_ADR + ALLONES)
+
+#define CALLZEROS (CSEQ_CIO_REG_BASE_ADR + ALLZEROS)
+
+#define CSINDIR (CSEQ_CIO_REG_BASE_ADR + SINDIR)
+
+#define CDINDIR (CSEQ_CIO_REG_BASE_ADR + DINDIR)
+
+#define CJUMLDIR (CSEQ_CIO_REG_BASE_ADR + JUMLDIR)
+
+#define CARP2HALTCODE (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE)
+
+#define CCURRADDR (CSEQ_CIO_REG_BASE_ADR + CURRADDR)
+
+#define CLASTADDR (CSEQ_CIO_REG_BASE_ADR + LASTADDR)
+
+#define CNXTLADDR (CSEQ_CIO_REG_BASE_ADR + NXTLADDR)
+
+#define CDBGPORTPTR (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR)
+
+#define CDBGPORT (CSEQ_CIO_REG_BASE_ADR + DBGPORT)
+
+#define CSCRATCHPAGE (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE)
+
+#define CMnSCBPTR(Mode) CSEQm_CIO_REG(Mode, MnSCBPTR)
+
+#define CMnDDBPTR(Mode) CSEQm_CIO_REG(Mode, MnDDBPTR)
+
+#define CMnSCRATCHPAGE(Mode) CSEQm_CIO_REG(Mode, MnSCRATCHPAGE)
+
+#define CLINKCON (CSEQ_CIO_REG_BASE_ADR + 0x28)
+
+#define CCIOAACESS (CSEQ_CIO_REG_BASE_ADR + 0x2C)
+
+/* mode 0-7 */
+#define MnREQMBX 0x30
+#define CMnREQMBX(Mode) CSEQm_CIO_REG(Mode, 0x30)
+
+/* mode 8 */
+#define CSEQCON CSEQm_CIO_REG(8, 0x30)
+
+/* mode 0-7 */
+#define MnRSPMBX 0x34
+#define CMnRSPMBX(Mode) CSEQm_CIO_REG(Mode, 0x34)
+
+/* mode 8 */
+#define CSEQCOMCTL CSEQm_CIO_REG(8, 0x34)
+
+/* mode 8 */
+#define CSEQCOMSTAT CSEQm_CIO_REG(8, 0x35)
+
+/* mode 8 */
+#define CSEQCOMINTEN CSEQm_CIO_REG(8, 0x36)
+
+/* mode 8 */
+#define CSEQCOMDMACTL CSEQm_CIO_REG(8, 0x37)
+
+#define CSHALTERR 0x10
+#define RESETCSDMA 0x08 /* wo */
+#define STARTCSDMA 0x04
+#define STOPCSDMA 0x02 /* wo */
+#define CSDMAACT 0x01 /* ro */
+
+/* mode 0-7 */
+#define MnINT 0x38
+#define CMnINT(Mode) CSEQm_CIO_REG(Mode, 0x38)
+
+#define CMnREQMBXE 0x02
+#define CMnRSPMBXF 0x01
+#define CMnINT_MASK 0x00000003
+
+/* mode 8 */
+#define CSEQREQMBX CSEQm_CIO_REG(8, 0x38)
+
+/* mode 0-7 */
+#define MnINTEN 0x3C
+#define CMnINTEN(Mode) CSEQm_CIO_REG(Mode, 0x3C)
+
+#define EN_CMnRSPMBXF 0x01
+
+/* mode 8 */
+#define CSEQRSPMBX CSEQm_CIO_REG(8, 0x3C)
+
+/* mode 8 */
+#define CSDMAADR CSEQm_CIO_REG(8, 0x40)
+
+/* mode 8 */
+#define CSDMACNT CSEQm_CIO_REG(8, 0x48)
+
+/* mode 8 */
+#define CSEQDLCTL CSEQm_CIO_REG(8, 0x4D)
+
+#define DONELISTEND 0x10
+#define DONELISTSIZE_MASK 0x0F
+#define DONELISTSIZE_8ELEM 0x01
+#define DONELISTSIZE_16ELEM 0x02
+#define DONELISTSIZE_32ELEM 0x03
+#define DONELISTSIZE_64ELEM 0x04
+#define DONELISTSIZE_128ELEM 0x05
+#define DONELISTSIZE_256ELEM 0x06
+#define DONELISTSIZE_512ELEM 0x07
+#define DONELISTSIZE_1024ELEM 0x08
+#define DONELISTSIZE_2048ELEM 0x09
+#define DONELISTSIZE_4096ELEM 0x0A
+#define DONELISTSIZE_8192ELEM 0x0B
+#define DONELISTSIZE_16384ELEM 0x0C
+
+/* mode 8 */
+#define CSEQDLOFFS CSEQm_CIO_REG(8, 0x4E)
+
+/* mode 11 */
+#define CM11INTVEC0 CSEQm_CIO_REG(11, 0x50)
+
+/* mode 11 */
+#define CM11INTVEC1 CSEQm_CIO_REG(11, 0x52)
+
+/* mode 11 */
+#define CM11INTVEC2 CSEQm_CIO_REG(11, 0x54)
+
+#define CCONMSK (CSEQ_CIO_REG_BASE_ADR + 0x60)
+
+#define CCONEXIST (CSEQ_CIO_REG_BASE_ADR + 0x61)
+
+#define CCONMODE (CSEQ_CIO_REG_BASE_ADR + 0x62)
+
+#define CTIMERCALC (CSEQ_CIO_REG_BASE_ADR + 0x64)
+
+#define CINTDIS (CSEQ_CIO_REG_BASE_ADR + 0x68)
+
+/* mode 8, 32x32 bits, 128 bytes of mapped buffer */
+#define CSBUFFER CSEQm_CIO_REG(8, 0x80)
+
+#define CSCRATCH (CSEQ_CIO_REG_BASE_ADR + 0x1C0)
+
+/* mode 0-8 */
+#define CMnSCRATCH(Mode) CSEQm_CIO_REG(Mode, 0x1E0)
+
+/*
+ * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC)
+ */
+#define CSEQ_RAM_REG_BASE_ADR 0xB8004000
+
+/*
+ * The common definitions below have the same address offset for all the Link
+ * sequencers.
+ */
+#define MODECTL 0x40
+
+#define DBGMODE 0x44
+
+#define CONTROL 0x48
+#define LEDTIMER 0x00010000
+#define LEDTIMERS_10us 0x00000000
+#define LEDTIMERS_1ms 0x00000800
+#define LEDTIMERS_100ms 0x00001000
+#define LEDMODE_TXRX 0x00000000
+#define LEDMODE_CONNECTED 0x00000200
+#define LEDPOL 0x00000100
+
+#define LSEQRAM 0x1000
+
+/*
+ * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC)
+ */
+#define LSEQ0_HOST_REG_BASE_ADR 0xB8020000
+#define LSEQ1_HOST_REG_BASE_ADR 0xB8024000
+#define LSEQ2_HOST_REG_BASE_ADR 0xB8028000
+#define LSEQ3_HOST_REG_BASE_ADR 0xB802C000
+#define LSEQ4_HOST_REG_BASE_ADR 0xB8030000
+#define LSEQ5_HOST_REG_BASE_ADR 0xB8034000
+#define LSEQ6_HOST_REG_BASE_ADR 0xB8038000
+#define LSEQ7_HOST_REG_BASE_ADR 0xB803C000
+
+#define LmARP2CTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2CTL)
+
+#define LmARP2INT(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2INT)
+
+#define LmARP2INTEN(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2INTEN)
+
+#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ DBGMODE)
+
+#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ CONTROL)
+
+#define LmARP2BREAKADR01(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2BREAKADR01)
+
+#define LmARP2BREAKADR23(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2BREAKADR23)
+
+#define LmMODECTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ MODECTL)
+
+#define LmAUTODISCI 0x08000000
+#define LmDSBLBITLT 0x04000000
+#define LmDSBLANTT 0x02000000
+#define LmDSBLCRTT 0x01000000
+#define LmDSBLCONT 0x00000100
+#define LmPRIMODE 0x00000080
+#define LmDSBLHOLD 0x00000040
+#define LmDISACK 0x00000020
+#define LmBLIND48 0x00000010
+#define LmRCVMODE_MASK 0x0000000C
+#define LmRCVMODE_PLD 0x00000000
+#define LmRCVMODE_HPC 0x00000004
+
+#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ DBGMODE)
+
+#define LmFRCPERR 0x80000000
+#define LmMEMSEL_MASK 0x30000000
+#define LmFRCRBPERR 0x00000000
+#define LmFRCTBPERR 0x10000000
+#define LmFRCSGBPERR 0x20000000
+#define LmFRCARBPERR 0x30000000
+#define LmRCVIDW 0x00080000
+#define LmINVDWERR 0x00040000
+#define LmRCVDISP 0x00004000
+#define LmDISPERR 0x00002000
+#define LmDSBLDSCR 0x00000800
+#define LmDSBLSCR 0x00000400
+#define LmFRCNAK 0x00000200
+#define LmFRCROFS 0x00000100
+#define LmFRCCRC 0x00000080
+#define LmFRMTYPE_MASK 0x00000070
+#define LmSG_DATA 0x00000000
+#define LmSG_COMMAND 0x00000010
+#define LmSG_TASK 0x00000020
+#define LmSG_TGTXFER 0x00000030
+#define LmSG_RESPONSE 0x00000040
+#define LmSG_IDENADDR 0x00000050
+#define LmSG_OPENADDR 0x00000060
+#define LmDISCRCGEN 0x00000008
+#define LmDISCRCCHK 0x00000004
+#define LmSSXMTFRM 0x00000002
+#define LmSSRCVFRM 0x00000001
+
+#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ CONTROL)
+
+#define LmSTEPXMTFRM 0x00000002
+#define LmSTEPRCVFRM 0x00000001
+
+#define LmBISTCTL0(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ BISTCTL0)
+
+#define ARBBISTEN 0x40000000
+#define ARBBISTDN 0x20000000 /* ro */
+#define ARBBISTFAIL 0x10000000 /* ro */
+#define TBBISTEN 0x00000400
+#define TBBISTDN 0x00000200 /* ro */
+#define TBBISTFAIL 0x00000100 /* ro */
+#define RBBISTEN 0x00000040
+#define RBBISTDN 0x00000020 /* ro */
+#define RBBISTFAIL 0x00000010 /* ro */
+#define SGBISTEN 0x00000004
+#define SGBISTDN 0x00000002 /* ro */
+#define SGBISTFAIL 0x00000001 /* ro */
+
+#define LmBISTCTL1(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\
+ BISTCTL1)
+
+#define LmRAMPAGE1 0x00000200
+#define LmRAMPAGE0 0x00000100
+#define LmIMEMBISTEN 0x00000040
+#define LmIMEMBISTDN 0x00000020 /* ro */
+#define LmIMEMBISTFAIL 0x00000010 /* ro */
+#define LmSCRBISTEN 0x00000004
+#define LmSCRBISTDN 0x00000002 /* ro */
+#define LmSCRBISTFAIL 0x00000001 /* ro */
+#define LmRAMPAGE (LmRAMPAGE1 + LmRAMPAGE0)
+#define LmRAMPAGE_LSHIFT 0x8
+
+#define LmSCRATCH(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+ MAPPEDSCR)
+
+#define LmSEQRAM(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+ LSEQRAM)
+
+/*
+ * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC)
+ * 8 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define LmSEQ_CIOBUS_REG_BASE 0x2000
+
+#define LmSEQ_PHY_BASE(Mode, LinkNum) \
+ (LSEQ0_HOST_REG_BASE_ADR + \
+ (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \
+ LmSEQ_CIOBUS_REG_BASE + \
+ ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE))
+
+#define LmSEQ_PHY_REG(Mode, LinkNum, Reg) \
+ (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg))
+
+#define LmMODEPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, MODEPTR)
+
+#define LmALTMODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALTMODE)
+
+#define LmATOMICXCHG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG)
+
+#define LmFLAG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FLAG)
+
+#define LmARP2INTCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL)
+
+#define LmSTACK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, STACK)
+
+#define LmFUNCTION1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FUNCTION1)
+
+#define LmPRGMCNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, PRGMCNT)
+
+#define LmACCUM(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ACCUM)
+
+#define LmSINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDEX)
+
+#define LmDINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDEX)
+
+#define LmALLONES(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLONES)
+
+#define LmALLZEROS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLZEROS)
+
+#define LmSINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDIR)
+
+#define LmDINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDIR)
+
+#define LmJUMLDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, JUMLDIR)
+
+#define LmARP2HALTCODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE)
+
+#define LmCURRADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, CURRADDR)
+
+#define LmLASTADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, LASTADDR)
+
+#define LmNXTLADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, NXTLADDR)
+
+#define LmDBGPORTPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR)
+
+#define LmDBGPORT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORT)
+
+#define LmSCRATCHPAGE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE)
+
+#define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, \
+ MnSCRATCHPAGE)
+
+#define LmTIMERCALC(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x28)
+
+#define LmREQMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x30)
+
+#define LmRSPMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x34)
+
+#define LmMnINT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x38)
+
+#define CTXMEMSIZE 0x80000000 /* ro */
+#define LmACKREQ 0x08000000
+#define LmNAKREQ 0x04000000
+#define LmMnXMTERR 0x02000000
+#define LmM5OOBSVC 0x01000000
+#define LmHWTINT 0x00800000
+#define LmMnCTXDONE 0x00100000
+#define LmM2REQMBXF 0x00080000
+#define LmM2RSPMBXE 0x00040000
+#define LmMnDMAERR 0x00020000
+#define LmRCVPRIM 0x00010000
+#define LmRCVERR 0x00008000
+#define LmADDRRCV 0x00004000
+#define LmMnHDRMISS 0x00002000
+#define LmMnWAITSCB 0x00001000
+#define LmMnRLSSCB 0x00000800
+#define LmMnSAVECTX 0x00000400
+#define LmMnFETCHSG 0x00000200
+#define LmMnLOADCTX 0x00000100
+#define LmMnCFGICL 0x00000080
+#define LmMnCFGSATA 0x00000040
+#define LmMnCFGEXPSATA 0x00000020
+#define LmMnCFGCMPLT 0x00000010
+#define LmMnCFGRBUF 0x00000008
+#define LmMnSAVETTR 0x00000004
+#define LmMnCFGRDAT 0x00000002
+#define LmMnCFGHDR 0x00000001
+
+#define LmMnINTEN(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x3C)
+
+#define EN_LmACKREQ 0x08000000
+#define EN_LmNAKREQ 0x04000000
+#define EN_LmMnXMTERR 0x02000000
+#define EN_LmM5OOBSVC 0x01000000
+#define EN_LmHWTINT 0x00800000
+#define EN_LmMnCTXDONE 0x00100000
+#define EN_LmM2REQMBXF 0x00080000
+#define EN_LmM2RSPMBXE 0x00040000
+#define EN_LmMnDMAERR 0x00020000
+#define EN_LmRCVPRIM 0x00010000
+#define EN_LmRCVERR 0x00008000
+#define EN_LmADDRRCV 0x00004000
+#define EN_LmMnHDRMISS 0x00002000
+#define EN_LmMnWAITSCB 0x00001000
+#define EN_LmMnRLSSCB 0x00000800
+#define EN_LmMnSAVECTX 0x00000400
+#define EN_LmMnFETCHSG 0x00000200
+#define EN_LmMnLOADCTX 0x00000100
+#define EN_LmMnCFGICL 0x00000080
+#define EN_LmMnCFGSATA 0x00000040
+#define EN_LmMnCFGEXPSATA 0x00000020
+#define EN_LmMnCFGCMPLT 0x00000010
+#define EN_LmMnCFGRBUF 0x00000008
+#define EN_LmMnSAVETTR 0x00000004
+#define EN_LmMnCFGRDAT 0x00000002
+#define EN_LmMnCFGHDR 0x00000001
+
+#define LmM0INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \
+ EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \
+ EN_LmMnCFGHDR | EN_LmRCVERR | \
+ EN_LmADDRRCV | EN_LmMnHDRMISS | \
+ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+ EN_LmHWTINT | EN_LmMnCTXDONE | \
+ EN_LmRCVPRIM | EN_LmMnCFGSATA | \
+ EN_LmMnCFGEXPSATA | EN_LmMnDMAERR)
+
+#define LmM1INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \
+ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+ EN_LmMnXMTERR | EN_LmHWTINT | \
+ EN_LmMnCTXDONE | EN_LmRCVPRIM | \
+ EN_LmRCVERR | EN_LmMnDMAERR)
+
+#define LmM2INTEN_MASK (EN_LmADDRRCV | EN_LmHWTINT | \
+ EN_LmM2REQMBXF | EN_LmRCVPRIM | \
+ EN_LmRCVERR)
+
+#define LmM5INTEN_MASK (EN_LmADDRRCV | EN_LmM5OOBSVC | \
+ EN_LmHWTINT | EN_LmRCVPRIM | \
+ EN_LmRCVERR)
+
+#define LmXMTPRIMD(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x40)
+
+#define LmXMTPRIMCS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x44)
+
+#define LmCONSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x45)
+
+#define LmMnDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x46)
+
+#define LmMnSGDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x47)
+
+#define LmM0EXPHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x48)
+
+#define LmM1SASALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x48)
+#define SAS_ALIGN_DEFAULT 0xFF
+
+#define LmM0MSKHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x49)
+
+#define LmM1STPALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x49)
+#define STP_ALIGN_DEFAULT 0x1F
+
+#define LmM0RCVHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4A)
+
+#define LmM1XMTHDRP(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4A)
+
+#define LmM0ICLADR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4B)
+
+#define LmM1ALIGNMODE(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4B)
+
+#define LmDISALIGN 0x20
+#define LmROTSTPALIGN 0x10
+#define LmSTPALIGN 0x08
+#define LmROTNOTIFY 0x04
+#define LmDUALALIGN 0x02
+#define LmROTALIGN 0x01
+
+#define LmM0EXPRCVNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4C)
+
+#define LmM1XMTCNT(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4C)
+
+#define LmMnBUFSTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x4E)
+
+#define LmMnBUFPERR 0x01
+
+/* mode 0-1 */
+#define LmMnXFRLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x59)
+
+#define LmMnXFRLVL_128 0x05
+#define LmMnXFRLVL_256 0x04
+#define LmMnXFRLVL_512 0x03
+#define LmMnXFRLVL_1024 0x02
+#define LmMnXFRLVL_1536 0x01
+#define LmMnXFRLVL_2048 0x00
+
+ /* mode 0-1 */
+#define LmMnSGDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5A)
+
+#define LmMnRESETSG 0x04
+#define LmMnSTOPSG 0x02
+#define LmMnSTARTSG 0x01
+
+/* mode 0-1 */
+#define LmMnSGDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5B)
+
+/* mode 0-1 */
+#define LmMnDDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5C)
+
+#define LmMnFLUSH 0x40 /* wo */
+#define LmMnRLSRTRY 0x20 /* wo */
+#define LmMnDISCARD 0x10 /* wo */
+#define LmMnRESETDAT 0x08 /* wo */
+#define LmMnSUSDAT 0x04 /* wo */
+#define LmMnSTOPDAT 0x02 /* wo */
+#define LmMnSTARTDAT 0x01 /* wo */
+
+/* mode 0-1 */
+#define LmMnDDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5D)
+
+#define LmMnDPEMPTY 0x80
+#define LmMnFLUSHING 0x40
+#define LmMnDDMAREQ 0x20
+#define LmMnHDMAREQ 0x10
+#define LmMnDATFREE 0x08
+#define LmMnDATSUS 0x04
+#define LmMnDATACT 0x02
+#define LmMnDATEN 0x01
+
+/* mode 0-1 */
+#define LmMnDDMAMODE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5E)
+
+#define LmMnDMATYPE_NORMAL 0x0000
+#define LmMnDMATYPE_HOST_ONLY_TX 0x0001
+#define LmMnDMATYPE_DEVICE_ONLY_TX 0x0002
+#define LmMnDMATYPE_INVALID 0x0003
+#define LmMnDMATYPE_MASK 0x0003
+
+#define LmMnDMAWRAP 0x0004
+#define LmMnBITBUCKET 0x0008
+#define LmMnDISHDR 0x0010
+#define LmMnSTPCRC 0x0020
+#define LmXTEST 0x0040
+#define LmMnDISCRC 0x0080
+#define LmMnENINTLK 0x0100
+#define LmMnADDRFRM 0x0400
+#define LmMnENXMTCRC 0x0800
+
+/* mode 0-1 */
+#define LmMnXFRCNT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x70)
+
+/* mode 0-1 */
+#define LmMnDPSEL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7B)
+#define LmMnDPSEL_MASK 0x07
+#define LmMnEOLPRE 0x40
+#define LmMnEOSPRE 0x80
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Receive Mode n = 0 */
+#define LmMnHRADDR 0x00
+#define LmMnHBYTECNT 0x01
+#define LmMnHREWIND 0x02
+#define LmMnDWADDR 0x03
+#define LmMnDSPACECNT 0x04
+#define LmMnDFRMSIZE 0x05
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Transmit Mode n = 1 */
+#define LmMnHWADDR 0x00
+#define LmMnHSPACECNT 0x01
+/* #define LmMnHREWIND 0x02 */
+#define LmMnDRADDR 0x03
+#define LmMnDBYTECNT 0x04
+/* #define LmMnDFRMSIZE 0x05 */
+
+/* mode 0-1 */
+#define LmMnDPACC(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x78)
+#define LmMnDPACC_MASK 0x00FFFFFF
+
+/* mode 0-1 */
+#define LmMnHOLDLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7D)
+
+#define LmPRMSTAT0(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x80)
+#define LmPRMSTAT0BYTE0 0x80
+#define LmPRMSTAT0BYTE1 0x81
+#define LmPRMSTAT0BYTE2 0x82
+#define LmPRMSTAT0BYTE3 0x83
+
+#define LmFRAMERCVD 0x80000000
+#define LmXFRRDYRCVD 0x40000000
+#define LmUNKNOWNP 0x20000000
+#define LmBREAK 0x10000000
+#define LmDONE 0x08000000
+#define LmOPENACPT 0x04000000
+#define LmOPENRJCT 0x02000000
+#define LmOPENRTRY 0x01000000
+#define LmCLOSERV1 0x00800000
+#define LmCLOSERV0 0x00400000
+#define LmCLOSENORM 0x00200000
+#define LmCLOSECLAF 0x00100000
+#define LmNOTIFYRV2 0x00080000
+#define LmNOTIFYRV1 0x00040000
+#define LmNOTIFYRV0 0x00020000
+#define LmNOTIFYSPIN 0x00010000
+#define LmBROADRV4 0x00008000
+#define LmBROADRV3 0x00004000
+#define LmBROADRV2 0x00002000
+#define LmBROADRV1 0x00001000
+#define LmBROADSES 0x00000800
+#define LmBROADRVCH1 0x00000400
+#define LmBROADRVCH0 0x00000200
+#define LmBROADCH 0x00000100
+#define LmAIPRVWP 0x00000080
+#define LmAIPWP 0x00000040
+#define LmAIPWD 0x00000020
+#define LmAIPWC 0x00000010
+#define LmAIPRV2 0x00000008
+#define LmAIPRV1 0x00000004
+#define LmAIPRV0 0x00000002
+#define LmAIPNRML 0x00000001
+
+#define LmBROADCAST_MASK (LmBROADCH | LmBROADRVCH0 | \
+ LmBROADRVCH1)
+
+#define LmPRMSTAT1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x84)
+#define LmPRMSTAT1BYTE0 0x84
+#define LmPRMSTAT1BYTE1 0x85
+#define LmPRMSTAT1BYTE2 0x86
+#define LmPRMSTAT1BYTE3 0x87
+
+#define LmFRMRCVDSTAT 0x80000000
+#define LmBREAK_DET 0x04000000
+#define LmCLOSE_DET 0x02000000
+#define LmDONE_DET 0x01000000
+#define LmXRDY 0x00040000
+#define LmSYNCSRST 0x00020000
+#define LmSYNC 0x00010000
+#define LmXHOLD 0x00008000
+#define LmRRDY 0x00004000
+#define LmHOLD 0x00002000
+#define LmROK 0x00001000
+#define LmRIP 0x00000800
+#define LmCRBLK 0x00000400
+#define LmACK 0x00000200
+#define LmNAK 0x00000100
+#define LmHARDRST 0x00000080
+#define LmERROR 0x00000040
+#define LmRERR 0x00000020
+#define LmPMREQP 0x00000010
+#define LmPMREQS 0x00000008
+#define LmPMACK 0x00000004
+#define LmPMNAK 0x00000002
+#define LmDMAT 0x00000001
+
+/* mode 1 */
+#define LmMnSATAFS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7E)
+#define LmMnXMTSIZE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x93)
+
+/* mode 0 */
+#define LmMnFRMERR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xB0)
+
+#define LmACRCERR 0x00000800
+#define LmPHYOVRN 0x00000400
+#define LmOBOVRN 0x00000200
+#define LmMnZERODATA 0x00000100
+#define LmSATAINTLK 0x00000080
+#define LmMnCRCERR 0x00000020
+#define LmRRDYOVRN 0x00000010
+#define LmMISSSOAF 0x00000008
+#define LmMISSSOF 0x00000004
+#define LmMISSEOAF 0x00000002
+#define LmMISSEOF 0x00000001
+
+#define LmFRMERREN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xB4)
+
+#define EN_LmACRCERR 0x00000800
+#define EN_LmPHYOVRN 0x00000400
+#define EN_LmOBOVRN 0x00000200
+#define EN_LmMnZERODATA 0x00000100
+#define EN_LmSATAINTLK 0x00000080
+#define EN_LmFRMBAD 0x00000040
+#define EN_LmMnCRCERR 0x00000020
+#define EN_LmRRDYOVRN 0x00000010
+#define EN_LmMISSSOAF 0x00000008
+#define EN_LmMISSSOF 0x00000004
+#define EN_LmMISSEOAF 0x00000002
+#define EN_LmMISSEOF 0x00000001
+
+#define LmFRMERREN_MASK (EN_LmSATAINTLK | EN_LmMnCRCERR | \
+ EN_LmRRDYOVRN | EN_LmMISSSOF | \
+ EN_LmMISSEOAF | EN_LmMISSEOF | \
+ EN_LmACRCERR | LmPHYOVRN | \
+ EN_LmOBOVRN | EN_LmMnZERODATA)
+
+#define LmHWTSTATEN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC5)
+
+#define EN_LmDONETO 0x80
+#define EN_LmINVDISP 0x40
+#define EN_LmINVDW 0x20
+#define EN_LmDWSEVENT 0x08
+#define EN_LmCRTTTO 0x04
+#define EN_LmANTTTO 0x02
+#define EN_LmBITLTTO 0x01
+
+#define LmHWTSTATEN_MASK (EN_LmINVDISP | EN_LmINVDW | \
+ EN_LmDWSEVENT | EN_LmCRTTTO | \
+ EN_LmANTTTO | EN_LmDONETO | \
+ EN_LmBITLTTO)
+
+#define LmHWTSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC7)
+
+#define LmDONETO 0x80
+#define LmINVDISP 0x40
+#define LmINVDW 0x20
+#define LmDWSEVENT 0x08
+#define LmCRTTTO 0x04
+#define LmANTTTO 0x02
+#define LmBITLTTO 0x01
+
+#define LmMnDATABUFADR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xC8)
+#define LmDATABUFADR_MASK 0x0FFF
+
+#define LmMnDATABUF(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xCA)
+
+#define LmPRIMSTAT0EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE0)
+
+#define EN_LmUNKNOWNP 0x20000000
+#define EN_LmBREAK 0x10000000
+#define EN_LmDONE 0x08000000
+#define EN_LmOPENACPT 0x04000000
+#define EN_LmOPENRJCT 0x02000000
+#define EN_LmOPENRTRY 0x01000000
+#define EN_LmCLOSERV1 0x00800000
+#define EN_LmCLOSERV0 0x00400000
+#define EN_LmCLOSENORM 0x00200000
+#define EN_LmCLOSECLAF 0x00100000
+#define EN_LmNOTIFYRV2 0x00080000
+#define EN_LmNOTIFYRV1 0x00040000
+#define EN_LmNOTIFYRV0 0x00020000
+#define EN_LmNOTIFYSPIN 0x00010000
+#define EN_LmBROADRV4 0x00008000
+#define EN_LmBROADRV3 0x00004000
+#define EN_LmBROADRV2 0x00002000
+#define EN_LmBROADRV1 0x00001000
+#define EN_LmBROADRV0 0x00000800
+#define EN_LmBROADRVCH1 0x00000400
+#define EN_LmBROADRVCH0 0x00000200
+#define EN_LmBROADCH 0x00000100
+#define EN_LmAIPRVWP 0x00000080
+#define EN_LmAIPWP 0x00000040
+#define EN_LmAIPWD 0x00000020
+#define EN_LmAIPWC 0x00000010
+#define EN_LmAIPRV2 0x00000008
+#define EN_LmAIPRV1 0x00000004
+#define EN_LmAIPRV0 0x00000002
+#define EN_LmAIPNRML 0x00000001
+
+#define LmPRIMSTAT0EN_MASK (EN_LmBREAK | \
+ EN_LmDONE | EN_LmOPENACPT | \
+ EN_LmOPENRJCT | EN_LmOPENRTRY | \
+ EN_LmCLOSERV1 | EN_LmCLOSERV0 | \
+ EN_LmCLOSENORM | EN_LmCLOSECLAF | \
+ EN_LmBROADRV4 | EN_LmBROADRV3 | \
+ EN_LmBROADRV2 | EN_LmBROADRV1 | \
+ EN_LmBROADRV0 | EN_LmBROADRVCH1 | \
+ EN_LmBROADRVCH0 | EN_LmBROADCH | \
+ EN_LmAIPRVWP | EN_LmAIPWP | \
+ EN_LmAIPWD | EN_LmAIPWC | \
+ EN_LmAIPRV2 | EN_LmAIPRV1 | \
+ EN_LmAIPRV0 | EN_LmAIPNRML)
+
+#define LmPRIMSTAT1EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE4)
+
+#define EN_LmXRDY 0x00040000
+#define EN_LmSYNCSRST 0x00020000
+#define EN_LmSYNC 0x00010000
+#define EN_LmXHOLD 0x00008000
+#define EN_LmRRDY 0x00004000
+#define EN_LmHOLD 0x00002000
+#define EN_LmROK 0x00001000
+#define EN_LmRIP 0x00000800
+#define EN_LmCRBLK 0x00000400
+#define EN_LmACK 0x00000200
+#define EN_LmNAK 0x00000100
+#define EN_LmHARDRST 0x00000080
+#define EN_LmERROR 0x00000040
+#define EN_LmRERR 0x00000020
+#define EN_LmPMREQP 0x00000010
+#define EN_LmPMREQS 0x00000008
+#define EN_LmPMACK 0x00000004
+#define EN_LmPMNAK 0x00000002
+#define EN_LmDMAT 0x00000001
+
+#define LmPRIMSTAT1EN_MASK (EN_LmHARDRST | \
+ EN_LmSYNCSRST | \
+ EN_LmPMREQP | EN_LmPMREQS | \
+ EN_LmPMACK | EN_LmPMNAK)
+
+#define LmSMSTATE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE8)
+
+#define LmSMSTATEBRK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xEC)
+
+#define LmSMDBGCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xF0)
+
+
+/*
+ * LmSEQ CIO Bus Mode 3 Register.
+ * Mode 3: Configuration and Setup, IOP Context SCB.
+ */
+#define LmM3SATATIMER(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x48)
+
+#define LmM3INTVEC0(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x90)
+
+#define LmM3INTVEC1(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x92)
+
+#define LmM3INTVEC2(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x94)
+
+#define LmM3INTVEC3(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x96)
+
+#define LmM3INTVEC4(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x98)
+
+#define LmM3INTVEC5(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9A)
+
+#define LmM3INTVEC6(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9C)
+
+#define LmM3INTVEC7(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9E)
+
+#define LmM3INTVEC8(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA4)
+
+#define LmM3INTVEC9(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA6)
+
+#define LmM3INTVEC10(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB0)
+
+#define LmM3FRMGAP(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB4)
+
+#define LmBITL_TIMER(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA2)
+
+#define LmWWN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA8)
+
+
+/*
+ * LmSEQ CIO Bus Mode 5 Registers.
+ * Mode 5: Phy/OOB Control and Status.
+ */
+#define LmSEQ_OOB_REG(phy_id, reg) LmSEQ_PHY_REG(5, (phy_id), (reg))
+
+#define OOB_BFLTR 0x100
+
+#define BFLTR_THR_MASK 0xF0
+#define BFLTR_TC_MASK 0x0F
+
+#define OOB_INIT_MIN 0x102
+
+#define OOB_INIT_MAX 0x104
+
+#define OOB_INIT_NEG 0x106
+
+#define OOB_SAS_MIN 0x108
+
+#define OOB_SAS_MAX 0x10A
+
+#define OOB_SAS_NEG 0x10C
+
+#define OOB_WAKE_MIN 0x10E
+
+#define OOB_WAKE_MAX 0x110
+
+#define OOB_WAKE_NEG 0x112
+
+#define OOB_IDLE_MAX 0x114
+
+#define OOB_BURST_MAX 0x116
+
+#define OOB_DATA_KBITS 0x126
+
+#define OOB_ALIGN_0_DATA 0x12C
+
+#define OOB_ALIGN_1_DATA 0x130
+
+#define D10_2_DATA_k 0x00
+#define SYNC_DATA_k 0x02
+#define ALIGN_1_DATA_k 0x04
+#define ALIGN_0_DATA_k 0x08
+#define BURST_DATA_k 0x10
+
+#define OOB_PHY_RESET_COUNT 0x13C
+
+#define OOB_SIG_GEN 0x140
+
+#define START_OOB 0x80
+#define START_DWS 0x40
+#define ALIGN_CNT3 0x30
+#define ALIGN_CNT2 0x20
+#define ALIGN_CNT1 0x10
+#define ALIGN_CNT4 0x00
+#define STOP_DWS 0x08
+#define SEND_COMSAS 0x04
+#define SEND_COMINIT 0x02
+#define SEND_COMWAKE 0x01
+
+#define OOB_XMIT 0x141
+
+#define TX_ENABLE 0x80
+#define XMIT_OOB_BURST 0x10
+#define XMIT_D10_2 0x08
+#define XMIT_SYNC 0x04
+#define XMIT_ALIGN_1 0x02
+#define XMIT_ALIGN_0 0x01
+
+#define FUNCTION_MASK 0x142
+
+#define SAS_MODE_DIS 0x80
+#define SATA_MODE_DIS 0x40
+#define SPINUP_HOLD_DIS 0x20
+#define HOT_PLUG_DIS 0x10
+#define SATA_PS_DIS 0x08
+#define FUNCTION_MASK_DEFAULT (SPINUP_HOLD_DIS | SATA_PS_DIS)
+
+#define OOB_MODE 0x143
+
+#define SAS_MODE 0x80
+#define SATA_MODE 0x40
+#define SLOW_CLK 0x20
+#define FORCE_XMIT_15 0x08
+#define PHY_SPEED_60 0x04
+#define PHY_SPEED_30 0x02
+#define PHY_SPEED_15 0x01
+
+#define CURRENT_STATUS 0x144
+
+#define CURRENT_OOB_DONE 0x80
+#define CURRENT_LOSS_OF_SIGNAL 0x40
+#define CURRENT_SPINUP_HOLD 0x20
+#define CURRENT_HOT_PLUG_CNCT 0x10
+#define CURRENT_GTO_TIMEOUT 0x08
+#define CURRENT_OOB_TIMEOUT 0x04
+#define CURRENT_DEVICE_PRESENT 0x02
+#define CURRENT_OOB_ERROR 0x01
+
+#define CURRENT_OOB1_ERROR (CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_GTO_TIMEOUT)
+
+#define CURRENT_OOB2_ERROR (CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_OOB_ERROR)
+
+#define DEVICE_ADDED_W_CNT (CURRENT_OOB_DONE | \
+ CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_DEVICE_PRESENT)
+
+#define DEVICE_ADDED_WO_CNT (CURRENT_OOB_DONE | \
+ CURRENT_DEVICE_PRESENT)
+
+#define DEVICE_REMOVED CURRENT_LOSS_OF_SIGNAL
+
+#define CURRENT_PHY_MASK (CURRENT_OOB_DONE | \
+ CURRENT_LOSS_OF_SIGNAL | \
+ CURRENT_SPINUP_HOLD | \
+ CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_GTO_TIMEOUT | \
+ CURRENT_DEVICE_PRESENT | \
+ CURRENT_OOB_ERROR )
+
+#define CURRENT_ERR_MASK (CURRENT_LOSS_OF_SIGNAL | \
+ CURRENT_GTO_TIMEOUT | \
+ CURRENT_OOB_TIMEOUT | \
+ CURRENT_OOB_ERROR )
+
+#define SPEED_MASK 0x145
+
+#define SATA_SPEED_30_DIS 0x10
+#define SATA_SPEED_15_DIS 0x08
+#define SAS_SPEED_60_DIS 0x04
+#define SAS_SPEED_30_DIS 0x02
+#define SAS_SPEED_15_DIS 0x01
+#define SAS_SPEED_MASK_DEFAULT 0x00
+
+#define OOB_TIMER_ENABLE 0x14D
+
+#define HOT_PLUG_EN 0x80
+#define RCD_EN 0x40
+#define COMTIMER_EN 0x20
+#define SNTT_EN 0x10
+#define SNLT_EN 0x04
+#define SNWT_EN 0x02
+#define ALIGN_EN 0x01
+
+#define OOB_STATUS 0x14E
+
+#define OOB_DONE 0x80
+#define LOSS_OF_SIGNAL 0x40 /* ro */
+#define SPINUP_HOLD 0x20
+#define HOT_PLUG_CNCT 0x10 /* ro */
+#define GTO_TIMEOUT 0x08 /* ro */
+#define OOB_TIMEOUT 0x04 /* ro */
+#define DEVICE_PRESENT 0x02 /* ro */
+#define OOB_ERROR 0x01 /* ro */
+
+#define OOB_STATUS_ERROR_MASK (LOSS_OF_SIGNAL | GTO_TIMEOUT | \
+ OOB_TIMEOUT | OOB_ERROR)
+
+#define OOB_STATUS_CLEAR 0x14F
+
+#define OOB_DONE_CLR 0x80
+#define LOSS_OF_SIGNAL_CLR 0x40
+#define SPINUP_HOLD_CLR 0x20
+#define HOT_PLUG_CNCT_CLR 0x10
+#define GTO_TIMEOUT_CLR 0x08
+#define OOB_TIMEOUT_CLR 0x04
+#define OOB_ERROR_CLR 0x01
+
+#define HOT_PLUG_DELAY 0x150
+/* In 5 ms units. 20 = 100 ms. */
+#define HOTPLUG_DELAY_TIMEOUT 20
+
+
+#define INT_ENABLE_2 0x15A
+
+#define OOB_DONE_EN 0x80
+#define LOSS_OF_SIGNAL_EN 0x40
+#define SPINUP_HOLD_EN 0x20
+#define HOT_PLUG_CNCT_EN 0x10
+#define GTO_TIMEOUT_EN 0x08
+#define OOB_TIMEOUT_EN 0x04
+#define DEVICE_PRESENT_EN 0x02
+#define OOB_ERROR_EN 0x01
+
+#define PHY_CONTROL_0 0x160
+
+#define PHY_LOWPWREN_TX 0x80
+#define PHY_LOWPWREN_RX 0x40
+#define SPARE_REG_160_B5 0x20
+#define OFFSET_CANCEL_RX 0x10
+
+/* bits 3:2 */
+#define PHY_RXCOMCENTER_60V 0x00
+#define PHY_RXCOMCENTER_70V 0x04
+#define PHY_RXCOMCENTER_80V 0x08
+#define PHY_RXCOMCENTER_90V 0x0C
+#define PHY_RXCOMCENTER_MASK 0x0C
+
+#define PHY_RESET 0x02
+#define SAS_DEFAULT_SEL 0x01
+
+#define PHY_CONTROL_1 0x161
+
+/* bits 2:0 */
+#define SATA_PHY_DETLEVEL_50mv 0x00
+#define SATA_PHY_DETLEVEL_75mv 0x01
+#define SATA_PHY_DETLEVEL_100mv 0x02
+#define SATA_PHY_DETLEVEL_125mv 0x03
+#define SATA_PHY_DETLEVEL_150mv 0x04
+#define SATA_PHY_DETLEVEL_175mv 0x05
+#define SATA_PHY_DETLEVEL_200mv 0x06
+#define SATA_PHY_DETLEVEL_225mv 0x07
+#define SATA_PHY_DETLEVEL_MASK 0x07
+
+/* bits 5:3 */
+#define SAS_PHY_DETLEVEL_50mv 0x00
+#define SAS_PHY_DETLEVEL_75mv 0x08
+#define SAS_PHY_DETLEVEL_100mv 0x10
+#define SAS_PHY_DETLEVEL_125mv 0x11
+#define SAS_PHY_DETLEVEL_150mv 0x20
+#define SAS_PHY_DETLEVEL_175mv 0x21
+#define SAS_PHY_DETLEVEL_200mv 0x30
+#define SAS_PHY_DETLEVEL_225mv 0x31
+#define SAS_PHY_DETLEVEL_MASK 0x38
+
+#define PHY_CONTROL_2 0x162
+
+/* bits 7:5 */
+#define SATA_PHY_DRV_400mv 0x00
+#define SATA_PHY_DRV_450mv 0x20
+#define SATA_PHY_DRV_500mv 0x40
+#define SATA_PHY_DRV_550mv 0x60
+#define SATA_PHY_DRV_600mv 0x80
+#define SATA_PHY_DRV_650mv 0xA0
+#define SATA_PHY_DRV_725mv 0xC0
+#define SATA_PHY_DRV_800mv 0xE0
+#define SATA_PHY_DRV_MASK 0xE0
+
+/* bits 4:3 */
+#define SATA_PREEMP_0 0x00
+#define SATA_PREEMP_1 0x08
+#define SATA_PREEMP_2 0x10
+#define SATA_PREEMP_3 0x18
+#define SATA_PREEMP_MASK 0x18
+
+#define SATA_CMSH1P5 0x04
+
+/* bits 1:0 */
+#define SATA_SLEW_0 0x00
+#define SATA_SLEW_1 0x01
+#define SATA_SLEW_2 0x02
+#define SATA_SLEW_3 0x03
+#define SATA_SLEW_MASK 0x03
+
+#define PHY_CONTROL_3 0x163
+
+/* bits 7:5 */
+#define SAS_PHY_DRV_400mv 0x00
+#define SAS_PHY_DRV_450mv 0x20
+#define SAS_PHY_DRV_500mv 0x40
+#define SAS_PHY_DRV_550mv 0x60
+#define SAS_PHY_DRV_600mv 0x80
+#define SAS_PHY_DRV_650mv 0xA0
+#define SAS_PHY_DRV_725mv 0xC0
+#define SAS_PHY_DRV_800mv 0xE0
+#define SAS_PHY_DRV_MASK 0xE0
+
+/* bits 4:3 */
+#define SAS_PREEMP_0 0x00
+#define SAS_PREEMP_1 0x08
+#define SAS_PREEMP_2 0x10
+#define SAS_PREEMP_3 0x18
+#define SAS_PREEMP_MASK 0x18
+
+#define SAS_CMSH1P5 0x04
+
+/* bits 1:0 */
+#define SAS_SLEW_0 0x00
+#define SAS_SLEW_1 0x01
+#define SAS_SLEW_2 0x02
+#define SAS_SLEW_3 0x03
+#define SAS_SLEW_MASK 0x03
+
+#define PHY_CONTROL_4 0x168
+
+#define PHY_DONE_CAL_TX 0x80
+#define PHY_DONE_CAL_RX 0x40
+#define RX_TERM_LOAD_DIS 0x20
+#define TX_TERM_LOAD_DIS 0x10
+#define AUTO_TERM_CAL_DIS 0x08
+#define PHY_SIGDET_FLTR_EN 0x04
+#define OSC_FREQ 0x02
+#define PHY_START_CAL 0x01
+
+/*
+ * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
+ */
+#define PCIX_REG_BASE_ADR 0xB8040000
+
+#define PCIC_VENDOR_ID 0x00
+
+#define PCIC_DEVICE_ID 0x02
+
+#define PCIC_COMMAND 0x04
+
+#define INT_DIS 0x0400
+#define FBB_EN 0x0200 /* ro */
+#define SERR_EN 0x0100
+#define STEP_EN 0x0080 /* ro */
+#define PERR_EN 0x0040
+#define VGA_EN 0x0020 /* ro */
+#define MWI_EN 0x0010
+#define SPC_EN 0x0008
+#define MST_EN 0x0004
+#define MEM_EN 0x0002
+#define IO_EN 0x0001
+
+#define PCIC_STATUS 0x06
+
+#define PERR_DET 0x8000
+#define SERR_GEN 0x4000
+#define MABT_DET 0x2000
+#define TABT_DET 0x1000
+#define TABT_GEN 0x0800
+#define DPERR_DET 0x0100
+#define CAP_LIST 0x0010
+#define INT_STAT 0x0008
+
+#define PCIC_DEVREV_ID 0x08
+
+#define PCIC_CLASS_CODE 0x09
+
+#define PCIC_CACHELINE_SIZE 0x0C
+
+#define PCIC_MBAR0 0x10
+
+#define PCIC_MBAR0_OFFSET 0
+
+#define PCIC_MBAR1 0x18
+
+#define PCIC_MBAR1_OFFSET 2
+
+#define PCIC_IOBAR 0x20
+
+#define PCIC_IOBAR_OFFSET 4
+
+#define PCIC_SUBVENDOR_ID 0x2C
+
+#define PCIC_SUBSYTEM_ID 0x2E
+
+#define PCIX_STATUS 0x44
+#define RCV_SCE 0x20000000
+#define UNEXP_SC 0x00080000
+#define SC_DISCARD 0x00040000
+
+#define ECC_CTRL_STAT 0x48
+#define UNCOR_ECCERR 0x00000008
+
+#define PCIC_PM_CSR 0x5C
+
+#define PWR_STATE_D0 0
+#define PWR_STATE_D1 1 /* not supported */
+#define PWR_STATE_D2 2 /* not supported */
+#define PWR_STATE_D3 3
+
+#define PCIC_BASE1 0x6C /* internal use only */
+
+#define BASE1_RSVD 0xFFFFFFF8
+
+#define PCIC_BASEA 0x70 /* internal use only */
+
+#define BASEA_RSVD 0xFFFFFFC0
+#define BASEA_START 0
+
+#define PCIC_BASEB 0x74 /* internal use only */
+
+#define BASEB_RSVD 0xFFFFFF80
+#define BASEB_IOMAP_MASK 0x7F
+#define BASEB_START 0x80
+
+#define PCIC_BASEC 0x78 /* internal use only */
+
+#define BASEC_RSVD 0xFFFFFFFC
+#define BASEC_MASK 0x03
+#define BASEC_START 0x58
+
+#define PCIC_MBAR_KEY 0x7C /* internal use only */
+
+#define MBAR_KEY_MASK 0xFFFFFFFF
+
+#define PCIC_HSTPCIX_CNTRL 0xA0
+
+#define REWIND_DIS 0x0800
+#define SC_TMR_DIS 0x04000000
+
+#define PCIC_MBAR0_MASK 0xA8
+#define PCIC_MBAR0_SIZE_MASK 0x1FFFE000
+#define PCIC_MBAR0_SIZE_SHIFT 13
+#define PCIC_MBAR0_SIZE(val) \
+ (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT)
+
+#define PCIC_FLASH_MBAR 0xB8
+
+#define PCIC_INTRPT_STAT 0xD4
+
+#define PCIC_TP_CTRL 0xFC
+
+/*
+ * EXSI Registers, Addresss Range: (0x00-0xFC)
+ */
+#define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI
+
+#define EXSICNFGR (EXSI_REG_BASE_ADR + 0x00)
+
+#define OCMINITIALIZED 0x80000000
+#define ASIEN 0x00400000
+#define HCMODE 0x00200000
+#define PCIDEF 0x00100000
+#define COMSTOCK 0x00080000
+#define SEEPROMEND 0x00040000
+#define MSTTIMEN 0x00020000
+#define XREGEX 0x00000200
+#define NVRAMW 0x00000100
+#define NVRAMEX 0x00000080
+#define SRAMW 0x00000040
+#define SRAMEX 0x00000020
+#define FLASHW 0x00000010
+#define FLASHEX 0x00000008
+#define SEEPROMCFG 0x00000004
+#define SEEPROMTYP 0x00000002
+#define SEEPROMEX 0x00000001
+
+
+#define EXSICNTRLR (EXSI_REG_BASE_ADR + 0x04)
+
+#define MODINT_EN 0x00000001
+
+
+#define PMSTATR (EXSI_REG_BASE_ADR + 0x10)
+
+#define FLASHRST 0x00000002
+#define FLASHRDY 0x00000001
+
+
+#define FLCNFGR (EXSI_REG_BASE_ADR + 0x14)
+
+#define FLWEH_MASK 0x30000000
+#define FLWESU_MASK 0x0C000000
+#define FLWEPW_MASK 0x03F00000
+#define FLOEH_MASK 0x000C0000
+#define FLOESU_MASK 0x00030000
+#define FLOEPW_MASK 0x0000FC00
+#define FLCSH_MASK 0x00000300
+#define FLCSSU_MASK 0x000000C0
+#define FLCSPW_MASK 0x0000003F
+
+#define SRCNFGR (EXSI_REG_BASE_ADR + 0x18)
+
+#define SRWEH_MASK 0x30000000
+#define SRWESU_MASK 0x0C000000
+#define SRWEPW_MASK 0x03F00000
+
+#define SROEH_MASK 0x000C0000
+#define SROESU_MASK 0x00030000
+#define SROEPW_MASK 0x0000FC00
+#define SRCSH_MASK 0x00000300
+#define SRCSSU_MASK 0x000000C0
+#define SRCSPW_MASK 0x0000003F
+
+#define NVCNFGR (EXSI_REG_BASE_ADR + 0x1C)
+
+#define NVWEH_MASK 0x30000000
+#define NVWESU_MASK 0x0C000000
+#define NVWEPW_MASK 0x03F00000
+#define NVOEH_MASK 0x000C0000
+#define NVOESU_MASK 0x00030000
+#define NVOEPW_MASK 0x0000FC00
+#define NVCSH_MASK 0x00000300
+#define NVCSSU_MASK 0x000000C0
+#define NVCSPW_MASK 0x0000003F
+
+#define XRCNFGR (EXSI_REG_BASE_ADR + 0x20)
+
+#define XRWEH_MASK 0x30000000
+#define XRWESU_MASK 0x0C000000
+#define XRWEPW_MASK 0x03F00000
+#define XROEH_MASK 0x000C0000
+#define XROESU_MASK 0x00030000
+#define XROEPW_MASK 0x0000FC00
+#define XRCSH_MASK 0x00000300
+#define XRCSSU_MASK 0x000000C0
+#define XRCSPW_MASK 0x0000003F
+
+#define XREGADDR (EXSI_REG_BASE_ADR + 0x24)
+
+#define XRADDRINCEN 0x80000000
+#define XREGADD_MASK 0x007FFFFF
+
+
+#define XREGDATAR (EXSI_REG_BASE_ADR + 0x28)
+
+#define XREGDATA_MASK 0x0000FFFF
+
+#define GPIOOER (EXSI_REG_BASE_ADR + 0x40)
+
+#define GPIOODENR (EXSI_REG_BASE_ADR + 0x44)
+
+#define GPIOINVR (EXSI_REG_BASE_ADR + 0x48)
+
+#define GPIODATAOR (EXSI_REG_BASE_ADR + 0x4C)
+
+#define GPIODATAIR (EXSI_REG_BASE_ADR + 0x50)
+
+#define GPIOCNFGR (EXSI_REG_BASE_ADR + 0x54)
+
+#define GPIO_EXTSRC 0x00000001
+
+#define SCNTRLR (EXSI_REG_BASE_ADR + 0xA0)
+
+#define SXFERDONE 0x00000100
+#define SXFERCNT_MASK 0x000000E0
+#define SCMDTYP_MASK 0x0000001C
+#define SXFERSTART 0x00000002
+#define SXFEREN 0x00000001
+
+#define SRATER (EXSI_REG_BASE_ADR + 0xA4)
+
+#define SADDRR (EXSI_REG_BASE_ADR + 0xA8)
+
+#define SADDR_MASK 0x0000FFFF
+
+#define SDATAOR (EXSI_REG_BASE_ADR + 0xAC)
+
+#define SDATAOR0 (EXSI_REG_BASE_ADR + 0xAC)
+#define SDATAOR1 (EXSI_REG_BASE_ADR + 0xAD)
+#define SDATAOR2 (EXSI_REG_BASE_ADR + 0xAE)
+#define SDATAOR3 (EXSI_REG_BASE_ADR + 0xAF)
+
+#define SDATAIR (EXSI_REG_BASE_ADR + 0xB0)
+
+#define SDATAIR0 (EXSI_REG_BASE_ADR + 0xB0)
+#define SDATAIR1 (EXSI_REG_BASE_ADR + 0xB1)
+#define SDATAIR2 (EXSI_REG_BASE_ADR + 0xB2)
+#define SDATAIR3 (EXSI_REG_BASE_ADR + 0xB3)
+
+#define ASISTAT0R (EXSI_REG_BASE_ADR + 0xD0)
+#define ASIFMTERR 0x00000400
+#define ASISEECHKERR 0x00000200
+#define ASIERR 0x00000100
+
+#define ASISTAT1R (EXSI_REG_BASE_ADR + 0xD4)
+#define CHECKSUM_MASK 0x0000FFFF
+
+#define ASIERRADDR (EXSI_REG_BASE_ADR + 0xD8)
+#define ASIERRDATAR (EXSI_REG_BASE_ADR + 0xDC)
+#define ASIERRSTATR (EXSI_REG_BASE_ADR + 0xE0)
+#define CPI2ASIBYTECNT_MASK 0x00070000
+#define CPI2ASIBYTEEN_MASK 0x0000F000
+#define CPI2ASITARGERR_MASK 0x00000F00
+#define CPI2ASITARGMID_MASK 0x000000F0
+#define CPI2ASIMSTERR_MASK 0x0000000F
+
+/*
+ * XSRAM, External SRAM (DWord and any BE pattern accessible)
+ */
+#define XSRAM_REG_BASE_ADDR 0xB8100000
+#define XSRAM_SIZE 0x100000
+
+/*
+ * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF).
+ */
+#define NVRAM_REG_BASE_ADR 0xBF800000
+#define NVRAM_MAX_BASE_ADR 0x003FFFFF
+
+/* OCM base address */
+#define OCM_BASE_ADDR 0xA0000000
+#define OCM_MAX_SIZE 0x20000
+
+/*
+ * Sequencers (Central and Link) Scratch RAM page definitions.
+ */
+
+/*
+ * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024
+ * byte memory. It is dword accessible and has byte parity
+ * protection. The CSEQ accesses it in 32 byte windows, either as mode
+ * dependent or mode independent memory. Each mode has 96 bytes,
+ * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of
+ * Mode Independent memory (four 32 byte pages 3-7). Note that mode
+ * dependent scratch memory, Mode 8, page 0-3 overlaps mode
+ * independent scratch memory, pages 0-3.
+ * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and
+ * 128 bytes in mode 8,
+ * - 259 bytes of mode independent scratch, common to modes 0-15.
+ *
+ * Sequencer scratch RAM is 1024 bytes. This scratch memory is
+ * divided into mode dependent and mode independent scratch with this
+ * memory further subdivided into pages of size 32 bytes. There are 5
+ * pages (160 bytes) of mode independent scratch and 3 pages of
+ * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages
+ * 0-2 dependent scratch overlap with pages 0-2 of mode independent
+ * scratch memory.
+ *
+ * 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
+ * corruption while the sequencer is running. This memory is mapped
+ * onto addresses 800h - BFFh, total of 400h bytes.
+ *
+ * These addresses are mapped as follows:
+ *
+ * 800h-83Fh Mode Dependent Scratch Mode 0 Pages 0-1
+ * 840h-87Fh Mode Dependent Scratch Mode 1 Pages 0-1
+ * 880h-8BFh Mode Dependent Scratch Mode 2 Pages 0-1
+ * 8C0h-8FFh Mode Dependent Scratch Mode 3 Pages 0-1
+ * 900h-93Fh Mode Dependent Scratch Mode 4 Pages 0-1
+ * 940h-97Fh Mode Dependent Scratch Mode 5 Pages 0-1
+ * 980h-9BFh Mode Dependent Scratch Mode 6 Pages 0-1
+ * 9C0h-9FFh Mode Dependent Scratch Mode 7 Pages 0-1
+ * A00h-A5Fh Mode Dependent Scratch Mode 8 Pages 0-2
+ * Mode Independent Scratch Pages 0-2
+ * A60h-A7Fh Mode Dependent Scratch Mode 8 Page 3
+ * Mode Independent Scratch Page 3
+ * A80h-AFFh Mode Independent Scratch Pages 4-7
+ * B00h-B1Fh Mode Dependent Scratch Mode 0 Page 2
+ * B20h-B3Fh Mode Dependent Scratch Mode 1 Page 2
+ * B40h-B5Fh Mode Dependent Scratch Mode 2 Page 2
+ * B60h-B7Fh Mode Dependent Scratch Mode 3 Page 2
+ * B80h-B9Fh Mode Dependent Scratch Mode 4 Page 2
+ * BA0h-BBFh Mode Dependent Scratch Mode 5 Page 2
+ * BC0h-BDFh Mode Dependent Scratch Mode 6 Page 2
+ * BE0h-BFFh Mode Dependent Scratch Mode 7 Page 2
+ */
+
+/* General macros */
+#define CSEQ_PAGE_SIZE 32 /* Scratch page size (in bytes) */
+
+/* All macros start with offsets from base + 0x800 (CMAPPEDSCR).
+ * Mode dependent scratch page 0, mode 0.
+ * For modes 1-7 you have to do arithmetic. */
+#define CSEQ_LRM_SAVE_SINDEX (CMAPPEDSCR + 0x0000)
+#define CSEQ_LRM_SAVE_SCBPTR (CMAPPEDSCR + 0x0002)
+#define CSEQ_Q_LINK_HEAD (CMAPPEDSCR + 0x0004)
+#define CSEQ_Q_LINK_TAIL (CMAPPEDSCR + 0x0006)
+#define CSEQ_LRM_SAVE_SCRPAGE (CMAPPEDSCR + 0x0008)
+
+/* Mode dependent scratch page 0 mode 8 macros. */
+#define CSEQ_RET_ADDR (CMAPPEDSCR + 0x0200)
+#define CSEQ_RET_SCBPTR (CMAPPEDSCR + 0x0202)
+#define CSEQ_SAVE_SCBPTR (CMAPPEDSCR + 0x0204)
+#define CSEQ_EMPTY_TRANS_CTX (CMAPPEDSCR + 0x0206)
+#define CSEQ_RESP_LEN (CMAPPEDSCR + 0x0208)
+#define CSEQ_TMF_SCBPTR (CMAPPEDSCR + 0x020A)
+#define CSEQ_GLOBAL_PREV_SCB (CMAPPEDSCR + 0x020C)
+#define CSEQ_GLOBAL_HEAD (CMAPPEDSCR + 0x020E)
+#define CSEQ_CLEAR_LU_HEAD (CMAPPEDSCR + 0x0210)
+#define CSEQ_TMF_OPCODE (CMAPPEDSCR + 0x0212)
+#define CSEQ_SCRATCH_FLAGS (CMAPPEDSCR + 0x0213)
+#define CSEQ_HSB_SITE (CMAPPEDSCR + 0x021A)
+#define CSEQ_FIRST_INV_SCB_SITE (CMAPPEDSCR + 0x021C)
+#define CSEQ_FIRST_INV_DDB_SITE (CMAPPEDSCR + 0x021E)
+
+/* Mode dependent scratch page 1 mode 8 macros. */
+#define CSEQ_LUN_TO_CLEAR (CMAPPEDSCR + 0x0220)
+#define CSEQ_LUN_TO_CHECK (CMAPPEDSCR + 0x0228)
+
+/* Mode dependent scratch page 2 mode 8 macros */
+#define CSEQ_HQ_NEW_POINTER (CMAPPEDSCR + 0x0240)
+#define CSEQ_HQ_DONE_BASE (CMAPPEDSCR + 0x0248)
+#define CSEQ_HQ_DONE_POINTER (CMAPPEDSCR + 0x0250)
+#define CSEQ_HQ_DONE_PASS (CMAPPEDSCR + 0x0254)
+
+/* Mode independent scratch page 4 macros. */
+#define CSEQ_Q_EXE_HEAD (CMAPPEDSCR + 0x0280)
+#define CSEQ_Q_EXE_TAIL (CMAPPEDSCR + 0x0282)
+#define CSEQ_Q_DONE_HEAD (CMAPPEDSCR + 0x0284)
+#define CSEQ_Q_DONE_TAIL (CMAPPEDSCR + 0x0286)
+#define CSEQ_Q_SEND_HEAD (CMAPPEDSCR + 0x0288)
+#define CSEQ_Q_SEND_TAIL (CMAPPEDSCR + 0x028A)
+#define CSEQ_Q_DMA2CHIM_HEAD (CMAPPEDSCR + 0x028C)
+#define CSEQ_Q_DMA2CHIM_TAIL (CMAPPEDSCR + 0x028E)
+#define CSEQ_Q_COPY_HEAD (CMAPPEDSCR + 0x0290)
+#define CSEQ_Q_COPY_TAIL (CMAPPEDSCR + 0x0292)
+#define CSEQ_REG0 (CMAPPEDSCR + 0x0294)
+#define CSEQ_REG1 (CMAPPEDSCR + 0x0296)
+#define CSEQ_REG2 (CMAPPEDSCR + 0x0298)
+#define CSEQ_LINK_CTL_Q_MAP (CMAPPEDSCR + 0x029C)
+#define CSEQ_MAX_CSEQ_MODE (CMAPPEDSCR + 0x029D)
+#define CSEQ_FREE_LIST_HACK_COUNT (CMAPPEDSCR + 0x029E)
+
+/* Mode independent scratch page 5 macros. */
+#define CSEQ_EST_NEXUS_REQ_QUEUE (CMAPPEDSCR + 0x02A0)
+#define CSEQ_EST_NEXUS_REQ_COUNT (CMAPPEDSCR + 0x02A8)
+#define CSEQ_Q_EST_NEXUS_HEAD (CMAPPEDSCR + 0x02B0)
+#define CSEQ_Q_EST_NEXUS_TAIL (CMAPPEDSCR + 0x02B2)
+#define CSEQ_NEED_EST_NEXUS_SCB (CMAPPEDSCR + 0x02B4)
+#define CSEQ_EST_NEXUS_REQ_HEAD (CMAPPEDSCR + 0x02B6)
+#define CSEQ_EST_NEXUS_REQ_TAIL (CMAPPEDSCR + 0x02B7)
+#define CSEQ_EST_NEXUS_SCB_OFFSET (CMAPPEDSCR + 0x02B8)
+
+/* Mode independent scratch page 6 macros. */
+#define CSEQ_INT_ROUT_RET_ADDR0 (CMAPPEDSCR + 0x02C0)
+#define CSEQ_INT_ROUT_RET_ADDR1 (CMAPPEDSCR + 0x02C2)
+#define CSEQ_INT_ROUT_SCBPTR (CMAPPEDSCR + 0x02C4)
+#define CSEQ_INT_ROUT_MODE (CMAPPEDSCR + 0x02C6)
+#define CSEQ_ISR_SCRATCH_FLAGS (CMAPPEDSCR + 0x02C7)
+#define CSEQ_ISR_SAVE_SINDEX (CMAPPEDSCR + 0x02C8)
+#define CSEQ_ISR_SAVE_DINDEX (CMAPPEDSCR + 0x02CA)
+#define CSEQ_Q_MONIRTT_HEAD (CMAPPEDSCR + 0x02D0)
+#define CSEQ_Q_MONIRTT_TAIL (CMAPPEDSCR + 0x02D2)
+#define CSEQ_FREE_SCB_MASK (CMAPPEDSCR + 0x02D5)
+#define CSEQ_BUILTIN_FREE_SCB_HEAD (CMAPPEDSCR + 0x02D6)
+#define CSEQ_BUILTIN_FREE_SCB_TAIL (CMAPPEDSCR + 0x02D8)
+#define CSEQ_EXTENDED_FREE_SCB_HEAD (CMAPPEDSCR + 0x02DA)
+#define CSEQ_EXTENDED_FREE_SCB_TAIL (CMAPPEDSCR + 0x02DC)
+
+/* Mode independent scratch page 7 macros. */
+#define CSEQ_EMPTY_REQ_QUEUE (CMAPPEDSCR + 0x02E0)
+#define CSEQ_EMPTY_REQ_COUNT (CMAPPEDSCR + 0x02E8)
+#define CSEQ_Q_EMPTY_HEAD (CMAPPEDSCR + 0x02F0)
+#define CSEQ_Q_EMPTY_TAIL (CMAPPEDSCR + 0x02F2)
+#define CSEQ_NEED_EMPTY_SCB (CMAPPEDSCR + 0x02F4)
+#define CSEQ_EMPTY_REQ_HEAD (CMAPPEDSCR + 0x02F6)
+#define CSEQ_EMPTY_REQ_TAIL (CMAPPEDSCR + 0x02F7)
+#define CSEQ_EMPTY_SCB_OFFSET (CMAPPEDSCR + 0x02F8)
+#define CSEQ_PRIMITIVE_DATA (CMAPPEDSCR + 0x02FA)
+#define CSEQ_TIMEOUT_CONST (CMAPPEDSCR + 0x02FC)
+
+/***************************************************************************
+* Link m Sequencer scratch RAM is 512 bytes.
+* This scratch memory is divided into mode dependent and mode
+* independent scratch with this memory further subdivided into
+* pages of size 32 bytes. There are 4 pages (128 bytes) of
+* mode independent scratch and 4 pages of dependent scratch
+* memory for modes 0-2 (384 bytes).
+*
+* The host accesses this scratch in a different manner from the
+* link sequencer. The sequencer has to use LSEQ registers
+* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat
+* mapping of the scratch memory is avaliable for software
+* convenience and to prevent corruption while the sequencer is
+* running. This memory is mapped onto addresses 800h - 9FFh.
+*
+* These addresses are mapped as follows:
+*
+* 800h-85Fh Mode Dependent Scratch Mode 0 Pages 0-2
+* 860h-87Fh Mode Dependent Scratch Mode 0 Page 3
+* Mode Dependent Scratch Mode 5 Page 0
+* 880h-8DFh Mode Dependent Scratch Mode 1 Pages 0-2
+* 8E0h-8FFh Mode Dependent Scratch Mode 1 Page 3
+* Mode Dependent Scratch Mode 5 Page 1
+* 900h-95Fh Mode Dependent Scratch Mode 2 Pages 0-2
+* 960h-97Fh Mode Dependent Scratch Mode 2 Page 3
+* Mode Dependent Scratch Mode 5 Page 2
+* 980h-9DFh Mode Independent Scratch Pages 0-3
+* 9E0h-9FFh Mode Independent Scratch Page 3
+* Mode Dependent Scratch Mode 5 Page 3
+*
+****************************************************************************/
+/* General macros */
+#define LSEQ_MODE_SCRATCH_SIZE 0x80 /* Size of scratch RAM per mode */
+#define LSEQ_PAGE_SIZE 0x20 /* Scratch page size (in bytes) */
+#define LSEQ_MODE5_PAGE0_OFFSET 0x60
+
+/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */
+/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */
+#define LmSEQ_RET_ADDR(LinkNum) (LmSCRATCH(LinkNum) + 0x0000)
+#define LmSEQ_REG0_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0002)
+#define LmSEQ_MODE_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0004)
+
+/* Mode flag macros (byte 0) */
+#define SAS_SAVECTX_OCCURRED 0x80
+#define SAS_OOBSVC_OCCURRED 0x40
+#define SAS_OOB_DEVICE_PRESENT 0x20
+#define SAS_CFGHDR_OCCURRED 0x10
+#define SAS_RCV_INTS_ARE_DISABLED 0x08
+#define SAS_OOB_HOT_PLUG_CNCT 0x04
+#define SAS_AWAIT_OPEN_CONNECTION 0x02
+#define SAS_CFGCMPLT_OCCURRED 0x01
+
+/* Mode flag macros (byte 1) */
+#define SAS_RLSSCB_OCCURRED 0x80
+#define SAS_FORCED_HEADER_MISS 0x40
+
+#define LmSEQ_RET_ADDR2(LinkNum) (LmSCRATCH(LinkNum) + 0x0006)
+#define LmSEQ_RET_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0008)
+#define LmSEQ_OPCODE_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000B)
+#define LmSEQ_DATA_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000C)
+
+/* Mode dependent scratch page 0 macros for mode 0 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x000E)
+#define LmSEQ_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0010)
+#define LmSEQ_RESP_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x0012)
+#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x0014)
+#define LmSEQ_INTEN_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0016)
+#define LmSEQ_LINK_RST_FRM_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x001A)
+#define LmSEQ_LINK_RST_PROTOCOL(LinkNum) (LmSCRATCH(LinkNum) + 0x001B)
+#define LmSEQ_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x001C)
+#define LmSEQ_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x001D)
+#define LmSEQ_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x001E)
+
+/* Mode dependent scratch page 0 macros for mode 1 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_Q_XMIT_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x008E)
+#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0090)
+#define LmSEQ_INI_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0092)
+#define LmSEQ_FAILED_OPEN_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009A)
+#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum) (LmSCRATCH(LinkNum) + 0x009B)
+#define LmSEQ_M1_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009C)
+#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x009D)
+#define LmSEQ_M1_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x009E)
+
+/* Mode dependent scratch page 0 macros for mode 2 (non-common) */
+#define LmSEQ_PORT_COUNTER(LinkNum) (LmSCRATCH(LinkNum) + 0x010E)
+#define LmSEQ_PM_TABLE_PTR(LinkNum) (LmSCRATCH(LinkNum) + 0x0110)
+#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112)
+#define LmSEQ_IP_BITL(LinkNum) (LmSCRATCH(LinkNum) + 0x0114)
+#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0116)
+#define LmSEQ_P0M2_OFFS1AH(LinkNum) (LmSCRATCH(LinkNum) + 0x011A)
+
+/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_SAVED_OOB_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x006E)
+#define LmSEQ_SAVED_OOB_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x006F)
+#define LmSEQ_Q_LINK_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0070)
+#define LmSEQ_LINK_RST_ERR(LinkNum) (LmSCRATCH(LinkNum) + 0x0072)
+#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) (LmSCRATCH(LinkNum) + 0x0073)
+#define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074)
+#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075)
+#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076)
+#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A)
+#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C)
+#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
+
+/* Mode dependent scratch page 1, mode 0 and mode 1 */
+#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020)
+#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0030)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x00A0)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x00B0)
+
+/* Mode dependent scratch page 1 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_INVALID_DWORD_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0120)
+#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0124)
+#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0128)
+
+/* Mode dependent scratch page 1 macros for mode 4/5 */
+#define LmSEQ_FRAME_TYPE_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E0)
+#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E1)
+#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4)
+#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E5)
+#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00EB)
+#define LmSEQ_TAG_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00F0)
+#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x00F2)
+#define LmSEQ_DATA_OFFSET(LinkNum) (LmSCRATCH(LinkNum) + 0x00F4)
+
+/* Mode dependent scratch page 2 macros for mode 0 */
+/* Absolute offsets */
+#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0040)
+#define LmSEQ_DEVICE_BITS(LinkNum) (LmSCRATCH(LinkNum) + 0x005B)
+#define LmSEQ_SDB_DDB(LinkNum) (LmSCRATCH(LinkNum) + 0x005C)
+#define LmSEQ_SDB_NUM_TAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x005E)
+#define LmSEQ_SDB_CURR_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x005F)
+
+/* Mode dependent scratch page 2 macros for mode 1 */
+/* Absolute offsets */
+/* byte 0 bits 1-0 are domain select. */
+#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum) (LmSCRATCH(LinkNum) + 0x00C0)
+#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00C8)
+#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00CC)
+#define LmSEQ_LAST_LOADED_SG_EL(LinkNum) (LmSCRATCH(LinkNum) + 0x00D4)
+
+/* Mode dependent scratch page 2 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140)
+#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0144)
+#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0148)
+#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C)
+#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \
+ (LmSCRATCH(LinkNum) + 0x0150)
+#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0154)
+
+/* Mode dependent scratch page 2 macros for mode 5 */
+#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0160)
+#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0164)
+#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0168)
+#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x016C)
+
+/* Mode dependent scratch page 3 macros for modes 0 and 1 */
+/* None defined */
+
+/* Mode dependent scratch page 3 macros for modes 2 and 5 */
+/* None defined */
+
+/* Mode Independent Scratch page 0 macros. */
+#define LmSEQ_Q_TGTXFR_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0180)
+#define LmSEQ_Q_TGTXFR_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x0182)
+#define LmSEQ_LINK_NUMBER(LinkNum) (LmSCRATCH(LinkNum) + 0x0186)
+#define LmSEQ_SCRATCH_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0187)
+/*
+ * Currently only bit 0, SAS_DWSAQD, is used.
+ */
+#define SAS_DWSAQD 0x01 /*
+ * DWSSTATUS: DWSAQD
+ * bit las read in ISR.
+ */
+#define LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188)
+/* Connection states (byte 0) */
+#define SAS_WE_OPENED_CS 0x01
+#define SAS_DEVICE_OPENED_CS 0x02
+#define SAS_WE_SENT_DONE_CS 0x04
+#define SAS_DEVICE_SENT_DONE_CS 0x08
+#define SAS_WE_SENT_CLOSE_CS 0x10
+#define SAS_DEVICE_SENT_CLOSE_CS 0x20
+#define SAS_WE_SENT_BREAK_CS 0x40
+#define SAS_DEVICE_SENT_BREAK_CS 0x80
+/* Connection states (byte 1) */
+#define SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS 0x01
+#define SAS_AIP_RECEIVED_CS 0x02
+#define SAS_CREDIT_TIMEOUT_OCCURRED_CS 0x04
+#define SAS_ACKNAK_TIMEOUT_OCCURRED_CS 0x08
+#define SAS_SMPRSP_TIMEOUT_OCCURRED_CS 0x10
+#define SAS_DONE_TIMEOUT_OCCURRED_CS 0x20
+/* Connection states (byte 2) */
+#define SAS_SMP_RESPONSE_RECEIVED_CS 0x01
+#define SAS_INTLK_TIMEOUT_OCCURRED_CS 0x02
+#define SAS_DEVICE_SENT_DMAT_CS 0x04
+#define SAS_DEVICE_SENT_SYNCSRST_CS 0x08
+#define SAS_CLEARING_AFFILIATION_CS 0x20
+#define SAS_RXTASK_ACTIVE_CS 0x40
+#define SAS_TXTASK_ACTIVE_CS 0x80
+/* Connection states (byte 3) */
+#define SAS_PHY_LOSS_OF_SIGNAL_CS 0x01
+#define SAS_DWS_TIMER_EXPIRED_CS 0x02
+#define SAS_LINK_RESET_NOT_COMPLETE_CS 0x04
+#define SAS_PHY_DISABLED_CS 0x08
+#define SAS_LINK_CTL_TASK_ACTIVE_CS 0x10
+#define SAS_PHY_EVENT_TASK_ACTIVE_CS 0x20
+#define SAS_DEVICE_SENT_ID_FRAME_CS 0x40
+#define SAS_DEVICE_SENT_REG_FIS_CS 0x40
+#define SAS_DEVICE_SENT_HARD_RESET_CS 0x80
+#define SAS_PHY_IS_DOWN_FLAGS (SAS_PHY_LOSS_OF_SIGNAL_CS|\
+ SAS_DWS_TIMER_EXPIRED_CS |\
+ SAS_LINK_RESET_NOT_COMPLETE_CS|\
+ SAS_PHY_DISABLED_CS)
+
+#define SAS_LINK_CTL_PHY_EVENT_FLAGS (SAS_LINK_CTL_TASK_ACTIVE_CS |\
+ SAS_PHY_EVENT_TASK_ACTIVE_CS |\
+ SAS_DEVICE_SENT_ID_FRAME_CS |\
+ SAS_DEVICE_SENT_HARD_RESET_CS)
+
+#define LmSEQ_CONCTL(LinkNum) (LmSCRATCH(LinkNum) + 0x018C)
+#define LmSEQ_CONSTAT(LinkNum) (LmSCRATCH(LinkNum) + 0x018E)
+#define LmSEQ_CONNECTION_MODES(LinkNum) (LmSCRATCH(LinkNum) + 0x018F)
+#define LmSEQ_REG1_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0192)
+#define LmSEQ_REG2_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0194)
+#define LmSEQ_REG3_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0196)
+#define LmSEQ_REG0_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0198)
+
+/* Mode independent scratch page 1 macros. */
+#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A0)
+#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A2)
+#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01A4)
+#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01A6)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A8)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A9)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum) (LmSCRATCH(LinkNum) + 0x01AA)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum) (LmSCRATCH(LinkNum) + 0x01AB)
+#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01AC)
+#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AD)
+#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AE)
+#define LmSEQ_TIMEOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01B8)
+#define LmSEQ_ISR_SAVE_SINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BC)
+#define LmSEQ_ISR_SAVE_DINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BE)
+
+/* Mode independent scratch page 2 macros. */
+#define LmSEQ_EMPTY_SCB_PTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C0)
+#define LmSEQ_EMPTY_SCB_PTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C2)
+#define LmSEQ_EMPTY_SCB_PTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01C4)
+#define LmSEQ_EMPTY_SCB_PTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01C6)
+#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8)
+#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9)
+#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA)
+#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB)
+#define LmSEQ_EMPTY_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01CC)
+#define LmSEQ_EMPTY_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CD)
+#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CE)
+#define LmSEQ_ATA_SCR_REGS(LinkNum) (LmSCRATCH(LinkNum) + 0x01D4)
+
+/* Mode independent scratch page 3 macros. */
+#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0)
+#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E4)
+#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E8)
+#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01EC)
+#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F0)
+#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F4)
+#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F8)
+#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01FC)
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
new file mode 100644
index 00000000000..64d23171234
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -0,0 +1,785 @@
+/*
+ * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_SAS_H_
+#define _AIC94XX_SAS_H_
+
+#include <scsi/libsas.h>
+
+/* ---------- DDBs ---------- */
+/* DDBs are device descriptor blocks which describe a device in the
+ * domain that this sequencer can maintain low-level connections for
+ * us. They are be 64 bytes.
+ */
+
+struct asd_ddb_ssp_smp_target_port {
+ u8 conn_type; /* byte 0 */
+#define DDB_TP_CONN_TYPE 0x81 /* Initiator port and addr frame type 0x01 */
+
+ u8 conn_rate;
+ __be16 init_conn_tag;
+ u8 dest_sas_addr[8]; /* bytes 4-11 */
+
+ __le16 send_queue_head;
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_TARGET */
+#define DDB_TYPE_UNUSED 0xFF
+#define DDB_TYPE_TARGET 0xFE
+#define DDB_TYPE_INITIATOR 0xFD
+#define DDB_TYPE_PM_PORT 0xFC
+
+ __le16 _r_a;
+ __be16 awt_def;
+
+ u8 compat_features; /* byte 20 */
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time;
+ __be32 more_compat_features; /* byte 24 */
+
+ u8 conn_mask;
+ u8 flags; /* concurrent conn:2,2 and open:0(1) */
+#define CONCURRENT_CONN_SUPP 0x04
+#define OPEN_REQUIRED 0x01
+
+ u16 _r_b;
+ __le16 exec_queue_tail;
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+
+ __le16 _r_c;
+
+ u8 max_concurrent_conn;
+ u8 num_concurrent_conn;
+ u8 num_contexts;
+
+ u8 _r_d;
+
+ __le16 active_task_count;
+
+ u8 _r_e[9];
+
+ u8 itnl_reason; /* I_T nexus loss reason */
+
+ __le16 _r_f;
+
+ __le16 itnl_timeout;
+#define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */
+
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+struct asd_ddb_stp_sata_target_port {
+ u8 conn_type; /* byte 0 */
+ u8 conn_rate;
+ __be16 init_conn_tag;
+ u8 dest_sas_addr[8]; /* bytes 4-11 */
+
+ __le16 send_queue_head;
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_TARGET */
+
+ __le16 _r_a;
+
+ __be16 awt_def;
+ u8 compat_features; /* byte 20 */
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time;
+ __be32 more_compat_features; /* byte 24 */
+
+ u8 conn_mask;
+ u8 flags; /* concurrent conn:2,2 and open:0(1) */
+#define SATA_MULTIPORT 0x80
+#define SUPPORTS_AFFIL 0x40
+#define STP_AFFIL_POL 0x20
+
+ u8 _r_b;
+ u8 flags2; /* STP close policy:0 */
+#define STP_CL_POL_NO_TX 0x00
+#define STP_CL_POL_BTW_CMDS 0x01
+
+ __le16 exec_queue_tail;
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+ __le16 ata_cmd_scbptr;
+ __le32 sata_tag_alloc_mask;
+ __le16 active_task_count;
+ __le16 _r_c;
+ __le32 sata_sactive;
+ u8 num_sata_tags;
+ u8 sata_status;
+ u8 sata_ending_status;
+ u8 itnl_reason; /* I_T nexus loss reason */
+ __le16 ncq_data_scb_ptr;
+ __le16 itnl_timeout;
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_init_port, describes the device descriptor block
+ * of an initiator port (when the sequencer is operating in target mode).
+ * Bytes [0,11] and [20,27] are from the OPEN address frame.
+ * The sequencer allocates an initiator port DDB entry.
+ */
+struct asd_ddb_init_port {
+ u8 conn_type; /* byte 0 */
+ u8 conn_rate;
+ __be16 init_conn_tag; /* BE */
+ u8 dest_sas_addr[8];
+ __le16 send_queue_head; /* LE, byte 12 */
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_INITIATOR */
+ __le16 _r_a;
+ __be16 awt_def; /* BE */
+ u8 compat_features;
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time; /* BE */
+ __be32 more_compat_features; /* BE */
+ u8 conn_mask;
+ u8 flags; /* == 5 */
+ u16 _r_b;
+ __le16 exec_queue_tail; /* execution queue tail */
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+ __le16 init_resp_timeout; /* initiator response timeout */
+ __le32 _r_c;
+ __le16 active_tasks; /* active task count */
+ __le16 init_list; /* initiator list link pointer */
+ __le32 _r_d;
+ u8 max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */
+ u8 itnl_reason; /* I_T nexus loss reason */
+ __le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */
+ __le16 itnl_to; /* from the Protocol Specific Port Ctrl MP */
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_tag, describes a look-up table to be used
+ * by the sequencers. SATA II, IDENTIFY DEVICE data, word 76, bit 8:
+ * NCQ support. This table is used by the sequencers to find the
+ * corresponding SCB, given a SATA II tag value.
+ */
+struct asd_ddb_sata_tag {
+ __le16 scb_pointer[32];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_table, describes a port number to
+ * connection handle look-up table. SATA targets attached to a port
+ * multiplier require a 4-bit port number value. There is one DDB
+ * entry of this type for each SATA port multiplier (sister DDB).
+ * Given a SATA PM port number, this table gives us the SATA PM Port
+ * DDB of the SATA port multiplier port (i.e. the SATA target
+ * discovered on the port).
+ */
+struct asd_ddb_sata_pm_table {
+ __le16 ddb_pointer[16];
+ __le16 _r_a[16];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier
+ * port format DDB.
+ */
+struct asd_ddb_sata_pm_port {
+ u8 _r_a[15];
+ u8 ddb_type;
+ u8 _r_b[13];
+ u8 pm_port_flags;
+#define PM_PORT_MASK 0xF0
+#define PM_PORT_SET 0x02
+ u8 _r_c[6];
+ __le16 sister_ddb;
+ __le16 ata_cmd_scbptr;
+ __le32 sata_tag_alloc_mask;
+ __le16 active_task_count;
+ __le16 parent_ddb;
+ __le32 sata_sactive;
+ u8 num_sata_tags;
+ u8 sata_status;
+ u8 sata_ending_status;
+ u8 _r_d[9];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_seq_shared, describes a DDB shared by the
+ * central and link sequencers. port_map_by_links is indexed phy
+ * number [0,7]; each byte is a bit mask of all the phys that are in
+ * the same port as the indexed phy.
+ */
+struct asd_ddb_seq_shared {
+ __le16 q_free_ddb_head;
+ __le16 q_free_ddb_tail;
+ __le16 q_free_ddb_cnt;
+ __le16 q_used_ddb_head;
+ __le16 q_used_ddb_tail;
+ __le16 shared_mem_lock;
+ __le16 smp_conn_tag;
+ __le16 est_nexus_buf_cnt;
+ __le16 est_nexus_buf_thresh;
+ u32 _r_a;
+ u8 settable_max_contexts;
+ u8 _r_b[23];
+ u8 conn_not_active;
+ u8 phy_is_up;
+ u8 _r_c[8];
+ u8 port_map_by_links[8];
+} __attribute__ ((packed));
+
+/* ---------- SG Element ---------- */
+
+/* This struct sg_el, describes the hardware scatter gather buffer
+ * element. All entries are little endian. In an SCB, there are 2 of
+ * this, plus one more, called a link element of this indicating a
+ * sublist if needed.
+ *
+ * A link element has only the bus address set and the flags (DS) bit
+ * valid. The bus address points to the start of the sublist.
+ *
+ * If a sublist is needed, then that sublist should also include the 2
+ * sg_el embedded in the SCB, in which case next_sg_offset is 32,
+ * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case.
+ */
+struct sg_el {
+ __le64 bus_addr;
+ __le32 size;
+ __le16 _r;
+ u8 next_sg_offs;
+ u8 flags;
+#define ASD_SG_EL_DS_MASK 0x30
+#define ASD_SG_EL_DS_OCM 0x10
+#define ASD_SG_EL_DS_HM 0x00
+#define ASD_SG_EL_LIST_MASK 0xC0
+#define ASD_SG_EL_LIST_EOL 0x40
+#define ASD_SG_EL_LIST_EOS 0x80
+} __attribute__ ((packed));
+
+/* ---------- SCBs ---------- */
+
+/* An SCB (sequencer control block) is comprised of a common header
+ * and a task part, for a total of 128 bytes. All fields are in LE
+ * order, unless otherwise noted.
+ */
+
+/* This struct scb_header, defines the SCB header format.
+ */
+struct scb_header {
+ __le64 next_scb;
+ __le16 index; /* transaction context */
+ u8 opcode;
+} __attribute__ ((packed));
+
+/* SCB opcodes: Execution queue
+ */
+#define INITIATE_SSP_TASK 0x00
+#define INITIATE_LONG_SSP_TASK 0x01
+#define INITIATE_BIDIR_SSP_TASK 0x02
+#define ABORT_TASK 0x03
+#define INITIATE_SSP_TMF 0x04
+#define SSP_TARG_GET_DATA 0x05
+#define SSP_TARG_GET_DATA_GOOD 0x06
+#define SSP_TARG_SEND_RESP 0x07
+#define QUERY_SSP_TASK 0x08
+#define INITIATE_ATA_TASK 0x09
+#define INITIATE_ATAPI_TASK 0x0a
+#define CONTROL_ATA_DEV 0x0b
+#define INITIATE_SMP_TASK 0x0c
+#define SMP_TARG_SEND_RESP 0x0f
+
+/* SCB opcodes: Send Queue
+ */
+#define SSP_TARG_SEND_DATA 0x40
+#define SSP_TARG_SEND_DATA_GOOD 0x41
+
+/* SCB opcodes: Link Queue
+ */
+#define CONTROL_PHY 0x80
+#define SEND_PRIMITIVE 0x81
+#define INITIATE_LINK_ADM_TASK 0x82
+
+/* SCB opcodes: other
+ */
+#define EMPTY_SCB 0xc0
+#define INITIATE_SEQ_ADM_TASK 0xc1
+#define EST_ICL_TARG_WINDOW 0xc2
+#define COPY_MEM 0xc3
+#define CLEAR_NEXUS 0xc4
+#define INITIATE_DDB_ADM_TASK 0xc6
+#define ESTABLISH_NEXUS_ESCB 0xd0
+
+#define LUN_SIZE 8
+
+/* See SAS spec, task IU
+ */
+struct ssp_task_iu {
+ u8 lun[LUN_SIZE]; /* BE */
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag; /* BE */
+ u8 _r_c[14];
+} __attribute__ ((packed));
+
+/* See SAS spec, command IU
+ */
+struct ssp_command_iu {
+ u8 lun[LUN_SIZE];
+ u8 _r_a;
+ u8 efb_prio_attr; /* enable first burst, task prio & attr */
+#define EFB_MASK 0x80
+#define TASK_PRIO_MASK 0x78
+#define TASK_ATTR_MASK 0x07
+
+ u8 _r_b;
+ u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
+ union {
+ u8 cdb[16];
+ struct {
+ __le64 long_cdb_addr; /* bus address, LE */
+ __le32 long_cdb_size; /* LE */
+ u8 _r_c[3];
+ u8 eol_ds; /* eol:6,6, ds:5,4 */
+ } long_cdb; /* sequencer extension */
+ };
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset; /* BE */
+ __be32 write_data_len; /* BE */
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+/* ---------- SCB tasks ---------- */
+
+/* This is both ssp_task and long_ssp_task
+ */
+struct initiate_ssp_task {
+ u8 proto_conn_rate; /* proto:6,4, conn_rate:3,0 */
+ __le32 total_xfer_len;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_command_iu ssp_cmd;
+ __le16 sister_scb; /* 0xFFFF */
+ __le16 conn_handle; /* index to DDB for the intended target */
+ u8 data_dir; /* :1,0 */
+#define DATA_DIR_NONE 0x00
+#define DATA_DIR_IN 0x01
+#define DATA_DIR_OUT 0x02
+#define DATA_DIR_BYRECIPIENT 0x03
+
+ u8 _r_a;
+ u8 retry_count;
+ u8 _r_b[5];
+ struct sg_el sg_element[3]; /* 2 real and 1 link */
+} __attribute__ ((packed));
+
+/* This defines both ata_task and atapi_task.
+ * ata: C bit of FIS should be 1,
+ * atapi: C bit of FIS should be 1, and command register should be 0xA0,
+ * to indicate a packet command.
+ */
+struct initiate_ata_task {
+ u8 proto_conn_rate;
+ __le32 total_xfer_len;
+ struct host_to_dev_fis fis;
+ __le32 data_offs;
+ u8 atapi_packet[16];
+ u8 _r_a[12];
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 ata_flags; /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */
+#define CSMI_TASK 0x40
+#define DATA_XFER_MODE_DMA 0x10
+#define ATA_Q_TYPE_MASK 0x08
+#define ATA_Q_TYPE_UNTAGGED 0x00
+#define ATA_Q_TYPE_NCQ 0x08
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c;
+ u8 flags;
+#define STP_AFFIL_POLICY 0x20
+#define SET_AFFIL_POLICY 0x10
+#define RET_PARTIAL_SGLIST 0x02
+
+ u8 _r_d[3];
+ struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+struct initiate_smp_task {
+ u8 proto_conn_rate;
+ u8 _r_a[40];
+ struct sg_el smp_req;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 _r_c[8];
+ struct sg_el smp_resp;
+ u8 _r_d[32];
+} __attribute__ ((packed));
+
+struct control_phy {
+ u8 phy_id;
+ u8 sub_func;
+#define DISABLE_PHY 0x00
+#define ENABLE_PHY 0x01
+#define RELEASE_SPINUP_HOLD 0x02
+#define ENABLE_PHY_NO_SAS_OOB 0x03
+#define ENABLE_PHY_NO_SATA_OOB 0x04
+#define PHY_NO_OP 0x05
+#define EXECUTE_HARD_RESET 0x81
+
+ u8 func_mask;
+ u8 speed_mask;
+ u8 hot_plug_delay;
+ u8 port_type;
+ u8 flags;
+#define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01
+#define DISABLE_PHY_IF_OOB_FAILS 0x02
+
+ __le32 timeout_override;
+ u8 link_reset_retries;
+ u8 _r_a[47];
+ __le16 conn_handle;
+ u8 _r_b[56];
+} __attribute__ ((packed));
+
+struct control_ata_dev {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct host_to_dev_fis fis;
+ u8 _r_b[32];
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 ata_flags; /* 0 */
+ u8 _r_c[55];
+} __attribute__ ((packed));
+
+struct empty_scb {
+ u8 num_valid;
+ __le32 _r_a;
+#define ASD_EDBS_PER_SCB 7
+/* header+data+CRC+DMA suffix data */
+#define ASD_EDB_SIZE (24+1024+4+16)
+ struct sg_el eb[ASD_EDBS_PER_SCB];
+#define ELEMENT_NOT_VALID 0xC0
+} __attribute__ ((packed));
+
+struct initiate_link_adm {
+ u8 phy_id;
+ u8 sub_func;
+#define GET_LINK_ERROR_COUNT 0x00
+#define RESET_LINK_ERROR_COUNT 0x01
+#define ENABLE_NOTIFY_SPINUP_INTS 0x02
+
+ u8 _r_a[57];
+ __le16 conn_handle;
+ u8 _r_b[56];
+} __attribute__ ((packed));
+
+struct copy_memory {
+ u8 _r_a;
+ __le16 xfer_len;
+ __le16 _r_b;
+ __le64 src_busaddr;
+ u8 src_ds; /* See definition of sg_el */
+ u8 _r_c[45];
+ __le16 conn_handle;
+ __le64 _r_d;
+ __le64 dest_busaddr;
+ u8 dest_ds; /* See definition of sg_el */
+ u8 _r_e[39];
+} __attribute__ ((packed));
+
+struct abort_task {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_task_iu ssp_task;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
+#define SUSPEND_DATA_TRANS 0x04
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ __le16 index; /* Transaction context of task to be queried */
+ __le16 itnl_to;
+ u8 _r_d[44];
+} __attribute__ ((packed));
+
+struct clear_nexus {
+ u8 nexus;
+#define NEXUS_ADAPTER 0x00
+#define NEXUS_PORT 0x01
+#define NEXUS_I_T 0x02
+#define NEXUS_I_T_L 0x03
+#define NEXUS_TAG 0x04
+#define NEXUS_TRANS_CX 0x05
+#define NEXUS_SATA_TAG 0x06
+#define NEXUS_T_L 0x07
+#define NEXUS_L 0x08
+#define NEXUS_T_TAG 0x09
+
+ __le32 _r_a;
+ u8 flags;
+#define SUSPEND_TX 0x80
+#define RESUME_TX 0x40
+#define SEND_Q 0x04
+#define EXEC_Q 0x02
+#define NOTINQ 0x01
+
+ u8 _r_b[3];
+ u8 conn_mask;
+ u8 _r_c[19];
+ struct ssp_task_iu ssp_task; /* LUN and TAG */
+ __le16 _r_d;
+ __le16 conn_handle;
+ __le64 _r_e;
+ __le16 index; /* Transaction context of task to be cleared */
+ __le16 context; /* Clear nexus context */
+ u8 _r_f[44];
+} __attribute__ ((packed));
+
+struct initiate_ssp_tmf {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_task_iu ssp_task;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 flags; /* itnl override and suspend data tx */
+#define OVERRIDE_ITNL_TIMER 8
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ __le16 index; /* Transaction context of task to be queried */
+ __le16 itnl_to;
+ u8 _r_d[44];
+} __attribute__ ((packed));
+
+/* Transmits an arbitrary primitive on the link.
+ * Used for NOTIFY and BROADCAST.
+ */
+struct send_prim {
+ u8 phy_id;
+ u8 wait_transmit; /* :0,0 */
+ u8 xmit_flags;
+#define XMTPSIZE_MASK 0xF0
+#define XMTPSIZE_SINGLE 0x10
+#define XMTPSIZE_REPEATED 0x20
+#define XMTPSIZE_CONT 0x20
+#define XMTPSIZE_TRIPLE 0x30
+#define XMTPSIZE_REDUNDANT 0x60
+#define XMTPSIZE_INF 0
+
+#define XMTCONTEN 0x04
+#define XMTPFRM 0x02 /* Transmit at the next frame boundary */
+#define XMTPIMM 0x01 /* Transmit immediately */
+
+ __le16 _r_a;
+ u8 prim[4]; /* K, D0, D1, D2 */
+ u8 _r_b[50];
+ __le16 conn_handle;
+ u8 _r_c[56];
+} __attribute__ ((packed));
+
+/* This describes both SSP Target Get Data and SSP Target Get Data And
+ * Send Good Response SCBs. Used when the sequencer is operating in
+ * target mode...
+ */
+struct ssp_targ_get_data {
+ u8 proto_conn_rate;
+ __le32 total_xfer_len;
+ struct ssp_frame_hdr ssp_frame;
+ struct xfer_rdy_iu xfer_rdy;
+ u8 lun[LUN_SIZE];
+ __le64 _r_a;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 data_dir; /* 01b */
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+/* ---------- The actual SCB struct ---------- */
+
+struct scb {
+ struct scb_header header;
+ union {
+ struct initiate_ssp_task ssp_task;
+ struct initiate_ata_task ata_task;
+ struct initiate_smp_task smp_task;
+ struct control_phy control_phy;
+ struct control_ata_dev control_ata_dev;
+ struct empty_scb escb;
+ struct initiate_link_adm link_adm;
+ struct copy_memory cp_mem;
+ struct abort_task abort_task;
+ struct clear_nexus clear_nexus;
+ struct initiate_ssp_tmf ssp_tmf;
+ };
+} __attribute__ ((packed));
+
+/* ---------- Done List ---------- */
+/* The done list entry opcode field is defined below.
+ * The mnemonic encoding and meaning is as follows:
+ * TC - Task Complete, status was received and acknowledged
+ * TF - Task Failed, indicates an error prior to receiving acknowledgment
+ * for the command:
+ * - no conn,
+ * - NACK or R_ERR received in response to this command,
+ * - credit blocked or not available, or in the case of SMP request,
+ * - no SMP response was received.
+ * In these four cases it is known that the target didn't receive the
+ * command.
+ * TI - Task Interrupted, error after the command was acknowledged. It is
+ * known that the command was received by the target.
+ * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK
+ * (R_ERR) was received due to loss of signal, broken connection, loss of
+ * dword sync or other reason. The application client should send the
+ * appropriate task query.
+ * TA - Task Aborted, see TF.
+ * _RESP - The completion includes an empty buffer containing status.
+ * TO - Timeout.
+ */
+#define TC_NO_ERROR 0x00
+#define TC_UNDERRUN 0x01
+#define TC_OVERRUN 0x02
+#define TF_OPEN_TO 0x03
+#define TF_OPEN_REJECT 0x04
+#define TI_BREAK 0x05
+#define TI_PROTO_ERR 0x06
+#define TC_SSP_RESP 0x07
+#define TI_PHY_DOWN 0x08
+#define TF_PHY_DOWN 0x09
+#define TC_LINK_ADM_RESP 0x0a
+#define TC_CSMI 0x0b
+#define TC_ATA_RESP 0x0c
+#define TU_PHY_DOWN 0x0d
+#define TU_BREAK 0x0e
+#define TI_SATA_TO 0x0f
+#define TI_NAK 0x10
+#define TC_CONTROL_PHY 0x11
+#define TF_BREAK 0x12
+#define TC_RESUME 0x13
+#define TI_ACK_NAK_TO 0x14
+#define TF_SMPRSP_TO 0x15
+#define TF_SMP_XMIT_RCV_ERR 0x16
+#define TC_PARTIAL_SG_LIST 0x17
+#define TU_ACK_NAK_TO 0x18
+#define TU_SATA_TO 0x19
+#define TF_NAK_RECV 0x1a
+#define TA_I_T_NEXUS_LOSS 0x1b
+#define TC_ATA_R_ERR_RECV 0x1c
+#define TF_TMF_NO_CTX 0x1d
+#define TA_ON_REQ 0x1e
+#define TF_TMF_NO_TAG 0x1f
+#define TF_TMF_TAG_FREE 0x20
+#define TF_TMF_TASK_DONE 0x21
+#define TF_TMF_NO_CONN_HANDLE 0x22
+#define TC_TASK_CLEARED 0x23
+#define TI_SYNCS_RECV 0x24
+#define TU_SYNCS_RECV 0x25
+#define TF_IRTT_TO 0x26
+#define TF_NO_SMP_CONN 0x27
+#define TF_IU_SHORT 0x28
+#define TF_DATA_OFFS_ERR 0x29
+#define TF_INV_CONN_HANDLE 0x2a
+#define TF_REQUESTED_N_PENDING 0x2b
+
+/* 0xc1 - 0xc7: empty buffer received,
+ 0xd1 - 0xd7: establish nexus empty buffer received
+*/
+/* This is the ESCB mask */
+#define ESCB_RECVD 0xC0
+
+
+/* This struct done_list_struct defines the done list entry.
+ * All fields are LE.
+ */
+struct done_list_struct {
+ __le16 index; /* aka transaction context */
+ u8 opcode;
+ u8 status_block[4];
+ u8 toggle; /* bit 0 */
+#define DL_TOGGLE_MASK 0x01
+} __attribute__ ((packed));
+
+/* ---------- PHYS ---------- */
+
+struct asd_phy {
+ struct asd_sas_phy sas_phy;
+ struct asd_phy_desc *phy_desc; /* hw profile */
+
+ struct sas_identify_frame *identify_frame;
+ struct asd_dma_tok *id_frm_tok;
+
+ u8 frame_rcvd[ASD_EDB_SIZE];
+};
+
+
+#define ASD_SCB_SIZE sizeof(struct scb)
+#define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port)
+
+/* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent.
+ * Default: 0x10 (it's a mask)
+ */
+#define ASD_NOTIFY_ENABLE_SPINUP 0x10
+
+/* If enabled, set this to the interval between transmission
+ * of NOTIFY (ENABLE SPINUP). In units of 200 us.
+ */
+#define ASD_NOTIFY_TIMEOUT 2500
+
+/* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP).
+ * If 0, transmit immediately. In milliseconds.
+ */
+#define ASD_NOTIFY_DOWN_COUNT 0
+
+/* Device present timer timeout constant, 10 ms. */
+#define ASD_DEV_PRESENT_TIMEOUT 0x2710
+
+#define ASD_SATA_INTERLOCK_TIMEOUT 0
+
+/* How long to wait before shutting down an STP connection, unless
+ * an STP target sent frame(s). 50 usec.
+ * IGNORED by the sequencer (i.e. value 0 always).
+ */
+#define ASD_STP_SHUTDOWN_TIMEOUT 0x0
+
+/* ATA soft reset timer timeout. 5 usec. */
+#define ASD_SRST_ASSERT_TIMEOUT 0x05
+
+/* 31 sec */
+#define ASD_RCV_FIS_TIMEOUT 0x01D905C0
+
+#define ASD_ONE_MILLISEC_TIMEOUT 0x03e8
+
+/* COMINIT timer */
+#define ASD_TEN_MILLISEC_TIMEOUT 0x2710
+#define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT
+
+/* 1 sec */
+#define ASD_SMP_RCV_TIMEOUT 0x000F4240
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
new file mode 100644
index 00000000000..7ee49b51b72
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -0,0 +1,758 @@
+/*
+ * Aic94xx SAS/SATA driver SCB management.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+#include "aic94xx_dump.h"
+
+/* ---------- EMPTY SCB ---------- */
+
+#define DL_PHY_MASK 7
+#define BYTES_DMAED 0
+#define PRIMITIVE_RECVD 0x08
+#define PHY_EVENT 0x10
+#define LINK_RESET_ERROR 0x18
+#define TIMER_EVENT 0x20
+#define REQ_TASK_ABORT 0xF0
+#define REQ_DEVICE_RESET 0xF1
+#define SIGNAL_NCQ_ERROR 0xF2
+#define CLEAR_NCQ_ERROR 0xF3
+
+#define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE \
+ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+ | CURRENT_OOB_ERROR)
+
+static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
+{
+ struct sas_phy *sas_phy = phy->sas_phy.phy;
+
+ switch (oob_mode & 7) {
+ case PHY_SPEED_60:
+ /* FIXME: sas transport class doesn't have this */
+ phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
+ break;
+ case PHY_SPEED_30:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+ break;
+ case PHY_SPEED_15:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+ break;
+ }
+ sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
+ sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+ sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sas_phy->maximum_linkrate = phy->phy_desc->max_sas_lrate;
+ sas_phy->minimum_linkrate = phy->phy_desc->min_sas_lrate;
+
+ if (oob_mode & SAS_MODE)
+ phy->sas_phy.oob_mode = SAS_OOB_MODE;
+ else if (oob_mode & SATA_MODE)
+ phy->sas_phy.oob_mode = SATA_OOB_MODE;
+}
+
+static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ int phy_id = dl->status_block[0] & DL_PHY_MASK;
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+ u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS;
+ u8 oob_mode = dl->status_block[2];
+
+ switch (oob_status) {
+ case CURRENT_LOSS_OF_SIGNAL:
+ /* directly attached device was removed */
+ ASD_DPRINTK("phy%d: device unplugged\n", phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL);
+ break;
+ case CURRENT_OOB_DONE:
+ /* hot plugged device */
+ asd_turn_led(asd_ha, phy_id, 1);
+ get_lrate_mode(phy, oob_mode);
+ ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n",
+ phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
+ break;
+ case CURRENT_SPINUP_HOLD:
+ /* hot plug SATA, no COMWAKE sent */
+ asd_turn_led(asd_ha, phy_id, 1);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD);
+ break;
+ case CURRENT_GTO_TIMEOUT:
+ case CURRENT_OOB_ERROR:
+ ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id,
+ dl->status_block[1]);
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR);
+ break;
+ }
+}
+
+/* If phys are enabled sparsely, this will do the right thing. */
+static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
+ struct asd_phy *phy)
+{
+ u8 enabled_mask = asd_ha->hw_prof.enabled_phys;
+ int i, k = 0;
+
+ for_each_phy(enabled_mask, enabled_mask, i) {
+ if (&asd_ha->phys[i] == phy)
+ return k;
+ k++;
+ }
+ return 0;
+}
+
+/**
+ * asd_get_attached_sas_addr -- extract/generate attached SAS address
+ * phy: pointer to asd_phy
+ * sas_addr: pointer to buffer where the SAS address is to be written
+ *
+ * This function extracts the SAS address from an IDENTIFY frame
+ * received. If OOB is SATA, then a SAS address is generated from the
+ * HA tables.
+ *
+ * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
+ * buffer.
+ */
+static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
+{
+ if (phy->sas_phy.frame_rcvd[0] == 0x34
+ && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
+ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+ /* FIS device-to-host */
+ u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr);
+
+ addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy);
+ *(__be64 *)sas_addr = cpu_to_be64(addr);
+ } else {
+ struct sas_identify_frame *idframe =
+ (void *) phy->sas_phy.frame_rcvd;
+ memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
+ }
+}
+
+static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int edb_id, int phy_id)
+{
+ unsigned long flags;
+ int edb_el = edb_id + ascb->edb_index;
+ struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el];
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+ struct sas_ha_struct *sas_ha = phy->sas_phy.ha;
+ u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2];
+
+ size = min(size, (u16) sizeof(phy->frame_rcvd));
+
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size);
+ phy->sas_phy.frame_rcvd_size = size;
+ 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);
+ sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
+}
+
+static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
+{
+ 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];
+ u8 lr_error = dl->status_block[1];
+ u8 retries_left = dl->status_block[2];
+
+ switch (lr_error) {
+ case 0:
+ ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id);
+ break;
+ case 1:
+ ASD_DPRINTK("phy%d: Loss of signal\n", phy_id);
+ break;
+ case 2:
+ ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id);
+ break;
+ case 3:
+ ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id);
+ break;
+ default:
+ ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n",
+ phy_id, lr_error);
+ break;
+ }
+
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(sas_phy);
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+
+ if (retries_left == 0) {
+ int num = 1;
+ struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
+ GFP_ATOMIC);
+ if (!cp) {
+ asd_printk("%s: out of memory\n", __FUNCTION__);
+ goto out;
+ }
+ ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
+ phy_id);
+ asd_build_control_phy(cp, phy_id, ENABLE_PHY);
+ if (asd_post_ascb_list(ascb->ha, cp, 1) != 0)
+ asd_ascb_free(cp);
+ }
+out:
+ ;
+}
+
+static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
+{
+ 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];
+ u8 reg = dl->status_block[1];
+ u32 cont = dl->status_block[2] << ((reg & 3)*8);
+
+ reg &= ~3;
+ switch (reg) {
+ case LmPRMSTAT0BYTE0:
+ switch (cont) {
+ case LmBROADCH:
+ case LmBROADRVCH0:
+ case LmBROADRVCH1:
+ case LmBROADSES:
+ ASD_DPRINTK("phy%d: BROADCAST change received:%d\n",
+ phy_id, cont);
+ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+ sas_phy->sas_prim = ffs(cont);
+ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+ sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD);
+ break;
+
+ case LmUNKNOWNP:
+ ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id);
+ break;
+
+ default:
+ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+ phy_id, reg, cont);
+ break;
+ }
+ break;
+ case LmPRMSTAT1BYTE0:
+ switch (cont) {
+ case LmHARDRST:
+ ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n",
+ phy_id);
+ /* The sequencer disables all phys on that port.
+ * We have to re-enable the phys ourselves. */
+ sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
+ break;
+
+ default:
+ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+ phy_id, reg, cont);
+ break;
+ }
+ break;
+ default:
+ ASD_DPRINTK("unknown primitive register:0x%x\n",
+ dl->status_block[1]);
+ break;
+ }
+}
+
+/**
+ * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB
+ * @ascb: pointer to Empty SCB
+ * @edb_id: index [0,6] to the empty data buffer which is to be invalidated
+ *
+ * After an EDB has been invalidated, if all EDBs in this ESCB have been
+ * invalidated, the ESCB is posted back to the sequencer.
+ * Context is tasklet/IRQ.
+ */
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
+{
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ struct empty_scb *escb = &ascb->scb->escb;
+ struct sg_el *eb = &escb->eb[edb_id];
+ struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id];
+
+ memset(edb->vaddr, 0, ASD_EDB_SIZE);
+ eb->flags |= ELEMENT_NOT_VALID;
+ escb->num_valid--;
+
+ if (escb->num_valid == 0) {
+ int i;
+ /* ASD_DPRINTK("reposting escb: vaddr: 0x%p, "
+ "dma_handle: 0x%08llx, next: 0x%08llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (u64)ascb->dma_scb.dma_handle,
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+ */
+ escb->num_valid = ASD_EDBS_PER_SCB;
+ for (i = 0; i < ASD_EDBS_PER_SCB; i++)
+ escb->eb[i].flags = 0;
+ if (!list_empty(&ascb->list))
+ list_del_init(&ascb->list);
+ i = asd_post_escb_list(ascb->ha, ascb, 1);
+ if (i)
+ asd_printk("couldn't post escb, err:%d\n", i);
+ }
+}
+
+static void escb_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */
+ 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];
+
+ if (edb > 6 || edb < 0) {
+ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+ edb, dl->opcode);
+ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+ sb_opcode, phy_id);
+ ASD_DPRINTK("escb: vaddr: 0x%p, "
+ "dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+ }
+
+ sb_opcode &= ~DL_PHY_MASK;
+
+ switch (sb_opcode) {
+ case BYTES_DMAED:
+ ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+ asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
+ break;
+ case PRIMITIVE_RECVD:
+ ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+ phy_id);
+ asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
+ break;
+ case PHY_EVENT:
+ ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+ asd_phy_event_tasklet(ascb, dl);
+ break;
+ case LINK_RESET_ERROR:
+ ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+ phy_id);
+ asd_link_reset_err_tasklet(ascb, dl, phy_id);
+ break;
+ case TIMER_EVENT:
+ ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
+ __FUNCTION__, phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ /* the device is gone */
+ sas_phy_disconnected(sas_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);
+ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+ edb, dl->opcode);
+ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+ sb_opcode, phy_id);
+ ASD_DPRINTK("escb: vaddr: 0x%p, "
+ "dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+
+ break;
+ }
+
+ asd_invalidate_edb(ascb, edb);
+}
+
+int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_escbs; i++)
+ seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
+
+ ASD_DPRINTK("posting %d escbs\n", i);
+ return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+#define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE \
+ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+ | CURRENT_OOB_ERROR)
+
+/**
+ * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
+ * @ascb: pointer to an ascb
+ * @dl: pointer to the done list entry
+ *
+ * This function completes a CONTROL PHY scb and frees the ascb.
+ * A note on LEDs:
+ * - an LED blinks if there is IO though it,
+ * - if a device is connected to the LED, it is lit,
+ * - if no device is connected to the LED, is is dimmed (off).
+ */
+static void control_phy_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct scb *scb = ascb->scb;
+ struct control_phy *control_phy = &scb->control_phy;
+ u8 phy_id = control_phy->phy_id;
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+
+ u8 status = dl->status_block[0];
+ u8 oob_status = dl->status_block[1];
+ u8 oob_mode = dl->status_block[2];
+ /* u8 oob_signals= dl->status_block[3]; */
+
+ if (status != 0) {
+ ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
+ __FUNCTION__, phy_id, status);
+ goto out;
+ }
+
+ switch (control_phy->sub_func) {
+ case DISABLE_PHY:
+ asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ asd_control_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+ break;
+
+ case ENABLE_PHY:
+ asd_control_led(asd_ha, phy_id, 1);
+ if (oob_status & CURRENT_OOB_DONE) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ get_lrate_mode(phy, oob_mode);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
+ __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+ phy->sas_phy.iproto);
+ } else if (oob_status & CURRENT_SPINUP_HOLD) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+ phy_id);
+ } else if (oob_status & CURRENT_ERR_MASK) {
+ asd_turn_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
+ __FUNCTION__, phy_id, oob_status);
+ } else if (oob_status & (CURRENT_HOT_PLUG_CNCT
+ | CURRENT_DEVICE_PRESENT)) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
+ __FUNCTION__, phy_id);
+ } else {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: phy%d: no device present: "
+ "oob_status:0x%x\n",
+ __FUNCTION__, phy_id, oob_status);
+ }
+ break;
+ case RELEASE_SPINUP_HOLD:
+ case PHY_NO_OP:
+ case EXECUTE_HARD_RESET:
+ ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+ phy_id, control_phy->sub_func);
+ /* XXX finish */
+ break;
+ default:
+ ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+ phy_id, control_phy->sub_func);
+ break;
+ }
+out:
+ asd_ascb_free(ascb);
+}
+
+static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
+{
+ /* disable all speeds, then enable defaults */
+ *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS
+ | SATA_SPEED_30_DIS | SATA_SPEED_15_DIS;
+
+ switch (pd->max_sas_lrate) {
+ case SAS_LINK_RATE_6_0_GBPS:
+ *speed_mask &= ~SAS_SPEED_60_DIS;
+ default:
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask &= ~SAS_SPEED_30_DIS;
+ case SAS_LINK_RATE_1_5_GBPS:
+ *speed_mask &= ~SAS_SPEED_15_DIS;
+ }
+
+ switch (pd->min_sas_lrate) {
+ case SAS_LINK_RATE_6_0_GBPS:
+ *speed_mask |= SAS_SPEED_30_DIS;
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask |= SAS_SPEED_15_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ /* nothing to do */
+ ;
+ }
+
+ switch (pd->max_sata_lrate) {
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask &= ~SATA_SPEED_30_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ *speed_mask &= ~SATA_SPEED_15_DIS;
+ }
+
+ switch (pd->min_sata_lrate) {
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask |= SATA_SPEED_15_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ /* nothing to do */
+ ;
+ }
+}
+
+/**
+ * asd_build_control_phy -- build a CONTROL PHY SCB
+ * @ascb: pointer to an ascb
+ * @phy_id: phy id to control, integer
+ * @subfunc: subfunction, what to actually to do the phy
+ *
+ * This function builds a CONTROL PHY scb. No allocation of any kind
+ * is performed. @ascb is allocated with the list function.
+ * The caller can override the ascb->tasklet_complete to point
+ * to its own callback function. It must call asd_ascb_free()
+ * at its tasklet complete function.
+ * See the default implementation.
+ */
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
+{
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+ struct scb *scb = ascb->scb;
+ struct control_phy *control_phy = &scb->control_phy;
+
+ scb->header.opcode = CONTROL_PHY;
+ control_phy->phy_id = (u8) phy_id;
+ control_phy->sub_func = subfunc;
+
+ switch (subfunc) {
+ case EXECUTE_HARD_RESET: /* 0x81 */
+ case ENABLE_PHY: /* 0x01 */
+ /* decide hot plug delay */
+ control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT;
+
+ /* decide speed mask */
+ set_speed_mask(&control_phy->speed_mask, phy->phy_desc);
+
+ /* initiator port settings are in the hi nibble */
+ if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
+ control_phy->port_type = SAS_PROTO_ALL << 4;
+ else if (phy->sas_phy.role == PHY_ROLE_TARGET)
+ control_phy->port_type = SAS_PROTO_ALL;
+ else
+ control_phy->port_type =
+ (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+
+ /* link reset retries, this should be nominal */
+ control_phy->link_reset_retries = 10;
+
+ case RELEASE_SPINUP_HOLD: /* 0x02 */
+ /* decide the func_mask */
+ control_phy->func_mask = FUNCTION_MASK_DEFAULT;
+ if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD)
+ control_phy->func_mask &= ~SPINUP_HOLD_DIS;
+ else
+ control_phy->func_mask |= SPINUP_HOLD_DIS;
+ }
+
+ control_phy->conn_handle = cpu_to_le16(0xFFFF);
+
+ ascb->tasklet_complete = control_phy_tasklet_complete;
+}
+
+/* ---------- INITIATE LINK ADM TASK ---------- */
+
+static void link_adm_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ u8 opcode = dl->opcode;
+ struct initiate_link_adm *link_adm = &ascb->scb->link_adm;
+ u8 phy_id = link_adm->phy_id;
+
+ if (opcode != TC_NO_ERROR) {
+ asd_printk("phy%d: link adm task 0x%x completed with error "
+ "0x%x\n", phy_id, link_adm->sub_func, opcode);
+ }
+ ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n",
+ phy_id, link_adm->sub_func, opcode);
+
+ asd_ascb_free(ascb);
+}
+
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+ u8 subfunc)
+{
+ struct scb *scb = ascb->scb;
+ struct initiate_link_adm *link_adm = &scb->link_adm;
+
+ scb->header.opcode = INITIATE_LINK_ADM_TASK;
+
+ link_adm->phy_id = phy_id;
+ link_adm->sub_func = subfunc;
+ link_adm->conn_handle = cpu_to_le16(0xFFFF);
+
+ ascb->tasklet_complete = link_adm_tasklet_complete;
+}
+
+/* ---------- SCB timer ---------- */
+
+/**
+ * asd_ascb_timedout -- called when a pending SCB's timer has expired
+ * @data: unsigned long, a pointer to the ascb in question
+ *
+ * This is the default timeout function which does the most necessary.
+ * Upper layers can implement their own timeout function, say to free
+ * resources they have with this SCB, and then call this one at the
+ * end of their timeout function. To do this, one should initialize
+ * the ascb->timer.{function, data, expires} prior to calling the post
+ * funcion. The timer is started by the post function.
+ */
+void asd_ascb_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ unsigned long flags;
+
+ ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode);
+
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ seq->pending--;
+ list_del_init(&ascb->list);
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+
+ asd_ascb_free(ascb);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+/* Given the spec value, return a driver value. */
+static const int phy_func_table[] = {
+ [PHY_FUNC_NOP] = PHY_NO_OP,
+ [PHY_FUNC_LINK_RESET] = ENABLE_PHY,
+ [PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET,
+ [PHY_FUNC_DISABLE] = DISABLE_PHY,
+ [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD,
+};
+
+int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg)
+{
+ struct asd_ha_struct *asd_ha = phy->ha->lldd_ha;
+ struct asd_phy_desc *pd = asd_ha->phys[phy->id].phy_desc;
+ struct asd_ascb *ascb;
+ struct sas_phy_linkrates *rates;
+ int res = 1;
+
+ switch (func) {
+ case PHY_FUNC_CLEAR_ERROR_LOG:
+ return -ENOSYS;
+ case PHY_FUNC_SET_LINK_RATE:
+ rates = arg;
+ if (rates->minimum_linkrate) {
+ pd->min_sas_lrate = rates->minimum_linkrate;
+ pd->min_sata_lrate = rates->minimum_linkrate;
+ }
+ if (rates->maximum_linkrate) {
+ pd->max_sas_lrate = rates->maximum_linkrate;
+ pd->max_sata_lrate = rates->maximum_linkrate;
+ }
+ func = PHY_FUNC_LINK_RESET;
+ break;
+ default:
+ break;
+ }
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+
+ asd_build_control_phy(ascb, phy->id, phy_func_table[func]);
+ res = asd_post_ascb_list(asd_ha, ascb , 1);
+ if (res)
+ asd_ascb_free(ascb);
+
+ return res;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
new file mode 100644
index 00000000000..83574b5b4e6
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -0,0 +1,1089 @@
+/*
+ * Aic94xx SAS/SATA driver access to shared data structures and memory
+ * maps.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+
+/* ---------- OCM stuff ---------- */
+
+struct asd_ocm_dir_ent {
+ u8 type;
+ u8 offs[3];
+ u8 _r1;
+ u8 size[3];
+} __attribute__ ((packed));
+
+struct asd_ocm_dir {
+ char sig[2];
+ u8 _r1[2];
+ u8 major; /* 0 */
+ u8 minor; /* 0 */
+ u8 _r2;
+ u8 num_de;
+ struct asd_ocm_dir_ent entry[15];
+} __attribute__ ((packed));
+
+#define OCM_DE_OCM_DIR 0x00
+#define OCM_DE_WIN_DRVR 0x01
+#define OCM_DE_BIOS_CHIM 0x02
+#define OCM_DE_RAID_ENGN 0x03
+#define OCM_DE_BIOS_INTL 0x04
+#define OCM_DE_BIOS_CHIM_OSM 0x05
+#define OCM_DE_BIOS_CHIM_DYNAMIC 0x06
+#define OCM_DE_ADDC2C_RES0 0x07
+#define OCM_DE_ADDC2C_RES1 0x08
+#define OCM_DE_ADDC2C_RES2 0x09
+#define OCM_DE_ADDC2C_RES3 0x0A
+
+#define OCM_INIT_DIR_ENTRIES 5
+/***************************************************************************
+* OCM dircetory default
+***************************************************************************/
+static struct asd_ocm_dir OCMDirInit =
+{
+ .sig = {0x4D, 0x4F}, /* signature */
+ .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */
+};
+
+/***************************************************************************
+* OCM dircetory Entries default
+***************************************************************************/
+static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
+{
+ {
+ .type = (OCM_DE_ADDC2C_RES0), /* Entry type */
+ .offs = {128}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES1), /* Entry type */
+ .offs = {128, 4}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES2), /* Entry type */
+ .offs = {128, 8}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES3), /* Entry type */
+ .offs = {128, 12}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_WIN_DRVR), /* Entry type */
+ .offs = {128, 16}, /* Offset */
+ .size = {128, 235, 1}, /* size */
+ },
+};
+
+struct asd_bios_chim_struct {
+ char sig[4];
+ u8 major; /* 1 */
+ u8 minor; /* 0 */
+ u8 bios_major;
+ u8 bios_minor;
+ __le32 bios_build;
+ u8 flags;
+ u8 pci_slot;
+ __le16 ue_num;
+ __le16 ue_size;
+ u8 _r[14];
+ /* The unit element array is right here.
+ */
+} __attribute__ ((packed));
+
+/**
+ * asd_read_ocm_seg - read an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to write the read data
+ * @offs: offset into OCM where to read from
+ * @size: how many bytes to read
+ *
+ * Return the number of bytes not read. Return 0 on success.
+ */
+static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+ u32 offs, int size)
+{
+ u8 *p = buffer;
+ if (unlikely(asd_ha->iospace))
+ asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+ else {
+ for ( ; size > 0; size--, offs++, p++)
+ *p = asd_read_ocm_byte(asd_ha, offs);
+ }
+ return size;
+}
+
+static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
+ struct asd_ocm_dir *dir, u32 offs)
+{
+ int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
+ if (err) {
+ ASD_DPRINTK("couldn't read ocm segment\n");
+ return err;
+ }
+
+ if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
+ ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
+ dir->sig[0], dir->sig[1]);
+ return -ENOENT;
+ }
+ if (dir->major != 0) {
+ asd_printk("unsupported major version of ocm dir:0x%x\n",
+ dir->major);
+ return -ENOENT;
+ }
+ dir->num_de &= 0xf;
+ return 0;
+}
+
+/**
+ * asd_write_ocm_seg - write an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to read the write data
+ * @offs: offset into OCM to write to
+ * @size: how many bytes to write
+ *
+ * Return the number of bytes not written. Return 0 on success.
+ */
+static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+ u32 offs, int size)
+{
+ u8 *p = buffer;
+ if (unlikely(asd_ha->iospace))
+ asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+ else {
+ for ( ; size > 0; size--, offs++, p++)
+ asd_write_ocm_byte(asd_ha, offs, *p);
+ }
+ return;
+}
+
+#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
+
+static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
+ u32 *offs, u32 *size)
+{
+ int i;
+ struct asd_ocm_dir_ent *ent;
+
+ for (i = 0; i < dir->num_de; i++) {
+ if (dir->entry[i].type == type)
+ break;
+ }
+ if (i >= dir->num_de)
+ return -ENOENT;
+ ent = &dir->entry[i];
+ *offs = (u32) THREE_TO_NUM(ent->offs);
+ *size = (u32) THREE_TO_NUM(ent->size);
+ return 0;
+}
+
+#define OCM_BIOS_CHIM_DE 2
+#define BC_BIOS_PRESENT 1
+
+static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
+ struct asd_ocm_dir *dir)
+{
+ int err;
+ struct asd_bios_chim_struct *bc_struct;
+ u32 offs, size;
+
+ err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
+ goto out;
+ }
+ err = -ENOMEM;
+ bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
+ if (!bc_struct) {
+ asd_printk("no memory for bios_chim struct\n");
+ goto out;
+ }
+ err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
+ sizeof(*bc_struct));
+ if (err) {
+ ASD_DPRINTK("couldn't read ocm segment\n");
+ goto out2;
+ }
+ if (strncmp(bc_struct->sig, "SOIB", 4)
+ && strncmp(bc_struct->sig, "IPSA", 4)) {
+ ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
+ bc_struct->sig[0], bc_struct->sig[1],
+ bc_struct->sig[2], bc_struct->sig[3]);
+ err = -ENOENT;
+ goto out2;
+ }
+ if (bc_struct->major != 1) {
+ asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
+ bc_struct->major);
+ err = -ENOENT;
+ goto out2;
+ }
+ if (bc_struct->flags & BC_BIOS_PRESENT) {
+ asd_ha->hw_prof.bios.present = 1;
+ asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
+ asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
+ asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
+ ASD_DPRINTK("BIOS present (%d,%d), %d\n",
+ asd_ha->hw_prof.bios.maj,
+ asd_ha->hw_prof.bios.min,
+ asd_ha->hw_prof.bios.bld);
+ }
+ asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
+ asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
+ ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
+ asd_ha->hw_prof.ue.size);
+ size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
+ if (size > 0) {
+ err = -ENOMEM;
+ asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ue.area)
+ goto out2;
+ err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
+ offs + sizeof(*bc_struct), size);
+ if (err) {
+ kfree(asd_ha->hw_prof.ue.area);
+ asd_ha->hw_prof.ue.area = NULL;
+ asd_ha->hw_prof.ue.num = 0;
+ asd_ha->hw_prof.ue.size = 0;
+ ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
+ }
+ }
+out2:
+ kfree(bc_struct);
+out:
+ return err;
+}
+
+static void
+asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ /* Zero OCM */
+ for (i = 0; i < OCM_MAX_SIZE; i += 4)
+ asd_write_ocm_dword(asd_ha, i, 0);
+
+ /* Write Dir */
+ asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
+ sizeof(struct asd_ocm_dir));
+
+ /* Write Dir Entries */
+ for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
+ asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
+ sizeof(struct asd_ocm_dir) +
+ (i * sizeof(struct asd_ocm_dir_ent))
+ , sizeof(struct asd_ocm_dir_ent));
+
+}
+
+static int
+asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
+{
+ struct pci_dev *pcidev = asd_ha->pcidev;
+ u32 reg;
+ int err = 0;
+ u32 v;
+
+ /* check if OCM has been initialized by BIOS */
+ reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
+
+ if (!(reg & OCMINITIALIZED)) {
+ err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
+ if (err) {
+ asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
+ pci_name(pcidev));
+ goto out;
+ }
+
+ printk(KERN_INFO "OCM is not initialized by BIOS,"
+ "reinitialize it and ignore it, current IntrptStatus"
+ "is 0x%x\n", v);
+
+ if (v)
+ err = pci_write_config_dword(pcidev,
+ PCIC_INTRPT_STAT, v);
+ if (err) {
+ asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
+ pci_name(pcidev));
+ goto out;
+ }
+
+ asd_hwi_initialize_ocm_dir(asd_ha);
+
+ }
+out:
+ return err;
+}
+
+/**
+ * asd_read_ocm - read on chip memory (OCM)
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_ocm(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ struct asd_ocm_dir *dir;
+
+ if (asd_hwi_check_ocm_access(asd_ha))
+ return -1;
+
+ dir = kmalloc(sizeof(*dir), GFP_KERNEL);
+ if (!dir) {
+ asd_printk("no memory for ocm dir\n");
+ return -ENOMEM;
+ }
+
+ err = asd_read_ocm_dir(asd_ha, dir, 0);
+ if (err)
+ goto out;
+
+ err = asd_get_bios_chim(asd_ha, dir);
+out:
+ kfree(dir);
+ return err;
+}
+
+/* ---------- FLASH stuff ---------- */
+
+#define FLASH_RESET 0xF0
+
+#define FLASH_SIZE 0x200000
+#define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** "
+#define FLASH_NEXT_ENTRY_OFFS 0x2000
+#define FLASH_MAX_DIR_ENTRIES 32
+
+#define FLASH_DE_TYPE_MASK 0x3FFFFFFF
+#define FLASH_DE_MS 0x120
+#define FLASH_DE_CTRL_A_USER 0xE0
+
+struct asd_flash_de {
+ __le32 type;
+ __le32 offs;
+ __le32 pad_size;
+ __le32 image_size;
+ __le32 chksum;
+ u8 _r[12];
+ u8 version[32];
+} __attribute__ ((packed));
+
+struct asd_flash_dir {
+ u8 cookie[32];
+ __le32 rev; /* 2 */
+ __le32 chksum;
+ __le32 chksum_antidote;
+ __le32 bld;
+ u8 bld_id[32]; /* build id data */
+ u8 ver_data[32]; /* date and time of build */
+ __le32 ae_mask;
+ __le32 v_mask;
+ __le32 oc_mask;
+ u8 _r[20];
+ struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
+} __attribute__ ((packed));
+
+struct asd_manuf_sec {
+ char sig[2]; /* 'S', 'M' */
+ u16 offs_next;
+ u8 maj; /* 0 */
+ u8 min; /* 0 */
+ u16 chksum;
+ u16 size;
+ u8 _r[6];
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 pcba_sn[ASD_PCBA_SN_SIZE];
+ /* Here start the other segments */
+ u8 linked_list[0];
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_desc {
+ u8 state; /* low 4 bits */
+#define MS_PHY_STATE_ENABLEABLE 0
+#define MS_PHY_STATE_REPORTED 1
+#define MS_PHY_STATE_HIDDEN 2
+ u8 phy_id;
+ u16 _r;
+ u8 phy_control_0; /* mode 5 reg 0x160 */
+ u8 phy_control_1; /* mode 5 reg 0x161 */
+ u8 phy_control_2; /* mode 5 reg 0x162 */
+ u8 phy_control_3; /* mode 5 reg 0x163 */
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_param {
+ char sig[2]; /* 'P', 'M' */
+ u16 next;
+ u8 maj; /* 0 */
+ u8 min; /* 2 */
+ u8 num_phy_desc; /* 8 */
+ u8 phy_desc_size; /* 8 */
+ u8 _r[3];
+ u8 usage_model_id;
+ u32 _r2;
+ struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_sb_type[] = {
+ "unknown",
+ "SGPIO",
+ [2 ... 0x7F] = "unknown",
+ [0x80] = "ADPT_I2C",
+ [0x81 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+#endif
+
+struct asd_ms_sb_desc {
+ u8 type;
+ u8 node_desc_index;
+ u8 conn_desc_index;
+ u8 _recvd[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_conn_type[] = {
+ [0 ... 7] = "unknown",
+ "SFF8470",
+ "SFF8482",
+ "SFF8484",
+ [0x80] = "PCIX_DAUGHTER0",
+ [0x81] = "SAS_DAUGHTER0",
+ [0x82 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+
+static const char *asd_conn_location[] = {
+ "unknown",
+ "internal",
+ "external",
+ "board_to_board",
+};
+#endif
+
+struct asd_ms_conn_desc {
+ u8 type;
+ u8 location;
+ u8 num_sideband_desc;
+ u8 size_sideband_desc;
+ u32 _resvd;
+ u8 name[16];
+ struct asd_ms_sb_desc sb_desc[0];
+} __attribute__ ((packed));
+
+struct asd_nd_phy_desc {
+ u8 vp_attch_type;
+ u8 attch_specific[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_node_type[] = {
+ "IOP",
+ "IO_CONTROLLER",
+ "EXPANDER",
+ "PORT_MULTIPLIER",
+ "PORT_MULTIPLEXER",
+ "MULTI_DROP_I2C_BUS",
+};
+#endif
+
+struct asd_ms_node_desc {
+ u8 type;
+ u8 num_phy_desc;
+ u8 size_phy_desc;
+ u8 _resvd;
+ u8 name[16];
+ struct asd_nd_phy_desc phy_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ms_conn_map {
+ char sig[2]; /* 'M', 'C' */
+ __le16 next;
+ u8 maj; /* 0 */
+ u8 min; /* 0 */
+ __le16 cm_size; /* size of this struct */
+ u8 num_conn;
+ u8 conn_size;
+ u8 num_nodes;
+ u8 usage_model_id;
+ u32 _resvd;
+ struct asd_ms_conn_desc conn_desc[0];
+ struct asd_ms_node_desc node_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_entry {
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 sas_link_rates; /* max in hi bits, min in low bits */
+ u8 flags;
+ u8 sata_link_rates;
+ u8 _r[5];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_settings {
+ u8 id0; /* P'h'y */
+ u8 _r;
+ u16 next;
+ u8 num_phys; /* number of PHYs in the PCI function */
+ u8 _r2[3];
+ struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+struct asd_ll_el {
+ u8 id0;
+ u8 id1;
+ __le16 next;
+ u8 something_here[0];
+} __attribute__ ((packed));
+
+static int asd_poll_flash(struct asd_ha_struct *asd_ha)
+{
+ int c;
+ u8 d;
+
+ for (c = 5000; c > 0; c--) {
+ d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+ d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+ if (!d)
+ return 0;
+ udelay(5);
+ }
+ return -ENOENT;
+}
+
+static int asd_reset_flash(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_poll_flash(asd_ha);
+ if (err)
+ return err;
+ asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
+ err = asd_poll_flash(asd_ha);
+
+ return err;
+}
+
+static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
+ void *buffer, u32 offs, int size)
+{
+ asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
+ size);
+ return 0;
+}
+
+/**
+ * asd_find_flash_dir - finds and reads the flash directory
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to flash directory structure
+ *
+ * If found, the flash directory segment will be copied to
+ * @flash_dir. Return 1 if found, 0 if not.
+ */
+static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ u32 v;
+ for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
+ asd_read_flash_seg(asd_ha, flash_dir, v,
+ sizeof(FLASH_DIR_COOKIE)-1);
+ if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
+ sizeof(FLASH_DIR_COOKIE)-1) == 0) {
+ asd_ha->hw_prof.flash.dir_offs = v;
+ asd_read_flash_seg(asd_ha, flash_dir, v,
+ sizeof(*flash_dir));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int asd_flash_getid(struct asd_ha_struct *asd_ha)
+{
+ int err = 0;
+ u32 reg;
+
+ 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",
+ pci_name(asd_ha->pcidev));
+ return -ENOENT;
+ }
+ asd_ha->hw_prof.flash.present = 1;
+ asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
+ err = asd_reset_flash(asd_ha);
+ if (err) {
+ ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static u16 asd_calc_flash_chksum(u16 *p, int size)
+{
+ u16 chksum = 0;
+
+ while (size-- > 0)
+ chksum += *p++;
+
+ return chksum;
+}
+
+
+static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
+ u32 *offs, u32 *size)
+{
+ int i;
+ struct asd_flash_de *de;
+
+ for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
+ u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
+
+ type &= FLASH_DE_TYPE_MASK;
+ if (type == entry_type)
+ break;
+ }
+ if (i >= FLASH_MAX_DIR_ENTRIES)
+ return -ENOENT;
+ de = &flash_dir->dir_entry[i];
+ *offs = le32_to_cpu(de->offs);
+ *size = le32_to_cpu(de->pad_size);
+ return 0;
+}
+
+static int asd_validate_ms(struct asd_manuf_sec *ms)
+{
+ if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
+ ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
+ ms->sig[0], ms->sig[1]);
+ return -ENOENT;
+ }
+ if (ms->maj != 0) {
+ asd_printk("unsupported manuf. sector. major version:%x\n",
+ ms->maj);
+ return -ENOENT;
+ }
+ ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
+ ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
+ ms->size = le16_to_cpu((__force __le16) ms->size);
+
+ if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
+ asd_printk("failed manuf sector checksum\n");
+ }
+
+ return 0;
+}
+
+static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *ms)
+{
+ memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
+ return 0;
+}
+
+static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *ms)
+{
+ memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
+ asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
+ return 0;
+}
+
+/**
+ * asd_find_ll_by_id - find a linked list entry by its id
+ * @start: void pointer to the first element in the linked list
+ * @id0: the first byte of the id (offs 0)
+ * @id1: the second byte of the id (offs 1)
+ *
+ * @start has to be the _base_ element start, since the
+ * linked list entries's offset is from this pointer.
+ * Some linked list entries use only the first id, in which case
+ * you can pass 0xFF for the second.
+ */
+static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
+{
+ struct asd_ll_el *el = start;
+
+ do {
+ switch (id1) {
+ default:
+ if (el->id1 == id1)
+ case 0xFF:
+ if (el->id0 == id0)
+ return el;
+ }
+ el = start + le16_to_cpu(el->next);
+ } while (el != start);
+
+ return NULL;
+}
+
+/**
+ * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @manuf_sec: pointer to the manufacturing sector
+ *
+ * The manufacturing sector contans also the linked list of sub-segments,
+ * since when it was read, its size was taken from the flash directory,
+ * not from the structure size.
+ *
+ * HIDDEN phys do not count in the total count. REPORTED phys cannot
+ * be enabled but are reported and counted towards the total.
+ * ENEBLEABLE phys are enabled by default and count towards the total.
+ * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys
+ * merely specifies the number of phys the host adapter decided to
+ * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
+ * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE.
+ * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
+ * are actually enabled (enabled by default, max number of phys
+ * enableable in this case).
+ */
+static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *manuf_sec)
+{
+ int i;
+ int en_phys = 0;
+ int rep_phys = 0;
+ struct asd_manuf_phy_param *phy_param;
+ struct asd_manuf_phy_param dflt_phy_param;
+
+ phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
+ if (!phy_param) {
+ ASD_DPRINTK("ms: no phy parameters found\n");
+ ASD_DPRINTK("ms: Creating default phy parameters\n");
+ dflt_phy_param.sig[0] = 'P';
+ dflt_phy_param.sig[1] = 'M';
+ dflt_phy_param.maj = 0;
+ dflt_phy_param.min = 2;
+ dflt_phy_param.num_phy_desc = 8;
+ dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
+ for (i =0; i < ASD_MAX_PHYS; i++) {
+ dflt_phy_param.phy_desc[i].state = 0;
+ dflt_phy_param.phy_desc[i].phy_id = i;
+ dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
+ dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
+ dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
+ dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
+ }
+
+ phy_param = &dflt_phy_param;
+
+ }
+
+ if (phy_param->maj != 0) {
+ asd_printk("unsupported manuf. phy param major version:0x%x\n",
+ phy_param->maj);
+ return -ENOENT;
+ }
+
+ ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
+ asd_ha->hw_prof.enabled_phys = 0;
+ for (i = 0; i < phy_param->num_phy_desc; i++) {
+ struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
+ switch (pd->state & 0xF) {
+ case MS_PHY_STATE_HIDDEN:
+ ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
+ continue;
+ case MS_PHY_STATE_REPORTED:
+ ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
+ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+ rep_phys++;
+ continue;
+ case MS_PHY_STATE_ENABLEABLE:
+ ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i);
+ asd_ha->hw_prof.enabled_phys |= (1 << i);
+ en_phys++;
+ break;
+ }
+ asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
+ asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
+ asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
+ asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
+ }
+ asd_ha->hw_prof.max_phys = rep_phys + en_phys;
+ asd_ha->hw_prof.num_phys = en_phys;
+ ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
+ asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
+ ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
+ return 0;
+}
+
+static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *manuf_sec)
+{
+ struct asd_ms_conn_map *cm;
+
+ cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
+ if (!cm) {
+ ASD_DPRINTK("ms: no connector map found\n");
+ return 0;
+ }
+
+ if (cm->maj != 0) {
+ ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
+ "\n", cm->maj);
+ return -ENOENT;
+ }
+
+ /* XXX */
+
+ return 0;
+}
+
+
+/**
+ * asd_process_ms - find and extract information from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ms(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ int err;
+ struct asd_manuf_sec *manuf_sec;
+ u32 offs, size;
+
+ err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("Couldn't find the manuf. sector\n");
+ goto out;
+ }
+
+ if (size == 0)
+ goto out;
+
+ err = -ENOMEM;
+ manuf_sec = kmalloc(size, GFP_KERNEL);
+ if (!manuf_sec) {
+ ASD_DPRINTK("no mem for manuf sector\n");
+ goto out;
+ }
+
+ err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
+ if (err) {
+ ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
+ offs, size);
+ goto out2;
+ }
+
+ err = asd_validate_ms(manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't validate manuf sector\n");
+ goto out2;
+ }
+
+ err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't read the SAS_ADDR\n");
+ goto out2;
+ }
+ ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
+ SAS_ADDR(asd_ha->hw_prof.sas_addr));
+
+ err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't read the PCBA SN\n");
+ goto out2;
+ }
+ ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
+
+ err = asd_ms_get_phy_params(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("ms: couldn't get phy parameters\n");
+ goto out2;
+ }
+
+ err = asd_ms_get_connector_map(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("ms: couldn't get connector map\n");
+ goto out2;
+ }
+
+out2:
+ kfree(manuf_sec);
+out:
+ return err;
+}
+
+static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
+ struct asd_ctrla_phy_settings *ps)
+{
+ int i;
+ for (i = 0; i < ps->num_phys; i++) {
+ struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
+
+ if (!PHY_ENABLED(asd_ha, i))
+ continue;
+ if (*(u64 *)pe->sas_addr == 0) {
+ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+ continue;
+ }
+ /* This is the SAS address which should be sent in IDENTIFY. */
+ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
+ SAS_ADDR_SIZE);
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
+ (pe->sas_link_rates & 0xF0) >> 4;
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
+ (pe->sas_link_rates & 0x0F);
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
+ (pe->sata_link_rates & 0xF0) >> 4;
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
+ (pe->sata_link_rates & 0x0F);
+ asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
+ ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
+ " sata rate:0x%x-0x%x, flags:0x%x\n",
+ i,
+ SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
+ asd_ha->hw_prof.phy_desc[i].flags);
+ }
+
+ return 0;
+}
+
+/**
+ * asd_process_ctrl_a_user - process CTRL-A user settings
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ int err, i;
+ u32 offs, size;
+ struct asd_ll_el *el;
+ struct asd_ctrla_phy_settings *ps;
+ struct asd_ctrla_phy_settings dflt_ps;
+
+ err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
+ ASD_DPRINTK("Creating default CTRL-A user settings section\n");
+
+ dflt_ps.id0 = 'h';
+ dflt_ps.num_phys = 8;
+ for (i =0; i < ASD_MAX_PHYS; i++) {
+ memcpy(dflt_ps.phy_ent[i].sas_addr,
+ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+ dflt_ps.phy_ent[i].sas_link_rates = 0x98;
+ dflt_ps.phy_ent[i].flags = 0x0;
+ dflt_ps.phy_ent[i].sata_link_rates = 0x0;
+ }
+
+ size = sizeof(struct asd_ctrla_phy_settings);
+ ps = &dflt_ps;
+ }
+
+ if (size == 0)
+ goto out;
+
+ err = -ENOMEM;
+ el = kmalloc(size, GFP_KERNEL);
+ if (!el) {
+ ASD_DPRINTK("no mem for ctrla user settings section\n");
+ goto out;
+ }
+
+ err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
+ if (err) {
+ ASD_DPRINTK("couldn't read ctrla phy settings section\n");
+ goto out2;
+ }
+
+ err = -ENOENT;
+ ps = asd_find_ll_by_id(el, 'h', 0xFF);
+ if (!ps) {
+ ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
+ goto out2;
+ }
+
+ err = asd_process_ctrla_phy_settings(asd_ha, ps);
+ if (err) {
+ ASD_DPRINTK("couldn't process ctrla phy settings\n");
+ goto out2;
+ }
+out2:
+ kfree(el);
+out:
+ return err;
+}
+
+/**
+ * asd_read_flash - read flash memory
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_flash(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ struct asd_flash_dir *flash_dir;
+
+ err = asd_flash_getid(asd_ha);
+ if (err)
+ return err;
+
+ flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
+ if (!flash_dir)
+ return -ENOMEM;
+
+ err = -ENOENT;
+ if (!asd_find_flash_dir(asd_ha, flash_dir)) {
+ ASD_DPRINTK("couldn't find flash directory\n");
+ goto out;
+ }
+
+ if (le32_to_cpu(flash_dir->rev) != 2) {
+ asd_printk("unsupported flash dir version:0x%x\n",
+ le32_to_cpu(flash_dir->rev));
+ goto out;
+ }
+
+ err = asd_process_ms(asd_ha, flash_dir);
+ if (err) {
+ ASD_DPRINTK("couldn't process manuf sector settings\n");
+ goto out;
+ }
+
+ err = asd_process_ctrl_a_user(asd_ha, flash_dir);
+ if (err) {
+ ASD_DPRINTK("couldn't process CTRL-A user settings\n");
+ goto out;
+ }
+
+out:
+ kfree(flash_dir);
+ return err;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
new file mode 100644
index 00000000000..56e4b3ba6a0
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -0,0 +1,1404 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Parts of this code adapted from David Chaw's adp94xx_seq.c.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+/* It takes no more than 0.05 us for an instruction
+ * to complete. So waiting for 1 us should be more than
+ * plenty.
+ */
+#define PAUSE_DELAY 1
+#define PAUSE_TRIES 1000
+
+static const struct firmware *sequencer_fw;
+static const char *sequencer_version;
+static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task,
+ cseq_idle_loop, lseq_idle_loop;
+static u8 *cseq_code, *lseq_code;
+static u32 cseq_code_size, lseq_code_size;
+
+static u16 first_scb_site_no = 0xFFFF;
+static u16 last_scb_site_no;
+
+/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */
+
+/**
+ * asd_pause_cseq - pause the central sequencer
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_cseq(struct asd_ha_struct *asd_ha)
+{
+ int count = PAUSE_TRIES;
+ u32 arp2ctl;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (arp2ctl & PAUSED)
+ return 0;
+
+ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (arp2ctl & PAUSED)
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't pause CSEQ\n");
+ return -1;
+}
+
+/**
+ * asd_unpause_cseq - unpause the central sequencer.
+ * @asd_ha: pointer to host adapter structure.
+ *
+ * Return 0 on success, negative on error.
+ */
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (!(arp2ctl & PAUSED))
+ return 0;
+
+ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (!(arp2ctl & PAUSED))
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't unpause the CSEQ\n");
+ return -1;
+}
+
+/**
+ * asd_seq_pause_lseq - pause a link sequencer
+ * @asd_ha: pointer to a host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (arp2ctl & PAUSED)
+ return 0;
+
+ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (arp2ctl & PAUSED)
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq);
+ return -1;
+}
+
+/**
+ * asd_pause_lseq - pause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+ int err = 0;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_pause_lseq(asd_ha, lseq);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/**
+ * asd_seq_unpause_lseq - unpause a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (!(arp2ctl & PAUSED))
+ return 0;
+
+ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (!(arp2ctl & PAUSED))
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq);
+ return 0;
+}
+
+
+/**
+ * asd_unpause_lseq - unpause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+ int err = 0;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_unpause_lseq(asd_ha, lseq);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/* ---------- Downloading CSEQ/LSEQ microcode ---------- */
+
+static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size)
+{
+ u32 addr = CSEQ_RAM_REG_BASE_ADR;
+ const u32 *prog = (u32 *) _prog;
+ u32 i;
+
+ for (i = 0; i < size; i += 4, prog++, addr += 4) {
+ u32 val = asd_read_reg_dword(asd_ha, addr);
+
+ if (le32_to_cpu(*prog) != val) {
+ asd_printk("%s: cseq verify failed at %u "
+ "read:0x%x, wanted:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ i, val, le32_to_cpu(*prog));
+ return -1;
+ }
+ }
+ ASD_DPRINTK("verified %d bytes, passed\n", size);
+ return 0;
+}
+
+/**
+ * asd_verify_lseq - verify the microcode of a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @_prog: pointer to the microcode
+ * @size: size of the microcode in bytes
+ * @lseq: link sequencer of interest
+ *
+ * The link sequencer code is accessed in 4 KB pages, which are selected
+ * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register.
+ * The 10 KB LSEQm instruction code is mapped, page at a time, at
+ * LmSEQRAM address.
+ */
+static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size, int lseq)
+{
+#define LSEQ_CODEPAGE_SIZE 4096
+ int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE;
+ u32 page;
+ const u32 *prog = (u32 *) _prog;
+
+ for (page = 0; page < pages; page++) {
+ u32 i;
+
+ asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq),
+ page << LmRAMPAGE_LSHIFT);
+ for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE;
+ i += 4, prog++, size-=4) {
+
+ u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i);
+
+ if (le32_to_cpu(*prog) != val) {
+ asd_printk("%s: LSEQ%d verify failed "
+ "page:%d, offs:%d\n",
+ pci_name(asd_ha->pcidev),
+ lseq, page, i);
+ return -1;
+ }
+ }
+ }
+ ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq,
+ (int)((u8 *)prog-_prog));
+ return 0;
+}
+
+/**
+ * asd_verify_seq -- verify CSEQ/LSEQ microcode
+ * @asd_ha: pointer to host adapter structure
+ * @prog: pointer to microcode
+ * @size: size of the microcode
+ * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest
+ *
+ * Return 0 if microcode is correct, negative on mismatch.
+ */
+static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog,
+ u32 size, u8 lseq_mask)
+{
+ if (lseq_mask == 0)
+ return asd_verify_cseq(asd_ha, prog, size);
+ else {
+ int lseq, err;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_verify_lseq(asd_ha, prog, size, lseq);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+#define ASD_DMA_MODE_DOWNLOAD
+#ifdef ASD_DMA_MODE_DOWNLOAD
+/* This is the size of the CSEQ Mapped instruction page */
+#define MAX_DMA_OVLY_COUNT ((1U << 14)-1)
+static int asd_download_seq(struct asd_ha_struct *asd_ha,
+ const u8 * const prog, u32 size, u8 lseq_mask)
+{
+ u32 comstaten;
+ u32 reg;
+ int page;
+ const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT;
+ struct asd_dma_tok *token;
+ int err = 0;
+
+ if (size % 4) {
+ asd_printk("sequencer program not multiple of 4\n");
+ return -1;
+ }
+
+ asd_pause_cseq(asd_ha);
+ asd_pause_lseq(asd_ha, 0xFF);
+
+ /* save, disable and clear interrupts */
+ comstaten = asd_read_reg_dword(asd_ha, COMSTATEN);
+ asd_write_reg_dword(asd_ha, COMSTATEN, 0);
+ asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK);
+
+ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+ asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK);
+
+ token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL);
+ if (!token) {
+ asd_printk("out of memory for dma SEQ download\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ ASD_DPRINTK("dma-ing %d bytes\n", size);
+
+ for (page = 0; page < pages; page++) {
+ int i;
+ u32 left = min(size-page*MAX_DMA_OVLY_COUNT,
+ (u32)MAX_DMA_OVLY_COUNT);
+
+ memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left);
+ asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle);
+ asd_write_reg_dword(asd_ha, OVLYDMACNT, left);
+ reg = !page ? RESETOVLYDMA : 0;
+ reg |= (STARTOVLYDMA | OVLYHALTERR);
+ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+ /* Start DMA. */
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ for (i = PAUSE_TRIES*100; i > 0; i--) {
+ u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL);
+ if (!(dmadone & OVLYDMAACT))
+ break;
+ udelay(PAUSE_DELAY);
+ }
+ }
+
+ reg = asd_read_reg_dword(asd_ha, COMSTAT);
+ if (!(reg & OVLYDMADONE) || (reg & OVLYERR)
+ || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){
+ asd_printk("%s: error DMA-ing sequencer code\n",
+ pci_name(asd_ha->pcidev));
+ err = -ENODEV;
+ }
+
+ asd_free_coherent(asd_ha, token);
+ out:
+ asd_write_reg_dword(asd_ha, COMSTATEN, comstaten);
+
+ return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask);
+}
+#else /* ASD_DMA_MODE_DOWNLOAD */
+static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size, u8 lseq_mask)
+{
+ int i;
+ u32 reg = 0;
+ const u32 *prog = (u32 *) _prog;
+
+ if (size % 4) {
+ asd_printk("sequencer program not multiple of 4\n");
+ return -1;
+ }
+
+ asd_pause_cseq(asd_ha);
+ asd_pause_lseq(asd_ha, 0xFF);
+
+ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+ reg |= PIOCMODE;
+
+ asd_write_reg_dword(asd_ha, OVLYDMACNT, size);
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n",
+ lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : "");
+
+ for (i = 0; i < size; i += 4, prog++)
+ asd_write_reg_dword(asd_ha, SPIODATA, *prog);
+
+ reg = (reg & ~PIOCMODE) | OVLYHALTERR;
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ return asd_verify_seq(asd_ha, _prog, size, lseq_mask);
+}
+#endif /* ASD_DMA_MODE_DOWNLOAD */
+
+/**
+ * asd_seq_download_seqs - download the sequencer microcode
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Download the central and link sequencer microcode.
+ */
+static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ if (!asd_ha->hw_prof.enabled_phys) {
+ asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev));
+ return -ENODEV;
+ }
+
+ /* Download the CSEQ */
+ ASD_DPRINTK("downloading CSEQ...\n");
+ err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0);
+ if (err) {
+ asd_printk("CSEQ download failed:%d\n", err);
+ return err;
+ }
+
+ /* Download the Link Sequencers code. All of the Link Sequencers
+ * microcode can be downloaded at the same time.
+ */
+ ASD_DPRINTK("downloading LSEQs...\n");
+ err = asd_download_seq(asd_ha, lseq_code, lseq_code_size,
+ asd_ha->hw_prof.enabled_phys);
+ if (err) {
+ /* Try it one at a time */
+ u8 lseq;
+ u8 lseq_mask = asd_ha->hw_prof.enabled_phys;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_download_seq(asd_ha, lseq_code,
+ lseq_code_size, 1<<lseq);
+ if (err)
+ break;
+ }
+ }
+ if (err)
+ asd_printk("LSEQs download failed:%d\n", err);
+
+ return err;
+}
+
+/* ---------- Initializing the chip, chip memory, etc. ---------- */
+
+/**
+ * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha)
+{
+ /* CSEQ Mode Independent, page 4 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_REG0, 0);
+ asd_write_reg_word(asd_ha, CSEQ_REG1, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_REG2, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0);
+ {
+ u8 con = asd_read_reg_byte(asd_ha, CCONEXIST);
+ u8 val = hweight8(con);
+ asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val);
+ }
+ asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0);
+
+ /* CSEQ Mode independent, page 5 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0);
+
+ /* CSEQ Mode independent, page 6 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0);
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0);
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0);
+ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF);
+ /* Calculate the free scb mask. */
+ {
+ u16 cmdctx = asd_get_cmdctx_size(asd_ha);
+ cmdctx = (~((cmdctx/128)-1)) >> 8;
+ asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx);
+ }
+ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD,
+ first_scb_site_no);
+ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL,
+ last_scb_site_no);
+ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF);
+
+ /* CSEQ Mode independent, page 7 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0);
+ asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0);
+}
+
+/**
+ * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ int moffs;
+
+ moffs = CSEQ_PAGE_SIZE * 2;
+
+ /* CSEQ Mode dependent, modes 0-7, page 0 setup. */
+ for (i = 0; i < 8; i++) {
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF);
+ asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0);
+ }
+
+ /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */
+
+ /* CSEQ Mode dependent, mode 8, page 0 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0);
+ asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0);
+ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0);
+ asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0);
+ asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0);
+ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE,
+ (u16)last_scb_site_no+1);
+ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE,
+ (u16)asd_ha->hw_prof.max_ddbs);
+
+ /* CSEQ Mode dependent, mode 8, page 1 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0);
+
+ /* CSEQ Mode dependent, mode 8, page 2 setup. */
+ /* Tell the sequencer the bus address of the first SCB. */
+ asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER,
+ asd_ha->seq.next_scb.dma_handle);
+ ASD_DPRINTK("First SCB dma_handle: 0x%llx\n",
+ (unsigned long long)asd_ha->seq.next_scb.dma_handle);
+
+ /* Tell the sequencer the first Done List entry address. */
+ asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE,
+ asd_ha->seq.actual_dl->dma_handle);
+
+ /* Initialize the Q_DONE_POINTER with the least significant
+ * 4 bytes of the first Done List address. */
+ asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER,
+ ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle));
+
+ asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE);
+
+ /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */
+}
+
+/**
+ * asd_init_cseq_scratch -- setup and init CSEQ
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Setup and initialize Central sequencers. Initialiaze the mode
+ * independent and dependent scratch page to the default settings.
+ */
+static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha)
+{
+ asd_init_cseq_mip(asd_ha);
+ asd_init_cseq_mdp(asd_ha);
+}
+
+/**
+ * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq)
+{
+ int i;
+
+ /* LSEQ Mode independent page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq);
+ asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq),
+ ASD_NOTIFY_ENABLE_SPINUP);
+ asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000);
+ asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0);
+
+ /* LSEQ Mode independent page 1 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0);
+
+ /* LSEQ Mode Independent page 2 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0);
+ for (i = 0; i < 12; i += 4)
+ asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0);
+
+ /* LSEQ Mode Independent page 3 setup. */
+
+ /* Device present timer timeout */
+ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq),
+ ASD_DEV_PRESENT_TIMEOUT);
+
+ /* SATA interlock timer disabled */
+ asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq),
+ ASD_SATA_INTERLOCK_TIMEOUT);
+
+ /* STP shutdown timer timeout constant, IGNORED by the sequencer,
+ * always 0. */
+ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq),
+ ASD_STP_SHUTDOWN_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq),
+ ASD_SRST_ASSERT_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq),
+ ASD_RCV_FIS_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq),
+ ASD_ONE_MILLISEC_TIMEOUT);
+
+ /* COM_INIT timer */
+ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq),
+ ASD_TEN_MILLISEC_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq),
+ ASD_SMP_RCV_TIMEOUT);
+}
+
+/**
+ * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages.
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
+{
+ int i;
+ u32 moffs;
+ u16 ret_addr[] = {
+ 0xFFFF, /* mode 0 */
+ 0xFFFF, /* mode 1 */
+ mode2_task, /* mode 2 */
+ 0,
+ 0xFFFF, /* mode 4/5 */
+ 0xFFFF, /* mode 4/5 */
+ };
+
+ /*
+ * Mode 0,1,2 and 4/5 have common field on page 0 for the first
+ * 14 bytes.
+ */
+ for (i = 0; i < 3; i++) {
+ moffs = i * LSEQ_MODE_SCRATCH_SIZE;
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs,
+ ret_addr[i]);
+ asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0);
+ asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0);
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0);
+ asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0);
+ }
+ /*
+ * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3.
+ */
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET,
+ ret_addr[5]);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+ asd_write_reg_byte(asd_ha,
+ LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+
+ /* LSEQ Mode dependent 0, page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq),
+ (u16)asd_ha->hw_prof.max_ddbs);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq),
+ (u16)last_scb_site_no+1);
+ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq),
+ (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16));
+ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2,
+ (u16) LmM0INTEN_MASK & 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0);
+
+ /* LSEQ mode dependent, mode 1, page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0);
+
+ /* LSEQ Mode dependent mode 2, page 0 setup */
+ asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0);
+
+ /* LSEQ Mode dependent, mode 4/5, page 0 setup. */
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0);
+ /*
+ * Set the desired interval between transmissions of the NOTIFY
+ * (ENABLE SPINUP) primitive. Must be initilized to val - 1.
+ */
+ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq),
+ ASD_NOTIFY_TIMEOUT - 1);
+ /* No delay for the first NOTIFY to be sent to the attached target. */
+ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq),
+ ASD_NOTIFY_DOWN_COUNT);
+
+ /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */
+ for (i = 0; i < 2; i++) {
+ int j;
+ /* Start from Page 1 of Mode 0 and 1. */
+ moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE;
+ /* All the fields of page 1 can be intialized to 0. */
+ for (j = 0; j < LSEQ_PAGE_SIZE; j += 4)
+ asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0);
+ }
+
+ /* LSEQ Mode dependent, mode 2, page 1 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0);
+
+ /* LSEQ Mode dependent, mode 4/5, page 1. */
+ for (i = 0; i < LSEQ_PAGE_SIZE; i+=4)
+ asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF);
+ asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF);
+
+ /* LSEQ Mode dependent, mode 0, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0);
+
+ /* LSEQ Mode Dependent 1, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0);
+
+ /* LSEQ Mode Dependent 2, page 2 setup. */
+ /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer,
+ * i.e. always 0. */
+ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0);
+ asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0);
+ asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0);
+
+ /* LSEQ Mode Dependent 4/5, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0);
+}
+
+/**
+ * asd_init_lseq_scratch -- setup and init link sequencers
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha)
+{
+ u8 lseq;
+ u8 lseq_mask;
+
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ asd_init_lseq_mip(asd_ha, lseq);
+ asd_init_lseq_mdp(asd_ha, lseq);
+ }
+}
+
+/**
+ * asd_init_scb_sites -- initialize sequencer SCB sites (memory).
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This should be done before initializing common CSEQ and LSEQ
+ * scratch since those areas depend on some computed values here,
+ * last_scb_site_no, etc.
+ */
+static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
+{
+ u16 site_no;
+ u16 max_scbs = 0;
+
+ for (site_no = asd_ha->hw_prof.max_scbs-1;
+ site_no != (u16) -1;
+ site_no--) {
+ u16 i;
+
+ /* Initialize all fields in the SCB site to 0. */
+ for (i = 0; i < ASD_SCB_SIZE; i += 4)
+ asd_scbsite_write_dword(asd_ha, site_no, i, 0);
+
+ /* Workaround needed by SEQ to fix a SATA issue is to exclude
+ * certain SCB sites from the free list. */
+ if (!SCB_SITE_VALID(site_no))
+ continue;
+
+ if (last_scb_site_no == 0)
+ last_scb_site_no = site_no;
+
+ /* For every SCB site, we need to initialize the
+ * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS,
+ * and SG Element Flag. */
+
+ /* Q_NEXT field of the last SCB is invalidated. */
+ asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no);
+
+ /* Initialize SCB Site Opcode field to invalid. */
+ asd_scbsite_write_byte(asd_ha, site_no,
+ offsetof(struct scb_header, opcode),
+ 0xFF);
+
+ /* Initialize SCB Site Flags field to mean a response
+ * frame has been received. This means inadvertent
+ * frames received to be dropped. */
+ asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
+
+ first_scb_site_no = site_no;
+ max_scbs++;
+ }
+ asd_ha->hw_prof.max_scbs = max_scbs;
+ ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs);
+ ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no);
+ ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no);
+}
+
+/**
+ * asd_init_cseq_cio - initialize CSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0);
+ asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS);
+ asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0);
+ asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0);
+ asd_ha->seq.scbpro = 0;
+ asd_write_reg_dword(asd_ha, SCBPRO, 0);
+ asd_write_reg_dword(asd_ha, CSEQCON, 0);
+
+ /* Intialize CSEQ Mode 11 Interrupt Vectors.
+ * The addresses are 16 bit wide and in dword units.
+ * The values of their macros are in byte units.
+ * Thus we have to divide by 4. */
+ asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]);
+ asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]);
+ asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]);
+
+ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+ asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC);
+
+ /* Initialize CSEQ Scratch Page to 0x04. */
+ asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04);
+
+ /* Initialize CSEQ Mode[0-8] Dependent registers. */
+ /* Initialize Scratch Page to 0. */
+ for (i = 0; i < 9; i++)
+ asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0);
+
+ /* Reset the ARP2 Program Count. */
+ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
+
+ for (i = 0; i < 8; i++) {
+ /* Intialize Mode n Link m Interrupt Enable. */
+ asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF);
+ /* Initialize Mode n Request Mailbox. */
+ asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0);
+ }
+}
+
+/**
+ * asd_init_lseq_cio -- initialize LmSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u8 *sas_addr;
+ int i;
+
+ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+ asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC);
+
+ asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0);
+
+ /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */
+ for (i = 0; i < 3; i++)
+ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0);
+
+ /* Initialize Mode 5 SCRATCHPAGE to 0. */
+ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0);
+
+ asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0);
+ /* Initialize Mode 0,1,2 and 5 Interrupt Enable and
+ * Interrupt registers. */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF);
+ /* Mode 1 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF);
+ /* Mode 2 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF);
+ /* Mode 5 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF);
+
+ /* Enable HW Timer status. */
+ asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK);
+
+ /* Enable Primitive Status 0 and 1. */
+ asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK);
+ asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK);
+
+ /* Enable Frame Error. */
+ asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK);
+ asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50);
+
+ /* Initialize Mode 0 Transfer Level to 512. */
+ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512);
+ /* Initialize Mode 1 Transfer Level to 256. */
+ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256);
+
+ /* Initialize Program Count. */
+ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
+
+ /* Enable Blind SG Move. */
+ asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48);
+ asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq),
+ ASD_SATA_INTERLOCK_TIMEOUT);
+
+ (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq));
+
+ /* Clear Primitive Status 0 and 1. */
+ asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF);
+ asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF);
+
+ /* Clear HW Timer status. */
+ asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF);
+
+ /* Clear DMA Errors for Mode 0 and 1. */
+ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF);
+ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF);
+
+ /* Clear SG DMA Errors for Mode 0 and 1. */
+ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF);
+ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF);
+
+ /* Clear Mode 0 Buffer Parity Error. */
+ asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR);
+
+ /* Clear Mode 0 Frame Error register. */
+ asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF);
+
+ /* Reset LSEQ external interrupt arbiter. */
+ asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL);
+
+ /* Set the Phy SAS for the LmSEQ WWN. */
+ sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr;
+ for (i = 0; i < SAS_ADDR_SIZE; i++)
+ asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]);
+
+ /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */
+ asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0);
+
+ /* Set the Bus Inactivity Time Limit Timer. */
+ asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9);
+
+ /* Enable SATA Port Multiplier. */
+ asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80);
+
+ /* Initialize Interrupt Vector[0-10] address in Mode 3.
+ * See the comment on CSEQ_INT_* */
+ asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]);
+ /*
+ * Program the Link LED control, applicable only for
+ * Chip Rev. B or later.
+ */
+ asd_write_reg_dword(asd_ha, LmCONTROL(lseq),
+ (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms));
+
+ /* Set the Align Rate for SAS and STP mode. */
+ asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT);
+ asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT);
+}
+
+
+/**
+ * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_post_init_cseq(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF);
+ for (i = 0; i < 8; i++)
+ asd_read_reg_dword(asd_ha, CMnRSPMBX(i));
+ /* Reset the external interrupt arbiter. */
+ asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL);
+}
+
+/**
+ * asd_init_ddb_0 -- initialize DDB 0
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Initialize DDB site 0 which is used internally by the sequencer.
+ */
+static void asd_init_ddb_0(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ /* Zero out the DDB explicitly */
+ for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4)
+ asd_ddbsite_write_dword(asd_ha, 0, i, 0);
+
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail),
+ asd_ha->hw_prof.max_ddbs-1);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh),
+ asd_ha->hw_prof.num_phys * 2);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00);
+ /* DDB 0 is reserved */
+ set_bit(0, asd_ha->hw_prof.ddb_bitmap);
+}
+
+/**
+ * asd_seq_setup_seqs -- setup and initialize central and link sequencers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha)
+{
+ int lseq;
+ u8 lseq_mask;
+
+ /* Initialize SCB sites. Done first to compute some values which
+ * the rest of the init code depends on. */
+ asd_init_scb_sites(asd_ha);
+
+ /* Initialize CSEQ Scratch RAM registers. */
+ asd_init_cseq_scratch(asd_ha);
+
+ /* Initialize LmSEQ Scratch RAM registers. */
+ asd_init_lseq_scratch(asd_ha);
+
+ /* Initialize CSEQ CIO registers. */
+ asd_init_cseq_cio(asd_ha);
+
+ asd_init_ddb_0(asd_ha);
+
+ /* Initialize LmSEQ CIO registers. */
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq)
+ asd_init_lseq_cio(asd_ha, lseq);
+ asd_post_init_cseq(asd_ha);
+}
+
+
+/**
+ * asd_seq_start_cseq -- start the central sequencer, CSEQ
+ * @asd_ha: pointer to host adapter structure
+ */
+static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha)
+{
+ /* Reset the ARP2 instruction to location zero. */
+ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
+
+ /* Unpause the CSEQ */
+ return asd_unpause_cseq(asd_ha);
+}
+
+/**
+ * asd_seq_start_lseq -- start a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: the link sequencer of interest
+ */
+static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ /* Reset the ARP2 instruction to location zero. */
+ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
+
+ /* Unpause the LmSEQ */
+ return asd_seq_unpause_lseq(asd_ha, lseq);
+}
+
+static int asd_request_firmware(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+ struct sequencer_file_header header, *hdr_ptr;
+ u32 csum = 0;
+ u16 *ptr_cseq_vecs, *ptr_lseq_vecs;
+
+ if (sequencer_fw)
+ /* already loaded */
+ return 0;
+
+ err = request_firmware(&sequencer_fw,
+ SAS_RAZOR_SEQUENCER_FW_FILE,
+ &asd_ha->pcidev->dev);
+ if (err)
+ return err;
+
+ hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data;
+
+ header.csum = le32_to_cpu(hdr_ptr->csum);
+ header.major = le32_to_cpu(hdr_ptr->major);
+ header.minor = le32_to_cpu(hdr_ptr->minor);
+ sequencer_version = hdr_ptr->version;
+ header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset);
+ header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size);
+ header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset);
+ header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size);
+ header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset);
+ header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size);
+ header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset);
+ header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size);
+ header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task);
+ header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop);
+ header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop);
+
+ for (i = sizeof(header.csum); i < sequencer_fw->size; i++)
+ csum += sequencer_fw->data[i];
+
+ if (csum != header.csum) {
+ asd_printk("Firmware file checksum mismatch\n");
+ return -EINVAL;
+ }
+
+ if (header.cseq_table_size != CSEQ_NUM_VECS ||
+ header.lseq_table_size != LSEQ_NUM_VECS) {
+ asd_printk("Firmware file table size mismatch\n");
+ return -EINVAL;
+ }
+
+ ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset];
+ ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset];
+ mode2_task = header.mode2_task;
+ cseq_idle_loop = header.cseq_idle_loop;
+ lseq_idle_loop = header.lseq_idle_loop;
+
+ for (i = 0; i < CSEQ_NUM_VECS; i++)
+ cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]);
+
+ for (i = 0; i < LSEQ_NUM_VECS; i++)
+ lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]);
+
+ cseq_code = &sequencer_fw->data[header.cseq_code_offset];
+ cseq_code_size = header.cseq_code_size;
+ lseq_code = &sequencer_fw->data[header.lseq_code_offset];
+ lseq_code_size = header.lseq_code_size;
+
+ return 0;
+}
+
+int asd_init_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_request_firmware(asd_ha);
+
+ if (err) {
+ asd_printk("Failed to load sequencer firmware file %s, error %d\n",
+ SAS_RAZOR_SEQUENCER_FW_FILE, err);
+ return err;
+ }
+
+ asd_printk("using sequencer %s\n", sequencer_version);
+ err = asd_seq_download_seqs(asd_ha);
+ if (err) {
+ asd_printk("couldn't download sequencers for %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ asd_seq_setup_seqs(asd_ha);
+
+ return 0;
+}
+
+int asd_start_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u8 lseq_mask;
+ int lseq;
+
+ err = asd_seq_start_cseq(asd_ha);
+ if (err) {
+ asd_printk("couldn't start CSEQ for %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_start_lseq(asd_ha, lseq);
+ if (err) {
+ asd_printk("coudln't start LSEQ %d for %s\n", lseq,
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * asd_update_port_links -- update port_map_by_links and phy_is_up
+ * @sas_phy: pointer to the phy which has been added to a port
+ *
+ * 1) When a link reset has completed and we got BYTES DMAED with a
+ * valid frame we call this function for that phy, to indicate that
+ * the phy is up, i.e. we update the phy_is_up in DDB 0. The
+ * sequencer checks phy_is_up when pending SCBs are to be sent, and
+ * when an open address frame has been received.
+ *
+ * 2) When we know of ports, we call this function to update the map
+ * of phys participaing in that port, i.e. we update the
+ * port_map_by_links in DDB 0. When a HARD_RESET primitive has been
+ * received, the sequencer disables all phys in that port.
+ * 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)
+{
+ struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
+ const u8 phy_mask = (u8) sas_phy->port->phy_mask;
+ u8 phy_is_up;
+ u8 mask;
+ int i, err;
+
+ for_each_phy(phy_mask, mask, i)
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared,
+ port_map_by_links)+i,phy_mask);
+
+ for (i = 0; i < 12; i++) {
+ phy_is_up = asd_ddbsite_read_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up));
+ err = asd_ddbsite_update_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up),
+ phy_is_up,
+ phy_is_up | phy_mask);
+ if (!err)
+ break;
+ else if (err == -EFAULT) {
+ asd_printk("phy_is_up: parity error in DDB 0\n");
+ break;
+ }
+ }
+
+ if (err)
+ asd_printk("couldn't update DDB 0:error:%d\n", err);
+}
+
+MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE);
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
new file mode 100644
index 00000000000..42281c36153
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_seq.h
@@ -0,0 +1,70 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_SEQ_H_
+#define _AIC94XX_SEQ_H_
+
+#define CSEQ_NUM_VECS 3
+#define LSEQ_NUM_VECS 11
+
+#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw"
+
+/* Note: All quantites in the sequencer file are little endian */
+struct sequencer_file_header {
+ /* Checksum of the entire contents of the sequencer excluding
+ * these four bytes */
+ u32 csum;
+ /* numeric major version */
+ u32 major;
+ /* numeric minor version */
+ u32 minor;
+ /* version string printed by driver */
+ char version[16];
+ u32 cseq_table_offset;
+ u32 cseq_table_size;
+ u32 lseq_table_offset;
+ u32 lseq_table_size;
+ u32 cseq_code_offset;
+ u32 cseq_code_size;
+ u32 lseq_code_offset;
+ u32 lseq_code_size;
+ u16 mode2_task;
+ u16 cseq_idle_loop;
+ u16 lseq_idle_loop;
+} __attribute__((packed));
+
+#ifdef __KERNEL__
+int asd_pause_cseq(struct asd_ha_struct *asd_ha);
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha);
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+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);
+#endif
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
new file mode 100644
index 00000000000..d202ed5a670
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -0,0 +1,642 @@
+/*
+ * Aic94xx SAS/SATA Tasks
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/spinlock.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a);
+static void asd_unbuild_smp_ascb(struct asd_ascb *a);
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a);
+
+static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_ha->seq.can_queue += num;
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+}
+
+/* PCI_DMA_... to our direction translation.
+ */
+static const u8 data_dir_flags[] = {
+ [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
+ [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */
+ [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */
+ [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
+};
+
+static inline int asd_map_scatterlist(struct sas_task *task,
+ struct sg_el *sg_arr,
+ gfp_t gfp_flags)
+{
+ struct asd_ascb *ascb = task->lldd_task;
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct scatterlist *sc;
+ int num_sg, res;
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return 0;
+
+ if (task->num_scatter == 0) {
+ void *p = task->scatter;
+ dma_addr_t dma = pci_map_single(asd_ha->pcidev, p,
+ task->total_xfer_len,
+ task->data_dir);
+ sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
+ sg_arr[0].size = cpu_to_le32(task->total_xfer_len);
+ sg_arr[0].flags |= ASD_SG_EL_LIST_EOL;
+ return 0;
+ }
+
+ num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+ if (num_sg == 0)
+ return -ENOMEM;
+
+ if (num_sg > 3) {
+ int i;
+
+ ascb->sg_arr = asd_alloc_coherent(asd_ha,
+ num_sg*sizeof(struct sg_el),
+ gfp_flags);
+ if (!ascb->sg_arr) {
+ res = -ENOMEM;
+ goto err_unmap;
+ }
+ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ struct sg_el *sg =
+ &((struct sg_el *)ascb->sg_arr->vaddr)[i];
+ sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc));
+ sg->size = cpu_to_le32((u32)sg_dma_len(sc));
+ if (i == num_sg-1)
+ sg->flags |= ASD_SG_EL_LIST_EOL;
+ }
+
+ for (sc = task->scatter, i = 0; i < 2; i++, sc++) {
+ sg_arr[i].bus_addr =
+ cpu_to_le64((u64)sg_dma_address(sc));
+ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+ }
+ sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr);
+ sg_arr[1].flags |= ASD_SG_EL_LIST_EOS;
+
+ memset(&sg_arr[2], 0, sizeof(*sg_arr));
+ sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle);
+ } else {
+ int i;
+ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ sg_arr[i].bus_addr =
+ cpu_to_le64((u64)sg_dma_address(sc));
+ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+ }
+ sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL;
+ }
+
+ return 0;
+err_unmap:
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+ return res;
+}
+
+static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_task *task = ascb->uldd_task;
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return;
+
+ if (task->num_scatter == 0) {
+ dma_addr_t dma = (dma_addr_t)
+ le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr);
+ pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len,
+ task->data_dir);
+ return;
+ }
+
+ asd_free_coherent(asd_ha, ascb->sg_arr);
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+}
+
+/* ---------- Task complete tasklet ---------- */
+
+static void asd_get_response_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_task *task = ascb->uldd_task;
+ struct task_status_struct *ts = &task->task_status;
+ unsigned long flags;
+ struct tc_resp_sb_struct {
+ __le16 index_escb;
+ u8 len_lsb;
+ u8 flags;
+ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+/* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */
+ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+ struct asd_ascb *escb;
+ struct asd_dma_tok *edb;
+ void *r;
+
+ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+ escb = asd_tc_index_find(&asd_ha->seq,
+ (int)le16_to_cpu(resp_sb->index_escb));
+ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+ if (!escb) {
+ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+ return;
+ }
+
+ ts->buf_valid_size = 0;
+ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+ r = edb->vaddr;
+ if (task->task_proto == SAS_PROTO_SSP) {
+ struct ssp_response_iu *iu =
+ r + 16 + sizeof(struct ssp_frame_hdr);
+
+ ts->residual = le32_to_cpu(*(__le32 *)r);
+ ts->resp = SAS_TASK_COMPLETE;
+ if (iu->datapres == 0)
+ ts->stat = iu->status;
+ else if (iu->datapres == 1)
+ ts->stat = iu->resp_data[3];
+ else if (iu->datapres == 2) {
+ ts->stat = SAM_CHECK_COND;
+ ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
+ be32_to_cpu(iu->sense_data_len));
+ memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
+ if (iu->status != SAM_CHECK_COND) {
+ ASD_DPRINTK("device %llx sent sense data, but "
+ "stat(0x%x) is not CHECK_CONDITION"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ ts->stat);
+ }
+ }
+ } else {
+ struct ata_task_resp *resp = (void *) &ts->buf[0];
+
+ ts->residual = le32_to_cpu(*(__le32 *)r);
+
+ if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
+ resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
+ memcpy(&resp->ending_fis[0], r+16, 24);
+ ts->buf_valid_size = sizeof(*resp);
+ }
+ }
+
+ asd_invalidate_edb(escb, edb_id);
+}
+
+static void asd_task_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct sas_task *task = ascb->uldd_task;
+ struct task_status_struct *ts = &task->task_status;
+ unsigned long flags;
+ u8 opcode = dl->opcode;
+
+ asd_can_dequeue(ascb->ha, 1);
+
+Again:
+ switch (opcode) {
+ case TC_NO_ERROR:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ break;
+ case TC_UNDERRUN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ ts->residual = le32_to_cpu(*(__le32 *)dl->status_block);
+ break;
+ case TC_OVERRUN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ case TC_SSP_RESP:
+ case TC_ATA_RESP:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PROTO_RESPONSE;
+ asd_get_response_tasklet(ascb, dl);
+ break;
+ case TF_OPEN_REJECT:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_REJECT;
+ if (dl->status_block[1] & 2)
+ ts->open_rej_reason = 1 + dl->status_block[2];
+ else if (dl->status_block[1] & 1)
+ ts->open_rej_reason = (dl->status_block[2] >> 4)+10;
+ else
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case TF_OPEN_TO:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case TF_PHY_DOWN:
+ case TU_PHY_DOWN:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case TI_PHY_DOWN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case TI_BREAK:
+ case TI_PROTO_ERR:
+ case TI_NAK:
+ case TI_ACK_NAK_TO:
+ case TF_SMP_XMIT_RCV_ERR:
+ case TC_ATA_R_ERR_RECV:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_INTERRUPTED;
+ break;
+ case TF_BREAK:
+ case TU_BREAK:
+ case TU_ACK_NAK_TO:
+ case TF_SMPRSP_TO:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case TF_NAK_RECV:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case TA_I_T_NEXUS_LOSS:
+ opcode = dl->status_block[0];
+ goto Again;
+ break;
+ case TF_INV_CONN_HANDLE:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEVICE_UNKNOWN;
+ break;
+ case TF_REQUESTED_N_PENDING:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PENDING;
+ break;
+ case TC_TASK_CLEARED:
+ case TA_ON_REQ:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ break;
+
+ case TF_NO_SMP_CONN:
+ case TF_TMF_NO_CTX:
+ case TF_TMF_NO_TAG:
+ case TF_TMF_TAG_FREE:
+ case TF_TMF_TASK_DONE:
+ case TF_TMF_NO_CONN_HANDLE:
+ case TF_IRTT_TO:
+ case TF_IU_SHORT:
+ case TF_DATA_OFFS_ERR:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+
+ case TC_LINK_ADM_RESP:
+ case TC_CONTROL_PHY:
+ case TC_RESUME:
+ case TC_PARTIAL_SG_LIST:
+ default:
+ ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
+ break;
+ }
+
+ switch (task->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ asd_unbuild_ata_ascb(ascb);
+ break;
+ case SAS_PROTO_SMP:
+ asd_unbuild_smp_ascb(ascb);
+ break;
+ case SAS_PROTO_SSP:
+ asd_unbuild_ssp_ascb(ascb);
+ default:
+ break;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
+ "stat 0x%x but aborted by upper layer!\n",
+ task, opcode, ts->resp, ts->stat);
+ complete(&ascb->completion);
+ } else {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ task->lldd_task = NULL;
+ asd_ascb_free(ascb);
+ mb();
+ task->task_done(task);
+ }
+}
+
+/* ---------- ATA ---------- */
+
+static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+ u8 flags;
+ int res = 0;
+
+ scb = ascb->scb;
+
+ if (unlikely(task->ata_task.device_control_reg_update))
+ scb->header.opcode = CONTROL_ATA_DEV;
+ else if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+ scb->header.opcode = INITIATE_ATA_TASK;
+ else
+ scb->header.opcode = INITIATE_ATAPI_TASK;
+
+ scb->ata_task.proto_conn_rate = (1 << 5); /* STP */
+ if (dev->port->oob_mode == SAS_OOB_MODE)
+ scb->ata_task.proto_conn_rate |= dev->linkrate;
+
+ scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+ scb->ata_task.fis = task->ata_task.fis;
+ scb->ata_task.fis.fis_type = 0x27;
+ if (likely(!task->ata_task.device_control_reg_update))
+ scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+ scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet,
+ 16);
+ scb->ata_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ata_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)dev->lldd_dev);
+
+ if (likely(!task->ata_task.device_control_reg_update)) {
+ flags = 0;
+ if (task->ata_task.dma_xfer)
+ flags |= DATA_XFER_MODE_DMA;
+ if (task->ata_task.use_ncq &&
+ dev->sata_dev.command_set != ATAPI_COMMAND_SET)
+ flags |= ATA_Q_TYPE_NCQ;
+ flags |= data_dir_flags[task->data_dir];
+ scb->ata_task.ata_flags = flags;
+
+ scb->ata_task.retry_count = task->ata_task.retry_count;
+
+ flags = 0;
+ if (task->ata_task.set_affil_pol)
+ flags |= SET_AFFIL_POLICY;
+ if (task->ata_task.stp_affil_pol)
+ flags |= STP_AFFIL_POLICY;
+ scb->ata_task.flags = flags;
+ }
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ res = asd_map_scatterlist(task, scb->ata_task.sg_element,
+ gfp_flags);
+
+ return res;
+}
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a)
+{
+ asd_unmap_scatterlist(a);
+}
+
+/* ---------- SMP ---------- */
+
+static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+
+ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
+ PCI_DMA_FROMDEVICE);
+ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+
+ scb = ascb->scb;
+
+ scb->header.opcode = INITIATE_SMP_TASK;
+
+ scb->smp_task.proto_conn_rate = dev->linkrate;
+
+ scb->smp_task.smp_req.bus_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
+ scb->smp_task.smp_req.size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
+
+ scb->smp_task.smp_resp.bus_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
+ scb->smp_task.smp_resp.size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
+
+ scb->smp_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->smp_task.conn_handle = cpu_to_le16((u16)
+ (unsigned long)dev->lldd_dev);
+
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ return 0;
+}
+
+static void asd_unbuild_smp_ascb(struct asd_ascb *a)
+{
+ struct sas_task *task = a->uldd_task;
+
+ BUG_ON(!task);
+ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+}
+
+/* ---------- SSP ---------- */
+
+static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+ int res = 0;
+
+ scb = ascb->scb;
+
+ scb->header.opcode = INITIATE_SSP_TASK;
+
+ scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */
+ scb->ssp_task.proto_conn_rate |= dev->linkrate;
+ scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+ scb->ssp_task.ssp_frame.frame_type = SSP_DATA;
+ memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr,
+ HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->ssp_task.ssp_frame.hashed_src_addr,
+ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+ memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8);
+ if (task->ssp_task.enable_first_burst)
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK;
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3);
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7);
+ memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16);
+
+ scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ssp_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)dev->lldd_dev);
+ scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
+ scb->ssp_task.retry_count = scb->ssp_task.retry_count;
+
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
+
+ return res;
+}
+
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a)
+{
+ asd_unmap_scatterlist(a);
+}
+
+/* ---------- Execute Task ---------- */
+
+static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
+{
+ int res = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ if ((asd_ha->seq.can_queue - num) < 0)
+ res = -SAS_QUEUE_FULL;
+ else
+ asd_ha->seq.can_queue -= num;
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return res;
+}
+
+int asd_execute_task(struct sas_task *task, const int num,
+ gfp_t gfp_flags)
+{
+ int res = 0;
+ LIST_HEAD(alist);
+ struct sas_task *t = task;
+ struct asd_ascb *ascb = NULL, *a;
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+
+ res = asd_can_queue(asd_ha, num);
+ if (res)
+ return res;
+
+ res = num;
+ ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
+ if (res) {
+ res = -ENOMEM;
+ goto out_err;
+ }
+
+ __list_add(&alist, ascb->list.prev, &ascb->list);
+ list_for_each_entry(a, &alist, list) {
+ a->uldd_task = t;
+ t->lldd_task = a;
+ t = list_entry(t->list.next, struct sas_task, list);
+ }
+ list_for_each_entry(a, &alist, list) {
+ t = a->uldd_task;
+ a->uldd_timer = 1;
+ if (t->task_proto & SAS_PROTO_STP)
+ t->task_proto = SAS_PROTO_STP;
+ switch (t->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ res = asd_build_ata_ascb(a, t, gfp_flags);
+ break;
+ case SAS_PROTO_SMP:
+ res = asd_build_smp_ascb(a, t, gfp_flags);
+ break;
+ case SAS_PROTO_SSP:
+ res = asd_build_ssp_ascb(a, t, gfp_flags);
+ break;
+ default:
+ asd_printk("unknown sas_task proto: 0x%x\n",
+ t->task_proto);
+ res = -ENOMEM;
+ break;
+ }
+ if (res)
+ goto out_err_unmap;
+ }
+ list_del_init(&alist);
+
+ res = asd_post_ascb_list(asd_ha, ascb, num);
+ if (unlikely(res)) {
+ a = NULL;
+ __list_add(&alist, ascb->list.prev, &ascb->list);
+ goto out_err_unmap;
+ }
+
+ return 0;
+out_err_unmap:
+ {
+ struct asd_ascb *b = a;
+ list_for_each_entry(a, &alist, list) {
+ if (a == b)
+ break;
+ t = a->uldd_task;
+ switch (t->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ asd_unbuild_ata_ascb(a);
+ break;
+ case SAS_PROTO_SMP:
+ asd_unbuild_smp_ascb(a);
+ break;
+ case SAS_PROTO_SSP:
+ asd_unbuild_ssp_ascb(a);
+ default:
+ break;
+ }
+ t->lldd_task = NULL;
+ }
+ }
+ list_del_init(&alist);
+out_err:
+ if (ascb)
+ asd_ascb_free_list(ascb);
+ asd_can_dequeue(asd_ha, num);
+ return res;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
new file mode 100644
index 00000000000..61234384503
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -0,0 +1,636 @@
+/*
+ * Aic94xx Task Management Functions
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/spinlock.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+/* ---------- Internal enqueue ---------- */
+
+static int asd_enqueue_internal(struct asd_ascb *ascb,
+ void (*tasklet_complete)(struct asd_ascb *,
+ struct done_list_struct *),
+ void (*timed_out)(unsigned long))
+{
+ int res;
+
+ ascb->tasklet_complete = tasklet_complete;
+ ascb->uldd_timer = 1;
+
+ ascb->timer.data = (unsigned long) ascb;
+ ascb->timer.function = timed_out;
+ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+
+ add_timer(&ascb->timer);
+
+ res = asd_post_ascb_list(ascb->ha, ascb, 1);
+ if (unlikely(res))
+ del_timer(&ascb->timer);
+ return res;
+}
+
+static inline void asd_timedout_common(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ seq->pending--;
+ list_del_init(&ascb->list);
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+}
+
+/* ---------- CLEAR NEXUS ---------- */
+
+static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ ASD_DPRINTK("%s: here\n", __FUNCTION__);
+ if (!del_timer(&ascb->timer)) {
+ ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
+ return;
+ }
+ ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
+ ascb->uldd_task = (void *) (unsigned long) dl->opcode;
+ complete(&ascb->completion);
+}
+
+static void asd_clear_nexus_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+
+ ASD_DPRINTK("%s: here\n", __FUNCTION__);
+ asd_timedout_common(data);
+ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+ complete(&ascb->completion);
+}
+
+#define CLEAR_NEXUS_PRE \
+ ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
+ res = 1; \
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
+ if (!ascb) \
+ return -ENOMEM; \
+ \
+ scb = ascb->scb; \
+ scb->header.opcode = CLEAR_NEXUS
+
+#define CLEAR_NEXUS_POST \
+ ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
+ res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
+ asd_clear_nexus_timedout); \
+ if (res) \
+ goto out_err; \
+ ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
+ wait_for_completion(&ascb->completion); \
+ res = (int) (unsigned long) ascb->uldd_task; \
+ if (res == TC_NO_ERROR) \
+ res = TMF_RESP_FUNC_COMPLETE; \
+out_err: \
+ asd_ascb_free(ascb); \
+ return res
+
+int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
+{
+ struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_ADAPTER;
+ CLEAR_NEXUS_POST;
+}
+
+int asd_clear_nexus_port(struct asd_sas_port *port)
+{
+ struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_PORT;
+ scb->clear_nexus.conn_mask = port->phy_mask;
+ CLEAR_NEXUS_POST;
+}
+
+#if 0
+static int asd_clear_nexus_I_T(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_I_T;
+ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+ if (dev->tproto)
+ scb->clear_nexus.flags |= SUSPEND_TX;
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+#endif
+
+static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_I_T_L;
+ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+ if (dev->tproto)
+ scb->clear_nexus.flags |= SUSPEND_TX;
+ memcpy(scb->clear_nexus.ssp_task.lun, lun, 8);
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_tag(struct sas_task *task)
+{
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_TAG;
+ memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8);
+ scb->clear_nexus.ssp_task.tag = tascb->tag;
+ if (task->dev->tproto)
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ task->dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_index(struct sas_task *task)
+{
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_TRANS_CX;
+ if (task->dev->tproto)
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ task->dev->lldd_dev);
+ scb->clear_nexus.index = cpu_to_le16(tascb->tc_index);
+ CLEAR_NEXUS_POST;
+}
+
+/* ---------- TMFs ---------- */
+
+static void asd_tmf_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+
+ ASD_DPRINTK("tmf timed out\n");
+ asd_timedout_common(data);
+ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+ complete(&ascb->completion);
+}
+
+static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ unsigned long flags;
+ struct tc_resp_sb_struct {
+ __le16 index_escb;
+ u8 len_lsb;
+ u8 flags;
+ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+ struct asd_ascb *escb;
+ struct asd_dma_tok *edb;
+ struct ssp_frame_hdr *fh;
+ struct ssp_response_iu *ru;
+ int res = TMF_RESP_FUNC_FAILED;
+
+ ASD_DPRINTK("tmf resp tasklet\n");
+
+ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+ escb = asd_tc_index_find(&asd_ha->seq,
+ (int)le16_to_cpu(resp_sb->index_escb));
+ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+ if (!escb) {
+ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+ return res;
+ }
+
+ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+ ascb->tag = *(__be16 *)(edb->vaddr+4);
+ fh = edb->vaddr + 16;
+ ru = edb->vaddr + 16 + sizeof(*fh);
+ res = ru->status;
+ if (ru->datapres == 1) /* Response data present */
+ res = ru->resp_data[3];
+#if 0
+ ascb->tag = fh->tag;
+#endif
+ ascb->tag_valid = 1;
+
+ asd_invalidate_edb(escb, edb_id);
+ return res;
+}
+
+static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ if (!del_timer(&ascb->timer))
+ return;
+
+ ASD_DPRINTK("tmf tasklet complete\n");
+
+ if (dl->opcode == TC_SSP_RESP)
+ ascb->uldd_task = (void *) (unsigned long)
+ asd_get_tmf_resp_tasklet(ascb, dl);
+ else
+ ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
+
+ complete(&ascb->completion);
+}
+
+static inline int asd_clear_nexus(struct sas_task *task)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct asd_ascb *tascb = task->lldd_task;
+ unsigned long flags;
+
+ ASD_DPRINTK("task not done, clearing nexus\n");
+ if (tascb->tag_valid)
+ res = asd_clear_nexus_tag(task);
+ else
+ res = asd_clear_nexus_index(task);
+ wait_for_completion_timeout(&tascb->completion,
+ AIC94XX_SCB_TIMEOUT);
+ ASD_DPRINTK("came back from clear nexus\n");
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE)
+ res = TMF_RESP_FUNC_COMPLETE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ return res;
+}
+
+/**
+ * asd_abort_task -- ABORT TASK TMF
+ * @task: the task to be aborted
+ *
+ * Before calling ABORT TASK the task state flags should be ORed with
+ * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under
+ * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called.
+ *
+ * Implements the ABORT TASK TMF, I_T_L_Q nexus.
+ * Returns: SAS TMF responses (see sas_task.h),
+ * -ENOMEM,
+ * -SAS_QUEUE_FULL.
+ *
+ * When ABORT TASK returns, the caller of ABORT TASK checks first the
+ * task->task_state_flags, and then the return value of ABORT TASK.
+ *
+ * If the task has task state bit SAS_TASK_STATE_DONE set, then the
+ * task was completed successfully prior to it being aborted. The
+ * caller of ABORT TASK has responsibility to call task->task_done()
+ * xor free the task, depending on their framework. The return code
+ * is TMF_RESP_FUNC_FAILED in this case.
+ *
+ * Else the SAS_TASK_STATE_DONE bit is not set,
+ * If the return code is TMF_RESP_FUNC_COMPLETE, then
+ * the task was aborted successfully. The caller of
+ * ABORT TASK has responsibility to call task->task_done()
+ * to finish the task, xor free the task depending on their
+ * framework.
+ * else
+ * the ABORT TASK returned some kind of error. The task
+ * was _not_ cancelled. Nothing can be assumed.
+ * The caller of ABORT TASK may wish to retry.
+ */
+int asd_abort_task(struct sas_task *task)
+{
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ha_struct *asd_ha = tascb->ha;
+ int res = 1;
+ unsigned long flags;
+ struct asd_ascb *ascb = NULL;
+ struct scb *scb;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ res = TMF_RESP_FUNC_COMPLETE;
+ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+ scb = ascb->scb;
+
+ scb->header.opcode = ABORT_TASK;
+
+ switch (task->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
+ break;
+ case SAS_PROTO_SSP:
+ scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */
+ scb->abort_task.proto_conn_rate |= task->dev->linkrate;
+ break;
+ case SAS_PROTO_SMP:
+ break;
+ default:
+ break;
+ }
+
+ if (task->task_proto == SAS_PROTO_SSP) {
+ scb->abort_task.ssp_frame.frame_type = SSP_TASK;
+ memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
+ task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->abort_task.ssp_frame.hashed_src_addr,
+ task->dev->port->ha->hashed_sas_addr,
+ HASHED_SAS_ADDR_SIZE);
+ scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+ memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8);
+ scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK;
+ scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF);
+ }
+
+ scb->abort_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->abort_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)task->dev->lldd_dev);
+ scb->abort_task.retry_count = 1;
+ scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
+ scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+
+ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ asd_tmf_timedout);
+ if (res)
+ goto out;
+ wait_for_completion(&ascb->completion);
+ ASD_DPRINTK("tmf came back\n");
+
+ res = (int) (unsigned long) ascb->uldd_task;
+ tascb->tag = ascb->tag;
+ tascb->tag_valid = ascb->tag_valid;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ res = TMF_RESP_FUNC_COMPLETE;
+ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ switch (res) {
+ /* The task to be aborted has been sent to the device.
+ * We got a Response IU for the ABORT TASK TMF. */
+ case TC_NO_ERROR + 0xFF00:
+ case TMF_RESP_FUNC_COMPLETE:
+ case TMF_RESP_FUNC_FAILED:
+ res = asd_clear_nexus(task);
+ break;
+ case TMF_RESP_INVALID_FRAME:
+ case TMF_RESP_OVERLAPPED_TAG:
+ case TMF_RESP_FUNC_ESUPP:
+ case TMF_RESP_NO_LUN:
+ goto out_done; break;
+ }
+ /* In the following we assume that the managing layer
+ * will _never_ make a mistake, when issuing ABORT TASK.
+ */
+ switch (res) {
+ default:
+ res = asd_clear_nexus(task);
+ /* fallthrough */
+ case TC_NO_ERROR + 0xFF00:
+ case TMF_RESP_FUNC_COMPLETE:
+ break;
+ /* The task hasn't been sent to the device xor we never got
+ * a (sane) Response IU for the ABORT TASK TMF.
+ */
+ case TF_NAK_RECV + 0xFF00:
+ res = TMF_RESP_INVALID_FRAME;
+ break;
+ case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
+ res = TMF_RESP_FUNC_FAILED;
+ wait_for_completion_timeout(&tascb->completion,
+ AIC94XX_SCB_TIMEOUT);
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE)
+ res = TMF_RESP_FUNC_COMPLETE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ goto out_done;
+ case TF_TMF_NO_TAG + 0xFF00:
+ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+ res = TMF_RESP_FUNC_COMPLETE;
+ goto out_done;
+ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+ res = TMF_RESP_FUNC_ESUPP;
+ goto out;
+ }
+out_done:
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ task->lldd_task = NULL;
+ mb();
+ asd_ascb_free(tascb);
+ }
+out:
+ asd_ascb_free(ascb);
+ ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
+ return res;
+}
+
+/**
+ * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus
+ * @dev: pointer to struct domain_device of interest
+ * @lun: pointer to u8[8] which is the LUN
+ * @tmf: the TMF to be performed (see sas_task.h or the SAS spec)
+ * @index: the transaction context of the task to be queried if QT TMF
+ *
+ * This function is used to send ABORT TASK SET, CLEAR ACA,
+ * CLEAR TASK SET, LU RESET and QUERY TASK TMFs.
+ *
+ * No SCBs should be queued to the I_T_L nexus when this SCB is
+ * pending.
+ *
+ * Returns: TMF response code (see sas_task.h or the SAS spec)
+ */
+static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
+ int tmf, int index)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ int res = 1;
+ struct scb *scb;
+
+ if (!(dev->tproto & SAS_PROTO_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+ scb = ascb->scb;
+
+ if (tmf == TMF_QUERY_TASK)
+ scb->header.opcode = QUERY_SSP_TASK;
+ else
+ scb->header.opcode = INITIATE_SSP_TMF;
+
+ scb->ssp_tmf.proto_conn_rate = (1 << 4); /* SSP */
+ scb->ssp_tmf.proto_conn_rate |= dev->linkrate;
+ /* SSP frame header */
+ scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK;
+ memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr,
+ dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr,
+ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+ /* SSP Task IU */
+ memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8);
+ scb->ssp_tmf.ssp_task.tmf = tmf;
+
+ scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ scb->ssp_tmf.retry_count = 1;
+ scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+ if (tmf == TMF_QUERY_TASK)
+ scb->ssp_tmf.index = cpu_to_le16(index);
+
+ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ asd_tmf_timedout);
+ if (res)
+ goto out_err;
+ wait_for_completion(&ascb->completion);
+ res = (int) (unsigned long) ascb->uldd_task;
+
+ switch (res) {
+ case TC_NO_ERROR + 0xFF00:
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ case TF_NAK_RECV + 0xFF00:
+ res = TMF_RESP_INVALID_FRAME;
+ break;
+ case TF_TMF_TASK_DONE + 0xFF00:
+ res = TMF_RESP_FUNC_FAILED;
+ break;
+ case TF_TMF_NO_TAG + 0xFF00:
+ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+ res = TMF_RESP_FUNC_ESUPP;
+ break;
+ default:
+ ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n",
+ __FUNCTION__, res);
+ res = TMF_RESP_FUNC_FAILED;
+ break;
+ }
+out_err:
+ asd_ascb_free(ascb);
+ return res;
+}
+
+int asd_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_clear_aca(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_lu_reset(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+/**
+ * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus
+ * task: pointer to sas_task struct of interest
+ *
+ * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set,
+ * or TMF_RESP_FUNC_SUCC if the task is in the task set.
+ *
+ * Normally the management layer sets the task to aborted state,
+ * and then calls query task and then abort task.
+ */
+int asd_query_task(struct sas_task *task)
+{
+ struct asd_ascb *ascb = task->lldd_task;
+ int index;
+
+ if (ascb) {
+ index = ascb->tc_index;
+ return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN,
+ TMF_QUERY_TASK, index);
+ }
+ return TMF_RESP_FUNC_COMPLETE;
+}
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index c0844fa32c5..9099d531d5a 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -11,7 +11,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/config.h>
#include <linux/zorro.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile
new file mode 100644
index 00000000000..721aced3916
--- /dev/null
+++ b/drivers/scsi/arcmsr/Makefile
@@ -0,0 +1,6 @@
+# File: drivers/arcmsr/Makefile
+# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
+
+arcmsr-objs := arcmsr_attr.o arcmsr_hba.o
+
+obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
new file mode 100644
index 00000000000..aff96db9ccf
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -0,0 +1,472 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr.h
+** BY : Erich Chen
+** Description: SCSI RAID Device Driver for
+** ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+**(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+*/
+#include <linux/interrupt.h>
+
+struct class_device_attribute;
+
+#define ARCMSR_MAX_OUTSTANDING_CMD 256
+#define ARCMSR_MAX_FREECCB_NUM 288
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13"
+#define ARCMSR_SCSI_INITIATOR_ID 255
+#define ARCMSR_MAX_XFER_SECTORS 512
+#define ARCMSR_MAX_TARGETID 17
+#define ARCMSR_MAX_TARGETLUN 8
+#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER 4096
+#define ARCMSR_MAX_SG_ENTRIES 38
+
+/*
+*******************************************************************************
+** split 64bits dma addressing
+*******************************************************************************
+*/
+#define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16)
+#define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff)
+/*
+*******************************************************************************
+** MESSAGE CONTROL CODE
+*******************************************************************************
+*/
+struct CMD_MESSAGE
+{
+ uint32_t HeaderLength;
+ uint8_t Signature[8];
+ uint32_t Timeout;
+ uint32_t ControlCode;
+ uint32_t ReturnCode;
+ uint32_t Length;
+};
+/*
+*******************************************************************************
+** IOP Message Transfer Data for user space
+*******************************************************************************
+*/
+struct CMD_MESSAGE_FIELD
+{
+ struct CMD_MESSAGE cmdmessage;
+ uint8_t messagedatabuffer[1032];
+};
+/* IOP message transfer */
+#define ARCMSR_MESSAGE_FAIL 0x0001
+/* DeviceType */
+#define ARECA_SATA_RAID 0x90000000
+/* FunctionCode */
+#define FUNCTION_READ_RQBUFFER 0x0801
+#define FUNCTION_WRITE_WQBUFFER 0x0802
+#define FUNCTION_CLEAR_RQBUFFER 0x0803
+#define FUNCTION_CLEAR_WQBUFFER 0x0804
+#define FUNCTION_CLEAR_ALLQBUFFER 0x0805
+#define FUNCTION_RETURN_CODE_3F 0x0806
+#define FUNCTION_SAY_HELLO 0x0807
+#define FUNCTION_SAY_GOODBYE 0x0808
+#define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809
+/* ARECA IO CONTROL CODE*/
+#define ARCMSR_MESSAGE_READ_RQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
+#define ARCMSR_MESSAGE_WRITE_WQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_RQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_WQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
+#define ARCMSR_MESSAGE_RETURN_CODE_3F \
+ ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
+#define ARCMSR_MESSAGE_SAY_HELLO \
+ ARECA_SATA_RAID | FUNCTION_SAY_HELLO
+#define ARCMSR_MESSAGE_SAY_GOODBYE \
+ ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
+#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
+ ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
+/* ARECA IOCTL ReturnCode */
+#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006
+#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F
+/*
+*************************************************************
+** structure for holding DMA address data
+*************************************************************
+*/
+#define IS_SG64_ADDR 0x01000000 /* bit24 */
+struct SG32ENTRY
+{
+ uint32_t length;
+ uint32_t address;
+};
+struct SG64ENTRY
+{
+ uint32_t length;
+ uint32_t address;
+ uint32_t addresshigh;
+};
+struct SGENTRY_UNION
+{
+ union
+ {
+ struct SG32ENTRY sg32entry;
+ struct SG64ENTRY sg64entry;
+ }u;
+};
+/*
+********************************************************************
+** Q Buffer of IOP Message Transfer
+********************************************************************
+*/
+struct QBUFFER
+{
+ uint32_t data_len;
+ uint8_t data[124];
+};
+/*
+*******************************************************************************
+** FIRMWARE INFO
+*******************************************************************************
+*/
+struct FIRMWARE_INFO
+{
+ uint32_t signature; /*0, 00-03*/
+ uint32_t request_len; /*1, 04-07*/
+ uint32_t numbers_queue; /*2, 08-11*/
+ uint32_t sdram_size; /*3, 12-15*/
+ uint32_t ide_channels; /*4, 16-19*/
+ char vendor[40]; /*5, 20-59*/
+ char model[8]; /*15, 60-67*/
+ char firmware_ver[16]; /*17, 68-83*/
+ char device_map[16]; /*21, 84-99*/
+};
+/* signature of set and get firmware config */
+#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
+/* message code of inbound message register */
+#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
+#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
+#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
+#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
+#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005
+#define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006
+#define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007
+#define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008
+/* doorbell interrupt generator */
+#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001
+#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002
+#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001
+#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002
+/* ccb areca cdb flag */
+#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000
+#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000
+#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
+/* outbound firmware ok */
+#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+/*
+*******************************************************************************
+** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
+*******************************************************************************
+*/
+struct ARCMSR_CDB
+{
+ uint8_t Bus;
+ uint8_t TargetID;
+ uint8_t LUN;
+ uint8_t Function;
+
+ uint8_t CdbLength;
+ uint8_t sgcount;
+ uint8_t Flags;
+#define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01
+#define ARCMSR_CDB_FLAG_BIOS 0x02
+#define ARCMSR_CDB_FLAG_WRITE 0x04
+#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
+#define ARCMSR_CDB_FLAG_HEADQ 0x08
+#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
+ uint8_t Reserved1;
+
+ uint32_t Context;
+ uint32_t DataLength;
+
+ uint8_t Cdb[16];
+
+ uint8_t DeviceStatus;
+#define ARCMSR_DEV_CHECK_CONDITION 0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
+#define ARCMSR_DEV_ABORTED 0xF1
+#define ARCMSR_DEV_INIT_FAIL 0xF2
+ uint8_t SenseData[15];
+
+ union
+ {
+ struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
+ struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES];
+ } u;
+};
+/*
+*******************************************************************************
+** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+*******************************************************************************
+*/
+struct MessageUnit
+{
+ uint32_t resrved0[4]; /*0000 000F*/
+ uint32_t inbound_msgaddr0; /*0010 0013*/
+ uint32_t inbound_msgaddr1; /*0014 0017*/
+ uint32_t outbound_msgaddr0; /*0018 001B*/
+ uint32_t outbound_msgaddr1; /*001C 001F*/
+ uint32_t inbound_doorbell; /*0020 0023*/
+ uint32_t inbound_intstatus; /*0024 0027*/
+ uint32_t inbound_intmask; /*0028 002B*/
+ uint32_t outbound_doorbell; /*002C 002F*/
+ uint32_t outbound_intstatus; /*0030 0033*/
+ uint32_t outbound_intmask; /*0034 0037*/
+ uint32_t reserved1[2]; /*0038 003F*/
+ uint32_t inbound_queueport; /*0040 0043*/
+ uint32_t outbound_queueport; /*0044 0047*/
+ uint32_t reserved2[2]; /*0048 004F*/
+ uint32_t reserved3[492]; /*0050 07FF 492*/
+ uint32_t reserved4[128]; /*0800 09FF 128*/
+ uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/
+ uint32_t message_wbuffer[32]; /*0E00 0E7F 32*/
+ uint32_t reserved5[32]; /*0E80 0EFF 32*/
+ uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
+ uint32_t reserved6[32]; /*0F80 0FFF 32*/
+};
+/*
+*******************************************************************************
+** Adapter Control Block
+*******************************************************************************
+*/
+struct AdapterControlBlock
+{
+ struct pci_dev * pdev;
+ struct Scsi_Host * host;
+ unsigned long vir2phy_offset;
+ /* Offset is used in making arc cdb physical to virtual calculations */
+ uint32_t outbound_int_enable;
+
+ struct MessageUnit __iomem * pmu;
+ /* message unit ATU inbound base address0 */
+
+ uint32_t acb_flags;
+#define ACB_F_SCSISTOPADAPTER 0x0001
+#define ACB_F_MSG_STOP_BGRB 0x0002
+ /* stop RAID background rebuild */
+#define ACB_F_MSG_START_BGRB 0x0004
+ /* stop RAID background rebuild */
+#define ACB_F_IOPDATA_OVERFLOW 0x0008
+ /* iop message data rqbuffer overflow */
+#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
+ /* message clear wqbuffer */
+#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
+ /* message clear rqbuffer */
+#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
+#define ACB_F_BUS_RESET 0x0080
+#define ACB_F_IOP_INITED 0x0100
+ /* iop init */
+
+ struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
+ /* used for memory free */
+ struct list_head ccb_free_list;
+ /* head of free ccb list */
+ atomic_t ccboutstandingcount;
+
+ void * dma_coherent;
+ /* dma_coherent used for memory free */
+ dma_addr_t dma_coherent_handle;
+ /* dma_coherent_handle used for memory free */
+
+ uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
+ /* data collection buffer for read from 80331 */
+ int32_t rqbuf_firstindex;
+ /* first of read buffer */
+ int32_t rqbuf_lastindex;
+ /* last of read buffer */
+ uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
+ /* data collection buffer for write to 80331 */
+ int32_t wqbuf_firstindex;
+ /* first of write buffer */
+ int32_t wqbuf_lastindex;
+ /* last of write buffer */
+ uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
+ /* id0 ..... id15, lun0...lun7 */
+#define ARECA_RAID_GONE 0x55
+#define ARECA_RAID_GOOD 0xaa
+ uint32_t num_resets;
+ uint32_t num_aborts;
+ uint32_t firm_request_len;
+ uint32_t firm_numbers_queue;
+ uint32_t firm_sdram_size;
+ uint32_t firm_hd_channels;
+ char firm_model[12];
+ char firm_version[20];
+};/* HW_DEVICE_EXTENSION */
+/*
+*******************************************************************************
+** Command Control Block
+** this CCB length must be 32 bytes boundary
+*******************************************************************************
+*/
+struct CommandControlBlock
+{
+ struct ARCMSR_CDB arcmsr_cdb;
+ /*
+ ** 0-503 (size of CDB=504):
+ ** arcmsr messenger scsi command descriptor size 504 bytes
+ */
+ uint32_t cdb_shifted_phyaddr;
+ /* 504-507 */
+ uint32_t reserved1;
+ /* 508-511 */
+#if BITS_PER_LONG == 64
+ /* ======================512+64 bytes======================== */
+ struct list_head list;
+ /* 512-527 16 bytes next/prev ptrs for ccb lists */
+ struct scsi_cmnd * pcmd;
+ /* 528-535 8 bytes pointer of linux scsi command */
+ struct AdapterControlBlock * acb;
+ /* 536-543 8 bytes pointer of acb */
+
+ uint16_t ccb_flags;
+ /* 544-545 */
+ #define CCB_FLAG_READ 0x0000
+ #define CCB_FLAG_WRITE 0x0001
+ #define CCB_FLAG_ERROR 0x0002
+ #define CCB_FLAG_FLUSHCACHE 0x0004
+ #define CCB_FLAG_MASTER_ABORTED 0x0008
+ uint16_t startdone;
+ /* 546-547 */
+ #define ARCMSR_CCB_DONE 0x0000
+ #define ARCMSR_CCB_START 0x55AA
+ #define ARCMSR_CCB_ABORTED 0xAA55
+ #define ARCMSR_CCB_ILLEGAL 0xFFFF
+ uint32_t reserved2[7];
+ /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
+#else
+ /* ======================512+32 bytes======================== */
+ struct list_head list;
+ /* 512-519 8 bytes next/prev ptrs for ccb lists */
+ struct scsi_cmnd * pcmd;
+ /* 520-523 4 bytes pointer of linux scsi command */
+ struct AdapterControlBlock * acb;
+ /* 524-527 4 bytes pointer of acb */
+
+ uint16_t ccb_flags;
+ /* 528-529 */
+ #define CCB_FLAG_READ 0x0000
+ #define CCB_FLAG_WRITE 0x0001
+ #define CCB_FLAG_ERROR 0x0002
+ #define CCB_FLAG_FLUSHCACHE 0x0004
+ #define CCB_FLAG_MASTER_ABORTED 0x0008
+ uint16_t startdone;
+ /* 530-531 */
+ #define ARCMSR_CCB_DONE 0x0000
+ #define ARCMSR_CCB_START 0x55AA
+ #define ARCMSR_CCB_ABORTED 0xAA55
+ #define ARCMSR_CCB_ILLEGAL 0xFFFF
+ uint32_t reserved2[3];
+ /* 532-535 536-539 540-543 */
+#endif
+ /* ========================================================== */
+};
+/*
+*******************************************************************************
+** ARECA SCSI sense data
+*******************************************************************************
+*/
+struct SENSE_DATA
+{
+ uint8_t ErrorCode:7;
+#define SCSI_SENSE_CURRENT_ERRORS 0x70
+#define SCSI_SENSE_DEFERRED_ERRORS 0x71
+ uint8_t Valid:1;
+ uint8_t SegmentNumber;
+ uint8_t SenseKey:4;
+ uint8_t Reserved:1;
+ uint8_t IncorrectLength:1;
+ uint8_t EndOfMedia:1;
+ uint8_t FileMark:1;
+ uint8_t Information[4];
+ uint8_t AdditionalSenseLength;
+ uint8_t CommandSpecificInformation[4];
+ uint8_t AdditionalSenseCode;
+ uint8_t AdditionalSenseCodeQualifier;
+ uint8_t FieldReplaceableUnitCode;
+ uint8_t SenseKeySpecific[3];
+};
+/*
+*******************************************************************************
+** Outbound Interrupt Status Register - OISR
+*******************************************************************************
+*/
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30
+#define ARCMSR_MU_OUTBOUND_PCI_INT 0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01
+#define ARCMSR_MU_OUTBOUND_HANDLE_INT \
+ (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \
+ |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \
+ |ARCMSR_MU_OUTBOUND_DOORBELL_INT \
+ |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \
+ |ARCMSR_MU_OUTBOUND_PCI_INT)
+/*
+*******************************************************************************
+** Outbound Interrupt Mask Register - OIMR
+*******************************************************************************
+*/
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34
+#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
+#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
+
+extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern struct class_device_attribute *arcmsr_host_attrs[];
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
+
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
new file mode 100644
index 00000000000..12497da5529
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -0,0 +1,381 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr_attr.c
+** BY : Erich Chen
+** Description: attributes exported to sysfs and device host
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
+** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include "arcmsr.h"
+
+struct class_device_attribute *arcmsr_host_attrs[];
+
+static ssize_t
+arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint8_t *pQbuffer,*ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ /* do message unit read. */
+ ptmpQbuffer = (uint8_t *)buf;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
+ &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ return (allxfer_len);
+}
+
+static ssize_t
+arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (count > 1032)
+ return -EINVAL;
+ /* do message unit write. */
+ ptmpuserbuffer = (uint8_t *)buf;
+ user_len = (int32_t)count;
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ arcmsr_post_Qbuffer(acb);
+ return 0; /*need retry*/
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_Qbuffer(acb);
+ }
+ return count;
+ } else {
+ return 0; /*need retry*/
+ }
+ }
+}
+
+static ssize_t
+arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint8_t *pQbuffer;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ return 1;
+}
+
+static struct bin_attribute arcmsr_sysfs_message_read_attr = {
+ .attr = {
+ .name = "mu_read",
+ .mode = S_IRUSR ,
+ .owner = THIS_MODULE,
+ },
+ .size = 1032,
+ .read = arcmsr_sysfs_iop_message_read,
+};
+
+static struct bin_attribute arcmsr_sysfs_message_write_attr = {
+ .attr = {
+ .name = "mu_write",
+ .mode = S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = 1032,
+ .write = arcmsr_sysfs_iop_message_write,
+};
+
+static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
+ .attr = {
+ .name = "mu_clear",
+ .mode = S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = 1,
+ .write = arcmsr_sysfs_iop_message_clear,
+};
+
+int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
+{
+ struct Scsi_Host *host = acb->host;
+ int error;
+
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
+ goto error_bin_file_message_read;
+ }
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
+ goto error_bin_file_message_write;
+ }
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_clear_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
+ goto error_bin_file_message_clear;
+ }
+ return 0;
+error_bin_file_message_clear:
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+error_bin_file_message_write:
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+error_bin_file_message_read:
+ return error;
+}
+
+void
+arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
+ struct Scsi_Host *host = acb->host;
+
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_clear_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+}
+
+
+static ssize_t
+arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) {
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ ARCMSR_DRIVER_VERSION);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_posted_cmd(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ atomic_read(&acb->ccboutstandingcount));
+}
+
+static ssize_t
+arcmsr_attr_host_driver_reset(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->num_resets);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_abort(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->num_aborts);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ acb->firm_model);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ acb->firm_version);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_request_len);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_numbers_queue);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_sdram_size);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_hd_channels);
+}
+
+static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
+static CLASS_DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
+static CLASS_DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
+static CLASS_DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
+static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
+static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
+static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
+static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
+static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
+static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
+
+struct class_device_attribute *arcmsr_host_attrs[] = {
+ &class_device_attr_host_driver_version,
+ &class_device_attr_host_driver_posted_cmd,
+ &class_device_attr_host_driver_reset,
+ &class_device_attr_host_driver_abort,
+ &class_device_attr_host_fw_model,
+ &class_device_attr_host_fw_version,
+ &class_device_attr_host_fw_request_len,
+ &class_device_attr_host_fw_numbers_queue,
+ &class_device_attr_host_fw_sdram_size,
+ &class_device_attr_host_fw_hd_channels,
+ NULL,
+};
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
new file mode 100644
index 00000000000..475f978ff8f
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -0,0 +1,1496 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr_hba.c
+** BY : Erich Chen
+** Description: SCSI RAID Device Driver for
+** ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
+** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/pci_ids.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsicam.h>
+#include "arcmsr.h"
+
+MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(ARCMSR_DRIVER_VERSION);
+
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_abort(struct scsi_cmnd *);
+static int arcmsr_bus_reset(struct scsi_cmnd *);
+static int arcmsr_bios_param(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd * cmd,
+ void (*done) (struct scsi_cmnd *));
+static int arcmsr_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+static void arcmsr_remove(struct pci_dev *pdev);
+static void arcmsr_shutdown(struct pci_dev *pdev);
+static void arcmsr_iop_init(struct AdapterControlBlock *acb);
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static const char *arcmsr_info(struct Scsi_Host *);
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
+
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+ if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
+ queue_depth = ARCMSR_MAX_CMD_PERLUN;
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+ return queue_depth;
+}
+
+static struct scsi_host_template arcmsr_scsi_host_template = {
+ .module = THIS_MODULE,
+ .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+ .info = arcmsr_info,
+ .queuecommand = arcmsr_queue_command,
+ .eh_abort_handler = arcmsr_abort,
+ .eh_bus_reset_handler = arcmsr_bus_reset,
+ .bios_param = arcmsr_bios_param,
+ .change_queue_depth = arcmsr_adjust_disk_queue_depth,
+ .can_queue = ARCMSR_MAX_OUTSTANDING_CMD,
+ .this_id = ARCMSR_SCSI_INITIATOR_ID,
+ .sg_tablesize = ARCMSR_MAX_SG_ENTRIES,
+ .max_sectors = ARCMSR_MAX_XFER_SECTORS,
+ .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = arcmsr_host_attrs,
+};
+
+static struct pci_device_id arcmsr_device_id_table[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
+ {0, 0}, /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
+static struct pci_driver arcmsr_pci_driver = {
+ .name = "arcmsr",
+ .id_table = arcmsr_device_id_table,
+ .probe = arcmsr_probe,
+ .remove = arcmsr_remove,
+ .shutdown = arcmsr_shutdown
+};
+
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ irqreturn_t handle_state;
+ struct AdapterControlBlock *acb;
+ unsigned long flags;
+
+ acb = (struct AdapterControlBlock *)dev_id;
+
+ spin_lock_irqsave(acb->host->host_lock, flags);
+ handle_state = arcmsr_interrupt(acb);
+ spin_unlock_irqrestore(acb->host->host_lock, flags);
+ return handle_state;
+}
+
+static int arcmsr_bios_param(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int *geom)
+{
+ int ret, heads, sectors, cylinders, total_capacity;
+ unsigned char *buffer;/* return copy of block device's partition table */
+
+ buffer = scsi_bios_ptable(bdev);
+ if (buffer) {
+ ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
+ kfree(buffer);
+ if (ret != -1)
+ return ret;
+ }
+ total_capacity = capacity;
+ heads = 64;
+ sectors = 32;
+ cylinders = total_capacity / (heads * sectors);
+ if (cylinders > 1024) {
+ heads = 255;
+ sectors = 63;
+ cylinders = total_capacity / (heads * sectors);
+ }
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+ return 0;
+}
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+ struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 ccb_phyaddr_hi32;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ struct CommandControlBlock *ccb_tmp;
+ int i, j;
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM *
+ sizeof (struct CommandControlBlock) + 0x20,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent)
+ return -ENOMEM;
+
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
+
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
+
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof (struct CommandControlBlock);
+ ccb_tmp++;
+ }
+
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -
+ (unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GOOD;
+
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
+ if (ccb_phyaddr_hi32 != 0) {
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
+ writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE "arcmsr%d: "
+ "'set ccb high part physical address' timeout\n",
+ acb->host->host_no);
+ }
+
+ writel(readl(&reg->outbound_intmask) |
+ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ return 0;
+}
+
+static int arcmsr_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct AdapterControlBlock *acb;
+ uint8_t bus, dev_fun;
+ int error;
+
+ error = pci_enable_device(pdev);
+ if (error)
+ goto out;
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&arcmsr_scsi_host_template,
+ sizeof(struct AdapterControlBlock));
+ if (!host) {
+ error = -ENOMEM;
+ goto out_disable_device;
+ }
+ acb = (struct AdapterControlBlock *)host->hostdata;
+ memset(acb, 0, sizeof (struct AdapterControlBlock));
+
+ error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error) {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_WARNING
+ "scsi%d: No suitable DMA mask available\n",
+ host->host_no);
+ goto out_host_put;
+ }
+ }
+ bus = pdev->bus->number;
+ dev_fun = pdev->devfn;
+ acb->host = host;
+ acb->pdev = pdev;
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ host->max_lun = ARCMSR_MAX_TARGETLUN;
+ host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
+ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
+ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
+ host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
+ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+ host->this_id = ARCMSR_SCSI_INITIATOR_ID;
+ host->unique_id = (bus << 8) | dev_fun;
+ host->irq = pdev->irq;
+ error = pci_request_regions(pdev, "arcmsr");
+ if (error)
+ goto out_host_put;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory"
+ " mapping region fail \n", acb->host->host_no);
+ goto out_release_regions;
+ }
+ acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_RQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+ INIT_LIST_HEAD(&acb->ccb_free_list);
+
+ error = arcmsr_alloc_ccb_pool(acb);
+ if (error)
+ goto out_iounmap;
+
+ error = request_irq(pdev->irq, arcmsr_do_interrupt,
+ SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb);
+ if (error)
+ goto out_free_ccb_pool;
+
+ arcmsr_iop_init(acb);
+ pci_set_drvdata(pdev, host);
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error)
+ goto out_free_irq;
+
+ error = arcmsr_alloc_sysfs_attr(acb);
+ if (error)
+ goto out_free_sysfs;
+
+ scsi_scan_host(host);
+ return 0;
+ out_free_sysfs:
+ out_free_irq:
+ free_irq(pdev->irq, acb);
+ out_free_ccb_pool:
+ arcmsr_free_ccb_pool(acb);
+ out_iounmap:
+ iounmap(acb->pmu);
+ out_release_regions:
+ pci_release_regions(pdev);
+ out_host_put:
+ scsi_host_put(host);
+ out_disable_device:
+ pci_disable_device(pdev);
+ out:
+ return error;
+}
+
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
+{
+ struct AdapterControlBlock *acb = ccb->acb;
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+
+ if (pcmd->use_sg != 0) {
+ struct scatterlist *sl;
+
+ sl = (struct scatterlist *)pcmd->request_buffer;
+ pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
+ }
+ else if (pcmd->request_bufflen != 0)
+ pci_unmap_single(acb->pdev,
+ pcmd->SCp.dma_handle,
+ pcmd->request_bufflen, pcmd->sc_data_direction);
+}
+
+static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
+{
+ struct AdapterControlBlock *acb = ccb->acb;
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+
+ arcmsr_pci_unmap_dma(ccb);
+ if (stand_flag == 1)
+ atomic_dec(&acb->ccboutstandingcount);
+ ccb->startdone = ARCMSR_CCB_DONE;
+ ccb->ccb_flags = 0;
+ list_add_tail(&ccb->list, &acb->ccb_free_list);
+ pcmd->scsi_done(pcmd);
+}
+
+static void arcmsr_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ int poll_count = 0;
+
+ arcmsr_free_sysfs_attr(acb);
+ scsi_remove_host(host);
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+ writel(readl(&reg->outbound_intmask) |
+ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
+ acb->acb_flags &= ~ACB_F_IOP_INITED;
+
+ for (poll_count = 0; poll_count < 256; poll_count++) {
+ if (!atomic_read(&acb->ccboutstandingcount))
+ break;
+ arcmsr_interrupt(acb);
+ msleep(25);
+ }
+
+ if (atomic_read(&acb->ccboutstandingcount)) {
+ int i;
+
+ arcmsr_abort_allcmd(acb);
+ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+ readl(&reg->outbound_queueport);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ struct CommandControlBlock *ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ }
+ }
+
+ free_irq(pdev->irq, acb);
+ iounmap(acb->pmu);
+ arcmsr_free_ccb_pool(acb);
+ pci_release_regions(pdev);
+
+ scsi_host_put(host);
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static void arcmsr_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)host->hostdata;
+
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+}
+
+static int arcmsr_module_init(void)
+{
+ int error = 0;
+
+ error = pci_register_driver(&arcmsr_pci_driver);
+ return error;
+}
+
+static void arcmsr_module_exit(void)
+{
+ pci_unregister_driver(&arcmsr_pci_driver);
+}
+module_init(arcmsr_module_init);
+module_exit(arcmsr_module_exit);
+
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 orig_mask = readl(&reg->outbound_intmask);
+
+ writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ return orig_mask;
+}
+
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
+ u32 orig_mask)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 mask;
+
+ mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+ ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(mask, &reg->outbound_intmask);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg=acb->pmu;
+
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'flush adapter cache' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+{
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+ pcmd->result = DID_OK << 16;
+ if (sensebuffer) {
+ int sense_data_length =
+ sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
+ ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
+ memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
+ memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+ sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+ sensebuffer->Valid = 1;
+ }
+}
+
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus)
+ & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
+ , &reg->outbound_intstatus);
+ return 0x00;
+ }
+ msleep_interruptible(10);
+ }/*max 1 seconds*/
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
+{
+ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+ int8_t *psge = (int8_t *)&arcmsr_cdb->u;
+ uint32_t address_lo, address_hi;
+ int arccdbsize = 0x30;
+
+ ccb->pcmd = pcmd;
+ memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
+ arcmsr_cdb->Bus = 0;
+ arcmsr_cdb->TargetID = pcmd->device->id;
+ arcmsr_cdb->LUN = pcmd->device->lun;
+ arcmsr_cdb->Function = 1;
+ arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
+ arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
+ memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
+ if (pcmd->use_sg) {
+ int length, sgcount, i, cdb_sgcount = 0;
+ struct scatterlist *sl;
+
+ /* Get Scatter Gather List from scsiport. */
+ sl = (struct scatterlist *) pcmd->request_buffer;
+ sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg,
+ pcmd->sc_data_direction);
+ /* map stor port SG list to our iop SG List. */
+ for (i = 0; i < sgcount; i++) {
+ /* Get the physical address of the current data pointer */
+ length = cpu_to_le32(sg_dma_len(sl));
+ address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
+ address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
+ if (address_hi == 0) {
+ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length;
+ psge += sizeof (struct SG32ENTRY);
+ arccdbsize += sizeof (struct SG32ENTRY);
+ } else {
+ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+
+ pdma_sg->addresshigh = address_hi;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length|IS_SG64_ADDR;
+ psge += sizeof (struct SG64ENTRY);
+ arccdbsize += sizeof (struct SG64ENTRY);
+ }
+ sl++;
+ cdb_sgcount++;
+ }
+ arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+ arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ if ( arccdbsize > 256)
+ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
+ } else if (pcmd->request_bufflen) {
+ dma_addr_t dma_addr;
+ dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer,
+ pcmd->request_bufflen, pcmd->sc_data_direction);
+ pcmd->SCp.dma_handle = dma_addr;
+ address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
+ address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
+ if (address_hi == 0) {
+ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = pcmd->request_bufflen;
+ } else {
+ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+ pdma_sg->addresshigh = address_hi;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
+ }
+ arcmsr_cdb->sgcount = 1;
+ arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ }
+ if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
+ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
+ ccb->ccb_flags |= CCB_FLAG_WRITE;
+ }
+}
+
+static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
+ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+
+ atomic_inc(&acb->ccboutstandingcount);
+ ccb->startdone = ARCMSR_CCB_START;
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ &reg->inbound_queueport);
+ else
+ writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+}
+
+void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
+ uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
+ int32_t allxfer_len = 0;
+
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
+ && (allxfer_len < 124)) {
+ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ writel(allxfer_len, &pwbuffer->data_len);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
+ , &reg->inbound_doorbell);
+ }
+}
+
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
+{
+ dma_free_coherent(&acb->pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
+ acb->dma_coherent,
+ acb->dma_coherent_handle);
+}
+
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+
+ outbound_intstatus = readl(&reg->outbound_intstatus)
+ & acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+ struct QBUFFER __iomem * prbuffer =
+ (struct QBUFFER __iomem *) &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+ rqbuf_lastindex = acb->rqbuf_lastindex;
+ rqbuf_firstindex = acb->rqbuf_firstindex;
+ iop_len = readl(&prbuffer->data_len);
+ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= iop_len) {
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ } else
+ acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+ }
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
+ if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+ struct QBUFFER __iomem * pwbuffer =
+ (struct QBUFFER __iomem *) &reg->message_wbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
+ int32_t allxfer_len = 0;
+
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
+ && (allxfer_len < 124)) {
+ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ writel(allxfer_len, &pwbuffer->data_len);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
+ &reg->inbound_doorbell);
+ }
+ if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ }
+ }
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+ int id, lun;
+ /*
+ ****************************************************************
+ ** areca cdb command done
+ ****************************************************************
+ */
+ while (1) {
+ if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
+ break;/*chip FIFO no ccb for completion already*/
+ /* check if command done with no error*/
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+ (flag_ccb << 5));
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd=ccb->pcmd;
+ if (abortcmd) {
+ abortcmd->result |= DID_ABORT >> 16;
+ arcmsr_ccb_complete(ccb, 1);
+ printk(KERN_NOTICE
+ "arcmsr%d: ccb='0x%p' isr got aborted command \n"
+ , acb->host->host_no, ccb);
+ }
+ continue;
+ }
+ printk(KERN_NOTICE
+ "arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
+ "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
+ " ccboutstandingcount=%d \n"
+ , acb->host->host_no
+ , acb
+ , ccb
+ , ccb->acb
+ , ccb->startdone
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_TIME_OUT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_ABORTED:
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d"
+ " isr get command error done,"
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ }/*drain reply FIFO*/
+ }
+ if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
+ return IRQ_NONE;
+ return IRQ_HANDLED;
+}
+
+static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
+{
+ if (acb) {
+ /* stop adapter background rebuild */
+ if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+ }
+ }
+}
+
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CMD_MESSAGE_FIELD *pcmdmessagefld;
+ int retvalue = 0, transfer_len = 0;
+ char *buffer;
+ uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
+ (uint32_t ) cmd->cmnd[6] << 16 |
+ (uint32_t ) cmd->cmnd[7] << 8 |
+ (uint32_t ) cmd->cmnd[8];
+ /* 4 bytes: Areca io control code */
+ if (cmd->use_sg) {
+ struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
+
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (cmd->use_sg > 1) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ transfer_len += sg->length;
+ } else {
+ buffer = cmd->request_buffer;
+ transfer_len = cmd->request_bufflen;
+ }
+ if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
+ switch(controlcode) {
+ case ARCMSR_MESSAGE_READ_RQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ uint8_t *pQbuffer, *ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpQbuffer = (uint8_t *) ver_addr;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
+ &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ memcpy(pcmdmessagefld->messagedatabuffer,
+ (uint8_t *)ver_addr, allxfer_len);
+ pcmdmessagefld->cmdmessage.Length = allxfer_len;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ }
+ break;
+ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpuserbuffer = (uint8_t *)ver_addr;
+ user_len = pcmdmessagefld->cmdmessage.Length;
+ memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ arcmsr_post_Qbuffer(acb);
+ /* has error report sensedata */
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_Qbuffer(acb);
+ }
+ } else {
+ /* has error report sensedata */
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ }
+ }
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
+ uint8_t *pQbuffer = acb->rqbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
+ uint8_t *pQbuffer = acb->wqbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
+ uint8_t *pQbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_RETURN_CODE_3F: {
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ }
+ break;
+ case ARCMSR_MESSAGE_SAY_HELLO: {
+ int8_t * hello_string = "Hello! I am ARCMSR";
+
+ memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+ , (int16_t)strlen(hello_string));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_SAY_GOODBYE:
+ arcmsr_iop_parking(acb);
+ break;
+ case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
+ arcmsr_flush_adapter_cache(acb);
+ break;
+ default:
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ }
+ message_out:
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ }
+ return retvalue;
+}
+
+static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
+{
+ struct list_head *head = &acb->ccb_free_list;
+ struct CommandControlBlock *ccb = NULL;
+
+ if (!list_empty(head)) {
+ ccb = list_entry(head->next, struct CommandControlBlock, list);
+ list_del(head->next);
+ }
+ return ccb;
+}
+
+static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
+ struct scsi_cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case INQUIRY: {
+ unsigned char inqdata[36];
+ char *buffer;
+
+ if (cmd->device->lun) {
+ cmd->result = (DID_TIME_OUT << 16);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ inqdata[0] = TYPE_PROCESSOR;
+ /* Periph Qualifier & Periph Dev Type */
+ inqdata[1] = 0;
+ /* rem media bit & Dev Type Modifier */
+ inqdata[2] = 0;
+ /* ISO,ECMA,& ANSI versions */
+ inqdata[4] = 31;
+ /* length of additional data */
+ strncpy(&inqdata[8], "Areca ", 8);
+ /* Vendor Identification */
+ strncpy(&inqdata[16], "RAID controller ", 16);
+ /* Product Identification */
+ strncpy(&inqdata[32], "R001", 4); /* Product Revision */
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ } else {
+ buffer = cmd->request_buffer;
+ }
+ memcpy(buffer, inqdata, sizeof(inqdata));
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ }
+ cmd->scsi_done(cmd);
+ }
+ break;
+ case WRITE_BUFFER:
+ case READ_BUFFER: {
+ if (arcmsr_iop_message_xfer(acb, cmd))
+ cmd->result = (DID_ERROR << 16);
+ cmd->scsi_done(cmd);
+ }
+ break;
+ default:
+ cmd->scsi_done(cmd);
+ }
+}
+
+static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+ void (* done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ struct CommandControlBlock *ccb;
+ int target = cmd->device->id;
+ int lun = cmd->device->lun;
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->result = 0;
+ if (acb->acb_flags & ACB_F_BUS_RESET) {
+ printk(KERN_NOTICE "arcmsr%d: bus reset"
+ " and return busy \n"
+ , acb->host->host_no);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ if(target == 16) {
+ /* virtual device for iop message transfer */
+ arcmsr_handle_virtual_command(acb, cmd);
+ return 0;
+ }
+ if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
+ uint8_t block_cmd;
+
+ block_cmd = cmd->cmnd[0] & 0x0f;
+ if (block_cmd == 0x08 || block_cmd == 0x0a) {
+ printk(KERN_NOTICE
+ "arcmsr%d: block 'read/write'"
+ "command with gone raid volume"
+ " Cmd=%2x, TargetId=%d, Lun=%d \n"
+ , acb->host->host_no
+ , cmd->cmnd[0]
+ , target, lun);
+ cmd->result = (DID_NO_CONNECT << 16);
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ }
+ if (atomic_read(&acb->ccboutstandingcount) >=
+ ARCMSR_MAX_OUTSTANDING_CMD)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ ccb = arcmsr_get_freeccb(acb);
+ if (!ccb)
+ return SCSI_MLQUEUE_HOST_BUSY;
+ arcmsr_build_ccb(acb, ccb, cmd);
+ arcmsr_post_ccb(acb, ccb);
+ return 0;
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ char *acb_firm_model = acb->firm_model;
+ char *acb_firm_version = acb->firm_version;
+ char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
+ char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+ int count;
+
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait "
+ "'get adapter firmware miscellaneous data' timeout \n"
+ , acb->host->host_no);
+ count = 8;
+ while (count) {
+ *acb_firm_model = readb(iop_firm_model);
+ acb_firm_model++;
+ iop_firm_model++;
+ count--;
+ }
+ count = 16;
+ while (count) {
+ *acb_firm_version = readb(iop_firm_version);
+ acb_firm_version++;
+ iop_firm_version++;
+ count--;
+ }
+ printk(KERN_INFO
+ "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+ , acb->host->host_no
+ , acb->firm_version);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
+ int id, lun;
+
+ polling_ccb_retry:
+ poll_count++;
+ outbound_intstatus = readl(&reg->outbound_intstatus)
+ & acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+ while (1) {
+ if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
+ if (poll_ccb_done)
+ break;
+ else {
+ msleep(25);
+ if (poll_count > 100)
+ break;
+ goto polling_ccb_retry;
+ }
+ }
+ ccb = (struct CommandControlBlock *)
+ (acb->vir2phy_offset + (flag_ccb << 5));
+ if ((ccb->acb != acb) ||
+ (ccb->startdone != ARCMSR_CCB_START)) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
+ (ccb == poll_ccb)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
+ " poll command abort successfully \n"
+ , acb->host->host_no
+ , ccb->pcmd->device->id
+ , ccb->pcmd->device->lun
+ , ccb);
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ poll_ccb_done = 1;
+ continue;
+ }
+ printk(KERN_NOTICE
+ "arcmsr%d: polling get an illegal ccb"
+ " command done ccb='0x%p'"
+ "ccboutstandingcount=%d \n"
+ , acb->host->host_no
+ , ccb
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_TIME_OUT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_ABORTED:
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d"
+ " polling and getting command error done"
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ }
+}
+
+static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
+ intmask_org = readl(&reg->outbound_intmask)
+ | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+ arcmsr_get_firmware_spec(acb);
+
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: "
+ "wait 'start adapter background rebulid' timeout\n",
+ acb->host->host_no);
+ }
+
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
+ | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(intmask_org & mask, &reg->outbound_intmask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+ acb->acb_flags |= ACB_F_IOP_INITED;
+}
+
+static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t intmask_org;
+ int i = 0;
+
+ if (atomic_read(&acb->ccboutstandingcount) != 0) {
+ /* talk to iop 331 outstanding command aborted */
+ arcmsr_abort_allcmd(acb);
+ /* wait for 3 sec for all command aborted*/
+ msleep_interruptible(3000);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ /* clear all outbound posted Q */
+ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+ readl(&reg->outbound_queueport);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb = acb->pccb_pool[i];
+ if ((ccb->startdone == ARCMSR_CCB_START) ||
+ (ccb->startdone == ARCMSR_CCB_ABORTED)) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ }
+ /* enable all outbound interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ atomic_set(&acb->ccboutstandingcount, 0);
+}
+
+static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)cmd->device->host->hostdata;
+ int i;
+
+ acb->num_resets++;
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ for (i = 0; i < 400; i++) {
+ if (!atomic_read(&acb->ccboutstandingcount))
+ break;
+ arcmsr_interrupt(acb);
+ msleep(25);
+ }
+ arcmsr_iop_reset(acb);
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ return SUCCESS;
+}
+
+static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *ccb)
+{
+ u32 intmask;
+
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+
+ /*
+ ** Wait for 3 sec for all command done.
+ */
+ msleep_interruptible(3000);
+
+ intmask = arcmsr_disable_outbound_ints(acb);
+ arcmsr_polling_ccbdone(acb, ccb);
+ arcmsr_enable_outbound_ints(acb, intmask);
+}
+
+static int arcmsr_abort(struct scsi_cmnd *cmd)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)cmd->device->host->hostdata;
+ int i = 0;
+
+ printk(KERN_NOTICE
+ "arcmsr%d: abort device command of scsi id=%d lun=%d \n",
+ acb->host->host_no, cmd->device->id, cmd->device->lun);
+ acb->num_aborts++;
+
+ /*
+ ************************************************
+ ** the all interrupt service routine is locked
+ ** we need to handle it as soon as possible and exit
+ ************************************************
+ */
+ if (!atomic_read(&acb->ccboutstandingcount))
+ return SUCCESS;
+
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ struct CommandControlBlock *ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
+ arcmsr_abort_one_cmd(acb, ccb);
+ break;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static const char *arcmsr_info(struct Scsi_Host *host)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ static char buf[256];
+ char *type;
+ int raid6 = 1;
+
+ switch (acb->pdev->device) {
+ case PCI_DEVICE_ID_ARECA_1110:
+ case PCI_DEVICE_ID_ARECA_1210:
+ raid6 = 0;
+ /*FALLTHRU*/
+ case PCI_DEVICE_ID_ARECA_1120:
+ case PCI_DEVICE_ID_ARECA_1130:
+ case PCI_DEVICE_ID_ARECA_1160:
+ case PCI_DEVICE_ID_ARECA_1170:
+ case PCI_DEVICE_ID_ARECA_1220:
+ case PCI_DEVICE_ID_ARECA_1230:
+ case PCI_DEVICE_ID_ARECA_1260:
+ case PCI_DEVICE_ID_ARECA_1270:
+ case PCI_DEVICE_ID_ARECA_1280:
+ type = "SATA";
+ break;
+ case PCI_DEVICE_ID_ARECA_1380:
+ case PCI_DEVICE_ID_ARECA_1381:
+ case PCI_DEVICE_ID_ARECA_1680:
+ case PCI_DEVICE_ID_ARECA_1681:
+ type = "SAS";
+ break;
+ default:
+ type = "X-TYPE";
+ break;
+ }
+ sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
+ type, raid6 ? "( RAID6 capable)" : "",
+ ARCMSR_DRIVER_VERSION);
+ return buf;
+}
+
+
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
index 06d7601cdf5..d006a8cb4a7 100644
--- a/drivers/scsi/arm/Kconfig
+++ b/drivers/scsi/arm/Kconfig
@@ -69,6 +69,7 @@ comment "The following drivers are not fully supported"
config SCSI_CUMANA_1
tristate "CumanaSCSI I support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the Cumana SCSI I card. If you have an
Acorn system with one of these, say Y. If unsure, say N.
@@ -76,6 +77,7 @@ config SCSI_CUMANA_1
config SCSI_ECOSCSI
tristate "EcoScsi support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the EcoSCSI card -- a small card that sits
in the Econet socket. If you have an Acorn system with one of these,
@@ -84,6 +86,7 @@ config SCSI_ECOSCSI
config SCSI_OAK1
tristate "Oak SCSI support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the Oak SCSI card. If you have an Acorn
system with one of these, say Y. If unsure, say N.
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index dda5a5f79c5..7621e3fa37b 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -129,7 +129,6 @@
#define STRx(x) STRINGIFY(x)
#define NO_WRITE_STR STRx(NO_WRITE)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -3031,7 +3030,7 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
if (!request_region(host->io_port, 2048, "acornscsi(ram)"))
goto err_5;
- ret = request_irq(host->irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", ashost);
+ ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost);
if (ret) {
printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
host->host_no, ashost->scsi.irq, ret);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index e6c9491dc5c..3bdfc36481a 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -277,7 +277,7 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
outb(0x00, host->io_port - 577);
- ret = request_irq(host->irq, cumanascsi_intr, SA_INTERRUPT,
+ ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index fad2109268b..719af0dcc0e 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -460,7 +460,7 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
goto out_free;
ret = request_irq(ec->irq, cumanascsi_2_intr,
- SA_INTERRUPT, "cumanascsi2", info);
+ IRQF_DISABLED, "cumanascsi2", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 3e1053f111d..4cf7afc31cc 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2427,7 +2427,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
info->stats.aborts += 1;
printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
- __scsi_print_command(SCpnt->data_cmnd);
+ __scsi_print_command(SCpnt->cmnd);
print_debug_list();
fas216_dumpstate(info);
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index 3d69f6c45a6..b2c346a4705 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -373,7 +373,7 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
goto out_free;
ret = request_irq(ec->irq, powertecscsi_intr,
- SA_INTERRUPT, "powertec", info);
+ IRQF_DISABLED, "powertec", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 6dd544a5eb5..8c2600ffc6a 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -74,7 +74,7 @@ static inline void init_SCp(Scsi_Cmnd *SCpnt)
unsigned long len = 0;
int buf;
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
+ SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
SCpnt->SCp.ptr = (char *)
(page_address(SCpnt->SCp.buffer->page) +
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
deleted file mode 100644
index 521b718763f..00000000000
--- a/drivers/scsi/ata_piix.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * ata_piix.c - Intel PATA/SATA controllers
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- *
- * Copyright 2003-2005 Red Hat Inc
- * Copyright 2003-2005 Jeff Garzik
- *
- *
- * Copyright header from piix.c:
- *
- * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available at http://developer.intel.com/
- *
- * Documentation
- * Publically available from Intel web site. Errata documentation
- * is also publically available. As an aide to anyone hacking on this
- * driver the list of errata that are relevant is below.going back to
- * PIIX4. Older device documentation is now a bit tricky to find.
- *
- * The chipsets all follow very much the same design. The orginal Triton
- * series chipsets do _not_ support independant device timings, but this
- * is fixed in Triton II. With the odd mobile exception the chips then
- * change little except in gaining more modes until SATA arrives. This
- * driver supports only the chips with independant timing (that is those
- * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
- * for the early chip drivers.
- *
- * Errata of note:
- *
- * Unfixable
- * PIIX4 errata #9 - Only on ultra obscure hw
- * ICH3 errata #13 - Not observed to affect real hw
- * by Intel
- *
- * Things we must deal with
- * PIIX4 errata #10 - BM IDE hang with non UDMA
- * (must stop/start dma to recover)
- * 440MX errata #15 - As PIIX4 errata #10
- * PIIX4 errata #15 - Must not read control registers
- * during a PIO transfer
- * 440MX errata #13 - As PIIX4 errata #15
- * ICH2 errata #21 - DMA mode 0 doesn't work right
- * ICH0/1 errata #55 - As ICH2 errata #21
- * ICH2 spec c #9 - Extra operations needed to handle
- * drive hotswap [NOT YET SUPPORTED]
- * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
- * and must be dword aligned
- * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
- *
- * Should have been BIOS fixed:
- * 450NX: errata #19 - DMA hangs on old 450NX
- * 450NX: errata #20 - DMA hangs on old 450NX
- * 450NX: errata #25 - Corruption with DMA on old 450NX
- * ICH3 errata #15 - IDE deadlock under high load
- * (BIOS must set dev 31 fn 0 bit 23)
- * ICH3 errata #18 - Don't use native mode
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "ata_piix"
-#define DRV_VERSION "1.10"
-
-enum {
- PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
- ICH5_PMR = 0x90, /* port mapping register */
- ICH5_PCS = 0x92, /* port control and status */
- PIIX_SCC = 0x0A, /* sub-class code register */
-
- PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */
- PIIX_FLAG_SCR = (1 << 26), /* SCR available */
- PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
- PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
- PIIX_FLAG_COMBINED = (1 << 29), /* combined mode possible */
- /* ICH6/7 use different scheme for map value */
- PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30),
-
- /* combined mode. if set, PATA is channel 0.
- * if clear, PATA is channel 1.
- */
- PIIX_PORT_ENABLED = (1 << 0),
- PIIX_PORT_PRESENT = (1 << 4),
-
- PIIX_80C_PRI = (1 << 5) | (1 << 4),
- PIIX_80C_SEC = (1 << 7) | (1 << 6),
-
- /* controller IDs */
- piix4_pata = 0,
- ich5_pata = 1,
- ich5_sata = 2,
- esb_sata = 3,
- ich6_sata = 4,
- ich6_sata_ahci = 5,
- ich6m_sata_ahci = 6,
-
- /* constants for mapping table */
- P0 = 0, /* port 0 */
- P1 = 1, /* port 1 */
- P2 = 2, /* port 2 */
- P3 = 3, /* port 3 */
- IDE = -1, /* IDE */
- NA = -2, /* not avaliable */
- RV = -3, /* reserved */
-
- PIIX_AHCI_DEVICE = 6,
-};
-
-struct piix_map_db {
- const u32 mask;
- const int map[][4];
-};
-
-static int piix_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
-static void piix_pata_error_handler(struct ata_port *ap);
-static void piix_sata_error_handler(struct ata_port *ap);
-
-static unsigned int in_module_init = 1;
-
-static const struct pci_device_id piix_pci_tbl[] = {
-#ifdef ATA_ENABLE_PATA
- { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
- { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
- { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
- { 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
-#endif
-
- /* NOTE: The following PCI ids must be kept in sync with the
- * list in drivers/pci/quirks.c.
- */
-
- /* 82801EB (ICH5) */
- { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
- /* 82801EB (ICH5) */
- { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
- /* 6300ESB (ICH5 variant with broken PCS present bits) */
- { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
- /* 6300ESB pretending RAID */
- { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
- /* 82801FB/FW (ICH6/ICH6W) */
- { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
- /* 82801FR/FRW (ICH6R/ICH6RW) */
- { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
- { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
- /* 82801GB/GR/GH (ICH7, identical to ICH6) */
- { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
- { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
- /* Enterprise Southbridge 2 (where's the datasheet?) */
- { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
- { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* SATA Controller 2 IDE (ICH8, ditto) */
- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
- /* Mobile SATA Controller IDE (ICH8M, ditto) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
-
- { } /* terminate list */
-};
-
-static struct pci_driver piix_pci_driver = {
- .name = DRV_NAME,
- .id_table = piix_pci_tbl,
- .probe = piix_init_one,
- .remove = ata_pci_remove_one,
- .suspend = ata_pci_device_suspend,
- .resume = ata_pci_device_resume,
-};
-
-static struct scsi_host_template piix_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
- .resume = ata_scsi_device_resume,
- .suspend = ata_scsi_device_suspend,
-};
-
-static const struct ata_port_operations piix_pata_ops = {
- .port_disable = ata_port_disable,
- .set_piomode = piix_set_piomode,
- .set_dmamode = piix_set_dmamode,
- .mode_filter = ata_pci_default_filter,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
-
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = piix_pata_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
-
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
-
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
-};
-
-static const struct ata_port_operations piix_sata_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
-
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = piix_sata_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
-
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
-
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
-};
-
-static struct piix_map_db ich5_map_db = {
- .mask = 0x7,
- .map = {
- /* PM PS SM SS MAP */
- { P0, NA, P1, NA }, /* 000b */
- { P1, NA, P0, NA }, /* 001b */
- { RV, RV, RV, RV },
- { RV, RV, RV, RV },
- { P0, P1, IDE, IDE }, /* 100b */
- { P1, P0, IDE, IDE }, /* 101b */
- { IDE, IDE, P0, P1 }, /* 110b */
- { IDE, IDE, P1, P0 }, /* 111b */
- },
-};
-
-static struct piix_map_db ich6_map_db = {
- .mask = 0x3,
- .map = {
- /* PM PS SM SS MAP */
- { P0, P2, P1, P3 }, /* 00b */
- { IDE, IDE, P1, P3 }, /* 01b */
- { P0, P2, IDE, IDE }, /* 10b */
- { RV, RV, RV, RV },
- },
-};
-
-static struct piix_map_db ich6m_map_db = {
- .mask = 0x3,
- .map = {
- /* PM PS SM SS MAP */
- { P0, P2, RV, RV }, /* 00b */
- { RV, RV, RV, RV },
- { P0, P2, IDE, IDE }, /* 10b */
- { RV, RV, RV, RV },
- },
-};
-
-static struct ata_port_info piix_port_info[] = {
- /* piix4_pata */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
-#if 0
- .mwdma_mask = 0x06, /* mwdma1-2 */
-#else
- .mwdma_mask = 0x00, /* mwdma broken */
-#endif
- .udma_mask = ATA_UDMA_MASK_40C,
- .port_ops = &piix_pata_ops,
- },
-
- /* ich5_pata */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio0-4 */
-#if 0
- .mwdma_mask = 0x06, /* mwdma1-2 */
-#else
- .mwdma_mask = 0x00, /* mwdma broken */
-#endif
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &piix_pata_ops,
- },
-
- /* ich5_sata */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
- PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
- },
-
- /* i6300esb_sata */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
- PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
- },
-
- /* ich6_sata */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
- },
-
- /* ich6_sata_ahci */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
- PIIX_FLAG_AHCI,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
- },
-
- /* ich6m_sata_ahci */
- {
- .sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
- PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
- PIIX_FLAG_AHCI,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &piix_sata_ops,
- .private_data = &ich6m_map_db,
- },
-};
-
-static struct pci_bits piix_enable_bits[] = {
- { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
- { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
-};
-
-MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
-MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-/**
- * piix_pata_cbl_detect - Probe host controller cable detect info
- * @ap: Port for which cable detect info is desired
- *
- * Read 80c cable indicator from ATA PCI device's PCI config
- * register. This register is normally set by firmware (BIOS).
- *
- * LOCKING:
- * None (inherited from caller).
- */
-static void piix_pata_cbl_detect(struct ata_port *ap)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- u8 tmp, mask;
-
- /* no 80c support in host controller? */
- if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
- goto cbl40;
-
- /* check BIOS cable detect results */
- mask = ap->hard_port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
- pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
- if ((tmp & mask) == 0)
- goto cbl40;
-
- ap->cbl = ATA_CBL_PATA80;
- return;
-
-cbl40:
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
-}
-
-/**
- * piix_pata_prereset - prereset for PATA host controller
- * @ap: Target port
- *
- * Prereset including cable detection.
- *
- * LOCKING:
- * None (inherited from caller).
- */
-static int piix_pata_prereset(struct ata_port *ap)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-
- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
- return 0;
- }
-
- piix_pata_cbl_detect(ap);
-
- return ata_std_prereset(ap);
-}
-
-static void piix_pata_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
- * piix_sata_prereset - prereset for SATA host controller
- * @ap: Target port
- *
- * Reads and configures SATA PCI device's PCI config register
- * Port Configuration and Status (PCS) to determine port and
- * device availability. Return -ENODEV to skip reset if no
- * device is present.
- *
- * LOCKING:
- * None (inherited from caller).
- *
- * RETURNS:
- * 0 if device is present, -ENODEV otherwise.
- */
-static int piix_sata_prereset(struct ata_port *ap)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- const unsigned int *map = ap->host_set->private_data;
- int base = 2 * ap->hard_port_no;
- unsigned int present_mask = 0;
- int port, i;
- u8 pcs;
-
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
- DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
-
- /* enable all ports on this ap and wait for them to settle */
- for (i = 0; i < 2; i++) {
- port = map[base + i];
- if (port >= 0)
- pcs |= 1 << port;
- }
-
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
- msleep(100);
-
- /* let's see which devices are present */
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-
- for (i = 0; i < 2; i++) {
- port = map[base + i];
- if (port < 0)
- continue;
- if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
- present_mask |= 1 << i;
- else
- pcs &= ~(1 << port);
- }
-
- /* disable offline ports on non-AHCI controllers */
- if (!(ap->flags & PIIX_FLAG_AHCI))
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
-
- DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
- ap->id, pcs, present_mask);
-
- if (!present_mask) {
- ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
- return 0;
- }
-
- return ata_std_prereset(ap);
-}
-
-static void piix_sata_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
- * piix_set_piomode - Initialize host controller PATA PIO timings
- * @ap: Port whose timings we are configuring
- * @adev: um
- *
- * Set PIO mode for device, in host controller PCI config space.
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
-{
- unsigned int pio = adev->pio_mode - XFER_PIO_0;
- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
- unsigned int is_slave = (adev->devno != 0);
- unsigned int master_port= ap->hard_port_no ? 0x42 : 0x40;
- unsigned int slave_port = 0x44;
- u16 master_data;
- u8 slave_data;
-
- static const /* ISP RTC */
- u8 timings[][2] = { { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
-
- pci_read_config_word(dev, master_port, &master_data);
- if (is_slave) {
- master_data |= 0x4000;
- /* enable PPE, IE and TIME */
- master_data |= 0x0070;
- pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data &= (ap->hard_port_no ? 0x0f : 0xf0);
- slave_data |=
- (timings[pio][0] << 2) |
- (timings[pio][1] << (ap->hard_port_no ? 4 : 0));
- } else {
- master_data &= 0xccf8;
- /* enable PPE, IE and TIME */
- master_data |= 0x0007;
- master_data |=
- (timings[pio][0] << 12) |
- (timings[pio][1] << 8);
- }
- pci_write_config_word(dev, master_port, master_data);
- if (is_slave)
- pci_write_config_byte(dev, slave_port, slave_data);
-}
-
-/**
- * piix_set_dmamode - Initialize host controller PATA PIO timings
- * @ap: Port whose timings we are configuring
- * @adev: um
- * @udma: udma mode, 0 - 6
- *
- * Set UDMA mode for device, in host controller PCI config space.
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
-{
- unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */
- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
- u8 maslave = ap->hard_port_no ? 0x42 : 0x40;
- u8 speed = udma;
- unsigned int drive_dn = (ap->hard_port_no ? 2 : 0) + adev->devno;
- int a_speed = 3 << (drive_dn * 4);
- int u_flag = 1 << drive_dn;
- int v_flag = 0x01 << drive_dn;
- int w_flag = 0x10 << drive_dn;
- int u_speed = 0;
- int sitre;
- u16 reg4042, reg4a;
- u8 reg48, reg54, reg55;
-
- pci_read_config_word(dev, maslave, &reg4042);
- DPRINTK("reg4042 = 0x%04x\n", reg4042);
- sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_word(dev, 0x4a, &reg4a);
- pci_read_config_byte(dev, 0x54, &reg54);
- pci_read_config_byte(dev, 0x55, &reg55);
-
- switch(speed) {
- case XFER_UDMA_4:
- case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break;
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_3:
- case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break;
- case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break;
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1: break;
- default:
- BUG();
- return;
- }
-
- if (speed >= XFER_UDMA_0) {
- if (!(reg48 & u_flag))
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- if (speed == XFER_UDMA_5) {
- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
- } else {
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
- if ((reg4a & a_speed) != u_speed)
- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
- if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag))
- pci_write_config_byte(dev, 0x54, reg54 | v_flag);
- } else
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- } else {
- if (reg48 & u_flag)
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- if (reg4a & a_speed)
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- if (reg54 & v_flag)
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- if (reg55 & w_flag)
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
-}
-
-#define AHCI_PCI_BAR 5
-#define AHCI_GLOBAL_CTL 0x04
-#define AHCI_ENABLE (1 << 31)
-static int piix_disable_ahci(struct pci_dev *pdev)
-{
- void __iomem *mmio;
- u32 tmp;
- int rc = 0;
-
- /* BUG: pci_enable_device has not yet been called. This
- * works because this device is usually set up by BIOS.
- */
-
- if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
- !pci_resource_len(pdev, AHCI_PCI_BAR))
- return 0;
-
- mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
- if (!mmio)
- return -ENOMEM;
-
- tmp = readl(mmio + AHCI_GLOBAL_CTL);
- if (tmp & AHCI_ENABLE) {
- tmp &= ~AHCI_ENABLE;
- writel(tmp, mmio + AHCI_GLOBAL_CTL);
-
- tmp = readl(mmio + AHCI_GLOBAL_CTL);
- if (tmp & AHCI_ENABLE)
- rc = -EIO;
- }
-
- pci_iounmap(pdev, mmio);
- return rc;
-}
-
-/**
- * piix_check_450nx_errata - Check for problem 450NX setup
- * @ata_dev: the PCI device to check
- *
- * Check for the present of 450NX errata #19 and errata #25. If
- * they are found return an error code so we can turn off DMA
- */
-
-static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
-{
- struct pci_dev *pdev = NULL;
- u16 cfg;
- u8 rev;
- int no_piix_dma = 0;
-
- while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
- {
- /* Look for 450NX PXB. Check for problem configurations
- A PCI quirk checks bit 6 already */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- pci_read_config_word(pdev, 0x41, &cfg);
- /* Only on the original revision: IDE DMA can hang */
- if (rev == 0x00)
- no_piix_dma = 1;
- /* On all revisions below 5 PXB bus lock must be disabled for IDE */
- else if (cfg & (1<<14) && rev < 5)
- no_piix_dma = 2;
- }
- if (no_piix_dma)
- dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
- if (no_piix_dma == 2)
- dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
- return no_piix_dma;
-}
-
-static void __devinit piix_init_sata_map(struct pci_dev *pdev,
- struct ata_port_info *pinfo)
-{
- struct piix_map_db *map_db = pinfo[0].private_data;
- const unsigned int *map;
- int i, invalid_map = 0;
- u8 map_value;
-
- pci_read_config_byte(pdev, ICH5_PMR, &map_value);
-
- map = map_db->map[map_value & map_db->mask];
-
- dev_printk(KERN_INFO, &pdev->dev, "MAP [");
- for (i = 0; i < 4; i++) {
- switch (map[i]) {
- case RV:
- invalid_map = 1;
- printk(" XX");
- break;
-
- case NA:
- printk(" --");
- break;
-
- case IDE:
- WARN_ON((i & 1) || map[i + 1] != IDE);
- pinfo[i / 2] = piix_port_info[ich5_pata];
- i++;
- printk(" IDE IDE");
- break;
-
- default:
- printk(" P%d", map[i]);
- if (i & 1)
- pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
- break;
- }
- }
- printk(" ]\n");
-
- if (invalid_map)
- dev_printk(KERN_ERR, &pdev->dev,
- "invalid MAP value %u\n", map_value);
-
- pinfo[0].private_data = (void *)map;
- pinfo[1].private_data = (void *)map;
-}
-
-/**
- * piix_init_one - Register PIIX ATA PCI device with kernel services
- * @pdev: PCI device to register
- * @ent: Entry in piix_pci_tbl matching with @pdev
- *
- * Called from kernel PCI layer. We probe for combined mode (sigh),
- * and then hand over control to libata, for it to do the rest.
- *
- * LOCKING:
- * Inherited from PCI layer (may sleep).
- *
- * RETURNS:
- * Zero on success, or -ERRNO value.
- */
-
-static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_port_info port_info[2];
- struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
- unsigned long host_flags;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev,
- "version " DRV_VERSION "\n");
-
- /* no hotplugging support (FIXME) */
- if (!in_module_init)
- return -ENODEV;
-
- port_info[0] = piix_port_info[ent->driver_data];
- port_info[1] = piix_port_info[ent->driver_data];
-
- host_flags = port_info[0].host_flags;
-
- if (host_flags & PIIX_FLAG_AHCI) {
- u8 tmp;
- pci_read_config_byte(pdev, PIIX_SCC, &tmp);
- if (tmp == PIIX_AHCI_DEVICE) {
- int rc = piix_disable_ahci(pdev);
- if (rc)
- return rc;
- }
- }
-
- /* Initialize SATA map */
- if (host_flags & ATA_FLAG_SATA)
- piix_init_sata_map(pdev, port_info);
-
- /* On ICH5, some BIOSen disable the interrupt using the
- * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
- * On ICH6, this bit has the same effect, but only when
- * MSI is disabled (and it is disabled, as we don't use
- * message-signalled interrupts currently).
- */
- if (host_flags & PIIX_FLAG_CHECKINTR)
- pci_intx(pdev, 1);
-
- if (piix_check_450nx_errata(pdev)) {
- /* This writes into the master table but it does not
- really matter for this errata as we will apply it to
- all the PIIX devices on the board */
- port_info[0].mwdma_mask = 0;
- port_info[0].udma_mask = 0;
- port_info[1].mwdma_mask = 0;
- port_info[1].udma_mask = 0;
- }
- return ata_pci_init_one(pdev, ppinfo, 2);
-}
-
-static int __init piix_init(void)
-{
- int rc;
-
- DPRINTK("pci_module_init\n");
- rc = pci_module_init(&piix_pci_driver);
- if (rc)
- return rc;
-
- in_module_init = 0;
-
- DPRINTK("done\n");
- return 0;
-}
-
-static void __exit piix_exit(void)
-{
- pci_unregister_driver(&piix_pci_driver);
-}
-
-module_init(piix_init);
-module_exit(piix_exit);
-
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 57295bcea3e..e397129c90d 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -507,7 +507,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
cmd->SCp.buffer->offset;
@@ -524,7 +524,6 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
}
}
-#include <linux/config.h>
#include <linux/delay.h>
#if NDEBUG
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index f677c5a32a6..e1be4a4387c 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -65,7 +65,6 @@
-#include <linux/config.h>
#include <linux/module.h>
#define NDEBUG (0)
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 3ee4d4d3f44..0ec41f34f46 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -2625,29 +2625,32 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
unsigned int base_io, tmport, error,n;
unsigned char host_id;
struct Scsi_Host *shpnt = NULL;
- struct atp_unit atp_dev, *p;
+ struct atp_unit *atpdev, *p;
unsigned char setupdata[2][16];
int count = 0;
-
+
+ atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
+ if (!atpdev)
+ return -ENOMEM;
+
if (pci_enable_device(pdev))
- return -EIO;
+ goto err_eio;
if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
} else {
printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
- return -EIO;
+ goto err_eio;
}
- memset(&atp_dev, 0, sizeof atp_dev);
/*
* It's probably easier to weed out some revisions like
* this than via the PCI device table
*/
if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
- error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
- if (atp_dev.chip_ver < 2)
- return -EIO;
+ error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
+ if (atpdev->chip_ver < 2)
+ goto err_eio;
}
switch (ent->device) {
@@ -2656,15 +2659,15 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case ATP880_DEVID1:
case ATP880_DEVID2:
case ATP885_DEVID:
- atp_dev.chip_ver = 0x04;
+ atpdev->chip_ver = 0x04;
default:
break;
}
base_io = pci_resource_start(pdev, 0);
base_io &= 0xfffffff8;
-
+
if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
- error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+ error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
host_id = inb(base_io + 0x39);
@@ -2672,17 +2675,17 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
" IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atp_dev.ioport[0] = base_io + 0x40;
- atp_dev.pciport[0] = base_io + 0x28;
- atp_dev.dev_id = ent->device;
- atp_dev.host_id[0] = host_id;
+ atpdev->ioport[0] = base_io + 0x40;
+ atpdev->pciport[0] = base_io + 0x28;
+ atpdev->dev_id = ent->device;
+ atpdev->host_id[0] = host_id;
tmport = base_io + 0x22;
- atp_dev.scam_on = inb(tmport);
+ atpdev->scam_on = inb(tmport);
tmport += 0x13;
- atp_dev.global_map[0] = inb(tmport);
+ atpdev->global_map[0] = inb(tmport);
tmport += 0x07;
- atp_dev.ultra_map[0] = inw(tmport);
+ atpdev->ultra_map[0] = inw(tmport);
n = 0x3f09;
next_fblk_880:
@@ -2695,63 +2698,63 @@ next_fblk_880:
if (inb(base_io + 0x30) == 0xff)
goto flash_ok_880;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
n += 0x0018;
goto next_fblk_880;
flash_ok_880:
outw(0, base_io + 0x34);
- atp_dev.ultra_map[0] = 0;
- atp_dev.async[0] = 0;
+ atpdev->ultra_map[0] = 0;
+ atpdev->async[0] = 0;
for (k = 0; k < 16; k++) {
n = 1;
n = n << k;
- if (atp_dev.sp[0][k] > 1) {
- atp_dev.ultra_map[0] |= n;
+ if (atpdev->sp[0][k] > 1) {
+ atpdev->ultra_map[0] |= n;
} else {
- if (atp_dev.sp[0][k] == 0)
- atp_dev.async[0] |= n;
+ if (atpdev->sp[0][k] == 0)
+ atpdev->async[0] |= n;
}
}
- atp_dev.async[0] = ~(atp_dev.async[0]);
- outb(atp_dev.global_map[0], base_io + 0x35);
+ atpdev->async[0] = ~(atpdev->async[0]);
+ outb(atpdev->global_map[0], base_io + 0x35);
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof atp_dev);
+ memcpy(p, atpdev, sizeof(*atpdev));
if (atp870u_init_tables(shpnt) < 0) {
printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
goto unregister;
}
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp880i", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
goto free_tables;
}
@@ -2798,31 +2801,31 @@ flash_ok_880:
printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
, base_io, pdev->irq);
- atp_dev.pdev = pdev;
- atp_dev.dev_id = ent->device;
- atp_dev.baseport = base_io;
- atp_dev.ioport[0] = base_io + 0x80;
- atp_dev.ioport[1] = base_io + 0xc0;
- atp_dev.pciport[0] = base_io + 0x40;
- atp_dev.pciport[1] = base_io + 0x50;
+ atpdev->pdev = pdev;
+ atpdev->dev_id = ent->device;
+ atpdev->baseport = base_io;
+ atpdev->ioport[0] = base_io + 0x80;
+ atpdev->ioport[1] = base_io + 0xc0;
+ atpdev->pciport[0] = base_io + 0x40;
+ atpdev->pciport[1] = base_io + 0x50;
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof(struct atp_unit));
+ memcpy(p, atpdev, sizeof(struct atp_unit));
if (atp870u_init_tables(shpnt) < 0)
goto unregister;
#ifdef ED_DBGP
printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
#endif
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
goto free_tables;
}
@@ -2974,43 +2977,43 @@ flash_ok_885:
printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
"IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atp_dev.ioport[0] = base_io;
- atp_dev.pciport[0] = base_io + 0x20;
- atp_dev.dev_id = ent->device;
+ atpdev->ioport[0] = base_io;
+ atpdev->pciport[0] = base_io + 0x20;
+ atpdev->dev_id = ent->device;
host_id &= 0x07;
- atp_dev.host_id[0] = host_id;
+ atpdev->host_id[0] = host_id;
tmport = base_io + 0x22;
- atp_dev.scam_on = inb(tmport);
+ atpdev->scam_on = inb(tmport);
tmport += 0x0b;
- atp_dev.global_map[0] = inb(tmport++);
- atp_dev.ultra_map[0] = inw(tmport);
+ atpdev->global_map[0] = inb(tmport++);
+ atpdev->ultra_map[0] = inw(tmport);
- if (atp_dev.ultra_map[0] == 0) {
- atp_dev.scam_on = 0x00;
- atp_dev.global_map[0] = 0x20;
- atp_dev.ultra_map[0] = 0xffff;
+ if (atpdev->ultra_map[0] == 0) {
+ atpdev->scam_on = 0x00;
+ atpdev->global_map[0] = 0x20;
+ atpdev->ultra_map[0] = 0xffff;
}
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof atp_dev);
+ memcpy(p, atpdev, sizeof(*atpdev));
if (atp870u_init_tables(shpnt) < 0)
goto unregister;
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870i", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
goto free_tables;
}
spin_lock_irqsave(shpnt->host_lock, flags);
- if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
+ if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
tmport = base_io + 0x3e;
outb(0x00, tmport);
}
@@ -3044,7 +3047,7 @@ flash_ok_885:
outb((inb(tmport) & 0xef), tmport);
tmport++;
outb((inb(tmport) | 0x20), tmport);
- if (atp_dev.chip_ver == 4)
+ if (atpdev->chip_ver == 4)
shpnt->max_id = 16;
else
shpnt->max_id = 8;
@@ -3093,6 +3096,12 @@ unregister:
printk("atp870u_prob:unregister\n");
scsi_host_put(shpnt);
return -1;
+err_eio:
+ kfree(atpdev);
+ return -EIO;
+err_nomem:
+ kfree(atpdev);
+ return -ENOMEM;
}
/* The abort command does not leave the device in a clean state where
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 3867ac2de4c..329a8f297b3 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -172,7 +172,7 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+REAL_BLZ1230_ESP_ADDR;
- if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Blizzard 1230 SCSI IV", esp->ehost))
goto err_out;
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index 4ebe69e3275..b6c137b9735 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -146,7 +146,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Blizzard 2060 SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index d9abd1645d1..f6caa430776 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -7,7 +7,6 @@
#define VERSION "0.25"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index d92d5040a9f..61f6024b61b 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -5,9 +5,9 @@
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
* Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
+ * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702
*/
-#include <linux/config.h>
#include <linux/blkdev.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -37,55 +37,56 @@ static const char * cdb_byte0_names[] = {
/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
"Reasssign Blocks",
-/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL,
+/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
-/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)",
- "Reserve (6)",
-/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)",
+/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
+ "Reserve(6)",
+/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)",
/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
/* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
/* 20-22 */ NULL, NULL, NULL,
/* 23-28 */ "Read Format Capacities", "Set Window",
- "Read Capacity (10)", NULL, NULL, "Read (10)",
-/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)",
- "Read updated block",
-/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal",
+ "Read Capacity(10)", NULL, NULL, "Read(10)",
+/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
+ "Read updated block",
+/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
-/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)",
+/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
"Read Defect Data(10)",
/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
"Read Buffer",
-/* 3d-3f */ "Update Block", "Read Long (10)", "Write Long (10)",
-/* 40-41 */ "Change Definition", "Write Same (10)",
+/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
+/* 40-41 */ "Change Definition", "Write Same(10)",
/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
- "Play audio (10)", "Get configuration", "Play audio msf",
+ "Play audio(10)", "Get configuration", "Play audio msf",
"Play audio track/index",
-/* 49-4f */ "Play track relative (10)", "Get event status notification",
+/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info",
- "Reserve track", "Send OPC info", "Mode Select (10)",
-/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue",
- "Mode Sense (10)", "Close track/session",
+ "Reserve track", "Send OPC info", "Mode Select(10)",
+/* 56-5b */ "Reserve(10)", "Release(10)", "Repair track", "Read master cue",
+ "Mode Sense(10)", "Close track/session",
/* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in",
"Persistent reserve out",
/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
-/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy",
+/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
"Receive copy results",
-/* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out",
- "Read (16)", "Memory Export Out (16)",
-/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes",
- "Write and verify (16)", "Verify (16)",
-/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)",
- "Lock/unlock cache (16)", "Write same (16)", NULL,
+/* 85-89 */ "ATA command pass through(16)", "Access control in",
+ "Access control out", "Read(16)", "Memory Export Out(16)",
+/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes",
+ "Write and verify(16)", "Verify(16)",
+/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
+ "Lock/unlock cache(16)", "Write same(16)", NULL,
/* 95-99 */ NULL, NULL, NULL, NULL, NULL,
-/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)",
- "Service action out (16)",
-/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in",
- "Maintenance out", "Move medium/play audio(12)",
+/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)",
+ "Service action out(16)",
+/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank",
+ "Security protocol in", "Maintenance in", "Maintenance out",
+ "Move medium/play audio(12)",
/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)",
"Play track relative(12)",
/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance",
@@ -93,12 +94,12 @@ static const char * cdb_byte0_names[] = {
/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
/* b2-b4 */ "Search data low(12)", "Set limits(12)",
"Read element status attached",
-/* b5-b6 */ "Request volume element address", "Send volume tag, set streaming",
+/* b5-b6 */ "Security protocol out", "Send volume tag, set streaming",
/* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf",
/* ba-bc */ "Redundancy group (in), Scan",
- "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd",
-/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd",
- "Volume set out, Send DVD structure",
+ "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd",
+/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd",
+ "Volume set (out), Send DVD structure",
};
struct value_name_pair {
@@ -113,6 +114,7 @@ static const struct value_name_pair maint_in_arr[] = {
{0xc, "Report supported operation codes"},
{0xd, "Report supported task management functions"},
{0xe, "Report priority"},
+ {0xf, "Report timestamp"},
};
#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
@@ -121,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = {
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
{0xe, "Set priority"},
+ {0xe, "Set timestamp"},
};
#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
@@ -428,6 +431,7 @@ static struct error_info additional[] =
{0x001A, "Rewind operation in progress"},
{0x001B, "Set capacity operation in progress"},
{0x001C, "Verify operation in progress"},
+ {0x001D, "ATA pass through information available"},
{0x0100, "No index/sector signal"},
@@ -439,7 +443,7 @@ static struct error_info additional[] =
{0x0400, "Logical unit not ready, cause not reportable"},
{0x0401, "Logical unit is in process of becoming ready"},
- {0x0402, "Logical unit not ready, initializing cmd. required"},
+ {0x0402, "Logical unit not ready, initializing command required"},
{0x0403, "Logical unit not ready, manual intervention required"},
{0x0404, "Logical unit not ready, format in progress"},
{0x0405, "Logical unit not ready, rebuild in progress"},
@@ -479,6 +483,9 @@ static struct error_info additional[] =
{0x0B00, "Warning"},
{0x0B01, "Warning - specified temperature exceeded"},
{0x0B02, "Warning - enclosure degraded"},
+ {0x0B03, "Warning - background self-test failed"},
+ {0x0B04, "Warning - background pre-scan detected medium error"},
+ {0x0B05, "Warning - background medium scan detected medium error"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@@ -494,6 +501,7 @@ static struct error_info additional[] =
{0x0C0B, "Auxiliary memory write error"},
{0x0C0C, "Write error - unexpected unsolicited data"},
{0x0C0D, "Write error - not enough unsolicited data"},
+ {0x0C0F, "Defects in error window"},
{0x0D00, "Error detected by third party temporary initiator"},
{0x0D01, "Third party device failure"},
@@ -505,11 +513,12 @@ static struct error_info additional[] =
{0x0E00, "Invalid information unit"},
{0x0E01, "Information unit too short"},
{0x0E02, "Information unit too long"},
+ {0x0E03, "Invalid field in command information unit"},
{0x1000, "Id CRC or ECC error"},
- {0x1001, "Data block guard check failed"},
- {0x1002, "Data block application tag check failed"},
- {0x1003, "Data block reference tag check failed"},
+ {0x1001, "Logical block guard check failed"},
+ {0x1002, "Logical block application tag check failed"},
+ {0x1003, "Logical block reference tag check failed"},
{0x1100, "Unrecovered read error"},
{0x1101, "Read retries exhausted"},
@@ -531,6 +540,7 @@ static struct error_info additional[] =
{0x1111, "Read error - loss of streaming"},
{0x1112, "Auxiliary memory read error"},
{0x1113, "Read error - failed retransmission request"},
+ {0x1114, "Read error - lba marked bad by application client"},
{0x1200, "Address mark not found for id field"},
@@ -611,11 +621,14 @@ static struct error_info additional[] =
{0x2100, "Logical block address out of range"},
{0x2101, "Invalid element address"},
{0x2102, "Invalid address for write"},
+ {0x2103, "Invalid write crossing layer jump"},
{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
{0x2400, "Invalid field in cdb"},
{0x2401, "CDB decryption error"},
+ {0x2402, "Obsolete"},
+ {0x2403, "Obsolete"},
{0x2404, "Security audit value frozen"},
{0x2405, "Security working key frozen"},
{0x2406, "Nonce not unique"},
@@ -638,7 +651,10 @@ static struct error_info additional[] =
{0x260C, "Invalid operation for copy source or destination"},
{0x260D, "Copy segment granularity violation"},
{0x260E, "Invalid parameter while port is enabled"},
- {0x260F, "Invalid data-out buffer integrity"},
+ {0x260F, "Invalid data-out buffer integrity check value"},
+ {0x2610, "Data decryption key fail limit reached"},
+ {0x2611, "Incomplete key-associated data set"},
+ {0x2612, "Vendor specific key reference not found"},
{0x2700, "Write protected"},
{0x2701, "Hardware write protected"},
@@ -650,6 +666,7 @@ static struct error_info additional[] =
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
+ {0x2802, "Format-layer may have changed"},
{0x2900, "Power on, reset, or bus device reset occurred"},
{0x2901, "Power on occurred"},
@@ -670,6 +687,11 @@ static struct error_info additional[] =
{0x2A07, "Implicit asymmetric access state transition failed"},
{0x2A08, "Priority changed"},
{0x2A09, "Capacity data has changed"},
+ {0x2A10, "Timestamp changed"},
+ {0x2A11, "Data encryption parameters changed by another i_t nexus"},
+ {0x2A12, "Data encryption parameters changed by vendor specific "
+ "event"},
+ {0x2A13, "Data encryption key instance counter has changed"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@@ -691,6 +713,7 @@ static struct error_info additional[] =
{0x2E00, "Insufficient time for operation"},
{0x2F00, "Commands cleared by another initiator"},
+ {0x2F01, "Commands cleared by power loss notification"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -703,7 +726,8 @@ static struct error_info additional[] =
{0x3008, "Cannot write - application code mismatch"},
{0x3009, "Current session not fixated for append"},
{0x300A, "Cleaning request rejected"},
- {0x300C, "WORM medium, overwrite attempted"},
+ {0x300C, "WORM medium - overwrite attempted"},
+ {0x300D, "WORM medium - integrity check"},
{0x3010, "Medium not formatted"},
{0x3100, "Medium format corrupted"},
@@ -791,6 +815,9 @@ static struct error_info additional[] =
{0x3F0F, "Echo buffer overwritten"},
{0x3F10, "Medium loadable"},
{0x3F11, "Medium auxiliary memory accessible"},
+ {0x3F12, "iSCSI IP address added"},
+ {0x3F13, "iSCSI IP address removed"},
+ {0x3F14, "iSCSI IP address changed"},
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
@@ -800,6 +827,7 @@ static struct error_info additional[] =
{0x4300, "Message error"},
{0x4400, "Internal target failure"},
+ {0x4471, "ATA device failed set features"},
{0x4500, "Select or reselect failure"},
@@ -808,9 +836,10 @@ static struct error_info additional[] =
{0x4700, "Scsi parity error"},
{0x4701, "Data phase CRC error detected"},
{0x4702, "Scsi parity error detected during st data phase"},
- {0x4703, "Information unit CRC error detected"},
+ {0x4703, "Information unit iuCRC error detected"},
{0x4704, "Asynchronous information protection error detected"},
{0x4705, "Protocol service CRC error"},
+ {0x4706, "Phy test function in progress"},
{0x477f, "Some commands cleared by iSCSI Protocol event"},
{0x4800, "Initiator detected error message received"},
@@ -845,6 +874,8 @@ static struct error_info additional[] =
{0x5300, "Media load or eject failed"},
{0x5301, "Unload tape failure"},
{0x5302, "Medium removal prevented"},
+ {0x5303, "Medium removal prevented by data transfer element"},
+ {0x5304, "Medium thread or unthread failure"},
{0x5400, "Scsi to host system interface failure"},
@@ -856,6 +887,7 @@ static struct error_info additional[] =
{0x5505, "Insufficient access control resources"},
{0x5506, "Auxiliary memory out of space"},
{0x5507, "Quota error"},
+ {0x5508, "Maximum number of supplemental decryption keys exceeded"},
{0x5700, "Unable to recover table-of-contents"},
@@ -1005,6 +1037,7 @@ static struct error_info additional[] =
{0x6708, "Assign failure occurred"},
{0x6709, "Multiply assigned logical unit"},
{0x670A, "Set target port groups command failed"},
+ {0x670B, "ATA device feature not enabled"},
{0x6800, "Logical unit not configured"},
@@ -1031,6 +1064,8 @@ static struct error_info additional[] =
{0x6F03, "Read of scrambled sector without authentication"},
{0x6F04, "Media region code is mismatched to logical unit region"},
{0x6F05, "Drive region must be permanent/region reset count error"},
+ {0x6F06, "Insufficient block count for binding nonce recording"},
+ {0x6F07, "Conflict in binding nonce recording"},
/*
* {0x70NN, "Decompression exception short algorithm id of nn"},
*/
@@ -1042,6 +1077,8 @@ static struct error_info additional[] =
{0x7203, "Session fixation error - incomplete track in session"},
{0x7204, "Empty or partially written reserved track"},
{0x7205, "No more track reservations allowed"},
+ {0x7206, "RMZ extension is not allowed"},
+ {0x7207, "No more test zone extensions are allowed"},
{0x7300, "Cd control error"},
{0x7301, "Power calibration area almost full"},
@@ -1050,6 +1087,18 @@ static struct error_info additional[] =
{0x7304, "Program memory area update failure"},
{0x7305, "Program memory area is full"},
{0x7306, "RMA/PMA is almost full"},
+ {0x7310, "Current power calibration area almost full"},
+ {0x7311, "Current power calibration area is full"},
+ {0x7317, "RDZ is full"},
+
+ {0x7400, "Security error"},
+ {0x7401, "Unable to decrypt data"},
+ {0x7402, "Unencrypted data encountered while decrypting"},
+ {0x7403, "Incorrect data encryption key"},
+ {0x7404, "Cryptographic integrity validation failed"},
+ {0x7405, "Error decrypting data"},
+ {0x7471, "Logical unit access not authorized"},
+
{0, NULL}
};
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index a4a4fac5c0a..7c7cfb54e89 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -172,7 +172,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"CyberStorm SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
/* The DMA cond flag contains a hardcoded jumper bit
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index 3a803d73bc5..d88cb9cf091 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -153,7 +153,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"CyberStorm SCSI Mk II", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 18324525493..ff2b1796fa3 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -3771,7 +3771,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
* @target: The target for the new device.
* @lun: The lun for the new device.
*
- * Return the new device if succesfull or NULL on failure.
+ * Return the new device if successful or NULL on failure.
**/
static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
u8 target, u8 lun)
@@ -4562,7 +4562,7 @@ static int __devinit adapter_init(struct AdapterCtlBlk *acb,
acb->io_port_base = io_port;
acb->io_port_len = io_port_len;
- if (request_irq(irq, dc395x_interrupt, SA_SHIRQ, DC395X_NAME, acb)) {
+ if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) {
/* release the region we just claimed */
dprintkl(KERN_INFO, "Failed to register IRQ\n");
goto failed;
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index a35ee43a48d..eb32062f7e6 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -202,19 +202,19 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
esp_initialize(esp);
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"ncr53c94", esp->ehost))
goto err_dealloc;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
- scsi_dma_merr_int, SA_INTERRUPT,
+ scsi_dma_merr_int, IRQF_DISABLED,
"ncr53c94 error", esp->ehost))
goto err_free_irq;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
- scsi_dma_err_int, SA_INTERRUPT,
+ scsi_dma_err_int, IRQF_DISABLED,
"ncr53c94 overrun", esp->ehost))
goto err_free_irq_merr;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
- scsi_dma_int, SA_INTERRUPT,
+ scsi_dma_int, IRQF_DISABLED,
"ncr53c94 dma", esp->ehost))
goto err_free_irq_err;
@@ -276,7 +276,7 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
esp->dma_mmu_release_scsi_sgl = 0;
esp->dma_advance_sg = 0;
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"PMAZ_AA", esp->ehost)) {
esp_deallocate(esp);
release_tc_card(slot);
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 38e4010eff9..879a2665767 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -94,7 +94,7 @@ static int __devinit dmx3191d_probe_one(struct pci_dev *pdev,
NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
- if (request_irq(pdev->irq, NCR5380_intr, SA_SHIRQ,
+ if (request_irq(pdev->irq, NCR5380_intr, IRQF_SHARED,
DMX3191D_DRIVER_NAME, shost)) {
/*
* Steam powered scsi controllers run without an IRQ anyway
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index a9585f5235d..d84a281ad94 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -23,7 +23,6 @@
#include <asm/semaphore.h> /* Needed for MUTEX init macros */
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/notifier.h>
#include <asm/atomic.h>
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b1b704a42ef..7b3bd34faf4 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -46,7 +46,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
-#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/pci.h> /* for PCI support */
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
@@ -185,7 +184,7 @@ static int adpt_detect(struct scsi_host_template* sht)
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
- while ((pDev = pci_find_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
+ while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
if(pDev->device == PCI_DPT_DEVICE_ID ||
pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
if(adpt_install_hba(sht, pDev) ){
@@ -193,8 +192,11 @@ static int adpt_detect(struct scsi_host_template* sht)
PERROR("Will not try to detect others.\n");
return hba_count-1;
}
+ pci_dev_get(pDev);
}
}
+ if (pDev)
+ pci_dev_put(pDev);
/* In INIT state, Activate IOPs */
for (pHba = hba_chain; pHba; pHba = pHba->next) {
@@ -1009,7 +1011,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
}
- if (request_irq (pDev->irq, adpt_isr, SA_SHIRQ, pHba->name, pHba)) {
+ if (request_irq (pDev->irq, adpt_isr, IRQF_SHARED, pHba->name, pHba)) {
printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq);
adpt_i2o_delete_hba(pHba);
return -EINVAL;
@@ -1076,6 +1078,7 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
}
}
}
+ pci_dev_put(pHba->pDev);
kfree(pHba);
if(hba_count <= 0){
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index c5108c8c887..0d5713dfa20 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -280,7 +280,7 @@ found:
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc", instance)) {
+ if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED, "dtc", instance)) {
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 059eeee4b55..a5ff43b1b26 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -477,7 +477,6 @@
* the driver sets host->wish_block = 1 for all ISA boards.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -1222,7 +1221,7 @@ static int port_detect(unsigned long port_base, unsigned int j,
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+ IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
driver_name, (void *)&sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name,
irq);
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
index 34bce2c9e92..635c14861f8 100644
--- a/drivers/scsi/eata_generic.h
+++ b/drivers/scsi/eata_generic.h
@@ -364,6 +364,7 @@ typedef struct hstd {
__u8 moresupport; /* HBA supports MORE flag */
struct Scsi_Host *next;
struct Scsi_Host *prev;
+ struct pci_dev *pdev; /* PCI device or NULL for non PCI */
struct eata_sp sp; /* status packet */
struct eata_ccb ccb[0]; /* ccb array begins here */
}hostdata;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 23beb48c79c..d312633db92 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -46,7 +46,6 @@
* last change: 2002/11/02 OS: Linux 2.5.45 *
************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -72,11 +71,11 @@
#include "eata_pio.h"
-static uint ISAbases[MAXISA] = {
+static unsigned int ISAbases[MAXISA] = {
0x1F0, 0x170, 0x330, 0x230
};
-static uint ISAirqs[MAXISA] = {
+static unsigned int ISAirqs[MAXISA] = {
14, 12, 15, 11
};
@@ -85,7 +84,7 @@ static unsigned char EISAbases[] = {
1, 1, 1, 1, 1, 1, 1, 1
};
-static uint registered_HBAs;
+static unsigned int registered_HBAs;
static struct Scsi_Host *last_HBA;
static struct Scsi_Host *first_HBA;
static unsigned char reg_IRQ[16];
@@ -166,6 +165,7 @@ static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **star
static int eata_pio_release(struct Scsi_Host *sh)
{
+ hostdata *hd = SD(sh);
if (sh->irq && reg_IRQ[sh->irq] == 1)
free_irq(sh->irq, NULL);
else
@@ -174,10 +174,13 @@ static int eata_pio_release(struct Scsi_Host *sh)
if (sh->io_port && sh->n_io_port)
release_region(sh->io_port, sh->n_io_port);
}
+ /* At this point the PCI reference can go */
+ if (hd->pdev)
+ pci_dev_put(hd->pdev);
return 1;
}
-static void IncStat(struct scsi_pointer *SCp, uint Increment)
+static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
{
SCp->ptr += Increment;
if ((SCp->this_residual -= Increment) == 0) {
@@ -191,46 +194,49 @@ static void IncStat(struct scsi_pointer *SCp, uint Increment)
}
}
-static void 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, struct pt_regs *regs);
static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
struct pt_regs *regs)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
+ irqreturn_t ret;
spin_lock_irqsave(dev->host_lock, flags);
- eata_pio_int_handler(irq, dev_id, regs);
+ ret = eata_pio_int_handler(irq, dev_id, regs);
spin_unlock_irqrestore(dev->host_lock, flags);
- return IRQ_HANDLED;
+ return ret;
}
-static void 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, struct pt_regs *regs)
{
- uint eata_stat = 0xfffff;
+ unsigned int eata_stat = 0xfffff;
struct scsi_cmnd *cmd;
hostdata *hd;
struct eata_ccb *cp;
- uint base;
- uint x, z;
+ unsigned long base;
+ unsigned int x, z;
struct Scsi_Host *sh;
unsigned short zwickel = 0;
unsigned char stat, odd;
+ irqreturn_t ret = IRQ_NONE;
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev)
{
if (sh->irq != irq)
continue;
- if (inb((uint) sh->base + HA_RSTATUS) & HA_SBUSY)
+ if (inb(sh->base + HA_RSTATUS) & HA_SBUSY)
continue;
int_counter++;
+ ret = IRQ_HANDLED;
hd = SD(sh);
cp = &hd->ccb[0];
cmd = cp->cmd;
- base = (uint) cmd->device->host->base;
+ base = cmd->device->host->base;
do {
stat = inb(base + HA_RSTATUS);
@@ -305,7 +311,7 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
cmd->result = (DID_OK << 16);
hd->devflags |= (1 << cp->cp_id);
- } else if (hd->devflags & 1 << cp->cp_id)
+ } else if (hd->devflags & (1 << cp->cp_id))
cmd->result = (DID_OK << 16) + 0x02;
else
cmd->result = (DID_NO_CONNECT << 16);
@@ -314,7 +320,7 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
cp->status = FREE;
eata_stat = inb(base + HA_RSTATUS);
printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
- return;
+ return ret;
}
#if DBG_INTR2
if (stat != 0x50)
@@ -326,12 +332,12 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
cmd->scsi_done(cmd);
}
- return;
+ return ret;
}
-static inline uint eata_pio_send_command(uint base, unsigned char command)
+static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command)
{
- uint loop = HZ / 2;
+ unsigned int loop = 50;
while (inb(base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
@@ -350,8 +356,8 @@ static inline uint eata_pio_send_command(uint base, unsigned char command)
static int eata_pio_queue(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
- uint x, y;
- uint base;
+ unsigned int x, y;
+ unsigned long base;
hostdata *hd;
struct Scsi_Host *sh;
@@ -361,7 +367,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
hd = HD(cmd);
sh = cmd->device->host;
- base = (uint) sh->base;
+ base = sh->base;
/* use only slot 0, as 2001 can handle only one cmd at a time */
@@ -396,9 +402,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cp->DataIn = 0; /* Input mode */
cp->Interpret = (cmd->device->id == hd->hostid);
- cp->cp_datalen = htonl((unsigned long) cmd->request_bufflen);
+ cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
cp->Auto_Req_Sen = 0;
- cp->cp_reqDMA = htonl(0);
+ cp->cp_reqDMA = 0;
cp->reqlen = 0;
cp->cp_id = cmd->device->id;
@@ -407,7 +413,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cp->cp_identify = 1;
memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
- cp->cp_statDMA = htonl(0);
+ cp->cp_statDMA = 0;
cp->cp_viraddr = cp;
cp->cmd = cmd;
@@ -446,14 +452,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"Queued base %#.4lx pid: %ld "
- "slot %d irq %d\n", (long) sh->base, cmd->pid, y, sh->irq));
+ "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
return (0);
}
static int eata_pio_abort(struct scsi_cmnd *cmd)
{
- uint loop = HZ;
+ unsigned int loop = 100;
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_abort called pid: %ld\n",
@@ -486,7 +492,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
static int eata_pio_host_reset(struct scsi_cmnd *cmd)
{
- uint x, limit = 0;
+ unsigned int x, limit = 0;
unsigned char success = 0;
struct scsi_cmnd *sp;
struct Scsi_Host *host = cmd->device->host;
@@ -519,7 +525,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
}
/* hard reset the HBA */
- outb(EATA_CMD_RESET, (uint) cmd->device->host->base + HA_WCOMMAND);
+ outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND);
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
HD(cmd)->state = RESET;
@@ -559,7 +565,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
}
}
-static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned long cplen, unsigned short cppadlen)
+static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen)
{
struct eata_ccb cp;
static char buff[256];
@@ -571,8 +577,8 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
cp.DataIn = 1;
cp.Interpret = 1; /* Interpret command */
- cp.cp_datalen = htonl(254);
- cp.cp_dataDMA = htonl(0);
+ cp.cp_datalen = cpu_to_be32(254);
+ cp.cp_dataDMA = cpu_to_be32(0);
cp.cp_id = id;
cp.cp_lun = 0;
@@ -584,7 +590,7 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
cp.cp_cdb[4] = 254;
cp.cp_cdb[5] = 0;
- if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
+ if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
return (NULL);
while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
outsw(base + HA_RDATA, &cp, cplen);
@@ -605,7 +611,7 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
}
}
-static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf)
{
unsigned long loop = HZ / 2;
int z;
@@ -620,30 +626,30 @@ static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
if (--loop == 0)
goto fail;
- DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
+ DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base));
eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
- loop = HZ / 2;
+ loop = 50;
for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
goto fail;
- loop = HZ / 2;
+ loop = 50;
*p = inw(base + HA_RDATA);
}
if (inb(base + HA_RSTATUS) & HA_SERROR) {
DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
- "transfer for HBA at %x\n", base));
+ "transfer for HBA at %lx\n", base));
goto fail;
}
- if (htonl(EATA_SIGNATURE) != buf->signature)
+ if (cpu_to_be32(EATA_SIGNATURE) != buf->signature)
goto fail;
DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
- "at %#4x EATA Level: %x\n",
- base, (uint) (buf->version)));
+ "at %#4lx EATA Level: %x\n",
+ base, (unsigned int) (buf->version)));
while (inb(base + HA_RSTATUS) & HA_SDRQ)
inw(base + HA_RDATA);
@@ -666,12 +672,12 @@ static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
static void print_pio_config(struct get_conf *gc)
{
printk("Please check values: (read config data)\n");
- printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", (uint) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
- printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+ printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+ printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND);
printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
}
-static uint print_selftest(uint base)
+static unsigned int print_selftest(unsigned int base)
{
unsigned char buffer[512];
#ifdef VERBOSE_SETUP
@@ -698,7 +704,7 @@ static uint print_selftest(uint base)
return (!(inb(base + HA_RSTATUS) & HA_SERROR));
}
-static int register_pio_HBA(long base, struct get_conf *gc)
+static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev)
{
unsigned long size = 0;
char *buff;
@@ -715,24 +721,24 @@ static int register_pio_HBA(long base, struct get_conf *gc)
return 0;
}
- if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
- printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
+ if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) {
+ printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base);
return 0;
}
if (!print_selftest(base) && !ALLOW_DMA_BOARDS) {
- printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
+ printk("HBA at %#lx failed while performing self test & setup.\n", base);
return 0;
}
- size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+ size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz));
sh = scsi_register(&driver_template, size);
if (sh == NULL)
return 0;
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", sh)) {
+ if (!request_irq(gc->IRQ, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", sh)) {
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */
@@ -750,8 +756,8 @@ static int register_pio_HBA(long base, struct get_conf *gc)
hd = SD(sh);
- memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
- memset(hd->reads, 0, sizeof(unsigned long) * 26);
+ memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)));
+ memset(hd->reads, 0, sizeof(hd->reads));
strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor));
strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name));
@@ -762,7 +768,7 @@ static int register_pio_HBA(long base, struct get_conf *gc)
SD(sh)->revision[4] = buff[35];
SD(sh)->revision[5] = 0;
- switch (ntohl(gc->len)) {
+ switch (be32_to_cpu(gc->len)) {
case 0x1c:
SD(sh)->EATA_revision = 'a';
break;
@@ -778,7 +784,7 @@ static int register_pio_HBA(long base, struct get_conf *gc)
SD(sh)->EATA_revision = '?';
}
- if (ntohl(gc->len) >= 0x22) {
+ if (be32_to_cpu(gc->len) >= 0x22) {
if (gc->is_PCI)
hd->bustype = IS_PCI;
else if (gc->is_EISA)
@@ -812,6 +818,8 @@ static int register_pio_HBA(long base, struct get_conf *gc)
hd->channel = 0;
+ hd->pdev = pci_dev_get(pdev); /* Keep a PCI reference */
+
sh->max_id = 8;
sh->max_lun = 8;
@@ -842,7 +850,7 @@ static void find_pio_ISA(struct get_conf *buf)
continue;
if (!get_pio_conf_PIO(ISAbases[i], buf))
continue;
- if (!register_pio_HBA(ISAbases[i], buf))
+ if (!register_pio_HBA(ISAbases[i], buf, NULL))
release_region(ISAbases[i], 9);
else
ISAbases[i] = 0;
@@ -874,7 +882,7 @@ static void find_pio_EISA(struct get_conf *buf)
if (get_pio_conf_PIO(base, buf)) {
DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
if (buf->IRQ) {
- if (!register_pio_HBA(base, buf))
+ if (!register_pio_HBA(base, buf, NULL))
release_region(base, 9);
} else {
printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
@@ -897,9 +905,9 @@ static void find_pio_PCI(struct get_conf *buf)
printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
#else
struct pci_dev *dev = NULL;
- u32 base, x;
+ unsigned long base, x;
- while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
+ while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev)));
if (pci_enable_device(dev))
continue;
@@ -927,7 +935,7 @@ static void find_pio_PCI(struct get_conf *buf)
* eventually remove it from the EISA and ISA list
*/
- if (!register_pio_HBA(base, buf)) {
+ if (!register_pio_HBA(base, buf, dev)) {
release_region(base, 9);
continue;
}
@@ -966,7 +974,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
for (i = 0; i <= MAXIRQ; i++)
if (reg_IRQ[i])
- request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+ request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
HBA_ptr = first_HBA;
@@ -977,12 +985,12 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
printk("Registered HBAs:\n");
printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
for (i = 1; i <= registered_HBAs; i++) {
- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c"
+ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d %d %d %c"
" %2d %2d %2d\n",
HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
"PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
- (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
+ HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue,
HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
HBA_ptr = SD(HBA_ptr)->next;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 0a3e45d7a97..5630868c1b2 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,7 +1,6 @@
-/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
- * esp.c: EnhancedScsiProcessor Sun SCSI driver code.
+/* esp.c: ESP Sun SCSI driver.
*
- * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
@@ -13,7 +12,6 @@
* 3) Add tagged queueing.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
@@ -185,11 +183,6 @@ enum {
/*5*/ do_intr_end
};
-/* The master ring of all esp hosts we are managing in this driver. */
-static struct esp *espchain;
-static DEFINE_SPINLOCK(espchain_lock);
-static int esps_running = 0;
-
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -694,36 +687,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
-static void esp_chain_add(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain) {
- struct esp *elink = espchain;
- while (elink->next)
- elink = elink->next;
- elink->next = esp;
- } else {
- espchain = esp;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
-static void esp_chain_del(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain == esp) {
- espchain = esp->next;
- } else {
- struct esp *elink = espchain;
- while (elink->next != esp)
- elink = elink->next;
- elink->next = esp->next;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
@@ -815,7 +778,7 @@ static int __init esp_register_irq(struct esp *esp)
* sanely maintain.
*/
if (request_irq(esp->ehost->irq, esp_intr,
- SA_SHIRQ, "ESP SCSI", esp)) {
+ IRQF_SHARED, "ESP SCSI", esp)) {
printk("esp%d: Cannot acquire irq line\n",
esp->esp_id);
return -1;
@@ -830,19 +793,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
+ struct device_node *dp = sdev->ofdev.node;
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "initiator-id",
+ -1);
if (esp->scsi_id == -1)
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "scsi-initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "scsi-initiator-id",
+ -1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
- prom_getintdefault(sdev->bus->prom_node,
- "scsi-initiator-id",
- 7);
+ of_getintprop_default(sdev->bus->ofdev.node,
+ "scsi-initiator-id",
+ 7);
esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id);
@@ -1067,28 +1031,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
-static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
- struct sbus_dev *espdma, struct sbus_bus *sbus,
- int id, int hme)
+static int __init detect_one_esp(struct scsi_host_template *tpnt,
+ struct device *dev,
+ struct sbus_dev *esp_dev,
+ struct sbus_dev *espdma,
+ struct sbus_bus *sbus,
+ int hme)
{
- struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
+ static int instance;
+ struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
- if (!esp_host) {
- printk("ESP: Cannot register SCSI host\n");
- return -1;
- }
+ if (!esp_host)
+ return -ENOMEM;
+
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
- esp->esp_id = id;
+ esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
- esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
@@ -1115,8 +1081,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
+ if (scsi_add_host(esp_host, dev))
+ goto fail_free_irq;
+
+ dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+ scsi_scan_host(esp_host);
+ instance++;
+
return 0;
+fail_free_irq:
+ free_irq(esp->ehost->irq, esp);
+
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
@@ -1129,119 +1106,99 @@ fail_dvma_release:
esp->dma->allocated = 0;
fail_unlink:
- esp_chain_del(esp);
- scsi_unregister(esp_host);
+ scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
+static int __devexit esp_remove_common(struct esp *esp)
+{
+ unsigned int irq = esp->ehost->irq;
+
+ scsi_remove_host(esp->ehost);
+
+ ESP_INTSOFF(esp->dregs);
+#if 0
+ esp_reset_dma(esp);
+ esp_reset_esp(esp);
+#endif
+
+ free_irq(irq, esp);
+ sbus_free_consistent(esp->sdev, 16,
+ (void *) esp->esp_command, esp->esp_command_dvma);
+ sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+ esp->dma->allocated = 0;
+
+ scsi_host_put(esp->ehost);
+
+ return 0;
+}
+
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
-static int __init esp_detect(struct scsi_host_template *tpnt)
-{
- static struct sbus_dev esp_dev;
- int esps_in_use = 0;
-
- espchain = NULL;
+static struct sbus_dev sun4_esp_dev;
+static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
+{
if (sun4_esp_physaddr) {
- memset (&esp_dev, 0, sizeof(esp_dev));
- esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
- esp_dev.irqs[0] = 4;
- esp_dev.resource[0].start = sun4_esp_physaddr;
- esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
- esp_dev.resource[0].flags = IORESOURCE_IO;
-
- if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
- esps_in_use++;
- printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
- esps_running = esps_in_use;
+ memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev));
+ sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
+ sun4_esp_dev.irqs[0] = 4;
+ sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
+ sun4_esp_dev.resource[0].end =
+ sun4_esp_physaddr + ESP_REG_SIZE - 1;
+ sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
+
+ return detect_one_esp(tpnt, NULL,
+ &sun4_esp_dev, NULL, NULL, 0);
}
- return esps_in_use;
+ return 0;
}
-#else /* !CONFIG_SUN4 */
-
-static int __init esp_detect(struct scsi_host_template *tpnt)
+static int __devexit esp_sun4_remove(void)
{
- struct sbus_bus *sbus;
- struct sbus_dev *esp_dev, *sbdev_iter;
- int nesps = 0, esps_in_use = 0;
+ struct of_device *dev = &sun4_esp_dev.ofdev;
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- espchain = 0;
- if (!sbus_root) {
-#ifdef CONFIG_PCI
- return 0;
-#else
- panic("No SBUS in esp_detect()");
-#endif
- }
- for_each_sbus(sbus) {
- for_each_sbusdev(sbdev_iter, sbus) {
- struct sbus_dev *espdma = NULL;
- int hme = 0;
-
- /* Is it an esp sbus device? */
- esp_dev = sbdev_iter;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp")) {
- if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
- hme = 1;
- espdma = esp_dev;
- } else {
- if (!esp_dev->child ||
- (strcmp(esp_dev->prom_name, "espdma") &&
- strcmp(esp_dev->prom_name, "dma")))
- continue; /* nope... */
- espdma = esp_dev;
- esp_dev = esp_dev->child;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp"))
- continue; /* how can this happen? */
- }
- }
-
- if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
- continue;
-
- esps_in_use++;
- } /* for each sbusdev */
- } /* for each sbus */
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
- esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ return esp_remove_common(esp);
}
-#endif /* !CONFIG_SUN4 */
+#else /* !CONFIG_SUN4 */
-/*
- */
-static int esp_release(struct Scsi_Host *host)
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct esp *esp = (struct esp *) host->hostdata;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct sbus_dev *dma_sdev = NULL;
+ int hme = 0;
+
+ if (dp->parent &&
+ (!strcmp(dp->parent->name, "espdma") ||
+ !strcmp(dp->parent->name, "dma")))
+ dma_sdev = sdev->parent;
+ else if (!strcmp(dp->name, "SUNW,fas")) {
+ dma_sdev = sdev;
+ hme = 1;
+ }
- ESP_INTSOFF(esp->dregs);
-#if 0
- esp_reset_dma(esp);
- esp_reset_esp(esp);
-#endif
+ return detect_one_esp(match->data, &dev->dev,
+ sdev, dma_sdev, sdev->bus, hme);
+}
- free_irq(esp->ehost->irq, esp);
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command, esp->esp_command_dvma);
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
- esp->dma->allocated = 0;
- esp_chain_del(esp);
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- return 0;
+ return esp_remove_common(esp);
}
+#endif /* !CONFIG_SUN4 */
+
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
@@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
- struct esp *esp;
+ struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
- for_each_esp(esp) {
- if (esp->ehost == host)
- break;
- }
- if (!esp)
- return -EINVAL;
-
if (start)
*start = buffer;
@@ -1448,7 +1398,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
sp->SCp.ptr = NULL;
}
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
sp->SCp.buffer,
sp->use_sg,
@@ -1461,7 +1411,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
{
if (sp->use_sg) {
- sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+ sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
sp->sc_data_direction);
} else if (sp->request_bufflen) {
sbus_unmap_single(esp->sdev,
@@ -2805,18 +2755,15 @@ static int esp_do_data_finale(struct esp *esp)
*/
static int esp_should_clear_sync(struct scsi_cmnd *sp)
{
- u8 cmd1 = sp->cmnd[0];
- u8 cmd2 = sp->data_cmnd[0];
+ u8 cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if (cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if (cmd == START_STOP)
return 0;
- if (cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if (cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
@@ -2824,8 +2771,7 @@ static int esp_should_clear_sync(struct scsi_cmnd *sp)
* completion of a rewind or tape load operation.
*/
if (sp->device->type == TYPE_TAPE) {
- if (cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
+ if (cmd == MODE_SENSE)
return 0;
}
@@ -4377,15 +4323,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
-static struct scsi_host_template driver_template = {
- .proc_name = "esp",
- .proc_info = esp_proc_info,
- .name = "Sun ESP 100/100a/200",
- .detect = esp_detect,
+static struct scsi_host_template esp_template = {
+ .module = THIS_MODULE,
+ .name = "esp",
+ .info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
- .release = esp_release,
- .info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
@@ -4394,12 +4337,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .proc_name = "esp",
+ .proc_info = esp_proc_info,
+};
+
+#ifndef CONFIG_SUN4
+static struct of_device_id esp_match[] = {
+ {
+ .name = "SUNW,esp",
+ .data = &esp_template,
+ },
+ {
+ .name = "SUNW,fas",
+ .data = &esp_template,
+ },
+ {
+ .name = "esp",
+ .data = &esp_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+ .name = "esp",
+ .match_table = esp_match,
+ .probe = esp_sbus_probe,
+ .remove = __devexit_p(esp_sbus_remove),
};
+#endif
+
+static int __init esp_init(void)
+{
+#ifdef CONFIG_SUN4
+ return esp_sun4_probe(&esp_template);
+#else
+ return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+#endif
+}
-#include "scsi_module.c"
+static void __exit esp_exit(void)
+{
+#ifdef CONFIG_SUN4
+ esp_sun4_remove();
+#else
+ of_unregister_driver(&esp_sbus_driver);
+#endif
+}
-MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("ESP Sun SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
index 73f7d6968ab..a98cda9121f 100644
--- a/drivers/scsi/esp.h
+++ b/drivers/scsi/esp.h
@@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
-/* For our interrupt engine. */
-#define for_each_esp(esp) \
- for((esp) = espchain; (esp); (esp) = (esp)->next)
-
#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 8ae9c406a83..2a1c5c22b9e 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -210,7 +210,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+FASTLANE_ESP_ADDR;
- if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Fastlane SCSI", esp->ehost)) {
printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
goto err_unmap;
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
index 03416548f20..c4e16c0775d 100644
--- a/drivers/scsi/fcal.c
+++ b/drivers/scsi/fcal.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-#include <linux/config.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -249,8 +248,7 @@ int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t of
if (scd->id == target) {
SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ",
alpa, target, u1[0], u1[1], u2[0], u2[1]);
- SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
- scsi_device_types[(short) scd->type] : "Unknown device");
+ SPRINTF ("%s ", scsi_device_type(scd->type));
for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
SPRINTF ("%c", scd->vendor[j]);
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 70a1606bd58..dde3edf35c0 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -400,7 +400,7 @@ static int fd_mcs_detect(struct scsi_host_template * tpnt)
mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
/* check irq/region */
- if (request_irq(irq, fd_mcs_intr, SA_SHIRQ, "fd_mcs", hosts)) {
+ if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
continue;
}
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index e16013f0ad6..b0694dcce24 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -266,7 +266,6 @@
**************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -950,7 +949,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
/* Register the IRQ with the kernel */
retcode = request_irq( interrupt_level,
- do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt);
+ do_fdomain_16x0_intr, pdev?IRQF_SHARED:0, "fdomain", shpnt);
if (retcode < 0) {
if (retcode == -EINVAL) {
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5f313c93b7a..cdd893bb4e2 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -91,7 +91,6 @@
#define AUTOPROBE_IRQ
#define AUTOSENSE
-#include <linux/config.h>
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define NCR53C400_PSEUDO_DMA 1
@@ -462,7 +461,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, 0xffff);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", instance)) {
+ if (request_irq(instance->irq, generic_NCR5380_intr, IRQF_DISABLED, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
@@ -812,7 +811,6 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
struct NCR5380_hostdata *hostdata;
#ifdef NCR5380_STATS
struct scsi_device *dev;
- extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#endif
NCR5380_setup(scsi_ptr);
@@ -852,7 +850,7 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
long tr = hostdata->time_read[dev->id] / HZ;
long tw = hostdata->time_write[dev->id] / HZ;
- PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+ PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
for (i = 0; i < 8; i++)
if (dev->vendor[i] >= 0x20)
*(buffer + (len++)) = dev->vendor[i];
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index d60a89cb805..df0b3f69ef6 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -32,7 +32,6 @@
#ifndef GENERIC_NCR5380_H
#define GENERIC_NCR5380_H
-#include <linux/config.h>
#define GENERIC_NCR5380_PUBLIC_RELEASE 1
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 76071a15830..43afd476e60 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4350,7 +4350,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
isa_bios,ha->irq,ha->drq);
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+ if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
printk("GDT-ISA: Unable to allocate IRQ\n");
scsi_unregister(shp);
continue;
@@ -4476,7 +4476,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
eisa_slot>>12,ha->irq);
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+ if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
printk("GDT-EISA: Unable to allocate IRQ\n");
scsi_unregister(shp);
continue;
@@ -4603,7 +4603,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
if (request_irq(ha->irq, gdth_interrupt,
- SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+ IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
{
printk("GDT-PCI: Unable to allocate IRQ\n");
scsi_unregister(shp);
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 5b154498056..18dbe5c27da 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -47,7 +47,7 @@ void gvp11_setup (char *str, int *ints)
gvp11_xfer_mask = ints[1];
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = GVP11_DMAC_INT_ENABLE;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -142,8 +142,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
- int status)
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
{
/* stop DMA */
DMA(instance)->SP_DMA = 1;
@@ -328,7 +328,7 @@ int __init gvp11_detect(struct scsi_host_template *tpnt)
(epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
: WD33C93_FS_12_15);
- request_irq(IRQ_AMIGA_PORTS, gvp11_intr, SA_SHIRQ, "GVP11 SCSI",
+ request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
instance);
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
num_gvp11++;
@@ -341,7 +341,7 @@ release:
return num_gvp11;
}
-static int gvp11_bus_reset(Scsi_Cmnd *cmd)
+static int gvp11_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
index 575d219d14b..bf22859a503 100644
--- a/drivers/scsi/gvp11.h
+++ b/drivers/scsi/gvp11.h
@@ -13,10 +13,6 @@
int gvp11_detect(struct scsi_host_template *);
int gvp11_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index dfcb96f3e60..68ef1636678 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -265,6 +265,9 @@ static void scsi_host_dev_release(struct device *dev)
destroy_workqueue(shost->work_q);
scsi_destroy_command_freelist(shost);
+ if (shost->bqt)
+ blk_free_tags(shost->bqt);
+
kfree(shost->shost_data);
if (parent)
@@ -487,7 +490,9 @@ EXPORT_SYMBOL(scsi_is_host_device);
* @work: Work to queue for execution.
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 - work queued for execution
+ * 0 - work is already queued
+ * -EINVAL - work queue doesn't exist
**/
int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
{
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index f77808329e7..28bfb8f9f81 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -15,7 +15,6 @@
*
* For more information, visit http://www.highpoint-tech.com
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -45,10 +44,6 @@ static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
static const char driver_ver[] = "v1.0 (060426)";
-static DEFINE_SPINLOCK(hptiop_hba_list_lock);
-static LIST_HEAD(hptiop_hba_list);
-static int hptiop_cdev_major = -1;
-
static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
@@ -577,7 +572,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
if (atomic_xchg(&hba->resetting, 1) == 0) {
atomic_inc(&hba->reset_count);
writel(IOPMU_INBOUND_MSG0_RESET,
- &hba->iop->outbound_msgaddr0);
+ &hba->iop->inbound_msgaddr0);
hptiop_pci_posting_flush(hba->iop);
}
@@ -620,532 +615,11 @@ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
return queue_depth;
}
-struct hptiop_getinfo {
- char __user *buffer;
- loff_t buflength;
- loff_t bufoffset;
- loff_t buffillen;
- loff_t filpos;
-};
-
-static void hptiop_copy_mem_info(struct hptiop_getinfo *pinfo,
- char *data, int datalen)
-{
- if (pinfo->filpos < pinfo->bufoffset) {
- if (pinfo->filpos + datalen <= pinfo->bufoffset) {
- pinfo->filpos += datalen;
- return;
- } else {
- data += (pinfo->bufoffset - pinfo->filpos);
- datalen -= (pinfo->bufoffset - pinfo->filpos);
- pinfo->filpos = pinfo->bufoffset;
- }
- }
-
- pinfo->filpos += datalen;
- if (pinfo->buffillen == pinfo->buflength)
- return;
-
- if (pinfo->buflength - pinfo->buffillen < datalen)
- datalen = pinfo->buflength - pinfo->buffillen;
-
- if (copy_to_user(pinfo->buffer + pinfo->buffillen, data, datalen))
- return;
-
- pinfo->buffillen += datalen;
-}
-
-static int hptiop_copy_info(struct hptiop_getinfo *pinfo, char *fmt, ...)
-{
- va_list args;
- char buf[128];
- int len;
-
- va_start(args, fmt);
- len = vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
- hptiop_copy_mem_info(pinfo, buf, len);
- return len;
-}
-
-static void hptiop_ioctl_done(struct hpt_ioctl_k *arg)
-{
- arg->done = NULL;
- wake_up(&arg->hba->ioctl_wq);
-}
-
-static void hptiop_do_ioctl(struct hpt_ioctl_k *arg)
-{
- struct hptiop_hba *hba = arg->hba;
- u32 val;
- struct hpt_iop_request_ioctl_command __iomem *req;
- int ioctl_retry = 0;
-
- dprintk("scsi%d: hptiop_do_ioctl\n", hba->host->host_no);
-
- /*
- * check (in + out) buff size from application.
- * outbuf must be dword aligned.
- */
- if (((arg->inbuf_size + 3) & ~3) + arg->outbuf_size >
- hba->max_request_size
- - sizeof(struct hpt_iop_request_header)
- - 4 * sizeof(u32)) {
- dprintk("scsi%d: ioctl buf size (%d/%d) is too large\n",
- hba->host->host_no,
- arg->inbuf_size, arg->outbuf_size);
- arg->result = HPT_IOCTL_RESULT_FAILED;
- return;
- }
-
-retry:
- spin_lock_irq(hba->host->host_lock);
-
- val = readl(&hba->iop->inbound_queue);
- if (val == IOPMU_QUEUE_EMPTY) {
- spin_unlock_irq(hba->host->host_lock);
- dprintk("scsi%d: no free req for ioctl\n", hba->host->host_no);
- arg->result = -1;
- return;
- }
-
- req = (struct hpt_iop_request_ioctl_command __iomem *)
- ((unsigned long)hba->iop + val);
-
- writel(HPT_CTL_CODE_LINUX_TO_IOP(arg->ioctl_code),
- &req->ioctl_code);
- writel(arg->inbuf_size, &req->inbuf_size);
- writel(arg->outbuf_size, &req->outbuf_size);
-
- /*
- * use the buffer on the IOP local memory first, then copy it
- * back to host.
- * the caller's request buffer shoudl be little-endian.
- */
- if (arg->inbuf_size)
- memcpy_toio(req->buf, arg->inbuf, arg->inbuf_size);
-
- /* correct the controller ID for IOP */
- if ((arg->ioctl_code == HPT_IOCTL_GET_CHANNEL_INFO ||
- arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO_V2 ||
- arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO)
- && arg->inbuf_size >= sizeof(u32))
- writel(0, req->buf);
-
- writel(IOP_REQUEST_TYPE_IOCTL_COMMAND, &req->header.type);
- writel(0, &req->header.flags);
- writel(offsetof(struct hpt_iop_request_ioctl_command, buf)
- + arg->inbuf_size, &req->header.size);
- writel((u32)(unsigned long)arg, &req->header.context);
- writel(BITS_PER_LONG > 32 ? (u32)((unsigned long)arg>>32) : 0,
- &req->header.context_hi32);
- writel(IOP_RESULT_PENDING, &req->header.result);
-
- arg->result = HPT_IOCTL_RESULT_FAILED;
- arg->done = hptiop_ioctl_done;
-
- writel(val, &hba->iop->inbound_queue);
- hptiop_pci_posting_flush(hba->iop);
-
- spin_unlock_irq(hba->host->host_lock);
-
- wait_event_timeout(hba->ioctl_wq, arg->done == NULL, 60 * HZ);
-
- if (arg->done != NULL) {
- hptiop_reset_hba(hba);
- if (ioctl_retry++ < 3)
- goto retry;
- }
-
- dprintk("hpt_iop_ioctl %x result %d\n",
- arg->ioctl_code, arg->result);
-}
-
-static int __hpt_do_ioctl(struct hptiop_hba *hba, u32 code, void *inbuf,
- u32 insize, void *outbuf, u32 outsize)
-{
- struct hpt_ioctl_k arg;
- arg.hba = hba;
- arg.ioctl_code = code;
- arg.inbuf = inbuf;
- arg.outbuf = outbuf;
- arg.inbuf_size = insize;
- arg.outbuf_size = outsize;
- arg.bytes_returned = NULL;
- hptiop_do_ioctl(&arg);
- return arg.result;
-}
-
-static inline int hpt_id_valid(__le32 id)
-{
- return id != 0 && id != cpu_to_le32(0xffffffff);
-}
-
-static int hptiop_get_controller_info(struct hptiop_hba *hba,
- struct hpt_controller_info *pinfo)
-{
- int id = 0;
-
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CONTROLLER_INFO,
- &id, sizeof(int), pinfo, sizeof(*pinfo));
-}
-
-
-static int hptiop_get_channel_info(struct hptiop_hba *hba, int bus,
- struct hpt_channel_info *pinfo)
-{
- u32 ids[2];
-
- ids[0] = 0;
- ids[1] = bus;
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CHANNEL_INFO,
- ids, sizeof(ids), pinfo, sizeof(*pinfo));
-
-}
-
-static int hptiop_get_logical_devices(struct hptiop_hba *hba,
- __le32 *pids, int maxcount)
-{
- int i;
- u32 count = maxcount - 1;
-
- if (__hpt_do_ioctl(hba, HPT_IOCTL_GET_LOGICAL_DEVICES,
- &count, sizeof(u32),
- pids, sizeof(u32) * maxcount))
- return -1;
-
- maxcount = le32_to_cpu(pids[0]);
- for (i = 0; i < maxcount; i++)
- pids[i] = pids[i+1];
-
- return maxcount;
-}
-
-static int hptiop_get_device_info_v3(struct hptiop_hba *hba, __le32 id,
- struct hpt_logical_device_info_v3 *pinfo)
-{
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_DEVICE_INFO_V3,
- &id, sizeof(u32),
- pinfo, sizeof(*pinfo));
-}
-
-static const char *get_array_status(struct hpt_logical_device_info_v3 *devinfo)
-{
- static char s[64];
- u32 flags = le32_to_cpu(devinfo->u.array.flags);
- u32 trans_prog = le32_to_cpu(devinfo->u.array.transforming_progress);
- u32 reb_prog = le32_to_cpu(devinfo->u.array.rebuilding_progress);
-
- if (flags & ARRAY_FLAG_DISABLED)
- return "Disabled";
- else if (flags & ARRAY_FLAG_TRANSFORMING)
- sprintf(s, "Expanding/Migrating %d.%d%%%s%s",
- trans_prog / 100,
- trans_prog % 100,
- (flags & (ARRAY_FLAG_NEEDBUILDING|ARRAY_FLAG_BROKEN))?
- ", Critical" : "",
- ((flags & ARRAY_FLAG_NEEDINITIALIZING) &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))?
- ", Unintialized" : "");
- else if ((flags & ARRAY_FLAG_BROKEN) &&
- devinfo->u.array.array_type != AT_RAID6)
- return "Critical";
- else if (flags & ARRAY_FLAG_REBUILDING)
- sprintf(s,
- (flags & ARRAY_FLAG_NEEDINITIALIZING)?
- "%sBackground initializing %d.%d%%" :
- "%sRebuilding %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_VERIFYING)
- sprintf(s, "%sVerifying %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_INITIALIZING)
- sprintf(s, "%sForground initializing %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_NEEDTRANSFORM)
- sprintf(s,"%s%s%s", "Need Expanding/Migrating",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- ((flags & ARRAY_FLAG_NEEDINITIALIZING) &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))?
- ", Unintialized" : "");
- else if (flags & ARRAY_FLAG_NEEDINITIALIZING &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))
- sprintf(s,"%sUninitialized",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "");
- else if ((flags & ARRAY_FLAG_NEEDBUILDING) ||
- (flags & ARRAY_FLAG_BROKEN))
- return "Critical";
- else
- return "Normal";
- return s;
-}
-
-static void hptiop_dump_devinfo(struct hptiop_hba *hba,
- struct hptiop_getinfo *pinfo, __le32 id, int indent)
-{
- struct hpt_logical_device_info_v3 devinfo;
- int i;
- u64 capacity;
-
- for (i = 0; i < indent; i++)
- hptiop_copy_info(pinfo, "\t");
-
- if (hptiop_get_device_info_v3(hba, id, &devinfo)) {
- hptiop_copy_info(pinfo, "unknown\n");
- return;
- }
-
- switch (devinfo.type) {
-
- case LDT_DEVICE: {
- struct hd_driveid *driveid;
- u32 flags = le32_to_cpu(devinfo.u.device.flags);
-
- driveid = (struct hd_driveid *)devinfo.u.device.ident;
- /* model[] is 40 chars long, but we just want 20 chars here */
- driveid->model[20] = 0;
-
- if (indent)
- if (flags & DEVICE_FLAG_DISABLED)
- hptiop_copy_info(pinfo,"Missing\n");
- else
- hptiop_copy_info(pinfo, "CH%d %s\n",
- devinfo.u.device.path_id + 1,
- driveid->model);
- else {
- capacity = le64_to_cpu(devinfo.capacity) * 512;
- do_div(capacity, 1000000);
- hptiop_copy_info(pinfo,
- "CH%d %s, %lluMB, %s %s%s%s%s\n",
- devinfo.u.device.path_id + 1,
- driveid->model,
- capacity,
- (flags & DEVICE_FLAG_DISABLED)?
- "Disabled" : "Normal",
- devinfo.u.device.read_ahead_enabled?
- "[RA]" : "",
- devinfo.u.device.write_cache_enabled?
- "[WC]" : "",
- devinfo.u.device.TCQ_enabled?
- "[TCQ]" : "",
- devinfo.u.device.NCQ_enabled?
- "[NCQ]" : ""
- );
- }
- break;
- }
-
- case LDT_ARRAY:
- if (devinfo.target_id != INVALID_TARGET_ID)
- hptiop_copy_info(pinfo, "[DISK %d_%d] ",
- devinfo.vbus_id, devinfo.target_id);
-
- capacity = le64_to_cpu(devinfo.capacity) * 512;
- do_div(capacity, 1000000);
- hptiop_copy_info(pinfo, "%s (%s), %lluMB, %s\n",
- devinfo.u.array.name,
- devinfo.u.array.array_type==AT_RAID0? "RAID0" :
- devinfo.u.array.array_type==AT_RAID1? "RAID1" :
- devinfo.u.array.array_type==AT_RAID5? "RAID5" :
- devinfo.u.array.array_type==AT_RAID6? "RAID6" :
- devinfo.u.array.array_type==AT_JBOD? "JBOD" :
- "unknown",
- capacity,
- get_array_status(&devinfo));
- for (i = 0; i < devinfo.u.array.ndisk; i++) {
- if (hpt_id_valid(devinfo.u.array.members[i])) {
- if (cpu_to_le16(1<<i) &
- devinfo.u.array.critical_members)
- hptiop_copy_info(pinfo, "\t*");
- hptiop_dump_devinfo(hba, pinfo,
- devinfo.u.array.members[i], indent+1);
- }
- else
- hptiop_copy_info(pinfo, "\tMissing\n");
- }
- if (id == devinfo.u.array.transform_source) {
- hptiop_copy_info(pinfo, "\tExpanding/Migrating to:\n");
- hptiop_dump_devinfo(hba, pinfo,
- devinfo.u.array.transform_target, indent+1);
- }
- break;
- }
-}
-
static ssize_t hptiop_show_version(struct class_device *class_dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver);
}
-static ssize_t hptiop_cdev_read(struct file *filp, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct hptiop_hba *hba = filp->private_data;
- struct hptiop_getinfo info;
- int i, j, ndev;
- struct hpt_controller_info con_info;
- struct hpt_channel_info chan_info;
- __le32 ids[32];
-
- info.buffer = buf;
- info.buflength = count;
- info.bufoffset = ppos ? *ppos : 0;
- info.filpos = 0;
- info.buffillen = 0;
-
- if (hptiop_get_controller_info(hba, &con_info))
- return -EIO;
-
- for (i = 0; i < con_info.num_buses; i++) {
- if (hptiop_get_channel_info(hba, i, &chan_info) == 0) {
- if (hpt_id_valid(chan_info.devices[0]))
- hptiop_dump_devinfo(hba, &info,
- chan_info.devices[0], 0);
- if (hpt_id_valid(chan_info.devices[1]))
- hptiop_dump_devinfo(hba, &info,
- chan_info.devices[1], 0);
- }
- }
-
- ndev = hptiop_get_logical_devices(hba, ids,
- sizeof(ids) / sizeof(ids[0]));
-
- /*
- * if hptiop_get_logical_devices fails, ndev==-1 and it just
- * output nothing here
- */
- for (j = 0; j < ndev; j++)
- hptiop_dump_devinfo(hba, &info, ids[j], 0);
-
- if (ppos)
- *ppos += info.buffillen;
-
- return info.buffillen;
-}
-
-static int hptiop_cdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct hptiop_hba *hba = file->private_data;
- struct hpt_ioctl_u ioctl_u;
- struct hpt_ioctl_k ioctl_k;
- u32 bytes_returned;
- int err = -EINVAL;
-
- if (copy_from_user(&ioctl_u,
- (void __user *)arg, sizeof(struct hpt_ioctl_u)))
- return -EINVAL;
-
- if (ioctl_u.magic != HPT_IOCTL_MAGIC)
- return -EINVAL;
-
- ioctl_k.ioctl_code = ioctl_u.ioctl_code;
- ioctl_k.inbuf = NULL;
- ioctl_k.inbuf_size = ioctl_u.inbuf_size;
- ioctl_k.outbuf = NULL;
- ioctl_k.outbuf_size = ioctl_u.outbuf_size;
- ioctl_k.hba = hba;
- ioctl_k.bytes_returned = &bytes_returned;
-
- /* verify user buffer */
- if ((ioctl_k.inbuf_size && !access_ok(VERIFY_READ,
- ioctl_u.inbuf, ioctl_k.inbuf_size)) ||
- (ioctl_k.outbuf_size && !access_ok(VERIFY_WRITE,
- ioctl_u.outbuf, ioctl_k.outbuf_size)) ||
- (ioctl_u.bytes_returned && !access_ok(VERIFY_WRITE,
- ioctl_u.bytes_returned, sizeof(u32))) ||
- ioctl_k.inbuf_size + ioctl_k.outbuf_size > 0x10000) {
-
- dprintk("scsi%d: got bad user address\n", hba->host->host_no);
- return -EINVAL;
- }
-
- /* map buffer to kernel. */
- if (ioctl_k.inbuf_size) {
- ioctl_k.inbuf = kmalloc(ioctl_k.inbuf_size, GFP_KERNEL);
- if (!ioctl_k.inbuf) {
- dprintk("scsi%d: fail to alloc inbuf\n",
- hba->host->host_no);
- err = -ENOMEM;
- goto err_exit;
- }
-
- if (copy_from_user(ioctl_k.inbuf,
- ioctl_u.inbuf, ioctl_k.inbuf_size)) {
- goto err_exit;
- }
- }
-
- if (ioctl_k.outbuf_size) {
- ioctl_k.outbuf = kmalloc(ioctl_k.outbuf_size, GFP_KERNEL);
- if (!ioctl_k.outbuf) {
- dprintk("scsi%d: fail to alloc outbuf\n",
- hba->host->host_no);
- err = -ENOMEM;
- goto err_exit;
- }
- }
-
- hptiop_do_ioctl(&ioctl_k);
-
- if (ioctl_k.result == HPT_IOCTL_RESULT_OK) {
- if (ioctl_k.outbuf_size &&
- copy_to_user(ioctl_u.outbuf,
- ioctl_k.outbuf, ioctl_k.outbuf_size))
- goto err_exit;
-
- if (ioctl_u.bytes_returned &&
- copy_to_user(ioctl_u.bytes_returned,
- &bytes_returned, sizeof(u32)))
- goto err_exit;
-
- err = 0;
- }
-
-err_exit:
- kfree(ioctl_k.inbuf);
- kfree(ioctl_k.outbuf);
-
- return err;
-}
-
-static int hptiop_cdev_open(struct inode *inode, struct file *file)
-{
- struct hptiop_hba *hba;
- unsigned i = 0, minor = iminor(inode);
- int ret = -ENODEV;
-
- spin_lock(&hptiop_hba_list_lock);
- list_for_each_entry(hba, &hptiop_hba_list, link) {
- if (i == minor) {
- file->private_data = hba;
- ret = 0;
- goto out;
- }
- i++;
- }
-
-out:
- spin_unlock(&hptiop_hba_list_lock);
- return ret;
-}
-
-static struct file_operations hptiop_cdev_fops = {
- .owner = THIS_MODULE,
- .read = hptiop_cdev_read,
- .ioctl = hptiop_cdev_ioctl,
- .open = hptiop_cdev_open,
-};
-
static ssize_t hptiop_show_fw_version(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *host = class_to_shost(class_dev);
@@ -1296,19 +770,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
goto unmap_pci_bar;
}
- if (scsi_add_host(host, &pcidev->dev)) {
- printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
- hba->host->host_no);
- goto unmap_pci_bar;
- }
-
pci_set_drvdata(pcidev, host);
- if (request_irq(pcidev->irq, hptiop_intr, SA_SHIRQ,
+ if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED,
driver_name, hba)) {
printk(KERN_ERR "scsi%d: request irq %d failed\n",
hba->host->host_no, pcidev->irq);
- goto remove_scsi_host;
+ goto unmap_pci_bar;
}
/* Allocate request mem */
@@ -1355,9 +823,12 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
if (hptiop_initialize_iop(hba))
goto free_request_mem;
- spin_lock(&hptiop_hba_list_lock);
- list_add_tail(&hba->link, &hptiop_hba_list);
- spin_unlock(&hptiop_hba_list_lock);
+ if (scsi_add_host(host, &pcidev->dev)) {
+ printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
+ hba->host->host_no);
+ goto free_request_mem;
+ }
+
scsi_scan_host(host);
@@ -1372,9 +843,6 @@ free_request_mem:
free_request_irq:
free_irq(hba->pcidev->irq, hba);
-remove_scsi_host:
- scsi_remove_host(host);
-
unmap_pci_bar:
iounmap(hba->iop);
@@ -1422,10 +890,6 @@ static void hptiop_remove(struct pci_dev *pcidev)
scsi_remove_host(host);
- spin_lock(&hptiop_hba_list_lock);
- list_del_init(&hba->link);
- spin_unlock(&hptiop_hba_list_lock);
-
hptiop_shutdown(pcidev);
free_irq(hba->pcidev->irq, hba);
@@ -1462,27 +926,12 @@ static struct pci_driver hptiop_pci_driver = {
static int __init hptiop_module_init(void)
{
- int error;
-
printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver);
-
- error = pci_register_driver(&hptiop_pci_driver);
- if (error < 0)
- return error;
-
- hptiop_cdev_major = register_chrdev(0, "hptiop", &hptiop_cdev_fops);
- if (hptiop_cdev_major < 0) {
- printk(KERN_WARNING "unable to register hptiop device.\n");
- return hptiop_cdev_major;
- }
-
- return 0;
+ return pci_register_driver(&hptiop_pci_driver);
}
static void __exit hptiop_module_exit(void)
{
- dprintk("hptiop_module_exit\n");
- unregister_chrdev(hptiop_cdev_major, "hptiop");
pci_unregister_driver(&hptiop_pci_driver);
}
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 115f55471ed..2be1dc5d852 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -17,7 +17,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -760,7 +759,7 @@ static int device_inquiry(int host_index, int ldn)
while (!got_interrupt(host_index))
barrier();
- /*if command succesful, break */
+ /*if command successful, break */
if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
@@ -885,7 +884,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun,
while (!got_interrupt(host_index))
barrier();
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -921,7 +920,7 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti
return 2;
} else
global_command_error_excuse = 0;
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -959,7 +958,7 @@ static int immediate_reset(int host_index, unsigned int ldn)
/* did not work, finish */
return 1;
}
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -1511,7 +1510,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
#endif
/* get interrupt request level */
- if (request_irq(IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+ if (request_irq(IM_IRQ, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
return 0;
} else
@@ -1636,7 +1635,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
/* IRQ11 is used by SCSI-2 F/W Adapter/A */
printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
/* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+ if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
} else
IRQ11_registered++;
@@ -1697,7 +1696,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
/* IRQ11 is used by SCSI-2 F/W Adapter/A */
printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
/* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts))
+ if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts))
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
else
IRQ11_registered++;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 944fc1203eb..669ea4fff16 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -535,6 +535,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
struct ibmvscsi_host_data *hostdata)
{
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+ int request_status;
int rc;
/* If we have exhausted our request limit, just fail this request.
@@ -542,9 +543,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
* (such as task management requests) that the mid layer may think we
* can handle more requests (can_queue) when we actually can't
*/
- if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
- (atomic_dec_if_positive(&hostdata->request_limit) < 0))
- goto send_error;
+ if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+ request_status =
+ atomic_dec_if_positive(&hostdata->request_limit);
+ /* If request limit was -1 when we started, it is now even
+ * less than that
+ */
+ if (request_status < -1)
+ goto send_error;
+ /* Otherwise, if we have run out of requests */
+ else if (request_status < 0)
+ goto send_busy;
+ }
/* Copy the IU into the transfer area */
*evt_struct->xfer_iu = evt_struct->iu;
@@ -567,11 +577,23 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
return 0;
- send_error:
+ send_busy:
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
+
+ send_error:
+ unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
+
+ if (evt_struct->cmnd != NULL) {
+ evt_struct->cmnd->result = DID_ERROR << 16;
+ evt_struct->cmnd_done(evt_struct->cmnd);
+ } else if (evt_struct->done)
+ evt_struct->done(evt_struct);
+
+ free_event_struct(&hostdata->pool, evt_struct);
+ return 0;
}
/**
@@ -1184,27 +1206,37 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
return;
case 0xFF: /* Hypervisor telling us the connection is closed */
scsi_block_requests(hostdata->host);
+ atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
/* We need to re-setup the interpartition connection */
printk(KERN_INFO
"ibmvscsi: Re-enabling adapter!\n");
- atomic_set(&hostdata->request_limit, -1);
purge_requests(hostdata, DID_REQUEUE);
- if (ibmvscsi_reenable_crq_queue(&hostdata->queue,
- hostdata) == 0)
- if (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))
+ if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
+ hostdata) == 0) ||
+ (ibmvscsi_send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
+ atomic_set(&hostdata->request_limit,
+ -1);
printk(KERN_ERR
- "ibmvscsi: transmit error after"
+ "ibmvscsi: error after"
" enable\n");
+ }
} else {
printk(KERN_INFO
"ibmvscsi: Virtual adapter failed rc %d!\n",
crq->format);
- atomic_set(&hostdata->request_limit, -1);
purge_requests(hostdata, DID_ERROR);
- ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+ if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
+ atomic_set(&hostdata->request_limit,
+ -1);
+ printk(KERN_ERR
+ "ibmvscsi: error after reset\n");
+ }
}
scsi_unblock_requests(hostdata->host);
return;
@@ -1467,6 +1499,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct Scsi_Host *host;
struct device *dev = &vdev->dev;
unsigned long wait_switch = 0;
+ int rc;
vdev->dev.driver_data = NULL;
@@ -1484,8 +1517,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
atomic_set(&hostdata->request_limit, -1);
hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
- if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
- max_requests) != 0) {
+ rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+ if (rc != 0 && rc != H_RESOURCE) {
printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
goto init_crq_failed;
}
@@ -1505,7 +1538,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
* to fail if the other end is not acive. In that case we don't
* want to scan
*/
- if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) {
+ if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+ || rc == H_RESOURCE) {
/*
* Wait around max init_timeout secs for the adapter to finish
* initializing. When we are done initializing, we will have a
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
index 7eed0b09817..6aeb5f003c3 100644
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -81,7 +81,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
int rc;
single_host_data = hostdata;
- rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0);
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests);
if (rc < 0) {
printk("viopath_open failed with rc %d in open_event_path\n",
rc);
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 1a9992bdfef..01b8ac641eb 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -156,8 +156,8 @@ static void gather_partition_info(void)
{
struct device_node *rootdn;
- char *ppartition_name;
- unsigned int *p_number_ptr;
+ const char *ppartition_name;
+ const unsigned int *p_number_ptr;
/* Retrieve information about this partition */
rootdn = find_path_device("/");
@@ -165,14 +165,11 @@ static void gather_partition_info(void)
return;
}
- ppartition_name =
- get_property(rootdn, "ibm,partition-name", NULL);
+ ppartition_name = get_property(rootdn, "ibm,partition-name", NULL);
if (ppartition_name)
strncpy(partition_name, ppartition_name,
sizeof(partition_name));
- p_number_ptr =
- (unsigned int *)get_property(rootdn, "ibm,partition-no",
- NULL);
+ p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = *p_number_ptr;
}
@@ -208,6 +205,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
int max_requests)
{
int rc;
+ int retrc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
@@ -226,7 +224,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
gather_partition_info();
set_adapter_info(hostdata);
- rc = plpar_hcall_norets(H_REG_CRQ,
+ retrc = rc = plpar_hcall_norets(H_REG_CRQ,
vdev->unit_address,
queue->msg_token, PAGE_SIZE);
if (rc == H_RESOURCE)
@@ -237,6 +235,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
if (rc == 2) {
/* Adapter is good, but other end is not ready */
printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ retrc = 0;
} else if (rc != 0) {
printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
goto reg_crq_failed;
@@ -263,7 +262,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
(unsigned long)hostdata);
- return 0;
+ return retrc;
req_irq_failed:
do {
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 988e6f7af01..94d1de55607 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -34,7 +34,6 @@
#define IDESCSI_VERSION "0.92"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -518,7 +517,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
/* No more interrupts */
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
- local_irq_enable();
+ local_irq_enable_in_hardirq();
if (status.b.check)
rq->errors++;
idescsi_end_request (drive, 1, 0);
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index cd2dffdab77..2d95ac9c32c 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -3,15 +3,11 @@
*
* (The IMM is the embedded controller in the ZIP Plus drive.)
*
- * Current Maintainer: David Campbell (Perth, Western Australia)
- * campbell@torque.net
- *
* My unoffical company acronym list is 21 pages long:
* FLA: Four letter acronym with built in facility for
* future expansion to five letters.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index dc3aebf0e36..ece936ac29c 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -2,7 +2,7 @@
/* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in
* the Iomega ZIP Plus drive
*
- * (c) 1998 David Campbell campbell@torque.net
+ * (c) 1998 David Campbell
*
* Please note that I live in Perth, Western Australia. GMT+0800
*/
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 883bc92b4d9..59a4097f125 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2015,7 +2015,7 @@ static int __init in2000_detect(struct scsi_host_template * tpnt)
write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */
write1_io(0, IO_INTR_MASK); /* allow all ints */
x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", instance)) {
+ if (request_irq(x, in2000_intr, IRQF_DISABLED, "in2000", instance)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 913ba95f85b..9e10dac61cf 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -118,7 +118,6 @@
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
@@ -2868,7 +2867,7 @@ static int i91u_detect(struct scsi_host_template * tpnt)
hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
/* Initial tulip chip */
- ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr, IRQF_DISABLED | IRQF_SHARED, "i91u", hreg);
if (ok < 0) {
printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
return 0;
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
index 3efb1184fc3..acb67a4af2c 100644
--- a/drivers/scsi/initio.h
+++ b/drivers/scsi/initio.h
@@ -54,7 +54,6 @@
**************************************************************************/
-#include <linux/config.h>
#include <linux/types.h>
#define ULONG unsigned long
@@ -193,13 +192,13 @@ typedef struct {
#define TSC_SEL_ATN_DIRECT_OUT 0x15 /* Select With ATN Sequence */
#define TSC_SEL_ATN3_DIRECT_IN 0xB5 /* Select With ATN3 Sequence */
#define TSC_SEL_ATN3_DIRECT_OUT 0x35 /* Select With ATN3 Sequence */
-#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Infomation out */
-#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Infomation in */
+#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Information out */
+#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Information in */
-#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Infomation out */
-#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Infomation in */
-#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Infomation out */
-#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Infomation in */
+#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Information out */
+#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Information in */
+#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Information out */
+#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Information in */
#define TSC_MSG_ACCEPT 0x0F /* Message Accept */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 96b65b307dd..7ed4eef8347 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -54,7 +54,6 @@
*
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -176,6 +175,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"Qualified success"},
{0x01080000, 1, 1,
"FFFE: Soft device bus error recovered by the IOA"},
+ {0x01088100, 0, 1,
+ "4101: Soft device bus fabric error"},
{0x01170600, 0, 1,
"FFF9: Device sector reassign successful"},
{0x01170900, 0, 1,
@@ -226,6 +227,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"3109: IOA timed out a device command"},
{0x04088000, 0, 0,
"3120: SCSI bus is not operational"},
+ {0x04088100, 0, 1,
+ "4100: Hard device bus fabric error"},
{0x04118000, 0, 1,
"9000: IOA reserved area data check"},
{0x04118100, 0, 1,
@@ -274,6 +277,14 @@ struct ipr_error_table_t ipr_error_table[] = {
"9091: Incorrect hardware configuration change has been detected"},
{0x04678000, 0, 1,
"9073: Invalid multi-adapter configuration"},
+ {0x04678100, 0, 1,
+ "4010: Incorrect connection between cascaded expanders"},
+ {0x04678200, 0, 1,
+ "4020: Connections exceed IOA design limits"},
+ {0x04678300, 0, 1,
+ "4030: Incorrect multipath connection"},
+ {0x04679000, 0, 1,
+ "4110: Unsupported enclosure function"},
{0x046E0000, 0, 1,
"FFF4: Command to logical unit failed"},
{0x05240000, 1, 0,
@@ -298,6 +309,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"9031: Array protection temporarily suspended, protection resuming"},
{0x06040600, 0, 1,
"9040: Array protection temporarily suspended, protection resuming"},
+ {0x06288000, 0, 1,
+ "3140: Device bus not ready to ready transition"},
{0x06290000, 0, 1,
"FFFB: SCSI bus was reset"},
{0x06290500, 0, 0,
@@ -320,6 +333,16 @@ struct ipr_error_table_t ipr_error_table[] = {
"3150: SCSI bus configuration error"},
{0x06678100, 0, 1,
"9074: Asymmetric advanced function disk configuration"},
+ {0x06678300, 0, 1,
+ "4040: Incomplete multipath connection between IOA and enclosure"},
+ {0x06678400, 0, 1,
+ "4041: Incomplete multipath connection between enclosure and device"},
+ {0x06678500, 0, 1,
+ "9075: Incomplete multipath connection between IOA and remote IOA"},
+ {0x06678600, 0, 1,
+ "9076: Configuration error, missing remote IOA"},
+ {0x06679100, 0, 1,
+ "4050: Enclosure does not support a required multipath function"},
{0x06690200, 0, 1,
"9041: Array protection temporarily suspended"},
{0x06698200, 0, 1,
@@ -332,6 +355,10 @@ struct ipr_error_table_t ipr_error_table[] = {
"9072: Link not operational transition"},
{0x066B8200, 0, 1,
"9032: Array exposed but still protected"},
+ {0x066B9100, 0, 1,
+ "4061: Multipath redundancy level got better"},
+ {0x066B9200, 0, 1,
+ "4060: Multipath redundancy level got worse"},
{0x07270000, 0, 0,
"Failure due to other device"},
{0x07278000, 0, 1,
@@ -4100,8 +4127,7 @@ static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
- if ((be32_to_cpu(ioasa->ioasc_specific) &
- (IPR_ADDITIONAL_STATUS_FMT | IPR_AUTOSENSE_VALID)) == 0)
+ if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0)
return 0;
memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
@@ -4191,7 +4217,8 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
case IPR_IOASC_NR_INIT_CMD_REQUIRED:
break;
default:
- scsi_cmd->result |= (DID_ERROR << 16);
+ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
+ scsi_cmd->result |= (DID_ERROR << 16);
if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res))
res->needs_sync_complete = 1;
break;
@@ -6429,7 +6456,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg->needs_hard_reset = 1;
ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
- rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg);
+ rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
if (rc) {
dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n",
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 1ad24df69d7..11eaff52432 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -36,8 +36,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.1.3"
-#define IPR_DRIVER_DATE "(March 29, 2006)"
+#define IPR_DRIVER_VERSION "2.1.4"
+#define IPR_DRIVER_DATE "(August 2, 2006)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -45,6 +45,7 @@
* This can be adjusted at runtime through sysfs device attributes.
*/
#define IPR_MAX_CMD_PER_LUN 6
+#define IPR_MAX_CMD_PER_ATA_LUN 1
/*
* IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
@@ -106,7 +107,7 @@
#define IPR_IOA_BUS 0xff
#define IPR_IOA_TARGET 0xff
#define IPR_IOA_LUN 0xff
-#define IPR_MAX_NUM_BUSES 8
+#define IPR_MAX_NUM_BUSES 16
#define IPR_MAX_BUS_TO_SCAN IPR_MAX_NUM_BUSES
#define IPR_NUM_RESET_RELOAD_RETRIES 3
@@ -145,6 +146,7 @@
#define IPR_LUN_RESET 0x40
#define IPR_TARGET_RESET 0x20
#define IPR_BUS_RESET 0x10
+#define IPR_ATA_PHY_RESET 0x80
#define IPR_ID_HOST_RR_Q 0xC4
#define IPR_QUERY_IOA_CONFIG 0xC5
#define IPR_CANCEL_ALL_REQUESTS 0xCE
@@ -295,7 +297,11 @@ struct ipr_std_inq_data {
}__attribute__ ((packed));
struct ipr_config_table_entry {
- u8 service_level;
+ u8 proto;
+#define IPR_PROTO_SATA 0x02
+#define IPR_PROTO_SATA_ATAPI 0x03
+#define IPR_PROTO_SAS_STP 0x06
+#define IPR_PROTO_SAS_STP_ATAPI 0x07
u8 array_id;
u8 flags;
#define IPR_IS_IOA_RESOURCE 0x80
@@ -307,6 +313,7 @@ struct ipr_config_table_entry {
#define IPR_SUBTYPE_AF_DASD 0
#define IPR_SUBTYPE_GENERIC_SCSI 1
#define IPR_SUBTYPE_VOLUME_SET 2
+#define IPR_SUBTYPE_GENERIC_ATA 4
#define IPR_QUEUEING_MODEL(res) ((((res)->cfgte.flags) & 0x70) >> 4)
#define IPR_QUEUE_FROZEN_MODEL 0
@@ -350,6 +357,7 @@ struct ipr_cmd_pkt {
#define IPR_RQTYPE_SCSICDB 0x00
#define IPR_RQTYPE_IOACMD 0x01
#define IPR_RQTYPE_HCAM 0x02
+#define IPR_RQTYPE_ATA_PASSTHRU 0x04
u8 luntar_luntrn;
@@ -373,6 +381,37 @@ struct ipr_cmd_pkt {
__be16 timeout;
}__attribute__ ((packed, aligned(4)));
+struct ipr_ioarcb_ata_regs {
+ u8 flags;
+#define IPR_ATA_FLAG_PACKET_CMD 0x80
+#define IPR_ATA_FLAG_XFER_TYPE_DMA 0x40
+#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION 0x20
+ u8 reserved[3];
+
+ __be16 data;
+ u8 feature;
+ u8 nsect;
+ u8 lbal;
+ u8 lbam;
+ u8 lbah;
+ u8 device;
+ u8 command;
+ u8 reserved2[3];
+ u8 hob_feature;
+ u8 hob_nsect;
+ u8 hob_lbal;
+ u8 hob_lbam;
+ u8 hob_lbah;
+ u8 ctl;
+}__attribute__ ((packed, aligned(4)));
+
+struct ipr_ioarcb_add_data {
+ union {
+ struct ipr_ioarcb_ata_regs regs;
+ __be32 add_cmd_parms[10];
+ }u;
+}__attribute__ ((packed, aligned(4)));
+
/* IOA Request Control Block 128 bytes */
struct ipr_ioarcb {
__be32 ioarcb_host_pci_addr;
@@ -397,7 +436,7 @@ struct ipr_ioarcb {
struct ipr_cmd_pkt cmd_pkt;
__be32 add_cmd_parms_len;
- __be32 add_cmd_parms[10];
+ struct ipr_ioarcb_add_data add_data;
}__attribute__((packed, aligned (4)));
struct ipr_ioadl_desc {
@@ -433,6 +472,21 @@ struct ipr_ioasa_gpdd {
__be32 ioa_data[2];
}__attribute__((packed, aligned (4)));
+struct ipr_ioasa_gata {
+ u8 error;
+ u8 nsect; /* Interrupt reason */
+ u8 lbal;
+ u8 lbam;
+ u8 lbah;
+ u8 device;
+ u8 status;
+ u8 alt_status; /* ATA CTL */
+ u8 hob_nsect;
+ u8 hob_lbal;
+ u8 hob_lbam;
+ u8 hob_lbah;
+}__attribute__((packed, aligned (4)));
+
struct ipr_auto_sense {
__be16 auto_sense_len;
__be16 ioa_data_len;
@@ -466,6 +520,7 @@ struct ipr_ioasa {
__be32 ioasc_specific; /* status code specific field */
#define IPR_ADDITIONAL_STATUS_FMT 0x80000000
#define IPR_AUTOSENSE_VALID 0x40000000
+#define IPR_ATA_DEVICE_WAS_RESET 0x20000000
#define IPR_IOASC_SPECIFIC_MASK 0x00ffffff
#define IPR_FIELD_POINTER_VALID (0x80000000 >> 8)
#define IPR_FIELD_POINTER_MASK 0x0000ffff
@@ -474,6 +529,7 @@ struct ipr_ioasa {
struct ipr_ioasa_vset vset;
struct ipr_ioasa_af_dasd dasd;
struct ipr_ioasa_gpdd gpdd;
+ struct ipr_ioasa_gata gata;
} u;
struct ipr_auto_sense auto_sense;
@@ -1308,6 +1364,22 @@ static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res)
}
/**
+ * ipr_is_gata - Determine if a resource is a generic ATA resource
+ * @res: resource entry struct
+ *
+ * Return value:
+ * 1 if GATA / 0 if not GATA
+ **/
+static inline int ipr_is_gata(struct ipr_resource_entry *res)
+{
+ if (!ipr_is_ioa_resource(res) &&
+ IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_ATA)
+ return 1;
+ else
+ return 0;
+}
+
+/**
* ipr_is_naca_model - Determine if a resource is using NACA queueing model
* @res: resource entry struct
*
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 5353b28b293..3c639286ec1 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -196,7 +196,6 @@
#include <linux/module.h>
#include <linux/stat.h>
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/init.h>
@@ -6438,7 +6437,7 @@ ips_erase_bios(ips_ha_t * ha)
/* VPP failure */
return (1);
- /* check for succesful flash */
+ /* check for successful flash */
if (status & 0x30)
/* sequence error */
return (1);
@@ -6550,7 +6549,7 @@ ips_erase_bios_memio(ips_ha_t * ha)
/* VPP failure */
return (1);
- /* check for succesful flash */
+ /* check for successful flash */
if (status & 0x30)
/* sequence error */
return (1);
@@ -7008,7 +7007,7 @@ ips_register_scsi(int index)
memcpy(ha, oldha, sizeof (ips_ha_t));
free_irq(oldha->irq, oldha);
/* Install the interrupt handler with the new ha */
- if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+ if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
IPS_PRINTK(KERN_WARNING, ha->pcidev,
"Unable to install interrupt handler\n");
scsi_host_put(sh);
@@ -7420,7 +7419,7 @@ ips_init_phase2(int index)
}
/* Install the interrupt handler */
- if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+ if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
IPS_PRINTK(KERN_WARNING, ha->pcidev,
"Unable to install interrupt handler\n");
return ips_abort_init(ha, index);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index b4743a9ecc8..0a9dbc59663 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -43,13 +43,10 @@
#include "iscsi_tcp.h"
-#define ISCSI_TCP_VERSION "1.0-595"
-
MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI/TCP data-path");
MODULE_LICENSE("GPL");
-MODULE_VERSION(ISCSI_TCP_VERSION);
/* #define DEBUG_TCP */
#define DEBUG_ASSERT
@@ -111,8 +108,8 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
- buf->sg.length += sizeof(uint32_t);
+ crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
+ buf->sg.length = tcp_conn->hdr_size;
}
static inline int
@@ -185,11 +182,19 @@ iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
* must be called with session lock
*/
static void
-__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_r2t_info *r2t;
struct scsi_cmnd *sc;
+ /* flush ctask's r2t queues */
+ while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
+ __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ sizeof(void*));
+ debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
+ }
+
sc = ctask->sc;
if (unlikely(!sc))
return;
@@ -276,7 +281,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
{
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
@@ -331,10 +335,12 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
sg_count += sg->length;
}
BUG_ON(r2t->sg == NULL);
- } else
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
+ } else {
+ iscsi_buf_init_iov(&r2t->sendbuf,
(char*)sc->request_buffer + r2t->data_offset,
r2t->data_count);
+ r2t->sg = NULL;
+ }
}
/**
@@ -353,8 +359,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
int r2tsn = be32_to_cpu(rhdr->r2tsn);
int rc;
- if (tcp_conn->in.datalen)
+ if (tcp_conn->in.datalen) {
+ printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n",
+ tcp_conn->in.datalen);
return ISCSI_ERR_DATALEN;
+ }
if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
return ISCSI_ERR_R2TSN;
@@ -374,20 +383,29 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
spin_unlock(&session->lock);
return 0;
}
+
rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
BUG_ON(!rc);
r2t->exp_statsn = rhdr->statsn;
r2t->data_length = be32_to_cpu(rhdr->data_length);
- if (r2t->data_length == 0 ||
- r2t->data_length > session->max_burst) {
+ if (r2t->data_length == 0) {
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
spin_unlock(&session->lock);
return ISCSI_ERR_DATALEN;
}
+ if (r2t->data_length > session->max_burst)
+ debug_scsi("invalid R2T with data len %u and max burst %u."
+ "Attempting to execute request.\n",
+ r2t->data_length, session->max_burst);
+
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
if (r2t->data_offset + r2t->data_length > ctask->total_length) {
spin_unlock(&session->lock);
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
+ "offset %u and total length %d\n", r2t->data_length,
+ r2t->data_offset, ctask->total_length);
return ISCSI_ERR_DATALEN;
}
@@ -399,7 +417,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
tcp_ctask->exp_r2tsn = r2tsn + 1;
tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
- __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
+ list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork);
conn->r2t_pdus_cnt++;
@@ -450,7 +468,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
sg_init_one(&sg, (u8 *)hdr,
sizeof(struct iscsi_hdr) + ahslen);
- crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
+ crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+ (u8 *)&cdgst);
rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
ahslen);
if (cdgst != rdgst) {
@@ -477,6 +496,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
case ISCSI_OP_SCSI_DATA_IN:
tcp_conn->in.ctask = session->cmds[itt];
rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
+ if (rc)
+ return rc;
/* fall through */
case ISCSI_OP_SCSI_CMD_RSP:
tcp_conn->in.ctask = session->cmds[itt];
@@ -484,7 +505,6 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
goto copy_hdr;
spin_lock(&session->lock);
- __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
spin_unlock(&session->lock);
break;
@@ -500,13 +520,28 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
break;
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
- case ISCSI_OP_LOGOUT_RSP:
- case ISCSI_OP_NOOP_IN:
case ISCSI_OP_REJECT:
case ISCSI_OP_ASYNC_EVENT:
+ /*
+ * It is possible that we could get a PDU with a buffer larger
+ * than 8K, but there are no targets that currently do this.
+ * For now we fail until we find a vendor that needs it
+ */
+ if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
+ tcp_conn->in.datalen) {
+ printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
+ "but conn buffer is only %u (opcode %0x)\n",
+ tcp_conn->in.datalen,
+ DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
+
if (tcp_conn->in.datalen)
goto copy_hdr;
/* fall through */
+ case ISCSI_OP_LOGOUT_RSP:
+ case ISCSI_OP_NOOP_IN:
case ISCSI_OP_SCSI_TMFUNC_RSP:
rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
break;
@@ -523,7 +558,7 @@ copy_hdr:
* skbs to complete the command then we have to copy the header
* for later use
*/
- if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <
+ if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
(tcp_conn->in.datalen + tcp_conn->in.padding +
(conn->datadgst_en ? 4 : 0))) {
debug_tcp("Copying header for later use. in.copy %d in.datalen"
@@ -614,10 +649,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
* byte counters.
**/
static inline int
-iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
+iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
{
- void *buf = tcp_conn->data;
- int buf_size = tcp_conn->in.datalen;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int buf_left = buf_size - tcp_conn->data_copied;
int size = min(tcp_conn->in.copy, buf_left);
int rc;
@@ -627,7 +661,7 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
BUG_ON(size <= 0);
rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
- (char*)buf + tcp_conn->data_copied, size);
+ (char*)conn->data + tcp_conn->data_copied, size);
BUG_ON(rc);
tcp_conn->in.offset += size;
@@ -642,15 +676,15 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
}
static inline void
-partial_sg_digest_update(struct iscsi_tcp_conn *tcp_conn,
- struct scatterlist *sg, int offset, int length)
+partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
+ int offset, int length)
{
struct scatterlist temp;
memcpy(&temp, sg, sizeof(struct scatterlist));
temp.offset = offset;
temp.length = length;
- crypto_digest_update(tcp_conn->data_rx_tfm, &temp, 1);
+ crypto_hash_update(desc, &temp, length);
}
static void
@@ -659,7 +693,7 @@ iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
struct scatterlist tmp;
sg_init_one(&tmp, buf, len);
- crypto_digest_update(tcp_conn->data_rx_tfm, &tmp, 1);
+ crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
}
static int iscsi_scsi_data_in(struct iscsi_conn *conn)
@@ -713,11 +747,12 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
if (!rc) {
if (conn->datadgst_en) {
if (!offset)
- crypto_digest_update(
- tcp_conn->data_rx_tfm,
+ crypto_hash_update(
+ &tcp_conn->rx_hash,
&sg[i], 1);
else
- partial_sg_digest_update(tcp_conn,
+ partial_sg_digest_update(
+ &tcp_conn->rx_hash,
&sg[i],
sg[i].offset + offset,
sg[i].length - offset);
@@ -731,8 +766,10 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
/*
* data-in is complete, but buffer not...
*/
- partial_sg_digest_update(tcp_conn, &sg[i],
- sg[i].offset, sg[i].length-rc);
+ partial_sg_digest_update(&tcp_conn->rx_hash,
+ &sg[i],
+ sg[i].offset,
+ sg[i].length-rc);
rc = 0;
break;
}
@@ -745,10 +782,10 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
done:
/* check for non-exceptional status */
if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
- debug_scsi("done [sc %lx res %d itt 0x%x]\n",
- (long)sc, sc->result, ctask->itt);
+ debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
+ (long)sc, sc->result, ctask->itt,
+ tcp_conn->in.hdr->flags);
spin_lock(&conn->session->lock);
- __iscsi_ctask_cleanup(conn, ctask);
__iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
spin_unlock(&conn->session->lock);
}
@@ -768,27 +805,23 @@ iscsi_data_recv(struct iscsi_conn *conn)
rc = iscsi_scsi_data_in(conn);
break;
case ISCSI_OP_SCSI_CMD_RSP:
- spin_lock(&conn->session->lock);
- __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
- spin_unlock(&conn->session->lock);
case ISCSI_OP_TEXT_RSP:
case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_NOOP_IN:
case ISCSI_OP_ASYNC_EVENT:
case ISCSI_OP_REJECT:
/*
* Collect data segment to the connection's data
* placeholder
*/
- if (iscsi_tcp_copy(tcp_conn)) {
+ if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
rc = -EAGAIN;
goto exit;
}
- rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data,
+ rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
tcp_conn->in.datalen);
if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
- iscsi_recv_digest_update(tcp_conn, tcp_conn->data,
+ iscsi_recv_digest_update(tcp_conn, conn->data,
tcp_conn->in.datalen);
break;
default:
@@ -843,7 +876,7 @@ more:
if (rc == -EAGAIN)
goto nomore;
else {
- iscsi_conn_failure(conn, rc);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
}
@@ -853,10 +886,8 @@ more:
*/
rc = iscsi_tcp_hdr_recv(conn);
if (!rc && tcp_conn->in.datalen) {
- if (conn->datadgst_en) {
- BUG_ON(!tcp_conn->data_rx_tfm);
- crypto_digest_init(tcp_conn->data_rx_tfm);
- }
+ if (conn->datadgst_en)
+ crypto_hash_init(&tcp_conn->rx_hash);
tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
} else if (rc) {
iscsi_conn_failure(conn, rc);
@@ -869,10 +900,15 @@ more:
debug_tcp("extra data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
- skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
- &recv_digest, 4);
- tcp_conn->in.offset += 4;
- tcp_conn->in.copy -= 4;
+ rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
+ if (rc) {
+ if (rc == -EAGAIN)
+ goto again;
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ return 0;
+ }
+
+ memcpy(&recv_digest, conn->data, sizeof(uint32_t));
if (recv_digest != tcp_conn->in.datadgst) {
debug_tcp("iscsi_tcp: data digest error!"
"0x%x != 0x%x\n", recv_digest,
@@ -897,7 +933,7 @@ more:
if (rc) {
if (rc == -EAGAIN)
goto again;
- iscsi_conn_failure(conn, rc);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
tcp_conn->in.copy -= tcp_conn->in.padding;
@@ -908,13 +944,14 @@ more:
tcp_conn->in.padding);
memset(pad, 0, tcp_conn->in.padding);
sg_init_one(&sg, pad, tcp_conn->in.padding);
- crypto_digest_update(tcp_conn->data_rx_tfm,
- &sg, 1);
+ crypto_hash_update(&tcp_conn->rx_hash,
+ &sg, sg.length);
}
- crypto_digest_final(tcp_conn->data_rx_tfm,
- (u8 *) & tcp_conn->in.datadgst);
+ crypto_hash_final(&tcp_conn->rx_hash,
+ (u8 *) &tcp_conn->in.datadgst);
debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ tcp_conn->data_copied = 0;
} else
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
}
@@ -1028,9 +1065,8 @@ iscsi_conn_set_callbacks(struct iscsi_conn *conn)
}
static void
-iscsi_conn_restore_callbacks(struct iscsi_conn *conn)
+iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct sock *sk = tcp_conn->sock->sk;
/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
@@ -1155,37 +1191,12 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
static inline void
iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_cmd_task *ctask)
+ struct iscsi_tcp_cmd_task *tcp_ctask)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-
- BUG_ON(!tcp_conn->data_tx_tfm);
- crypto_digest_init(tcp_conn->data_tx_tfm);
+ crypto_hash_init(&tcp_conn->tx_hash);
tcp_ctask->digest_count = 4;
}
-static int
-iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- struct iscsi_buf *buf, uint32_t *digest, int final)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- int rc = 0;
- int sent = 0;
-
- if (final)
- crypto_digest_final(tcp_conn->data_tx_tfm, (u8*)digest);
-
- iscsi_buf_init_iov(buf, (char*)digest, 4);
- rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
- if (rc) {
- tcp_ctask->datadigest = *digest;
- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
- } else
- tcp_ctask->digest_count = 4;
- return rc;
-}
-
/**
* iscsi_solicit_data_cont - initialize next Data-Out
* @conn: iscsi connection
@@ -1203,7 +1214,6 @@ static void
iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
struct iscsi_r2t_info *r2t, int left)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
int new_offset;
@@ -1232,27 +1242,30 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- if (sc->use_sg && !iscsi_buf_left(&r2t->sendbuf)) {
- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
+ if (iscsi_buf_left(&r2t->sendbuf))
+ return;
+
+ if (sc->use_sg) {
iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
r2t->sg += 1;
- } else
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
+ } else {
+ iscsi_buf_init_iov(&r2t->sendbuf,
(char*)sc->request_buffer + new_offset,
r2t->data_count);
+ r2t->sg = NULL;
+ }
}
-static void
-iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
+ unsigned long len)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_data_task *dtask;
+ tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
+ if (!tcp_ctask->pad_count)
+ return;
- dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
- iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
- tcp_ctask->r2t_data_count);
- iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
- sizeof(struct iscsi_hdr));
+ tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
+ debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
+ tcp_ctask->xmstate |= XMSTATE_W_PAD;
}
/**
@@ -1280,38 +1293,20 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
if (sc->use_sg) {
struct scatterlist *sg = sc->request_buffer;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &sg[tcp_ctask->sg_count++]);
- tcp_ctask->sg = sg;
+ iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
+ tcp_ctask->sg = sg + 1;
tcp_ctask->bad_sg = sg + sc->use_sg;
- } else
+ } else {
iscsi_buf_init_iov(&tcp_ctask->sendbuf,
sc->request_buffer,
sc->request_bufflen);
-
- if (ctask->imm_count)
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
-
- tcp_ctask->pad_count = ctask->total_length & (ISCSI_PAD_LEN-1);
- if (tcp_ctask->pad_count) {
- tcp_ctask->pad_count = ISCSI_PAD_LEN -
- tcp_ctask->pad_count;
- debug_scsi("write padding %d bytes\n",
- tcp_ctask->pad_count);
- tcp_ctask->xmstate |= XMSTATE_W_PAD;
+ tcp_ctask->sg = NULL;
+ tcp_ctask->bad_sg = NULL;
}
-
- if (ctask->unsol_count)
- tcp_ctask->xmstate |= XMSTATE_UNS_HDR |
- XMSTATE_UNS_INIT;
- tcp_ctask->r2t_data_count = ctask->total_length -
- ctask->imm_count -
- ctask->unsol_count;
-
- debug_scsi("cmd [itt %x total %d imm %d imm_data %d "
- "r2t_data %d]\n",
+ debug_scsi("cmd [itt 0x%x total %d imm_data %d "
+ "unsol count %d, unsol offset %d]\n",
ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count, tcp_ctask->r2t_data_count);
+ ctask->unsol_count, ctask->unsol_offset);
} else
tcp_ctask->xmstate = XMSTATE_R_HDR;
@@ -1393,8 +1388,8 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
}
static inline int
-handle_xmstate_r_hdr(struct iscsi_conn *conn,
- struct iscsi_tcp_cmd_task *tcp_ctask)
+iscsi_send_read_hdr(struct iscsi_conn *conn,
+ struct iscsi_tcp_cmd_task *tcp_ctask)
{
int rc;
@@ -1412,7 +1407,7 @@ handle_xmstate_r_hdr(struct iscsi_conn *conn,
}
static inline int
-handle_xmstate_w_hdr(struct iscsi_conn *conn,
+iscsi_send_write_hdr(struct iscsi_conn *conn,
struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
@@ -1423,85 +1418,126 @@ handle_xmstate_w_hdr(struct iscsi_conn *conn,
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext);
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
- if (rc)
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_W_HDR;
- return rc;
+ return rc;
+ }
+
+ if (ctask->imm_count) {
+ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_set_padding(tcp_ctask, ctask->imm_count);
+
+ if (ctask->conn->datadgst_en) {
+ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
+ tcp_ctask->immdigest = 0;
+ }
+ }
+
+ if (ctask->unsol_count)
+ tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
+ return 0;
}
-static inline int
-handle_xmstate_data_digest(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- int rc;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int sent = 0, rc;
- tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST;
- debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest);
- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->datadigest, 0);
+ if (tcp_ctask->xmstate & XMSTATE_W_PAD) {
+ iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+ tcp_ctask->pad_count);
+ if (conn->datadgst_en)
+ crypto_hash_update(&tcp_conn->tx_hash,
+ &tcp_ctask->sendbuf.sg,
+ tcp_ctask->sendbuf.sg.length);
+ } else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
+ return 0;
+
+ tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
+ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_PAD;
+ debug_scsi("sending %d pad bytes for itt 0x%x\n",
+ tcp_ctask->pad_count, ctask->itt);
+ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
+ &sent);
if (rc) {
- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
- debug_tcp("resent data digest 0x%x fail!\n",
- tcp_ctask->datadigest);
+ debug_scsi("padding send failed %d\n", rc);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_PAD;
}
-
return rc;
}
-static inline int
-handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ struct iscsi_buf *buf, uint32_t *digest)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- int rc;
+ struct iscsi_tcp_cmd_task *tcp_ctask;
+ struct iscsi_tcp_conn *tcp_conn;
+ int rc, sent = 0;
- BUG_ON(!ctask->imm_count);
- tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
+ if (!conn->datadgst_en)
+ return 0;
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- tcp_ctask->immdigest = 0;
- }
+ tcp_ctask = ctask->dd_data;
+ tcp_conn = conn->dd_data;
- for (;;) {
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
- &ctask->imm_count, &tcp_ctask->sent);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8*)&tcp_ctask->immdigest);
- debug_tcp("tx imm sendpage fail 0x%x\n",
- tcp_ctask->datadigest);
- }
- return rc;
- }
- if (conn->datadgst_en)
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
+ if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
+ crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
+ iscsi_buf_init_iov(buf, (char*)digest, 4);
+ }
+ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST;
- if (!ctask->imm_count)
- break;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &tcp_ctask->sg[tcp_ctask->sg_count++]);
+ rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
+ if (!rc)
+ debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
+ ctask->itt);
+ else {
+ debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
+ *digest, ctask->itt);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_DATA_DIGEST;
}
+ return rc;
+}
- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1);
- if (rc) {
- debug_tcp("sending imm digest 0x%x fail!\n",
- tcp_ctask->immdigest);
- return rc;
+static int
+iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
+ struct scatterlist **sg, int *sent, int *count,
+ struct iscsi_buf *digestbuf, uint32_t *digest)
+{
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_conn *conn = ctask->conn;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int rc, buf_sent, offset;
+
+ while (*count) {
+ buf_sent = 0;
+ offset = sendbuf->sent;
+
+ rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
+ *sent = *sent + buf_sent;
+ if (buf_sent && conn->datadgst_en)
+ partial_sg_digest_update(&tcp_conn->tx_hash,
+ &sendbuf->sg, sendbuf->sg.offset + offset,
+ buf_sent);
+ if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
+ iscsi_buf_init_sg(sendbuf, *sg);
+ *sg = *sg + 1;
}
- debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest);
+
+ if (rc)
+ return rc;
}
- return 0;
+ rc = iscsi_send_padding(conn, ctask);
+ if (rc)
+ return rc;
+
+ return iscsi_send_digest(conn, ctask, digestbuf, digest);
}
-static inline int
-handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_task *dtask;
@@ -1509,12 +1545,17 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
- iscsi_unsolicit_data_init(conn, ctask);
- dtask = tcp_ctask->dtask;
+ dtask = &tcp_ctask->unsol_dtask;
+
+ iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
+ iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
+ sizeof(struct iscsi_hdr));
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)dtask->hdrext);
+
tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
+ iscsi_set_padding(tcp_ctask, ctask->data_count);
}
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
@@ -1524,254 +1565,138 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
return rc;
}
+ if (conn->datadgst_en) {
+ dtask = &tcp_ctask->unsol_dtask;
+ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
+ dtask->digest = 0;
+ }
+
debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
ctask->itt, ctask->unsol_count, tcp_ctask->sent);
return 0;
}
-static inline int
-handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_data_task *dtask = tcp_ctask->dtask;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int rc;
- BUG_ON(!ctask->data_count);
- tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
-
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- dtask->digest = 0;
+ if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
+ BUG_ON(!ctask->unsol_count);
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
+send_hdr:
+ rc = iscsi_send_unsol_hdr(conn, ctask);
+ if (rc)
+ return rc;
}
- for (;;) {
+ if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
+ struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
int start = tcp_ctask->sent;
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
- &ctask->data_count, &tcp_ctask->sent);
- if (rc) {
- ctask->unsol_count -= tcp_ctask->sent - start;
- tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
- /* will continue with this ctask later.. */
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8 *)&dtask->digest);
- debug_tcp("tx uns data fail 0x%x\n",
- dtask->digest);
- }
- return rc;
- }
-
- BUG_ON(tcp_ctask->sent > ctask->total_length);
+ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+ &tcp_ctask->sent, &ctask->data_count,
+ &dtask->digestbuf, &dtask->digest);
ctask->unsol_count -= tcp_ctask->sent - start;
-
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
/*
- * XXX:we may run here with un-initial sendbuf.
- * so pass it
+ * Done with the Data-Out. Next, check if we need
+ * to send another unsolicited Data-Out.
*/
- if (conn->datadgst_en && tcp_ctask->sent - start > 0)
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
-
- if (!ctask->data_count)
- break;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &tcp_ctask->sg[tcp_ctask->sg_count++]);
- }
- BUG_ON(ctask->unsol_count < 0);
-
- /*
- * Done with the Data-Out. Next, check if we need
- * to send another unsolicited Data-Out.
- */
- if (ctask->unsol_count) {
- if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send uns digest 0x%x fail\n",
- dtask->digest);
- return rc;
- }
- debug_tcp("sending uns digest 0x%x, more uns\n",
- dtask->digest);
+ if (ctask->unsol_count) {
+ debug_scsi("sending more uns\n");
+ tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
+ goto send_hdr;
}
- tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
- return 1;
}
-
- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send last uns digest 0x%x fail\n",
- dtask->digest);
- return rc;
- }
- debug_tcp("sending uns digest 0x%x\n",dtask->digest);
- }
-
return 0;
}
-static inline int
-handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
{
- struct iscsi_session *session = conn->session;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_r2t_info *r2t = tcp_ctask->r2t;
- struct iscsi_data_task *dtask = &r2t->dtask;
+ struct iscsi_session *session = conn->session;
+ struct iscsi_r2t_info *r2t;
+ struct iscsi_data_task *dtask;
int left, rc;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->dtask = dtask;
-
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- dtask->digest = 0;
- }
-solicit_again:
- /*
- * send Data-Out whitnin this R2T sequence.
- */
- if (!r2t->data_count)
- goto data_out_done;
-
- rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent);
- if (rc) {
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- /* will continue with this ctask later.. */
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8 *)&dtask->digest);
- debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
- }
- return rc;
- }
+ if (!tcp_ctask->r2t)
+ __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
+ sizeof(void*));
+send_hdr:
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
- BUG_ON(r2t->data_count < 0);
- if (conn->datadgst_en)
- crypto_digest_update(tcp_conn->data_tx_tfm, &r2t->sendbuf.sg,
- 1);
-
- if (r2t->data_count) {
- BUG_ON(ctask->sc->use_sg == 0);
- if (!iscsi_buf_left(&r2t->sendbuf)) {
- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
- iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
- r2t->sg += 1;
+ if (conn->hdrdgst_en)
+ iscsi_hdr_digest(conn, &r2t->headbuf,
+ (u8*)dtask->hdrext);
+ rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
+ if (rc) {
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ return rc;
}
- goto solicit_again;
- }
-data_out_done:
- /*
- * Done with this Data-Out. Next, check if we have
- * to send another Data-Out for this R2T.
- */
- BUG_ON(r2t->data_length - r2t->sent < 0);
- left = r2t->data_length - r2t->sent;
- if (left) {
if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send r2t data digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("r2t data send digest 0x%x\n",
- dtask->digest);
+ iscsi_data_digest_init(conn->dd_data, tcp_ctask);
+ dtask->digest = 0;
}
- iscsi_solicit_data_cont(conn, ctask, r2t, left);
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- return 1;
- }
-
- /*
- * Done with this R2T. Check if there are more
- * outstanding R2Ts ready to be processed.
- */
- BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
- if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send last r2t data digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
- }
- tcp_ctask->r2t_data_count -= r2t->data_length;
- tcp_ctask->r2t = NULL;
- spin_lock_bh(&session->lock);
- __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
- spin_unlock_bh(&session->lock);
- if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
- tcp_ctask->r2t = r2t;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- return 1;
+ iscsi_set_padding(tcp_ctask, r2t->data_count);
+ debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
+ r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
+ r2t->sent);
}
- return 0;
-}
+ if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
-static inline int
-handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_data_task *dtask = tcp_ctask->dtask;
- int sent, rc;
+ rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
+ &r2t->sent, &r2t->data_count,
+ &dtask->digestbuf, &dtask->digest);
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
- iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
- tcp_ctask->pad_count);
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
- &sent);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_W_PAD;
- return rc;
- }
+ /*
+ * Done with this Data-Out. Next, check if we have
+ * to send another Data-Out for this R2T.
+ */
+ BUG_ON(r2t->data_length - r2t->sent < 0);
+ left = r2t->data_length - r2t->sent;
+ if (left) {
+ iscsi_solicit_data_cont(conn, ctask, r2t, left);
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ goto send_hdr;
+ }
- if (conn->datadgst_en) {
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
- /* imm data? */
- if (!dtask) {
- rc = iscsi_digest_final_send(conn, ctask,
- &tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1);
- if (rc) {
- debug_tcp("send padding digest 0x%x"
- "fail!\n", tcp_ctask->immdigest);
- return rc;
- }
- debug_tcp("done with padding, digest 0x%x\n",
- tcp_ctask->datadigest);
- } else {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send padding digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("done with padding, digest 0x%x\n",
- dtask->digest);
+ /*
+ * Done with this R2T. Check if there are more
+ * outstanding R2Ts ready to be processed.
+ */
+ spin_lock_bh(&session->lock);
+ tcp_ctask->r2t = NULL;
+ __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ sizeof(void*));
+ if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
+ sizeof(void*))) {
+ tcp_ctask->r2t = r2t;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ spin_unlock_bh(&session->lock);
+ goto send_hdr;
}
+ spin_unlock_bh(&session->lock);
}
-
return 0;
}
@@ -1791,85 +1716,30 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
return rc;
if (tcp_ctask->xmstate & XMSTATE_R_HDR)
- return handle_xmstate_r_hdr(conn, tcp_ctask);
+ return iscsi_send_read_hdr(conn, tcp_ctask);
if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
- rc = handle_xmstate_w_hdr(conn, ctask);
- if (rc)
- return rc;
- }
-
- /* XXX: for data digest xmit recover */
- if (tcp_ctask->xmstate & XMSTATE_DATA_DIGEST) {
- rc = handle_xmstate_data_digest(conn, ctask);
+ rc = iscsi_send_write_hdr(conn, ctask);
if (rc)
return rc;
}
if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
- rc = handle_xmstate_imm_data(conn, ctask);
+ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+ &tcp_ctask->sent, &ctask->imm_count,
+ &tcp_ctask->immbuf, &tcp_ctask->immdigest);
if (rc)
return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
}
- if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
- BUG_ON(!ctask->unsol_count);
- tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
-unsolicit_head_again:
- rc = handle_xmstate_uns_hdr(conn, ctask);
- if (rc)
- return rc;
- }
-
- if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
- rc = handle_xmstate_uns_data(conn, ctask);
- if (rc == 1)
- goto unsolicit_head_again;
- else if (rc)
- return rc;
- goto done;
- }
-
- if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
- struct iscsi_r2t_info *r2t;
-
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- if (!tcp_ctask->r2t)
- __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
- sizeof(void*));
-solicit_head_again:
- r2t = tcp_ctask->r2t;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &r2t->headbuf,
- (u8*)r2t->dtask.hdrext);
- rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
- if (rc) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
- return rc;
- }
-
- debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
- r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
- r2t->sent);
- }
-
- if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
- rc = handle_xmstate_sol_data(conn, ctask);
- if (rc == 1)
- goto solicit_head_again;
- if (rc)
- return rc;
- }
+ rc = iscsi_send_unsol_pdu(conn, ctask);
+ if (rc)
+ return rc;
-done:
- /*
- * Last thing to check is whether we need to send write
- * padding. Note that we check for xmstate equality, not just the bit.
- */
- if (tcp_ctask->xmstate == XMSTATE_W_PAD)
- rc = handle_xmstate_w_pad(conn, ctask);
+ rc = iscsi_send_sol_pdu(conn, ctask);
+ if (rc)
+ return rc;
return rc;
}
@@ -1900,20 +1770,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
/* initial operational parameters */
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
- tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
- /* allocate initial PDU receive place holder */
- if (tcp_conn->data_size <= PAGE_SIZE)
- tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL);
- else
- tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL,
- get_order(tcp_conn->data_size));
- if (!tcp_conn->data)
- goto max_recv_dlenght_alloc_fail;
+ tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->tx_hash.flags = 0;
+ if (!tcp_conn->tx_hash.tfm)
+ goto free_tcp_conn;
+
+ tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->rx_hash.flags = 0;
+ if (!tcp_conn->rx_hash.tfm)
+ goto free_tx_tfm;
return cls_conn;
-max_recv_dlenght_alloc_fail:
+free_tx_tfm:
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
+free_tcp_conn:
kfree(tcp_conn);
tcp_conn_alloc_fail:
iscsi_conn_teardown(cls_conn);
@@ -1921,6 +1795,23 @@ tcp_conn_alloc_fail:
}
static void
+iscsi_tcp_release_conn(struct iscsi_conn *conn)
+{
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+ if (!tcp_conn->sock)
+ return;
+
+ sock_hold(tcp_conn->sock->sk);
+ iscsi_conn_restore_callbacks(tcp_conn);
+ sock_put(tcp_conn->sock->sk);
+
+ sock_release(tcp_conn->sock);
+ tcp_conn->sock = NULL;
+ conn->recv_lock = NULL;
+}
+
+static void
iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
@@ -1930,29 +1821,31 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
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_tfm)
- crypto_free_tfm(tcp_conn->tx_tfm);
- if (tcp_conn->rx_tfm)
- crypto_free_tfm(tcp_conn->rx_tfm);
- if (tcp_conn->data_tx_tfm)
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- if (tcp_conn->data_rx_tfm)
- crypto_free_tfm(tcp_conn->data_rx_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);
}
- /* free conn->data, size = MaxRecvDataSegmentLength */
- if (tcp_conn->data_size <= PAGE_SIZE)
- kfree(tcp_conn->data);
- else
- free_pages((unsigned long)tcp_conn->data,
- get_order(tcp_conn->data_size));
kfree(tcp_conn);
}
+static void
+iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+ iscsi_conn_stop(cls_conn, flag);
+ iscsi_tcp_release_conn(conn);
+ tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+}
+
static int
iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@@ -2001,52 +1894,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
return 0;
}
-static void
-iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_r2t_info *r2t;
-
- /* flush ctask's r2t queues */
- while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)))
- __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
-
- __iscsi_ctask_cleanup(conn, ctask);
-}
-
-static void
-iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct sock *sk;
-
- if (!tcp_conn->sock)
- return;
-
- sk = tcp_conn->sock->sk;
- write_lock_bh(&sk->sk_callback_lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void
-iscsi_tcp_terminate_conn(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
- if (!tcp_conn->sock)
- return;
-
- sock_hold(tcp_conn->sock->sk);
- iscsi_conn_restore_callbacks(conn);
- sock_put(tcp_conn->sock->sk);
-
- sock_release(tcp_conn->sock);
- tcp_conn->sock = NULL;
- conn->recv_lock = NULL;
-}
-
/* called with host lock */
static void
iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
@@ -2057,6 +1904,7 @@ iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
sizeof(struct iscsi_hdr));
tcp_mtask->xmstate = XMSTATE_IMM_HDR;
+ tcp_mtask->sent = 0;
if (mtask->data_count)
iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data,
@@ -2130,211 +1978,55 @@ iscsi_r2tpool_free(struct iscsi_session *session)
static int
iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
- uint32_t value)
+ char *buf, int buflen)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int value;
switch(param) {
- case ISCSI_PARAM_MAX_RECV_DLENGTH: {
- char *saveptr = tcp_conn->data;
- gfp_t flags = GFP_KERNEL;
-
- if (tcp_conn->data_size >= value) {
- conn->max_recv_dlength = value;
- break;
- }
-
- spin_lock_bh(&session->lock);
- if (conn->stop_stage == STOP_CONN_RECOVER)
- flags = GFP_ATOMIC;
- spin_unlock_bh(&session->lock);
-
- if (value <= PAGE_SIZE)
- tcp_conn->data = kmalloc(value, flags);
- else
- tcp_conn->data = (void*)__get_free_pages(flags,
- get_order(value));
- if (tcp_conn->data == NULL) {
- tcp_conn->data = saveptr;
- return -ENOMEM;
- }
- if (tcp_conn->data_size <= PAGE_SIZE)
- kfree(saveptr);
- else
- free_pages((unsigned long)saveptr,
- get_order(tcp_conn->data_size));
- conn->max_recv_dlength = value;
- tcp_conn->data_size = value;
- }
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- conn->max_xmit_dlength = value;
- break;
case ISCSI_PARAM_HDRDGST_EN:
- conn->hdrdgst_en = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
- if (conn->hdrdgst_en) {
+ if (conn->hdrdgst_en)
tcp_conn->hdr_size += sizeof(__u32);
- if (!tcp_conn->tx_tfm)
- tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c",
- 0);
- if (!tcp_conn->tx_tfm)
- return -ENOMEM;
- if (!tcp_conn->rx_tfm)
- tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c",
- 0);
- if (!tcp_conn->rx_tfm) {
- crypto_free_tfm(tcp_conn->tx_tfm);
- return -ENOMEM;
- }
- } else {
- if (tcp_conn->tx_tfm)
- crypto_free_tfm(tcp_conn->tx_tfm);
- if (tcp_conn->rx_tfm)
- crypto_free_tfm(tcp_conn->rx_tfm);
- }
break;
case ISCSI_PARAM_DATADGST_EN:
- conn->datadgst_en = value;
- if (conn->datadgst_en) {
- if (!tcp_conn->data_tx_tfm)
- tcp_conn->data_tx_tfm =
- crypto_alloc_tfm("crc32c", 0);
- if (!tcp_conn->data_tx_tfm)
- return -ENOMEM;
- if (!tcp_conn->data_rx_tfm)
- tcp_conn->data_rx_tfm =
- crypto_alloc_tfm("crc32c", 0);
- if (!tcp_conn->data_rx_tfm) {
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- return -ENOMEM;
- }
- } else {
- if (tcp_conn->data_tx_tfm)
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- if (tcp_conn->data_rx_tfm)
- crypto_free_tfm(tcp_conn->data_rx_tfm);
- }
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->sendpage = conn->datadgst_en ?
sock_no_sendpage : tcp_conn->sock->ops->sendpage;
break;
- case ISCSI_PARAM_INITIAL_R2T_EN:
- session->initial_r2t_en = value;
- break;
case ISCSI_PARAM_MAX_R2T:
+ sscanf(buf, "%d", &value);
if (session->max_r2t == roundup_pow_of_two(value))
break;
iscsi_r2tpool_free(session);
- session->max_r2t = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
if (session->max_r2t & (session->max_r2t - 1))
session->max_r2t = roundup_pow_of_two(session->max_r2t);
if (iscsi_r2tpool_alloc(session))
return -ENOMEM;
break;
- case ISCSI_PARAM_IMM_DATA_EN:
- session->imm_data_en = value;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- session->first_burst = value;
- break;
- case ISCSI_PARAM_MAX_BURST:
- session->max_burst = value;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- session->pdu_inorder_en = value;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- session->dataseq_inorder_en = value;
- break;
- case ISCSI_PARAM_ERL:
- session->erl = value;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- BUG_ON(value);
- session->ifmarker_en = value;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- BUG_ON(value);
- session->ofmarker_en = value;
- break;
- case ISCSI_PARAM_EXP_STATSN:
- conn->exp_statsn = value;
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int
-iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- enum iscsi_param param, uint32_t *value)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
-
- switch(param) {
- case ISCSI_PARAM_INITIAL_R2T_EN:
- *value = session->initial_r2t_en;
- break;
- case ISCSI_PARAM_MAX_R2T:
- *value = session->max_r2t;
- break;
- case ISCSI_PARAM_IMM_DATA_EN:
- *value = session->imm_data_en;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- *value = session->first_burst;
- break;
- case ISCSI_PARAM_MAX_BURST:
- *value = session->max_burst;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- *value = session->pdu_inorder_en;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- *value = session->dataseq_inorder_en;
- break;
- case ISCSI_PARAM_ERL:
- *value = session->erl;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- *value = session->ifmarker_en;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- *value = session->ofmarker_en;
- break;
default:
- return -EINVAL;
+ return iscsi_set_param(cls_conn, param, buf, buflen);
}
return 0;
}
static int
-iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, uint32_t *value)
+iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct inet_sock *inet;
+ struct ipv6_pinfo *np;
+ struct sock *sk;
+ int len;
switch(param) {
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- *value = conn->max_recv_dlength;
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- *value = conn->max_xmit_dlength;
- break;
- case ISCSI_PARAM_HDRDGST_EN:
- *value = conn->hdrdgst_en;
- break;
- case ISCSI_PARAM_DATADGST_EN:
- *value = conn->datadgst_en;
- break;
case ISCSI_PARAM_CONN_PORT:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
@@ -2343,30 +2035,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
}
inet = inet_sk(tcp_conn->sock->sk);
- *value = be16_to_cpu(inet->dport);
+ len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
mutex_unlock(&conn->xmitmutex);
- case ISCSI_PARAM_EXP_STATSN:
- *value = conn->exp_statsn;
break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct sock *sk;
- struct inet_sock *inet;
- struct ipv6_pinfo *np;
- int len = 0;
-
- switch (param) {
case ISCSI_PARAM_CONN_ADDRESS:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
@@ -2388,7 +2059,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
mutex_unlock(&conn->xmitmutex);
break;
default:
- return -EINVAL;
+ return iscsi_conn_get_param(cls_conn, param, buf);
}
return len;
@@ -2468,8 +2139,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
}
static struct scsi_host_template iscsi_sht = {
- .name = "iSCSI Initiator over TCP/IP, v"
- ISCSI_TCP_VERSION,
+ .name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
@@ -2501,7 +2171,11 @@ static struct iscsi_transport iscsi_tcp_transport = {
ISCSI_ERL |
ISCSI_CONN_PORT |
ISCSI_CONN_ADDRESS |
- ISCSI_EXP_STATSN,
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
@@ -2514,14 +2188,10 @@ static struct iscsi_transport iscsi_tcp_transport = {
.bind_conn = iscsi_tcp_conn_bind,
.destroy_conn = iscsi_tcp_conn_destroy,
.set_param = iscsi_conn_set_param,
- .get_conn_param = iscsi_conn_get_param,
- .get_conn_str_param = iscsi_conn_get_str_param,
+ .get_conn_param = iscsi_tcp_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
- .stop_conn = iscsi_conn_stop,
- /* these are called as part of conn recovery */
- .suspend_conn_recv = iscsi_tcp_suspend_conn_rx,
- .terminate_conn = iscsi_tcp_terminate_conn,
+ .stop_conn = iscsi_tcp_conn_stop,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_conn_get_stats,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 808302832e6..32736831790 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -31,26 +31,25 @@
#define IN_PROGRESS_DDIGEST_RECV 0x3
/* xmit state machine */
-#define XMSTATE_IDLE 0x0
-#define XMSTATE_R_HDR 0x1
-#define XMSTATE_W_HDR 0x2
-#define XMSTATE_IMM_HDR 0x4
-#define XMSTATE_IMM_DATA 0x8
-#define XMSTATE_UNS_INIT 0x10
-#define XMSTATE_UNS_HDR 0x20
-#define XMSTATE_UNS_DATA 0x40
-#define XMSTATE_SOL_HDR 0x80
-#define XMSTATE_SOL_DATA 0x100
-#define XMSTATE_W_PAD 0x200
-#define XMSTATE_DATA_DIGEST 0x400
-
-#define ISCSI_CONN_RCVBUF_MIN 262144
-#define ISCSI_CONN_SNDBUF_MIN 262144
+#define XMSTATE_IDLE 0x0
+#define XMSTATE_R_HDR 0x1
+#define XMSTATE_W_HDR 0x2
+#define XMSTATE_IMM_HDR 0x4
+#define XMSTATE_IMM_DATA 0x8
+#define XMSTATE_UNS_INIT 0x10
+#define XMSTATE_UNS_HDR 0x20
+#define XMSTATE_UNS_DATA 0x40
+#define XMSTATE_SOL_HDR 0x80
+#define XMSTATE_SOL_DATA 0x100
+#define XMSTATE_W_PAD 0x200
+#define XMSTATE_W_RESEND_PAD 0x400
+#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
+
#define ISCSI_PAD_LEN 4
-#define ISCSI_R2T_MAX 16
#define ISCSI_SG_TABLESIZE SG_ALL
#define ISCSI_TCP_MAX_CMD_LEN 16
+struct crypto_hash;
struct socket;
/* Socket connection recieve helper */
@@ -78,17 +77,12 @@ struct iscsi_tcp_conn {
char hdrext[4*sizeof(__u16) +
sizeof(__u32)];
int data_copied;
- char *data; /* data placeholder */
- int data_size; /* actual recv_dlength */
int stop_stage; /* conn_stop() flag: *
* stop to recover, *
* stop to terminate */
/* iSCSI connection-wide sequencing */
int hdr_size; /* PDU header size */
- struct crypto_tfm *rx_tfm; /* CRC32C (Rx) */
- struct crypto_tfm *data_rx_tfm; /* CRC32C (Rx) for data */
-
/* control data */
struct iscsi_tcp_recv in; /* TCP receive context */
int in_progress; /* connection state machine */
@@ -98,9 +92,9 @@ struct iscsi_tcp_conn {
void (*old_state_change)(struct sock *);
void (*old_write_space)(struct sock *);
- /* xmit */
- struct crypto_tfm *tx_tfm; /* CRC32C (Tx) */
- struct crypto_tfm *data_tx_tfm; /* CRC32C (Tx) for data */
+ /* data and header digests */
+ struct hash_desc tx_hash; /* CRC32C (Tx) */
+ struct hash_desc rx_hash; /* CRC32C (Rx) */
/* MIB custom statistics */
uint32_t sendpage_failures_cnt;
@@ -159,19 +153,15 @@ struct iscsi_tcp_cmd_task {
struct scatterlist *bad_sg; /* assert statement */
int sg_count; /* SG's to process */
uint32_t exp_r2tsn;
- int r2t_data_count; /* R2T Data-Out bytes */
int data_offset;
struct iscsi_r2t_info *r2t; /* in progress R2T */
struct iscsi_queue r2tpool;
struct kfifo *r2tqueue;
struct iscsi_r2t_info **r2ts;
- uint32_t datadigest; /* for recover digest */
int digest_count;
uint32_t immdigest; /* for imm data */
struct iscsi_buf immbuf; /* for imm data digest */
- struct iscsi_data_task *dtask; /* data task in progress*/
struct iscsi_data_task unsol_dtask; /* unsol data task */
- int digest_offset; /* for partial buff digest */
};
#endif /* ISCSI_H */
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index fc031c76dad..bfac4441d89 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -131,7 +131,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = vdma_alloc(CPHYSADDR(cmd_buffer), sizeof (cmd_buffer));
esp->irq = JAZZ_SCSI_IRQ;
- request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI",
+ request_irq(JAZZ_SCSI_IRQ, esp_intr, IRQF_DISABLED, "JAZZ SCSI",
esp->ehost);
/*
@@ -257,7 +257,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
vdma_free(sg[sz].dma_address);
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index eb7bd310cc8..f0871c3ac3d 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -131,7 +131,7 @@ lasi700_probe(struct parisc_device *dev)
host->this_id = 7;
host->base = base;
host->irq = dev->irq;
- if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) {
+ if(request_irq(dev->irq, NCR_700_intr, IRQF_SHARED, "lasi700", host)) {
printk(KERN_ERR "lasi700: request_irq failed!\n");
goto out_put_host;
}
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c
deleted file mode 100644
index 004e1a0d8b7..00000000000
--- a/drivers/scsi/libata-bmdma.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*
- * libata-bmdma.c - helper library for PCI IDE BMDMA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2006 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2006 Jeff Garzik
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available from http://www.t13.org/ and
- * http://www.sata-io.org/
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/libata.h>
-
-#include "libata.h"
-
-/**
- * ata_tf_load_pio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- if (tf->ctl != ap->last_ctl) {
- outb(tf->ctl, ioaddr->ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
-
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- outb(tf->hob_feature, ioaddr->feature_addr);
- outb(tf->hob_nsect, ioaddr->nsect_addr);
- outb(tf->hob_lbal, ioaddr->lbal_addr);
- outb(tf->hob_lbam, ioaddr->lbam_addr);
- outb(tf->hob_lbah, ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
-
- if (is_addr) {
- outb(tf->feature, ioaddr->feature_addr);
- outb(tf->nsect, ioaddr->nsect_addr);
- outb(tf->lbal, ioaddr->lbal_addr);
- outb(tf->lbam, ioaddr->lbam_addr);
- outb(tf->lbah, ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE) {
- outb(tf->device, ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
-
- ata_wait_idle(ap);
-}
-
-/**
- * ata_tf_load_mmio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
-
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
-
- if (is_addr) {
- writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE) {
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
-
- ata_wait_idle(ap);
-}
-
-
-/**
- * ata_tf_load - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO
- * or PIO as indicated by the ATA_FLAG_MMIO flag.
- * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- * hob_lbal, hob_lbam, and hob_lbah.
- *
- * This function waits for idle (!BUSY and !DRQ) after writing
- * registers. If the control register has a new value, this
- * function also waits for idle after writing control and before
- * writing the remaining registers.
- *
- * May be used as the tf_load() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_load_mmio(ap, tf);
- else
- ata_tf_load_pio(ap, tf);
-}
-
-/**
- * ata_exec_command_pio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- outb(tf->command, ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
-/**
- * ata_exec_command_mmio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * FIXME: missing write posting for 400nS delay enforcement
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
-/**
- * ata_exec_command - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO/MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_exec_command_mmio(ap, tf);
- else
- ata_exec_command_pio(ap, tf);
-}
-
-/**
- * ata_tf_read_pio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = inb(ioaddr->error_addr);
- tf->nsect = inb(ioaddr->nsect_addr);
- tf->lbal = inb(ioaddr->lbal_addr);
- tf->lbam = inb(ioaddr->lbam_addr);
- tf->lbah = inb(ioaddr->lbah_addr);
- tf->device = inb(ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
- tf->hob_feature = inb(ioaddr->error_addr);
- tf->hob_nsect = inb(ioaddr->nsect_addr);
- tf->hob_lbal = inb(ioaddr->lbal_addr);
- tf->hob_lbam = inb(ioaddr->lbam_addr);
- tf->hob_lbah = inb(ioaddr->lbah_addr);
- }
-}
-
-/**
- * ata_tf_read_mmio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf via MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = readb((void __iomem *)ioaddr->error_addr);
- tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
- tf->device = readb((void __iomem *)ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
- tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
- tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
- }
-}
-
-
-/**
- * ata_tf_read - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
- * is set, also reads the hob registers.
- *
- * May be used as the tf_read() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_read_mmio(ap, tf);
- else
- ata_tf_read_pio(ap, tf);
-}
-
-/**
- * ata_check_status_pio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
- return inb(ap->ioaddr.status_addr);
-}
-
-/**
- * ata_check_status_mmio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * via MMIO and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
- return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
-/**
- * ata_check_status - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * May be used as the check_status() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-u8 ata_check_status(struct ata_port *ap)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_check_status_mmio(ap);
- return ata_check_status_pio(ap);
-}
-
-
-/**
- * ata_altstatus - Read device alternate status reg
- * @ap: port where the device is
- *
- * Reads ATA taskfile alternate status register for
- * currently-selected device and return its value.
- *
- * Note: may NOT be used as the check_altstatus() entry in
- * ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-u8 ata_altstatus(struct ata_port *ap)
-{
- if (ap->ops->check_altstatus)
- return ap->ops->check_altstatus(ap);
-
- if (ap->flags & ATA_FLAG_MMIO)
- return readb((void __iomem *)ap->ioaddr.altstatus_addr);
- return inb(ap->ioaddr.altstatus_addr);
-}
-
-/**
- * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
-
- /* load PRD table addr. */
- mb(); /* make sure PRD table writes are visible to controller */
- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = readb(mmio + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- writeb(dmactl, mmio + ATA_DMA_CMD);
-
- /* issue r/w command */
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-/**
- * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = readb(mmio + ATA_DMA_CMD);
- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
-
- /* Strictly, one may wish to issue a readb() here, to
- * flush the mmio write. However, control also passes
- * to the hardware at this point, and it will interrupt
- * us when we are to resume control. So, in effect,
- * we don't care when the mmio write flushes.
- * Further, a read of the DMA status register _immediately_
- * following the write may not be what certain flaky hardware
- * is expected, so I think it is best to not add a readb()
- * without first all the MMIO ATA cards/mobos.
- * Or maybe I'm just being paranoid.
- */
-}
-
-/**
- * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
-
- /* load PRD table addr. */
- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* issue r/w command */
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-/**
- * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- outb(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-}
-
-
-/**
- * ata_bmdma_start - Start a PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes the ATA_DMA_START flag to the DMA command register.
- *
- * May be used as the bmdma_start() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_bmdma_start(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_start_mmio(qc);
- else
- ata_bmdma_start_pio(qc);
-}
-
-
-/**
- * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes address of PRD table to device's PRD Table Address
- * register, sets the DMA control register, and calls
- * ops->exec_command() to start the transfer.
- *
- * May be used as the bmdma_setup() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_bmdma_setup(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_setup_mmio(qc);
- else
- ata_bmdma_setup_pio(qc);
-}
-
-
-/**
- * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
- * @ap: Port associated with this ATA transaction.
- *
- * Clear interrupt and error flags in DMA status register.
- *
- * May be used as the irq_clear() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_bmdma_irq_clear(struct ata_port *ap)
-{
- if (!ap->ioaddr.bmdma_addr)
- return;
-
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio =
- ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
- writeb(readb(mmio), mmio);
- } else {
- unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
- outb(inb(addr), addr);
- }
-}
-
-
-/**
- * ata_bmdma_status - Read PCI IDE BMDMA status
- * @ap: Port associated with this ATA transaction.
- *
- * Read and return BMDMA status register.
- *
- * May be used as the bmdma_status() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-u8 ata_bmdma_status(struct ata_port *ap)
-{
- u8 host_stat;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
- host_stat = readb(mmio + ATA_DMA_STATUS);
- } else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- return host_stat;
-}
-
-
-/**
- * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
- * @qc: Command we are ending DMA for
- *
- * Clears the ATA_DMA_START flag in the dma control register
- *
- * May be used as the bmdma_stop() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
-
- /* clear start/stop bit */
- writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
- mmio + ATA_DMA_CMD);
- } else {
- /* clear start/stop bit */
- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- }
-
- /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_altstatus(ap); /* dummy read */
-}
-
-/**
- * ata_bmdma_freeze - Freeze BMDMA controller port
- * @ap: port to freeze
- *
- * Freeze BMDMA controller port.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_bmdma_freeze(struct ata_port *ap)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- ap->ctl |= ATA_NIEN;
- ap->last_ctl = ap->ctl;
-
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
-}
-
-/**
- * ata_bmdma_thaw - Thaw BMDMA controller port
- * @ap: port to thaw
- *
- * Thaw BMDMA controller port.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_bmdma_thaw(struct ata_port *ap)
-{
- /* clear & re-enable interrupts */
- ata_chk_status(ap);
- ap->ops->irq_clear(ap);
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
-}
-
-/**
- * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
- * @ap: port to handle error for
- * @prereset: prereset method (can be NULL)
- * @softreset: softreset method (can be NULL)
- * @hardreset: hardreset method (can be NULL)
- * @postreset: postreset method (can be NULL)
- *
- * Handle error for ATA BMDMA controller. It can handle both
- * PATA and SATA controllers. Many controllers should be able to
- * use this EH as-is or with some added handling before and
- * after.
- *
- * This function is intended to be used for constructing
- * ->error_handler callback by low level drivers.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_queued_cmd *qc;
- unsigned long flags;
- int thaw = 0;
-
- qc = __ata_qc_from_tag(ap, ap->active_tag);
- if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
- qc = NULL;
-
- /* reset PIO HSM and stop DMA engine */
- spin_lock_irqsave(ap->lock, flags);
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
- u8 host_stat;
-
- host_stat = ata_bmdma_status(ap);
-
- ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
-
- /* BMDMA controllers indicate host bus error by
- * setting DMA_ERR bit and timing out. As it wasn't
- * really a timeout event, adjust error mask and
- * cancel frozen state.
- */
- if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
- qc->err_mask = AC_ERR_HOST_BUS;
- thaw = 1;
- }
-
- ap->ops->bmdma_stop(qc);
- }
-
- ata_altstatus(ap);
- ata_chk_status(ap);
- ap->ops->irq_clear(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- if (thaw)
- ata_eh_thaw_port(ap);
-
- /* PIO and DMA engines have been stopped, perform recovery */
- ata_do_eh(ap, prereset, softreset, hardreset, postreset);
-}
-
-/**
- * ata_bmdma_error_handler - Stock error handler for BMDMA controller
- * @ap: port to handle error for
- *
- * Stock error handler for BMDMA controller.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_bmdma_error_handler(struct ata_port *ap)
-{
- ata_reset_fn_t hardreset;
-
- hardreset = NULL;
- if (sata_scr_valid(ap))
- hardreset = sata_std_hardreset;
-
- ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
- ata_std_postreset);
-}
-
-/**
- * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
- * BMDMA controller
- * @qc: internal command to clean up
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- ata_bmdma_stop(qc);
-}
-
-#ifdef CONFIG_PCI
-static struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
- struct ata_probe_ent *probe_ent;
-
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent) {
- printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
- kobject_name(&(dev->kobj)));
- return NULL;
- }
-
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = dev;
-
- probe_ent->sht = port->sht;
- probe_ent->host_flags = port->host_flags;
- probe_ent->pio_mask = port->pio_mask;
- probe_ent->mwdma_mask = port->mwdma_mask;
- probe_ent->udma_mask = port->udma_mask;
- probe_ent->port_ops = port->port_ops;
-
- return probe_ent;
-}
-
-
-/**
- * ata_pci_init_native_mode - Initialize native-mode driver
- * @pdev: pci device to be initialized
- * @port: array[2] of pointers to port info structures.
- * @ports: bitmap of ports present
- *
- * Utility function which allocates and initializes an
- * ata_probe_ent structure for a standard dual-port
- * PIO-based IDE controller. The returned ata_probe_ent
- * structure can be passed to ata_device_add(). The returned
- * ata_probe_ent structure should then be freed with kfree().
- *
- * The caller need only pass the address of the primary port, the
- * secondary will be deduced automatically. If the device has non
- * standard secondary port mappings this function can be called twice,
- * once for each interface.
- */
-
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
-{
- struct ata_probe_ent *probe_ent =
- ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- int p = 0;
- unsigned long bmdma;
-
- if (!probe_ent)
- return NULL;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->private_data = port[0]->private_data;
-
- if (ports & ATA_PORT_PRIMARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
- if (inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
- }
- ata_std_ports(&probe_ent->port[p]);
- p++;
- }
-
- if (ports & ATA_PORT_SECONDARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
- bmdma += 8;
- if(inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
- }
- ata_std_ports(&probe_ent->port[p]);
- p++;
- }
-
- probe_ent->n_ports = p;
- return probe_ent;
-}
-
-
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
- struct ata_port_info *port, int port_num)
-{
- struct ata_probe_ent *probe_ent;
- unsigned long bmdma;
-
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
- if (!probe_ent)
- return NULL;
-
- probe_ent->legacy_mode = 1;
- probe_ent->n_ports = 1;
- probe_ent->hard_port_no = port_num;
- probe_ent->private_data = port->private_data;
-
- switch(port_num)
- {
- case 0:
- probe_ent->irq = 14;
- probe_ent->port[0].cmd_addr = 0x1f0;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x3f6;
- break;
- case 1:
- probe_ent->irq = 15;
- probe_ent->port[0].cmd_addr = 0x170;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x376;
- break;
- }
-
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma != 0) {
- bmdma += 8 * port_num;
- probe_ent->port[0].bmdma_addr = bmdma;
- if (inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
- }
- ata_std_ports(&probe_ent->port[0]);
-
- return probe_ent;
-}
-
-
-/**
- * ata_pci_init_one - Initialize/register PCI IDE host controller
- * @pdev: Controller to be initialized
- * @port_info: Information from low-level host driver
- * @n_ports: Number of ports attached to host controller
- *
- * This is a helper function which can be called from a driver's
- * xxx_init_one() probe function if the hardware uses traditional
- * IDE taskfile registers.
- *
- * This function calls pci_enable_device(), reserves its register
- * regions, sets the dma mask, enables bus master mode, and calls
- * ata_device_add()
- *
- * LOCKING:
- * Inherited from PCI layer (may sleep).
- *
- * RETURNS:
- * Zero on success, negative on errno-based value on error.
- */
-
-int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
- unsigned int n_ports)
-{
- struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
- struct ata_port_info *port[2];
- u8 tmp8, mask;
- unsigned int legacy_mode = 0;
- int disable_dev_on_err = 1;
- int rc;
-
- DPRINTK("ENTER\n");
-
- port[0] = port_info[0];
- if (n_ports > 1)
- port[1] = port_info[1];
- else
- port[1] = port[0];
-
- if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- /* TODO: What if one channel is in native mode ... */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
- mask = (1 << 2) | (1 << 0);
- if ((tmp8 & mask) != mask)
- legacy_mode = (1 << 3);
- }
-
- /* FIXME... */
- if ((!legacy_mode) && (n_ports > 2)) {
- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
- n_ports = 2;
- /* For now */
- }
-
- /* FIXME: Really for ATA it isn't safe because the device may be
- multi-purpose and we want to leave it alone if it was already
- enabled. Secondly for shared use as Arjan says we want refcounting
-
- Checking dev->is_enabled is insufficient as this is not set at
- boot for the primary video which is BIOS enabled
- */
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- disable_dev_on_err = 0;
- goto err_out;
- }
-
- /* FIXME: Should use platform specific mappers for legacy port ranges */
- if (legacy_mode) {
- if (!request_region(0x1f0, 8, "libata")) {
- struct resource *conflict, res;
- res.start = 0x1f0;
- res.end = 0x1f0 + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 0);
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
- }
- } else
- legacy_mode |= (1 << 0);
-
- if (!request_region(0x170, 8, "libata")) {
- struct resource *conflict, res;
- res.start = 0x170;
- res.end = 0x170 + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 1);
- else {
- disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
- }
- } else
- legacy_mode |= (1 << 1);
- }
-
- /* we have legacy mode, but all ports are unavailable */
- if (legacy_mode == (1 << 3)) {
- rc = -EBUSY;
- goto err_out_regions;
- }
-
- /* FIXME: If we get no DMA mask we should fall back to PIO */
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- if (legacy_mode) {
- if (legacy_mode & (1 << 0))
- probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
- if (legacy_mode & (1 << 1))
- probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
- } else {
- if (n_ports == 2)
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- else
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
- }
- if (!probe_ent && !probe_ent2) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return */
- if (legacy_mode) {
- struct device *dev = &pdev->dev;
- struct ata_host_set *host_set = NULL;
-
- if (legacy_mode & (1 << 0)) {
- ata_device_add(probe_ent);
- host_set = dev_get_drvdata(dev);
- }
-
- if (legacy_mode & (1 << 1)) {
- ata_device_add(probe_ent2);
- if (host_set) {
- host_set->next = dev_get_drvdata(dev);
- dev_set_drvdata(dev, host_set);
- }
- }
- } else
- ata_device_add(probe_ent);
-
- kfree(probe_ent);
- kfree(probe_ent2);
-
- return 0;
-
-err_out_regions:
- if (legacy_mode & (1 << 0))
- release_region(0x1f0, 8);
- if (legacy_mode & (1 << 1))
- release_region(0x170, 8);
- pci_release_regions(pdev);
-err_out:
- if (disable_dev_on_err)
- pci_disable_device(pdev);
- return rc;
-}
-
-/**
- * ata_pci_clear_simplex - attempt to kick device out of simplex
- * @pdev: PCI device
- *
- * Some PCI ATA devices report simplex mode but in fact can be told to
- * enter non simplex mode. This implements the neccessary logic to
- * perform the task on such devices. Calling it on other devices will
- * have -undefined- behaviour.
- */
-
-int ata_pci_clear_simplex(struct pci_dev *pdev)
-{
- unsigned long bmdma = pci_resource_start(pdev, 4);
- u8 simplex;
-
- if (bmdma == 0)
- return -ENOENT;
-
- simplex = inb(bmdma + 0x02);
- outb(simplex & 0x60, bmdma + 0x02);
- simplex = inb(bmdma + 0x02);
- if (simplex & 0x80)
- return -EOPNOTSUPP;
- return 0;
-}
-
-unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
-{
- /* Filter out DMA modes if the device has been configured by
- the BIOS as PIO only */
-
- if (ap->ioaddr.bmdma_addr == 0)
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- return xfer_mask;
-}
-
-#endif /* CONFIG_PCI */
-
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
deleted file mode 100644
index 6c66877be2b..00000000000
--- a/drivers/scsi/libata-core.c
+++ /dev/null
@@ -1,5916 +0,0 @@
-/*
- * libata-core.c - helper library for ATA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2004 Jeff Garzik
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available from http://www.t13.org/ and
- * http://www.sata-io.org/
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/spinlock.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/suspend.h>
-#include <linux/workqueue.h>
-#include <linux/jiffies.h>
-#include <linux/scatterlist.h>
-#include <scsi/scsi.h>
-#include "scsi_priv.h"
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-#include <asm/semaphore.h>
-#include <asm/byteorder.h>
-
-#include "libata.h"
-
-/* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
-const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
-
-static unsigned int ata_dev_init_params(struct ata_device *dev,
- u16 heads, u16 sectors);
-static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
-static void ata_dev_xfermask(struct ata_device *dev);
-
-static unsigned int ata_unique_id = 1;
-static struct workqueue_struct *ata_wq;
-
-struct workqueue_struct *ata_aux_wq;
-
-int atapi_enabled = 1;
-module_param(atapi_enabled, int, 0444);
-MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
-
-int atapi_dmadir = 0;
-module_param(atapi_dmadir, int, 0444);
-MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
-
-int libata_fua = 0;
-module_param_named(fua, libata_fua, int, 0444);
-MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Library module for ATA devices");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-
-/**
- * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
- * @tf: Taskfile to convert
- * @fis: Buffer into which data will output
- * @pmp: Port multiplier port
- *
- * Converts a standard ATA taskfile to a Serial ATA
- * FIS structure (Register - Host to Device).
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
-{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
- fis[2] = tf->command;
- fis[3] = tf->feature;
-
- fis[4] = tf->lbal;
- fis[5] = tf->lbam;
- fis[6] = tf->lbah;
- fis[7] = tf->device;
-
- fis[8] = tf->hob_lbal;
- fis[9] = tf->hob_lbam;
- fis[10] = tf->hob_lbah;
- fis[11] = tf->hob_feature;
-
- fis[12] = tf->nsect;
- fis[13] = tf->hob_nsect;
- fis[14] = 0;
- fis[15] = tf->ctl;
-
- fis[16] = 0;
- fis[17] = 0;
- fis[18] = 0;
- fis[19] = 0;
-}
-
-/**
- * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
- * @fis: Buffer from which data will be input
- * @tf: Taskfile to output
- *
- * Converts a serial ATA FIS structure to a standard ATA taskfile.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
-{
- tf->command = fis[2]; /* status */
- tf->feature = fis[3]; /* error */
-
- tf->lbal = fis[4];
- tf->lbam = fis[5];
- tf->lbah = fis[6];
- tf->device = fis[7];
-
- tf->hob_lbal = fis[8];
- tf->hob_lbam = fis[9];
- tf->hob_lbah = fis[10];
-
- tf->nsect = fis[12];
- tf->hob_nsect = fis[13];
-}
-
-static const u8 ata_rw_cmds[] = {
- /* pio multi */
- ATA_CMD_READ_MULTI,
- ATA_CMD_WRITE_MULTI,
- ATA_CMD_READ_MULTI_EXT,
- ATA_CMD_WRITE_MULTI_EXT,
- 0,
- 0,
- 0,
- ATA_CMD_WRITE_MULTI_FUA_EXT,
- /* pio */
- ATA_CMD_PIO_READ,
- ATA_CMD_PIO_WRITE,
- ATA_CMD_PIO_READ_EXT,
- ATA_CMD_PIO_WRITE_EXT,
- 0,
- 0,
- 0,
- 0,
- /* dma */
- ATA_CMD_READ,
- ATA_CMD_WRITE,
- ATA_CMD_READ_EXT,
- ATA_CMD_WRITE_EXT,
- 0,
- 0,
- 0,
- ATA_CMD_WRITE_FUA_EXT
-};
-
-/**
- * ata_rwcmd_protocol - set taskfile r/w commands and protocol
- * @qc: command to examine and configure
- *
- * Examine the device configuration and tf->flags to calculate
- * the proper read/write commands and protocol to use.
- *
- * LOCKING:
- * caller.
- */
-int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
-{
- struct ata_taskfile *tf = &qc->tf;
- struct ata_device *dev = qc->dev;
- u8 cmd;
-
- int index, fua, lba48, write;
-
- fua = (tf->flags & ATA_TFLAG_FUA) ? 4 : 0;
- lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
- write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
-
- if (dev->flags & ATA_DFLAG_PIO) {
- tf->protocol = ATA_PROT_PIO;
- index = dev->multi_count ? 0 : 8;
- } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) {
- /* Unable to use DMA due to host limitation */
- tf->protocol = ATA_PROT_PIO;
- index = dev->multi_count ? 0 : 8;
- } else {
- tf->protocol = ATA_PROT_DMA;
- index = 16;
- }
-
- cmd = ata_rw_cmds[index + fua + lba48 + write];
- if (cmd) {
- tf->command = cmd;
- return 0;
- }
- return -1;
-}
-
-/**
- * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
- * @pio_mask: pio_mask
- * @mwdma_mask: mwdma_mask
- * @udma_mask: udma_mask
- *
- * Pack @pio_mask, @mwdma_mask and @udma_mask into a single
- * unsigned int xfer_mask.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Packed xfer_mask.
- */
-static unsigned int ata_pack_xfermask(unsigned int pio_mask,
- unsigned int mwdma_mask,
- unsigned int udma_mask)
-{
- return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
- ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
- ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
-}
-
-/**
- * ata_unpack_xfermask - Unpack xfer_mask into pio, mwdma and udma masks
- * @xfer_mask: xfer_mask to unpack
- * @pio_mask: resulting pio_mask
- * @mwdma_mask: resulting mwdma_mask
- * @udma_mask: resulting udma_mask
- *
- * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
- * Any NULL distination masks will be ignored.
- */
-static void ata_unpack_xfermask(unsigned int xfer_mask,
- unsigned int *pio_mask,
- unsigned int *mwdma_mask,
- unsigned int *udma_mask)
-{
- if (pio_mask)
- *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
- if (mwdma_mask)
- *mwdma_mask = (xfer_mask & ATA_MASK_MWDMA) >> ATA_SHIFT_MWDMA;
- if (udma_mask)
- *udma_mask = (xfer_mask & ATA_MASK_UDMA) >> ATA_SHIFT_UDMA;
-}
-
-static const struct ata_xfer_ent {
- int shift, bits;
- u8 base;
-} ata_xfer_tbl[] = {
- { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
- { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
- { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
- { -1, },
-};
-
-/**
- * ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
- * @xfer_mask: xfer_mask of interest
- *
- * Return matching XFER_* value for @xfer_mask. Only the highest
- * bit of @xfer_mask is considered.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Matching XFER_* value, 0 if no match found.
- */
-static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
-{
- int highbit = fls(xfer_mask) - 1;
- const struct ata_xfer_ent *ent;
-
- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
- if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
- return ent->base + highbit - ent->shift;
- return 0;
-}
-
-/**
- * ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
- * @xfer_mode: XFER_* of interest
- *
- * Return matching xfer_mask for @xfer_mode.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Matching xfer_mask, 0 if no match found.
- */
-static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
-{
- const struct ata_xfer_ent *ent;
-
- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
- if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
- return 1 << (ent->shift + xfer_mode - ent->base);
- return 0;
-}
-
-/**
- * ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
- * @xfer_mode: XFER_* of interest
- *
- * Return matching xfer_shift for @xfer_mode.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Matching xfer_shift, -1 if no match found.
- */
-static int ata_xfer_mode2shift(unsigned int xfer_mode)
-{
- const struct ata_xfer_ent *ent;
-
- for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
- if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
- return ent->shift;
- return -1;
-}
-
-/**
- * ata_mode_string - convert xfer_mask to string
- * @xfer_mask: mask of bits supported; only highest bit counts.
- *
- * Determine string which represents the highest speed
- * (highest bit in @modemask).
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Constant C string representing highest speed listed in
- * @mode_mask, or the constant C string "<n/a>".
- */
-static const char *ata_mode_string(unsigned int xfer_mask)
-{
- static const char * const xfer_mode_str[] = {
- "PIO0",
- "PIO1",
- "PIO2",
- "PIO3",
- "PIO4",
- "MWDMA0",
- "MWDMA1",
- "MWDMA2",
- "UDMA/16",
- "UDMA/25",
- "UDMA/33",
- "UDMA/44",
- "UDMA/66",
- "UDMA/100",
- "UDMA/133",
- "UDMA7",
- };
- int highbit;
-
- highbit = fls(xfer_mask) - 1;
- if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
- return xfer_mode_str[highbit];
- return "<n/a>";
-}
-
-static const char *sata_spd_string(unsigned int spd)
-{
- static const char * const spd_str[] = {
- "1.5 Gbps",
- "3.0 Gbps",
- };
-
- if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
- return "<unknown>";
- return spd_str[spd - 1];
-}
-
-void ata_dev_disable(struct ata_device *dev)
-{
- if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
- ata_dev_printk(dev, KERN_WARNING, "disabled\n");
- dev->class++;
- }
-}
-
-/**
- * ata_pio_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * This technique was originally described in
- * Hale Landis's ATADRVR (www.ata-atapi.com), and
- * later found its way into the ATA/ATAPI spec.
- *
- * Write a pattern to the ATA shadow registers,
- * and if a device is present, it will respond by
- * correctly storing and echoing back the
- * ATA shadow register contents.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_pio_devchk(struct ata_port *ap,
- unsigned int device)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 nsect, lbal;
-
- ap->ops->dev_select(ap, device);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- outb(0xaa, ioaddr->nsect_addr);
- outb(0x55, ioaddr->lbal_addr);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
-
- if ((nsect == 0x55) && (lbal == 0xaa))
- return 1; /* we found a device */
-
- return 0; /* nothing found */
-}
-
-/**
- * ata_mmio_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * This technique was originally described in
- * Hale Landis's ATADRVR (www.ata-atapi.com), and
- * later found its way into the ATA/ATAPI spec.
- *
- * Write a pattern to the ATA shadow registers,
- * and if a device is present, it will respond by
- * correctly storing and echoing back the
- * ATA shadow register contents.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_mmio_devchk(struct ata_port *ap,
- unsigned int device)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 nsect, lbal;
-
- ap->ops->dev_select(ap, device);
-
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
-
- writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
- writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
-
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
-
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
-
- if ((nsect == 0x55) && (lbal == 0xaa))
- return 1; /* we found a device */
-
- return 0; /* nothing found */
-}
-
-/**
- * ata_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * Dispatch ATA device presence detection, depending
- * on whether we are using PIO or MMIO to talk to the
- * ATA shadow registers.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_devchk(struct ata_port *ap,
- unsigned int device)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_mmio_devchk(ap, device);
- return ata_pio_devchk(ap, device);
-}
-
-/**
- * ata_dev_classify - determine device type based on ATA-spec signature
- * @tf: ATA taskfile register set for device to be identified
- *
- * Determine from taskfile register contents whether a device is
- * ATA or ATAPI, as per "Signature and persistence" section
- * of ATA/PI spec (volume 1, sect 5.14).
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- * the event of failure.
- */
-
-unsigned int ata_dev_classify(const struct ata_taskfile *tf)
-{
- /* Apple's open source Darwin code hints that some devices only
- * put a proper signature into the LBA mid/high registers,
- * So, we only check those. It's sufficient for uniqueness.
- */
-
- if (((tf->lbam == 0) && (tf->lbah == 0)) ||
- ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
- DPRINTK("found ATA device by sig\n");
- return ATA_DEV_ATA;
- }
-
- if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
- ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
- DPRINTK("found ATAPI device by sig\n");
- return ATA_DEV_ATAPI;
- }
-
- DPRINTK("unknown device\n");
- return ATA_DEV_UNKNOWN;
-}
-
-/**
- * ata_dev_try_classify - Parse returned ATA device signature
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- * @r_err: Value of error register on completion
- *
- * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
- * an ATA/ATAPI-defined set of values is placed in the ATA
- * shadow registers, indicating the results of device detection
- * and diagnostics.
- *
- * Select the ATA device, and read the values from the ATA shadow
- * registers. Then parse according to the Error register value,
- * and the spec-defined values examined by ata_dev_classify().
- *
- * LOCKING:
- * caller.
- *
- * RETURNS:
- * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
- */
-
-static unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
-{
- struct ata_taskfile tf;
- unsigned int class;
- u8 err;
-
- ap->ops->dev_select(ap, device);
-
- memset(&tf, 0, sizeof(tf));
-
- ap->ops->tf_read(ap, &tf);
- err = tf.feature;
- if (r_err)
- *r_err = err;
-
- /* see if device passed diags */
- if (err == 1)
- /* do nothing */ ;
- else if ((device == 0) && (err == 0x81))
- /* do nothing */ ;
- else
- return ATA_DEV_NONE;
-
- /* determine if device is ATA or ATAPI */
- class = ata_dev_classify(&tf);
-
- if (class == ATA_DEV_UNKNOWN)
- return ATA_DEV_NONE;
- if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
- return ATA_DEV_NONE;
- return class;
-}
-
-/**
- * ata_id_string - Convert IDENTIFY DEVICE page into string
- * @id: IDENTIFY DEVICE results we will examine
- * @s: string into which data is output
- * @ofs: offset into identify device page
- * @len: length of string to return. must be an even number.
- *
- * The strings in the IDENTIFY DEVICE page are broken up into
- * 16-bit chunks. Run through the string, and output each
- * 8-bit chunk linearly, regardless of platform.
- *
- * LOCKING:
- * caller.
- */
-
-void ata_id_string(const u16 *id, unsigned char *s,
- unsigned int ofs, unsigned int len)
-{
- unsigned int c;
-
- while (len > 0) {
- c = id[ofs] >> 8;
- *s = c;
- s++;
-
- c = id[ofs] & 0xff;
- *s = c;
- s++;
-
- ofs++;
- len -= 2;
- }
-}
-
-/**
- * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
- * @id: IDENTIFY DEVICE results we will examine
- * @s: string into which data is output
- * @ofs: offset into identify device page
- * @len: length of string to return. must be an odd number.
- *
- * This function is identical to ata_id_string except that it
- * trims trailing spaces and terminates the resulting string with
- * null. @len must be actual maximum length (even number) + 1.
- *
- * LOCKING:
- * caller.
- */
-void ata_id_c_string(const u16 *id, unsigned char *s,
- unsigned int ofs, unsigned int len)
-{
- unsigned char *p;
-
- WARN_ON(!(len & 1));
-
- ata_id_string(id, s, ofs, len - 1);
-
- p = s + strnlen(s, len - 1);
- while (p > s && p[-1] == ' ')
- p--;
- *p = '\0';
-}
-
-static u64 ata_id_n_sectors(const u16 *id)
-{
- if (ata_id_has_lba(id)) {
- if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
- else
- return ata_id_u32(id, 60);
- } else {
- if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
- else
- return id[1] * id[3] * id[6];
- }
-}
-
-/**
- * ata_noop_dev_select - Select device 0/1 on ATA bus
- * @ap: ATA channel to manipulate
- * @device: ATA device (numbered from zero) to select
- *
- * This function performs no actual function.
- *
- * May be used as the dev_select() entry in ata_port_operations.
- *
- * LOCKING:
- * caller.
- */
-void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
-{
-}
-
-
-/**
- * ata_std_dev_select - Select device 0/1 on ATA bus
- * @ap: ATA channel to manipulate
- * @device: ATA device (numbered from zero) to select
- *
- * Use the method defined in the ATA specification to
- * make either device 0, or device 1, active on the
- * ATA channel. Works with both PIO and MMIO.
- *
- * May be used as the dev_select() entry in ata_port_operations.
- *
- * LOCKING:
- * caller.
- */
-
-void ata_std_dev_select (struct ata_port *ap, unsigned int device)
-{
- u8 tmp;
-
- if (device == 0)
- tmp = ATA_DEVICE_OBS;
- else
- tmp = ATA_DEVICE_OBS | ATA_DEV1;
-
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
- } else {
- outb(tmp, ap->ioaddr.device_addr);
- }
- ata_pause(ap); /* needed; also flushes, for mmio */
-}
-
-/**
- * ata_dev_select - Select device 0/1 on ATA bus
- * @ap: ATA channel to manipulate
- * @device: ATA device (numbered from zero) to select
- * @wait: non-zero to wait for Status register BSY bit to clear
- * @can_sleep: non-zero if context allows sleeping
- *
- * Use the method defined in the ATA specification to
- * make either device 0, or device 1, active on the
- * ATA channel.
- *
- * This is a high-level version of ata_std_dev_select(),
- * which additionally provides the services of inserting
- * the proper pauses and status polling, where needed.
- *
- * LOCKING:
- * caller.
- */
-
-void ata_dev_select(struct ata_port *ap, unsigned int device,
- unsigned int wait, unsigned int can_sleep)
-{
- if (ata_msg_probe(ap)) {
- ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
- "device %u, wait %u\n",
- ap->id, device, wait);
- }
-
- if (wait)
- ata_wait_idle(ap);
-
- ap->ops->dev_select(ap, device);
-
- if (wait) {
- if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
- msleep(150);
- ata_wait_idle(ap);
- }
-}
-
-/**
- * ata_dump_id - IDENTIFY DEVICE info debugging output
- * @id: IDENTIFY DEVICE page to dump
- *
- * Dump selected 16-bit words from the given IDENTIFY DEVICE
- * page.
- *
- * LOCKING:
- * caller.
- */
-
-static inline void ata_dump_id(const u16 *id)
-{
- DPRINTK("49==0x%04x "
- "53==0x%04x "
- "63==0x%04x "
- "64==0x%04x "
- "75==0x%04x \n",
- id[49],
- id[53],
- id[63],
- id[64],
- id[75]);
- DPRINTK("80==0x%04x "
- "81==0x%04x "
- "82==0x%04x "
- "83==0x%04x "
- "84==0x%04x \n",
- id[80],
- id[81],
- id[82],
- id[83],
- id[84]);
- DPRINTK("88==0x%04x "
- "93==0x%04x\n",
- id[88],
- id[93]);
-}
-
-/**
- * ata_id_xfermask - Compute xfermask from the given IDENTIFY data
- * @id: IDENTIFY data to compute xfer mask from
- *
- * Compute the xfermask for this device. This is not as trivial
- * as it seems if we must consider early devices correctly.
- *
- * FIXME: pre IDE drive timing (do we care ?).
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Computed xfermask
- */
-static unsigned int ata_id_xfermask(const u16 *id)
-{
- unsigned int pio_mask, mwdma_mask, udma_mask;
-
- /* Usual case. Word 53 indicates word 64 is valid */
- if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
- pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
- pio_mask <<= 3;
- pio_mask |= 0x7;
- } else {
- /* If word 64 isn't valid then Word 51 high byte holds
- * the PIO timing number for the maximum. Turn it into
- * a mask.
- */
- pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
-
- /* But wait.. there's more. Design your standards by
- * committee and you too can get a free iordy field to
- * process. However its the speeds not the modes that
- * are supported... Note drivers using the timing API
- * will get this right anyway
- */
- }
-
- mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
-
- udma_mask = 0;
- if (id[ATA_ID_FIELD_VALID] & (1 << 2))
- udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
-
- return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
-}
-
-/**
- * ata_port_queue_task - Queue port_task
- * @ap: The ata_port to queue port_task for
- * @fn: workqueue function to be scheduled
- * @data: data value to pass to workqueue function
- * @delay: delay time for workqueue function
- *
- * Schedule @fn(@data) for execution after @delay jiffies using
- * port_task. There is one port_task per port and it's the
- * user(low level driver)'s responsibility to make sure that only
- * one task is active at any given time.
- *
- * libata core layer takes care of synchronization between
- * port_task and EH. ata_port_queue_task() may be ignored for EH
- * synchronization.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
- unsigned long delay)
-{
- int rc;
-
- if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
- return;
-
- PREPARE_WORK(&ap->port_task, fn, data);
-
- if (!delay)
- rc = queue_work(ata_wq, &ap->port_task);
- else
- rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
-
- /* rc == 0 means that another user is using port task */
- WARN_ON(rc == 0);
-}
-
-/**
- * ata_port_flush_task - Flush port_task
- * @ap: The ata_port to flush port_task for
- *
- * After this function completes, port_task is guranteed not to
- * be running or scheduled.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_port_flush_task(struct ata_port *ap)
-{
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(ap->lock, flags);
-
- DPRINTK("flush #1\n");
- flush_workqueue(ata_wq);
-
- /*
- * At this point, if a task is running, it's guaranteed to see
- * the FLUSH flag; thus, it will never queue pio tasks again.
- * Cancel and flush.
- */
- if (!cancel_delayed_work(&ap->port_task)) {
- if (ata_msg_ctl(ap))
- ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
- flush_workqueue(ata_wq);
- }
-
- spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(ap->lock, flags);
-
- if (ata_msg_ctl(ap))
- ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
-}
-
-void ata_qc_complete_internal(struct ata_queued_cmd *qc)
-{
- struct completion *waiting = qc->private_data;
-
- complete(waiting);
-}
-
-/**
- * ata_exec_internal - execute libata internal command
- * @dev: Device to which the command is sent
- * @tf: Taskfile registers for the command and the result
- * @cdb: CDB for packet command
- * @dma_dir: Data tranfer direction of the command
- * @buf: Data buffer of the command
- * @buflen: Length of data buffer
- *
- * Executes libata internal command with timeout. @tf contains
- * command on entry and result on return. Timeout and error
- * conditions are reported via return value. No recovery action
- * is taken after a command times out. It's caller's duty to
- * clean up after timeout.
- *
- * LOCKING:
- * None. Should be called with kernel context, might sleep.
- *
- * RETURNS:
- * Zero on success, AC_ERR_* mask on failure
- */
-unsigned ata_exec_internal(struct ata_device *dev,
- struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen)
-{
- struct ata_port *ap = dev->ap;
- u8 command = tf->command;
- struct ata_queued_cmd *qc;
- unsigned int tag, preempted_tag;
- u32 preempted_sactive, preempted_qc_active;
- DECLARE_COMPLETION(wait);
- unsigned long flags;
- unsigned int err_mask;
- int rc;
-
- spin_lock_irqsave(ap->lock, flags);
-
- /* no internal command while frozen */
- if (ap->flags & ATA_FLAG_FROZEN) {
- spin_unlock_irqrestore(ap->lock, flags);
- return AC_ERR_SYSTEM;
- }
-
- /* initialize internal qc */
-
- /* XXX: Tag 0 is used for drivers with legacy EH as some
- * drivers choke if any other tag is given. This breaks
- * ata_tag_internal() test for those drivers. Don't use new
- * EH stuff without converting to it.
- */
- if (ap->ops->error_handler)
- tag = ATA_TAG_INTERNAL;
- else
- tag = 0;
-
- if (test_and_set_bit(tag, &ap->qc_allocated))
- BUG();
- qc = __ata_qc_from_tag(ap, tag);
-
- qc->tag = tag;
- qc->scsicmd = NULL;
- qc->ap = ap;
- qc->dev = dev;
- ata_qc_reinit(qc);
-
- preempted_tag = ap->active_tag;
- preempted_sactive = ap->sactive;
- preempted_qc_active = ap->qc_active;
- ap->active_tag = ATA_TAG_POISON;
- ap->sactive = 0;
- ap->qc_active = 0;
-
- /* prepare & issue qc */
- qc->tf = *tf;
- if (cdb)
- memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
- qc->flags |= ATA_QCFLAG_RESULT_TF;
- qc->dma_dir = dma_dir;
- if (dma_dir != DMA_NONE) {
- ata_sg_init_one(qc, buf, buflen);
- qc->nsect = buflen / ATA_SECT_SIZE;
- }
-
- qc->private_data = &wait;
- qc->complete_fn = ata_qc_complete_internal;
-
- ata_qc_issue(qc);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
-
- ata_port_flush_task(ap);
-
- if (!rc) {
- spin_lock_irqsave(ap->lock, flags);
-
- /* We're racing with irq here. If we lose, the
- * following test prevents us from completing the qc
- * twice. If we win, the port is frozen and will be
- * cleaned up by ->post_internal_cmd().
- */
- if (qc->flags & ATA_QCFLAG_ACTIVE) {
- qc->err_mask |= AC_ERR_TIMEOUT;
-
- if (ap->ops->error_handler)
- ata_port_freeze(ap);
- else
- ata_qc_complete(qc);
-
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "qc timeout (cmd 0x%x)\n", command);
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
- }
-
- /* do post_internal_cmd */
- if (ap->ops->post_internal_cmd)
- ap->ops->post_internal_cmd(qc);
-
- if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "zero err_mask for failed "
- "internal command, assuming AC_ERR_OTHER\n");
- qc->err_mask |= AC_ERR_OTHER;
- }
-
- /* finish up */
- spin_lock_irqsave(ap->lock, flags);
-
- *tf = qc->result_tf;
- err_mask = qc->err_mask;
-
- ata_qc_free(qc);
- ap->active_tag = preempted_tag;
- ap->sactive = preempted_sactive;
- ap->qc_active = preempted_qc_active;
-
- /* XXX - Some LLDDs (sata_mv) disable port on command failure.
- * Until those drivers are fixed, we detect the condition
- * here, fail the command with AC_ERR_SYSTEM and reenable the
- * port.
- *
- * Note that this doesn't change any behavior as internal
- * command failure results in disabling the device in the
- * higher layer for LLDDs without new reset/EH callbacks.
- *
- * Kill the following code as soon as those drivers are fixed.
- */
- if (ap->flags & ATA_FLAG_DISABLED) {
- err_mask |= AC_ERR_SYSTEM;
- ata_port_probe(ap);
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- return err_mask;
-}
-
-/**
- * ata_pio_need_iordy - check if iordy needed
- * @adev: ATA device
- *
- * Check if the current speed of the device requires IORDY. Used
- * by various controllers for chip configuration.
- */
-
-unsigned int ata_pio_need_iordy(const struct ata_device *adev)
-{
- int pio;
- int speed = adev->pio_mode - XFER_PIO_0;
-
- if (speed < 2)
- return 0;
- if (speed > 2)
- return 1;
-
- /* If we have no drive specific rule, then PIO 2 is non IORDY */
-
- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
- pio = adev->id[ATA_ID_EIDE_PIO];
- /* Is the speed faster than the drive allows non IORDY ? */
- if (pio) {
- /* This is cycle times not frequency - watch the logic! */
- if (pio > 240) /* PIO2 is 240nS per cycle */
- return 1;
- return 0;
- }
- }
- return 0;
-}
-
-/**
- * ata_dev_read_id - Read ID data from the specified device
- * @dev: target device
- * @p_class: pointer to class of the target device (may be changed)
- * @post_reset: is this read ID post-reset?
- * @id: buffer to read IDENTIFY data into
- *
- * Read ID data from the specified device. ATA_CMD_ID_ATA is
- * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
- * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
- * for pre-ATA4 drives.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
- int post_reset, u16 *id)
-{
- struct ata_port *ap = dev->ap;
- unsigned int class = *p_class;
- struct ata_taskfile tf;
- unsigned int err_mask = 0;
- const char *reason;
- int rc;
-
- if (ata_msg_ctl(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
-
- ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
- retry:
- ata_tf_init(dev, &tf);
-
- switch (class) {
- case ATA_DEV_ATA:
- tf.command = ATA_CMD_ID_ATA;
- break;
- case ATA_DEV_ATAPI:
- tf.command = ATA_CMD_ID_ATAPI;
- break;
- default:
- rc = -ENODEV;
- reason = "unsupported class";
- goto err_out;
- }
-
- tf.protocol = ATA_PROT_PIO;
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- id, sizeof(id[0]) * ATA_ID_WORDS);
- if (err_mask) {
- rc = -EIO;
- reason = "I/O error";
- goto err_out;
- }
-
- swap_buf_le16(id, ATA_ID_WORDS);
-
- /* sanity check */
- if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) {
- rc = -EINVAL;
- reason = "device reports illegal type";
- goto err_out;
- }
-
- if (post_reset && class == ATA_DEV_ATA) {
- /*
- * The exact sequence expected by certain pre-ATA4 drives is:
- * SRST RESET
- * IDENTIFY
- * INITIALIZE DEVICE PARAMETERS
- * anything else..
- * Some drives were very specific about that exact sequence.
- */
- if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
- err_mask = ata_dev_init_params(dev, id[3], id[6]);
- if (err_mask) {
- rc = -EIO;
- reason = "INIT_DEV_PARAMS failed";
- goto err_out;
- }
-
- /* current CHS translation info (id[53-58]) might be
- * changed. reread the identify device info.
- */
- post_reset = 0;
- goto retry;
- }
- }
-
- *p_class = class;
-
- return 0;
-
- err_out:
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
- "(%s, err_mask=0x%x)\n", reason, err_mask);
- return rc;
-}
-
-static inline u8 ata_dev_knobble(struct ata_device *dev)
-{
- return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
-}
-
-static void ata_dev_config_ncq(struct ata_device *dev,
- char *desc, size_t desc_sz)
-{
- struct ata_port *ap = dev->ap;
- int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
-
- if (!ata_id_has_ncq(dev->id)) {
- desc[0] = '\0';
- return;
- }
-
- if (ap->flags & ATA_FLAG_NCQ) {
- hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1);
- dev->flags |= ATA_DFLAG_NCQ;
- }
-
- if (hdepth >= ddepth)
- snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
- else
- snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
-}
-
-/**
- * ata_dev_configure - Configure the specified ATA/ATAPI device
- * @dev: Target device to configure
- * @print_info: Enable device info printout
- *
- * Configure @dev according to @dev->id. Generic and low-level
- * driver specific fixups are also applied.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise
- */
-int ata_dev_configure(struct ata_device *dev, int print_info)
-{
- struct ata_port *ap = dev->ap;
- const u16 *id = dev->id;
- unsigned int xfer_mask;
- int i, rc;
-
- if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
- ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
- __FUNCTION__, ap->id, dev->devno);
- return 0;
- }
-
- if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
-
- /* print device capabilities */
- if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
- "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
- __FUNCTION__,
- id[49], id[82], id[83], id[84],
- id[85], id[86], id[87], id[88]);
-
- /* initialize to-be-configured parameters */
- dev->flags &= ~ATA_DFLAG_CFG_MASK;
- dev->max_sectors = 0;
- dev->cdb_len = 0;
- dev->n_sectors = 0;
- dev->cylinders = 0;
- dev->heads = 0;
- dev->sectors = 0;
-
- /*
- * common ATA, ATAPI feature tests
- */
-
- /* find max transfer mode; for printk only */
- xfer_mask = ata_id_xfermask(id);
-
- if (ata_msg_probe(ap))
- ata_dump_id(id);
-
- /* ATA-specific feature tests */
- if (dev->class == ATA_DEV_ATA) {
- dev->n_sectors = ata_id_n_sectors(id);
-
- if (ata_id_has_lba(id)) {
- const char *lba_desc;
- char ncq_desc[20];
-
- lba_desc = "LBA";
- dev->flags |= ATA_DFLAG_LBA;
- if (ata_id_has_lba48(id)) {
- dev->flags |= ATA_DFLAG_LBA48;
- lba_desc = "LBA48";
- }
-
- /* config NCQ */
- ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
-
- /* print device info to dmesg */
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
- "max %s, %Lu sectors: %s %s\n",
- ata_id_major_version(id),
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- lba_desc, ncq_desc);
- } else {
- /* CHS */
-
- /* Default translation */
- dev->cylinders = id[1];
- dev->heads = id[3];
- dev->sectors = id[6];
-
- if (ata_id_current_chs_valid(id)) {
- /* Current CHS translation is valid. */
- dev->cylinders = id[54];
- dev->heads = id[55];
- dev->sectors = id[56];
- }
-
- /* print device info to dmesg */
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
- "max %s, %Lu sectors: CHS %u/%u/%u\n",
- ata_id_major_version(id),
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- dev->cylinders, dev->heads, dev->sectors);
- }
-
- if (dev->id[59] & 0x100) {
- dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
- ap->id, dev->devno, dev->multi_count);
- }
-
- dev->cdb_len = 16;
- }
-
- /* ATAPI-specific feature tests */
- else if (dev->class == ATA_DEV_ATAPI) {
- char *cdb_intr_string = "";
-
- rc = atapi_cdb_len(id);
- if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "unsupported CDB len\n");
- rc = -EINVAL;
- goto err_out_nosup;
- }
- dev->cdb_len = (unsigned int) rc;
-
- if (ata_id_cdb_intr(dev->id)) {
- dev->flags |= ATA_DFLAG_CDB_INTR;
- cdb_intr_string = ", CDB intr";
- }
-
- /* print device info to dmesg */
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
- ata_mode_string(xfer_mask),
- cdb_intr_string);
- }
-
- ap->host->max_cmd_len = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->host->max_cmd_len = max_t(unsigned int,
- ap->host->max_cmd_len,
- ap->device[i].cdb_len);
-
- /* limit bridge transfers to udma5, 200 sectors */
- if (ata_dev_knobble(dev)) {
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO,
- "applying bridge limits\n");
- dev->udma_mask &= ATA_UDMA5;
- dev->max_sectors = ATA_MAX_SECTORS;
- }
-
- if (ap->ops->dev_config)
- ap->ops->dev_config(ap, dev);
-
- if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
- __FUNCTION__, ata_chk_status(ap));
- return 0;
-
-err_out_nosup:
- if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG,
- "%s: EXIT, err\n", __FUNCTION__);
- return rc;
-}
-
-/**
- * ata_bus_probe - Reset and probe ATA bus
- * @ap: Bus to probe
- *
- * Master ATA bus probing function. Initiates a hardware-dependent
- * bus reset, then attempts to identify any devices found on
- * the bus.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- * RETURNS:
- * Zero on success, negative errno otherwise.
- */
-
-static int ata_bus_probe(struct ata_port *ap)
-{
- unsigned int classes[ATA_MAX_DEVICES];
- int tries[ATA_MAX_DEVICES];
- int i, rc, down_xfermask;
- struct ata_device *dev;
-
- ata_port_probe(ap);
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- tries[i] = ATA_PROBE_MAX_TRIES;
-
- retry:
- down_xfermask = 0;
-
- /* reset and determine device classes */
- ap->ops->phy_reset(ap);
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!(ap->flags & ATA_FLAG_DISABLED) &&
- dev->class != ATA_DEV_UNKNOWN)
- classes[dev->devno] = dev->class;
- else
- classes[dev->devno] = ATA_DEV_NONE;
-
- dev->class = ATA_DEV_UNKNOWN;
- }
-
- ata_port_probe(ap);
-
- /* after the reset the device state is PIO 0 and the controller
- state is undefined. Record the mode */
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
-
- /* read IDENTIFY page and configure devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (tries[i])
- dev->class = classes[i];
-
- if (!ata_dev_enabled(dev))
- continue;
-
- rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
- if (rc)
- goto fail;
-
- rc = ata_dev_configure(dev, 1);
- if (rc)
- goto fail;
- }
-
- /* configure transfer mode */
- rc = ata_set_mode(ap, &dev);
- if (rc) {
- down_xfermask = 1;
- goto fail;
- }
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
- return 0;
-
- /* no device present, disable port */
- ata_port_disable(ap);
- ap->ops->port_disable(ap);
- return -ENODEV;
-
- fail:
- switch (rc) {
- case -EINVAL:
- case -ENODEV:
- tries[dev->devno] = 0;
- break;
- case -EIO:
- sata_down_spd_limit(ap);
- /* fall through */
- default:
- tries[dev->devno]--;
- if (down_xfermask &&
- ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
- tries[dev->devno] = 0;
- }
-
- if (!tries[dev->devno]) {
- ata_down_xfermask_limit(dev, 1);
- ata_dev_disable(dev);
- }
-
- goto retry;
-}
-
-/**
- * ata_port_probe - Mark port as enabled
- * @ap: Port for which we indicate enablement
- *
- * Modify @ap data structure such that the system
- * thinks that the entire port is enabled.
- *
- * LOCKING: host_set lock, or some other form of
- * serialization.
- */
-
-void ata_port_probe(struct ata_port *ap)
-{
- ap->flags &= ~ATA_FLAG_DISABLED;
-}
-
-/**
- * sata_print_link_status - Print SATA link status
- * @ap: SATA port to printk link status about
- *
- * This function prints link speed and status of a SATA link.
- *
- * LOCKING:
- * None.
- */
-static void sata_print_link_status(struct ata_port *ap)
-{
- u32 sstatus, scontrol, tmp;
-
- if (sata_scr_read(ap, SCR_STATUS, &sstatus))
- return;
- sata_scr_read(ap, SCR_CONTROL, &scontrol);
-
- if (ata_port_online(ap)) {
- tmp = (sstatus >> 4) & 0xf;
- ata_port_printk(ap, KERN_INFO,
- "SATA link up %s (SStatus %X SControl %X)\n",
- sata_spd_string(tmp), sstatus, scontrol);
- } else {
- ata_port_printk(ap, KERN_INFO,
- "SATA link down (SStatus %X SControl %X)\n",
- sstatus, scontrol);
- }
-}
-
-/**
- * __sata_phy_reset - Wake/reset a low-level SATA PHY
- * @ap: SATA port associated with target SATA PHY.
- *
- * This function issues commands to standard SATA Sxxx
- * PHY registers, to wake up the phy (and device), and
- * clear any reset condition.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- */
-void __sata_phy_reset(struct ata_port *ap)
-{
- u32 sstatus;
- unsigned long timeout = jiffies + (HZ * 5);
-
- if (ap->flags & ATA_FLAG_SATA_RESET) {
- /* issue phy wake/reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
- /* Couldn't find anything in SATA I/II specs, but
- * AHCI-1.1 10.4.2 says at least 1 ms. */
- mdelay(1);
- }
- /* phy wake/clear reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
-
- /* wait for phy to become ready, if necessary */
- do {
- msleep(200);
- sata_scr_read(ap, SCR_STATUS, &sstatus);
- if ((sstatus & 0xf) != 1)
- break;
- } while (time_before(jiffies, timeout));
-
- /* print link status */
- sata_print_link_status(ap);
-
- /* TODO: phy layer with polling, timeouts, etc. */
- if (!ata_port_offline(ap))
- ata_port_probe(ap);
- else
- ata_port_disable(ap);
-
- if (ap->flags & ATA_FLAG_DISABLED)
- return;
-
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- ata_port_disable(ap);
- return;
- }
-
- ap->cbl = ATA_CBL_SATA;
-}
-
-/**
- * sata_phy_reset - Reset SATA bus.
- * @ap: SATA port associated with target SATA PHY.
- *
- * This function resets the SATA bus, and then probes
- * the bus for devices.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- */
-void sata_phy_reset(struct ata_port *ap)
-{
- __sata_phy_reset(ap);
- if (ap->flags & ATA_FLAG_DISABLED)
- return;
- ata_bus_reset(ap);
-}
-
-/**
- * ata_dev_pair - return other device on cable
- * @adev: device
- *
- * Obtain the other device on the same cable, or if none is
- * present NULL is returned
- */
-
-struct ata_device *ata_dev_pair(struct ata_device *adev)
-{
- struct ata_port *ap = adev->ap;
- struct ata_device *pair = &ap->device[1 - adev->devno];
- if (!ata_dev_enabled(pair))
- return NULL;
- return pair;
-}
-
-/**
- * ata_port_disable - Disable port.
- * @ap: Port to be disabled.
- *
- * Modify @ap data structure such that the system
- * thinks that the entire port is disabled, and should
- * never attempt to probe or communicate with devices
- * on this port.
- *
- * LOCKING: host_set lock, or some other form of
- * serialization.
- */
-
-void ata_port_disable(struct ata_port *ap)
-{
- ap->device[0].class = ATA_DEV_NONE;
- ap->device[1].class = ATA_DEV_NONE;
- ap->flags |= ATA_FLAG_DISABLED;
-}
-
-/**
- * sata_down_spd_limit - adjust SATA spd limit downward
- * @ap: Port to adjust SATA spd limit for
- *
- * Adjust SATA spd limit of @ap downward. Note that this
- * function only adjusts the limit. The change must be applied
- * using sata_set_spd().
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 0 on success, negative errno on failure
- */
-int sata_down_spd_limit(struct ata_port *ap)
-{
- u32 sstatus, spd, mask;
- int rc, highbit;
-
- rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
- if (rc)
- return rc;
-
- mask = ap->sata_spd_limit;
- if (mask <= 1)
- return -EINVAL;
- highbit = fls(mask) - 1;
- mask &= ~(1 << highbit);
-
- spd = (sstatus >> 4) & 0xf;
- if (spd <= 1)
- return -EINVAL;
- spd--;
- mask &= (1 << spd) - 1;
- if (!mask)
- return -EINVAL;
-
- ap->sata_spd_limit = mask;
-
- ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
- sata_spd_string(fls(mask)));
-
- return 0;
-}
-
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
-{
- u32 spd, limit;
-
- if (ap->sata_spd_limit == UINT_MAX)
- limit = 0;
- else
- limit = fls(ap->sata_spd_limit);
-
- spd = (*scontrol >> 4) & 0xf;
- *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
-
- return spd != limit;
-}
-
-/**
- * sata_set_spd_needed - is SATA spd configuration needed
- * @ap: Port in question
- *
- * Test whether the spd limit in SControl matches
- * @ap->sata_spd_limit. This function is used to determine
- * whether hardreset is necessary to apply SATA spd
- * configuration.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 1 if SATA spd configuration is needed, 0 otherwise.
- */
-int sata_set_spd_needed(struct ata_port *ap)
-{
- u32 scontrol;
-
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
- return 0;
-
- return __sata_set_spd_needed(ap, &scontrol);
-}
-
-/**
- * sata_set_spd - set SATA spd according to spd limit
- * @ap: Port to set SATA spd for
- *
- * Set SATA spd of @ap according to sata_spd_limit.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 0 if spd doesn't need to be changed, 1 if spd has been
- * changed. Negative errno if SCR registers are inaccessible.
- */
-int sata_set_spd(struct ata_port *ap)
-{
- u32 scontrol;
- int rc;
-
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
- return rc;
-
- if (!__sata_set_spd_needed(ap, &scontrol))
- return 0;
-
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
- return rc;
-
- return 1;
-}
-
-/*
- * This mode timing computation functionality is ported over from
- * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
- */
-/*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
- * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension and UDMA6, which
- * is currently supported only by Maxtor drives.
- */
-
-static const struct ata_timing ata_timing[] = {
-
- { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
- { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
- { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
- { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
-
- { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
- { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
- { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
-
-/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
-
- { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
- { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
- { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
-
- { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
- { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
- { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
-
-/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */
- { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
- { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
-
- { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
- { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
- { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
-
-/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */
-
- { 0xFF }
-};
-
-#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
-#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
-
-static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
-{
- q->setup = EZ(t->setup * 1000, T);
- q->act8b = EZ(t->act8b * 1000, T);
- q->rec8b = EZ(t->rec8b * 1000, T);
- q->cyc8b = EZ(t->cyc8b * 1000, T);
- q->active = EZ(t->active * 1000, T);
- q->recover = EZ(t->recover * 1000, T);
- q->cycle = EZ(t->cycle * 1000, T);
- q->udma = EZ(t->udma * 1000, UT);
-}
-
-void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
- struct ata_timing *m, unsigned int what)
-{
- if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup);
- if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b);
- if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b);
- if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
- if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
- if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
- if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
- if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
-}
-
-static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
-{
- const struct ata_timing *t;
-
- for (t = ata_timing; t->mode != speed; t++)
- if (t->mode == 0xFF)
- return NULL;
- return t;
-}
-
-int ata_timing_compute(struct ata_device *adev, unsigned short speed,
- struct ata_timing *t, int T, int UT)
-{
- const struct ata_timing *s;
- struct ata_timing p;
-
- /*
- * Find the mode.
- */
-
- if (!(s = ata_timing_find_mode(speed)))
- return -EINVAL;
-
- memcpy(t, s, sizeof(*s));
-
- /*
- * If the drive is an EIDE drive, it can tell us it needs extended
- * PIO/MW_DMA cycle timing.
- */
-
- if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
- memset(&p, 0, sizeof(p));
- if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
- if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
- else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
- } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
- p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
- }
- ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
- }
-
- /*
- * Convert the timing to bus clock counts.
- */
-
- ata_timing_quantize(t, t, T, UT);
-
- /*
- * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
- * S.M.A.R.T * and some other commands. We have to ensure that the
- * DMA cycle timing is slower/equal than the fastest PIO timing.
- */
-
- if (speed > XFER_PIO_4) {
- ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
- ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
- }
-
- /*
- * Lengthen active & recovery time so that cycle time is correct.
- */
-
- if (t->act8b + t->rec8b < t->cyc8b) {
- t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
- t->rec8b = t->cyc8b - t->act8b;
- }
-
- if (t->active + t->recover < t->cycle) {
- t->active += (t->cycle - (t->active + t->recover)) / 2;
- t->recover = t->cycle - t->active;
- }
-
- return 0;
-}
-
-/**
- * ata_down_xfermask_limit - adjust dev xfer masks downward
- * @dev: Device to adjust xfer masks
- * @force_pio0: Force PIO0
- *
- * Adjust xfer masks of @dev downward. Note that this function
- * does not apply the change. Invoking ata_set_mode() afterwards
- * will apply the limit.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 0 on success, negative errno on failure
- */
-int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
-{
- unsigned long xfer_mask;
- int highbit;
-
- xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
- dev->udma_mask);
-
- if (!xfer_mask)
- goto fail;
- /* don't gear down to MWDMA from UDMA, go directly to PIO */
- if (xfer_mask & ATA_MASK_UDMA)
- xfer_mask &= ~ATA_MASK_MWDMA;
-
- highbit = fls(xfer_mask) - 1;
- xfer_mask &= ~(1 << highbit);
- if (force_pio0)
- xfer_mask &= 1 << ATA_SHIFT_PIO;
- if (!xfer_mask)
- goto fail;
-
- ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
- &dev->udma_mask);
-
- ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
- ata_mode_string(xfer_mask));
-
- return 0;
-
- fail:
- return -EINVAL;
-}
-
-static int ata_dev_set_mode(struct ata_device *dev)
-{
- unsigned int err_mask;
- int rc;
-
- dev->flags &= ~ATA_DFLAG_PIO;
- if (dev->xfer_shift == ATA_SHIFT_PIO)
- dev->flags |= ATA_DFLAG_PIO;
-
- err_mask = ata_dev_set_xfermode(dev);
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
- }
-
- rc = ata_dev_revalidate(dev, 0);
- if (rc)
- return rc;
-
- DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
- dev->xfer_shift, (int)dev->xfer_mode);
-
- ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
- ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
- return 0;
-}
-
-/**
- * ata_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
- * @r_failed_dev: out paramter for failed device
- *
- * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
- * ata_set_mode() fails, pointer to the failing device is
- * returned in @r_failed_dev.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- * RETURNS:
- * 0 on success, negative errno otherwise
- */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
-{
- struct ata_device *dev;
- int i, rc = 0, used_dma = 0, found = 0;
-
- /* has private set_mode? */
- if (ap->ops->set_mode) {
- /* FIXME: make ->set_mode handle no device case and
- * return error code and failing device on failure.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (ata_dev_enabled(&ap->device[i])) {
- ap->ops->set_mode(ap);
- break;
- }
- }
- return 0;
- }
-
- /* step 1: calculate xfer_mask */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- unsigned int pio_mask, dma_mask;
-
- dev = &ap->device[i];
-
- if (!ata_dev_enabled(dev))
- continue;
-
- ata_dev_xfermask(dev);
-
- pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
- dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
- dev->pio_mode = ata_xfer_mask2mode(pio_mask);
- dev->dma_mode = ata_xfer_mask2mode(dma_mask);
-
- found = 1;
- if (dev->dma_mode)
- used_dma = 1;
- }
- if (!found)
- goto out;
-
- /* step 2: always set host PIO timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
- if (!ata_dev_enabled(dev))
- continue;
-
- if (!dev->pio_mode) {
- ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
- rc = -EINVAL;
- goto out;
- }
-
- dev->xfer_mode = dev->pio_mode;
- dev->xfer_shift = ATA_SHIFT_PIO;
- if (ap->ops->set_piomode)
- ap->ops->set_piomode(ap, dev);
- }
-
- /* step 3: set host DMA timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!ata_dev_enabled(dev) || !dev->dma_mode)
- continue;
-
- dev->xfer_mode = dev->dma_mode;
- dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
- if (ap->ops->set_dmamode)
- ap->ops->set_dmamode(ap, dev);
- }
-
- /* step 4: update devices' xfer mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!ata_dev_enabled(dev))
- continue;
-
- rc = ata_dev_set_mode(dev);
- if (rc)
- goto out;
- }
-
- /* Record simplex status. If we selected DMA then the other
- * host channels are not permitted to do so.
- */
- if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX))
- ap->host_set->simplex_claimed = 1;
-
- /* step5: chip specific finalisation */
- if (ap->ops->post_set_mode)
- ap->ops->post_set_mode(ap);
-
- out:
- if (rc)
- *r_failed_dev = dev;
- return rc;
-}
-
-/**
- * ata_tf_to_host - issue ATA taskfile to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues ATA taskfile register set to ATA host controller,
- * with proper synchronization with interrupt handler and
- * other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static inline void ata_tf_to_host(struct ata_port *ap,
- const struct ata_taskfile *tf)
-{
- ap->ops->tf_load(ap, tf);
- ap->ops->exec_command(ap, tf);
-}
-
-/**
- * ata_busy_sleep - sleep until BSY clears, or timeout
- * @ap: port containing status register to be polled
- * @tmout_pat: impatience timeout
- * @tmout: overall timeout
- *
- * Sleep until ATA Status register bit BSY clears,
- * or a timeout occurs.
- *
- * LOCKING: None.
- */
-
-unsigned int ata_busy_sleep (struct ata_port *ap,
- unsigned long tmout_pat, unsigned long tmout)
-{
- unsigned long timer_start, timeout;
- u8 status;
-
- status = ata_busy_wait(ap, ATA_BUSY, 300);
- timer_start = jiffies;
- timeout = timer_start + tmout_pat;
- while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
- msleep(50);
- status = ata_busy_wait(ap, ATA_BUSY, 3);
- }
-
- if (status & ATA_BUSY)
- ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient\n");
-
- timeout = timer_start + tmout;
- while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
- msleep(50);
- status = ata_chk_status(ap);
- }
-
- if (status & ATA_BUSY) {
- ata_port_printk(ap, KERN_ERR, "port failed to respond "
- "(%lu secs)\n", tmout / HZ);
- return 1;
- }
-
- return 0;
-}
-
-static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int dev0 = devmask & (1 << 0);
- unsigned int dev1 = devmask & (1 << 1);
- unsigned long timeout;
-
- /* if device 0 was found in ata_devchk, wait for its
- * BSY bit to clear
- */
- if (dev0)
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-
- /* if device 1 was found in ata_devchk, wait for
- * register access, then wait for BSY to clear
- */
- timeout = jiffies + ATA_TMOUT_BOOT;
- while (dev1) {
- u8 nsect, lbal;
-
- ap->ops->dev_select(ap, 1);
- if (ap->flags & ATA_FLAG_MMIO) {
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
- } else {
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
- }
- if ((nsect == 1) && (lbal == 1))
- break;
- if (time_after(jiffies, timeout)) {
- dev1 = 0;
- break;
- }
- msleep(50); /* give drive a breather */
- }
- if (dev1)
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-
- /* is all this really necessary? */
- ap->ops->dev_select(ap, 0);
- if (dev1)
- ap->ops->dev_select(ap, 1);
- if (dev0)
- ap->ops->dev_select(ap, 0);
-}
-
-static unsigned int ata_bus_softreset(struct ata_port *ap,
- unsigned int devmask)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- DPRINTK("ata%u: bus reset via SRST\n", ap->id);
-
- /* software reset. causes dev0 to be selected */
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- } else {
- outb(ap->ctl, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl, ioaddr->ctl_addr);
- }
-
- /* spec mandates ">= 2ms" before checking status.
- * We wait 150ms, because that was the magic delay used for
- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- *
- * Old drivers/ide uses the 2mS rule and then waits for ready
- */
- msleep(150);
-
- /* Before we perform post reset processing we want to see if
- * the bus shows 0xFF because the odd clown forgets the D7
- * pulldown resistor.
- */
- if (ata_check_status(ap) == 0xFF) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n");
- return AC_ERR_OTHER;
- }
-
- ata_bus_post_reset(ap, devmask);
-
- return 0;
-}
-
-/**
- * ata_bus_reset - reset host port and associated ATA channel
- * @ap: port to reset
- *
- * This is typically the first time we actually start issuing
- * commands to the ATA channel. We wait for BSY to clear, then
- * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
- * result. Determine what devices, if any, are on the channel
- * by looking at the device 0/1 error register. Look at the signature
- * stored in each device's taskfile registers, to determine if
- * the device is ATA or ATAPI.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- * Obtains host_set lock.
- *
- * SIDE EFFECTS:
- * Sets ATA_FLAG_DISABLED if bus reset fails.
- */
-
-void ata_bus_reset(struct ata_port *ap)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
- u8 err;
- unsigned int dev0, dev1 = 0, devmask = 0;
-
- DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
-
- /* determine if device 0/1 are present */
- if (ap->flags & ATA_FLAG_SATA_RESET)
- dev0 = 1;
- else {
- dev0 = ata_devchk(ap, 0);
- if (slave_possible)
- dev1 = ata_devchk(ap, 1);
- }
-
- if (dev0)
- devmask |= (1 << 0);
- if (dev1)
- devmask |= (1 << 1);
-
- /* select device 0 again */
- ap->ops->dev_select(ap, 0);
-
- /* issue bus reset */
- if (ap->flags & ATA_FLAG_SRST)
- if (ata_bus_softreset(ap, devmask))
- goto err_out;
-
- /*
- * determine by signature whether we have ATA or ATAPI devices
- */
- ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
- if ((slave_possible) && (err != 0x81))
- ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
-
- /* re-enable interrupts */
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
-
- /* is double-select really necessary? */
- if (ap->device[1].class != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 1);
- if (ap->device[0].class != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 0);
-
- /* if no devices were detected, disable this port */
- if ((ap->device[0].class == ATA_DEV_NONE) &&
- (ap->device[1].class == ATA_DEV_NONE))
- goto err_out;
-
- if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
- /* set up device control for ATA_FLAG_SATA_RESET */
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
- }
-
- DPRINTK("EXIT\n");
- return;
-
-err_out:
- ata_port_printk(ap, KERN_ERR, "disabling port\n");
- ap->ops->port_disable(ap);
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * sata_phy_debounce - debounce SATA phy status
- * @ap: ATA port to debounce SATA phy status for
- * @params: timing parameters { interval, duratinon, timeout } in msec
- *
- * Make sure SStatus of @ap reaches stable state, determined by
- * holding the same value where DET is not 1 for @duration polled
- * every @interval, before @timeout. Timeout constraints the
- * beginning of the stable state. Because, after hot unplugging,
- * DET gets stuck at 1 on some controllers, this functions waits
- * until timeout then returns 0 if DET is stable at 1.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
-{
- unsigned long interval_msec = params[0];
- unsigned long duration = params[1] * HZ / 1000;
- unsigned long timeout = jiffies + params[2] * HZ / 1000;
- unsigned long last_jiffies;
- u32 last, cur;
- int rc;
-
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
- return rc;
- cur &= 0xf;
-
- last = cur;
- last_jiffies = jiffies;
-
- while (1) {
- msleep(interval_msec);
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
- return rc;
- cur &= 0xf;
-
- /* DET stable? */
- if (cur == last) {
- if (cur == 1 && time_before(jiffies, timeout))
- continue;
- if (time_after(jiffies, last_jiffies + duration))
- return 0;
- continue;
- }
-
- /* unstable, start over */
- last = cur;
- last_jiffies = jiffies;
-
- /* check timeout */
- if (time_after(jiffies, timeout))
- return -EBUSY;
- }
-}
-
-/**
- * sata_phy_resume - resume SATA phy
- * @ap: ATA port to resume SATA phy for
- * @params: timing parameters { interval, duratinon, timeout } in msec
- *
- * Resume SATA phy of @ap and debounce it.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
-{
- u32 scontrol;
- int rc;
-
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
- return rc;
-
- scontrol = (scontrol & 0x0f0) | 0x300;
-
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
- return rc;
-
- /* Some PHYs react badly if SStatus is pounded immediately
- * after resuming. Delay 200ms before debouncing.
- */
- msleep(200);
-
- return sata_phy_debounce(ap, params);
-}
-
-static void ata_wait_spinup(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- unsigned long end, secs;
- int rc;
-
- /* first, debounce phy if SATA */
- if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_debounce(ap, sata_deb_timing_eh);
-
- /* if debounced successfully and offline, no need to wait */
- if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
- return;
- }
-
- /* okay, let's give the drive time to spin up */
- end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
- secs = ((end - jiffies) + HZ - 1) / HZ;
-
- if (time_after(jiffies, end))
- return;
-
- if (secs > 5)
- ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
- "(%lu secs)\n", secs);
-
- schedule_timeout_uninterruptible(end - jiffies);
-}
-
-/**
- * ata_std_prereset - prepare for reset
- * @ap: ATA port to be reset
- *
- * @ap is about to be reset. Initialize it.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_std_prereset(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- const unsigned long *timing;
- int rc;
-
- /* hotplug? */
- if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
- if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
- ehc->i.action |= ATA_EH_HARDRESET;
- if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
- ata_wait_spinup(ap);
- }
-
- /* if we're about to do hardreset, nothing more to do */
- if (ehc->i.action & ATA_EH_HARDRESET)
- return 0;
-
- /* if SATA, resume phy */
- if (ap->cbl == ATA_CBL_SATA) {
- if (ap->flags & ATA_FLAG_LOADING)
- timing = sata_deb_timing_boot;
- else
- timing = sata_deb_timing_eh;
-
- rc = sata_phy_resume(ap, timing);
- if (rc && rc != -EOPNOTSUPP) {
- /* phy resume failed */
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
- "link for reset (errno=%d)\n", rc);
- return rc;
- }
- }
-
- /* Wait for !BSY if the controller can wait for the first D2H
- * Reg FIS and we don't know that no device is attached.
- */
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-
- return 0;
-}
-
-/**
- * ata_std_softreset - reset host port via ATA SRST
- * @ap: port to reset
- * @classes: resulting classes of attached devices
- *
- * Reset host port using ATA SRST.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
-{
- unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
- unsigned int devmask = 0, err_mask;
- u8 err;
-
- DPRINTK("ENTER\n");
-
- if (ata_port_offline(ap)) {
- classes[0] = ATA_DEV_NONE;
- goto out;
- }
-
- /* determine if device 0/1 are present */
- if (ata_devchk(ap, 0))
- devmask |= (1 << 0);
- if (slave_possible && ata_devchk(ap, 1))
- devmask |= (1 << 1);
-
- /* select device 0 again */
- ap->ops->dev_select(ap, 0);
-
- /* issue bus reset */
- DPRINTK("about to softreset, devmask=%x\n", devmask);
- err_mask = ata_bus_softreset(ap, devmask);
- if (err_mask) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
- err_mask);
- return -EIO;
- }
-
- /* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
- if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
-
- out:
- DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
- return 0;
-}
-
-/**
- * sata_std_hardreset - reset host port via SATA phy reset
- * @ap: port to reset
- * @class: resulting class of attached device
- *
- * SATA phy-reset host port using DET bits of SControl register.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
-{
- u32 scontrol;
- int rc;
-
- DPRINTK("ENTER\n");
-
- if (sata_set_spd_needed(ap)) {
- /* SATA spec says nothing about how to reconfigure
- * spd. To be on the safe side, turn off phy during
- * reconfiguration. This works for at least ICH7 AHCI
- * and Sil3124.
- */
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
- return rc;
-
- scontrol = (scontrol & 0x0f0) | 0x302;
-
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
- return rc;
-
- sata_set_spd(ap);
- }
-
- /* issue phy wake/reset */
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
- return rc;
-
- scontrol = (scontrol & 0x0f0) | 0x301;
-
- if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
- return rc;
-
- /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
- * 10.4.2 says at least 1 ms.
- */
- msleep(1);
-
- /* bring phy back */
- sata_phy_resume(ap, sata_deb_timing_eh);
-
- /* TODO: phy layer with polling, timeouts, etc. */
- if (ata_port_offline(ap)) {
- *class = ATA_DEV_NONE;
- DPRINTK("EXIT, link offline\n");
- return 0;
- }
-
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- ata_port_printk(ap, KERN_ERR,
- "COMRESET failed (device not ready)\n");
- return -EIO;
- }
-
- ap->ops->dev_select(ap, 0); /* probably unnecessary */
-
- *class = ata_dev_try_classify(ap, 0, NULL);
-
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
-}
-
-/**
- * ata_std_postreset - standard postreset callback
- * @ap: the target ata_port
- * @classes: classes of attached devices
- *
- * This function is invoked after a successful reset. Note that
- * the device might have been reset more than once using
- * different reset methods before postreset is invoked.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- */
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
-{
- u32 serror;
-
- DPRINTK("ENTER\n");
-
- /* print link status */
- sata_print_link_status(ap);
-
- /* clear SError */
- if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
- sata_scr_write(ap, SCR_ERROR, serror);
-
- /* re-enable interrupts */
- if (!ap->ops->error_handler) {
- /* FIXME: hack. create a hook instead */
- if (ap->ioaddr.ctl_addr)
- ata_irq_on(ap);
- }
-
- /* is double-select really necessary? */
- if (classes[0] != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 1);
- if (classes[1] != ATA_DEV_NONE)
- ap->ops->dev_select(ap, 0);
-
- /* bail out if no device is present */
- if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
- DPRINTK("EXIT, no device\n");
- return;
- }
-
- /* set up device control */
- if (ap->ioaddr.ctl_addr) {
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
- else
- outb(ap->ctl, ap->ioaddr.ctl_addr);
- }
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_dev_same_device - Determine whether new ID matches configured device
- * @dev: device to compare against
- * @new_class: class of the new device
- * @new_id: IDENTIFY page of the new device
- *
- * Compare @new_class and @new_id against @dev and determine
- * whether @dev is the device indicated by @new_class and
- * @new_id.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if @dev matches @new_class and @new_id, 0 otherwise.
- */
-static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
- const u16 *new_id)
-{
- const u16 *old_id = dev->id;
- unsigned char model[2][41], serial[2][21];
- u64 new_n_sectors;
-
- if (dev->class != new_class) {
- ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
- dev->class, new_class);
- return 0;
- }
-
- ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
- ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
- ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
- ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
- new_n_sectors = ata_id_n_sectors(new_id);
-
- if (strcmp(model[0], model[1])) {
- ata_dev_printk(dev, KERN_INFO, "model number mismatch "
- "'%s' != '%s'\n", model[0], model[1]);
- return 0;
- }
-
- if (strcmp(serial[0], serial[1])) {
- ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
- "'%s' != '%s'\n", serial[0], serial[1]);
- return 0;
- }
-
- if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
- ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
- "%llu != %llu\n",
- (unsigned long long)dev->n_sectors,
- (unsigned long long)new_n_sectors);
- return 0;
- }
-
- return 1;
-}
-
-/**
- * ata_dev_revalidate - Revalidate ATA device
- * @dev: device to revalidate
- * @post_reset: is this revalidation after reset?
- *
- * Re-read IDENTIFY page and make sure @dev is still attached to
- * the port.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, negative errno otherwise
- */
-int ata_dev_revalidate(struct ata_device *dev, int post_reset)
-{
- unsigned int class = dev->class;
- u16 *id = (void *)dev->ap->sector_buf;
- int rc;
-
- if (!ata_dev_enabled(dev)) {
- rc = -ENODEV;
- goto fail;
- }
-
- /* read ID data */
- rc = ata_dev_read_id(dev, &class, post_reset, id);
- if (rc)
- goto fail;
-
- /* is the device still there? */
- if (!ata_dev_same_device(dev, class, id)) {
- rc = -ENODEV;
- goto fail;
- }
-
- memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS);
-
- /* configure device according to the new ID */
- rc = ata_dev_configure(dev, 0);
- if (rc == 0)
- return 0;
-
- fail:
- ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
- return rc;
-}
-
-static const char * const ata_dma_blacklist [] = {
- "WDC AC11000H", NULL,
- "WDC AC22100H", NULL,
- "WDC AC32500H", NULL,
- "WDC AC33100H", NULL,
- "WDC AC31600H", NULL,
- "WDC AC32100H", "24.09P07",
- "WDC AC23200L", "21.10N21",
- "Compaq CRD-8241B", NULL,
- "CRD-8400B", NULL,
- "CRD-8480B", NULL,
- "CRD-8482B", NULL,
- "CRD-84", NULL,
- "SanDisk SDP3B", NULL,
- "SanDisk SDP3B-64", NULL,
- "SANYO CD-ROM CRD", NULL,
- "HITACHI CDR-8", NULL,
- "HITACHI CDR-8335", NULL,
- "HITACHI CDR-8435", NULL,
- "Toshiba CD-ROM XM-6202B", NULL,
- "TOSHIBA CD-ROM XM-1702BC", NULL,
- "CD-532E-A", NULL,
- "E-IDE CD-ROM CR-840", NULL,
- "CD-ROM Drive/F5A", NULL,
- "WPI CDD-820", NULL,
- "SAMSUNG CD-ROM SC-148C", NULL,
- "SAMSUNG CD-ROM SC", NULL,
- "SanDisk SDP3B-64", NULL,
- "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,
- "_NEC DV5800A", NULL,
- "SAMSUNG CD-ROM SN-124", "N001"
-};
-
-static int ata_strim(char *s, size_t len)
-{
- len = strnlen(s, len);
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
- return len;
-}
-
-static int ata_dma_blacklisted(const struct ata_device *dev)
-{
- unsigned char model_num[40];
- unsigned char model_rev[16];
- unsigned int nlen, rlen;
- int i;
-
- /* We don't support polling DMA.
- * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
- * if the LLDD handles only interrupts in the HSM_ST_LAST state.
- */
- if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
- (dev->flags & ATA_DFLAG_CDB_INTR))
- return 1;
-
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
- sizeof(model_rev));
- nlen = ata_strim(model_num, sizeof(model_num));
- rlen = ata_strim(model_rev, sizeof(model_rev));
-
- for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) {
- if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) {
- if (ata_dma_blacklist[i+1] == NULL)
- return 1;
- if (!strncmp(ata_dma_blacklist[i], model_rev, rlen))
- return 1;
- }
- }
- return 0;
-}
-
-/**
- * ata_dev_xfermask - Compute supported xfermask of the given device
- * @dev: Device to compute xfermask for
- *
- * Compute supported xfermask of @dev and store it in
- * dev->*_mask. This function is responsible for applying all
- * known limits including host controller limits, device
- * blacklist, etc...
- *
- * FIXME: The current implementation limits all transfer modes to
- * the fastest of the lowested device on the port. This is not
- * required on most controllers.
- *
- * LOCKING:
- * None.
- */
-static void ata_dev_xfermask(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
- struct ata_host_set *hs = ap->host_set;
- unsigned long xfer_mask;
- int i;
-
- xfer_mask = ata_pack_xfermask(ap->pio_mask,
- ap->mwdma_mask, ap->udma_mask);
-
- /* Apply cable rule here. Don't apply it early because when
- * we handle hot plug the cable type can itself change.
- */
- if (ap->cbl == ATA_CBL_PATA40)
- xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
-
- /* FIXME: Use port-wide xfermask for now */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *d = &ap->device[i];
-
- if (ata_dev_absent(d))
- continue;
-
- if (ata_dev_disabled(d)) {
- /* to avoid violating device selection timing */
- xfer_mask &= ata_pack_xfermask(d->pio_mask,
- UINT_MAX, UINT_MAX);
- continue;
- }
-
- xfer_mask &= ata_pack_xfermask(d->pio_mask,
- d->mwdma_mask, d->udma_mask);
- xfer_mask &= ata_id_xfermask(d->id);
- if (ata_dma_blacklisted(d))
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- }
-
- if (ata_dma_blacklisted(dev))
- ata_dev_printk(dev, KERN_WARNING,
- "device is on DMA blacklist, disabling DMA\n");
-
- if (hs->flags & ATA_HOST_SIMPLEX) {
- if (hs->simplex_claimed)
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- }
-
- if (ap->ops->mode_filter)
- xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
-
- ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
- &dev->mwdma_mask, &dev->udma_mask);
-}
-
-/**
- * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
- * @dev: Device to which command will be sent
- *
- * Issue SET FEATURES - XFER MODE command to device @dev
- * on port @ap.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- * RETURNS:
- * 0 on success, AC_ERR_* mask otherwise.
- */
-
-static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
-{
- struct ata_taskfile tf;
- unsigned int err_mask;
-
- /* set up set-features taskfile */
- DPRINTK("set features - xfer mode\n");
-
- ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_SET_FEATURES;
- tf.feature = SETFEATURES_XFER;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
- tf.nsect = dev->xfer_mode;
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-
- DPRINTK("EXIT, err_mask=%x\n", err_mask);
- return err_mask;
-}
-
-/**
- * ata_dev_init_params - Issue INIT DEV PARAMS command
- * @dev: Device to which command will be sent
- * @heads: Number of heads (taskfile parameter)
- * @sectors: Number of sectors (taskfile parameter)
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * 0 on success, AC_ERR_* mask otherwise.
- */
-static unsigned int ata_dev_init_params(struct ata_device *dev,
- u16 heads, u16 sectors)
-{
- struct ata_taskfile tf;
- unsigned int err_mask;
-
- /* Number of sectors per track 1-255. Number of heads 1-16 */
- if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
- return AC_ERR_INVALID;
-
- /* set up init dev params taskfile */
- DPRINTK("init dev params \n");
-
- ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_INIT_DEV_PARAMS;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
- tf.nsect = sectors;
- tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-
- DPRINTK("EXIT, err_mask=%x\n", err_mask);
- return err_mask;
-}
-
-/**
- * ata_sg_clean - Unmap DMA memory associated with command
- * @qc: Command containing DMA memory to be released
- *
- * Unmap all mapped DMA memory associated with this command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_sg_clean(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg = qc->__sg;
- int dir = qc->dma_dir;
- void *pad_buf = NULL;
-
- WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
- WARN_ON(sg == NULL);
-
- if (qc->flags & ATA_QCFLAG_SINGLE)
- WARN_ON(qc->n_elem > 1);
-
- VPRINTK("unmapping %u sg elements\n", qc->n_elem);
-
- /* if we padded the buffer out to 32-bit bound, and data
- * xfer direction is from-device, we must copy from the
- * pad buffer back into the supplied buffer
- */
- if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
- pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
-
- if (qc->flags & ATA_QCFLAG_SG) {
- if (qc->n_elem)
- dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
- /* restore last sg */
- sg[qc->orig_n_elem - 1].length += qc->pad_len;
- if (pad_buf) {
- struct scatterlist *psg = &qc->pad_sgent;
- void *addr = kmap_atomic(psg->page, KM_IRQ0);
- memcpy(addr + psg->offset, pad_buf, qc->pad_len);
- kunmap_atomic(addr, KM_IRQ0);
- }
- } else {
- if (qc->n_elem)
- dma_unmap_single(ap->dev,
- sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
- dir);
- /* restore sg */
- sg->length += qc->pad_len;
- if (pad_buf)
- memcpy(qc->buf_virt + sg->length - qc->pad_len,
- pad_buf, qc->pad_len);
- }
-
- qc->flags &= ~ATA_QCFLAG_DMAMAP;
- qc->__sg = NULL;
-}
-
-/**
- * ata_fill_sg - Fill PCI IDE PRD table
- * @qc: Metadata associated with taskfile to be transferred
- *
- * Fill PCI IDE PRD (scatter-gather) table with segments
- * associated with the current disk command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- */
-static void ata_fill_sg(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg;
- unsigned int idx;
-
- WARN_ON(qc->__sg == NULL);
- WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
- idx = 0;
- ata_for_each_sg(sg, qc) {
- u32 addr, offset;
- u32 sg_len, len;
-
- /* determine if physical DMA addr spans 64K boundary.
- * Note h/w doesn't support 64-bit, so we unconditionally
- * truncate dma_addr_t to u32.
- */
- addr = (u32) sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & 0xffff;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
-
- ap->prd[idx].addr = cpu_to_le32(addr);
- ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
-
- idx++;
- sg_len -= len;
- addr += len;
- }
- }
-
- if (idx)
- ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
-}
-/**
- * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
- * @qc: Metadata associated with taskfile to check
- *
- * Allow low-level driver to filter ATA PACKET commands, returning
- * a status indicating whether or not it is OK to use DMA for the
- * supplied PACKET command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS: 0 when ATAPI DMA can be used
- * nonzero otherwise
- */
-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- int rc = 0; /* Assume ATAPI DMA is OK by default */
-
- if (ap->ops->check_atapi_dma)
- rc = ap->ops->check_atapi_dma(qc);
-
- return rc;
-}
-/**
- * ata_qc_prep - Prepare taskfile for submission
- * @qc: Metadata associated with taskfile to be prepared
- *
- * Prepare ATA taskfile for submission.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_qc_prep(struct ata_queued_cmd *qc)
-{
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
-
- ata_fill_sg(qc);
-}
-
-void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
-
-/**
- * ata_sg_init_one - Associate command with memory buffer
- * @qc: Command to be associated
- * @buf: Memory buffer
- * @buflen: Length of memory buffer, in bytes.
- *
- * Initialize the data-related elements of queued_cmd @qc
- * to point to a single memory buffer, @buf of byte length @buflen.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
-{
- struct scatterlist *sg;
-
- qc->flags |= ATA_QCFLAG_SINGLE;
-
- memset(&qc->sgent, 0, sizeof(qc->sgent));
- qc->__sg = &qc->sgent;
- qc->n_elem = 1;
- qc->orig_n_elem = 1;
- qc->buf_virt = buf;
- qc->nbytes = buflen;
-
- sg = qc->__sg;
- sg_init_one(sg, buf, buflen);
-}
-
-/**
- * ata_sg_init - Associate command with scatter-gather table.
- * @qc: Command to be associated
- * @sg: Scatter-gather table.
- * @n_elem: Number of elements in s/g table.
- *
- * Initialize the data-related elements of queued_cmd @qc
- * to point to a scatter-gather table @sg, containing @n_elem
- * elements.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
- unsigned int n_elem)
-{
- qc->flags |= ATA_QCFLAG_SG;
- qc->__sg = sg;
- qc->n_elem = n_elem;
- qc->orig_n_elem = n_elem;
-}
-
-/**
- * ata_sg_setup_one - DMA-map the memory buffer associated with a command.
- * @qc: Command with memory buffer to be mapped.
- *
- * DMA-map the memory buffer associated with queued_cmd @qc.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, negative on error.
- */
-
-static int ata_sg_setup_one(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- int dir = qc->dma_dir;
- struct scatterlist *sg = qc->__sg;
- dma_addr_t dma_address;
- int trim_sg = 0;
-
- /* we must lengthen transfers to end on a 32-bit boundary */
- qc->pad_len = sg->length & 3;
- if (qc->pad_len) {
- void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
- struct scatterlist *psg = &qc->pad_sgent;
-
- WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
-
- memset(pad_buf, 0, ATA_DMA_PAD_SZ);
-
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
- qc->pad_len);
-
- sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
- sg_dma_len(psg) = ATA_DMA_PAD_SZ;
- /* trim sg */
- sg->length -= qc->pad_len;
- if (sg->length == 0)
- trim_sg = 1;
-
- DPRINTK("padding done, sg->length=%u pad_len=%u\n",
- sg->length, qc->pad_len);
- }
-
- if (trim_sg) {
- qc->n_elem--;
- goto skip_map;
- }
-
- dma_address = dma_map_single(ap->dev, qc->buf_virt,
- sg->length, dir);
- if (dma_mapping_error(dma_address)) {
- /* restore sg */
- sg->length += qc->pad_len;
- return -1;
- }
-
- sg_dma_address(sg) = dma_address;
- sg_dma_len(sg) = sg->length;
-
-skip_map:
- DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
- qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
-
- return 0;
-}
-
-/**
- * ata_sg_setup - DMA-map the scatter-gather table associated with a command.
- * @qc: Command with scatter-gather table to be mapped.
- *
- * DMA-map the scatter-gather table associated with queued_cmd @qc.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, negative on error.
- *
- */
-
-static int ata_sg_setup(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scatterlist *sg = qc->__sg;
- struct scatterlist *lsg = &sg[qc->n_elem - 1];
- int n_elem, pre_n_elem, dir, trim_sg = 0;
-
- VPRINTK("ENTER, ata%u\n", ap->id);
- WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
-
- /* we must lengthen transfers to end on a 32-bit boundary */
- qc->pad_len = lsg->length & 3;
- if (qc->pad_len) {
- void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
- struct scatterlist *psg = &qc->pad_sgent;
- unsigned int offset;
-
- WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
-
- memset(pad_buf, 0, ATA_DMA_PAD_SZ);
-
- /*
- * psg->page/offset are used to copy to-be-written
- * data in this function or read data in ata_sg_clean.
- */
- offset = lsg->offset + lsg->length - qc->pad_len;
- psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
- psg->offset = offset_in_page(offset);
-
- if (qc->tf.flags & ATA_TFLAG_WRITE) {
- void *addr = kmap_atomic(psg->page, KM_IRQ0);
- memcpy(pad_buf, addr + psg->offset, qc->pad_len);
- kunmap_atomic(addr, KM_IRQ0);
- }
-
- sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
- sg_dma_len(psg) = ATA_DMA_PAD_SZ;
- /* trim last sg */
- lsg->length -= qc->pad_len;
- if (lsg->length == 0)
- trim_sg = 1;
-
- DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
- qc->n_elem - 1, lsg->length, qc->pad_len);
- }
-
- pre_n_elem = qc->n_elem;
- if (trim_sg && pre_n_elem)
- pre_n_elem--;
-
- if (!pre_n_elem) {
- n_elem = 0;
- goto skip_map;
- }
-
- dir = qc->dma_dir;
- n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
- if (n_elem < 1) {
- /* restore last sg */
- lsg->length += qc->pad_len;
- return -1;
- }
-
- DPRINTK("%d sg elements mapped\n", n_elem);
-
-skip_map:
- qc->n_elem = n_elem;
-
- return 0;
-}
-
-/**
- * swap_buf_le16 - swap halves of 16-bit words in place
- * @buf: Buffer to swap
- * @buf_words: Number of 16-bit words in buffer.
- *
- * Swap halves of 16-bit words if needed to convert from
- * little-endian byte order to native cpu byte order, or
- * vice-versa.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void swap_buf_le16(u16 *buf, unsigned int buf_words)
-{
-#ifdef __BIG_ENDIAN
- unsigned int i;
-
- for (i = 0; i < buf_words; i++)
- buf[i] = le16_to_cpu(buf[i]);
-#endif /* __BIG_ENDIAN */
-}
-
-/**
- * ata_mmio_data_xfer - Transfer data by MMIO
- * @adev: device for this I/O
- * @buf: data buffer
- * @buflen: buffer length
- * @write_data: read/write
- *
- * Transfer data from/to the device data register by MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- struct ata_port *ap = adev->ap;
- unsigned int i;
- unsigned int words = buflen >> 1;
- u16 *buf16 = (u16 *) buf;
- void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
-
- /* Transfer multiple of 2 bytes */
- if (write_data) {
- for (i = 0; i < words; i++)
- writew(le16_to_cpu(buf16[i]), mmio);
- } else {
- for (i = 0; i < words; i++)
- buf16[i] = cpu_to_le16(readw(mmio));
- }
-
- /* Transfer trailing 1 byte, if any. */
- if (unlikely(buflen & 0x01)) {
- u16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
-
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- writew(le16_to_cpu(align_buf[0]), mmio);
- } else {
- align_buf[0] = cpu_to_le16(readw(mmio));
- memcpy(trailing_buf, align_buf, 1);
- }
- }
-}
-
-/**
- * ata_pio_data_xfer - Transfer data by PIO
- * @adev: device to target
- * @buf: data buffer
- * @buflen: buffer length
- * @write_data: read/write
- *
- * Transfer data from/to the device data register by PIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- struct ata_port *ap = adev->ap;
- unsigned int words = buflen >> 1;
-
- /* Transfer multiple of 2 bytes */
- if (write_data)
- outsw(ap->ioaddr.data_addr, buf, words);
- else
- insw(ap->ioaddr.data_addr, buf, words);
-
- /* Transfer trailing 1 byte, if any. */
- if (unlikely(buflen & 0x01)) {
- u16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
-
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
- } else {
- align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
- memcpy(trailing_buf, align_buf, 1);
- }
- }
-}
-
-/**
- * ata_pio_data_xfer_noirq - Transfer data by PIO
- * @adev: device to target
- * @buf: data buffer
- * @buflen: buffer length
- * @write_data: read/write
- *
- * Transfer data from/to the device data register by PIO. Do the
- * transfer with interrupts disabled.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- unsigned long flags;
- local_irq_save(flags);
- ata_pio_data_xfer(adev, buf, buflen, write_data);
- local_irq_restore(flags);
-}
-
-
-/**
- * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
- * @qc: Command on going
- *
- * Transfer ATA_SECT_SIZE of data from/to the ATA device.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_pio_sector(struct ata_queued_cmd *qc)
-{
- int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
- struct scatterlist *sg = qc->__sg;
- struct ata_port *ap = qc->ap;
- struct page *page;
- unsigned int offset;
- unsigned char *buf;
-
- if (qc->cursect == (qc->nsect - 1))
- ap->hsm_task_state = HSM_ST_LAST;
-
- page = sg[qc->cursg].page;
- offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
-
- /* get the current page and offset */
- page = nth_page(page, (offset >> PAGE_SHIFT));
- offset %= PAGE_SIZE;
-
- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
-
- if (PageHighMem(page)) {
- unsigned long flags;
-
- /* FIXME: use a bounce buffer */
- local_irq_save(flags);
- buf = kmap_atomic(page, KM_IRQ0);
-
- /* do the actual data transfer */
- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
-
- kunmap_atomic(buf, KM_IRQ0);
- local_irq_restore(flags);
- } else {
- buf = page_address(page);
- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
- }
-
- qc->cursect++;
- qc->cursg_ofs++;
-
- if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
- qc->cursg++;
- qc->cursg_ofs = 0;
- }
-}
-
-/**
- * ata_pio_sectors - Transfer one or many 512-byte sectors.
- * @qc: Command on going
- *
- * Transfer one or many ATA_SECT_SIZE of data from/to the
- * ATA device for the DRQ request.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_pio_sectors(struct ata_queued_cmd *qc)
-{
- if (is_multi_taskfile(&qc->tf)) {
- /* READ/WRITE MULTIPLE */
- unsigned int nsect;
-
- WARN_ON(qc->dev->multi_count == 0);
-
- nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
- while (nsect--)
- ata_pio_sector(qc);
- } else
- ata_pio_sector(qc);
-}
-
-/**
- * atapi_send_cdb - Write CDB bytes to hardware
- * @ap: Port to which ATAPI device is attached.
- * @qc: Taskfile currently active
- *
- * When device has indicated its readiness to accept
- * a CDB, this function is called. Send the CDB.
- *
- * LOCKING:
- * caller.
- */
-
-static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
-{
- /* send SCSI cdb */
- DPRINTK("send cdb\n");
- WARN_ON(qc->dev->cdb_len < 12);
-
- ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
- ata_altstatus(ap); /* flush */
-
- switch (qc->tf.protocol) {
- case ATA_PROT_ATAPI:
- ap->hsm_task_state = HSM_ST;
- break;
- case ATA_PROT_ATAPI_NODATA:
- ap->hsm_task_state = HSM_ST_LAST;
- break;
- case ATA_PROT_ATAPI_DMA:
- ap->hsm_task_state = HSM_ST_LAST;
- /* initiate bmdma */
- ap->ops->bmdma_start(qc);
- break;
- }
-}
-
-/**
- * __atapi_pio_bytes - Transfer data from/to the ATAPI device.
- * @qc: Command on going
- * @bytes: number of bytes
- *
- * Transfer Transfer data from/to the ATAPI device.
- *
- * LOCKING:
- * Inherited from caller.
- *
- */
-
-static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
-{
- int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
- struct scatterlist *sg = qc->__sg;
- struct ata_port *ap = qc->ap;
- struct page *page;
- unsigned char *buf;
- unsigned int offset, count;
-
- if (qc->curbytes + bytes >= qc->nbytes)
- ap->hsm_task_state = HSM_ST_LAST;
-
-next_sg:
- if (unlikely(qc->cursg >= qc->n_elem)) {
- /*
- * The end of qc->sg is reached and the device expects
- * more data to transfer. In order not to overrun qc->sg
- * and fulfill length specified in the byte count register,
- * - for read case, discard trailing data from the device
- * - for write case, padding zero data to the device
- */
- u16 pad_buf[1] = { 0 };
- unsigned int words = bytes >> 1;
- unsigned int i;
-
- if (words) /* warning if bytes > 1 */
- ata_dev_printk(qc->dev, KERN_WARNING,
- "%u bytes trailing data\n", bytes);
-
- for (i = 0; i < words; i++)
- ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
-
- ap->hsm_task_state = HSM_ST_LAST;
- return;
- }
-
- sg = &qc->__sg[qc->cursg];
-
- page = sg->page;
- offset = sg->offset + qc->cursg_ofs;
-
- /* get the current page and offset */
- page = nth_page(page, (offset >> PAGE_SHIFT));
- offset %= PAGE_SIZE;
-
- /* don't overrun current sg */
- count = min(sg->length - qc->cursg_ofs, bytes);
-
- /* don't cross page boundaries */
- count = min(count, (unsigned int)PAGE_SIZE - offset);
-
- DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
-
- if (PageHighMem(page)) {
- unsigned long flags;
-
- /* FIXME: use bounce buffer */
- local_irq_save(flags);
- buf = kmap_atomic(page, KM_IRQ0);
-
- /* do the actual data transfer */
- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
-
- kunmap_atomic(buf, KM_IRQ0);
- local_irq_restore(flags);
- } else {
- buf = page_address(page);
- ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
- }
-
- bytes -= count;
- qc->curbytes += count;
- qc->cursg_ofs += count;
-
- if (qc->cursg_ofs == sg->length) {
- qc->cursg++;
- qc->cursg_ofs = 0;
- }
-
- if (bytes)
- goto next_sg;
-}
-
-/**
- * atapi_pio_bytes - Transfer data from/to the ATAPI device.
- * @qc: Command on going
- *
- * Transfer Transfer data from/to the ATAPI device.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void atapi_pio_bytes(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_device *dev = qc->dev;
- unsigned int ireason, bc_lo, bc_hi, bytes;
- int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
-
- /* Abuse qc->result_tf for temp storage of intermediate TF
- * here to save some kernel stack usage.
- * For normal completion, qc->result_tf is not relevant. For
- * error, qc->result_tf is later overwritten by ata_qc_complete().
- * So, the correctness of qc->result_tf is not affected.
- */
- ap->ops->tf_read(ap, &qc->result_tf);
- ireason = qc->result_tf.nsect;
- bc_lo = qc->result_tf.lbam;
- bc_hi = qc->result_tf.lbah;
- bytes = (bc_hi << 8) | bc_lo;
-
- /* shall be cleared to zero, indicating xfer of data */
- if (ireason & (1 << 0))
- goto err_out;
-
- /* make sure transfer direction matches expected */
- i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
- if (do_write != i_write)
- goto err_out;
-
- VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
-
- __atapi_pio_bytes(qc, bytes);
-
- return;
-
-err_out:
- ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
- qc->err_mask |= AC_ERR_HSM;
- ap->hsm_task_state = HSM_ST_ERR;
-}
-
-/**
- * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
- * @ap: the target ata_port
- * @qc: qc on going
- *
- * RETURNS:
- * 1 if ok in workqueue, 0 otherwise.
- */
-
-static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
-{
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- return 1;
-
- if (ap->hsm_task_state == HSM_ST_FIRST) {
- if (qc->tf.protocol == ATA_PROT_PIO &&
- (qc->tf.flags & ATA_TFLAG_WRITE))
- return 1;
-
- if (is_atapi_taskfile(&qc->tf) &&
- !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- return 1;
- }
-
- return 0;
-}
-
-/**
- * ata_hsm_qc_complete - finish a qc running on standard HSM
- * @qc: Command to complete
- * @in_wq: 1 if called from workqueue, 0 otherwise
- *
- * Finish @qc which is running on standard HSM.
- *
- * LOCKING:
- * If @in_wq is zero, spin_lock_irqsave(host_set lock).
- * Otherwise, none on entry and grabs host lock.
- */
-static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
-{
- struct ata_port *ap = qc->ap;
- unsigned long flags;
-
- if (ap->ops->error_handler) {
- if (in_wq) {
- spin_lock_irqsave(ap->lock, flags);
-
- /* EH might have kicked in while host_set lock
- * is released.
- */
- qc = ata_qc_from_tag(ap, qc->tag);
- if (qc) {
- if (likely(!(qc->err_mask & AC_ERR_HSM))) {
- ata_irq_on(ap);
- ata_qc_complete(qc);
- } else
- ata_port_freeze(ap);
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
- } else {
- if (likely(!(qc->err_mask & AC_ERR_HSM)))
- ata_qc_complete(qc);
- else
- ata_port_freeze(ap);
- }
- } else {
- if (in_wq) {
- spin_lock_irqsave(ap->lock, flags);
- ata_irq_on(ap);
- ata_qc_complete(qc);
- spin_unlock_irqrestore(ap->lock, flags);
- } else
- ata_qc_complete(qc);
- }
-
- ata_altstatus(ap); /* flush */
-}
-
-/**
- * ata_hsm_move - move the HSM to the next state.
- * @ap: the target ata_port
- * @qc: qc on going
- * @status: current device status
- * @in_wq: 1 if called from workqueue, 0 otherwise
- *
- * RETURNS:
- * 1 when poll next status needed, 0 otherwise.
- */
-int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
- u8 status, int in_wq)
-{
- unsigned long flags = 0;
- int poll_next;
-
- WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
-
- /* Make sure ata_qc_issue_prot() does not throw things
- * like DMA polling into the workqueue. Notice that
- * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
- */
- WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
-
-fsm_start:
- DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, ap->hsm_task_state, status);
-
- switch (ap->hsm_task_state) {
- case HSM_ST_FIRST:
- /* Send first data block or PACKET CDB */
-
- /* If polling, we will stay in the work queue after
- * sending the data. Otherwise, interrupt handler
- * takes over after sending the data.
- */
- poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
-
- /* check device status */
- if (unlikely((status & ATA_DRQ) == 0)) {
- /* handle BSY=0, DRQ=0 as error */
- if (likely(status & (ATA_ERR | ATA_DF)))
- /* device stops HSM for abort/error */
- qc->err_mask |= AC_ERR_DEV;
- else
- /* HSM violation. Let EH handle this */
- qc->err_mask |= AC_ERR_HSM;
-
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- /* Device should not ask for data transfer (DRQ=1)
- * when it finds something wrong.
- * We ignore DRQ here and stop the HSM by
- * changing hsm_task_state to HSM_ST_ERR and
- * let the EH abort the command or reset the device.
- */
- if (unlikely(status & (ATA_ERR | ATA_DF))) {
- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
- ap->id, status);
- qc->err_mask |= AC_ERR_HSM;
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- /* Send the CDB (atapi) or the first data block (ata pio out).
- * During the state transition, interrupt handler shouldn't
- * be invoked before the data transfer is complete and
- * hsm_task_state is changed. Hence, the following locking.
- */
- if (in_wq)
- spin_lock_irqsave(ap->lock, flags);
-
- if (qc->tf.protocol == ATA_PROT_PIO) {
- /* PIO data out protocol.
- * send first data block.
- */
-
- /* ata_pio_sectors() might change the state
- * to HSM_ST_LAST. so, the state is changed here
- * before ata_pio_sectors().
- */
- ap->hsm_task_state = HSM_ST;
- ata_pio_sectors(qc);
- ata_altstatus(ap); /* flush */
- } else
- /* send CDB */
- atapi_send_cdb(ap, qc);
-
- if (in_wq)
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* if polling, ata_pio_task() handles the rest.
- * otherwise, interrupt handler takes over from here.
- */
- break;
-
- case HSM_ST:
- /* complete command or read/write the data register */
- if (qc->tf.protocol == ATA_PROT_ATAPI) {
- /* ATAPI PIO protocol */
- if ((status & ATA_DRQ) == 0) {
- /* No more data to transfer or device error.
- * Device error will be tagged in HSM_ST_LAST.
- */
- ap->hsm_task_state = HSM_ST_LAST;
- goto fsm_start;
- }
-
- /* Device should not ask for data transfer (DRQ=1)
- * when it finds something wrong.
- * We ignore DRQ here and stop the HSM by
- * changing hsm_task_state to HSM_ST_ERR and
- * let the EH abort the command or reset the device.
- */
- if (unlikely(status & (ATA_ERR | ATA_DF))) {
- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
- ap->id, status);
- qc->err_mask |= AC_ERR_HSM;
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- atapi_pio_bytes(qc);
-
- if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
- /* bad ireason reported by device */
- goto fsm_start;
-
- } else {
- /* ATA PIO protocol */
- if (unlikely((status & ATA_DRQ) == 0)) {
- /* handle BSY=0, DRQ=0 as error */
- if (likely(status & (ATA_ERR | ATA_DF)))
- /* device stops HSM for abort/error */
- qc->err_mask |= AC_ERR_DEV;
- else
- /* HSM violation. Let EH handle this */
- qc->err_mask |= AC_ERR_HSM;
-
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- /* For PIO reads, some devices may ask for
- * data transfer (DRQ=1) alone with ERR=1.
- * We respect DRQ here and transfer one
- * block of junk data before changing the
- * hsm_task_state to HSM_ST_ERR.
- *
- * For PIO writes, ERR=1 DRQ=1 doesn't make
- * sense since the data block has been
- * transferred to the device.
- */
- if (unlikely(status & (ATA_ERR | ATA_DF))) {
- /* data might be corrputed */
- qc->err_mask |= AC_ERR_DEV;
-
- if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
- ata_pio_sectors(qc);
- ata_altstatus(ap);
- status = ata_wait_idle(ap);
- }
-
- if (status & (ATA_BUSY | ATA_DRQ))
- qc->err_mask |= AC_ERR_HSM;
-
- /* ata_pio_sectors() might change the
- * state to HSM_ST_LAST. so, the state
- * is changed after ata_pio_sectors().
- */
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- ata_pio_sectors(qc);
-
- if (ap->hsm_task_state == HSM_ST_LAST &&
- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
- /* all data read */
- ata_altstatus(ap);
- status = ata_wait_idle(ap);
- goto fsm_start;
- }
- }
-
- ata_altstatus(ap); /* flush */
- poll_next = 1;
- break;
-
- case HSM_ST_LAST:
- if (unlikely(!ata_ok(status))) {
- qc->err_mask |= __ac_err_mask(status);
- ap->hsm_task_state = HSM_ST_ERR;
- goto fsm_start;
- }
-
- /* no more data to transfer */
- DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
- ap->id, qc->dev->devno, status);
-
- WARN_ON(qc->err_mask);
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- /* complete taskfile transaction */
- ata_hsm_qc_complete(qc, in_wq);
-
- poll_next = 0;
- break;
-
- case HSM_ST_ERR:
- /* make sure qc->err_mask is available to
- * know what's wrong and recover
- */
- WARN_ON(qc->err_mask == 0);
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- /* complete taskfile transaction */
- ata_hsm_qc_complete(qc, in_wq);
-
- poll_next = 0;
- break;
- default:
- poll_next = 0;
- BUG();
- }
-
- return poll_next;
-}
-
-static void ata_pio_task(void *_data)
-{
- struct ata_queued_cmd *qc = _data;
- struct ata_port *ap = qc->ap;
- u8 status;
- int poll_next;
-
-fsm_start:
- WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
-
- /*
- * This is purely heuristic. This is a fast path.
- * Sometimes when we enter, BSY will be cleared in
- * a chk-status or two. If not, the drive is probably seeking
- * or something. Snooze for a couple msecs, then
- * chk-status again. If still busy, queue delayed work.
- */
- status = ata_busy_wait(ap, ATA_BUSY, 5);
- if (status & ATA_BUSY) {
- msleep(2);
- status = ata_busy_wait(ap, ATA_BUSY, 10);
- if (status & ATA_BUSY) {
- ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
- return;
- }
- }
-
- /* move the HSM */
- poll_next = ata_hsm_move(ap, qc, status, 1);
-
- /* another command or interrupt handler
- * may be running at this point.
- */
- if (poll_next)
- goto fsm_start;
-}
-
-/**
- * ata_qc_new - Request an available ATA command, for queueing
- * @ap: Port associated with device @dev
- * @dev: Device from whom we request an available command structure
- *
- * LOCKING:
- * None.
- */
-
-static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
-{
- struct ata_queued_cmd *qc = NULL;
- unsigned int i;
-
- /* no command while frozen */
- if (unlikely(ap->flags & ATA_FLAG_FROZEN))
- return NULL;
-
- /* the last tag is reserved for internal command. */
- for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
- if (!test_and_set_bit(i, &ap->qc_allocated)) {
- qc = __ata_qc_from_tag(ap, i);
- break;
- }
-
- if (qc)
- qc->tag = i;
-
- return qc;
-}
-
-/**
- * ata_qc_new_init - Request an available ATA command, and initialize it
- * @dev: Device from whom we request an available command structure
- *
- * LOCKING:
- * None.
- */
-
-struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_new(ap);
- if (qc) {
- qc->scsicmd = NULL;
- qc->ap = ap;
- qc->dev = dev;
-
- ata_qc_reinit(qc);
- }
-
- return qc;
-}
-
-/**
- * ata_qc_free - free unused ata_queued_cmd
- * @qc: Command to complete
- *
- * Designed to free unused ata_queued_cmd object
- * in case something prevents using it.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_qc_free(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int tag;
-
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
-
- qc->flags = 0;
- tag = qc->tag;
- if (likely(ata_tag_valid(tag))) {
- qc->tag = ATA_TAG_POISON;
- clear_bit(tag, &ap->qc_allocated);
- }
-}
-
-void __ata_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
-
- if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
- ata_sg_clean(qc);
-
- /* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
- ap->sactive &= ~(1 << qc->tag);
- else
- ap->active_tag = ATA_TAG_POISON;
-
- /* atapi: mark qc as inactive to prevent the interrupt handler
- * from completing the command twice later, before the error handler
- * is called. (when rc != 0 and atapi request sense is needed)
- */
- qc->flags &= ~ATA_QCFLAG_ACTIVE;
- ap->qc_active &= ~(1 << qc->tag);
-
- /* call completion callback */
- qc->complete_fn(qc);
-}
-
-/**
- * ata_qc_complete - Complete an active ATA command
- * @qc: Command to complete
- * @err_mask: ATA Status register contents
- *
- * Indicate to the mid and upper layers that an ATA
- * command has completed, with either an ok or not-ok status.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- /* XXX: New EH and old EH use different mechanisms to
- * synchronize EH with regular execution path.
- *
- * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
- * Normal execution path is responsible for not accessing a
- * failed qc. libata core enforces the rule by returning NULL
- * from ata_qc_from_tag() for failed qcs.
- *
- * Old EH depends on ata_qc_complete() nullifying completion
- * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
- * not synchronize with interrupt handler. Only PIO task is
- * taken care of.
- */
- if (ap->ops->error_handler) {
- WARN_ON(ap->flags & ATA_FLAG_FROZEN);
-
- if (unlikely(qc->err_mask))
- qc->flags |= ATA_QCFLAG_FAILED;
-
- if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
- if (!ata_tag_internal(qc->tag)) {
- /* always fill result TF for failed qc */
- ap->ops->tf_read(ap, &qc->result_tf);
- ata_qc_schedule_eh(qc);
- return;
- }
- }
-
- /* read result TF if requested */
- if (qc->flags & ATA_QCFLAG_RESULT_TF)
- ap->ops->tf_read(ap, &qc->result_tf);
-
- __ata_qc_complete(qc);
- } else {
- if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
- return;
-
- /* read result TF if failed or requested */
- if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
- ap->ops->tf_read(ap, &qc->result_tf);
-
- __ata_qc_complete(qc);
- }
-}
-
-/**
- * ata_qc_complete_multiple - Complete multiple qcs successfully
- * @ap: port in question
- * @qc_active: new qc_active mask
- * @finish_qc: LLDD callback invoked before completing a qc
- *
- * Complete in-flight commands. This functions is meant to be
- * called from low-level driver's interrupt routine to complete
- * requests normally. ap->qc_active and @qc_active is compared
- * and commands are completed accordingly.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Number of completed commands on success, -errno otherwise.
- */
-int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
- void (*finish_qc)(struct ata_queued_cmd *))
-{
- int nr_done = 0;
- u32 done_mask;
- int i;
-
- done_mask = ap->qc_active ^ qc_active;
-
- if (unlikely(done_mask & qc_active)) {
- ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
- "(%08x->%08x)\n", ap->qc_active, qc_active);
- return -EINVAL;
- }
-
- for (i = 0; i < ATA_MAX_QUEUE; i++) {
- struct ata_queued_cmd *qc;
-
- if (!(done_mask & (1 << i)))
- continue;
-
- if ((qc = ata_qc_from_tag(ap, i))) {
- if (finish_qc)
- finish_qc(qc);
- ata_qc_complete(qc);
- nr_done++;
- }
- }
-
- return nr_done;
-}
-
-static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- switch (qc->tf.protocol) {
- case ATA_PROT_NCQ:
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- return 1;
-
- case ATA_PROT_ATAPI:
- case ATA_PROT_PIO:
- if (ap->flags & ATA_FLAG_PIO_DMA)
- return 1;
-
- /* fall through */
-
- default:
- return 0;
- }
-
- /* never reached */
-}
-
-/**
- * ata_qc_issue - issue taskfile to device
- * @qc: command to issue to device
- *
- * Prepare an ATA command to submission to device.
- * This includes mapping the data into a DMA-able
- * area, filling in the S/G table, and finally
- * writing the taskfile to hardware, starting the command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- /* Make sure only one non-NCQ command is outstanding. The
- * check is skipped for old EH because it reuses active qc to
- * request ATAPI sense.
- */
- WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
-
- if (qc->tf.protocol == ATA_PROT_NCQ) {
- WARN_ON(ap->sactive & (1 << qc->tag));
- ap->sactive |= 1 << qc->tag;
- } else {
- WARN_ON(ap->sactive);
- ap->active_tag = qc->tag;
- }
-
- qc->flags |= ATA_QCFLAG_ACTIVE;
- ap->qc_active |= 1 << qc->tag;
-
- if (ata_should_dma_map(qc)) {
- if (qc->flags & ATA_QCFLAG_SG) {
- if (ata_sg_setup(qc))
- goto sg_err;
- } else if (qc->flags & ATA_QCFLAG_SINGLE) {
- if (ata_sg_setup_one(qc))
- goto sg_err;
- }
- } else {
- qc->flags &= ~ATA_QCFLAG_DMAMAP;
- }
-
- ap->ops->qc_prep(qc);
-
- qc->err_mask |= ap->ops->qc_issue(qc);
- if (unlikely(qc->err_mask))
- goto err;
- return;
-
-sg_err:
- qc->flags &= ~ATA_QCFLAG_DMAMAP;
- qc->err_mask |= AC_ERR_SYSTEM;
-err:
- ata_qc_complete(qc);
-}
-
-/**
- * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
- * @qc: command to issue to device
- *
- * Using various libata functions and hooks, this function
- * starts an ATA command. ATA commands are grouped into
- * classes called "protocols", and issuing each type of protocol
- * is slightly different.
- *
- * May be used as the qc_issue() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, AC_ERR_* mask on failure
- */
-
-unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- /* Use polling pio if the LLD doesn't handle
- * interrupt driven pio and atapi CDB interrupt.
- */
- if (ap->flags & ATA_FLAG_PIO_POLLING) {
- switch (qc->tf.protocol) {
- case ATA_PROT_PIO:
- case ATA_PROT_ATAPI:
- case ATA_PROT_ATAPI_NODATA:
- qc->tf.flags |= ATA_TFLAG_POLLING;
- break;
- case ATA_PROT_ATAPI_DMA:
- if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
- /* see ata_dma_blacklisted() */
- BUG();
- break;
- default:
- break;
- }
- }
-
- /* select the device */
- ata_dev_select(ap, qc->dev->devno, 1, 0);
-
- /* start the command */
- switch (qc->tf.protocol) {
- case ATA_PROT_NODATA:
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_qc_set_polling(qc);
-
- ata_tf_to_host(ap, &qc->tf);
- ap->hsm_task_state = HSM_ST_LAST;
-
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_port_queue_task(ap, ata_pio_task, qc, 0);
-
- break;
-
- case ATA_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
-
- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
- ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- ap->hsm_task_state = HSM_ST_LAST;
- break;
-
- case ATA_PROT_PIO:
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_qc_set_polling(qc);
-
- ata_tf_to_host(ap, &qc->tf);
-
- if (qc->tf.flags & ATA_TFLAG_WRITE) {
- /* PIO data out protocol */
- ap->hsm_task_state = HSM_ST_FIRST;
- ata_port_queue_task(ap, ata_pio_task, qc, 0);
-
- /* always send first data block using
- * the ata_pio_task() codepath.
- */
- } else {
- /* PIO data in protocol */
- ap->hsm_task_state = HSM_ST;
-
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_port_queue_task(ap, ata_pio_task, qc, 0);
-
- /* if polling, ata_pio_task() handles the rest.
- * otherwise, interrupt handler takes over from here.
- */
- }
-
- break;
-
- case ATA_PROT_ATAPI:
- case ATA_PROT_ATAPI_NODATA:
- if (qc->tf.flags & ATA_TFLAG_POLLING)
- ata_qc_set_polling(qc);
-
- ata_tf_to_host(ap, &qc->tf);
-
- ap->hsm_task_state = HSM_ST_FIRST;
-
- /* send cdb by polling if no cdb interrupt */
- if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
- (qc->tf.flags & ATA_TFLAG_POLLING))
- ata_port_queue_task(ap, ata_pio_task, qc, 0);
- break;
-
- case ATA_PROT_ATAPI_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
-
- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
- ap->ops->bmdma_setup(qc); /* set up bmdma */
- ap->hsm_task_state = HSM_ST_FIRST;
-
- /* send cdb by polling if no cdb interrupt */
- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- ata_port_queue_task(ap, ata_pio_task, qc, 0);
- break;
-
- default:
- WARN_ON(1);
- return AC_ERR_SYSTEM;
- }
-
- return 0;
-}
-
-/**
- * ata_host_intr - Handle host interrupt for given (port, task)
- * @ap: Port on which interrupt arrived (possibly...)
- * @qc: Taskfile currently active in engine
- *
- * Handle host interrupt for given queued command. Currently,
- * only DMA interrupts are handled. All other commands are
- * handled via polling with interrupts disabled (nIEN bit).
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * One if interrupt was handled, zero if not (shared irq).
- */
-
-inline unsigned int ata_host_intr (struct ata_port *ap,
- struct ata_queued_cmd *qc)
-{
- u8 status, host_stat = 0;
-
- VPRINTK("ata%u: protocol %d task_state %d\n",
- ap->id, qc->tf.protocol, ap->hsm_task_state);
-
- /* Check whether we are expecting interrupt in this state */
- switch (ap->hsm_task_state) {
- case HSM_ST_FIRST:
- /* Some pre-ATAPI-4 devices assert INTRQ
- * at this state when ready to receive CDB.
- */
-
- /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
- * The flag was turned on only for atapi devices.
- * No need to check is_atapi_taskfile(&qc->tf) again.
- */
- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- goto idle_irq;
- break;
- case HSM_ST_LAST:
- if (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
- /* check status of DMA engine */
- host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
-
- /* if it's not our irq... */
- if (!(host_stat & ATA_DMA_INTR))
- goto idle_irq;
-
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
-
- if (unlikely(host_stat & ATA_DMA_ERR)) {
- /* error when transfering data to/from memory */
- qc->err_mask |= AC_ERR_HOST_BUS;
- ap->hsm_task_state = HSM_ST_ERR;
- }
- }
- break;
- case HSM_ST:
- break;
- default:
- goto idle_irq;
- }
-
- /* check altstatus */
- status = ata_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
-
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto idle_irq;
-
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
-
- ata_hsm_move(ap, qc, status, 0);
- return 1; /* irq handled */
-
-idle_irq:
- ap->stats.idle_irq++;
-
-#ifdef ATA_IRQ_TRAP
- if ((ap->stats.idle_irq % 1000) == 0) {
- ata_irq_ack(ap, 0); /* debug trap */
- ata_port_printk(ap, KERN_WARNING, "irq trap\n");
- return 1;
- }
-#endif
- return 0; /* irq not handled */
-}
-
-/**
- * ata_interrupt - Default ATA host interrupt handler
- * @irq: irq line (unused)
- * @dev_instance: pointer to our ata_host_set information structure
- * @regs: unused
- *
- * Default interrupt handler for PCI IDE devices. Calls
- * ata_host_intr() for each port that is not disabled.
- *
- * LOCKING:
- * Obtains host_set lock during operation.
- *
- * RETURNS:
- * IRQ_NONE or IRQ_HANDLED.
- */
-
-irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int i;
- unsigned int handled = 0;
- unsigned long flags;
-
- /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
- spin_lock_irqsave(&host_set->lock, flags);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap;
-
- ap = host_set->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
- (qc->flags & ATA_QCFLAG_ACTIVE))
- handled |= ata_host_intr(ap, qc);
- }
- }
-
- spin_unlock_irqrestore(&host_set->lock, flags);
-
- return IRQ_RETVAL(handled);
-}
-
-/**
- * sata_scr_valid - test whether SCRs are accessible
- * @ap: ATA port to test SCR accessibility for
- *
- * Test whether SCRs are accessible for @ap.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if SCRs are accessible, 0 otherwise.
- */
-int sata_scr_valid(struct ata_port *ap)
-{
- return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
-}
-
-/**
- * sata_scr_read - read SCR register of the specified port
- * @ap: ATA port to read SCR for
- * @reg: SCR to read
- * @val: Place to store read value
- *
- * Read SCR register @reg of @ap into *@val. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
-{
- if (sata_scr_valid(ap)) {
- *val = ap->ops->scr_read(ap, reg);
- return 0;
- }
- return -EOPNOTSUPP;
-}
-
-/**
- * sata_scr_write - write SCR register of the specified port
- * @ap: ATA port to write SCR for
- * @reg: SCR to write
- * @val: value to write
- *
- * Write @val to SCR register @reg of @ap. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
-{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- return 0;
- }
- return -EOPNOTSUPP;
-}
-
-/**
- * sata_scr_write_flush - write SCR register of the specified port and flush
- * @ap: ATA port to write SCR for
- * @reg: SCR to write
- * @val: value to write
- *
- * This function is identical to sata_scr_write() except that this
- * function performs flush after writing to the register.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 0 on success, negative errno on failure.
- */
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
-{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- ap->ops->scr_read(ap, reg);
- return 0;
- }
- return -EOPNOTSUPP;
-}
-
-/**
- * ata_port_online - test whether the given port is online
- * @ap: ATA port to test
- *
- * Test whether @ap is online. Note that this function returns 0
- * if online status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if the port online status is available and online.
- */
-int ata_port_online(struct ata_port *ap)
-{
- u32 sstatus;
-
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
- return 1;
- return 0;
-}
-
-/**
- * ata_port_offline - test whether the given port is offline
- * @ap: ATA port to test
- *
- * Test whether @ap is offline. Note that this function returns
- * 0 if offline status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * 1 if the port offline status is available and offline.
- */
-int ata_port_offline(struct ata_port *ap)
-{
- u32 sstatus;
-
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
- return 1;
- return 0;
-}
-
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
- struct ata_taskfile tf;
- int err;
-
- ata_tf_init(dev, &tf);
-
- tf.command = cmd;
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
- __FUNCTION__, err);
-
- return err;
-}
-
-static int ata_flush_cache(struct ata_device *dev)
-{
- u8 cmd;
-
- if (!ata_try_flush_cache(dev))
- return 0;
-
- if (ata_id_has_flush_ext(dev->id))
- cmd = ATA_CMD_FLUSH_EXT;
- else
- cmd = ATA_CMD_FLUSH;
-
- return ata_do_simple_cmd(dev, cmd);
-}
-
-static int ata_standby_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
-}
-
-static int ata_start_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
-}
-
-/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
- *
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
- *
- */
-int ata_device_resume(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
-
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
-
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
-
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
- }
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
-
- return 0;
-}
-
-/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
- *
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
- */
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
-{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
- return 0;
-}
-
-/**
- * ata_port_start - Set port up for dma.
- * @ap: Port to initialize
- *
- * Called just after data structures for each port are
- * initialized. Allocates space for PRD table.
- *
- * May be used as the port_start() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-int ata_port_start (struct ata_port *ap)
-{
- struct device *dev = ap->dev;
- int rc;
-
- ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
- if (!ap->prd)
- return -ENOMEM;
-
- rc = ata_pad_alloc(ap, dev);
- if (rc) {
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
- return rc;
- }
-
- DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
-
- return 0;
-}
-
-
-/**
- * ata_port_stop - Undo ata_port_start()
- * @ap: Port to shut down
- *
- * Frees the PRD table.
- *
- * May be used as the port_stop() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_port_stop (struct ata_port *ap)
-{
- struct device *dev = ap->dev;
-
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
- ata_pad_free(ap, dev);
-}
-
-void ata_host_stop (struct ata_host_set *host_set)
-{
- if (host_set->mmio_base)
- iounmap(host_set->mmio_base);
-}
-
-
-/**
- * ata_host_remove - Unregister SCSI host structure with upper layers
- * @ap: Port to unregister
- * @do_unregister: 1 if we fully unregister, 0 to just stop the port
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
-{
- struct Scsi_Host *sh = ap->host;
-
- DPRINTK("ENTER\n");
-
- if (do_unregister)
- scsi_remove_host(sh);
-
- ap->ops->port_stop(ap);
-}
-
-/**
- * ata_dev_init - Initialize an ata_device structure
- * @dev: Device structure to initialize
- *
- * Initialize @dev in preparation for probing.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_dev_init(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
- unsigned long flags;
-
- /* SATA spd limit is bound to the first device */
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
- /* High bits of dev->flags are used to record warm plug
- * requests which occur asynchronously. Synchronize using
- * host_set lock.
- */
- spin_lock_irqsave(ap->lock, flags);
- dev->flags &= ~ATA_DFLAG_INIT_MASK;
- spin_unlock_irqrestore(ap->lock, flags);
-
- memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
- sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
- dev->pio_mask = UINT_MAX;
- dev->mwdma_mask = UINT_MAX;
- dev->udma_mask = UINT_MAX;
-}
-
-/**
- * ata_host_init - Initialize an ata_port structure
- * @ap: Structure to initialize
- * @host: associated SCSI mid-layer structure
- * @host_set: Collection of hosts to which @ap belongs
- * @ent: Probe information provided by low-level driver
- * @port_no: Port number associated with this ata_port
- *
- * Initialize a new ata_port structure, and its associated
- * scsi_host.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
- struct ata_host_set *host_set,
- const struct ata_probe_ent *ent, unsigned int port_no)
-{
- unsigned int i;
-
- host->max_id = 16;
- host->max_lun = 1;
- host->max_channel = 1;
- host->unique_id = ata_unique_id++;
- host->max_cmd_len = 12;
-
- ap->lock = &host_set->lock;
- ap->flags = ATA_FLAG_DISABLED;
- ap->id = host->unique_id;
- ap->host = host;
- ap->ctl = ATA_DEVCTL_OBS;
- ap->host_set = host_set;
- ap->dev = ent->dev;
- ap->port_no = port_no;
- ap->hard_port_no =
- ent->legacy_mode ? ent->hard_port_no : port_no;
- ap->pio_mask = ent->pio_mask;
- ap->mwdma_mask = ent->mwdma_mask;
- ap->udma_mask = ent->udma_mask;
- ap->flags |= ent->host_flags;
- ap->ops = ent->port_ops;
- ap->hw_sata_spd_limit = UINT_MAX;
- ap->active_tag = ATA_TAG_POISON;
- ap->last_ctl = 0xFF;
-
-#if defined(ATA_VERBOSE_DEBUG)
- /* turn on all debugging levels */
- ap->msg_enable = 0x00FF;
-#elif defined(ATA_DEBUG)
- ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
-#else
- ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
-#endif
-
- INIT_WORK(&ap->port_task, NULL, NULL);
- INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
- INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
- INIT_LIST_HEAD(&ap->eh_done_q);
- init_waitqueue_head(&ap->eh_wait_q);
-
- /* set cable type */
- ap->cbl = ATA_CBL_NONE;
- if (ap->flags & ATA_FLAG_SATA)
- ap->cbl = ATA_CBL_SATA;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- dev->ap = ap;
- dev->devno = i;
- ata_dev_init(dev);
- }
-
-#ifdef ATA_IRQ_TRAP
- ap->stats.unhandled_irq = 1;
- ap->stats.idle_irq = 1;
-#endif
-
- memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
-}
-
-/**
- * ata_host_add - Attach low-level ATA driver to system
- * @ent: Information provided by low-level driver
- * @host_set: Collections of ports to which we add
- * @port_no: Port number associated with this host
- *
- * Attach low-level ATA driver to system.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- * RETURNS:
- * New ata_port on success, for NULL on error.
- */
-
-static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
- struct ata_host_set *host_set,
- unsigned int port_no)
-{
- struct Scsi_Host *host;
- struct ata_port *ap;
- int rc;
-
- DPRINTK("ENTER\n");
-
- if (!ent->port_ops->error_handler &&
- !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
- printk(KERN_ERR "ata%u: no reset mechanism available\n",
- port_no);
- return NULL;
- }
-
- host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
- if (!host)
- return NULL;
-
- host->transportt = &ata_scsi_transport_template;
-
- ap = ata_shost_to_port(host);
-
- ata_host_init(ap, host, host_set, ent, port_no);
-
- rc = ap->ops->port_start(ap);
- if (rc)
- goto err_out;
-
- return ap;
-
-err_out:
- scsi_host_put(host);
- return NULL;
-}
-
-/**
- * ata_device_add - Register hardware device with ATA and SCSI layers
- * @ent: Probe information describing hardware device to be registered
- *
- * This function processes the information provided in the probe
- * information struct @ent, allocates the necessary ATA and SCSI
- * host information structures, initializes them, and registers
- * everything with requisite kernel subsystems.
- *
- * This function requests irqs, probes the ATA bus, and probes
- * the SCSI bus.
- *
- * LOCKING:
- * PCI/etc. bus probe sem.
- *
- * RETURNS:
- * Number of ports registered. Zero on error (no ports registered).
- */
-int ata_device_add(const struct ata_probe_ent *ent)
-{
- unsigned int count = 0, i;
- struct device *dev = ent->dev;
- struct ata_host_set *host_set;
- int rc;
-
- DPRINTK("ENTER\n");
- /* alloc a container for our list of ATA ports (buses) */
- host_set = kzalloc(sizeof(struct ata_host_set) +
- (ent->n_ports * sizeof(void *)), GFP_KERNEL);
- if (!host_set)
- return 0;
- spin_lock_init(&host_set->lock);
-
- host_set->dev = dev;
- host_set->n_ports = ent->n_ports;
- host_set->irq = ent->irq;
- host_set->mmio_base = ent->mmio_base;
- host_set->private_data = ent->private_data;
- host_set->ops = ent->port_ops;
- host_set->flags = ent->host_set_flags;
-
- /* register each port bound to this device */
- for (i = 0; i < ent->n_ports; i++) {
- struct ata_port *ap;
- unsigned long xfer_mode_mask;
-
- ap = ata_host_add(ent, host_set, i);
- if (!ap)
- goto err_out;
-
- host_set->ports[i] = ap;
- xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
- (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
- (ap->pio_mask << ATA_SHIFT_PIO);
-
- /* print per-port info to dmesg */
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
- "ctl 0x%lX bmdma 0x%lX irq %lu\n",
- ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
- ata_mode_string(xfer_mode_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- ent->irq);
-
- ata_chk_status(ap);
- host_set->ops->irq_clear(ap);
- ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
- count++;
- }
-
- if (!count)
- goto err_free_ret;
-
- /* obtain irq, that is shared between channels */
- rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host_set);
- if (rc) {
- dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
- ent->irq, rc);
- goto err_out;
- }
-
- /* perform each probe synchronously */
- DPRINTK("probe begin\n");
- for (i = 0; i < count; i++) {
- struct ata_port *ap;
- u32 scontrol;
- int rc;
-
- ap = host_set->ports[i];
-
- /* init sata_spd_limit to the current value */
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
- int spd = (scontrol >> 4) & 0xf;
- ap->hw_sata_spd_limit &= (1 << spd) - 1;
- }
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
- rc = scsi_add_host(ap->host, dev);
- if (rc) {
- ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
- /* FIXME: do something useful here */
- /* FIXME: handle unconditional calls to
- * scsi_scan_host and ata_host_remove, below,
- * at the very least
- */
- }
-
- if (ap->ops->error_handler) {
- unsigned long flags;
-
- ata_port_probe(ap);
-
- /* kick EH for boot probing */
- spin_lock_irqsave(ap->lock, flags);
-
- ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
-
- ap->flags |= ATA_FLAG_LOADING;
- ata_port_schedule_eh(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* wait for EH to finish */
- ata_port_wait_eh(ap);
- } else {
- DPRINTK("ata%u: bus probe begin\n", ap->id);
- rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->id);
-
- if (rc) {
- /* FIXME: do something useful here?
- * Current libata behavior will
- * tear down everything when
- * the module is removed
- * or the h/w is unplugged.
- */
- }
- }
- }
-
- /* probes are done, now scan each port's disk(s) */
- DPRINTK("host probe begin\n");
- for (i = 0; i < count; i++) {
- struct ata_port *ap = host_set->ports[i];
-
- ata_scsi_scan_host(ap);
- }
-
- dev_set_drvdata(dev, host_set);
-
- VPRINTK("EXIT, returning %u\n", ent->n_ports);
- return ent->n_ports; /* success */
-
-err_out:
- for (i = 0; i < count; i++) {
- ata_host_remove(host_set->ports[i], 1);
- scsi_host_put(host_set->ports[i]->host);
- }
-err_free_ret:
- kfree(host_set);
- VPRINTK("EXIT, returning 0\n");
- return 0;
-}
-
-/**
- * ata_port_detach - Detach ATA port in prepration of device removal
- * @ap: ATA port to be detached
- *
- * Detach all ATA devices and the associated SCSI devices of @ap;
- * then, remove the associated SCSI host. @ap is guaranteed to
- * be quiescent on return from this function.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_port_detach(struct ata_port *ap)
-{
- unsigned long flags;
- int i;
-
- if (!ap->ops->error_handler)
- return;
-
- /* tell EH we're leaving & flush EH */
- spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_UNLOADING;
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_port_wait_eh(ap);
-
- /* EH is now guaranteed to see UNLOADING, so no new device
- * will be attached. Disable all existing devices.
- */
- spin_lock_irqsave(ap->lock, flags);
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* Final freeze & EH. All in-flight commands are aborted. EH
- * will be skipped and retrials will be terminated with bad
- * target.
- */
- spin_lock_irqsave(ap->lock, flags);
- ata_port_freeze(ap); /* won't be thawed */
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_port_wait_eh(ap);
-
- /* Flush hotplug task. The sequence is similar to
- * ata_port_flush_task().
- */
- flush_workqueue(ata_aux_wq);
- cancel_delayed_work(&ap->hotplug_task);
- flush_workqueue(ata_aux_wq);
-
- /* remove the associated SCSI host */
- scsi_remove_host(ap->host);
-}
-
-/**
- * ata_host_set_remove - PCI layer callback for device removal
- * @host_set: ATA host set that was removed
- *
- * Unregister all objects associated with this host set. Free those
- * objects.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- */
-
-void ata_host_set_remove(struct ata_host_set *host_set)
-{
- unsigned int i;
-
- for (i = 0; i < host_set->n_ports; i++)
- ata_port_detach(host_set->ports[i]);
-
- free_irq(host_set->irq, host_set);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
-
- ata_scsi_release(ap->host);
-
- if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- if (ioaddr->cmd_addr == 0x1f0)
- release_region(0x1f0, 8);
- else if (ioaddr->cmd_addr == 0x170)
- release_region(0x170, 8);
- }
-
- scsi_host_put(ap->host);
- }
-
- if (host_set->ops->host_stop)
- host_set->ops->host_stop(host_set);
-
- kfree(host_set);
-}
-
-/**
- * ata_scsi_release - SCSI layer callback hook for host unload
- * @host: libata host to be unloaded
- *
- * Performs all duties necessary to shut down a libata port...
- * Kill port kthread, disable port, and release resources.
- *
- * LOCKING:
- * Inherited from SCSI layer.
- *
- * RETURNS:
- * One.
- */
-
-int ata_scsi_release(struct Scsi_Host *host)
-{
- struct ata_port *ap = ata_shost_to_port(host);
-
- DPRINTK("ENTER\n");
-
- ap->ops->port_disable(ap);
- ata_host_remove(ap, 0);
-
- DPRINTK("EXIT\n");
- return 1;
-}
-
-/**
- * ata_std_ports - initialize ioaddr with standard port offsets.
- * @ioaddr: IO address structure to be initialized
- *
- * Utility function which initializes data_addr, error_addr,
- * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
- * device_addr, status_addr, and command_addr to standard offsets
- * relative to cmd_addr.
- *
- * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
- */
-
-void ata_std_ports(struct ata_ioports *ioaddr)
-{
- ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
- ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
- ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
- ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
- ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
- ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
- ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
- ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
- ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
- ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
-}
-
-
-#ifdef CONFIG_PCI
-
-void ata_pci_host_stop (struct ata_host_set *host_set)
-{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
-
- pci_iounmap(pdev, host_set->mmio_base);
-}
-
-/**
- * ata_pci_remove_one - PCI layer callback for device removal
- * @pdev: PCI device that was removed
- *
- * PCI layer indicates to libata via this hook that
- * hot-unplug or module unload event has occurred.
- * Handle this by unregistering all objects associated
- * with this PCI device. Free those objects. Then finally
- * release PCI resources and disable device.
- *
- * LOCKING:
- * Inherited from PCI layer (may sleep).
- */
-
-void ata_pci_remove_one (struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host_set *host_set = dev_get_drvdata(dev);
- struct ata_host_set *host_set2 = host_set->next;
-
- ata_host_set_remove(host_set);
- if (host_set2)
- ata_host_set_remove(host_set2);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
-}
-
-/* move to PCI subsystem */
-int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
-{
- unsigned long tmp = 0;
-
- switch (bits->width) {
- case 1: {
- u8 tmp8 = 0;
- pci_read_config_byte(pdev, bits->reg, &tmp8);
- tmp = tmp8;
- break;
- }
- case 2: {
- u16 tmp16 = 0;
- pci_read_config_word(pdev, bits->reg, &tmp16);
- tmp = tmp16;
- break;
- }
- case 4: {
- u32 tmp32 = 0;
- pci_read_config_dword(pdev, bits->reg, &tmp32);
- tmp = tmp32;
- break;
- }
-
- default:
- return -EINVAL;
- }
-
- tmp &= bits->mask;
-
- return (tmp == bits->val) ? 1 : 0;
-}
-
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- return 0;
-}
-
-int ata_pci_device_resume(struct pci_dev *pdev)
-{
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- pci_enable_device(pdev);
- pci_set_master(pdev);
- return 0;
-}
-#endif /* CONFIG_PCI */
-
-
-static int __init ata_init(void)
-{
- ata_wq = create_workqueue("ata");
- if (!ata_wq)
- return -ENOMEM;
-
- ata_aux_wq = create_singlethread_workqueue("ata_aux");
- if (!ata_aux_wq) {
- destroy_workqueue(ata_wq);
- return -ENOMEM;
- }
-
- printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
- return 0;
-}
-
-static void __exit ata_exit(void)
-{
- destroy_workqueue(ata_wq);
- destroy_workqueue(ata_aux_wq);
-}
-
-module_init(ata_init);
-module_exit(ata_exit);
-
-static unsigned long ratelimit_time;
-static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
-
-int ata_ratelimit(void)
-{
- int rc;
- unsigned long flags;
-
- spin_lock_irqsave(&ata_ratelimit_lock, flags);
-
- if (time_after(jiffies, ratelimit_time)) {
- rc = 1;
- ratelimit_time = jiffies + (HZ/5);
- } else
- rc = 0;
-
- spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
-
- return rc;
-}
-
-/**
- * ata_wait_register - wait until register value changes
- * @reg: IO-mapped register
- * @mask: Mask to apply to read register value
- * @val: Wait condition
- * @interval_msec: polling interval in milliseconds
- * @timeout_msec: timeout in milliseconds
- *
- * Waiting for some bits of register to change is a common
- * operation for ATA controllers. This function reads 32bit LE
- * IO-mapped register @reg and tests for the following condition.
- *
- * (*@reg & mask) != val
- *
- * If the condition is met, it returns; otherwise, the process is
- * repeated after @interval_msec until timeout.
- *
- * LOCKING:
- * Kernel thread context (may sleep)
- *
- * RETURNS:
- * The final register value.
- */
-u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
- unsigned long interval_msec,
- unsigned long timeout_msec)
-{
- unsigned long timeout;
- u32 tmp;
-
- tmp = ioread32(reg);
-
- /* Calculate timeout _after_ the first read to make sure
- * preceding writes reach the controller before starting to
- * eat away the timeout.
- */
- timeout = jiffies + (timeout_msec * HZ) / 1000;
-
- while ((tmp & mask) == val && time_before(jiffies, timeout)) {
- msleep(interval_msec);
- tmp = ioread32(reg);
- }
-
- return tmp;
-}
-
-/*
- * libata is essentially a library of internal helper functions for
- * low-level ATA host controller drivers. As such, the API/ABI is
- * likely to change as new drivers are added and updated.
- * Do not depend on ABI/API stability.
- */
-
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
-EXPORT_SYMBOL_GPL(ata_std_bios_param);
-EXPORT_SYMBOL_GPL(ata_std_ports);
-EXPORT_SYMBOL_GPL(ata_device_add);
-EXPORT_SYMBOL_GPL(ata_port_detach);
-EXPORT_SYMBOL_GPL(ata_host_set_remove);
-EXPORT_SYMBOL_GPL(ata_sg_init);
-EXPORT_SYMBOL_GPL(ata_sg_init_one);
-EXPORT_SYMBOL_GPL(ata_hsm_move);
-EXPORT_SYMBOL_GPL(ata_qc_complete);
-EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
-EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
-EXPORT_SYMBOL_GPL(ata_tf_load);
-EXPORT_SYMBOL_GPL(ata_tf_read);
-EXPORT_SYMBOL_GPL(ata_noop_dev_select);
-EXPORT_SYMBOL_GPL(ata_std_dev_select);
-EXPORT_SYMBOL_GPL(ata_tf_to_fis);
-EXPORT_SYMBOL_GPL(ata_tf_from_fis);
-EXPORT_SYMBOL_GPL(ata_check_status);
-EXPORT_SYMBOL_GPL(ata_altstatus);
-EXPORT_SYMBOL_GPL(ata_exec_command);
-EXPORT_SYMBOL_GPL(ata_port_start);
-EXPORT_SYMBOL_GPL(ata_port_stop);
-EXPORT_SYMBOL_GPL(ata_host_stop);
-EXPORT_SYMBOL_GPL(ata_interrupt);
-EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
-EXPORT_SYMBOL_GPL(ata_qc_prep);
-EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
-EXPORT_SYMBOL_GPL(ata_bmdma_setup);
-EXPORT_SYMBOL_GPL(ata_bmdma_start);
-EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
-EXPORT_SYMBOL_GPL(ata_bmdma_status);
-EXPORT_SYMBOL_GPL(ata_bmdma_stop);
-EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
-EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
-EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
-EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
-EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
-EXPORT_SYMBOL_GPL(ata_port_probe);
-EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
-EXPORT_SYMBOL_GPL(sata_phy_reset);
-EXPORT_SYMBOL_GPL(__sata_phy_reset);
-EXPORT_SYMBOL_GPL(ata_bus_reset);
-EXPORT_SYMBOL_GPL(ata_std_prereset);
-EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_std_hardreset);
-EXPORT_SYMBOL_GPL(ata_std_postreset);
-EXPORT_SYMBOL_GPL(ata_dev_revalidate);
-EXPORT_SYMBOL_GPL(ata_dev_classify);
-EXPORT_SYMBOL_GPL(ata_dev_pair);
-EXPORT_SYMBOL_GPL(ata_port_disable);
-EXPORT_SYMBOL_GPL(ata_ratelimit);
-EXPORT_SYMBOL_GPL(ata_wait_register);
-EXPORT_SYMBOL_GPL(ata_busy_sleep);
-EXPORT_SYMBOL_GPL(ata_port_queue_task);
-EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
-EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
-EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
-EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
-EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
-EXPORT_SYMBOL_GPL(ata_scsi_release);
-EXPORT_SYMBOL_GPL(ata_host_intr);
-EXPORT_SYMBOL_GPL(sata_scr_valid);
-EXPORT_SYMBOL_GPL(sata_scr_read);
-EXPORT_SYMBOL_GPL(sata_scr_write);
-EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
-EXPORT_SYMBOL_GPL(ata_id_string);
-EXPORT_SYMBOL_GPL(ata_id_c_string);
-EXPORT_SYMBOL_GPL(ata_scsi_simulate);
-
-EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
-EXPORT_SYMBOL_GPL(ata_timing_compute);
-EXPORT_SYMBOL_GPL(ata_timing_merge);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_host_stop);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
-EXPORT_SYMBOL_GPL(ata_pci_init_one);
-EXPORT_SYMBOL_GPL(ata_pci_remove_one);
-EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
-EXPORT_SYMBOL_GPL(ata_pci_device_resume);
-EXPORT_SYMBOL_GPL(ata_pci_default_filter);
-EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
-#endif /* CONFIG_PCI */
-
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
-EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
-EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
-
-EXPORT_SYMBOL_GPL(ata_eng_timeout);
-EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
-EXPORT_SYMBOL_GPL(ata_port_abort);
-EXPORT_SYMBOL_GPL(ata_port_freeze);
-EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
-EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
-EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
-EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
-EXPORT_SYMBOL_GPL(ata_do_eh);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
deleted file mode 100644
index 823385981a7..00000000000
--- a/drivers/scsi/libata-eh.c
+++ /dev/null
@@ -1,1907 +0,0 @@
-/*
- * libata-eh.c - libata error handling
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2006 Tejun Heo <htejun@gmail.com>
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available from http://www.t13.org/ and
- * http://www.sata-io.org/
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_cmnd.h>
-#include "scsi_transport_api.h"
-
-#include <linux/libata.h>
-
-#include "libata.h"
-
-static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
-
-static void ata_ering_record(struct ata_ering *ering, int is_io,
- unsigned int err_mask)
-{
- struct ata_ering_entry *ent;
-
- WARN_ON(!err_mask);
-
- ering->cursor++;
- ering->cursor %= ATA_ERING_SIZE;
-
- ent = &ering->ring[ering->cursor];
- ent->is_io = is_io;
- ent->err_mask = err_mask;
- ent->timestamp = get_jiffies_64();
-}
-
-static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
-{
- struct ata_ering_entry *ent = &ering->ring[ering->cursor];
- if (!ent->err_mask)
- return NULL;
- return ent;
-}
-
-static int ata_ering_map(struct ata_ering *ering,
- int (*map_fn)(struct ata_ering_entry *, void *),
- void *arg)
-{
- int idx, rc = 0;
- struct ata_ering_entry *ent;
-
- idx = ering->cursor;
- do {
- ent = &ering->ring[idx];
- if (!ent->err_mask)
- break;
- rc = map_fn(ent, arg);
- if (rc)
- break;
- idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
- } while (idx != ering->cursor);
-
- return rc;
-}
-
-/**
- * ata_scsi_timed_out - SCSI layer time out callback
- * @cmd: timed out SCSI command
- *
- * Handles SCSI layer timeout. We race with normal completion of
- * the qc for @cmd. If the qc is already gone, we lose and let
- * the scsi command finish (EH_HANDLED). Otherwise, the qc has
- * timed out and EH should be invoked. Prevent ata_qc_complete()
- * from finishing it by setting EH_SCHEDULED and return
- * EH_NOT_HANDLED.
- *
- * TODO: kill this function once old EH is gone.
- *
- * LOCKING:
- * Called from timer context
- *
- * RETURNS:
- * EH_HANDLED or EH_NOT_HANDLED
- */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *host = cmd->device->host;
- struct ata_port *ap = ata_shost_to_port(host);
- unsigned long flags;
- struct ata_queued_cmd *qc;
- enum scsi_eh_timer_return ret;
-
- DPRINTK("ENTER\n");
-
- if (ap->ops->error_handler) {
- ret = EH_NOT_HANDLED;
- goto out;
- }
-
- ret = EH_HANDLED;
- spin_lock_irqsave(ap->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc) {
- WARN_ON(qc->scsicmd != cmd);
- qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
- qc->err_mask |= AC_ERR_TIMEOUT;
- ret = EH_NOT_HANDLED;
- }
- spin_unlock_irqrestore(ap->lock, flags);
-
- out:
- DPRINTK("EXIT, ret=%d\n", ret);
- return ret;
-}
-
-/**
- * ata_scsi_error - SCSI layer error handler callback
- * @host: SCSI host on which error occurred
- *
- * Handles SCSI-layer-thrown error events.
- *
- * LOCKING:
- * Inherited from SCSI layer (none, can sleep)
- *
- * RETURNS:
- * Zero.
- */
-void ata_scsi_error(struct Scsi_Host *host)
-{
- struct ata_port *ap = ata_shost_to_port(host);
- spinlock_t *ap_lock = ap->lock;
- int i, repeat_cnt = ATA_EH_MAX_REPEAT;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- /* synchronize with port task */
- ata_port_flush_task(ap);
-
- /* synchronize with host_set lock and sort out timeouts */
-
- /* For new EH, all qcs are finished in one of three ways -
- * normal completion, error completion, and SCSI timeout.
- * Both cmpletions can race against SCSI timeout. When normal
- * completion wins, the qc never reaches EH. When error
- * completion wins, the qc has ATA_QCFLAG_FAILED set.
- *
- * When SCSI timeout wins, things are a bit more complex.
- * Normal or error completion can occur after the timeout but
- * before this point. In such cases, both types of
- * completions are honored. A scmd is determined to have
- * timed out iff its associated qc is active and not failed.
- */
- if (ap->ops->error_handler) {
- struct scsi_cmnd *scmd, *tmp;
- int nr_timedout = 0;
-
- spin_lock_irqsave(ap_lock, flags);
-
- list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
- struct ata_queued_cmd *qc;
-
- for (i = 0; i < ATA_MAX_QUEUE; i++) {
- qc = __ata_qc_from_tag(ap, i);
- if (qc->flags & ATA_QCFLAG_ACTIVE &&
- qc->scsicmd == scmd)
- break;
- }
-
- if (i < ATA_MAX_QUEUE) {
- /* the scmd has an associated qc */
- if (!(qc->flags & ATA_QCFLAG_FAILED)) {
- /* which hasn't failed yet, timeout */
- qc->err_mask |= AC_ERR_TIMEOUT;
- qc->flags |= ATA_QCFLAG_FAILED;
- nr_timedout++;
- }
- } else {
- /* Normal completion occurred after
- * SCSI timeout but before this point.
- * Successfully complete it.
- */
- scmd->retries = scmd->allowed;
- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
- }
- }
-
- /* If we have timed out qcs. They belong to EH from
- * this point but the state of the controller is
- * unknown. Freeze the port to make sure the IRQ
- * handler doesn't diddle with those qcs. This must
- * be done atomically w.r.t. setting QCFLAG_FAILED.
- */
- if (nr_timedout)
- __ata_port_freeze(ap);
-
- spin_unlock_irqrestore(ap_lock, flags);
- } else
- spin_unlock_wait(ap_lock);
-
- repeat:
- /* invoke error handler */
- if (ap->ops->error_handler) {
- /* fetch & clear EH info */
- spin_lock_irqsave(ap_lock, flags);
-
- memset(&ap->eh_context, 0, sizeof(ap->eh_context));
- ap->eh_context.i = ap->eh_info;
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
-
- ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
- ap->flags &= ~ATA_FLAG_EH_PENDING;
-
- spin_unlock_irqrestore(ap_lock, flags);
-
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
- ap->ops->error_handler(ap);
- else
- ata_eh_finish(ap);
-
- /* Exception might have happend after ->error_handler
- * recovered the port but before this point. Repeat
- * EH in such case.
- */
- spin_lock_irqsave(ap_lock, flags);
-
- if (ap->flags & ATA_FLAG_EH_PENDING) {
- if (--repeat_cnt) {
- ata_port_printk(ap, KERN_INFO,
- "EH pending after completion, "
- "repeating EH (cnt=%d)\n", repeat_cnt);
- spin_unlock_irqrestore(ap_lock, flags);
- goto repeat;
- }
- ata_port_printk(ap, KERN_ERR, "EH pending after %d "
- "tries, giving up\n", ATA_EH_MAX_REPEAT);
- }
-
- /* this run is complete, make sure EH info is clear */
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
-
- /* Clear host_eh_scheduled while holding ap_lock such
- * that if exception occurs after this point but
- * before EH completion, SCSI midlayer will
- * re-initiate EH.
- */
- host->host_eh_scheduled = 0;
-
- spin_unlock_irqrestore(ap_lock, flags);
- } else {
- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
- ap->ops->eng_timeout(ap);
- }
-
- /* finish or retry handled scmd's and clean up */
- WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
-
- scsi_eh_flush_done_q(&ap->eh_done_q);
-
- /* clean up */
- spin_lock_irqsave(ap_lock, flags);
-
- if (ap->flags & ATA_FLAG_LOADING) {
- ap->flags &= ~ATA_FLAG_LOADING;
- } else {
- if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
- queue_work(ata_aux_wq, &ap->hotplug_task);
- if (ap->flags & ATA_FLAG_RECOVERED)
- ata_port_printk(ap, KERN_INFO, "EH complete\n");
- }
-
- ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
-
- /* tell wait_eh that we're done */
- ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
- wake_up_all(&ap->eh_wait_q);
-
- spin_unlock_irqrestore(ap_lock, flags);
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_port_wait_eh - Wait for the currently pending EH to complete
- * @ap: Port to wait EH for
- *
- * Wait until the currently pending EH is complete.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_port_wait_eh(struct ata_port *ap)
-{
- unsigned long flags;
- DEFINE_WAIT(wait);
-
- retry:
- spin_lock_irqsave(ap->lock, flags);
-
- while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
- prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
- spin_unlock_irqrestore(ap->lock, flags);
- schedule();
- spin_lock_irqsave(ap->lock, flags);
- }
- finish_wait(&ap->eh_wait_q, &wait);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* make sure SCSI EH is complete */
- if (scsi_host_in_recovery(ap->host)) {
- msleep(10);
- goto retry;
- }
-}
-
-/**
- * ata_qc_timeout - Handle timeout of queued command
- * @qc: Command that timed out
- *
- * Some part of the kernel (currently, only the SCSI layer)
- * has noticed that the active command on port @ap has not
- * completed after a specified length of time. Handle this
- * condition by disabling DMA (if necessary) and completing
- * transactions, with error if necessary.
- *
- * This also handles the case of the "lost interrupt", where
- * for some reason (possibly hardware bug, possibly driver bug)
- * an interrupt was not delivered to the driver, even though the
- * transaction completed successfully.
- *
- * TODO: kill this function once old EH is gone.
- *
- * LOCKING:
- * Inherited from SCSI layer (none, can sleep)
- */
-static void ata_qc_timeout(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 host_stat = 0, drv_stat;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- ap->hsm_task_state = HSM_ST_IDLE;
-
- spin_lock_irqsave(ap->lock, flags);
-
- switch (qc->tf.protocol) {
-
- case ATA_PROT_DMA:
- case ATA_PROT_ATAPI_DMA:
- host_stat = ap->ops->bmdma_status(ap);
-
- /* before we do anything else, clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
-
- /* fall through */
-
- default:
- ata_altstatus(ap);
- drv_stat = ata_chk_status(ap);
-
- /* ack bmdma irq events */
- ap->ops->irq_clear(ap);
-
- ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
- "stat 0x%x host_stat 0x%x\n",
- qc->tf.command, drv_stat, host_stat);
-
- /* complete taskfile transaction */
- qc->err_mask |= AC_ERR_TIMEOUT;
- break;
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_eh_qc_complete(qc);
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_eng_timeout - Handle timeout of queued command
- * @ap: Port on which timed-out command is active
- *
- * Some part of the kernel (currently, only the SCSI layer)
- * has noticed that the active command on port @ap has not
- * completed after a specified length of time. Handle this
- * condition by disabling DMA (if necessary) and completing
- * transactions, with error if necessary.
- *
- * This also handles the case of the "lost interrupt", where
- * for some reason (possibly hardware bug, possibly driver bug)
- * an interrupt was not delivered to the driver, even though the
- * transaction completed successfully.
- *
- * TODO: kill this function once old EH is gone.
- *
- * LOCKING:
- * Inherited from SCSI layer (none, can sleep)
- */
-void ata_eng_timeout(struct ata_port *ap)
-{
- DPRINTK("ENTER\n");
-
- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_qc_schedule_eh - schedule qc for error handling
- * @qc: command to schedule error handling for
- *
- * Schedule error handling for @qc. EH will kick in as soon as
- * other commands are drained.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- WARN_ON(!ap->ops->error_handler);
-
- qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->flags |= ATA_FLAG_EH_PENDING;
-
- /* The following will fail if timeout has already expired.
- * ata_scsi_error() takes care of such scmds on EH entry.
- * Note that ATA_QCFLAG_FAILED is unconditionally set after
- * this function completes.
- */
- scsi_req_abort_cmd(qc->scsicmd);
-}
-
-/**
- * ata_port_schedule_eh - schedule error handling without a qc
- * @ap: ATA port to schedule EH for
- *
- * Schedule error handling for @ap. EH will kick in as soon as
- * all commands are drained.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_port_schedule_eh(struct ata_port *ap)
-{
- WARN_ON(!ap->ops->error_handler);
-
- ap->flags |= ATA_FLAG_EH_PENDING;
- scsi_schedule_eh(ap->host);
-
- DPRINTK("port EH scheduled\n");
-}
-
-/**
- * ata_port_abort - abort all qc's on the port
- * @ap: ATA port to abort qc's for
- *
- * Abort all active qc's of @ap and schedule EH.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
-{
- int tag, nr_aborted = 0;
-
- WARN_ON(!ap->ops->error_handler);
-
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
-
- if (qc) {
- qc->flags |= ATA_QCFLAG_FAILED;
- ata_qc_complete(qc);
- nr_aborted++;
- }
- }
-
- if (!nr_aborted)
- ata_port_schedule_eh(ap);
-
- return nr_aborted;
-}
-
-/**
- * __ata_port_freeze - freeze port
- * @ap: ATA port to freeze
- *
- * This function is called when HSM violation or some other
- * condition disrupts normal operation of the port. Frozen port
- * is not allowed to perform any operation until the port is
- * thawed, which usually follows a successful reset.
- *
- * ap->ops->freeze() callback can be used for freezing the port
- * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
- * port cannot be frozen hardware-wise, the interrupt handler
- * must ack and clear interrupts unconditionally while the port
- * is frozen.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-static void __ata_port_freeze(struct ata_port *ap)
-{
- WARN_ON(!ap->ops->error_handler);
-
- if (ap->ops->freeze)
- ap->ops->freeze(ap);
-
- ap->flags |= ATA_FLAG_FROZEN;
-
- DPRINTK("ata%u port frozen\n", ap->id);
-}
-
-/**
- * ata_port_freeze - abort & freeze port
- * @ap: ATA port to freeze
- *
- * Abort and freeze @ap.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Number of aborted commands.
- */
-int ata_port_freeze(struct ata_port *ap)
-{
- int nr_aborted;
-
- WARN_ON(!ap->ops->error_handler);
-
- nr_aborted = ata_port_abort(ap);
- __ata_port_freeze(ap);
-
- return nr_aborted;
-}
-
-/**
- * ata_eh_freeze_port - EH helper to freeze port
- * @ap: ATA port to freeze
- *
- * Freeze @ap.
- *
- * LOCKING:
- * None.
- */
-void ata_eh_freeze_port(struct ata_port *ap)
-{
- unsigned long flags;
-
- if (!ap->ops->error_handler)
- return;
-
- spin_lock_irqsave(ap->lock, flags);
- __ata_port_freeze(ap);
- spin_unlock_irqrestore(ap->lock, flags);
-}
-
-/**
- * ata_port_thaw_port - EH helper to thaw port
- * @ap: ATA port to thaw
- *
- * Thaw frozen port @ap.
- *
- * LOCKING:
- * None.
- */
-void ata_eh_thaw_port(struct ata_port *ap)
-{
- unsigned long flags;
-
- if (!ap->ops->error_handler)
- return;
-
- spin_lock_irqsave(ap->lock, flags);
-
- ap->flags &= ~ATA_FLAG_FROZEN;
-
- if (ap->ops->thaw)
- ap->ops->thaw(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- DPRINTK("ata%u port thawed\n", ap->id);
-}
-
-static void ata_eh_scsidone(struct scsi_cmnd *scmd)
-{
- /* nada */
-}
-
-static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scsi_cmnd *scmd = qc->scsicmd;
- unsigned long flags;
-
- spin_lock_irqsave(ap->lock, flags);
- qc->scsidone = ata_eh_scsidone;
- __ata_qc_complete(qc);
- WARN_ON(ata_tag_valid(qc->tag));
- spin_unlock_irqrestore(ap->lock, flags);
-
- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
-}
-
-/**
- * ata_eh_qc_complete - Complete an active ATA command from EH
- * @qc: Command to complete
- *
- * Indicate to the mid and upper layers that an ATA command has
- * completed. To be used from EH.
- */
-void ata_eh_qc_complete(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *scmd = qc->scsicmd;
- scmd->retries = scmd->allowed;
- __ata_eh_qc_complete(qc);
-}
-
-/**
- * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
- * @qc: Command to retry
- *
- * Indicate to the mid and upper layers that an ATA command
- * should be retried. To be used from EH.
- *
- * SCSI midlayer limits the number of retries to scmd->allowed.
- * scmd->retries is decremented for commands which get retried
- * due to unrelated failures (qc->err_mask is zero).
- */
-void ata_eh_qc_retry(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *scmd = qc->scsicmd;
- if (!qc->err_mask && scmd->retries)
- scmd->retries--;
- __ata_eh_qc_complete(qc);
-}
-
-/**
- * ata_eh_detach_dev - detach ATA device
- * @dev: ATA device to detach
- *
- * Detach @dev.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_detach_dev(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
- unsigned long flags;
-
- ata_dev_disable(dev);
-
- spin_lock_irqsave(ap->lock, flags);
-
- dev->flags &= ~ATA_DFLAG_DETACH;
-
- if (ata_scsi_offline_dev(dev)) {
- dev->flags |= ATA_DFLAG_DETACHED;
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
-}
-
-static void ata_eh_clear_action(struct ata_device *dev,
- struct ata_eh_info *ehi, unsigned int action)
-{
- int i;
-
- if (!dev) {
- ehi->action &= ~action;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] &= ~action;
- } else {
- /* doesn't make sense for port-wide EH actions */
- WARN_ON(!(action & ATA_EH_PERDEV_MASK));
-
- /* break ehi->action into ehi->dev_action */
- if (ehi->action & action) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] |= ehi->action & action;
- ehi->action &= ~action;
- }
-
- /* turn off the specified per-dev action */
- ehi->dev_action[dev->devno] &= ~action;
- }
-}
-
-/**
- * ata_eh_about_to_do - about to perform eh_action
- * @ap: target ATA port
- * @dev: target ATA dev for per-dev action (can be NULL)
- * @action: action about to be performed
- *
- * Called just before performing EH actions to clear related bits
- * in @ap->eh_info such that eh actions are not unnecessarily
- * repeated.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
-{
- unsigned long flags;
-
- spin_lock_irqsave(ap->lock, flags);
- ata_eh_clear_action(dev, &ap->eh_info, action);
- ap->flags |= ATA_FLAG_RECOVERED;
- spin_unlock_irqrestore(ap->lock, flags);
-}
-
-/**
- * ata_eh_done - EH action complete
- * @ap: target ATA port
- * @dev: target ATA dev for per-dev action (can be NULL)
- * @action: action just completed
- *
- * Called right after performing EH actions to clear related bits
- * in @ap->eh_context.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
-{
- ata_eh_clear_action(dev, &ap->eh_context.i, action);
-}
-
-/**
- * ata_err_string - convert err_mask to descriptive string
- * @err_mask: error mask to convert to string
- *
- * Convert @err_mask to descriptive string. Errors are
- * prioritized according to severity and only the most severe
- * error is reported.
- *
- * LOCKING:
- * None.
- *
- * RETURNS:
- * Descriptive string for @err_mask
- */
-static const char * ata_err_string(unsigned int err_mask)
-{
- if (err_mask & AC_ERR_HOST_BUS)
- return "host bus error";
- if (err_mask & AC_ERR_ATA_BUS)
- return "ATA bus error";
- if (err_mask & AC_ERR_TIMEOUT)
- return "timeout";
- if (err_mask & AC_ERR_HSM)
- return "HSM violation";
- if (err_mask & AC_ERR_SYSTEM)
- return "internal error";
- if (err_mask & AC_ERR_MEDIA)
- return "media error";
- if (err_mask & AC_ERR_INVALID)
- return "invalid argument";
- if (err_mask & AC_ERR_DEV)
- return "device error";
- return "unknown error";
-}
-
-/**
- * ata_read_log_page - read a specific log page
- * @dev: target device
- * @page: page to read
- * @buf: buffer to store read page
- * @sectors: number of sectors to read
- *
- * Read log page using READ_LOG_EXT command.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, AC_ERR_* mask otherwise.
- */
-static unsigned int ata_read_log_page(struct ata_device *dev,
- u8 page, void *buf, unsigned int sectors)
-{
- struct ata_taskfile tf;
- unsigned int err_mask;
-
- DPRINTK("read log page - page %d\n", page);
-
- ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_READ_LOG_EXT;
- tf.lbal = page;
- tf.nsect = sectors;
- tf.hob_nsect = sectors >> 8;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_PIO;
-
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- buf, sectors * ATA_SECT_SIZE);
-
- DPRINTK("EXIT, err_mask=%x\n", err_mask);
- return err_mask;
-}
-
-/**
- * ata_eh_read_log_10h - Read log page 10h for NCQ error details
- * @dev: Device to read log page 10h from
- * @tag: Resulting tag of the failed command
- * @tf: Resulting taskfile registers of the failed command
- *
- * Read log page 10h to obtain NCQ error details and clear error
- * condition.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-static int ata_eh_read_log_10h(struct ata_device *dev,
- int *tag, struct ata_taskfile *tf)
-{
- u8 *buf = dev->ap->sector_buf;
- unsigned int err_mask;
- u8 csum;
- int i;
-
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
- if (err_mask)
- return -EIO;
-
- csum = 0;
- for (i = 0; i < ATA_SECT_SIZE; i++)
- csum += buf[i];
- if (csum)
- ata_dev_printk(dev, KERN_WARNING,
- "invalid checksum 0x%x on log page 10h\n", csum);
-
- if (buf[0] & 0x80)
- return -ENOENT;
-
- *tag = buf[0] & 0x1f;
-
- tf->command = buf[2];
- tf->feature = buf[3];
- tf->lbal = buf[4];
- tf->lbam = buf[5];
- tf->lbah = buf[6];
- tf->device = buf[7];
- tf->hob_lbal = buf[8];
- tf->hob_lbam = buf[9];
- tf->hob_lbah = buf[10];
- tf->nsect = buf[12];
- tf->hob_nsect = buf[13];
-
- return 0;
-}
-
-/**
- * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
- * @dev: device to perform REQUEST_SENSE to
- * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
- *
- * Perform ATAPI REQUEST_SENSE after the device reported CHECK
- * SENSE. This function is EH helper.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, AC_ERR_* mask on failure
- */
-static unsigned int atapi_eh_request_sense(struct ata_device *dev,
- unsigned char *sense_buf)
-{
- struct ata_port *ap = dev->ap;
- struct ata_taskfile tf;
- u8 cdb[ATAPI_CDB_LEN];
-
- DPRINTK("ATAPI request sense\n");
-
- ata_tf_init(dev, &tf);
-
- /* FIXME: is this needed? */
- memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
-
- /* XXX: why tf_read here? */
- ap->ops->tf_read(ap, &tf);
-
- /* fill these in, for the case where they are -not- overwritten */
- sense_buf[0] = 0x70;
- sense_buf[2] = tf.feature >> 4;
-
- memset(cdb, 0, ATAPI_CDB_LEN);
- cdb[0] = REQUEST_SENSE;
- cdb[4] = SCSI_SENSE_BUFFERSIZE;
-
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf.command = ATA_CMD_PACKET;
-
- /* is it pointless to prefer PIO for "safety reasons"? */
- if (ap->flags & ATA_FLAG_PIO_DMA) {
- tf.protocol = ATA_PROT_ATAPI_DMA;
- tf.feature |= ATAPI_PKT_DMA;
- } else {
- tf.protocol = ATA_PROT_ATAPI;
- tf.lbam = (8 * 1024) & 0xff;
- tf.lbah = (8 * 1024) >> 8;
- }
-
- return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
- sense_buf, SCSI_SENSE_BUFFERSIZE);
-}
-
-/**
- * ata_eh_analyze_serror - analyze SError for a failed port
- * @ap: ATA port to analyze SError for
- *
- * Analyze SError if available and further determine cause of
- * failure.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_analyze_serror(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- u32 serror = ehc->i.serror;
- unsigned int err_mask = 0, action = 0;
-
- if (serror & SERR_PERSISTENT) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_HARDRESET;
- }
- if (serror &
- (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_SOFTRESET;
- }
- if (serror & SERR_PROTOCOL) {
- err_mask |= AC_ERR_HSM;
- action |= ATA_EH_SOFTRESET;
- }
- if (serror & SERR_INTERNAL) {
- err_mask |= AC_ERR_SYSTEM;
- action |= ATA_EH_SOFTRESET;
- }
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
- ata_ehi_hotplugged(&ehc->i);
-
- ehc->i.err_mask |= err_mask;
- ehc->i.action |= action;
-}
-
-/**
- * ata_eh_analyze_ncq_error - analyze NCQ error
- * @ap: ATA port to analyze NCQ error for
- *
- * Read log page 10h, determine the offending qc and acquire
- * error status TF. For NCQ device errors, all LLDDs have to do
- * is setting AC_ERR_DEV in ehi->err_mask. This function takes
- * care of the rest.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev = ap->device;
- struct ata_queued_cmd *qc;
- struct ata_taskfile tf;
- int tag, rc;
-
- /* if frozen, we can't do much */
- if (ap->flags & ATA_FLAG_FROZEN)
- return;
-
- /* is it NCQ device error? */
- if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
- return;
-
- /* has LLDD analyzed already? */
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- qc = __ata_qc_from_tag(ap, tag);
-
- if (!(qc->flags & ATA_QCFLAG_FAILED))
- continue;
-
- if (qc->err_mask)
- return;
- }
-
- /* okay, this error is ours */
- rc = ata_eh_read_log_10h(dev, &tag, &tf);
- if (rc) {
- ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
- "(errno=%d)\n", rc);
- return;
- }
-
- if (!(ap->sactive & (1 << tag))) {
- ata_port_printk(ap, KERN_ERR, "log page 10h reported "
- "inactive tag %d\n", tag);
- return;
- }
-
- /* we've got the perpetrator, condemn it */
- qc = __ata_qc_from_tag(ap, tag);
- memcpy(&qc->result_tf, &tf, sizeof(tf));
- qc->err_mask |= AC_ERR_DEV;
- ehc->i.err_mask &= ~AC_ERR_DEV;
-}
-
-/**
- * ata_eh_analyze_tf - analyze taskfile of a failed qc
- * @qc: qc to analyze
- * @tf: Taskfile registers to analyze
- *
- * Analyze taskfile of @qc and further determine cause of
- * failure. This function also requests ATAPI sense data if
- * avaliable.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * Determined recovery action
- */
-static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
- const struct ata_taskfile *tf)
-{
- unsigned int tmp, action = 0;
- u8 stat = tf->command, err = tf->feature;
-
- if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
- qc->err_mask |= AC_ERR_HSM;
- return ATA_EH_SOFTRESET;
- }
-
- if (!(qc->err_mask & AC_ERR_DEV))
- return 0;
-
- switch (qc->dev->class) {
- case ATA_DEV_ATA:
- if (err & ATA_ICRC)
- qc->err_mask |= AC_ERR_ATA_BUS;
- if (err & ATA_UNC)
- qc->err_mask |= AC_ERR_MEDIA;
- if (err & ATA_IDNF)
- qc->err_mask |= AC_ERR_INVALID;
- break;
-
- case ATA_DEV_ATAPI:
- tmp = atapi_eh_request_sense(qc->dev,
- qc->scsicmd->sense_buffer);
- if (!tmp) {
- /* ATA_QCFLAG_SENSE_VALID is used to tell
- * atapi_qc_complete() that sense data is
- * already valid.
- *
- * TODO: interpret sense data and set
- * appropriate err_mask.
- */
- qc->flags |= ATA_QCFLAG_SENSE_VALID;
- } else
- qc->err_mask |= tmp;
- }
-
- if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
- action |= ATA_EH_SOFTRESET;
-
- return action;
-}
-
-static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
-{
- if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
- return 1;
-
- if (ent->is_io) {
- if (ent->err_mask & AC_ERR_HSM)
- return 1;
- if ((ent->err_mask &
- (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
- return 2;
- }
-
- return 0;
-}
-
-struct speed_down_needed_arg {
- u64 since;
- int nr_errors[3];
-};
-
-static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
-{
- struct speed_down_needed_arg *arg = void_arg;
-
- if (ent->timestamp < arg->since)
- return -1;
-
- arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
- return 0;
-}
-
-/**
- * ata_eh_speed_down_needed - Determine wheter speed down is necessary
- * @dev: Device of interest
- *
- * This function examines error ring of @dev and determines
- * whether speed down is necessary. Speed down is necessary if
- * there have been more than 3 of Cat-1 errors or 10 of Cat-2
- * errors during last 15 minutes.
- *
- * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
- * violation for known supported commands.
- *
- * Cat-2 errors are unclassified DEV error for known supported
- * command.
- *
- * LOCKING:
- * Inherited from caller.
- *
- * RETURNS:
- * 1 if speed down is necessary, 0 otherwise
- */
-static int ata_eh_speed_down_needed(struct ata_device *dev)
-{
- const u64 interval = 15LLU * 60 * HZ;
- static const int err_limits[3] = { -1, 3, 10 };
- struct speed_down_needed_arg arg;
- struct ata_ering_entry *ent;
- int err_cat;
- u64 j64;
-
- ent = ata_ering_top(&dev->ering);
- if (!ent)
- return 0;
-
- err_cat = ata_eh_categorize_ering_entry(ent);
- if (err_cat == 0)
- return 0;
-
- memset(&arg, 0, sizeof(arg));
-
- j64 = get_jiffies_64();
- if (j64 >= interval)
- arg.since = j64 - interval;
- else
- arg.since = 0;
-
- ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
-
- return arg.nr_errors[err_cat] > err_limits[err_cat];
-}
-
-/**
- * ata_eh_speed_down - record error and speed down if necessary
- * @dev: Failed device
- * @is_io: Did the device fail during normal IO?
- * @err_mask: err_mask of the error
- *
- * Record error and examine error history to determine whether
- * adjusting transmission speed is necessary. It also sets
- * transmission limits appropriately if such adjustment is
- * necessary.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise
- */
-static int ata_eh_speed_down(struct ata_device *dev, int is_io,
- unsigned int err_mask)
-{
- if (!err_mask)
- return 0;
-
- /* record error and determine whether speed down is necessary */
- ata_ering_record(&dev->ering, is_io, err_mask);
-
- if (!ata_eh_speed_down_needed(dev))
- return 0;
-
- /* speed down SATA link speed if possible */
- if (sata_down_spd_limit(dev->ap) == 0)
- return ATA_EH_HARDRESET;
-
- /* lower transfer mode */
- if (ata_down_xfermask_limit(dev, 0) == 0)
- return ATA_EH_SOFTRESET;
-
- ata_dev_printk(dev, KERN_ERR,
- "speed down requested but no transfer mode left\n");
- return 0;
-}
-
-/**
- * ata_eh_autopsy - analyze error and determine recovery action
- * @ap: ATA port to perform autopsy on
- *
- * Analyze why @ap failed and determine which recovery action is
- * needed. This function also sets more detailed AC_ERR_* values
- * and fills sense data for ATAPI CHECK SENSE.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-static void ata_eh_autopsy(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- unsigned int action = ehc->i.action;
- struct ata_device *failed_dev = NULL;
- unsigned int all_err_mask = 0;
- int tag, is_io = 0;
- u32 serror;
- int rc;
-
- DPRINTK("ENTER\n");
-
- /* obtain and analyze SError */
- rc = sata_scr_read(ap, SCR_ERROR, &serror);
- if (rc == 0) {
- ehc->i.serror |= serror;
- ata_eh_analyze_serror(ap);
- } else if (rc != -EOPNOTSUPP)
- action |= ATA_EH_HARDRESET;
-
- /* analyze NCQ failure */
- ata_eh_analyze_ncq_error(ap);
-
- /* any real error trumps AC_ERR_OTHER */
- if (ehc->i.err_mask & ~AC_ERR_OTHER)
- ehc->i.err_mask &= ~AC_ERR_OTHER;
-
- all_err_mask |= ehc->i.err_mask;
-
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
-
- if (!(qc->flags & ATA_QCFLAG_FAILED))
- continue;
-
- /* inherit upper level err_mask */
- qc->err_mask |= ehc->i.err_mask;
-
- /* analyze TF */
- action |= ata_eh_analyze_tf(qc, &qc->result_tf);
-
- /* DEV errors are probably spurious in case of ATA_BUS error */
- if (qc->err_mask & AC_ERR_ATA_BUS)
- qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
- AC_ERR_INVALID);
-
- /* any real error trumps unknown error */
- if (qc->err_mask & ~AC_ERR_OTHER)
- qc->err_mask &= ~AC_ERR_OTHER;
-
- /* SENSE_VALID trumps dev/unknown error and revalidation */
- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
- qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
- action &= ~ATA_EH_REVALIDATE;
- }
-
- /* accumulate error info */
- failed_dev = qc->dev;
- all_err_mask |= qc->err_mask;
- if (qc->flags & ATA_QCFLAG_IO)
- is_io = 1;
- }
-
- /* enforce default EH actions */
- if (ap->flags & ATA_FLAG_FROZEN ||
- all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
- action |= ATA_EH_SOFTRESET;
- else if (all_err_mask)
- action |= ATA_EH_REVALIDATE;
-
- /* if we have offending qcs and the associated failed device */
- if (failed_dev) {
- /* speed down */
- action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask);
-
- /* perform per-dev EH action only on the offending device */
- ehc->i.dev_action[failed_dev->devno] |=
- action & ATA_EH_PERDEV_MASK;
- action &= ~ATA_EH_PERDEV_MASK;
- }
-
- /* record autopsy result */
- ehc->i.dev = failed_dev;
- ehc->i.action = action;
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_eh_report - report error handling to user
- * @ap: ATA port EH is going on
- *
- * Report EH to user.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_report(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- const char *frozen, *desc;
- int tag, nr_failed = 0;
-
- desc = NULL;
- if (ehc->i.desc[0] != '\0')
- desc = ehc->i.desc;
-
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
-
- if (!(qc->flags & ATA_QCFLAG_FAILED))
- continue;
- if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
- continue;
-
- nr_failed++;
- }
-
- if (!nr_failed && !ehc->i.err_mask)
- return;
-
- frozen = "";
- if (ap->flags & ATA_FLAG_FROZEN)
- frozen = " frozen";
-
- if (ehc->i.dev) {
- ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
- if (desc)
- ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
- } else {
- ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
- if (desc)
- ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
- }
-
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
-
- if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
- continue;
-
- ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
- "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
- qc->tag, qc->tf.command, qc->err_mask,
- qc->result_tf.command, qc->result_tf.feature,
- ata_err_string(qc->err_mask));
- }
-}
-
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
- unsigned int *classes)
-{
- int i, rc;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
-
- rc = reset(ap, classes);
- if (rc)
- return rc;
-
- /* If any class isn't ATA_DEV_UNKNOWN, consider classification
- * is complete and convert all ATA_DEV_UNKNOWN to
- * ATA_DEV_NONE.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
- break;
-
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
-
- return 0;
-}
-
-static int ata_eh_followup_srst_needed(int rc, int classify,
- const unsigned int *classes)
-{
- if (rc == -EAGAIN)
- return 1;
- if (rc != 0)
- return 0;
- if (classify && classes[0] == ATA_DEV_UNKNOWN)
- return 1;
- return 0;
-}
-
-static int ata_eh_reset(struct ata_port *ap, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- unsigned int *classes = ehc->classes;
- int tries = ATA_EH_RESET_TRIES;
- int verbose = !(ap->flags & ATA_FLAG_LOADING);
- unsigned int action;
- ata_reset_fn_t reset;
- int i, did_followup_srst, rc;
-
- /* Determine which reset to use and record in ehc->i.action.
- * prereset() may examine and modify it.
- */
- action = ehc->i.action;
- ehc->i.action &= ~ATA_EH_RESET_MASK;
- if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
- !(action & ATA_EH_HARDRESET))))
- ehc->i.action |= ATA_EH_SOFTRESET;
- else
- ehc->i.action |= ATA_EH_HARDRESET;
-
- if (prereset) {
- rc = prereset(ap);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "prereset failed (errno=%d)\n", rc);
- return rc;
- }
- }
-
- /* prereset() might have modified ehc->i.action */
- if (ehc->i.action & ATA_EH_HARDRESET)
- reset = hardreset;
- else if (ehc->i.action & ATA_EH_SOFTRESET)
- reset = softreset;
- else {
- /* prereset told us not to reset, bang classes and return */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
- return 0;
- }
-
- /* did prereset() screw up? if so, fix up to avoid oopsing */
- if (!reset) {
- ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
- "invalid reset type\n");
- if (softreset)
- reset = softreset;
- else
- reset = hardreset;
- }
-
- retry:
- /* shut up during boot probing */
- if (verbose)
- ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
- reset == softreset ? "soft" : "hard");
-
- /* reset */
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- ehc->i.flags |= ATA_EHI_DID_RESET;
-
- rc = ata_do_reset(ap, reset, classes);
-
- did_followup_srst = 0;
- if (reset == hardreset &&
- ata_eh_followup_srst_needed(rc, classify, classes)) {
- /* okay, let's do follow-up softreset */
- did_followup_srst = 1;
- reset = softreset;
-
- if (!reset) {
- ata_port_printk(ap, KERN_ERR,
- "follow-up softreset required "
- "but no softreset avaliable\n");
- return -EINVAL;
- }
-
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- rc = ata_do_reset(ap, reset, classes);
-
- if (rc == 0 && classify &&
- classes[0] == ATA_DEV_UNKNOWN) {
- ata_port_printk(ap, KERN_ERR,
- "classification failed\n");
- return -EINVAL;
- }
- }
-
- if (rc && --tries) {
- const char *type;
-
- if (reset == softreset) {
- if (did_followup_srst)
- type = "follow-up soft";
- else
- type = "soft";
- } else
- type = "hard";
-
- ata_port_printk(ap, KERN_WARNING,
- "%sreset failed, retrying in 5 secs\n", type);
- ssleep(5);
-
- if (reset == hardreset)
- sata_down_spd_limit(ap);
- if (hardreset)
- reset = hardreset;
- goto retry;
- }
-
- if (rc == 0) {
- /* After the reset, the device state is PIO 0 and the
- * controller state is undefined. Record the mode.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
-
- if (postreset)
- postreset(ap, classes);
-
- /* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
- ehc->i.action |= ATA_EH_REVALIDATE;
- }
-
- return rc;
-}
-
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
- struct ata_device **r_failed_dev)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev;
- unsigned long flags;
- int i, rc = 0;
-
- DPRINTK("ENTER\n");
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- unsigned int action;
-
- dev = &ap->device[i];
- action = ehc->i.action | ehc->i.dev_action[dev->devno];
-
- if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
- if (ata_port_offline(ap)) {
- rc = -EIO;
- break;
- }
-
- ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev,
- ehc->i.flags & ATA_EHI_DID_RESET);
- if (rc)
- break;
-
- ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
-
- /* schedule the scsi_rescan_device() here */
- queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
- } else if (dev->class == ATA_DEV_UNKNOWN &&
- ehc->tries[dev->devno] &&
- ata_class_enabled(ehc->classes[dev->devno])) {
- dev->class = ehc->classes[dev->devno];
-
- rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
- if (rc == 0)
- rc = ata_dev_configure(dev, 1);
-
- if (rc) {
- dev->class = ATA_DEV_UNKNOWN;
- break;
- }
-
- spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
- spin_unlock_irqrestore(ap->lock, flags);
- }
- }
-
- if (rc)
- *r_failed_dev = dev;
-
- DPRINTK("EXIT\n");
- return rc;
-}
-
-static int ata_port_nr_enabled(struct ata_port *ap)
-{
- int i, cnt = 0;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
- cnt++;
- return cnt;
-}
-
-static int ata_port_nr_vacant(struct ata_port *ap)
-{
- int i, cnt = 0;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ap->device[i].class == ATA_DEV_UNKNOWN)
- cnt++;
- return cnt;
-}
-
-static int ata_eh_skip_recovery(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- int i;
-
- if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
- return 0;
-
- /* skip if class codes for all vacant slots are ATA_DEV_NONE */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
- if (dev->class == ATA_DEV_UNKNOWN &&
- ehc->classes[dev->devno] != ATA_DEV_NONE)
- return 0;
- }
-
- return 1;
-}
-
-/**
- * ata_eh_recover - recover host port after error
- * @ap: host port to recover
- * @prereset: prereset method (can be NULL)
- * @softreset: softreset method (can be NULL)
- * @hardreset: hardreset method (can be NULL)
- * @postreset: postreset method (can be NULL)
- *
- * This is the alpha and omega, eum and yang, heart and soul of
- * libata exception handling. On entry, actions required to
- * recover the port and hotplug requests are recorded in
- * eh_context. This function executes all the operations with
- * appropriate retrials and fallbacks to resurrect failed
- * devices, detach goners and greet newcomers.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev;
- int down_xfermask, i, rc;
-
- DPRINTK("ENTER\n");
-
- /* prep for recovery */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-
- /* process hotplug request */
- if (dev->flags & ATA_DFLAG_DETACH)
- ata_eh_detach_dev(dev);
-
- if (!ata_dev_enabled(dev) &&
- ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno)))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
- }
- }
-
- retry:
- down_xfermask = 0;
- rc = 0;
-
- /* if UNLOADING, finish immediately */
- if (ap->flags & ATA_FLAG_UNLOADING)
- goto out;
-
- /* skip EH if possible. */
- if (ata_eh_skip_recovery(ap))
- ehc->i.action = 0;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehc->classes[i] = ATA_DEV_UNKNOWN;
-
- /* reset */
- if (ehc->i.action & ATA_EH_RESET_MASK) {
- ata_eh_freeze_port(ap);
-
- rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
- softreset, hardreset, postreset);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
- }
-
- ata_eh_thaw_port(ap);
- }
-
- /* revalidate existing devices and attach new ones */
- rc = ata_eh_revalidate_and_attach(ap, &dev);
- if (rc)
- goto dev_fail;
-
- /* configure transfer mode if the port has been reset */
- if (ehc->i.flags & ATA_EHI_DID_RESET) {
- rc = ata_set_mode(ap, &dev);
- if (rc) {
- down_xfermask = 1;
- goto dev_fail;
- }
- }
-
- goto out;
-
- dev_fail:
- switch (rc) {
- case -ENODEV:
- /* device missing, schedule probing */
- ehc->i.probe_mask |= (1 << dev->devno);
- case -EINVAL:
- ehc->tries[dev->devno] = 0;
- break;
- case -EIO:
- sata_down_spd_limit(ap);
- default:
- ehc->tries[dev->devno]--;
- if (down_xfermask &&
- ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
- ehc->tries[dev->devno] = 0;
- }
-
- if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
- /* disable device if it has used up all its chances */
- ata_dev_disable(dev);
-
- /* detach if offline */
- if (ata_port_offline(ap))
- ata_eh_detach_dev(dev);
-
- /* probe if requested */
- if ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
- }
- } else {
- /* soft didn't work? be haaaaard */
- if (ehc->i.flags & ATA_EHI_DID_RESET)
- ehc->i.action |= ATA_EH_HARDRESET;
- else
- ehc->i.action |= ATA_EH_SOFTRESET;
- }
-
- if (ata_port_nr_enabled(ap)) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover some "
- "devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left, repeat fast */
- msleep(500);
- }
-
- goto retry;
-
- out:
- if (rc) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
- }
-
- DPRINTK("EXIT, rc=%d\n", rc);
- return rc;
-}
-
-/**
- * ata_eh_finish - finish up EH
- * @ap: host port to finish EH for
- *
- * Recovery is complete. Clean up EH states and retry or finish
- * failed qcs.
- *
- * LOCKING:
- * None.
- */
-static void ata_eh_finish(struct ata_port *ap)
-{
- int tag;
-
- /* retry or finish qcs */
- for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
- struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
-
- if (!(qc->flags & ATA_QCFLAG_FAILED))
- continue;
-
- if (qc->err_mask) {
- /* FIXME: Once EH migration is complete,
- * generate sense data in this function,
- * considering both err_mask and tf.
- */
- if (qc->err_mask & AC_ERR_INVALID)
- ata_eh_qc_complete(qc);
- else
- ata_eh_qc_retry(qc);
- } else {
- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
- ata_eh_qc_complete(qc);
- } else {
- /* feed zero TF to sense generation */
- memset(&qc->result_tf, 0, sizeof(qc->result_tf));
- ata_eh_qc_retry(qc);
- }
- }
- }
-}
-
-/**
- * ata_do_eh - do standard error handling
- * @ap: host port to handle error for
- * @prereset: prereset method (can be NULL)
- * @softreset: softreset method (can be NULL)
- * @hardreset: hardreset method (can be NULL)
- * @postreset: postreset method (can be NULL)
- *
- * Perform standard error handling sequence.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
-{
- if (!(ap->flags & ATA_FLAG_LOADING)) {
- ata_eh_autopsy(ap);
- ata_eh_report(ap);
- }
-
- ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
- ata_eh_finish(ap);
-}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
deleted file mode 100644
index 93d18a74c40..00000000000
--- a/drivers/scsi/libata-scsi.c
+++ /dev/null
@@ -1,3052 +0,0 @@
-/*
- * libata-scsi.c - helper library for ATA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2004 Jeff Garzik
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available from
- * - http://www.t10.org/
- * - http://www.t13.org/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_transport.h>
-#include <linux/libata.h>
-#include <linux/hdreg.h>
-#include <asm/uaccess.h>
-
-#include "libata.h"
-
-#define SECTOR_SIZE 512
-
-typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
-
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
- const struct scsi_device *scsidev);
-static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
- const struct scsi_device *scsidev);
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
- unsigned int id, unsigned int lun);
-
-
-#define RW_RECOVERY_MPAGE 0x1
-#define RW_RECOVERY_MPAGE_LEN 12
-#define CACHE_MPAGE 0x8
-#define CACHE_MPAGE_LEN 20
-#define CONTROL_MPAGE 0xa
-#define CONTROL_MPAGE_LEN 12
-#define ALL_MPAGES 0x3f
-#define ALL_SUB_MPAGES 0xff
-
-
-static const u8 def_rw_recovery_mpage[] = {
- RW_RECOVERY_MPAGE,
- RW_RECOVERY_MPAGE_LEN - 2,
- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
- (1 << 6), /* ARRE (auto read reallocation) */
- 0, /* read retry count */
- 0, 0, 0, 0,
- 0, /* write retry count */
- 0, 0, 0
-};
-
-static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {
- CACHE_MPAGE,
- CACHE_MPAGE_LEN - 2,
- 0, /* contains WCE, needs to be 0 for logic */
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, /* contains DRA, needs to be 0 for logic */
- 0, 0, 0, 0, 0, 0, 0
-};
-
-static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
- CONTROL_MPAGE,
- CONTROL_MPAGE_LEN - 2,
- 2, /* DSENSE=0, GLTSD=1 */
- 0, /* [QAM+QERR may be 1, see 05-359r1] */
- 0, 0, 0, 0, 0xff, 0xff,
- 0, 30 /* extended self test time, see 05-359r1 */
-};
-
-/*
- * libata transport template. libata doesn't do real transport stuff.
- * It just needs the eh_timed_out hook.
- */
-struct scsi_transport_template ata_scsi_transport_template = {
- .eh_strategy_handler = ata_scsi_error,
- .eh_timed_out = ata_scsi_timed_out,
- .user_scan = ata_scsi_user_scan,
-};
-
-
-static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
-{
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
- done(cmd);
-}
-
-/**
- * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
- * @sdev: SCSI device for which BIOS geometry is to be determined
- * @bdev: block device associated with @sdev
- * @capacity: capacity of SCSI device
- * @geom: location to which geometry will be output
- *
- * Generic bios head/sector/cylinder calculator
- * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS)
- * mapping. Some situations may arise where the disk is not
- * bootable if this is not used.
- *
- * LOCKING:
- * Defined by the SCSI layer. We don't really care.
- *
- * RETURNS:
- * Zero.
- */
-int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int geom[])
-{
- geom[0] = 255;
- geom[1] = 63;
- sector_div(capacity, 255*63);
- geom[2] = capacity;
-
- return 0;
-}
-
-/**
- * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
- * @scsidev: Device to which we are issuing command
- * @arg: User provided data for issuing command
- *
- * LOCKING:
- * Defined by the SCSI layer. We don't really care.
- *
- * RETURNS:
- * Zero on success, negative errno on error.
- */
-
-int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
-{
- int rc = 0;
- u8 scsi_cmd[MAX_COMMAND_SIZE];
- u8 args[4], *argbuf = NULL;
- int argsize = 0;
- struct scsi_sense_hdr sshdr;
- enum dma_data_direction data_dir;
-
- if (arg == NULL)
- return -EINVAL;
-
- if (copy_from_user(args, arg, sizeof(args)))
- return -EFAULT;
-
- memset(scsi_cmd, 0, sizeof(scsi_cmd));
-
- if (args[3]) {
- argsize = SECTOR_SIZE * args[3];
- argbuf = kmalloc(argsize, GFP_KERNEL);
- if (argbuf == NULL) {
- rc = -ENOMEM;
- goto error;
- }
-
- scsi_cmd[1] = (4 << 1); /* PIO Data-in */
- scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
- block count in sector count field */
- data_dir = DMA_FROM_DEVICE;
- } else {
- scsi_cmd[1] = (3 << 1); /* Non-data */
- /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
- data_dir = DMA_NONE;
- }
-
- scsi_cmd[0] = ATA_16;
-
- scsi_cmd[4] = args[2];
- if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
- scsi_cmd[6] = args[3];
- scsi_cmd[8] = args[1];
- scsi_cmd[10] = 0x4f;
- scsi_cmd[12] = 0xc2;
- } else {
- scsi_cmd[6] = args[1];
- }
- scsi_cmd[14] = args[0];
-
- /* Good values for timeout and retries? Values below
- from scsi_ioctl_send_command() for default case... */
- if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- &sshdr, (10*HZ), 5)) {
- rc = -EIO;
- goto error;
- }
-
- /* Need code to retrieve data from check condition? */
-
- if ((argbuf)
- && copy_to_user(arg + sizeof(args), argbuf, argsize))
- rc = -EFAULT;
-error:
- if (argbuf)
- kfree(argbuf);
-
- return rc;
-}
-
-/**
- * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
- * @scsidev: Device to which we are issuing command
- * @arg: User provided data for issuing command
- *
- * LOCKING:
- * Defined by the SCSI layer. We don't really care.
- *
- * RETURNS:
- * Zero on success, negative errno on error.
- */
-int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
-{
- int rc = 0;
- u8 scsi_cmd[MAX_COMMAND_SIZE];
- u8 args[7];
- struct scsi_sense_hdr sshdr;
-
- if (arg == NULL)
- return -EINVAL;
-
- if (copy_from_user(args, arg, sizeof(args)))
- return -EFAULT;
-
- memset(scsi_cmd, 0, sizeof(scsi_cmd));
- scsi_cmd[0] = ATA_16;
- scsi_cmd[1] = (3 << 1); /* Non-data */
- /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
- scsi_cmd[4] = args[1];
- scsi_cmd[6] = args[2];
- scsi_cmd[8] = args[3];
- scsi_cmd[10] = args[4];
- scsi_cmd[12] = args[5];
- scsi_cmd[14] = args[0];
-
- /* Good values for timeout and retries? Values below
- from scsi_ioctl_send_command() for default case... */
- if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr,
- (10*HZ), 5))
- rc = -EIO;
-
- /* Need code to retrieve data from check condition? */
- return rc;
-}
-
-int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
-{
- int val = -EINVAL, rc = -EINVAL;
-
- switch (cmd) {
- case ATA_IOC_GET_IO32:
- val = 0;
- if (copy_to_user(arg, &val, 1))
- return -EFAULT;
- return 0;
-
- case ATA_IOC_SET_IO32:
- val = (unsigned long) arg;
- if (val != 0)
- return -EINVAL;
- return 0;
-
- case HDIO_DRIVE_CMD:
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- return ata_cmd_ioctl(scsidev, arg);
-
- case HDIO_DRIVE_TASK:
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- return ata_task_ioctl(scsidev, arg);
-
- default:
- rc = -ENOTTY;
- break;
- }
-
- return rc;
-}
-
-/**
- * ata_scsi_qc_new - acquire new ata_queued_cmd reference
- * @dev: ATA device to which the new command is attached
- * @cmd: SCSI command that originated this ATA command
- * @done: SCSI command completion function
- *
- * Obtain a reference to an unused ata_queued_cmd structure,
- * which is the basic libata structure representing a single
- * ATA command sent to the hardware.
- *
- * If a command was available, fill in the SCSI-specific
- * portions of the structure with information on the
- * current command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Command allocated, or %NULL if none available.
- */
-struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
-{
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_new_init(dev);
- if (qc) {
- qc->scsicmd = cmd;
- qc->scsidone = done;
-
- if (cmd->use_sg) {
- qc->__sg = (struct scatterlist *) cmd->request_buffer;
- qc->n_elem = cmd->use_sg;
- } else {
- qc->__sg = &qc->sgent;
- qc->n_elem = 1;
- }
- } else {
- cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
- done(cmd);
- }
-
- return qc;
-}
-
-/**
- * ata_dump_status - user friendly display of error info
- * @id: id of the port in question
- * @tf: ptr to filled out taskfile
- *
- * Decode and dump the ATA error/status registers for the user so
- * that they have some idea what really happened at the non
- * make-believe layer.
- *
- * LOCKING:
- * inherited from caller
- */
-void ata_dump_status(unsigned id, struct ata_taskfile *tf)
-{
- u8 stat = tf->command, err = tf->feature;
-
- printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat);
- if (stat & ATA_BUSY) {
- printk("Busy }\n"); /* Data is not valid in this case */
- } else {
- if (stat & 0x40) printk("DriveReady ");
- if (stat & 0x20) printk("DeviceFault ");
- if (stat & 0x10) printk("SeekComplete ");
- if (stat & 0x08) printk("DataRequest ");
- if (stat & 0x04) printk("CorrectedError ");
- if (stat & 0x02) printk("Index ");
- if (stat & 0x01) printk("Error ");
- printk("}\n");
-
- if (err) {
- printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);
- if (err & 0x04) printk("DriveStatusError ");
- if (err & 0x80) {
- if (err & 0x04) printk("BadCRC ");
- else printk("Sector ");
- }
- if (err & 0x40) printk("UncorrectableError ");
- if (err & 0x10) printk("SectorIdNotFound ");
- if (err & 0x02) printk("TrackZeroNotFound ");
- if (err & 0x01) printk("AddrMarkNotFound ");
- printk("}\n");
- }
- }
-}
-
-int ata_scsi_device_resume(struct scsi_device *sdev)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_resume(dev);
-}
-
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- return ata_device_suspend(dev, state);
-}
-
-/**
- * ata_to_sense_error - convert ATA error to SCSI error
- * @id: ATA device number
- * @drv_stat: value contained in ATA status register
- * @drv_err: value contained in ATA error register
- * @sk: the sense key we'll fill out
- * @asc: the additional sense code we'll fill out
- * @ascq: the additional sense code qualifier we'll fill out
- * @verbose: be verbose
- *
- * Converts an ATA error into a SCSI error. Fill out pointers to
- * SK, ASC, and ASCQ bytes for later use in fixed or descriptor
- * format sense blocks.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
- u8 *ascq, int verbose)
-{
- int i;
-
- /* Based on the 3ware driver translation table */
- static const unsigned char sense_table[][4] = {
- /* BBD|ECC|ID|MAR */
- {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
- /* BBD|ECC|ID */
- {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
- /* ECC|MC|MARK */
- {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error
- /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */
- {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error
- /* MC|ID|ABRT|TRK0|MARK */
- {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready
- /* MCR|MARK */
- {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready
- /* Bad address mark */
- {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
- /* TRK0 */
- {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
- /* Abort & !ICRC */
- {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
- /* Media change request */
- {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
- /* SRV */
- {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
- /* Media change */
- {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
- /* ECC */
- {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
- /* BBD - block marked bad */
- {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
- {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
- };
- static const unsigned char stat_table[][4] = {
- /* Must be first because BUSY means no other bits valid */
- {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
- {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
- {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
- {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
- {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
- };
-
- /*
- * Is this an error we can process/parse
- */
- if (drv_stat & ATA_BUSY) {
- drv_err = 0; /* Ignore the err bits, they're invalid */
- }
-
- if (drv_err) {
- /* Look for drv_err */
- for (i = 0; sense_table[i][0] != 0xFF; i++) {
- /* Look for best matches first */
- if ((sense_table[i][0] & drv_err) ==
- sense_table[i][0]) {
- *sk = sense_table[i][1];
- *asc = sense_table[i][2];
- *ascq = sense_table[i][3];
- goto translate_done;
- }
- }
- /* No immediate match */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "error 0x%02x\n", id, drv_err);
- }
-
- /* Fall back to interpreting status bits */
- for (i = 0; stat_table[i][0] != 0xFF; i++) {
- if (stat_table[i][0] & drv_stat) {
- *sk = stat_table[i][1];
- *asc = stat_table[i][2];
- *ascq = stat_table[i][3];
- goto translate_done;
- }
- }
- /* No error? Undecoded? */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "status: 0x%02x\n", id, drv_stat);
-
- /* We need a sensible error return here, which is tricky, and one
- that won't cause people to do things like return a disk wrongly */
- *sk = ABORTED_COMMAND;
- *asc = 0x00;
- *ascq = 0x00;
-
- translate_done:
- if (verbose)
- printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
- "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
- id, drv_stat, drv_err, *sk, *asc, *ascq);
- return;
-}
-
-/*
- * ata_gen_ata_desc_sense - Generate check condition sense block.
- * @qc: Command that completed.
- *
- * This function is specific to the ATA descriptor format sense
- * block specified for the ATA pass through commands. Regardless
- * of whether the command errored or not, return a sense
- * block. Copy all controller registers into the sense
- * block. Clear sense key, ASC & ASCQ if there is no error.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_taskfile *tf = &qc->result_tf;
- unsigned char *sb = cmd->sense_buffer;
- unsigned char *desc = sb + 8;
- int verbose = qc->ap->ops->error_handler == NULL;
-
- memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
-
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- /*
- * Use ata_to_sense_error() to map status register bits
- * onto sense key, asc & ascq.
- */
- if (qc->err_mask ||
- tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
- &sb[1], &sb[2], &sb[3], verbose);
- sb[1] &= 0x0f;
- }
-
- /*
- * Sense data is current and format is descriptor.
- */
- sb[0] = 0x72;
-
- desc[0] = 0x09;
-
- /*
- * Set length of additional sense data.
- * Since we only populate descriptor 0, the total
- * length is the same (fixed) length as descriptor 0.
- */
- desc[1] = sb[7] = 14;
-
- /*
- * Copy registers into sense buffer.
- */
- desc[2] = 0x00;
- desc[3] = tf->feature; /* == error reg */
- desc[5] = tf->nsect;
- desc[7] = tf->lbal;
- desc[9] = tf->lbam;
- desc[11] = tf->lbah;
- desc[12] = tf->device;
- desc[13] = tf->command; /* == status reg */
-
- /*
- * Fill in Extend bit, and the high order bytes
- * if applicable.
- */
- if (tf->flags & ATA_TFLAG_LBA48) {
- desc[2] |= 0x01;
- desc[4] = tf->hob_nsect;
- desc[6] = tf->hob_lbal;
- desc[8] = tf->hob_lbam;
- desc[10] = tf->hob_lbah;
- }
-}
-
-/**
- * ata_gen_fixed_sense - generate a SCSI fixed sense block
- * @qc: Command that we are erroring out
- *
- * Leverage ata_to_sense_error() to give us the codes. Fit our
- * LBA in here if there's room.
- *
- * LOCKING:
- * inherited from caller
- */
-void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_taskfile *tf = &qc->result_tf;
- unsigned char *sb = cmd->sense_buffer;
- int verbose = qc->ap->ops->error_handler == NULL;
-
- memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
-
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- /*
- * Use ata_to_sense_error() to map status register bits
- * onto sense key, asc & ascq.
- */
- if (qc->err_mask ||
- tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
- &sb[2], &sb[12], &sb[13], verbose);
- sb[2] &= 0x0f;
- }
-
- sb[0] = 0x70;
- sb[7] = 0x0a;
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- /* TODO: find solution for LBA48 descriptors */
- }
-
- else if (tf->flags & ATA_TFLAG_LBA) {
- /* A small (28b) LBA will fit in the 32b info field */
- sb[0] |= 0x80; /* set valid bit */
- sb[3] = tf->device & 0x0f;
- sb[4] = tf->lbah;
- sb[5] = tf->lbam;
- sb[6] = tf->lbal;
- }
-
- else {
- /* TODO: C/H/S */
- }
-}
-
-static void ata_scsi_sdev_config(struct scsi_device *sdev)
-{
- sdev->use_10_for_rw = 1;
- sdev->use_10_for_ms = 1;
-}
-
-static void ata_scsi_dev_config(struct scsi_device *sdev,
- struct ata_device *dev)
-{
- unsigned int max_sectors;
-
- /* TODO: 2048 is an arbitrary number, not the
- * hardware maximum. This should be increased to
- * 65534 when Jens Axboe's patch for dynamically
- * determining max_sectors is merged.
- */
- max_sectors = ATA_MAX_SECTORS;
- if (dev->flags & ATA_DFLAG_LBA48)
- max_sectors = ATA_MAX_SECTORS_LBA48;
- if (dev->max_sectors)
- max_sectors = dev->max_sectors;
-
- blk_queue_max_sectors(sdev->request_queue, max_sectors);
-
- /*
- * SATA DMA transfers must be multiples of 4 byte, so
- * we need to pad ATAPI transfers using an extra sg.
- * Decrement max hw segments accordingly.
- */
- if (dev->class == ATA_DEV_ATAPI) {
- request_queue_t *q = sdev->request_queue;
- blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
- }
-
- if (dev->flags & ATA_DFLAG_NCQ) {
- int depth;
-
- depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
- depth = min(ATA_MAX_QUEUE - 1, depth);
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
- }
-}
-
-/**
- * ata_scsi_slave_config - Set SCSI device attributes
- * @sdev: SCSI device to examine
- *
- * This is called before we actually start reading
- * and writing to the device, to configure certain
- * SCSI mid-layer behaviors.
- *
- * LOCKING:
- * Defined by SCSI layer. We don't really care.
- */
-
-int ata_scsi_slave_config(struct scsi_device *sdev)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
-
- ata_scsi_sdev_config(sdev);
-
- blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
-
- if (dev)
- ata_scsi_dev_config(sdev, dev);
-
- return 0; /* scsi layer doesn't check return value, sigh */
-}
-
-/**
- * ata_scsi_slave_destroy - SCSI device is about to be destroyed
- * @sdev: SCSI device to be destroyed
- *
- * @sdev is about to be destroyed for hot/warm unplugging. If
- * this unplugging was initiated by libata as indicated by NULL
- * dev->sdev, this function doesn't have to do anything.
- * Otherwise, SCSI layer initiated warm-unplug is in progress.
- * Clear dev->sdev, schedule the device for ATA detach and invoke
- * EH.
- *
- * LOCKING:
- * Defined by SCSI layer. We don't really care.
- */
-void ata_scsi_slave_destroy(struct scsi_device *sdev)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- unsigned long flags;
- struct ata_device *dev;
-
- if (!ap->ops->error_handler)
- return;
-
- spin_lock_irqsave(ap->lock, flags);
- dev = __ata_scsi_find_dev(ap, sdev);
- if (dev && dev->sdev) {
- /* SCSI device already in CANCEL state, no need to offline it */
- dev->sdev = NULL;
- dev->flags |= ATA_DFLAG_DETACH;
- ata_port_schedule_eh(ap);
- }
- spin_unlock_irqrestore(ap->lock, flags);
-}
-
-/**
- * ata_scsi_change_queue_depth - SCSI callback for queue depth config
- * @sdev: SCSI device to configure queue depth for
- * @queue_depth: new queue depth
- *
- * This is libata standard hostt->change_queue_depth callback.
- * SCSI will call into this callback when user tries to set queue
- * depth via sysfs.
- *
- * LOCKING:
- * SCSI layer (we don't care)
- *
- * RETURNS:
- * Newly configured queue depth.
- */
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
-{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev;
- int max_depth;
-
- if (queue_depth < 1)
- return sdev->queue_depth;
-
- dev = ata_scsi_find_dev(ap, sdev);
- if (!dev || !ata_dev_enabled(dev))
- return sdev->queue_depth;
-
- max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
- max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
- if (queue_depth > max_depth)
- queue_depth = max_depth;
-
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
- return queue_depth;
-}
-
-/**
- * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
- * @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
- *
- * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
- * (to start). Perhaps these commands should be preceded by
- * CHECK POWER MODE to see what power mode the device is already in.
- * [See SAT revision 5 at www.t10.org]
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, non-zero on error.
- */
-
-static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
- const u8 *scsicmd)
-{
- struct ata_taskfile *tf = &qc->tf;
-
- tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
- tf->protocol = ATA_PROT_NODATA;
- if (scsicmd[1] & 0x1) {
- ; /* ignore IMMED bit, violates sat-r05 */
- }
- if (scsicmd[4] & 0x2)
- goto invalid_fld; /* LOEJ bit set not supported */
- if (((scsicmd[4] >> 4) & 0xf) != 0)
- goto invalid_fld; /* power conditions not supported */
- if (scsicmd[4] & 0x1) {
- tf->nsect = 1; /* 1 sector, lba=0 */
-
- if (qc->dev->flags & ATA_DFLAG_LBA) {
- tf->flags |= ATA_TFLAG_LBA;
-
- tf->lbah = 0x0;
- tf->lbam = 0x0;
- tf->lbal = 0x0;
- tf->device |= ATA_LBA;
- } else {
- /* CHS */
- tf->lbal = 0x1; /* sect */
- tf->lbam = 0x0; /* cyl low */
- tf->lbah = 0x0; /* cyl high */
- }
-
- tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
- } else {
- tf->nsect = 0; /* time period value (0 implies now) */
- tf->command = ATA_CMD_STANDBY;
- /* Consider: ATA STANDBY IMMEDIATE command */
- }
- /*
- * Standby and Idle condition timers could be implemented but that
- * would require libata to implement the Power condition mode page
- * and allow the user to change it. Changing mode pages requires
- * MODE SELECT to be implemented.
- */
-
- return 0;
-
-invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
- return 1;
-}
-
-
-/**
- * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
- * @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate (ignored)
- *
- * Sets up an ATA taskfile to issue FLUSH CACHE or
- * FLUSH CACHE EXT.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, non-zero on error.
- */
-
-static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
-{
- struct ata_taskfile *tf = &qc->tf;
-
- tf->flags |= ATA_TFLAG_DEVICE;
- tf->protocol = ATA_PROT_NODATA;
-
- if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
- (ata_id_has_flush_ext(qc->dev->id)))
- tf->command = ATA_CMD_FLUSH_EXT;
- else
- tf->command = ATA_CMD_FLUSH;
-
- return 0;
-}
-
-/**
- * scsi_6_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
- *
- * Calculate LBA and transfer length for 6-byte commands.
- *
- * RETURNS:
- * @plba: the LBA
- * @plen: the transfer length
- */
-
-static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
-{
- u64 lba = 0;
- u32 len = 0;
-
- VPRINTK("six-byte command\n");
-
- lba |= ((u64)scsicmd[2]) << 8;
- lba |= ((u64)scsicmd[3]);
-
- len |= ((u32)scsicmd[4]);
-
- *plba = lba;
- *plen = len;
-}
-
-/**
- * scsi_10_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
- *
- * Calculate LBA and transfer length for 10-byte commands.
- *
- * RETURNS:
- * @plba: the LBA
- * @plen: the transfer length
- */
-
-static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
-{
- u64 lba = 0;
- u32 len = 0;
-
- VPRINTK("ten-byte command\n");
-
- lba |= ((u64)scsicmd[2]) << 24;
- lba |= ((u64)scsicmd[3]) << 16;
- lba |= ((u64)scsicmd[4]) << 8;
- lba |= ((u64)scsicmd[5]);
-
- len |= ((u32)scsicmd[7]) << 8;
- len |= ((u32)scsicmd[8]);
-
- *plba = lba;
- *plen = len;
-}
-
-/**
- * scsi_16_lba_len - Get LBA and transfer length
- * @scsicmd: SCSI command to translate
- *
- * Calculate LBA and transfer length for 16-byte commands.
- *
- * RETURNS:
- * @plba: the LBA
- * @plen: the transfer length
- */
-
-static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
-{
- u64 lba = 0;
- u32 len = 0;
-
- VPRINTK("sixteen-byte command\n");
-
- lba |= ((u64)scsicmd[2]) << 56;
- lba |= ((u64)scsicmd[3]) << 48;
- lba |= ((u64)scsicmd[4]) << 40;
- lba |= ((u64)scsicmd[5]) << 32;
- lba |= ((u64)scsicmd[6]) << 24;
- lba |= ((u64)scsicmd[7]) << 16;
- lba |= ((u64)scsicmd[8]) << 8;
- lba |= ((u64)scsicmd[9]);
-
- len |= ((u32)scsicmd[10]) << 24;
- len |= ((u32)scsicmd[11]) << 16;
- len |= ((u32)scsicmd[12]) << 8;
- len |= ((u32)scsicmd[13]);
-
- *plba = lba;
- *plen = len;
-}
-
-/**
- * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
- * @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
- *
- * Converts SCSI VERIFY command to an ATA READ VERIFY command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, non-zero on error.
- */
-
-static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
-{
- struct ata_taskfile *tf = &qc->tf;
- struct ata_device *dev = qc->dev;
- u64 dev_sectors = qc->dev->n_sectors;
- u64 block;
- u32 n_block;
-
- tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- tf->protocol = ATA_PROT_NODATA;
-
- if (scsicmd[0] == VERIFY)
- scsi_10_lba_len(scsicmd, &block, &n_block);
- else if (scsicmd[0] == VERIFY_16)
- scsi_16_lba_len(scsicmd, &block, &n_block);
- else
- goto invalid_fld;
-
- if (!n_block)
- goto nothing_to_do;
- if (block >= dev_sectors)
- goto out_of_range;
- if ((block + n_block) > dev_sectors)
- goto out_of_range;
-
- if (dev->flags & ATA_DFLAG_LBA) {
- tf->flags |= ATA_TFLAG_LBA;
-
- if (lba_28_ok(block, n_block)) {
- /* use LBA28 */
- tf->command = ATA_CMD_VERIFY;
- tf->device |= (block >> 24) & 0xf;
- } else if (lba_48_ok(block, n_block)) {
- if (!(dev->flags & ATA_DFLAG_LBA48))
- goto out_of_range;
-
- /* use LBA48 */
- tf->flags |= ATA_TFLAG_LBA48;
- tf->command = ATA_CMD_VERIFY_EXT;
-
- tf->hob_nsect = (n_block >> 8) & 0xff;
-
- tf->hob_lbah = (block >> 40) & 0xff;
- tf->hob_lbam = (block >> 32) & 0xff;
- tf->hob_lbal = (block >> 24) & 0xff;
- } else
- /* request too large even for LBA48 */
- goto out_of_range;
-
- tf->nsect = n_block & 0xff;
-
- tf->lbah = (block >> 16) & 0xff;
- tf->lbam = (block >> 8) & 0xff;
- tf->lbal = block & 0xff;
-
- tf->device |= ATA_LBA;
- } else {
- /* CHS */
- u32 sect, head, cyl, track;
-
- if (!lba_28_ok(block, n_block))
- goto out_of_range;
-
- /* Convert LBA to CHS */
- track = (u32)block / dev->sectors;
- cyl = track / dev->heads;
- head = track % dev->heads;
- sect = (u32)block % dev->sectors + 1;
-
- DPRINTK("block %u track %u cyl %u head %u sect %u\n",
- (u32)block, track, cyl, head, sect);
-
- /* Check whether the converted CHS can fit.
- Cylinder: 0-65535
- Head: 0-15
- Sector: 1-255*/
- if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
- goto out_of_range;
-
- tf->command = ATA_CMD_VERIFY;
- tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
- tf->lbal = sect;
- tf->lbam = cyl;
- tf->lbah = cyl >> 8;
- tf->device |= head;
- }
-
- return 0;
-
-invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
- return 1;
-
-out_of_range:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
- /* "Logical Block Address out of range" */
- return 1;
-
-nothing_to_do:
- qc->scsicmd->result = SAM_STAT_GOOD;
- return 1;
-}
-
-/**
- * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
- * @qc: Storage for translated ATA taskfile
- * @scsicmd: SCSI command to translate
- *
- * Converts any of six SCSI read/write commands into the
- * ATA counterpart, including starting sector (LBA),
- * sector count, and taking into account the device's LBA48
- * support.
- *
- * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
- * %WRITE_16 are currently supported.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, non-zero on error.
- */
-
-static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
-{
- struct ata_taskfile *tf = &qc->tf;
- struct ata_device *dev = qc->dev;
- u64 block;
- u32 n_block;
-
- qc->flags |= ATA_QCFLAG_IO;
- tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-
- if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
- scsicmd[0] == WRITE_16)
- tf->flags |= ATA_TFLAG_WRITE;
-
- /* Calculate the SCSI LBA, transfer length and FUA. */
- switch (scsicmd[0]) {
- case READ_10:
- case WRITE_10:
- scsi_10_lba_len(scsicmd, &block, &n_block);
- if (unlikely(scsicmd[1] & (1 << 3)))
- tf->flags |= ATA_TFLAG_FUA;
- break;
- case READ_6:
- case WRITE_6:
- scsi_6_lba_len(scsicmd, &block, &n_block);
-
- /* for 6-byte r/w commands, transfer length 0
- * means 256 blocks of data, not 0 block.
- */
- if (!n_block)
- n_block = 256;
- break;
- case READ_16:
- case WRITE_16:
- scsi_16_lba_len(scsicmd, &block, &n_block);
- if (unlikely(scsicmd[1] & (1 << 3)))
- tf->flags |= ATA_TFLAG_FUA;
- break;
- default:
- DPRINTK("no-byte command\n");
- goto invalid_fld;
- }
-
- /* Check and compose ATA command */
- if (!n_block)
- /* For 10-byte and 16-byte SCSI R/W commands, transfer
- * length 0 means transfer 0 block of data.
- * However, for ATA R/W commands, sector count 0 means
- * 256 or 65536 sectors, not 0 sectors as in SCSI.
- *
- * WARNING: one or two older ATA drives treat 0 as 0...
- */
- goto nothing_to_do;
-
- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
- /* yay, NCQ */
- if (!lba_48_ok(block, n_block))
- goto out_of_range;
-
- tf->protocol = ATA_PROT_NCQ;
- tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
-
- if (tf->flags & ATA_TFLAG_WRITE)
- tf->command = ATA_CMD_FPDMA_WRITE;
- else
- tf->command = ATA_CMD_FPDMA_READ;
-
- qc->nsect = n_block;
-
- tf->nsect = qc->tag << 3;
- tf->hob_feature = (n_block >> 8) & 0xff;
- tf->feature = n_block & 0xff;
-
- tf->hob_lbah = (block >> 40) & 0xff;
- tf->hob_lbam = (block >> 32) & 0xff;
- tf->hob_lbal = (block >> 24) & 0xff;
- tf->lbah = (block >> 16) & 0xff;
- tf->lbam = (block >> 8) & 0xff;
- tf->lbal = block & 0xff;
-
- tf->device = 1 << 6;
- if (tf->flags & ATA_TFLAG_FUA)
- tf->device |= 1 << 7;
- } else if (dev->flags & ATA_DFLAG_LBA) {
- tf->flags |= ATA_TFLAG_LBA;
-
- if (lba_28_ok(block, n_block)) {
- /* use LBA28 */
- tf->device |= (block >> 24) & 0xf;
- } else if (lba_48_ok(block, n_block)) {
- if (!(dev->flags & ATA_DFLAG_LBA48))
- goto out_of_range;
-
- /* use LBA48 */
- tf->flags |= ATA_TFLAG_LBA48;
-
- tf->hob_nsect = (n_block >> 8) & 0xff;
-
- tf->hob_lbah = (block >> 40) & 0xff;
- tf->hob_lbam = (block >> 32) & 0xff;
- tf->hob_lbal = (block >> 24) & 0xff;
- } else
- /* request too large even for LBA48 */
- goto out_of_range;
-
- if (unlikely(ata_rwcmd_protocol(qc) < 0))
- goto invalid_fld;
-
- qc->nsect = n_block;
- tf->nsect = n_block & 0xff;
-
- tf->lbah = (block >> 16) & 0xff;
- tf->lbam = (block >> 8) & 0xff;
- tf->lbal = block & 0xff;
-
- tf->device |= ATA_LBA;
- } else {
- /* CHS */
- u32 sect, head, cyl, track;
-
- /* The request -may- be too large for CHS addressing. */
- if (!lba_28_ok(block, n_block))
- goto out_of_range;
-
- if (unlikely(ata_rwcmd_protocol(qc) < 0))
- goto invalid_fld;
-
- /* Convert LBA to CHS */
- track = (u32)block / dev->sectors;
- cyl = track / dev->heads;
- head = track % dev->heads;
- sect = (u32)block % dev->sectors + 1;
-
- DPRINTK("block %u track %u cyl %u head %u sect %u\n",
- (u32)block, track, cyl, head, sect);
-
- /* Check whether the converted CHS can fit.
- Cylinder: 0-65535
- Head: 0-15
- Sector: 1-255*/
- if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
- goto out_of_range;
-
- qc->nsect = n_block;
- tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
- tf->lbal = sect;
- tf->lbam = cyl;
- tf->lbah = cyl >> 8;
- tf->device |= head;
- }
-
- return 0;
-
-invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
- return 1;
-
-out_of_range:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
- /* "Logical Block Address out of range" */
- return 1;
-
-nothing_to_do:
- qc->scsicmd->result = SAM_STAT_GOOD;
- return 1;
-}
-
-static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *cmd = qc->scsicmd;
- u8 *cdb = cmd->cmnd;
- int need_sense = (qc->err_mask != 0);
-
- /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
- * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
- * cache
- */
- if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
- ((qc->tf.feature == SETFEATURES_WC_ON) ||
- (qc->tf.feature == SETFEATURES_WC_OFF))) {
- qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
- ata_port_schedule_eh(qc->ap);
- }
-
- /* For ATA pass thru (SAT) commands, generate a sense block if
- * user mandated it or if there's an error. Note that if we
- * generate because the user forced us to, a check condition
- * is generated and the ATA register values are returned
- * whether the command completed successfully or not. If there
- * was no error, SK, ASC and ASCQ will all be zero.
- */
- if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
- ((cdb[2] & 0x20) || need_sense)) {
- ata_gen_ata_desc_sense(qc);
- } else {
- if (!need_sense) {
- cmd->result = SAM_STAT_GOOD;
- } else {
- /* TODO: decide which descriptor format to use
- * for 48b LBA devices and call that here
- * instead of the fixed desc, which is only
- * good for smaller LBA (and maybe CHS?)
- * devices.
- */
- ata_gen_fixed_sense(qc);
- }
- }
-
- if (need_sense && !qc->ap->ops->error_handler)
- ata_dump_status(qc->ap->id, &qc->result_tf);
-
- qc->scsidone(cmd);
-
- ata_qc_free(qc);
-}
-
-/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_port *ap = dev->ap;
-
- if (!(dev->flags & ATA_DFLAG_NCQ))
- return 0;
-
- if (is_io) {
- if (!ata_tag_valid(ap->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
- * ata_scsi_translate - Translate then issue SCSI command to ATA device
- * @dev: ATA device to which the command is addressed
- * @cmd: SCSI command to execute
- * @done: SCSI command completion function
- * @xlat_func: Actor which translates @cmd to an ATA taskfile
- *
- * Our ->queuecommand() function has decided that the SCSI
- * command issued can be directly translated into an ATA
- * command, rather than handled internally.
- *
- * This function sets up an ata_queued_cmd structure for the
- * SCSI command, and sends that ata_queued_cmd to the hardware.
- *
- * The xlat_func argument (actor) returns 0 if ready to execute
- * ATA command, else 1 to finish translation. If 1 is returned
- * then cmd->result (and possibly cmd->sense_buffer) are assumed
- * to be set reflecting an error condition or clean (early)
- * termination.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
- * needs to be deferred.
- */
-static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- ata_xlat_func_t xlat_func)
-{
- struct ata_queued_cmd *qc;
- u8 *scsicmd = cmd->cmnd;
- int is_io = xlat_func == ata_scsi_rw_xlat;
-
- VPRINTK("ENTER\n");
-
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
- qc = ata_scsi_qc_new(dev, cmd, done);
- if (!qc)
- goto err_mem;
-
- /* data is present; dma-map it */
- if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
- cmd->sc_data_direction == DMA_TO_DEVICE) {
- if (unlikely(cmd->request_bufflen < 1)) {
- ata_dev_printk(dev, KERN_WARNING,
- "WARNING: zero len r/w req\n");
- goto err_did;
- }
-
- if (cmd->use_sg)
- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
- else
- ata_sg_init_one(qc, cmd->request_buffer,
- cmd->request_bufflen);
-
- qc->dma_dir = cmd->sc_data_direction;
- }
-
- qc->complete_fn = ata_scsi_qc_complete;
-
- if (xlat_func(qc, scsicmd))
- goto early_finish;
-
- /* select device, send command to hardware */
- ata_qc_issue(qc);
-
- VPRINTK("EXIT\n");
- return 0;
-
-early_finish:
- ata_qc_free(qc);
- done(cmd);
- DPRINTK("EXIT - early finish (good or error)\n");
- return 0;
-
-err_did:
- ata_qc_free(qc);
-err_mem:
- cmd->result = (DID_ERROR << 16);
- done(cmd);
- DPRINTK("EXIT - internal\n");
- return 0;
-
-defer:
- DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
-}
-
-/**
- * ata_scsi_rbuf_get - Map response buffer.
- * @cmd: SCSI command containing buffer to be mapped.
- * @buf_out: Pointer to mapped area.
- *
- * Maps buffer contained within SCSI command @cmd.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Length of response buffer.
- */
-
-static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
-{
- u8 *buf;
- unsigned int buflen;
-
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
- buflen = sg->length;
- } else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
- }
-
- *buf_out = buf;
- return buflen;
-}
-
-/**
- * ata_scsi_rbuf_put - Unmap response buffer.
- * @cmd: SCSI command containing buffer to be unmapped.
- * @buf: buffer to unmap
- *
- * Unmaps response buffer contained within @cmd.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
-{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_USER0);
- }
-}
-
-/**
- * ata_scsi_rbuf_fill - wrapper for SCSI command simulators
- * @args: device IDENTIFY data / SCSI command of interest.
- * @actor: Callback hook for desired SCSI command simulator
- *
- * Takes care of the hard work of simulating a SCSI command...
- * Mapping the response buffer, calling the command's handler,
- * and handling the handler's return value. This return value
- * indicates whether the handler wishes the SCSI command to be
- * completed successfully (0), or not (in which case cmd->result
- * and sense buffer are assumed to be set).
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
-{
- u8 *rbuf;
- unsigned int buflen, rc;
- struct scsi_cmnd *cmd = args->cmd;
-
- buflen = ata_scsi_rbuf_get(cmd, &rbuf);
- memset(rbuf, 0, buflen);
- rc = actor(args, rbuf, buflen);
- ata_scsi_rbuf_put(cmd, rbuf);
-
- if (rc == 0)
- cmd->result = SAM_STAT_GOOD;
- args->done(cmd);
-}
-
-/**
- * ata_scsiop_inq_std - Simulate INQUIRY command
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Returns standard device identification data associated
- * with non-VPD INQUIRY command output.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- u8 hdr[] = {
- TYPE_DISK,
- 0,
- 0x5, /* claim SPC-3 version compatibility */
- 2,
- 95 - 4
- };
-
- /* set scsi removeable (RMB) bit per ata bit */
- if (ata_id_removeable(args->id))
- hdr[1] |= (1 << 7);
-
- VPRINTK("ENTER\n");
-
- memcpy(rbuf, hdr, sizeof(hdr));
-
- if (buflen > 35) {
- memcpy(&rbuf[8], "ATA ", 8);
- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
- if (rbuf[32] == 0 || rbuf[32] == ' ')
- memcpy(&rbuf[32], "n/a ", 4);
- }
-
- if (buflen > 63) {
- const u8 versions[] = {
- 0x60, /* SAM-3 (no version claimed) */
-
- 0x03,
- 0x20, /* SBC-2 (no version claimed) */
-
- 0x02,
- 0x60 /* SPC-3 (no version claimed) */
- };
-
- memcpy(rbuf + 59, versions, sizeof(versions));
- }
-
- return 0;
-}
-
-/**
- * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Returns list of inquiry VPD pages available.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- const u8 pages[] = {
- 0x00, /* page 0x00, this page */
- 0x80, /* page 0x80, unit serial no page */
- 0x83 /* page 0x83, device ident page */
- };
- rbuf[3] = sizeof(pages); /* number of supported VPD pages */
-
- if (buflen > 6)
- memcpy(rbuf + 4, pages, sizeof(pages));
-
- return 0;
-}
-
-/**
- * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Returns ATA device serial number.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- const u8 hdr[] = {
- 0,
- 0x80, /* this page code */
- 0,
- ATA_SERNO_LEN, /* page len */
- };
- memcpy(rbuf, hdr, sizeof(hdr));
-
- if (buflen > (ATA_SERNO_LEN + 4 - 1))
- ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
-
- return 0;
-}
-
-/**
- * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Yields two logical unit device identification designators:
- * - vendor specific ASCII containing the ATA serial number
- * - SAT defined "t10 vendor id based" containing ASCII vendor
- * name ("ATA "), model and serial numbers.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- int num;
- const int sat_model_serial_desc_len = 68;
- const int ata_model_byte_len = 40;
-
- rbuf[1] = 0x83; /* this page code */
- num = 4;
-
- if (buflen > (ATA_SERNO_LEN + num + 3)) {
- /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
- rbuf[num + 0] = 2;
- rbuf[num + 3] = ATA_SERNO_LEN;
- num += 4;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
- }
- if (buflen > (sat_model_serial_desc_len + num + 3)) {
- /* SAT defined lu model and serial numbers descriptor */
- /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
- rbuf[num + 0] = 2;
- rbuf[num + 1] = 1;
- rbuf[num + 3] = sat_model_serial_desc_len;
- num += 4;
- memcpy(rbuf + num, "ATA ", 8);
- num += 8;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD_OFS, ata_model_byte_len);
- num += ata_model_byte_len;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
- }
- rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
- return 0;
-}
-
-/**
- * ata_scsiop_noop - Command handler that simply returns success.
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * No operation. Simply returns success to caller, to indicate
- * that the caller should successfully complete this SCSI command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- VPRINTK("ENTER\n");
- return 0;
-}
-
-/**
- * ata_msense_push - Push data onto MODE SENSE data output buffer
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- * @buf: Pointer to BLOB being added to output buffer
- * @buflen: Length of BLOB
- *
- * Store MODE SENSE data on an output buffer.
- *
- * LOCKING:
- * None.
- */
-
-static void ata_msense_push(u8 **ptr_io, const u8 *last,
- const u8 *buf, unsigned int buflen)
-{
- u8 *ptr = *ptr_io;
-
- if ((ptr + buflen - 1) > last)
- return;
-
- memcpy(ptr, buf, buflen);
-
- ptr += buflen;
-
- *ptr_io = ptr;
-}
-
-/**
- * ata_msense_caching - Simulate MODE SENSE caching info page
- * @id: device IDENTIFY data
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- *
- * Generate a caching info page, which conditionally indicates
- * write caching to the SCSI layer, depending on device
- * capabilities.
- *
- * LOCKING:
- * None.
- */
-
-static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
- const u8 *last)
-{
- u8 page[CACHE_MPAGE_LEN];
-
- memcpy(page, def_cache_mpage, sizeof(page));
- if (ata_id_wcache_enabled(id))
- page[2] |= (1 << 2); /* write cache enable */
- if (!ata_id_rahead_enabled(id))
- page[12] |= (1 << 5); /* disable read ahead */
-
- ata_msense_push(ptr_io, last, page, sizeof(page));
- return sizeof(page);
-}
-
-/**
- * ata_msense_ctl_mode - Simulate MODE SENSE control mode page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- *
- * Generate a generic MODE SENSE control mode page.
- *
- * LOCKING:
- * None.
- */
-
-static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
-{
- ata_msense_push(ptr_io, last, def_control_mpage,
- sizeof(def_control_mpage));
- return sizeof(def_control_mpage);
-}
-
-/**
- * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- *
- * Generate a generic MODE SENSE r/w error recovery page.
- *
- * LOCKING:
- * None.
- */
-
-static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
-{
-
- ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
- sizeof(def_rw_recovery_mpage));
- return sizeof(def_rw_recovery_mpage);
-}
-
-/*
- * We can turn this into a real blacklist if it's needed, for now just
- * blacklist any Maxtor BANC1G10 revision firmware
- */
-static int ata_dev_supports_fua(u16 *id)
-{
- unsigned char model[41], fw[9];
-
- if (!libata_fua)
- return 0;
- if (!ata_id_has_fua(id))
- return 0;
-
- ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
- ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
-
- if (strcmp(model, "Maxtor"))
- return 1;
- if (strcmp(fw, "BANC1G10"))
- return 1;
-
- return 0; /* blacklisted */
-}
-
-/**
- * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Simulate MODE SENSE commands. Assume this is invoked for direct
- * access devices (e.g. disks) only. There should be no block
- * descriptor for other device types.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- struct ata_device *dev = args->dev;
- u8 *scsicmd = args->cmd->cmnd, *p, *last;
- const u8 sat_blk_desc[] = {
- 0, 0, 0, 0, /* number of blocks: sat unspecified */
- 0,
- 0, 0x2, 0x0 /* block length: 512 bytes */
- };
- u8 pg, spg;
- unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
- u8 dpofua;
-
- VPRINTK("ENTER\n");
-
- six_byte = (scsicmd[0] == MODE_SENSE);
- ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
- /*
- * LLBA bit in msense(10) ignored (compliant)
- */
-
- page_control = scsicmd[2] >> 6;
- switch (page_control) {
- case 0: /* current */
- break; /* supported */
- case 3: /* saved */
- goto saving_not_supp;
- case 1: /* changeable */
- case 2: /* defaults */
- default:
- goto invalid_fld;
- }
-
- if (six_byte) {
- output_len = 4 + (ebd ? 8 : 0);
- alloc_len = scsicmd[4];
- } else {
- output_len = 8 + (ebd ? 8 : 0);
- alloc_len = (scsicmd[7] << 8) + scsicmd[8];
- }
- minlen = (alloc_len < buflen) ? alloc_len : buflen;
-
- p = rbuf + output_len;
- last = rbuf + minlen - 1;
-
- pg = scsicmd[2] & 0x3f;
- spg = scsicmd[3];
- /*
- * No mode subpages supported (yet) but asking for _all_
- * subpages may be valid
- */
- if (spg && (spg != ALL_SUB_MPAGES))
- goto invalid_fld;
-
- switch(pg) {
- case RW_RECOVERY_MPAGE:
- output_len += ata_msense_rw_recovery(&p, last);
- break;
-
- case CACHE_MPAGE:
- output_len += ata_msense_caching(args->id, &p, last);
- break;
-
- case CONTROL_MPAGE: {
- output_len += ata_msense_ctl_mode(&p, last);
- break;
- }
-
- case ALL_MPAGES:
- output_len += ata_msense_rw_recovery(&p, last);
- output_len += ata_msense_caching(args->id, &p, last);
- output_len += ata_msense_ctl_mode(&p, last);
- break;
-
- default: /* invalid page code */
- goto invalid_fld;
- }
-
- if (minlen < 1)
- return 0;
-
- dpofua = 0;
- if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
- (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
- dpofua = 1 << 4;
-
- if (six_byte) {
- output_len--;
- rbuf[0] = output_len;
- if (minlen > 2)
- rbuf[2] |= dpofua;
- if (ebd) {
- if (minlen > 3)
- rbuf[3] = sizeof(sat_blk_desc);
- if (minlen > 11)
- memcpy(rbuf + 4, sat_blk_desc,
- sizeof(sat_blk_desc));
- }
- } else {
- output_len -= 2;
- rbuf[0] = output_len >> 8;
- if (minlen > 1)
- rbuf[1] = output_len;
- if (minlen > 3)
- rbuf[3] |= dpofua;
- if (ebd) {
- if (minlen > 7)
- rbuf[7] = sizeof(sat_blk_desc);
- if (minlen > 15)
- memcpy(rbuf + 8, sat_blk_desc,
- sizeof(sat_blk_desc));
- }
- }
- return 0;
-
-invalid_fld:
- ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
- return 1;
-
-saving_not_supp:
- ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
- /* "Saving parameters not supported" */
- return 1;
-}
-
-/**
- * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Simulate READ CAPACITY commands.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- u64 n_sectors;
- u32 tmp;
-
- VPRINTK("ENTER\n");
-
- if (ata_id_has_lba(args->id)) {
- if (ata_id_has_lba48(args->id))
- n_sectors = ata_id_u64(args->id, 100);
- else
- n_sectors = ata_id_u32(args->id, 60);
- } else {
- /* CHS default translation */
- n_sectors = args->id[1] * args->id[3] * args->id[6];
-
- if (ata_id_current_chs_valid(args->id))
- /* CHS current translation */
- n_sectors = ata_id_u32(args->id, 57);
- }
-
- n_sectors--; /* ATA TotalUserSectors - 1 */
-
- if (args->cmd->cmnd[0] == READ_CAPACITY) {
- if( n_sectors >= 0xffffffffULL )
- tmp = 0xffffffff ; /* Return max count on overflow */
- else
- tmp = n_sectors ;
-
- /* sector count, 32-bit */
- rbuf[0] = tmp >> (8 * 3);
- rbuf[1] = tmp >> (8 * 2);
- rbuf[2] = tmp >> (8 * 1);
- rbuf[3] = tmp;
-
- /* sector size */
- tmp = ATA_SECT_SIZE;
- rbuf[6] = tmp >> 8;
- rbuf[7] = tmp;
-
- } else {
- /* sector count, 64-bit */
- tmp = n_sectors >> (8 * 4);
- rbuf[2] = tmp >> (8 * 3);
- rbuf[3] = tmp >> (8 * 2);
- rbuf[4] = tmp >> (8 * 1);
- rbuf[5] = tmp;
- tmp = n_sectors;
- rbuf[6] = tmp >> (8 * 3);
- rbuf[7] = tmp >> (8 * 2);
- rbuf[8] = tmp >> (8 * 1);
- rbuf[9] = tmp;
-
- /* sector size */
- tmp = ATA_SECT_SIZE;
- rbuf[12] = tmp >> 8;
- rbuf[13] = tmp;
- }
-
- return 0;
-}
-
-/**
- * ata_scsiop_report_luns - Simulate REPORT LUNS command
- * @args: device IDENTIFY data / SCSI command of interest.
- * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
- *
- * Simulate REPORT LUNS command.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
-{
- VPRINTK("ENTER\n");
- rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
-
- return 0;
-}
-
-/**
- * ata_scsi_set_sense - Set SCSI sense data and status
- * @cmd: SCSI request to be handled
- * @sk: SCSI-defined sense key
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that builds a valid fixed format, current
- * response code and the given sense key (sk), additional sense
- * code (asc) and additional sense code qualifier (ascq) with
- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
- *
- * LOCKING:
- * Not required
- */
-
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- cmd->sense_buffer[0] = 0x70; /* fixed format, current */
- cmd->sense_buffer[2] = sk;
- cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
- cmd->sense_buffer[12] = asc;
- cmd->sense_buffer[13] = ascq;
-}
-
-/**
- * ata_scsi_badcmd - End a SCSI request with an error
- * @cmd: SCSI request to be handled
- * @done: SCSI command completion function
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that completes a SCSI command with
- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
- * and the specified additional sense codes.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
-{
- DPRINTK("ENTER\n");
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
-
- done(cmd);
-}
-
-static void atapi_sense_complete(struct ata_queued_cmd *qc)
-{
- if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
- /* FIXME: not quite right; we don't want the
- * translation of taskfile registers into
- * a sense descriptors, since that's only
- * correct for ATA, not ATAPI
- */
- ata_gen_ata_desc_sense(qc);
- }
-
- qc->scsidone(qc->scsicmd);
- ata_qc_free(qc);
-}
-
-/* is it pointless to prefer PIO for "safety reasons"? */
-static inline int ata_pio_use_silly(struct ata_port *ap)
-{
- return (ap->flags & ATA_FLAG_PIO_DMA);
-}
-
-static void atapi_request_sense(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct scsi_cmnd *cmd = qc->scsicmd;
-
- DPRINTK("ATAPI request sense\n");
-
- /* FIXME: is this needed? */
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-
- ap->ops->tf_read(ap, &qc->tf);
-
- /* fill these in, for the case where they are -not- overwritten */
- cmd->sense_buffer[0] = 0x70;
- cmd->sense_buffer[2] = qc->tf.feature >> 4;
-
- ata_qc_reinit(qc);
-
- ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
- qc->dma_dir = DMA_FROM_DEVICE;
-
- memset(&qc->cdb, 0, qc->dev->cdb_len);
- qc->cdb[0] = REQUEST_SENSE;
- qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
-
- qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- qc->tf.command = ATA_CMD_PACKET;
-
- if (ata_pio_use_silly(ap)) {
- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
- qc->tf.feature |= ATAPI_PKT_DMA;
- } else {
- qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
- }
- qc->nbytes = SCSI_SENSE_BUFFERSIZE;
-
- qc->complete_fn = atapi_sense_complete;
-
- ata_qc_issue(qc);
-
- DPRINTK("EXIT\n");
-}
-
-static void atapi_qc_complete(struct ata_queued_cmd *qc)
-{
- struct scsi_cmnd *cmd = qc->scsicmd;
- unsigned int err_mask = qc->err_mask;
-
- VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
-
- /* handle completion from new EH */
- if (unlikely(qc->ap->ops->error_handler &&
- (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
-
- if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
- /* FIXME: not quite right; we don't want the
- * translation of taskfile registers into a
- * sense descriptors, since that's only
- * correct for ATA, not ATAPI
- */
- ata_gen_ata_desc_sense(qc);
- }
-
- qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
- qc->scsidone(cmd);
- ata_qc_free(qc);
- return;
- }
-
- /* successful completion or old EH failure path */
- if (unlikely(err_mask & AC_ERR_DEV)) {
- cmd->result = SAM_STAT_CHECK_CONDITION;
- atapi_request_sense(qc);
- return;
- } else if (unlikely(err_mask)) {
- /* FIXME: not quite right; we don't want the
- * translation of taskfile registers into
- * a sense descriptors, since that's only
- * correct for ATA, not ATAPI
- */
- ata_gen_ata_desc_sense(qc);
- } else {
- u8 *scsicmd = cmd->cmnd;
-
- if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
- u8 *buf = NULL;
- unsigned int buflen;
-
- buflen = ata_scsi_rbuf_get(cmd, &buf);
-
- /* ATAPI devices typically report zero for their SCSI version,
- * and sometimes deviate from the spec WRT response data
- * format. If SCSI version is reported as zero like normal,
- * then we make the following fixups: 1) Fake MMC-5 version,
- * to indicate to the Linux scsi midlayer this is a modern
- * device. 2) Ensure response data format / ATAPI information
- * are always correct.
- */
- if (buf[2] == 0) {
- buf[2] = 0x5;
- buf[3] = 0x32;
- }
-
- ata_scsi_rbuf_put(cmd, buf);
- }
-
- cmd->result = SAM_STAT_GOOD;
- }
-
- qc->scsidone(cmd);
- ata_qc_free(qc);
-}
-/**
- * atapi_xlat - Initialize PACKET taskfile
- * @qc: command structure to be initialized
- * @scsicmd: SCSI CDB associated with this PACKET command
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Zero on success, non-zero on failure.
- */
-
-static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
-{
- struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_device *dev = qc->dev;
- int using_pio = (dev->flags & ATA_DFLAG_PIO);
- int nodata = (cmd->sc_data_direction == DMA_NONE);
-
- if (!using_pio)
- /* Check whether ATAPI DMA is safe */
- if (ata_check_atapi_dma(qc))
- using_pio = 1;
-
- memcpy(&qc->cdb, scsicmd, dev->cdb_len);
-
- qc->complete_fn = atapi_qc_complete;
-
- qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- if (cmd->sc_data_direction == DMA_TO_DEVICE) {
- qc->tf.flags |= ATA_TFLAG_WRITE;
- DPRINTK("direction: write\n");
- }
-
- qc->tf.command = ATA_CMD_PACKET;
-
- /* no data, or PIO data xfer */
- if (using_pio || nodata) {
- if (nodata)
- qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
- else
- qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
- }
-
- /* DMA data xfer */
- else {
- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
- qc->tf.feature |= ATAPI_PKT_DMA;
-
- if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
- /* some SATA bridges need us to indicate data xfer direction */
- qc->tf.feature |= ATAPI_DMADIR;
- }
-
- qc->nbytes = cmd->request_bufflen;
-
- return 0;
-}
-
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
-{
- if (likely(id < ATA_MAX_DEVICES))
- return &ap->device[id];
- return NULL;
-}
-
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
- const struct scsi_device *scsidev)
-{
- /* skip commands not addressed to targets we simulate */
- if (unlikely(scsidev->channel || scsidev->lun))
- return NULL;
-
- return ata_find_dev(ap, scsidev->id);
-}
-
-/**
- * ata_scsi_dev_enabled - determine if device is enabled
- * @dev: ATA device
- *
- * Determine if commands should be sent to the specified device.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * 0 if commands are not allowed / 1 if commands are allowed
- */
-
-static int ata_scsi_dev_enabled(struct ata_device *dev)
-{
- if (unlikely(!ata_dev_enabled(dev)))
- return 0;
-
- if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
- if (unlikely(dev->class == ATA_DEV_ATAPI)) {
- ata_dev_printk(dev, KERN_WARNING,
- "WARNING: ATAPI is %s, device ignored.\n",
- atapi_enabled ? "not supported with this driver" : "disabled");
- return 0;
- }
- }
-
- return 1;
-}
-
-/**
- * ata_scsi_find_dev - lookup ata_device from scsi_cmnd
- * @ap: ATA port to which the device is attached
- * @scsidev: SCSI device from which we derive the ATA device
- *
- * Given various information provided in struct scsi_cmnd,
- * map that onto an ATA bus, and using that mapping
- * determine which ata_device is associated with the
- * SCSI command to be sent.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * Associated ATA device, or %NULL if not found.
- */
-static struct ata_device *
-ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
-{
- struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
-
- if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
- return NULL;
-
- return dev;
-}
-
-/*
- * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value.
- * @byte1: Byte 1 from pass-thru CDB.
- *
- * RETURNS:
- * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise.
- */
-static u8
-ata_scsi_map_proto(u8 byte1)
-{
- switch((byte1 & 0x1e) >> 1) {
- case 3: /* Non-data */
- return ATA_PROT_NODATA;
-
- case 6: /* DMA */
- return ATA_PROT_DMA;
-
- case 4: /* PIO Data-in */
- case 5: /* PIO Data-out */
- return ATA_PROT_PIO;
-
- case 10: /* Device Reset */
- case 0: /* Hard Reset */
- case 1: /* SRST */
- case 2: /* Bus Idle */
- case 7: /* Packet */
- case 8: /* DMA Queued */
- case 9: /* Device Diagnostic */
- case 11: /* UDMA Data-in */
- case 12: /* UDMA Data-Out */
- case 13: /* FPDMA */
- default: /* Reserved */
- break;
- }
-
- return ATA_PROT_UNKNOWN;
-}
-
-/**
- * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
- * @qc: command structure to be initialized
- * @scsicmd: SCSI command to convert
- *
- * Handles either 12 or 16-byte versions of the CDB.
- *
- * RETURNS:
- * Zero on success, non-zero on failure.
- */
-static unsigned int
-ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
-{
- struct ata_taskfile *tf = &(qc->tf);
- struct scsi_cmnd *cmd = qc->scsicmd;
- struct ata_device *dev = qc->dev;
-
- if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
- goto invalid_fld;
-
- /* We may not issue DMA commands if no DMA mode is set */
- if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
- goto invalid_fld;
-
- if (scsicmd[1] & 0xe0)
- /* PIO multi not supported yet */
- goto invalid_fld;
-
- /*
- * 12 and 16 byte CDBs use different offsets to
- * provide the various register values.
- */
- if (scsicmd[0] == ATA_16) {
- /*
- * 16-byte CDB - may contain extended commands.
- *
- * If that is the case, copy the upper byte register values.
- */
- if (scsicmd[1] & 0x01) {
- tf->hob_feature = scsicmd[3];
- tf->hob_nsect = scsicmd[5];
- tf->hob_lbal = scsicmd[7];
- tf->hob_lbam = scsicmd[9];
- tf->hob_lbah = scsicmd[11];
- tf->flags |= ATA_TFLAG_LBA48;
- } else
- tf->flags &= ~ATA_TFLAG_LBA48;
-
- /*
- * Always copy low byte, device and command registers.
- */
- tf->feature = scsicmd[4];
- tf->nsect = scsicmd[6];
- tf->lbal = scsicmd[8];
- tf->lbam = scsicmd[10];
- tf->lbah = scsicmd[12];
- tf->device = scsicmd[13];
- tf->command = scsicmd[14];
- } else {
- /*
- * 12-byte CDB - incapable of extended commands.
- */
- tf->flags &= ~ATA_TFLAG_LBA48;
-
- tf->feature = scsicmd[3];
- tf->nsect = scsicmd[4];
- tf->lbal = scsicmd[5];
- tf->lbam = scsicmd[6];
- tf->lbah = scsicmd[7];
- tf->device = scsicmd[8];
- tf->command = scsicmd[9];
- }
- /*
- * If slave is possible, enforce correct master/slave bit
- */
- if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
- tf->device = qc->dev->devno ?
- tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
-
- /*
- * Filter SET_FEATURES - XFER MODE command -- otherwise,
- * SET_FEATURES - XFER MODE must be preceded/succeeded
- * by an update to hardware-specific registers for each
- * controller (i.e. the reason for ->set_piomode(),
- * ->set_dmamode(), and ->post_set_mode() hooks).
- */
- if ((tf->command == ATA_CMD_SET_FEATURES)
- && (tf->feature == SETFEATURES_XFER))
- goto invalid_fld;
-
- /*
- * Set flags so that all registers will be written,
- * and pass on write indication (used for PIO/DMA
- * setup.)
- */
- tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
-
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- tf->flags |= ATA_TFLAG_WRITE;
-
- /*
- * Set transfer length.
- *
- * TODO: find out if we need to do more here to
- * cover scatter/gather case.
- */
- qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
-
- /* request result TF */
- qc->flags |= ATA_QCFLAG_RESULT_TF;
-
- return 0;
-
- invalid_fld:
- ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00);
- /* "Invalid field in cdb" */
- return 1;
-}
-
-/**
- * ata_get_xlat_func - check if SCSI to ATA translation is possible
- * @dev: ATA device
- * @cmd: SCSI command opcode to consider
- *
- * Look up the SCSI command given, and determine whether the
- * SCSI command is to be translated or simulated.
- *
- * RETURNS:
- * Pointer to translation function if possible, %NULL if not.
- */
-
-static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
-{
- switch (cmd) {
- case READ_6:
- case READ_10:
- case READ_16:
-
- case WRITE_6:
- case WRITE_10:
- case WRITE_16:
- return ata_scsi_rw_xlat;
-
- case SYNCHRONIZE_CACHE:
- if (ata_try_flush_cache(dev))
- return ata_scsi_flush_xlat;
- break;
-
- case VERIFY:
- case VERIFY_16:
- return ata_scsi_verify_xlat;
-
- case ATA_12:
- case ATA_16:
- return ata_scsi_pass_thru;
-
- case START_STOP:
- return ata_scsi_start_stop_xlat;
- }
-
- return NULL;
-}
-
-/**
- * ata_scsi_dump_cdb - dump SCSI command contents to dmesg
- * @ap: ATA port to which the command was being sent
- * @cmd: SCSI command to dump
- *
- * Prints the contents of a SCSI command via printk().
- */
-
-static inline void ata_scsi_dump_cdb(struct ata_port *ap,
- struct scsi_cmnd *cmd)
-{
-#ifdef ATA_DEBUG
- struct scsi_device *scsidev = cmd->device;
- u8 *scsicmd = cmd->cmnd;
-
- DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ap->id,
- scsidev->channel, scsidev->id, scsidev->lun,
- scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
- scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
- scsicmd[8]);
-#endif
-}
-
-static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- struct ata_device *dev)
-{
- int rc = 0;
-
- if (dev->class == ATA_DEV_ATA) {
- ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
- cmd->cmnd[0]);
-
- if (xlat_func)
- rc = ata_scsi_translate(dev, cmd, done, xlat_func);
- else
- ata_scsi_simulate(dev, cmd, done);
- } else
- rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
-
- return rc;
-}
-
-/**
- * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
- * @cmd: SCSI command to be sent
- * @done: Completion function, called when command is complete
- *
- * In some cases, this function translates SCSI commands into
- * ATA taskfiles, and queues the taskfiles to be sent to
- * hardware. In other cases, this function simulates a
- * SCSI device by evaluating and responding to certain
- * SCSI commands. This creates the overall effect of
- * ATA and ATAPI devices appearing as SCSI devices.
- *
- * LOCKING:
- * Releases scsi-layer-held lock, and obtains host_set lock.
- *
- * RETURNS:
- * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
- * 0 otherwise.
- */
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
-{
- struct ata_port *ap;
- struct ata_device *dev;
- struct scsi_device *scsidev = cmd->device;
- struct Scsi_Host *shost = scsidev->host;
- int rc = 0;
-
- ap = ata_shost_to_port(shost);
-
- spin_unlock(shost->host_lock);
- spin_lock(ap->lock);
-
- ata_scsi_dump_cdb(ap, cmd);
-
- dev = ata_scsi_find_dev(ap, scsidev);
- if (likely(dev))
- rc = __ata_scsi_queuecmd(cmd, done, dev);
- else {
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- }
-
- spin_unlock(ap->lock);
- spin_lock(shost->host_lock);
- return rc;
-}
-
-/**
- * ata_scsi_simulate - simulate SCSI command on ATA device
- * @dev: the target device
- * @cmd: SCSI command being sent to device.
- * @done: SCSI command completion function.
- *
- * Interprets and directly executes a select list of SCSI commands
- * that can be handled internally.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
-{
- struct ata_scsi_args args;
- const u8 *scsicmd = cmd->cmnd;
-
- args.dev = dev;
- args.id = dev->id;
- args.cmd = cmd;
- args.done = done;
-
- switch(scsicmd[0]) {
- /* no-op's, complete with success */
- case SYNCHRONIZE_CACHE:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case FORMAT_UNIT: /* FIXME: correct? */
- case SEND_DIAGNOSTIC: /* FIXME: correct? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
- break;
-
- case INQUIRY:
- if (scsicmd[1] & 2) /* is CmdDt set? */
- ata_scsi_invalid_field(cmd, done);
- else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
- else if (scsicmd[2] == 0x00)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
- else if (scsicmd[2] == 0x80)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
- else if (scsicmd[2] == 0x83)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
- else
- ata_scsi_invalid_field(cmd, done);
- break;
-
- case MODE_SENSE:
- case MODE_SENSE_10:
- ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
- break;
-
- case MODE_SELECT: /* unconditionally return */
- case MODE_SELECT_10: /* bad-field-in-cdb */
- ata_scsi_invalid_field(cmd, done);
- break;
-
- case READ_CAPACITY:
- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- break;
-
- case SERVICE_ACTION_IN:
- if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- else
- ata_scsi_invalid_field(cmd, done);
- break;
-
- case REPORT_LUNS:
- ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
- break;
-
- /* mandatory commands we haven't implemented yet */
- case REQUEST_SENSE:
-
- /* all other commands */
- default:
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
- /* "Invalid command operation code" */
- done(cmd);
- break;
- }
-}
-
-void ata_scsi_scan_host(struct ata_port *ap)
-{
- unsigned int i;
-
- if (ap->flags & ATA_FLAG_DISABLED)
- return;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- struct scsi_device *sdev;
-
- if (!ata_dev_enabled(dev) || dev->sdev)
- continue;
-
- sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
- if (!IS_ERR(sdev)) {
- dev->sdev = sdev;
- scsi_device_put(sdev);
- }
- }
-}
-
-/**
- * ata_scsi_offline_dev - offline attached SCSI device
- * @dev: ATA device to offline attached SCSI device for
- *
- * This function is called from ata_eh_hotplug() and responsible
- * for taking the SCSI device attached to @dev offline. This
- * function is called with host_set lock which protects dev->sdev
- * against clearing.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * 1 if attached SCSI device exists, 0 otherwise.
- */
-int ata_scsi_offline_dev(struct ata_device *dev)
-{
- if (dev->sdev) {
- scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
- return 1;
- }
- return 0;
-}
-
-/**
- * ata_scsi_remove_dev - remove attached SCSI device
- * @dev: ATA device to remove attached SCSI device for
- *
- * This function is called from ata_eh_scsi_hotplug() and
- * responsible for removing the SCSI device attached to @dev.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-static void ata_scsi_remove_dev(struct ata_device *dev)
-{
- struct ata_port *ap = dev->ap;
- struct scsi_device *sdev;
- unsigned long flags;
-
- /* Alas, we need to grab scan_mutex to ensure SCSI device
- * state doesn't change underneath us and thus
- * scsi_device_get() always succeeds. The mutex locking can
- * be removed if there is __scsi_device_get() interface which
- * increments reference counts regardless of device state.
- */
- mutex_lock(&ap->host->scan_mutex);
- spin_lock_irqsave(ap->lock, flags);
-
- /* clearing dev->sdev is protected by host_set lock */
- sdev = dev->sdev;
- dev->sdev = NULL;
-
- if (sdev) {
- /* If user initiated unplug races with us, sdev can go
- * away underneath us after the host_set lock and
- * scan_mutex are released. Hold onto it.
- */
- if (scsi_device_get(sdev) == 0) {
- /* The following ensures the attached sdev is
- * offline on return from ata_scsi_offline_dev()
- * regardless it wins or loses the race
- * against this function.
- */
- scsi_device_set_state(sdev, SDEV_OFFLINE);
- } else {
- WARN_ON(1);
- sdev = NULL;
- }
- }
-
- spin_unlock_irqrestore(ap->lock, flags);
- mutex_unlock(&ap->host->scan_mutex);
-
- if (sdev) {
- ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
- sdev->sdev_gendev.bus_id);
-
- scsi_remove_device(sdev);
- scsi_device_put(sdev);
- }
-}
-
-/**
- * ata_scsi_hotplug - SCSI part of hotplug
- * @data: Pointer to ATA port to perform SCSI hotplug on
- *
- * Perform SCSI part of hotplug. It's executed from a separate
- * workqueue after EH completes. This is necessary because SCSI
- * hot plugging requires working EH and hot unplugging is
- * synchronized with hot plugging with a mutex.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_scsi_hotplug(void *data)
-{
- struct ata_port *ap = data;
- int i;
-
- if (ap->flags & ATA_FLAG_UNLOADING) {
- DPRINTK("ENTER/EXIT - unloading\n");
- return;
- }
-
- DPRINTK("ENTER\n");
-
- /* unplug detached devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- unsigned long flags;
-
- if (!(dev->flags & ATA_DFLAG_DETACHED))
- continue;
-
- spin_lock_irqsave(ap->lock, flags);
- dev->flags &= ~ATA_DFLAG_DETACHED;
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_scsi_remove_dev(dev);
- }
-
- /* scan for new ones */
- ata_scsi_scan_host(ap);
-
- /* If we scanned while EH was in progress, scan would have
- * failed silently. Requeue if there are enabled but
- * unattached devices.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
- break;
- }
- }
-
- DPRINTK("EXIT\n");
-}
-
-/**
- * ata_scsi_user_scan - indication for user-initiated bus scan
- * @shost: SCSI host to scan
- * @channel: Channel to scan
- * @id: ID to scan
- * @lun: LUN to scan
- *
- * This function is called when user explicitly requests bus
- * scan. Set probe pending flag and invoke EH.
- *
- * LOCKING:
- * SCSI layer (we don't care)
- *
- * RETURNS:
- * Zero.
- */
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
- unsigned int id, unsigned int lun)
-{
- struct ata_port *ap = ata_shost_to_port(shost);
- unsigned long flags;
- int rc = 0;
-
- if (!ap->ops->error_handler)
- return -EOPNOTSUPP;
-
- if ((channel != SCAN_WILD_CARD && channel != 0) ||
- (lun != SCAN_WILD_CARD && lun != 0))
- return -EINVAL;
-
- spin_lock_irqsave(ap->lock, flags);
-
- if (id == SCAN_WILD_CARD) {
- ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
- } else {
- struct ata_device *dev = ata_find_dev(ap, id);
-
- if (dev) {
- ap->eh_info.probe_mask |= 1 << dev->devno;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
- } else
- rc = -EINVAL;
- }
-
- if (rc == 0)
- ata_port_schedule_eh(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- return rc;
-}
-
-/**
- * ata_scsi_dev_rescan - initiate scsi_rescan_device()
- * @data: Pointer to ATA port to perform scsi_rescan_device()
- *
- * After ATA pass thru (SAT) commands are executed successfully,
- * libata need to propagate the changes to SCSI layer. This
- * function must be executed from ata_aux_wq such that sdev
- * attach/detach don't race with rescan.
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- */
-void ata_scsi_dev_rescan(void *data)
-{
- struct ata_port *ap = data;
- struct ata_device *dev;
- unsigned int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (ata_dev_enabled(dev) && dev->sdev)
- scsi_rescan_device(&(dev->sdev->sdev_gendev));
- }
-}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
deleted file mode 100644
index bdd48889709..00000000000
--- a/drivers/scsi/libata.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * libata.h - helper library for ATA
- *
- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2004 Jeff Garzik
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- */
-
-#ifndef __LIBATA_H__
-#define __LIBATA_H__
-
-#define DRV_NAME "libata"
-#define DRV_VERSION "1.30" /* must be exactly four chars */
-
-struct ata_scsi_args {
- struct ata_device *dev;
- u16 *id;
- struct scsi_cmnd *cmd;
- void (*done)(struct scsi_cmnd *);
-};
-
-/* libata-core.c */
-extern struct workqueue_struct *ata_aux_wq;
-extern int atapi_enabled;
-extern int atapi_dmadir;
-extern int libata_fua;
-extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
-extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
-extern void ata_dev_disable(struct ata_device *dev);
-extern void ata_port_flush_task(struct ata_port *ap);
-extern unsigned ata_exec_internal(struct ata_device *dev,
- struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen);
-extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
- int post_reset, u16 *id);
-extern int ata_dev_configure(struct ata_device *dev, int print_info);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
-extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
-extern void ata_qc_free(struct ata_queued_cmd *qc);
-extern void ata_qc_issue(struct ata_queued_cmd *qc);
-extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
-extern void ata_dev_select(struct ata_port *ap, unsigned int device,
- unsigned int wait, unsigned int can_sleep);
-extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
-extern void ata_dev_init(struct ata_device *dev);
-extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-
-
-/* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
-extern void ata_scsi_scan_host(struct ata_port *ap);
-extern int ata_scsi_offline_dev(struct ata_device *dev);
-extern void ata_scsi_hotplug(void *data);
-extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- u8 asc, u8 ascq);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
- u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen));
-extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
-extern void ata_scsi_dev_rescan(void *data);
-
-/* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
-extern void ata_scsi_error(struct Scsi_Host *host);
-extern void ata_port_wait_eh(struct ata_port *ap);
-extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
-
-#endif /* __LIBATA_H__ */
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 2673a11a949..c542d0e95e6 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
- struct iscsi_data *hdr,
- int transport_data_cnt)
+ struct iscsi_data *hdr)
{
struct iscsi_conn *conn = ctask->conn;
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
hdr->itt = ctask->hdr->itt;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-
- hdr->offset = cpu_to_be32(ctask->total_length -
- transport_data_cnt -
- ctask->unsol_count);
+ hdr->offset = cpu_to_be32(ctask->unsol_offset);
if (ctask->unsol_count > conn->max_xmit_dlength) {
hton24(hdr->dlength, conn->max_xmit_dlength);
ctask->data_count = conn->max_xmit_dlength;
+ ctask->unsol_offset += ctask->data_count;
hdr->flags = 0;
} else {
hton24(hdr->dlength, ctask->unsol_count);
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+ ctask->data_count = 0;
if (sc->sc_data_direction == DMA_TO_DEVICE) {
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
/*
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
*/
ctask->imm_count = 0;
ctask->unsol_count = 0;
+ ctask->unsol_offset = 0;
ctask->unsol_datasn = 0;
if (session->imm_data_en) {
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
} else
zero_data(ctask->hdr->dlength);
- if (!session->initial_r2t_en)
+ if (!session->initial_r2t_en) {
ctask->unsol_count = min(session->first_burst,
ctask->total_length) - ctask->imm_count;
+ ctask->unsol_offset = ctask->imm_count;
+ }
+
if (!ctask->unsol_count)
/* No unsolicit Data-Out's */
ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
@@ -177,24 +179,51 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
/**
* iscsi_complete_command - return command back to scsi-ml
- * @session: iscsi session
* @ctask: iscsi cmd task
*
* Must be called with session lock.
* This function returns the scsi command to scsi-ml and returns
* the cmd task to the pool of available cmd tasks.
*/
-static void iscsi_complete_command(struct iscsi_session *session,
- struct iscsi_cmd_task *ctask)
+static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
{
+ struct iscsi_session *session = ctask->conn->session;
struct scsi_cmnd *sc = ctask->sc;
+ ctask->state = ISCSI_TASK_COMPLETED;
ctask->sc = NULL;
+ /* SCSI eh reuses commands to verify us */
+ sc->SCp.ptr = NULL;
list_del_init(&ctask->running);
__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
sc->scsi_done(sc);
}
+static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+ atomic_inc(&ctask->refcount);
+}
+
+static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+ spin_lock_bh(&ctask->conn->session->lock);
+ __iscsi_get_ctask(ctask);
+ spin_unlock_bh(&ctask->conn->session->lock);
+}
+
+static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+ if (atomic_dec_and_test(&ctask->refcount))
+ iscsi_complete_command(ctask);
+}
+
+static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+ spin_lock_bh(&ctask->conn->session->lock);
+ __iscsi_put_ctask(ctask);
+ spin_unlock_bh(&ctask->conn->session->lock);
+}
+
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
@@ -271,10 +300,53 @@ out:
(long)sc, sc->result, ctask->itt);
conn->scsirsp_pdus_cnt++;
- iscsi_complete_command(conn->session, ctask);
+ __iscsi_put_ctask(ctask);
return rc;
}
+static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+{
+ struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
+
+ conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+ conn->tmfrsp_pdus_cnt++;
+
+ if (conn->tmabort_state != TMABORT_INITIAL)
+ return;
+
+ if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
+ conn->tmabort_state = TMABORT_SUCCESS;
+ else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
+ conn->tmabort_state = TMABORT_NOT_FOUND;
+ else
+ conn->tmabort_state = TMABORT_FAILED;
+ wake_up(&conn->ehwait);
+}
+
+static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, int datalen)
+{
+ struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
+ struct iscsi_hdr rejected_pdu;
+ uint32_t itt;
+
+ conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
+
+ if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
+ if (ntoh24(reject->dlength) > datalen)
+ return ISCSI_ERR_PROTO;
+
+ if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
+ memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
+ itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n", itt,
+ rejected_pdu.opcode);
+ }
+ }
+ return 0;
+}
+
/**
* __iscsi_complete_pdu - complete pdu
* @conn: iscsi conn
@@ -316,7 +388,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
conn->scsirsp_pdus_cnt++;
- iscsi_complete_command(session, ctask);
+ __iscsi_put_ctask(ctask);
}
break;
case ISCSI_OP_R2T:
@@ -340,6 +412,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
switch(opcode) {
case ISCSI_OP_LOGOUT_RSP:
+ if (datalen) {
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
/* fall through */
case ISCSI_OP_LOGIN_RSP:
@@ -348,7 +424,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
* login related PDU's exp_statsn is handled in
* userspace
*/
- rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
list_del(&mtask->running);
if (conn->login_mtask != mtask)
__kfifo_put(session->mgmtpool.queue,
@@ -360,25 +437,17 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- conn->tmfrsp_pdus_cnt++;
- if (conn->tmabort_state == TMABORT_INITIAL) {
- conn->tmabort_state =
- ((struct iscsi_tm_rsp *)hdr)->
- response == ISCSI_TMF_RSP_COMPLETE ?
- TMABORT_SUCCESS:TMABORT_FAILED;
- /* unblock eh_abort() */
- wake_up(&conn->ehwait);
- }
+ iscsi_tmf_rsp(conn, hdr);
break;
case ISCSI_OP_NOOP_IN:
- if (hdr->ttt != ISCSI_RESERVED_TAG) {
+ if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
rc = ISCSI_ERR_PROTO;
break;
}
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
list_del(&mtask->running);
if (conn->login_mtask != mtask)
__kfifo_put(session->mgmtpool.queue,
@@ -389,19 +458,27 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
} else if (itt == ISCSI_RESERVED_TAG) {
+ rc = iscsi_check_assign_cmdsn(session,
+ (struct iscsi_nopin*)hdr);
+ if (rc)
+ goto done;
+
switch(opcode) {
case ISCSI_OP_NOOP_IN:
- if (!datalen) {
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (!rc && hdr->ttt != ISCSI_RESERVED_TAG)
- rc = iscsi_recv_pdu(conn->cls_conn,
- hdr, NULL, 0);
- } else
+ if (datalen) {
rc = ISCSI_ERR_PROTO;
+ break;
+ }
+
+ if (hdr->ttt == ISCSI_RESERVED_TAG)
+ break;
+
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
+ rc = ISCSI_ERR_CONN_FAILED;
break;
case ISCSI_OP_REJECT:
- /* we need sth like iscsi_reject_rsp()*/
+ rc = iscsi_handle_reject(conn, hdr, data, datalen);
+ break;
case ISCSI_OP_ASYNC_EVENT:
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
/* we need sth like iscsi_async_event_rsp() */
@@ -537,7 +614,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) {
+ iscsi_get_ctask(conn->ctask);
rc = tt->xmit_cmd_task(conn, conn->ctask);
+ iscsi_put_ctask(conn->ctask);
if (rc)
goto again;
/* done with this in-progress ctask */
@@ -568,20 +647,31 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
}
/* process command queue */
- while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask,
- sizeof(void*))) {
+ spin_lock_bh(&conn->session->lock);
+ while (!list_empty(&conn->xmitqueue)) {
/*
* iscsi tcp may readd the task to the xmitqueue to send
* write data
*/
- spin_lock_bh(&conn->session->lock);
- if (list_empty(&conn->ctask->running))
- list_add_tail(&conn->ctask->running, &conn->run_list);
+ conn->ctask = list_entry(conn->xmitqueue.next,
+ struct iscsi_cmd_task, running);
+ conn->ctask->state = ISCSI_TASK_RUNNING;
+ list_move_tail(conn->xmitqueue.next, &conn->run_list);
+ __iscsi_get_ctask(conn->ctask);
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);
+ if (rc) {
+ spin_unlock_bh(&conn->session->lock);
+ goto again;
+ }
}
+ spin_unlock_bh(&conn->session->lock);
/* done with this ctask */
conn->ctask = NULL;
@@ -629,6 +719,7 @@ enum {
FAILURE_SESSION_FAILED,
FAILURE_SESSION_FREED,
FAILURE_WINDOW_CLOSED,
+ FAILURE_OOM,
FAILURE_SESSION_TERMINATE,
FAILURE_SESSION_IN_RECOVERY,
FAILURE_SESSION_RECOVERY_TIMEOUT,
@@ -644,6 +735,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
sc->scsi_done = done;
sc->result = 0;
+ sc->SCp.ptr = NULL;
host = sc->device->host;
session = iscsi_hostdata(host->hostdata);
@@ -687,10 +779,16 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
conn = session->leadconn;
- __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+ if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
+ sizeof(void*))) {
+ reason = FAILURE_OOM;
+ goto reject;
+ }
sc->SCp.phase = session->age;
sc->SCp.ptr = (char *)ctask;
+ atomic_set(&ctask->refcount, 1);
+ ctask->state = ISCSI_TASK_PENDING;
ctask->mtask = NULL;
ctask->conn = conn;
ctask->sc = sc;
@@ -700,11 +798,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
session->tt->init_cmd_task(ctask);
- __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
+ list_add_tail(&ctask->running, &conn->xmitqueue);
debug_scsi(
- "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n",
+ "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
+ "win %d]\n",
sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- conn->id, (long)sc, ctask->itt, sc->request_bufflen,
+ conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
spin_unlock(&session->lock);
@@ -977,31 +1076,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
/*
* xmit mutex and session lock must be held
*/
-#define iscsi_remove_task(tasktype) \
-static struct iscsi_##tasktype * \
-iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \
-{ \
- int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \
- struct iscsi_##tasktype *task; \
- \
- debug_scsi("searching %d tasks\n", nr_tasks); \
- \
- for (i = 0; i < nr_tasks; i++) { \
- __kfifo_get(fifo, (void*)&task, sizeof(void*)); \
- debug_scsi("check task %u\n", task->itt); \
- \
- if (task->itt == itt) { \
- debug_scsi("matched task\n"); \
- return task; \
- } \
- \
- __kfifo_put(fifo, (void*)&task, sizeof(void*)); \
- } \
- return NULL; \
-}
+static struct iscsi_mgmt_task *
+iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
+{
+ int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
+ struct iscsi_mgmt_task *task;
+
+ debug_scsi("searching %d tasks\n", nr_tasks);
+
+ for (i = 0; i < nr_tasks; i++) {
+ __kfifo_get(fifo, (void*)&task, sizeof(void*));
+ debug_scsi("check task %u\n", task->itt);
+
+ if (task->itt == itt) {
+ debug_scsi("matched task\n");
+ return task;
+ }
-iscsi_remove_task(mgmt_task);
-iscsi_remove_task(cmd_task);
+ __kfifo_put(fifo, (void*)&task, sizeof(void*));
+ }
+ return NULL;
+}
static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
{
@@ -1027,25 +1122,39 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
{
struct scsi_cmnd *sc;
- conn->session->tt->cleanup_cmd_task(conn, ctask);
- iscsi_ctask_mtask_cleanup(ctask);
-
sc = ctask->sc;
if (!sc)
return;
+
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
+ iscsi_ctask_mtask_cleanup(ctask);
+
sc->result = err;
sc->resid = sc->request_bufflen;
- iscsi_complete_command(conn->session, ctask);
+ /* release ref from queuecommand */
+ __iscsi_put_ctask(ctask);
}
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
- struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
- struct iscsi_conn *conn = ctask->conn;
- struct iscsi_session *session = conn->session;
- struct iscsi_cmd_task *pending_ctask;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_conn *conn;
+ struct iscsi_session *session;
int rc;
+ /*
+ * if session was ISCSI_STATE_IN_RECOVERY then we may not have
+ * got the command.
+ */
+ if (!sc->SCp.ptr) {
+ debug_scsi("sc never reached iscsi layer or it completed.\n");
+ return SUCCESS;
+ }
+
+ ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+ conn = ctask->conn;
+ session = conn->session;
+
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
@@ -1061,8 +1170,11 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto failed;
/* ctask completed before time out */
- if (!ctask->sc)
- goto success;
+ if (!ctask->sc) {
+ spin_unlock_bh(&session->lock);
+ debug_scsi("sc completed while abort in progress\n");
+ goto success_rel_mutex;
+ }
/* what should we do here ? */
if (conn->ctask == ctask) {
@@ -1071,17 +1183,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto failed;
}
- /* check for the easy pending cmd abort */
- pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt);
- if (pending_ctask) {
- /* iscsi_tcp queues write transfers on the xmitqueue */
- if (list_empty(&pending_ctask->running)) {
- debug_scsi("found pending task\n");
- goto success;
- } else
- __kfifo_put(conn->xmitqueue, (void*)&pending_ctask,
- sizeof(void*));
- }
+ if (ctask->state == ISCSI_TASK_PENDING)
+ goto success_cleanup;
conn->tmabort_state = TMABORT_INITIAL;
@@ -1089,25 +1192,31 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
rc = iscsi_exec_abort_task(sc, ctask);
spin_lock_bh(&session->lock);
- iscsi_ctask_mtask_cleanup(ctask);
if (rc || sc->SCp.phase != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
goto failed;
+ iscsi_ctask_mtask_cleanup(ctask);
- /* ctask completed before tmf abort response */
- if (!ctask->sc) {
- debug_scsi("sc completed while abort in progress\n");
- goto success;
- }
-
- if (conn->tmabort_state != TMABORT_SUCCESS) {
+ switch (conn->tmabort_state) {
+ case TMABORT_SUCCESS:
+ goto success_cleanup;
+ case TMABORT_NOT_FOUND:
+ if (!ctask->sc) {
+ /* ctask completed before tmf abort response */
+ spin_unlock_bh(&session->lock);
+ debug_scsi("sc completed while abort in progress\n");
+ goto success_rel_mutex;
+ }
+ /* fall through */
+ default:
+ /* timedout or failed */
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
spin_lock_bh(&session->lock);
goto failed;
}
-success:
+success_cleanup:
debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
spin_unlock_bh(&session->lock);
@@ -1121,6 +1230,7 @@ success:
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
+success_rel_mutex:
mutex_unlock(&conn->xmitmutex);
return SUCCESS;
@@ -1263,6 +1373,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
if (cmd_task_size)
ctask->dd_data = &ctask[1];
ctask->itt = cmd_i;
+ INIT_LIST_HEAD(&ctask->running);
}
spin_lock_init(&session->lock);
@@ -1282,18 +1393,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
if (mgmt_task_size)
mtask->dd_data = &mtask[1];
mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i;
+ INIT_LIST_HEAD(&mtask->running);
}
if (scsi_add_host(shost, NULL))
goto add_host_fail;
+ if (!try_module_get(iscsit->owner))
+ goto cls_session_fail;
+
cls_session = iscsi_create_session(shost, iscsit, 0);
if (!cls_session)
- goto cls_session_fail;
+ goto module_put;
*(unsigned long*)shost->hostdata = (unsigned long)cls_session;
return cls_session;
+module_put:
+ module_put(iscsit->owner);
cls_session_fail:
scsi_remove_host(shost);
add_host_fail:
@@ -1317,14 +1434,18 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
{
struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ struct module *owner = cls_session->transport->owner;
scsi_remove_host(shost);
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+ kfree(session->targetname);
+
iscsi_destroy_session(cls_session);
scsi_host_put(shost);
+ module_put(owner);
}
EXPORT_SYMBOL_GPL(iscsi_session_teardown);
@@ -1355,12 +1476,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
conn->tmabort_state = TMABORT_INITIAL;
INIT_LIST_HEAD(&conn->run_list);
INIT_LIST_HEAD(&conn->mgmt_run_list);
-
- /* initialize general xmit PDU commands queue */
- conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (conn->xmitqueue == ERR_PTR(-ENOMEM))
- goto xmitqueue_alloc_fail;
+ INIT_LIST_HEAD(&conn->xmitqueue);
/* initialize general immediate & non-immediate PDU commands queue */
conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
@@ -1388,7 +1504,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
if (!data)
goto login_mtask_data_alloc_fail;
- conn->login_mtask->data = data;
+ conn->login_mtask->data = conn->data = data;
init_timer(&conn->tmabort_timer);
mutex_init(&conn->xmitmutex);
@@ -1404,8 +1520,6 @@ login_mtask_alloc_fail:
mgmtqueue_alloc_fail:
kfifo_free(conn->immqueue);
immqueue_alloc_fail:
- kfifo_free(conn->xmitqueue);
-xmitqueue_alloc_fail:
iscsi_destroy_conn(cls_conn);
return NULL;
}
@@ -1426,12 +1540,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
mutex_lock(&conn->xmitmutex);
- if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) {
- if (session->tt->suspend_conn_recv)
- session->tt->suspend_conn_recv(conn);
-
- session->tt->terminate_conn(conn);
- }
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
@@ -1468,7 +1576,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_lock_bh(&session->lock);
- kfree(conn->login_mtask->data);
+ kfree(conn->data);
+ kfree(conn->persistent_address);
__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
sizeof(void*));
list_del(&conn->item);
@@ -1483,7 +1592,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
spin_unlock_bh(&session->lock);
- kfifo_free(conn->xmitqueue);
kfifo_free(conn->immqueue);
kfifo_free(conn->mgmtqueue);
@@ -1496,11 +1604,19 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
- if (session == NULL) {
+ if (!session) {
printk(KERN_ERR "iscsi: can't start unbound connection\n");
return -EPERM;
}
+ if ((session->imm_data_en || !session->initial_r2t_en) &&
+ session->first_burst > session->max_burst) {
+ printk("iscsi: invalid burst lengths: "
+ "first_burst %d max_burst %d\n",
+ session->first_burst, session->max_burst);
+ return -EINVAL;
+ }
+
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
@@ -1566,7 +1682,7 @@ static void fail_all_commands(struct iscsi_conn *conn)
struct iscsi_cmd_task *ctask, *tmp;
/* flush pending */
- while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) {
+ list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
ctask->itt);
fail_command(conn, ctask, DID_BUS_BUSY << 16);
@@ -1609,8 +1725,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&session->lock);
- if (session->tt->suspend_conn_recv)
- session->tt->suspend_conn_recv(conn);
+ write_lock_bh(conn->recv_lock);
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ write_unlock_bh(conn->recv_lock);
mutex_lock(&conn->xmitmutex);
/*
@@ -1629,7 +1746,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
}
}
- session->tt->terminate_conn(conn);
/*
* flush queues.
*/
@@ -1697,6 +1813,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
+
+int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+ uint32_t value;
+
+ switch(param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ sscanf(buf, "%d", &conn->max_recv_dlength);
+ break;
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ sscanf(buf, "%d", &conn->max_xmit_dlength);
+ break;
+ case ISCSI_PARAM_HDRDGST_EN:
+ sscanf(buf, "%d", &conn->hdrdgst_en);
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ sscanf(buf, "%d", &conn->datadgst_en);
+ break;
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ sscanf(buf, "%d", &session->initial_r2t_en);
+ break;
+ case ISCSI_PARAM_MAX_R2T:
+ sscanf(buf, "%d", &session->max_r2t);
+ break;
+ case ISCSI_PARAM_IMM_DATA_EN:
+ sscanf(buf, "%d", &session->imm_data_en);
+ break;
+ case ISCSI_PARAM_FIRST_BURST:
+ sscanf(buf, "%d", &session->first_burst);
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ sscanf(buf, "%d", &session->max_burst);
+ break;
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ sscanf(buf, "%d", &session->pdu_inorder_en);
+ break;
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ sscanf(buf, "%d", &session->dataseq_inorder_en);
+ break;
+ case ISCSI_PARAM_ERL:
+ sscanf(buf, "%d", &session->erl);
+ break;
+ case ISCSI_PARAM_IFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ BUG_ON(value);
+ break;
+ case ISCSI_PARAM_OFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ BUG_ON(value);
+ break;
+ case ISCSI_PARAM_EXP_STATSN:
+ sscanf(buf, "%u", &conn->exp_statsn);
+ break;
+ case ISCSI_PARAM_TARGET_NAME:
+ /* this should not change between logins */
+ if (session->targetname)
+ break;
+
+ session->targetname = kstrdup(buf, GFP_KERNEL);
+ if (!session->targetname)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_TPGT:
+ sscanf(buf, "%d", &session->tpgt);
+ break;
+ case ISCSI_PARAM_PERSISTENT_PORT:
+ sscanf(buf, "%d", &conn->persistent_port);
+ break;
+ case ISCSI_PARAM_PERSISTENT_ADDRESS:
+ /*
+ * this is the address returned in discovery so it should
+ * not change between logins.
+ */
+ if (conn->persistent_address)
+ break;
+
+ conn->persistent_address = kstrdup(buf, GFP_KERNEL);
+ if (!conn->persistent_address)
+ return -ENOMEM;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_set_param);
+
+int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
+ enum iscsi_param param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch(param) {
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ len = sprintf(buf, "%d\n", session->initial_r2t_en);
+ break;
+ case ISCSI_PARAM_MAX_R2T:
+ len = sprintf(buf, "%hu\n", session->max_r2t);
+ break;
+ case ISCSI_PARAM_IMM_DATA_EN:
+ len = sprintf(buf, "%d\n", session->imm_data_en);
+ break;
+ case ISCSI_PARAM_FIRST_BURST:
+ len = sprintf(buf, "%u\n", session->first_burst);
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ len = sprintf(buf, "%u\n", session->max_burst);
+ break;
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ len = sprintf(buf, "%d\n", session->pdu_inorder_en);
+ break;
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
+ break;
+ case ISCSI_PARAM_ERL:
+ len = sprintf(buf, "%d\n", session->erl);
+ break;
+ case ISCSI_PARAM_TARGET_NAME:
+ len = sprintf(buf, "%s\n", session->targetname);
+ break;
+ case ISCSI_PARAM_TPGT:
+ len = sprintf(buf, "%d\n", session->tpgt);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_session_get_param);
+
+int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ int len;
+
+ switch(param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ len = sprintf(buf, "%u\n", conn->max_recv_dlength);
+ break;
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
+ break;
+ case ISCSI_PARAM_HDRDGST_EN:
+ len = sprintf(buf, "%d\n", conn->hdrdgst_en);
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ len = sprintf(buf, "%d\n", conn->datadgst_en);
+ break;
+ case ISCSI_PARAM_IFMARKER_EN:
+ len = sprintf(buf, "%d\n", conn->ifmarker_en);
+ break;
+ case ISCSI_PARAM_OFMARKER_EN:
+ len = sprintf(buf, "%d\n", conn->ofmarker_en);
+ break;
+ case ISCSI_PARAM_EXP_STATSN:
+ len = sprintf(buf, "%u\n", conn->exp_statsn);
+ break;
+ case ISCSI_PARAM_PERSISTENT_PORT:
+ len = sprintf(buf, "%d\n", conn->persistent_port);
+ break;
+ case ISCSI_PARAM_PERSISTENT_ADDRESS:
+ len = sprintf(buf, "%s\n", conn->persistent_address);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
+
MODULE_AUTHOR("Mike Christie");
MODULE_DESCRIPTION("iSCSI library functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
new file mode 100644
index 00000000000..aafdc92f831
--- /dev/null
+++ b/drivers/scsi/libsas/Kconfig
@@ -0,0 +1,39 @@
+#
+# Kernel configuration file for the SAS Class
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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; version 2 of the
+# License.
+#
+# 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
+#
+
+config SCSI_SAS_LIBSAS
+ tristate "SAS Domain Transport Attributes"
+ depends on SCSI
+ select SCSI_SAS_ATTRS
+ help
+ This provides transport specific helpers for SAS drivers which
+ use the domain device construct (like the aic94xxx).
+
+config SCSI_SAS_LIBSAS_DEBUG
+ bool "Compile the SAS Domain Transport Attributes in debug mode"
+ default y
+ depends on SCSI_SAS_LIBSAS
+ help
+ Compiles the SAS Layer in debug mode. In debug mode, the
+ SAS Layer prints diagnostic and debug messages.
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
new file mode 100644
index 00000000000..44d972a3b4b
--- /dev/null
+++ b/drivers/scsi/libsas/Makefile
@@ -0,0 +1,36 @@
+#
+# Kernel Makefile for the libsas helpers
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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; version 2 of the
+# License.
+#
+# 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
+
+ifeq ($(CONFIG_SCSI_SAS_LIBSAS_DEBUG),y)
+ EXTRA_CFLAGS += -DSAS_DEBUG
+endif
+
+obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o
+libsas-y += sas_init.o \
+ sas_phy.o \
+ sas_port.o \
+ sas_event.o \
+ sas_dump.o \
+ sas_discover.o \
+ sas_expander.o \
+ sas_scsi_host.o
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
new file mode 100644
index 00000000000..d977bd492d8
--- /dev/null
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -0,0 +1,749 @@
+/*
+ * Serial Attached SCSI (SAS) Discover process
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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/pci.h>
+#include <linux/scatterlist.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/* ---------- Basic task processing for discovery purposes ---------- */
+
+void sas_init_dev(struct domain_device *dev)
+{
+ INIT_LIST_HEAD(&dev->siblings);
+ INIT_LIST_HEAD(&dev->dev_list_node);
+ switch (dev->dev_type) {
+ case SAS_END_DEV:
+ break;
+ case EDGE_DEV:
+ case FANOUT_DEV:
+ INIT_LIST_HEAD(&dev->ex_dev.children);
+ break;
+ case SATA_DEV:
+ case SATA_PM:
+ case SATA_PM_PORT:
+ INIT_LIST_HEAD(&dev->sata_dev.children);
+ break;
+ default:
+ break;
+ }
+}
+
+static void sas_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ 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);
+
+ complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct scatterlist *scatter = NULL;
+ struct task_status_struct *ts = &task->task_status;
+ int num_scatter = 0;
+ int retries = 0;
+ struct sas_internal *i =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (pci_dma_dir != PCI_DMA_NONE) {
+ scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+ if (!scatter)
+ goto out;
+
+ sg_init_one(scatter, buffer, size);
+ num_scatter = 1;
+ }
+
+ task->task_proto = task->dev->tproto;
+ task->scatter = scatter;
+ task->num_scatter = num_scatter;
+ task->total_xfer_len = size;
+ task->data_dir = pci_dma_dir;
+ task->task_done = sas_disc_task_done;
+
+ for (retries = 0; retries < 5; retries++) {
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ init_completion(&task->completion);
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = sas_task_timedout;
+ task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+ res);
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ int res2;
+ SAS_DPRINTK("task aborted, flags:0x%x\n",
+ task->task_state_flags);
+ res2 = i->dft->lldd_abort_task(task);
+ SAS_DPRINTK("came back from abort task\n");
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ if (res2 == TMF_RESP_FUNC_COMPLETE)
+ continue; /* Retry the task */
+ else
+ goto ex_err;
+ }
+ }
+ if (task->task_status.stat == SAM_BUSY ||
+ task->task_status.stat == SAM_TASK_SET_FULL ||
+ task->task_status.stat == SAS_QUEUE_FULL) {
+ SAS_DPRINTK("task: q busy, sleeping...\n");
+ schedule_timeout_interruptible(HZ);
+ } else if (task->task_status.stat == SAM_CHECK_COND) {
+ struct scsi_sense_hdr shdr;
+
+ if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+ &shdr)) {
+ SAS_DPRINTK("couldn't normalize sense\n");
+ continue;
+ }
+ if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+ (shdr.sense_key == 2 && shdr.asc == 4 &&
+ shdr.ascq == 1)) {
+ SAS_DPRINTK("device %016llx LUN: %016llx "
+ "powering up or not ready yet, "
+ "sleeping...\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN));
+
+ schedule_timeout_interruptible(5*HZ);
+ } else if (shdr.sense_key == 1) {
+ res = 0;
+ break;
+ } else if (shdr.sense_key == 5) {
+ break;
+ } else {
+ SAS_DPRINTK("dev %016llx LUN: %016llx "
+ "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN),
+ shdr.sense_key,
+ shdr.asc, shdr.ascq);
+ }
+ } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+ task->task_status.stat != SAM_GOOD) {
+ SAS_DPRINTK("task finished with resp:0x%x, "
+ "stat:0x%x\n",
+ task->task_status.resp,
+ task->task_status.stat);
+ goto ex_err;
+ } else {
+ res = 0;
+ break;
+ }
+ }
+ex_err:
+ if (pci_dma_dir != PCI_DMA_NONE)
+ kfree(scatter);
+out:
+ return res;
+}
+
+/* ---------- Domain device discovery ---------- */
+
+/**
+ * sas_get_port_device -- Discover devices which caused port creation
+ * @port: pointer to struct sas_port of interest
+ *
+ * Devices directly attached to a HA port, have no parent. This is
+ * how we know they are (domain) "root" devices. All other devices
+ * do, and should have their "parent" pointer set appropriately as
+ * soon as a child device is discovered.
+ */
+static int sas_get_port_device(struct asd_sas_port *port)
+{
+ unsigned long flags;
+ struct asd_sas_phy *phy;
+ struct sas_rphy *rphy;
+ struct domain_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ if (list_empty(&port->phy_list)) {
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+ kfree(dev);
+ return -ENODEV;
+ }
+ phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
+ spin_lock(&phy->frame_rcvd_lock);
+ memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
+ (size_t)phy->frame_rcvd_size));
+ spin_unlock(&phy->frame_rcvd_lock);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+
+ if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+ if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
+ fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
+ && (fis->device & ~0x10) == 0)
+ dev->dev_type = SATA_PM;
+ else
+ dev->dev_type = SATA_DEV;
+ dev->tproto = SATA_PROTO;
+ } else {
+ struct sas_identify_frame *id =
+ (struct sas_identify_frame *) dev->frame_rcvd;
+ dev->dev_type = id->dev_type;
+ dev->iproto = id->initiator_bits;
+ dev->tproto = id->target_bits;
+ }
+
+ sas_init_dev(dev);
+
+ switch (dev->dev_type) {
+ case SAS_END_DEV:
+ rphy = sas_end_device_alloc(port->port);
+ break;
+ case EDGE_DEV:
+ rphy = sas_expander_alloc(port->port,
+ SAS_EDGE_EXPANDER_DEVICE);
+ break;
+ case FANOUT_DEV:
+ rphy = sas_expander_alloc(port->port,
+ SAS_FANOUT_EXPANDER_DEVICE);
+ break;
+ case SATA_DEV:
+ default:
+ printk("ERROR: Unidentified device type %d\n", dev->dev_type);
+ rphy = NULL;
+ break;
+ }
+
+ if (!rphy) {
+ kfree(dev);
+ return -ENODEV;
+ }
+ rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
+ memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
+ sas_fill_in_rphy(dev, rphy);
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ port->port_dev = dev;
+ dev->port = port;
+ dev->linkrate = port->linkrate;
+ dev->min_linkrate = port->linkrate;
+ dev->max_linkrate = port->linkrate;
+ dev->pathways = port->num_phys;
+ memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
+ memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
+ memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
+ port->disc.max_level = 0;
+
+ dev->rphy = rphy;
+ spin_lock(&port->dev_list_lock);
+ list_add_tail(&dev->dev_list_node, &port->dev_list);
+ spin_unlock(&port->dev_list_lock);
+
+ return 0;
+}
+
+/* ---------- Discover and Revalidate ---------- */
+
+/* ---------- SATA ---------- */
+
+static void sas_get_ata_command_set(struct domain_device *dev)
+{
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+
+ if ((fis->sector_count == 1 && /* ATA */
+ fis->lbal == 1 &&
+ fis->lbam == 0 &&
+ fis->lbah == 0 &&
+ fis->device == 0)
+ ||
+ (fis->sector_count == 0 && /* CE-ATA (mATA) */
+ fis->lbal == 0 &&
+ fis->lbam == 0xCE &&
+ fis->lbah == 0xAA &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+ else if ((fis->interrupt_reason == 1 && /* ATAPI */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x14 &&
+ fis->byte_count_high == 0xEB &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+ else if ((fis->sector_count == 1 && /* SEMB */
+ fis->lbal == 1 &&
+ fis->lbam == 0x3C &&
+ fis->lbah == 0xC3 &&
+ fis->device == 0)
+ ||
+ (fis->interrupt_reason == 1 && /* SATA PM */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x69 &&
+ fis->byte_count_high == 0x96 &&
+ (fis->device & ~0x10) == 0))
+
+ /* Treat it as a superset? */
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+ u8 features, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct sas_task *task;
+ struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+ &dev->frame_rcvd[0];
+
+ res = -ENOMEM;
+ task = sas_alloc_task(GFP_KERNEL);
+ if (!task)
+ goto out;
+
+ task->dev = dev;
+
+ task->ata_task.fis.command = command;
+ task->ata_task.fis.features = features;
+ task->ata_task.fis.device = d2h_fis->device;
+ task->ata_task.retry_count = 1;
+
+ res = sas_execute_task(task, buffer, size, pci_dma_dir);
+
+ sas_free_task(task);
+out:
+ return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+ unsigned long flags;
+ struct asd_sas_port *port = dev->port;
+ struct asd_sas_phy *phy;
+
+ BUG_ON(dev->parent);
+
+ memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ list_for_each_entry(phy, &port->phy_list, port_phy_el)
+ memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV 0xEC
+#define ATA_IDENTIFY_PACKET_DEV 0xA1
+#define ATA_SET_FEATURES 0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+ int res;
+ __le16 *identify_x;
+ u8 command;
+
+ identify_x = kzalloc(512, GFP_KERNEL);
+ if (!identify_x)
+ return -ENOMEM;
+
+ if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+ dev->sata_dev.identify_device = identify_x;
+ command = ATA_IDENTIFY_DEV;
+ } else {
+ dev->sata_dev.identify_packet_device = identify_x;
+ command = ATA_IDENTIFY_PACKET_DEV;
+ }
+
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+
+ /* lives on the media? */
+ if (le16_to_cpu(identify_x[0]) & 4) {
+ /* incomplete response */
+ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+ "dev %llx\n", SAS_ADDR(dev->sas_addr));
+ if (!le16_to_cpu(identify_x[83] & (1<<6)))
+ goto cont1;
+ res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+ ATA_FEATURE_PUP_STBY_SPIN_UP,
+ NULL, 0, PCI_DMA_NONE);
+ if (res)
+ goto cont1;
+
+ schedule_timeout_interruptible(5*HZ); /* More time? */
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+ }
+cont1:
+ /* Get WWN */
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+ (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+ == 0x5000) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ dev->sas_addr[2*i] =
+ (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+ dev->sas_addr[2*i+1] =
+ le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+ }
+ }
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ if (!dev->parent)
+ sas_sata_propagate_sas_addr(dev);
+
+ /* XXX Hint: register this SATA device with SATL.
+ When this returns, dev->sata_dev->lu is alive and
+ present.
+ sas_satl_register_dev(dev);
+ */
+ return 0;
+out_err:
+ dev->sata_dev.identify_packet_device = NULL;
+ dev->sata_dev.identify_device = NULL;
+ kfree(identify_x);
+ return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+int sas_notify_lldd_dev_found(struct domain_device *dev)
+{
+ int res = 0;
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ if (i->dft->lldd_dev_found) {
+ res = i->dft->lldd_dev_found(dev);
+ if (res) {
+ printk("sas: driver on pcidev %s cannot handle "
+ "device %llx, error:%d\n",
+ pci_name(sas_ha->pcidev),
+ SAS_ADDR(dev->sas_addr), res);
+ }
+ }
+ return res;
+}
+
+
+void sas_notify_lldd_dev_gone(struct domain_device *dev)
+{
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ if (i->dft->lldd_dev_gone)
+ i->dft->lldd_dev_gone(dev);
+}
+
+/* ---------- Common/dispatchers ---------- */
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it. Then depending on the type of device we call the appropriate
+ * discover functions. Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it. That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time. Devices directly attached to a HA
+ * port, have no parents. All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+ int res;
+
+ sas_get_ata_command_set(dev);
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ res = sas_discover_sata_dev(dev);
+ break;
+ case SATA_PM:
+ res = sas_discover_sata_pm(dev);
+ break;
+ default:
+ break;
+ }
+
+ sas_notify_lldd_dev_gone(dev);
+ if (!res) {
+ sas_notify_lldd_dev_found(dev);
+ }
+ return res;
+}
+
+/**
+ * sas_discover_end_dev -- discover an end device (SSP, etc)
+ * @end: pointer to domain device of interest
+ *
+ * See comment in sas_discover_sata().
+ */
+int sas_discover_end_dev(struct domain_device *dev)
+{
+ int res;
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ res = sas_rphy_add(dev->rphy);
+ if (res)
+ goto out_err;
+
+ /* do this to get the end device port attributes which will have
+ * been scanned in sas_rphy_add */
+ sas_notify_lldd_dev_gone(dev);
+ sas_notify_lldd_dev_found(dev);
+
+ return 0;
+
+out_err:
+ sas_notify_lldd_dev_gone(dev);
+ return res;
+}
+
+/* ---------- Device registration and unregistration ---------- */
+
+static inline void sas_unregister_common_dev(struct domain_device *dev)
+{
+ sas_notify_lldd_dev_gone(dev);
+ if (!dev->parent)
+ dev->port->port_dev = NULL;
+ else
+ list_del_init(&dev->siblings);
+ list_del_init(&dev->dev_list_node);
+}
+
+void sas_unregister_dev(struct domain_device *dev)
+{
+ if (dev->rphy) {
+ sas_remove_children(&dev->rphy->dev);
+ sas_rphy_delete(dev->rphy);
+ dev->rphy = NULL;
+ }
+ if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
+ /* remove the phys and ports, everything else should be gone */
+ kfree(dev->ex_dev.ex_phy);
+ dev->ex_dev.ex_phy = NULL;
+ }
+ sas_unregister_common_dev(dev);
+}
+
+void sas_unregister_domain_devices(struct asd_sas_port *port)
+{
+ struct domain_device *dev, *n;
+
+ list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node)
+ sas_unregister_dev(dev);
+
+ port->port->rphy = NULL;
+
+}
+
+/* ---------- Discovery and Revalidation ---------- */
+
+/**
+ * sas_discover_domain -- discover the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+static void sas_discover_domain(void *data)
+{
+ int error = 0;
+ struct asd_sas_port *port = data;
+
+ sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
+ &port->disc.pending);
+
+ if (port->port_dev)
+ return ;
+ else {
+ error = sas_get_port_device(port);
+ if (error)
+ return;
+ }
+
+ SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
+ current->pid);
+
+ switch (port->port_dev->dev_type) {
+ case SAS_END_DEV:
+ error = sas_discover_end_dev(port->port_dev);
+ break;
+ case EDGE_DEV:
+ case FANOUT_DEV:
+ error = sas_discover_root_expander(port->port_dev);
+ break;
+ case SATA_DEV:
+ case SATA_PM:
+ error = sas_discover_sata(port->port_dev);
+ break;
+ default:
+ SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type);
+ break;
+ }
+
+ if (error) {
+ kfree(port->port_dev); /* not kobject_register-ed yet */
+ port->port_dev = NULL;
+ }
+
+ SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
+ current->pid, error);
+}
+
+static void sas_revalidate_domain(void *data)
+{
+ int res = 0;
+ struct asd_sas_port *port = data;
+
+ sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
+ &port->disc.pending);
+
+ SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
+ current->pid);
+ if (port->port_dev)
+ res = sas_ex_revalidate_domain(port->port_dev);
+
+ SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
+ port->id, current->pid, res);
+}
+
+/* ---------- Events ---------- */
+
+int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
+{
+ struct sas_discovery *disc;
+
+ if (!port)
+ return 0;
+ disc = &port->disc;
+
+ BUG_ON(ev >= DISC_NUM_EVENTS);
+
+ sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
+ &disc->disc_work[ev], port->ha->core.shost);
+
+ return 0;
+}
+
+/**
+ * sas_init_disc -- initialize the discovery struct in the port
+ * @port: pointer to struct port
+ *
+ * Called when the ports are being initialized.
+ */
+void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
+{
+ int i;
+
+ static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = {
+ [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);
+}
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
new file mode 100644
index 00000000000..f1246d2c9be
--- /dev/null
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -0,0 +1,76 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_dump.h"
+
+#ifdef SAS_DEBUG
+
+static const char *sas_hae_str[] = {
+ [0] = "HAE_RESET",
+};
+
+static const char *sas_porte_str[] = {
+ [0] = "PORTE_BYTES_DMAED",
+ [1] = "PORTE_BROADCAST_RCVD",
+ [2] = "PORTE_LINK_RESET_ERR",
+ [3] = "PORTE_TIMER_EVENT",
+ [4] = "PORTE_HARD_RESET",
+};
+
+static const char *sas_phye_str[] = {
+ [0] = "PHYE_LOSS_OF_SIGNAL",
+ [1] = "PHYE_OOB_DONE",
+ [2] = "PHYE_OOB_ERROR",
+ [3] = "PHYE_SPINUP_HOLD",
+};
+
+void sas_dprint_porte(int phyid, enum port_event pe)
+{
+ SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]);
+}
+void sas_dprint_phye(int phyid, enum phy_event pe)
+{
+ SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]);
+}
+
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
+{
+ SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
+ sas_hae_str[he]);
+}
+
+void sas_dump_port(struct asd_sas_port *port)
+{
+ SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class);
+ SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id,
+ SAS_ADDR(port->sas_addr));
+ SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id,
+ SAS_ADDR(port->attached_sas_addr));
+ SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto);
+ SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto);
+ SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode);
+ SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys);
+}
+
+#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_dump.h b/drivers/scsi/libsas/sas_dump.h
new file mode 100644
index 00000000000..47b45d4f525
--- /dev/null
+++ b/drivers/scsi/libsas/sas_dump.h
@@ -0,0 +1,42 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_internal.h"
+
+#ifdef SAS_DEBUG
+
+void sas_dprint_porte(int phyid, enum port_event pe);
+void sas_dprint_phye(int phyid, enum phy_event pe);
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he);
+void sas_dump_port(struct asd_sas_port *port);
+
+#else /* SAS_DEBUG */
+
+static inline void sas_dprint_porte(int phyid, enum port_event pe) { }
+static inline void sas_dprint_phye(int phyid, enum phy_event pe) { }
+static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha,
+ enum ha_event he) { }
+static inline void sas_dump_port(struct asd_sas_port *port) { }
+
+#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
new file mode 100644
index 00000000000..19110ed1c89
--- /dev/null
+++ b/drivers/scsi/libsas/sas_event.c
@@ -0,0 +1,75 @@
+/*
+ * Serial Attached SCSI (SAS) Event processing
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 <scsi/scsi_host.h>
+#include "sas_internal.h"
+#include "sas_dump.h"
+
+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);
+}
+
+static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
+{
+ struct sas_ha_struct *ha = phy->ha;
+
+ BUG_ON(event >= PORT_NUM_EVENTS);
+
+ sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
+ &phy->port_events[event], ha->core.shost);
+}
+
+static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+{
+ struct sas_ha_struct *ha = phy->ha;
+
+ BUG_ON(event >= PHY_NUM_EVENTS);
+
+ sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
+ &phy->phy_events[event], ha->core.shost);
+}
+
+int sas_init_events(struct sas_ha_struct *sas_ha)
+{
+ static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = {
+ [HAE_RESET] = sas_hae_reset,
+ };
+
+ int i;
+
+ 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);
+
+ sas_ha->notify_ha_event = notify_ha_event;
+ sas_ha->notify_port_event = notify_port_event;
+ sas_ha->notify_phy_event = notify_phy_event;
+
+ return 0;
+}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
new file mode 100644
index 00000000000..30b8014bcc7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -0,0 +1,1855 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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/pci.h>
+#include <linux/scatterlist.h>
+
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+static int sas_discover_expander(struct domain_device *dev);
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
+static int sas_configure_phy(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int include);
+static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
+
+#if 0
+/* FIXME: smp needs to migrate into the sas class */
+static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
+static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
+#endif
+
+/* ---------- SMP task management ---------- */
+
+static void smp_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ 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);
+
+ complete(&task->completion);
+}
+
+static void smp_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+/* Give it some long enough timeout. In seconds. */
+#define SMP_TIMEOUT 10
+
+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);
+ 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);
+
+ task->task_done = smp_task_done;
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = smp_task_timedout;
+ task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+
+ 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;
+ 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);
+ return res;
+}
+
+/* ---------- Allocations ---------- */
+
+static inline void *alloc_smp_req(int size)
+{
+ u8 *p = kzalloc(size, GFP_KERNEL);
+ if (p)
+ p[0] = SMP_REQUEST;
+ return p;
+}
+
+static inline void *alloc_smp_resp(int size)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+
+/* ---------- Expander configuration ---------- */
+
+static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
+ void *disc_resp)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ struct smp_resp *resp = disc_resp;
+ struct discover_resp *dr = &resp->disc;
+ struct sas_rphy *rphy = dev->rphy;
+ int rediscover = (phy->phy != NULL);
+
+ if (!rediscover) {
+ phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
+
+ /* FIXME: error_handling */
+ BUG_ON(!phy->phy);
+ }
+
+ switch (resp->result) {
+ case SMP_RESP_PHY_VACANT:
+ phy->phy_state = PHY_VACANT;
+ return;
+ default:
+ phy->phy_state = PHY_NOT_PRESENT;
+ return;
+ case SMP_RESP_FUNC_ACC:
+ phy->phy_state = PHY_EMPTY; /* do not know yet */
+ break;
+ }
+
+ phy->phy_id = phy_id;
+ phy->attached_dev_type = dr->attached_dev_type;
+ phy->linkrate = dr->linkrate;
+ phy->attached_sata_host = dr->attached_sata_host;
+ phy->attached_sata_dev = dr->attached_sata_dev;
+ phy->attached_sata_ps = dr->attached_sata_ps;
+ phy->attached_iproto = dr->iproto << 1;
+ phy->attached_tproto = dr->tproto << 1;
+ memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
+ phy->attached_phy_id = dr->attached_phy_id;
+ phy->phy_change_count = dr->change_count;
+ phy->routing_attr = dr->routing_attr;
+ phy->virtual = dr->virtual;
+ phy->last_da_index = -1;
+
+ phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
+ phy->phy->identify.target_port_protocols = phy->attached_tproto;
+ phy->phy->identify.phy_identifier = phy_id;
+ phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
+ phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
+ phy->phy->minimum_linkrate = dr->pmin_linkrate;
+ phy->phy->maximum_linkrate = dr->pmax_linkrate;
+ phy->phy->negotiated_linkrate = phy->linkrate;
+
+ if (!rediscover)
+ sas_phy_add(phy->phy);
+
+ SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
+ SAS_ADDR(dev->sas_addr), phy->phy_id,
+ phy->routing_attr == TABLE_ROUTING ? 'T' :
+ phy->routing_attr == DIRECT_ROUTING ? 'D' :
+ phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
+ SAS_ADDR(phy->attached_sas_addr));
+
+ return;
+}
+
+#define DISCOVER_REQ_SIZE 16
+#define DISCOVER_RESP_SIZE 56
+
+static int sas_ex_phy_discover(struct domain_device *dev, int single)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = 0;
+ u8 *disc_req;
+ u8 *disc_resp;
+
+ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+ if (!disc_req)
+ return -ENOMEM;
+
+ disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
+ if (!disc_resp) {
+ kfree(disc_req);
+ return -ENOMEM;
+ }
+
+ disc_req[1] = SMP_DISCOVER;
+
+ if (0 <= single && single < ex->num_phys) {
+ disc_req[9] = single;
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ goto out_err;
+ sas_set_ex_phy(dev, single, disc_resp);
+ } else {
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ disc_req[9] = i;
+ res = smp_execute_task(dev, disc_req,
+ DISCOVER_REQ_SIZE, disc_resp,
+ DISCOVER_RESP_SIZE);
+ if (res)
+ goto out_err;
+ sas_set_ex_phy(dev, i, disc_resp);
+ }
+ }
+out_err:
+ kfree(disc_resp);
+ kfree(disc_req);
+ return res;
+}
+
+static int sas_expander_discover(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = -ENOMEM;
+
+ ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL);
+ if (!ex->ex_phy)
+ return -ENOMEM;
+
+ res = sas_ex_phy_discover(dev, -1);
+ if (res)
+ goto out_err;
+
+ return 0;
+ out_err:
+ kfree(ex->ex_phy);
+ ex->ex_phy = NULL;
+ return res;
+}
+
+#define MAX_EXPANDER_PHYS 128
+
+static void ex_assign_report_general(struct domain_device *dev,
+ struct smp_resp *resp)
+{
+ struct report_general_resp *rg = &resp->rg;
+
+ dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
+ dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
+ dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
+ dev->ex_dev.conf_route_table = rg->conf_route_table;
+ dev->ex_dev.configuring = rg->configuring;
+ memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
+}
+
+#define RG_REQ_SIZE 8
+#define RG_RESP_SIZE 32
+
+static int sas_ex_general(struct domain_device *dev)
+{
+ u8 *rg_req;
+ struct smp_resp *rg_resp;
+ int res;
+ int i;
+
+ rg_req = alloc_smp_req(RG_REQ_SIZE);
+ if (!rg_req)
+ return -ENOMEM;
+
+ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+ if (!rg_resp) {
+ kfree(rg_req);
+ return -ENOMEM;
+ }
+
+ rg_req[1] = SMP_REPORT_GENERAL;
+
+ for (i = 0; i < 5; i++) {
+ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+ RG_RESP_SIZE);
+
+ if (res) {
+ SAS_DPRINTK("RG to ex %016llx failed:0x%x\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out;
+ } else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n",
+ SAS_ADDR(dev->sas_addr), rg_resp->result);
+ res = rg_resp->result;
+ goto out;
+ }
+
+ ex_assign_report_general(dev, rg_resp);
+
+ if (dev->ex_dev.configuring) {
+ SAS_DPRINTK("RG: ex %llx self-configuring...\n",
+ SAS_ADDR(dev->sas_addr));
+ schedule_timeout_interruptible(5*HZ);
+ } else
+ break;
+ }
+out:
+ kfree(rg_req);
+ kfree(rg_resp);
+ return res;
+}
+
+static void ex_assign_manuf_info(struct domain_device *dev, void
+ *_mi_resp)
+{
+ u8 *mi_resp = _mi_resp;
+ struct sas_rphy *rphy = dev->rphy;
+ struct sas_expander_device *edev = rphy_to_expander_device(rphy);
+
+ memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
+ memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
+ memcpy(edev->product_rev, mi_resp + 36,
+ SAS_EXPANDER_PRODUCT_REV_LEN);
+
+ if (mi_resp[8] & 1) {
+ memcpy(edev->component_vendor_id, mi_resp + 40,
+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+ edev->component_id = mi_resp[48] << 8 | mi_resp[49];
+ edev->component_revision_id = mi_resp[50];
+ }
+}
+
+#define MI_REQ_SIZE 8
+#define MI_RESP_SIZE 64
+
+static int sas_ex_manuf_info(struct domain_device *dev)
+{
+ u8 *mi_req;
+ u8 *mi_resp;
+ int res;
+
+ mi_req = alloc_smp_req(MI_REQ_SIZE);
+ if (!mi_req)
+ return -ENOMEM;
+
+ mi_resp = alloc_smp_resp(MI_RESP_SIZE);
+ if (!mi_resp) {
+ kfree(mi_req);
+ return -ENOMEM;
+ }
+
+ mi_req[1] = SMP_REPORT_MANUF_INFO;
+
+ res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
+ if (res) {
+ SAS_DPRINTK("MI: ex %016llx failed:0x%x\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out;
+ } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n",
+ SAS_ADDR(dev->sas_addr), mi_resp[2]);
+ goto out;
+ }
+
+ ex_assign_manuf_info(dev, mi_resp);
+out:
+ kfree(mi_req);
+ kfree(mi_resp);
+ return res;
+}
+
+#define PC_REQ_SIZE 44
+#define PC_RESP_SIZE 8
+
+int sas_smp_phy_control(struct domain_device *dev, int phy_id,
+ enum phy_func phy_func,
+ struct sas_phy_linkrates *rates)
+{
+ u8 *pc_req;
+ u8 *pc_resp;
+ int res;
+
+ pc_req = alloc_smp_req(PC_REQ_SIZE);
+ if (!pc_req)
+ return -ENOMEM;
+
+ pc_resp = alloc_smp_resp(PC_RESP_SIZE);
+ if (!pc_resp) {
+ kfree(pc_req);
+ return -ENOMEM;
+ }
+
+ pc_req[1] = SMP_PHY_CONTROL;
+ pc_req[9] = phy_id;
+ pc_req[10]= phy_func;
+ if (rates) {
+ pc_req[32] = rates->minimum_linkrate << 4;
+ pc_req[33] = rates->maximum_linkrate << 4;
+ }
+
+ res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
+
+ kfree(pc_resp);
+ kfree(pc_req);
+ return res;
+}
+
+static void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+
+ sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL);
+ phy->linkrate = SAS_PHY_DISABLED;
+}
+
+static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
+ sas_ex_disable_phy(dev, i);
+ }
+}
+
+static int sas_dev_present_in_domain(struct asd_sas_port *port,
+ u8 *sas_addr)
+{
+ struct domain_device *dev;
+
+ if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
+ return 1;
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
+ return 1;
+ }
+ return 0;
+}
+
+#define RPEL_REQ_SIZE 16
+#define RPEL_RESP_SIZE 32
+int sas_smp_get_phy_events(struct sas_phy *phy)
+{
+ int res;
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *dev = sas_find_dev_by_rphy(rphy);
+ u8 *req = alloc_smp_req(RPEL_REQ_SIZE);
+ u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL);
+
+ if (!resp)
+ return -ENOMEM;
+
+ req[1] = SMP_REPORT_PHY_ERR_LOG;
+ req[9] = phy->number;
+
+ res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
+ resp, RPEL_RESP_SIZE);
+
+ if (!res)
+ goto out;
+
+ phy->invalid_dword_count = scsi_to_u32(&resp[12]);
+ phy->running_disparity_error_count = scsi_to_u32(&resp[16]);
+ phy->loss_of_dword_sync_count = scsi_to_u32(&resp[20]);
+ phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
+
+ out:
+ kfree(resp);
+ return res;
+
+}
+
+#define RPS_REQ_SIZE 16
+#define RPS_RESP_SIZE 60
+
+static int sas_get_report_phy_sata(struct domain_device *dev,
+ int phy_id,
+ struct smp_resp *rps_resp)
+{
+ int res;
+ u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+
+ if (!rps_req)
+ return -ENOMEM;
+
+ rps_req[1] = SMP_REPORT_PHY_SATA;
+ rps_req[9] = phy_id;
+
+ res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
+ rps_resp, RPS_RESP_SIZE);
+
+ kfree(rps_req);
+ return 0;
+}
+
+static void sas_ex_get_linkrate(struct domain_device *parent,
+ struct domain_device *child,
+ struct ex_phy *parent_phy)
+{
+ struct expander_device *parent_ex = &parent->ex_dev;
+ struct sas_port *port;
+ int i;
+
+ child->pathways = 0;
+
+ port = parent_phy->port;
+
+ for (i = 0; i < parent_ex->num_phys; i++) {
+ struct ex_phy *phy = &parent_ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr)) {
+
+ child->min_linkrate = min(parent->min_linkrate,
+ phy->linkrate);
+ child->max_linkrate = max(parent->max_linkrate,
+ phy->linkrate);
+ child->pathways++;
+ sas_port_add_phy(port, phy->phy);
+ }
+ }
+ child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
+ child->pathways = min(child->pathways, parent->pathways);
+}
+
+static struct domain_device *sas_ex_discover_end_dev(
+ struct domain_device *parent, int phy_id)
+{
+ struct expander_device *parent_ex = &parent->ex_dev;
+ struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ struct sas_rphy *rphy;
+ int res;
+
+ if (phy->attached_sata_host || phy->attached_sata_ps)
+ return NULL;
+
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
+ if (!child)
+ return NULL;
+
+ child->parent = parent;
+ child->port = parent->port;
+ 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);
+ sas_ex_get_linkrate(parent, child, phy);
+
+ if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
+ child->dev_type = SATA_DEV;
+ if (phy->attached_tproto & SAS_PROTO_STP)
+ child->tproto = phy->attached_tproto;
+ if (phy->attached_sata_dev)
+ child->tproto |= SATA_DEV;
+ res = sas_get_report_phy_sata(parent, phy_id,
+ &child->sata_dev.rps_resp);
+ if (res) {
+ 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;
+ }
+ memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
+ sizeof(struct dev_to_host_fis));
+ sas_init_dev(child);
+ res = sas_discover_sata(child);
+ if (res) {
+ SAS_DPRINTK("sas_discover_sata() for device %16llx at "
+ "%016llx:0x%x returned 0x%x\n",
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(parent->sas_addr), phy_id, res);
+ kfree(child);
+ return NULL;
+ }
+ } 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);
+ child->tproto = phy->attached_tproto;
+ sas_init_dev(child);
+
+ child->rphy = rphy;
+ sas_fill_in_rphy(child, rphy);
+
+ spin_lock(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock(&parent->port->dev_list_lock);
+
+ res = sas_discover_end_dev(child);
+ if (res) {
+ SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
+ "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;
+ }
+ } else {
+ SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
+ phy->attached_tproto, SAS_ADDR(parent->sas_addr),
+ phy_id);
+ }
+
+ list_add_tail(&child->siblings, &parent_ex->children);
+ return child;
+}
+
+static struct domain_device *sas_ex_discover_expander(
+ struct domain_device *parent, int phy_id)
+{
+ struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
+ struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ struct sas_rphy *rphy;
+ struct sas_expander_device *edev;
+ struct asd_sas_port *port;
+ int res;
+
+ if (phy->routing_attr == DIRECT_ROUTING) {
+ SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not "
+ "allowed\n",
+ SAS_ADDR(parent->sas_addr), phy_id,
+ SAS_ADDR(phy->attached_sas_addr),
+ phy->attached_phy_id);
+ return NULL;
+ }
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
+ if (!child)
+ return NULL;
+
+ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
+ /* FIXME: better error handling */
+ BUG_ON(sas_port_add(phy->port) != 0);
+
+
+ switch (phy->attached_dev_type) {
+ case EDGE_DEV:
+ rphy = sas_expander_alloc(phy->port,
+ SAS_EDGE_EXPANDER_DEVICE);
+ break;
+ case FANOUT_DEV:
+ rphy = sas_expander_alloc(phy->port,
+ SAS_FANOUT_EXPANDER_DEVICE);
+ break;
+ default:
+ rphy = NULL; /* shut gcc up */
+ BUG();
+ }
+ port = parent->port;
+ child->rphy = rphy;
+ edev = rphy_to_expander_device(rphy);
+ child->dev_type = phy->attached_dev_type;
+ child->parent = parent;
+ child->port = port;
+ child->iproto = phy->attached_iproto;
+ child->tproto = phy->attached_tproto;
+ memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+ sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
+ sas_ex_get_linkrate(parent, child, phy);
+ edev->level = parent_ex->level + 1;
+ parent->port->disc.max_level = max(parent->port->disc.max_level,
+ edev->level);
+ sas_init_dev(child);
+ sas_fill_in_rphy(child, rphy);
+ sas_rphy_add(rphy);
+
+ spin_lock(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock(&parent->port->dev_list_lock);
+
+ res = sas_discover_expander(child);
+ if (res) {
+ kfree(child);
+ return NULL;
+ }
+ list_add_tail(&child->siblings, &parent->ex_dev.children);
+ return child;
+}
+
+static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ int res = 0;
+
+ /* Phy state */
+ if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) {
+ if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL))
+ res = sas_ex_phy_discover(dev, phy_id);
+ if (res)
+ return res;
+ }
+
+ /* Parent and domain coherency */
+ if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+ SAS_ADDR(dev->port->sas_addr))) {
+ sas_add_parent_port(dev, phy_id);
+ return 0;
+ }
+ if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+ SAS_ADDR(dev->parent->sas_addr))) {
+ sas_add_parent_port(dev, phy_id);
+ if (ex_phy->routing_attr == TABLE_ROUTING)
+ sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1);
+ return 0;
+ }
+
+ if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
+ sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
+
+ if (ex_phy->attached_dev_type == NO_DEVICE) {
+ if (ex_phy->routing_attr == DIRECT_ROUTING) {
+ memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ sas_configure_routing(dev, ex_phy->attached_sas_addr);
+ }
+ return 0;
+ } else if (ex_phy->linkrate == SAS_LINK_RATE_UNKNOWN)
+ return 0;
+
+ if (ex_phy->attached_dev_type != SAS_END_DEV &&
+ ex_phy->attached_dev_type != FANOUT_DEV &&
+ ex_phy->attached_dev_type != EDGE_DEV) {
+ SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
+ "phy 0x%x\n", ex_phy->attached_dev_type,
+ SAS_ADDR(dev->sas_addr),
+ phy_id);
+ return 0;
+ }
+
+ res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
+ if (res) {
+ SAS_DPRINTK("configure routing for dev %016llx "
+ "reported 0x%x. Forgotten\n",
+ SAS_ADDR(ex_phy->attached_sas_addr), res);
+ sas_disable_routing(dev, ex_phy->attached_sas_addr);
+ return res;
+ }
+
+ switch (ex_phy->attached_dev_type) {
+ case SAS_END_DEV:
+ child = sas_ex_discover_end_dev(dev, phy_id);
+ break;
+ case FANOUT_DEV:
+ if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
+ SAS_DPRINTK("second fanout expander %016llx phy 0x%x "
+ "attached to ex %016llx phy 0x%x\n",
+ SAS_ADDR(ex_phy->attached_sas_addr),
+ ex_phy->attached_phy_id,
+ SAS_ADDR(dev->sas_addr),
+ phy_id);
+ sas_ex_disable_phy(dev, phy_id);
+ break;
+ } else
+ memcpy(dev->port->disc.fanout_sas_addr,
+ ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
+ /* fallthrough */
+ case EDGE_DEV:
+ child = sas_ex_discover_expander(dev, phy_id);
+ break;
+ default:
+ break;
+ }
+
+ if (child) {
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ if (ex->ex_phy[i].phy_state == PHY_VACANT ||
+ ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr))
+ ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+ }
+ }
+
+ return res;
+}
+
+static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if ((phy->attached_dev_type == EDGE_DEV ||
+ phy->attached_dev_type == FANOUT_DEV) &&
+ phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+ memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int sas_check_level_subtractive_boundary(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct domain_device *child;
+ u8 sub_addr[8] = {0, };
+
+ list_for_each_entry(child, &ex->children, siblings) {
+ if (child->dev_type != EDGE_DEV &&
+ child->dev_type != FANOUT_DEV)
+ continue;
+ if (sub_addr[0] == 0) {
+ sas_find_sub_addr(child, sub_addr);
+ continue;
+ } else {
+ u8 s2[8];
+
+ if (sas_find_sub_addr(child, s2) &&
+ (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
+
+ SAS_DPRINTK("ex %016llx->%016llx-?->%016llx "
+ "diverges from subtractive "
+ "boundary %016llx\n",
+ SAS_ADDR(dev->sas_addr),
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(s2),
+ SAS_ADDR(sub_addr));
+
+ sas_ex_disable_port(child, s2);
+ }
+ }
+ }
+ return 0;
+}
+/**
+ * sas_ex_discover_devices -- discover devices attached to this expander
+ * dev: pointer to the expander domain device
+ * single: if you want to do a single phy, else set to -1;
+ *
+ * Configure this expander for use with its devices and register the
+ * devices of this expander.
+ */
+static int sas_ex_discover_devices(struct domain_device *dev, int single)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i = 0, end = ex->num_phys;
+ int res = 0;
+
+ if (0 <= single && single < end) {
+ i = single;
+ end = i+1;
+ }
+
+ for ( ; i < end; i++) {
+ struct ex_phy *ex_phy = &ex->ex_phy[i];
+
+ if (ex_phy->phy_state == PHY_VACANT ||
+ ex_phy->phy_state == PHY_NOT_PRESENT ||
+ ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
+ continue;
+
+ switch (ex_phy->linkrate) {
+ case SAS_PHY_DISABLED:
+ case SAS_PHY_RESET_PROBLEM:
+ case SAS_SATA_PORT_SELECTOR:
+ continue;
+ default:
+ res = sas_ex_discover_dev(dev, i);
+ if (res)
+ break;
+ continue;
+ }
+ }
+
+ if (!res)
+ sas_check_level_subtractive_boundary(dev);
+
+ return res;
+}
+
+static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+ u8 *sub_sas_addr = NULL;
+
+ if (dev->dev_type != EDGE_DEV)
+ return 0;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if ((phy->attached_dev_type == FANOUT_DEV ||
+ phy->attached_dev_type == EDGE_DEV) &&
+ phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+ if (!sub_sas_addr)
+ sub_sas_addr = &phy->attached_sas_addr[0];
+ else if (SAS_ADDR(sub_sas_addr) !=
+ SAS_ADDR(phy->attached_sas_addr)) {
+
+ SAS_DPRINTK("ex %016llx phy 0x%x "
+ "diverges(%016llx) on subtractive "
+ "boundary(%016llx). Disabled\n",
+ SAS_ADDR(dev->sas_addr), i,
+ SAS_ADDR(phy->attached_sas_addr),
+ SAS_ADDR(sub_sas_addr));
+ sas_ex_disable_phy(dev, i);
+ }
+ }
+ }
+ return 0;
+}
+
+static void sas_print_parent_topology_bug(struct domain_device *child,
+ struct ex_phy *parent_phy,
+ struct ex_phy *child_phy)
+{
+ static const char ra_char[] = {
+ [DIRECT_ROUTING] = 'D',
+ [SUBTRACTIVE_ROUTING] = 'S',
+ [TABLE_ROUTING] = 'T',
+ };
+ static const char *ex_type[] = {
+ [EDGE_DEV] = "edge",
+ [FANOUT_DEV] = "fanout",
+ };
+ struct domain_device *parent = child->parent;
+
+ sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x "
+ "has %c:%c routing link!\n",
+
+ ex_type[parent->dev_type],
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+
+ ex_type[child->dev_type],
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id,
+
+ ra_char[parent_phy->routing_attr],
+ ra_char[child_phy->routing_attr]);
+}
+
+static int sas_check_eeds(struct domain_device *child,
+ struct ex_phy *parent_phy,
+ struct ex_phy *child_phy)
+{
+ int res = 0;
+ struct domain_device *parent = child->parent;
+
+ if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
+ res = -ENODEV;
+ SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx "
+ "phy S:0x%x, while there is a fanout ex %016llx\n",
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id,
+ SAS_ADDR(parent->port->disc.fanout_sas_addr));
+ } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
+ memcpy(parent->port->disc.eeds_a, parent->sas_addr,
+ SAS_ADDR_SIZE);
+ memcpy(parent->port->disc.eeds_b, child->sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
+ SAS_ADDR(parent->sas_addr)) ||
+ (SAS_ADDR(parent->port->disc.eeds_a) ==
+ SAS_ADDR(child->sas_addr)))
+ &&
+ ((SAS_ADDR(parent->port->disc.eeds_b) ==
+ SAS_ADDR(parent->sas_addr)) ||
+ (SAS_ADDR(parent->port->disc.eeds_b) ==
+ SAS_ADDR(child->sas_addr))))
+ ;
+ else {
+ res = -ENODEV;
+ SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx "
+ "phy 0x%x link forms a third EEDS!\n",
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id);
+ }
+
+ return res;
+}
+
+/* Here we spill over 80 columns. It is intentional.
+ */
+static int sas_check_parent_topology(struct domain_device *child)
+{
+ struct expander_device *child_ex = &child->ex_dev;
+ struct expander_device *parent_ex;
+ int i;
+ int res = 0;
+
+ if (!child->parent)
+ return 0;
+
+ if (child->parent->dev_type != EDGE_DEV &&
+ child->parent->dev_type != FANOUT_DEV)
+ return 0;
+
+ parent_ex = &child->parent->ex_dev;
+
+ for (i = 0; i < parent_ex->num_phys; i++) {
+ struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
+ struct ex_phy *child_phy;
+
+ if (parent_phy->phy_state == PHY_VACANT ||
+ parent_phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
+ continue;
+
+ child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
+
+ switch (child->parent->dev_type) {
+ case EDGE_DEV:
+ if (child->dev_type == FANOUT_DEV) {
+ if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
+ child_phy->routing_attr != TABLE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+ if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+ res = sas_check_eeds(child, parent_phy, child_phy);
+ } else if (child_phy->routing_attr != TABLE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ } else if (parent_phy->routing_attr == TABLE_ROUTING &&
+ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ break;
+ case FANOUT_DEV:
+ if (parent_phy->routing_attr != TABLE_ROUTING ||
+ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return res;
+}
+
+#define RRI_REQ_SIZE 16
+#define RRI_RESP_SIZE 44
+
+static int sas_configure_present(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int *index, int *present)
+{
+ int i, res = 0;
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ u8 *rri_req;
+ u8 *rri_resp;
+
+ *present = 0;
+ *index = 0;
+
+ rri_req = alloc_smp_req(RRI_REQ_SIZE);
+ if (!rri_req)
+ return -ENOMEM;
+
+ rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
+ if (!rri_resp) {
+ kfree(rri_req);
+ return -ENOMEM;
+ }
+
+ rri_req[1] = SMP_REPORT_ROUTE_INFO;
+ rri_req[9] = phy_id;
+
+ for (i = 0; i < ex->max_route_indexes ; i++) {
+ *(__be16 *)(rri_req+6) = cpu_to_be16(i);
+ res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
+ RRI_RESP_SIZE);
+ if (res)
+ goto out;
+ res = rri_resp[2];
+ if (res == SMP_RESP_NO_INDEX) {
+ SAS_DPRINTK("overflow of indexes: dev %016llx "
+ "phy 0x%x index 0x%x\n",
+ SAS_ADDR(dev->sas_addr), phy_id, i);
+ goto out;
+ } else if (res != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
+ "result 0x%x\n", __FUNCTION__,
+ SAS_ADDR(dev->sas_addr), phy_id, i, res);
+ goto out;
+ }
+ if (SAS_ADDR(sas_addr) != 0) {
+ if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
+ *index = i;
+ if ((rri_resp[12] & 0x80) == 0x80)
+ *present = 0;
+ else
+ *present = 1;
+ goto out;
+ } else if (SAS_ADDR(rri_resp+16) == 0) {
+ *index = i;
+ *present = 0;
+ goto out;
+ }
+ } else if (SAS_ADDR(rri_resp+16) == 0 &&
+ phy->last_da_index < i) {
+ phy->last_da_index = i;
+ *index = i;
+ *present = 0;
+ goto out;
+ }
+ }
+ res = -1;
+out:
+ kfree(rri_req);
+ kfree(rri_resp);
+ return res;
+}
+
+#define CRI_REQ_SIZE 44
+#define CRI_RESP_SIZE 8
+
+static int sas_configure_set(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int index, int include)
+{
+ int res;
+ u8 *cri_req;
+ u8 *cri_resp;
+
+ cri_req = alloc_smp_req(CRI_REQ_SIZE);
+ if (!cri_req)
+ return -ENOMEM;
+
+ cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
+ if (!cri_resp) {
+ kfree(cri_req);
+ return -ENOMEM;
+ }
+
+ cri_req[1] = SMP_CONF_ROUTE_INFO;
+ *(__be16 *)(cri_req+6) = cpu_to_be16(index);
+ cri_req[9] = phy_id;
+ if (SAS_ADDR(sas_addr) == 0 || !include)
+ cri_req[12] |= 0x80;
+ memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
+
+ res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
+ CRI_RESP_SIZE);
+ if (res)
+ goto out;
+ res = cri_resp[2];
+ if (res == SMP_RESP_NO_INDEX) {
+ SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x "
+ "index 0x%x\n",
+ SAS_ADDR(dev->sas_addr), phy_id, index);
+ }
+out:
+ kfree(cri_req);
+ kfree(cri_resp);
+ return res;
+}
+
+static int sas_configure_phy(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int include)
+{
+ int index;
+ int present;
+ int res;
+
+ res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
+ if (res)
+ return res;
+ if (include ^ present)
+ return sas_configure_set(dev, phy_id, sas_addr, index,include);
+
+ return res;
+}
+
+/**
+ * sas_configure_parent -- configure routing table of parent
+ * parent: parent expander
+ * child: child expander
+ * sas_addr: SAS port identifier of device directly attached to child
+ */
+static int sas_configure_parent(struct domain_device *parent,
+ struct domain_device *child,
+ u8 *sas_addr, int include)
+{
+ struct expander_device *ex_parent = &parent->ex_dev;
+ int res = 0;
+ int i;
+
+ if (parent->parent) {
+ res = sas_configure_parent(parent->parent, parent, sas_addr,
+ include);
+ if (res)
+ return res;
+ }
+
+ if (ex_parent->conf_route_table == 0) {
+ SAS_DPRINTK("ex %016llx has self-configuring routing table\n",
+ SAS_ADDR(parent->sas_addr));
+ return 0;
+ }
+
+ for (i = 0; i < ex_parent->num_phys; i++) {
+ struct ex_phy *phy = &ex_parent->ex_phy[i];
+
+ if ((phy->routing_attr == TABLE_ROUTING) &&
+ (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr))) {
+ res = sas_configure_phy(parent, i, sas_addr, include);
+ if (res)
+ return res;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * sas_configure_routing -- configure routing
+ * dev: expander device
+ * sas_addr: port identifier of device directly attached to the expander device
+ */
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
+{
+ if (dev->parent)
+ return sas_configure_parent(dev->parent, dev, sas_addr, 1);
+ return 0;
+}
+
+static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr)
+{
+ if (dev->parent)
+ return sas_configure_parent(dev->parent, dev, sas_addr, 0);
+ return 0;
+}
+
+#if 0
+#define SMP_BIN_ATTR_NAME "smp_portal"
+
+static void sas_ex_smp_hook(struct domain_device *dev)
+{
+ struct expander_device *ex_dev = &dev->ex_dev;
+ struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
+
+ memset(bin_attr, 0, sizeof(*bin_attr));
+
+ bin_attr->attr.name = SMP_BIN_ATTR_NAME;
+ bin_attr->attr.owner = THIS_MODULE;
+ bin_attr->attr.mode = 0600;
+
+ bin_attr->size = 0;
+ bin_attr->private = NULL;
+ bin_attr->read = smp_portal_read;
+ bin_attr->write= smp_portal_write;
+ bin_attr->mmap = NULL;
+
+ ex_dev->smp_portal_pid = -1;
+ init_MUTEX(&ex_dev->smp_sema);
+}
+#endif
+
+/**
+ * sas_discover_expander -- expander discovery
+ * @ex: pointer to expander domain device
+ *
+ * See comment in sas_discover_sata().
+ */
+static int sas_discover_expander(struct domain_device *dev)
+{
+ int res;
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ res = sas_ex_general(dev);
+ if (res)
+ goto out_err;
+ res = sas_ex_manuf_info(dev);
+ if (res)
+ goto out_err;
+
+ res = sas_expander_discover(dev);
+ if (res) {
+ SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out_err;
+ }
+
+ sas_check_ex_subtractive_boundary(dev);
+ res = sas_check_parent_topology(dev);
+ if (res)
+ goto out_err;
+ return 0;
+out_err:
+ sas_notify_lldd_dev_gone(dev);
+ return res;
+}
+
+static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
+{
+ int res = 0;
+ struct domain_device *dev;
+
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (dev->dev_type == EDGE_DEV ||
+ dev->dev_type == FANOUT_DEV) {
+ struct sas_expander_device *ex =
+ rphy_to_expander_device(dev->rphy);
+
+ if (level == ex->level)
+ res = sas_ex_discover_devices(dev, -1);
+ else if (level > 0)
+ res = sas_ex_discover_devices(port->port_dev, -1);
+
+ }
+ }
+
+ return res;
+}
+
+static int sas_ex_bfs_disc(struct asd_sas_port *port)
+{
+ int res;
+ int level;
+
+ do {
+ level = port->disc.max_level;
+ res = sas_ex_level_discovery(port, level);
+ mb();
+ } while (level < port->disc.max_level);
+
+ return res;
+}
+
+int sas_discover_root_expander(struct domain_device *dev)
+{
+ int res;
+ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+
+ sas_rphy_add(dev->rphy);
+
+ ex->level = dev->port->disc.max_level; /* 0 */
+ res = sas_discover_expander(dev);
+ if (!res)
+ sas_ex_bfs_disc(dev->port);
+
+ return res;
+}
+
+/* ---------- Domain revalidation ---------- */
+
+static int sas_get_phy_discover(struct domain_device *dev,
+ int phy_id, struct smp_resp *disc_resp)
+{
+ int res;
+ u8 *disc_req;
+
+ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+ if (!disc_req)
+ return -ENOMEM;
+
+ disc_req[1] = SMP_DISCOVER;
+ disc_req[9] = phy_id;
+
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ goto out;
+ else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
+ res = disc_resp->result;
+ goto out;
+ }
+out:
+ kfree(disc_req);
+ return res;
+}
+
+static int sas_get_phy_change_count(struct domain_device *dev,
+ int phy_id, int *pcc)
+{
+ int res;
+ struct smp_resp *disc_resp;
+
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+ if (!disc_resp)
+ return -ENOMEM;
+
+ res = sas_get_phy_discover(dev, phy_id, disc_resp);
+ if (!res)
+ *pcc = disc_resp->disc.change_count;
+
+ kfree(disc_resp);
+ return res;
+}
+
+static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
+ int phy_id, u8 *attached_sas_addr)
+{
+ int res;
+ struct smp_resp *disc_resp;
+ struct discover_resp *dr;
+
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+ if (!disc_resp)
+ return -ENOMEM;
+ dr = &disc_resp->disc;
+
+ res = sas_get_phy_discover(dev, phy_id, disc_resp);
+ if (!res) {
+ memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
+ if (dr->attached_dev_type == 0)
+ memset(attached_sas_addr, 0, 8);
+ }
+ kfree(disc_resp);
+ return res;
+}
+
+static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
+ int from_phy)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = 0;
+ int i;
+
+ for (i = from_phy; i < ex->num_phys; i++) {
+ int phy_change_count = 0;
+
+ res = sas_get_phy_change_count(dev, i, &phy_change_count);
+ if (res)
+ goto out;
+ else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
+ ex->ex_phy[i].phy_change_count = phy_change_count;
+ *phy_id = i;
+ return 0;
+ }
+ }
+out:
+ return res;
+}
+
+static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
+{
+ int res;
+ u8 *rg_req;
+ struct smp_resp *rg_resp;
+
+ rg_req = alloc_smp_req(RG_REQ_SIZE);
+ if (!rg_req)
+ return -ENOMEM;
+
+ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+ if (!rg_resp) {
+ kfree(rg_req);
+ return -ENOMEM;
+ }
+
+ rg_req[1] = SMP_REPORT_GENERAL;
+
+ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+ RG_RESP_SIZE);
+ if (res)
+ goto out;
+ if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+ res = rg_resp->result;
+ goto out;
+ }
+
+ *ecc = be16_to_cpu(rg_resp->rg.change_count);
+out:
+ kfree(rg_resp);
+ kfree(rg_req);
+ return res;
+}
+
+static int sas_find_bcast_dev(struct domain_device *dev,
+ struct domain_device **src_dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int ex_change_count = -1;
+ int res;
+
+ res = sas_get_ex_change_count(dev, &ex_change_count);
+ if (res)
+ goto out;
+ if (ex_change_count != -1 &&
+ ex_change_count != ex->ex_change_count) {
+ *src_dev = dev;
+ ex->ex_change_count = ex_change_count;
+ } else {
+ struct domain_device *ch;
+
+ list_for_each_entry(ch, &ex->children, siblings) {
+ if (ch->dev_type == EDGE_DEV ||
+ ch->dev_type == FANOUT_DEV) {
+ res = sas_find_bcast_dev(ch, src_dev);
+ if (src_dev)
+ return res;
+ }
+ }
+ }
+out:
+ return res;
+}
+
+static void sas_unregister_ex_tree(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct domain_device *child, *n;
+
+ list_for_each_entry_safe(child, n, &ex->children, siblings) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ }
+ sas_unregister_dev(dev);
+}
+
+static void sas_unregister_devs_sas_addr(struct domain_device *parent,
+ int phy_id)
+{
+ struct expander_device *ex_dev = &parent->ex_dev;
+ struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
+ struct domain_device *child, *n;
+
+ list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ break;
+ }
+ }
+ sas_disable_routing(parent, phy->attached_sas_addr);
+ memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ sas_port_delete_phy(phy->port, phy->phy);
+ if (phy->port->num_phys == 0)
+ sas_port_delete(phy->port);
+ phy->port = NULL;
+}
+
+static int sas_discover_bfs_by_root_level(struct domain_device *root,
+ const int level)
+{
+ struct expander_device *ex_root = &root->ex_dev;
+ struct domain_device *child;
+ int res = 0;
+
+ list_for_each_entry(child, &ex_root->children, siblings) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV) {
+ struct sas_expander_device *ex =
+ rphy_to_expander_device(child->rphy);
+
+ if (level > ex->level)
+ res = sas_discover_bfs_by_root_level(child,
+ level);
+ else if (level == ex->level)
+ res = sas_ex_discover_devices(child, -1);
+ }
+ }
+ return res;
+}
+
+static int sas_discover_bfs_by_root(struct domain_device *dev)
+{
+ int res;
+ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+ int level = ex->level+1;
+
+ res = sas_ex_discover_devices(dev, -1);
+ if (res)
+ goto out;
+ do {
+ res = sas_discover_bfs_by_root_level(dev, level);
+ mb();
+ level += 1;
+ } while (level <= dev->port->disc.max_level);
+out:
+ return res;
+}
+
+static int sas_discover_new(struct domain_device *dev, int phy_id)
+{
+ struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
+ struct domain_device *child;
+ int res;
+
+ SAS_DPRINTK("ex %016llx phy%d new device attached\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+ res = sas_ex_phy_discover(dev, phy_id);
+ if (res)
+ goto out;
+ res = sas_ex_discover_devices(dev, phy_id);
+ if (res)
+ goto out;
+ list_for_each_entry(child, &dev->ex_dev.children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(ex_phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ res = sas_discover_bfs_by_root(child);
+ break;
+ }
+ }
+out:
+ return res;
+}
+
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ u8 attached_sas_addr[8];
+ int res;
+
+ res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
+ switch (res) {
+ case SMP_RESP_NO_PHY:
+ phy->phy_state = PHY_NOT_PRESENT;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ goto out; break;
+ case SMP_RESP_PHY_VACANT:
+ phy->phy_state = PHY_VACANT;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ goto out; break;
+ case SMP_RESP_FUNC_ACC:
+ break;
+ }
+
+ if (SAS_ADDR(attached_sas_addr) == 0) {
+ phy->phy_state = PHY_EMPTY;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ } else if (SAS_ADDR(attached_sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+ sas_ex_phy_discover(dev, phy_id);
+ } else
+ res = sas_discover_new(dev, phy_id);
+out:
+ return res;
+}
+
+static int sas_rediscover(struct domain_device *dev, const int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
+ int res = 0;
+ int i;
+
+ SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+
+ if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (i == phy_id)
+ continue;
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(changed_phy->attached_sas_addr)) {
+ SAS_DPRINTK("phy%d part of wide port with "
+ "phy%d\n", phy_id, i);
+ goto out;
+ }
+ }
+ res = sas_rediscover_dev(dev, phy_id);
+ } else
+ res = sas_discover_new(dev, phy_id);
+out:
+ return res;
+}
+
+/**
+ * sas_revalidate_domain -- revalidate the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+int sas_ex_revalidate_domain(struct domain_device *port_dev)
+{
+ int res;
+ struct domain_device *dev = NULL;
+
+ res = sas_find_bcast_dev(port_dev, &dev);
+ if (res)
+ goto out;
+ if (dev) {
+ struct expander_device *ex = &dev->ex_dev;
+ int i = 0, phy_id;
+
+ do {
+ phy_id = -1;
+ res = sas_find_bcast_phy(dev, &phy_id, i);
+ if (phy_id == -1)
+ break;
+ res = sas_rediscover(dev, phy_id);
+ i = phy_id + 1;
+ } while (i < ex->num_phys);
+ }
+out:
+ return res;
+}
+
+#if 0
+/* ---------- SMP portal ---------- */
+
+static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
+ size_t size)
+{
+ struct domain_device *dev = to_dom_device(kobj);
+ struct expander_device *ex = &dev->ex_dev;
+
+ if (offs != 0)
+ return -EFBIG;
+ else if (size == 0)
+ return 0;
+
+ down_interruptible(&ex->smp_sema);
+ if (ex->smp_req)
+ kfree(ex->smp_req);
+ ex->smp_req = kzalloc(size, GFP_USER);
+ if (!ex->smp_req) {
+ up(&ex->smp_sema);
+ return -ENOMEM;
+ }
+ memcpy(ex->smp_req, buf, size);
+ ex->smp_req_size = size;
+ ex->smp_portal_pid = current->pid;
+ up(&ex->smp_sema);
+
+ return size;
+}
+
+static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
+ size_t size)
+{
+ struct domain_device *dev = to_dom_device(kobj);
+ struct expander_device *ex = &dev->ex_dev;
+ u8 *smp_resp;
+ int res = -EINVAL;
+
+ /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
+ * it should be 0.
+ */
+
+ down_interruptible(&ex->smp_sema);
+ if (!ex->smp_req || ex->smp_portal_pid != current->pid)
+ goto out;
+
+ res = 0;
+ if (size == 0)
+ goto out;
+
+ res = -ENOMEM;
+ smp_resp = alloc_smp_resp(size);
+ if (!smp_resp)
+ goto out;
+ res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
+ smp_resp, size);
+ if (!res) {
+ memcpy(buf, smp_resp, size);
+ res = size;
+ }
+
+ kfree(smp_resp);
+out:
+ kfree(ex->smp_req);
+ ex->smp_req = NULL;
+ ex->smp_req_size = 0;
+ ex->smp_portal_pid = -1;
+ up(&ex->smp_sema);
+ return res;
+}
+#endif
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
new file mode 100644
index 00000000000..c836a237fb7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_init.c
@@ -0,0 +1,267 @@
+/*
+ * Serial Attached SCSI (SAS) Transport Layer initialization
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+
+#include "sas_internal.h"
+
+#include "../scsi_sas_internal.h"
+
+kmem_cache_t *sas_task_cache;
+
+/*------------ SAS addr hash -----------*/
+void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
+{
+ const u32 poly = 0x00DB2777;
+ u32 r = 0;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ int b;
+ for (b = 7; b >= 0; b--) {
+ r <<= 1;
+ if ((1 << b) & sas_addr[i]) {
+ if (!(r & 0x01000000))
+ r ^= poly;
+ } else if (r & 0x01000000)
+ r ^= poly;
+ }
+ }
+
+ hashed[0] = (r >> 16) & 0xFF;
+ hashed[1] = (r >> 8) & 0xFF ;
+ hashed[2] = r & 0xFF;
+}
+
+
+/* ---------- HA events ---------- */
+
+void sas_hae_reset(void *data)
+{
+ struct sas_ha_struct *ha = data;
+
+ sas_begin_event(HAE_RESET, &ha->event_lock,
+ &ha->pending);
+}
+
+int sas_register_ha(struct sas_ha_struct *sas_ha)
+{
+ int error = 0;
+
+ spin_lock_init(&sas_ha->phy_port_lock);
+ sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
+
+ if (sas_ha->lldd_queue_size == 0)
+ sas_ha->lldd_queue_size = 1;
+ else if (sas_ha->lldd_queue_size == -1)
+ sas_ha->lldd_queue_size = 128; /* Sanity */
+
+ error = sas_register_phys(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
+ return error;
+ }
+
+ error = sas_register_ports(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't register sas ports:%d\n", error);
+ goto Undo_phys;
+ }
+
+ error = sas_init_events(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
+ goto Undo_ports;
+ }
+
+ if (sas_ha->lldd_max_execute_num > 1) {
+ error = sas_init_queue(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't start queue thread:%d, "
+ "running in direct mode\n", error);
+ sas_ha->lldd_max_execute_num = 1;
+ }
+ }
+
+ return 0;
+
+Undo_ports:
+ sas_unregister_ports(sas_ha);
+Undo_phys:
+
+ return error;
+}
+
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+ if (sas_ha->lldd_max_execute_num > 1) {
+ sas_shutdown_queue(sas_ha);
+ }
+
+ sas_unregister_ports(sas_ha);
+
+ return 0;
+}
+
+static int sas_get_linkerrors(struct sas_phy *phy)
+{
+ if (scsi_is_sas_phy_local(phy))
+ /* FIXME: we have no local phy stats
+ * gathering at this time */
+ return -EINVAL;
+
+ return sas_smp_get_phy_events(phy);
+}
+
+static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ int ret;
+ enum phy_func reset_type;
+
+ if (hard_reset)
+ reset_type = PHY_FUNC_HARD_RESET;
+ else
+ reset_type = PHY_FUNC_LINK_RESET;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
+ } else {
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+ ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
+ }
+ return ret;
+}
+
+static int sas_set_phy_speed(struct sas_phy *phy,
+ struct sas_phy_linkrates *rates)
+{
+ int ret;
+
+ if ((rates->minimum_linkrate &&
+ rates->minimum_linkrate > phy->maximum_linkrate) ||
+ (rates->maximum_linkrate &&
+ rates->maximum_linkrate < phy->minimum_linkrate))
+ return -EINVAL;
+
+ if (rates->minimum_linkrate &&
+ rates->minimum_linkrate < phy->minimum_linkrate_hw)
+ rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+ if (rates->maximum_linkrate &&
+ rates->maximum_linkrate > phy->maximum_linkrate_hw)
+ rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,
+ rates);
+ } else {
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+ ret = sas_smp_phy_control(ddev, phy->number,
+ PHY_FUNC_LINK_RESET, rates);
+
+ }
+
+ return ret;
+}
+
+static struct sas_function_template sft = {
+ .phy_reset = sas_phy_reset,
+ .set_phy_speed = sas_set_phy_speed,
+ .get_linkerrors = sas_get_linkerrors,
+};
+
+struct scsi_transport_template *
+sas_domain_attach_transport(struct sas_domain_function_template *dft)
+{
+ struct scsi_transport_template *stt = sas_attach_transport(&sft);
+ struct sas_internal *i;
+
+ if (!stt)
+ return stt;
+
+ i = to_sas_internal(stt);
+ i->dft = dft;
+ stt->create_work_queue = 1;
+ stt->eh_timed_out = sas_scsi_timed_out;
+ stt->eh_strategy_handler = sas_scsi_recover_host;
+
+ return stt;
+}
+EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
+
+
+void sas_domain_release_transport(struct scsi_transport_template *stt)
+{
+ sas_release_transport(stt);
+}
+EXPORT_SYMBOL_GPL(sas_domain_release_transport);
+
+/* ---------- SAS Class register/unregister ---------- */
+
+static int __init sas_class_init(void)
+{
+ sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!sas_task_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit sas_class_exit(void)
+{
+ kmem_cache_destroy(sas_task_cache);
+}
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION("SAS Transport Layer");
+MODULE_LICENSE("GPL v2");
+
+module_init(sas_class_init);
+module_exit(sas_class_exit);
+
+EXPORT_SYMBOL_GPL(sas_register_ha);
+EXPORT_SYMBOL_GPL(sas_unregister_ha);
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
new file mode 100644
index 00000000000..bffcee47492
--- /dev/null
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -0,0 +1,146 @@
+/*
+ * Serial Attached SCSI (SAS) class internal header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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
+ *
+ */
+
+#ifndef _SAS_INTERNAL_H_
+#define _SAS_INTERNAL_H_
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+#include <scsi/libsas.h>
+
+#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+
+#ifdef SAS_DEBUG
+#define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+#else
+#define SAS_DPRINTK(fmt, ...)
+#endif
+
+void sas_scsi_recover_host(struct Scsi_Host *shost);
+
+int sas_show_class(enum sas_class class, char *buf);
+int sas_show_proto(enum sas_proto proto, char *buf);
+int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
+int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
+
+int sas_register_phys(struct sas_ha_struct *sas_ha);
+void sas_unregister_phys(struct sas_ha_struct *sas_ha);
+
+int sas_register_ports(struct sas_ha_struct *sas_ha);
+void sas_unregister_ports(struct sas_ha_struct *sas_ha);
+
+enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+
+int sas_init_queue(struct sas_ha_struct *sas_ha);
+int sas_init_events(struct sas_ha_struct *sas_ha);
+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 *);
+
+int sas_notify_lldd_dev_found(struct domain_device *);
+void sas_notify_lldd_dev_gone(struct domain_device *);
+
+int sas_smp_phy_control(struct domain_device *dev, int phy_id,
+ enum phy_func phy_func, struct sas_phy_linkrates *);
+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 *);
+
+static inline void sas_queue_event(int event, spinlock_t *lock,
+ unsigned long *pending,
+ struct work_struct *work,
+ struct Scsi_Host *shost)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ if (test_bit(event, pending)) {
+ spin_unlock_irqrestore(lock, flags);
+ return;
+ }
+ __set_bit(event, pending);
+ spin_unlock_irqrestore(lock, flags);
+ scsi_queue_work(shost, work);
+}
+
+static inline void sas_begin_event(int event, spinlock_t *lock,
+ unsigned long *pending)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ __clear_bit(event, pending);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static inline void sas_fill_in_rphy(struct domain_device *dev,
+ struct sas_rphy *rphy)
+{
+ rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);
+ rphy->identify.initiator_port_protocols = dev->iproto;
+ rphy->identify.target_port_protocols = dev->tproto;
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ /* FIXME: need sata device type */
+ case SAS_END_DEV:
+ rphy->identify.device_type = SAS_END_DEVICE;
+ break;
+ case EDGE_DEV:
+ rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;
+ break;
+ case FANOUT_DEV:
+ rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;
+ break;
+ default:
+ rphy->identify.device_type = SAS_PHY_UNUSED;
+ break;
+ }
+}
+
+static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
+
+ if (!ex->parent_port) {
+ ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id);
+ /* FIXME: error handling */
+ BUG_ON(!ex->parent_port);
+ BUG_ON(sas_port_add(ex->parent_port));
+ sas_port_mark_backlink(ex->parent_port);
+ }
+ sas_port_add_phy(ex->parent_port, ex_phy->phy);
+}
+
+#endif /* _SAS_INTERNAL_H_ */
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
new file mode 100644
index 00000000000..9340cdbae4a
--- /dev/null
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -0,0 +1,158 @@
+/*
+ * Serial Attached SCSI (SAS) Phy class
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_internal.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/* ---------- Phy events ---------- */
+
+static void sas_phye_loss_of_signal(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+ phy->error = 0;
+ sas_deform_port(phy);
+}
+
+static void sas_phye_oob_done(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ 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)
+{
+ struct asd_sas_phy *phy = data;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+
+ sas_deform_port(phy);
+
+ if (!port && phy->enabled && i->dft->lldd_control_phy) {
+ phy->error++;
+ switch (phy->error) {
+ case 1:
+ case 2:
+ i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
+ NULL);
+ break;
+ case 3:
+ default:
+ phy->error = 0;
+ phy->enabled = 0;
+ i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
+ break;
+ }
+ }
+}
+
+static void sas_phye_spinup_hold(void *data)
+{
+ struct asd_sas_phy *phy = data;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+
+ phy->error = 0;
+ i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
+}
+
+/* ---------- Phy class registration ---------- */
+
+int sas_register_phys(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = {
+ [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 *) = {
+ [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
+ [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
+ [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
+ [PORTE_TIMER_EVENT] = sas_porte_timer_event,
+ [PORTE_HARD_RESET] = sas_porte_hard_reset,
+ };
+
+ /* Now register the phys. */
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ int k;
+ struct asd_sas_phy *phy = sas_ha->sas_phy[i];
+
+ 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 < 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);
+ spin_lock_init(&phy->sas_prim_lock);
+ phy->frame_rcvd_size = 0;
+
+ phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev,
+ i);
+ if (!phy->phy)
+ return -ENOMEM;
+
+ phy->phy->identify.initiator_port_protocols =
+ phy->iproto;
+ phy->phy->identify.target_port_protocols = phy->tproto;
+ phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
+ phy->phy->identify.phy_identifier = i;
+ phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ sas_phy_add(phy->phy);
+ }
+
+ return 0;
+}
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
new file mode 100644
index 00000000000..253cdcf306a
--- /dev/null
+++ b/drivers/scsi/libsas/sas_port.c
@@ -0,0 +1,279 @@
+/*
+ * Serial Attached SCSI (SAS) Port class
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/**
+ * sas_form_port -- add this phy to a port
+ * @phy: the phy of interest
+ *
+ * This function adds this phy to an existing port, thus creating a wide
+ * port, or it creates a port and adds the phy to the port.
+ */
+static void sas_form_port(struct asd_sas_phy *phy)
+{
+ int i;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *si =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ if (port) {
+ if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE) == 0)
+ sas_deform_port(phy);
+ else {
+ SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
+ __FUNCTION__, phy->id, phy->port->id,
+ phy->port->num_phys);
+ return;
+ }
+ }
+
+ /* find a port */
+ spin_lock(&sas_ha->phy_port_lock);
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ port = sas_ha->sas_port[i];
+ spin_lock(&port->phy_list_lock);
+ if (*(u64 *) port->sas_addr &&
+ memcmp(port->attached_sas_addr,
+ phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
+ port->num_phys > 0) {
+ /* wide port */
+ SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
+ port->id);
+ break;
+ } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
+ memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
+ break;
+ }
+ spin_unlock(&port->phy_list_lock);
+ }
+
+ if (i >= sas_ha->num_phys) {
+ printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
+ __FUNCTION__);
+ spin_unlock(&sas_ha->phy_port_lock);
+ return;
+ }
+
+ /* add the phy to the port */
+ list_add_tail(&phy->port_phy_el, &port->phy_list);
+ phy->port = port;
+ port->num_phys++;
+ port->phy_mask |= (1U << phy->id);
+
+ if (!port->phy)
+ port->phy = phy->phy;
+
+ SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,
+ port->id, port->phy_mask);
+
+ if (*(u64 *)port->attached_sas_addr == 0) {
+ port->class = phy->class;
+ memcpy(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE);
+ port->iproto = phy->iproto;
+ port->tproto = phy->tproto;
+ port->oob_mode = phy->oob_mode;
+ port->linkrate = phy->linkrate;
+ } else
+ port->linkrate = max(port->linkrate, phy->linkrate);
+ spin_unlock(&port->phy_list_lock);
+ spin_unlock(&sas_ha->phy_port_lock);
+
+ if (!port->port) {
+ port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
+ BUG_ON(!port->port);
+ sas_port_add(port->port);
+ }
+ sas_port_add_phy(port->port, phy->phy);
+
+ if (port->port_dev)
+ port->port_dev->pathways = port->num_phys;
+
+ /* Tell the LLDD about this port formation. */
+ if (si->dft->lldd_port_formed)
+ si->dft->lldd_port_formed(phy);
+
+ sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
+}
+
+/**
+ * sas_deform_port -- remove this phy from the port it belongs to
+ * @phy: the phy of interest
+ *
+ * This is called when the physical link to the other phy has been
+ * lost (on this phy), in Event thread context. We cannot delay here.
+ */
+void sas_deform_port(struct asd_sas_phy *phy)
+{
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *si =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ if (!port)
+ return; /* done by a phy event */
+
+ if (port->port_dev)
+ port->port_dev->pathways--;
+
+ if (port->num_phys == 1) {
+ sas_unregister_domain_devices(port);
+ sas_port_delete(port->port);
+ port->port = NULL;
+ } else
+ sas_port_delete_phy(port->port, phy->phy);
+
+
+ if (si->dft->lldd_port_deformed)
+ si->dft->lldd_port_deformed(phy);
+
+ spin_lock(&sas_ha->phy_port_lock);
+ spin_lock(&port->phy_list_lock);
+
+ list_del_init(&phy->port_phy_el);
+ phy->port = NULL;
+ port->num_phys--;
+ port->phy_mask &= ~(1U << phy->id);
+
+ if (port->num_phys == 0) {
+ INIT_LIST_HEAD(&port->phy_list);
+ memset(port->sas_addr, 0, SAS_ADDR_SIZE);
+ memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ port->class = 0;
+ port->iproto = 0;
+ port->tproto = 0;
+ port->oob_mode = 0;
+ port->phy_mask = 0;
+ }
+ spin_unlock(&port->phy_list_lock);
+ spin_unlock(&sas_ha->phy_port_lock);
+
+ return;
+}
+
+/* ---------- SAS port events ---------- */
+
+void sas_porte_bytes_dmaed(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_form_port(phy);
+}
+
+void sas_porte_broadcast_rcvd(void *data)
+{
+ 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);
+
+ spin_lock_irqsave(&phy->sas_prim_lock, flags);
+ prim = phy->sas_prim;
+ spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
+
+ SAS_DPRINTK("broadcast received: %d\n", prim);
+ sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
+}
+
+void sas_porte_link_reset_err(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+void sas_porte_timer_event(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+void sas_porte_hard_reset(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+/* ---------- SAS port registration ---------- */
+
+static void sas_init_port(struct asd_sas_port *port,
+ struct sas_ha_struct *sas_ha, int i)
+{
+ port->id = i;
+ INIT_LIST_HEAD(&port->dev_list);
+ spin_lock_init(&port->phy_list_lock);
+ INIT_LIST_HEAD(&port->phy_list);
+ port->num_phys = 0;
+ port->phy_mask = 0;
+ port->ha = sas_ha;
+
+ spin_lock_init(&port->dev_list_lock);
+}
+
+int sas_register_ports(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ /* initialize the ports and discovery */
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ struct asd_sas_port *port = sas_ha->sas_port[i];
+
+ sas_init_port(port, sas_ha, i);
+ sas_init_disc(&port->disc, port);
+ }
+ return 0;
+}
+
+void sas_unregister_ports(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ for (i = 0; i < sas_ha->num_phys; i++)
+ if (sas_ha->sas_phy[i]->port)
+ sas_deform_port(sas_ha->sas_phy[i]);
+
+}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
new file mode 100644
index 00000000000..7f9e89bcac7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -0,0 +1,786 @@
+/*
+ * Serial Attached SCSI (SAS) class SCSI Host glue.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_internal.h"
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
+
+/* ---------- SCSI Host glue ---------- */
+
+#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
+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;
+ unsigned ts_flags = task->task_state_flags;
+ int hs = 0, stat = 0;
+
+ if (unlikely(!sc)) {
+ SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+ list_del_init(&task->list);
+ sas_free_task(task);
+ return;
+ }
+
+ if (ts->resp == SAS_TASK_UNDELIVERED) {
+ /* transport error */
+ hs = DID_NO_CONNECT;
+ } else { /* ts->resp == SAS_TASK_COMPLETE */
+ /* task delivered, what happened afterwards? */
+ switch (ts->stat) {
+ case SAS_DEV_NO_RESPONSE:
+ case SAS_INTERRUPTED:
+ case SAS_PHY_DOWN:
+ case SAS_NAK_R_ERR:
+ case SAS_OPEN_TO:
+ hs = DID_NO_CONNECT;
+ break;
+ case SAS_DATA_UNDERRUN:
+ sc->resid = ts->residual;
+ if (sc->request_bufflen - sc->resid < sc->underflow)
+ hs = DID_ERROR;
+ break;
+ case SAS_DATA_OVERRUN:
+ hs = DID_ERROR;
+ break;
+ case SAS_QUEUE_FULL:
+ hs = DID_SOFT_ERROR; /* retry */
+ break;
+ case SAS_DEVICE_UNKNOWN:
+ hs = DID_BAD_TARGET;
+ break;
+ case SAS_SG_ERR:
+ hs = DID_PARITY;
+ break;
+ case SAS_OPEN_REJECT:
+ if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY)
+ hs = DID_SOFT_ERROR; /* retry */
+ else
+ hs = DID_ERROR;
+ break;
+ case SAS_PROTO_RESPONSE:
+ SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP "
+ "task; please report this\n",
+ task->dev->port->ha->sas_ha_name);
+ break;
+ case SAS_ABORTED_TASK:
+ hs = DID_ABORT;
+ break;
+ case SAM_CHECK_COND:
+ memcpy(sc->sense_buffer, ts->buf,
+ max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+ stat = SAM_CHECK_COND;
+ break;
+ default:
+ stat = ts->stat;
+ break;
+ }
+ }
+ ASSIGN_SAS_TASK(sc, NULL);
+ sc->result = (hs << 16) | stat;
+ list_del_init(&task->list);
+ 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);
+ else
+ sc->scsi_done(sc);
+}
+
+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))
+ ta = TASK_ATTR_HOQ;
+ }
+ return ta;
+}
+
+static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
+ struct domain_device *dev,
+ gfp_t gfp_flags)
+{
+ struct sas_task *task = sas_alloc_task(gfp_flags);
+ struct scsi_lun lun;
+
+ if (!task)
+ return NULL;
+
+ *(u32 *)cmd->sense_buffer = 0;
+ task->uldd_task = cmd;
+ ASSIGN_SAS_TASK(cmd, task);
+
+ task->dev = dev;
+ task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */
+
+ task->ssp_task.retry_count = 1;
+ int_to_scsilun(cmd->device->lun, &lun);
+ memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8);
+ task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
+ memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
+
+ task->scatter = cmd->request_buffer;
+ task->num_scatter = cmd->use_sg;
+ task->total_xfer_len = cmd->request_bufflen;
+ task->data_dir = cmd->sc_data_direction;
+
+ task->task_done = sas_scsi_task_done;
+
+ return task;
+}
+
+static int sas_queue_up(struct sas_task *task)
+{
+ struct sas_ha_struct *sas_ha = task->dev->port->ha;
+ struct scsi_core *core = &sas_ha->core;
+ unsigned long flags;
+ LIST_HEAD(list);
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ return -SAS_QUEUE_FULL;
+ }
+ list_add_tail(&task->list, &core->task_queue);
+ core->task_queue_size += 1;
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ up(&core->queue_thread_sema);
+
+ return 0;
+}
+
+/**
+ * sas_queuecommand -- Enqueue a command for processing
+ * @parameters: See SCSI Core documentation
+ *
+ * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
+ * call us without holding an IRQ spinlock...
+ */
+int sas_queuecommand(struct scsi_cmnd *cmd,
+ void (*scsi_done)(struct scsi_cmnd *))
+{
+ int res = 0;
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct Scsi_Host *host = cmd->device->host;
+ struct sas_internal *i = to_sas_internal(host->transportt);
+
+ spin_unlock_irq(host->host_lock);
+
+ {
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct sas_task *task;
+
+ res = -ENOMEM;
+ task = sas_create_task(cmd, dev, GFP_ATOMIC);
+ if (!task)
+ goto out;
+
+ cmd->scsi_done = scsi_done;
+ /* Queue up, Direct Mode or Task Collector Mode. */
+ if (sas_ha->lldd_max_execute_num < 2)
+ res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+ else
+ res = sas_queue_up(task);
+
+ /* Examine */
+ if (res) {
+ SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+ ASSIGN_SAS_TASK(cmd, NULL);
+ sas_free_task(task);
+ if (res == -SAS_QUEUE_FULL) {
+ cmd->result = DID_SOFT_ERROR << 16; /* retry */
+ res = 0;
+ scsi_done(cmd);
+ }
+ goto out;
+ }
+ }
+out:
+ spin_lock_irq(host->host_lock);
+ return res;
+}
+
+static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ if (cmd == my_cmd)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
+ struct domain_device *dev)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ struct domain_device *x = cmd_to_domain_dev(cmd);
+
+ if (x == dev)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+static void sas_scsi_clear_queue_port(struct list_head *error_q,
+ struct asd_sas_port *port)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct asd_sas_port *x = dev->port;
+
+ if (x == port)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+enum task_disposition {
+ TASK_IS_DONE,
+ TASK_IS_ABORTED,
+ TASK_IS_AT_LU,
+ TASK_IS_NOT_AT_LU,
+};
+
+static enum task_disposition sas_scsi_find_task(struct sas_task *task)
+{
+ struct sas_ha_struct *ha = task->dev->port->ha;
+ unsigned long flags;
+ int i, res;
+ struct sas_internal *si =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (ha->lldd_max_execute_num > 1) {
+ struct scsi_core *core = &ha->core;
+ struct sas_task *t, *n;
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ list_for_each_entry_safe(t, n, &core->task_queue, list) {
+ if (task == t) {
+ list_del_init(&t->list);
+ spin_unlock_irqrestore(&core->task_queue_lock,
+ flags);
+ SAS_DPRINTK("%s: task 0x%p aborted from "
+ "task_queue\n",
+ __FUNCTION__, task);
+ return TASK_IS_ABORTED;
+ }
+ }
+ spin_unlock_irqrestore(&core->task_queue_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);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ task);
+ return TASK_IS_DONE;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("%s: task 0x%p is aborted\n",
+ __FUNCTION__, task);
+ return TASK_IS_ABORTED;
+ } else if (si->dft->lldd_query_task) {
+ SAS_DPRINTK("%s: querying task 0x%p\n",
+ __FUNCTION__, task);
+ res = si->dft->lldd_query_task(task);
+ if (res == TMF_RESP_FUNC_SUCC) {
+ SAS_DPRINTK("%s: task 0x%p at LU\n",
+ __FUNCTION__, task);
+ return TASK_IS_AT_LU;
+ } else if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("%s: task 0x%p not at LU\n",
+ __FUNCTION__, task);
+ return TASK_IS_NOT_AT_LU;
+ }
+ }
+ }
+ return res;
+}
+
+static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct scsi_lun lun;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+
+ int_to_scsilun(cmd->device->lun, &lun);
+
+ SAS_DPRINTK("eh: device %llx LUN %x has the task\n",
+ SAS_ADDR(dev->sas_addr),
+ cmd->device->lun);
+
+ if (i->dft->lldd_abort_task_set)
+ res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun);
+
+ if (res == TMF_RESP_FUNC_FAILED) {
+ if (i->dft->lldd_clear_task_set)
+ res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun);
+ }
+
+ if (res == TMF_RESP_FUNC_FAILED) {
+ if (i->dft->lldd_lu_reset)
+ res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
+ }
+
+ return res;
+}
+
+static int sas_recover_I_T(struct domain_device *dev)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+
+ SAS_DPRINTK("I_T nexus reset for dev %016llx\n",
+ SAS_ADDR(dev->sas_addr));
+
+ if (i->dft->lldd_I_T_nexus_reset)
+ res = i->dft->lldd_I_T_nexus_reset(dev);
+
+ return res;
+}
+
+void sas_scsi_recover_host(struct Scsi_Host *shost)
+{
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ unsigned long flags;
+ LIST_HEAD(error_q);
+ struct scsi_cmnd *cmd, *n;
+ enum task_disposition res = TASK_IS_DONE;
+ int tmf_resp;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ list_splice_init(&shost->eh_cmd_q, &error_q);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+
+ /* All tasks on this list were marked SAS_TASK_STATE_ABORTED
+ * by sas_scsi_timed_out() callback.
+ */
+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);
+
+ 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:
+ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ task);
+ task->task_done(task);
+ continue;
+ case TASK_IS_ABORTED:
+ SAS_DPRINTK("%s: task 0x%p is aborted\n",
+ __FUNCTION__, task);
+ task->task_done(task);
+ continue;
+ case TASK_IS_AT_LU:
+ SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
+ tmf_resp = sas_recover_lu(task->dev, cmd);
+ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("dev %016llx LU %x is "
+ "recovered\n",
+ SAS_ADDR(task->dev),
+ cmd->device->lun);
+ task->task_done(task);
+ sas_scsi_clear_queue_lu(&error_q, cmd);
+ goto Again;
+ }
+ /* fallthrough */
+ case TASK_IS_NOT_AT_LU:
+ SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
+ task);
+ tmf_resp = sas_recover_I_T(task->dev);
+ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("I_T %016llx recovered\n",
+ SAS_ADDR(task->dev->sas_addr));
+ task->task_done(task);
+ sas_scsi_clear_queue_I_T(&error_q, task->dev);
+ goto Again;
+ }
+ /* Hammer time :-) */
+ if (i->dft->lldd_clear_nexus_port) {
+ struct asd_sas_port *port = task->dev->port;
+ SAS_DPRINTK("clearing nexus for port:%d\n",
+ port->id);
+ res = i->dft->lldd_clear_nexus_port(port);
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("clear nexus port:%d "
+ "succeeded\n", port->id);
+ task->task_done(task);
+ sas_scsi_clear_queue_port(&error_q,
+ port);
+ goto Again;
+ }
+ }
+ if (i->dft->lldd_clear_nexus_ha) {
+ SAS_DPRINTK("clear nexus ha\n");
+ res = i->dft->lldd_clear_nexus_ha(ha);
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("clear nexus ha "
+ "succeeded\n");
+ task->task_done(task);
+ goto out;
+ }
+ }
+ /* If we are here -- this means that no amount
+ * of effort could recover from errors. Quite
+ * possibly the HA just disappeared.
+ */
+ SAS_DPRINTK("error from device %llx, LUN %x "
+ "couldn't be recovered in any way\n",
+ SAS_ADDR(task->dev->sas_addr),
+ cmd->device->lun);
+
+ task->task_done(task);
+ goto clear_q;
+ }
+ }
+out:
+ SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+ return;
+clear_q:
+ SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+ 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);
+ task->task_done(task);
+ }
+}
+
+enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct sas_task *task = TO_SAS_TASK(cmd);
+ unsigned long flags;
+
+ if (!task) {
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+ cmd, task);
+ return EH_HANDLED;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ 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",
+ cmd, task);
+ return EH_HANDLED;
+ }
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+ cmd, task);
+
+ return EH_NOT_HANDLED;
+}
+
+struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
+{
+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ struct domain_device *found_dev = NULL;
+ int i;
+
+ spin_lock(&ha->phy_port_lock);
+ for (i = 0; i < ha->num_phys; i++) {
+ struct asd_sas_port *port = ha->sas_port[i];
+ struct domain_device *dev;
+
+ spin_lock(&port->dev_list_lock);
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (rphy == dev->rphy) {
+ found_dev = dev;
+ spin_unlock(&port->dev_list_lock);
+ goto found;
+ }
+ }
+ spin_unlock(&port->dev_list_lock);
+ }
+ found:
+ spin_unlock(&ha->phy_port_lock);
+
+ return found_dev;
+}
+
+static inline struct domain_device *sas_find_target(struct scsi_target *starget)
+{
+ struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
+
+ return sas_find_dev_by_rphy(rphy);
+}
+
+int sas_target_alloc(struct scsi_target *starget)
+{
+ struct domain_device *found_dev = sas_find_target(starget);
+
+ if (!found_dev)
+ return -ENODEV;
+
+ starget->hostdata = found_dev;
+ return 0;
+}
+
+#define SAS_DEF_QD 32
+#define SAS_MAX_QD 64
+
+int sas_slave_configure(struct scsi_device *scsi_dev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+ struct sas_ha_struct *sas_ha;
+
+ BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
+
+ sas_ha = dev->port->ha;
+
+ sas_read_port_mode_page(scsi_dev);
+
+ if (scsi_dev->tagged_supported) {
+ scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
+ scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
+ } else {
+ SAS_DPRINTK("device %llx, LUN %x doesn't support "
+ "TCQ\n", SAS_ADDR(dev->sas_addr),
+ scsi_dev->lun);
+ scsi_dev->tagged_supported = 0;
+ scsi_set_tag_type(scsi_dev, 0);
+ scsi_deactivate_tcq(scsi_dev, 1);
+ }
+
+ return 0;
+}
+
+void sas_slave_destroy(struct scsi_device *scsi_dev)
+{
+}
+
+int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
+{
+ int res = min(new_depth, SAS_MAX_QD);
+
+ if (scsi_dev->tagged_supported)
+ scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
+ res);
+ else {
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+ sas_printk("device %llx LUN %x queue depth changed to 1\n",
+ SAS_ADDR(dev->sas_addr),
+ scsi_dev->lun);
+ scsi_adjust_queue_depth(scsi_dev, 0, 1);
+ res = 1;
+ }
+
+ return res;
+}
+
+int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
+{
+ if (!scsi_dev->tagged_supported)
+ return 0;
+
+ scsi_deactivate_tcq(scsi_dev, 1);
+
+ scsi_set_tag_type(scsi_dev, qt);
+ scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
+
+ return qt;
+}
+
+int sas_bios_param(struct scsi_device *scsi_dev,
+ struct block_device *bdev,
+ sector_t capacity, int *hsc)
+{
+ hsc[0] = 255;
+ hsc[1] = 63;
+ sector_div(capacity, 255*63);
+ hsc[2] = capacity;
+
+ return 0;
+}
+
+/* ---------- Task Collector Thread implementation ---------- */
+
+static void sas_queue(struct sas_ha_struct *sas_ha)
+{
+ struct scsi_core *core = &sas_ha->core;
+ unsigned long flags;
+ LIST_HEAD(q);
+ int can_queue;
+ int res;
+ struct sas_internal *i = to_sas_internal(core->shost->transportt);
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ while (!core->queue_thread_kill &&
+ !list_empty(&core->task_queue)) {
+
+ can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
+ if (can_queue >= 0) {
+ can_queue = core->task_queue_size;
+ list_splice_init(&core->task_queue, &q);
+ } else {
+ struct list_head *a, *n;
+
+ can_queue = sas_ha->lldd_queue_size;
+ list_for_each_safe(a, n, &core->task_queue) {
+ list_move_tail(a, &q);
+ if (--can_queue == 0)
+ break;
+ }
+ can_queue = sas_ha->lldd_queue_size;
+ }
+ core->task_queue_size -= can_queue;
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ {
+ struct sas_task *task = list_entry(q.next,
+ struct sas_task,
+ list);
+ list_del_init(&q);
+ res = i->dft->lldd_execute_task(task, can_queue,
+ GFP_KERNEL);
+ if (unlikely(res))
+ __list_add(&q, task->list.prev, &task->list);
+ }
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ if (res) {
+ list_splice_init(&q, &core->task_queue); /*at head*/
+ core->task_queue_size += can_queue;
+ }
+ }
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+static DECLARE_COMPLETION(queue_th_comp);
+
+/**
+ * sas_queue_thread -- The Task Collector thread
+ * @_sas_ha: pointer to struct sas_ha
+ */
+static int sas_queue_thread(void *_sas_ha)
+{
+ struct sas_ha_struct *sas_ha = _sas_ha;
+ struct scsi_core *core = &sas_ha->core;
+
+ daemonize("sas_queue_%d", core->shost->host_no);
+ current->flags |= PF_NOFREEZE;
+
+ complete(&queue_th_comp);
+
+ while (1) {
+ down_interruptible(&core->queue_thread_sema);
+ sas_queue(sas_ha);
+ if (core->queue_thread_kill)
+ break;
+ }
+
+ complete(&queue_th_comp);
+
+ return 0;
+}
+
+int sas_init_queue(struct sas_ha_struct *sas_ha)
+{
+ int res;
+ struct scsi_core *core = &sas_ha->core;
+
+ spin_lock_init(&core->task_queue_lock);
+ core->task_queue_size = 0;
+ INIT_LIST_HEAD(&core->task_queue);
+ init_MUTEX_LOCKED(&core->queue_thread_sema);
+
+ res = kernel_thread(sas_queue_thread, sas_ha, 0);
+ if (res >= 0)
+ wait_for_completion(&queue_th_comp);
+
+ return res < 0 ? res : 0;
+}
+
+void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
+{
+ unsigned long flags;
+ struct scsi_core *core = &sas_ha->core;
+ struct sas_task *task, *n;
+
+ init_completion(&queue_th_comp);
+ core->queue_thread_kill = 1;
+ up(&core->queue_thread_sema);
+ wait_for_completion(&queue_th_comp);
+
+ if (!list_empty(&core->task_queue))
+ SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
+ SAS_ADDR(sas_ha->sas_addr));
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ list_for_each_entry_safe(task, n, &core->task_queue, list) {
+ struct scsi_cmnd *cmd = task->uldd_task;
+
+ list_del_init(&task->list);
+
+ ASSIGN_SAS_TASK(cmd, NULL);
+ sas_free_task(task);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ }
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(sas_queuecommand);
+EXPORT_SYMBOL_GPL(sas_target_alloc);
+EXPORT_SYMBOL_GPL(sas_slave_configure);
+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);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 087c44539a1..3f7f5f8abd7 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -21,10 +21,12 @@
struct lpfc_sli2_slim;
-#define LPFC_MAX_TARGET 256 /* max targets supported */
-#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els req */
-#define LPFC_MAX_NS_RETRY 3 /* max NameServer retries */
+#define LPFC_MAX_TARGET 256 /* max number of targets supported */
+#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
+ requests */
+#define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact
+ the NameServer before giving up. */
#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */
#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */
#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */
@@ -41,7 +43,6 @@ struct lpfc_sli2_slim;
(( (u64)(high)<<16 ) << 16)|( (u64)(low))))
/* Provide maximum configuration definitions. */
#define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */
-#define MAX_FCP_TARGET 256 /* max num of FCP targets supported */
#define FC_MAX_ADPTMSG 64
#define MAX_HBAEVT 32
@@ -174,7 +175,6 @@ struct lpfc_hba {
dma_addr_t slim2p_mapping;
uint16_t pci_cfg_value;
- struct semaphore hba_can_block;
int32_t hba_state;
#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
@@ -285,6 +285,7 @@ struct lpfc_hba {
uint32_t cfg_log_verbose;
uint32_t cfg_lun_queue_depth;
uint32_t cfg_nodev_tmo;
+ uint32_t cfg_devloss_tmo;
uint32_t cfg_hba_queue_depth;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
@@ -302,6 +303,9 @@ struct lpfc_hba {
uint32_t cfg_poll_tmo;
uint32_t cfg_sg_seg_cnt;
uint32_t cfg_sg_dma_buf_size;
+ uint64_t cfg_soft_wwpn;
+
+ uint32_t dev_loss_tmo_changed;
lpfc_vpd_t vpd; /* vital product data */
@@ -351,6 +355,8 @@ 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;
+
struct timer_list fcp_poll_timer;
struct timer_list els_tmofunc;
@@ -391,3 +397,5 @@ struct rnidrsp {
struct list_head list;
uint32_t data;
};
+
+#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index b62a72dfab2..9496e87c135 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -39,6 +39,9 @@
#include "lpfc_compat.h"
#include "lpfc_crtn.h"
+#define LPFC_DEF_DEVLOSS_TMO 30
+#define LPFC_MIN_DEVLOSS_TMO 1
+#define LPFC_MAX_DEVLOSS_TMO 255
static void
lpfc_jedec_to_ascii(int incr, char hdw[])
@@ -219,8 +222,18 @@ lpfc_issue_lip(struct Scsi_Host *host)
return -ENOMEM;
memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
- lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);
- mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+ pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
+ pmboxq->mb.mbxOwner = OWN_HOST;
+
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
+
+ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+ lpfc_init_link(phba, pmboxq, phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
+ phba->fc_ratov * 2);
+ }
if (mbxstatus == MBX_TIMEOUT)
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -233,51 +246,53 @@ lpfc_issue_lip(struct Scsi_Host *host)
return 0;
}
-static ssize_t
-lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+ struct completion online_compl;
+ int status = 0;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ return 0;
}
static ssize_t
-lpfc_board_online_show(struct class_device *cdev, char *buf)
+lpfc_issue_reset(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;
+ int status = -EINVAL;
- if (phba->fc_flag & FC_OFFLINE_MODE)
- return snprintf(buf, PAGE_SIZE, "0\n");
+ if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
+ status = lpfc_selective_reset(phba);
+
+ if (status == 0)
+ return strlen(buf);
else
- return snprintf(buf, PAGE_SIZE, "1\n");
+ return status;
}
static ssize_t
-lpfc_board_online_store(struct class_device *cdev, const char *buf,
- size_t count)
+lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- struct completion online_compl;
- int val=0, status=0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- init_completion(&online_compl);
-
- if (val)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_ONLINE);
- else
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
- wait_for_completion(&online_compl);
- if (!status)
- return strlen(buf);
- else
- return -EIO;
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
@@ -532,10 +547,122 @@ static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
NULL);
static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
NULL);
-static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
- lpfc_board_online_show, lpfc_board_online_store);
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
+static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+
+
+static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
+
+static ssize_t
+lpfc_soft_wwpn_enable_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 cnt = count;
+
+ /*
+ * We're doing a simple sanity check for soft_wwpn setting.
+ * We require that the user write a specific key to enable
+ * the soft_wwpn attribute to be settable. Once the attribute
+ * is written, the enable key resets. If further updates are
+ * desired, the key must be written again to re-enable the
+ * attribute.
+ *
+ * The "key" is not secret - it is a hardcoded string shown
+ * here. The intent is to protect against the random user or
+ * application that is just writing attributes.
+ */
+
+ /* count may include a LF at end of string */
+ 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))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 1;
+ return count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
+ lpfc_soft_wwpn_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);
+}
+
+
+static ssize_t
+lpfc_soft_wwpn_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;
+ struct completion online_compl;
+ int stat1=0, stat2=0;
+ unsigned int i, j, cnt=count;
+ u8 wwpn[8];
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
+ ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 0;
+
+ memset(wwpn, 0, sizeof(wwpn));
+
+ /* 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) {
+ wwpn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
+ fc_host_port_name(host) = phba->cfg_soft_wwpn;
+
+ dev_printk(KERN_NOTICE, &phba->pcidev->dev,
+ "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+ if (stat1)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat1);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+ if (stat2)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat2);
+
+ return (stat1 || stat2) ? -EIO : count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
+ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
+
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
@@ -548,6 +675,123 @@ static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
/*
+# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+# until the timer expires. Value range is [0,255]. Default value is 30.
+*/
+static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO;
+module_param(lpfc_nodev_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_nodev_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+static ssize_t
+lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int val = 0;
+ val = phba->cfg_devloss_tmo;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->cfg_devloss_tmo);
+}
+
+static int
+lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+{
+ static int warned;
+ if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
+ if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
+ warned = 1;
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0402 Ignoring nodev_tmo module "
+ "parameter because devloss_tmo is"
+ " set.\n",
+ phba->brd_no);
+ }
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+ phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+ return -EINVAL;
+}
+
+static int
+lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (phba->dev_loss_tmo_changed ||
+ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0401 Ignoring change to nodev_tmo "
+ "because devloss_tmo is set.\n",
+ phba->brd_no);
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(nodev_tmo)
+
+static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
+ lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
+
+/*
+# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
+# disappear until the timer expires. Value range is [0,255]. Default
+# value is 30.
+*/
+module_param(lpfc_devloss_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_devloss_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_param_show(devloss_tmo)
+static int
+lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ phba->dev_loss_tmo_changed = 1;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(devloss_tmo)
+static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
+ lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
+
+/*
# lpfc_log_verbose: Only turn this flag on if you are willing to risk being
# deluged with LOTS of information.
# You can set a bit mask to record specific types of verbose messages:
@@ -606,14 +850,6 @@ LPFC_ATTR_R(scan_down, 1, 0, 1,
"Start scanning for devices from highest ALPA to lowest");
/*
-# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
-# until the timer expires. Value range is [0,255]. Default value is 30.
-# NOTE: this MUST be less then the SCSI Layer command timeout - 1.
-*/
-LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
- "Seconds driver will hold I/O waiting for a device to come back");
-
-/*
# lpfc_topology: link topology for init link
# 0x0 = attempt loop mode then point-to-point
# 0x01 = internal loopback mode
@@ -695,12 +931,12 @@ LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
"during discovery");
/*
-# lpfc_max_luns: maximum number of LUNs per target driver will support
-# Value range is [1,32768]. Default value is 256.
-# NOTE: The SCSI layer will scan each target for this many luns
+# lpfc_max_luns: maximum allowed LUN.
+# Value range is [0,65535]. Default value is 255.
+# NOTE: The SCSI layer might probe all allowed LUN on some old targets.
*/
-LPFC_ATTR_R(max_luns, 256, 1, 32768,
- "Maximum number of LUNs per target driver will support");
+LPFC_ATTR_R(max_luns, 255, 0, 65535,
+ "Maximum allowed LUN");
/*
# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
@@ -709,6 +945,7 @@ LPFC_ATTR_R(max_luns, 256, 1, 32768,
LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
"Milliseconds driver will wait between polling FCP ring");
+
struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_info,
&class_device_attr_serialnum,
@@ -726,6 +963,7 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
&class_device_attr_lpfc_nodev_tmo,
+ &class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
&class_device_attr_lpfc_use_adisc,
&class_device_attr_lpfc_ack0,
@@ -739,10 +977,12 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
- &class_device_attr_board_online,
&class_device_attr_board_mode,
+ &class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
+ &class_device_attr_lpfc_soft_wwpn,
+ &class_device_attr_lpfc_soft_wwpn_enable,
NULL,
};
@@ -873,7 +1113,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
phba->sysfs_mbox.mbox == NULL ) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
}
@@ -989,14 +1229,15 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
spin_unlock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_mbox_wait (phba,
phba->sysfs_mbox.mbox,
- phba->fc_ratov * 2);
+ lpfc_mbox_tmo_val(phba,
+ phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
spin_lock_irq(phba->host->host_lock);
}
if (rc != MBX_SUCCESS) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -ENODEV;
+ return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
}
phba->sysfs_mbox.state = SMBOX_READING;
}
@@ -1005,7 +1246,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
printk(KERN_WARNING "mbox_read: Bad State\n");
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
@@ -1192,6 +1433,15 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
fc_host_fabric_name(shost) = node_name;
}
+static void
+lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+
+ spin_lock_irq(shost->host_lock);
+ lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+ spin_unlock_irq(shost->host_lock);
+}
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
@@ -1199,8 +1449,10 @@ lpfc_get_stats(struct Scsi_Host *shost)
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
+ unsigned long seconds;
int rc = 0;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1261,22 +1513,103 @@ lpfc_get_stats(struct Scsi_Host *shost)
hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
hs->error_frames = pmb->un.varRdLnk.crcCnt;
+ hs->link_failure_count -= lso->link_failure_count;
+ hs->loss_of_sync_count -= lso->loss_of_sync_count;
+ hs->loss_of_signal_count -= lso->loss_of_signal_count;
+ hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count;
+ hs->invalid_tx_word_count -= lso->invalid_tx_word_count;
+ hs->invalid_crc_count -= lso->invalid_crc_count;
+ hs->error_frames -= lso->error_frames;
+
if (phba->fc_topology == TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
+ hs->lip_count -= lso->link_events;
hs->nos_count = -1;
} else {
hs->lip_count = -1;
hs->nos_count = (phba->fc_eventTag >> 1);
+ hs->nos_count -= lso->link_events;
}
hs->dumped_frames = -1;
-/* FIX ME */
- /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/
+ seconds = get_seconds();
+ if (seconds < psli->stats_start)
+ hs->seconds_since_last_reset = seconds +
+ ((unsigned long)-1 - psli->stats_start);
+ else
+ hs->seconds_since_last_reset = seconds - psli->stats_start;
return hs;
}
+static void
+lpfc_reset_stats(struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ int rc = 0;
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq)
+ return;
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+
+ pmb = &pmboxq->mb;
+ pmb->mbxCommand = MBX_READ_STATUS;
+ pmb->mbxOwner = OWN_HOST;
+ pmb->un.varWords[0] = 0x1; /* reset request */
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ pmb->mbxCommand = MBX_READ_LNK_STAT;
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free( pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
+ lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt;
+ lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt;
+ lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt;
+ lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
+ lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
+ lso->error_frames = pmb->un.varRdLnk.crcCnt;
+ lso->link_events = (phba->fc_eventTag >> 1);
+
+ psli->stats_start = get_seconds();
+
+ return;
+}
/*
* The LPFC driver treats linkdown handling as target loss events so there
@@ -1346,27 +1679,12 @@ lpfc_get_starget_port_name(struct scsi_target *starget)
}
static void
-lpfc_get_rport_loss_tmo(struct fc_rport *rport)
-{
- /*
- * Return the driver's global value for device loss timeout plus
- * five seconds to allow the driver's nodev timer to run.
- */
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
-}
-
-static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
- /*
- * The driver doesn't have a per-target timeout setting. Set
- * this value globally. lpfc_nodev_tmo should be greater then 0.
- */
if (timeout)
- lpfc_nodev_tmo = timeout;
+ rport->dev_loss_tmo = timeout;
else
- lpfc_nodev_tmo = 1;
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+ rport->dev_loss_tmo = 1;
}
@@ -1391,7 +1709,6 @@ struct fc_function_template lpfc_transport_functions = {
.show_host_port_name = 1,
.show_host_supported_classes = 1,
.show_host_supported_fc4s = 1,
- .show_host_symbolic_name = 1,
.show_host_supported_speeds = 1,
.show_host_maxframe_size = 1,
@@ -1414,20 +1731,21 @@ struct fc_function_template lpfc_transport_functions = {
.get_host_fabric_name = lpfc_get_host_fabric_name,
.show_host_fabric_name = 1,
+ .get_host_symbolic_name = lpfc_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+
/*
* The LPFC driver treats linkdown handling as target loss events
* so there are no sysfs handlers for link_down_tmo.
*/
.get_fc_host_stats = lpfc_get_stats,
-
- /* the LPFC driver doesn't support resetting stats yet */
+ .reset_fc_host_stats = lpfc_reset_stats,
.dd_fcrport_size = sizeof(struct lpfc_rport_data),
.show_rport_maxframe_size = 1,
.show_rport_supported_classes = 1,
- .get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo,
.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
.show_rport_dev_loss_tmo = 1,
@@ -1441,6 +1759,8 @@ struct fc_function_template lpfc_transport_functions = {
.show_starget_port_name = 1,
.issue_fc_host_lip = lpfc_issue_lip,
+ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ .terminate_rport_io = lpfc_terminate_rport_io,
};
void
@@ -1456,14 +1776,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_ack0_init(phba, lpfc_ack0);
lpfc_topology_init(phba, lpfc_topology);
lpfc_scan_down_init(phba, lpfc_scan_down);
- lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
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_devloss_tmo_init(phba, lpfc_devloss_tmo);
+ lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
phba->cfg_poll = lpfc_poll;
+ phba->cfg_soft_wwpn = 0L;
/*
* The total number of segments is the configuration value plus 2
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index ee22173fce4..3d684496acd 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -18,6 +18,7 @@
* included with this package. *
*******************************************************************/
+struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
@@ -127,6 +128,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
@@ -147,6 +149,7 @@ int lpfc_sli_hba_setup(struct lpfc_hba *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
+int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -198,6 +201,8 @@ extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
+void lpfc_terminate_rport_io(struct fc_rport *);
+void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index b65ee57af53..ae410645899 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -131,6 +131,7 @@ lpfc_ct_unsol_event(struct lpfc_hba * phba,
}
ct_unsol_event_exit_piocbq:
+ list_del(&head);
if (pmbuf) {
list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
lpfc_mbuf_free(phba, matp->virt, matp->phys);
@@ -323,7 +324,6 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
struct lpfc_sli_ct_request *Response =
(struct lpfc_sli_ct_request *) mp->virt;
struct lpfc_nodelist *ndlp = NULL;
- struct lpfc_nodelist *next_ndlp;
struct lpfc_dmabuf *mlast, *next_mp;
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
uint32_t Did;
@@ -398,30 +398,6 @@ nsout1:
* current driver state.
*/
if (phba->hba_state == LPFC_HBA_READY) {
-
- /*
- * Switch ports that connect a loop of multiple targets need
- * special consideration. The driver wants to unregister the
- * rpi only on the target that was pulled from the loop. On
- * RSCN, the driver wants to rediscover an NPort only if the
- * driver flagged it as NLP_NPR_2B_DISC. Provided adisc is
- * not enabled and the NPort is not capable of retransmissions
- * (FC Tape) prevent timing races with the scsi error handler by
- * unregistering the Nport's RPI. This action causes all
- * outstanding IO to flush back to the midlayer.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) {
- if ((phba->cfg_use_adisc == 0) &&
- !(ndlp->nlp_fcp_info &
- NLP_FCP_2_DEVICE)) {
- lpfc_unreg_rpi(phba, ndlp);
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- }
- }
- }
lpfc_els_flush_rscn(phba);
spin_lock_irq(phba->host->host_lock);
phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
@@ -481,7 +457,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0239 NameServer Rsp "
+ "%d:0208 NameServer Rsp "
"Data: x%x\n",
phba->brd_no,
phba->fc_flag);
@@ -588,13 +564,9 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
lpfc_decode_firmware_rev(phba, fwrev, 0);
- if (phba->Port[0]) {
- sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName,
- phba->Port, fwrev, lpfc_release_version);
- } else {
- sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
- fwrev, lpfc_release_version);
- }
+ sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
+ fwrev, lpfc_release_version);
+ return;
}
/*
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 41cf5d3ea6c..9766f909c9c 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -30,7 +30,6 @@
/* worker thread events */
enum lpfc_work_type {
- LPFC_EVT_NODEV_TMO,
LPFC_EVT_ONLINE,
LPFC_EVT_OFFLINE,
LPFC_EVT_WARM_START,
@@ -74,11 +73,9 @@ struct lpfc_nodelist {
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
- struct timer_list nlp_tmofunc; /* Used for nodev tmo */
struct fc_rport *rport; /* Corresponding FC transport
port structure */
struct lpfc_hba *nlp_phba;
- struct lpfc_work_evt nodev_timeout_evt;
struct lpfc_work_evt els_retry_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
@@ -102,7 +99,6 @@ struct lpfc_nodelist {
#define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */
#define NLP_RNID_SND 0x400 /* sent RNID request for this entry */
#define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */
-#define NLP_NODEV_TMO 0x10000 /* nodev timeout is running for node */
#define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */
#define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */
#define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */
@@ -169,7 +165,7 @@ struct lpfc_nodelist {
*/
/*
* For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
* expire, all effected nodes will receive a DEVICE_RM event.
*/
/*
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 283b7d824c3..71864cdc6c7 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -648,33 +648,32 @@ lpfc_more_plogi(struct lpfc_hba * phba)
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
struct lpfc_nodelist *ndlp)
{
struct lpfc_nodelist *new_ndlp;
- struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
struct serv_parm *sp;
uint8_t name[sizeof (struct lpfc_name)];
uint32_t rc;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- prsp = (struct lpfc_dmabuf *) pcmd->list.next;
lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+ memset(name, 0, sizeof (struct lpfc_name));
/* Now we to find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
- memset(name, 0, sizeof (struct lpfc_name));
- rc = memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
- if (!rc || (new_ndlp == ndlp)) {
+ if (new_ndlp == ndlp)
return ndlp;
- }
if (!new_ndlp) {
+ rc =
+ memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+ if (!rc)
+ return ndlp;
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
if (!new_ndlp)
return ndlp;
@@ -683,17 +682,21 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
lpfc_unreg_rpi(phba, new_ndlp);
- new_ndlp->nlp_prev_state = ndlp->nlp_state;
new_ndlp->nlp_DID = ndlp->nlp_DID;
- new_ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, new_ndlp, NLP_PLOGI_LIST);
+ new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ new_ndlp->nlp_state = ndlp->nlp_state;
+ lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
/* Move this back to NPR list */
- lpfc_unreg_rpi(phba, ndlp);
- ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
-
+ if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ }
+ else {
+ lpfc_unreg_rpi(phba, ndlp);
+ ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+ ndlp->nlp_state = NLP_STE_NPR_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ }
return new_ndlp;
}
@@ -703,6 +706,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
{
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *prsp;
int disc, rc, did, type;
@@ -769,7 +773,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
} else {
/* Good status, call state machine */
- ndlp = lpfc_plogi_confirm_nport(phba, cmdiocb, ndlp);
+ prsp = list_entry(((struct lpfc_dmabuf *)
+ cmdiocb->context2)->list.next,
+ struct lpfc_dmabuf, list);
+ ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
}
@@ -821,7 +828,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did,
+ elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did,
ELS_CMD_PLOGI);
if (!elsiocb)
return 1;
@@ -1841,9 +1848,12 @@ static void
lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb)
{
+ IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
LPFC_MBOXQ_t *mbox = NULL;
+ irsp = &rspiocb->iocb;
+
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
if (cmdiocb->context_un.mbox)
mbox = cmdiocb->context_un.mbox;
@@ -1886,9 +1896,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
mempool_free( mbox, phba->mbox_mem_pool);
} else {
mempool_free( mbox, phba->mbox_mem_pool);
- if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- ndlp = NULL;
+ /* 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) ||
+ (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
+ (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
+ if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ ndlp = NULL;
+ }
}
}
}
@@ -2490,6 +2506,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
uint32_t *lp;
IOCB_t *icmd;
uint32_t payload_len, cmd;
+ int i;
icmd = &cmdiocb->iocb;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2508,6 +2525,10 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
phba->brd_no,
phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+ for (i = 0; i < payload_len/sizeof(uint32_t); i++)
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_RSCN, lp[i]);
+
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
@@ -2791,8 +2812,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp = (struct lpfc_nodelist *) pmb->context2;
xri = (uint16_t) ((unsigned long)(pmb->context1));
- pmb->context1 = 0;
- pmb->context2 = 0;
+ pmb->context1 = NULL;
+ pmb->context2 = NULL;
if (mb->mbxStatus) {
mempool_free( pmb, phba->mbox_mem_pool);
@@ -2832,7 +2853,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS RPS ACC response tag x%x "
+ "%d:0118 Xmit ELS RPS ACC response tag x%x "
"Data: x%x x%x x%x x%x x%x\n",
phba->brd_no,
elsiocb->iocb.ulpIoTag,
@@ -2941,7 +2962,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS RPL ACC response tag x%x "
+ "%d:0120 Xmit ELS RPL ACC response tag x%x "
"Data: x%x x%x x%x x%x x%x\n",
phba->brd_no,
elsiocb->iocb.ulpIoTag,
@@ -3102,7 +3123,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_nodelist *ndlp, *next_ndlp;
/* FAN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n",
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
phba->brd_no);
icmd = &cmdiocb->iocb;
@@ -3282,10 +3303,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
} else
lpfc_sli_release_iocbq(phba, piocb);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
- phba->els_tmofunc.expires = jiffies + HZ * timeout;
- add_timer(&phba->els_tmofunc);
- }
+ if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+
spin_unlock_irq(phba->host->host_lock);
}
@@ -3442,6 +3462,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
}
phba->fc_stat.elsRcvFrame++;
@@ -3463,13 +3485,14 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
rjt_err = 1;
break;
}
+ ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
break;
case ELS_CMD_FLOGI:
phba->fc_stat.elsRcvFLOGI++;
lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_LOGO:
@@ -3492,7 +3515,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvRSCN++;
lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_ADISC:
@@ -3535,28 +3558,28 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvLIRR++;
lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPS:
phba->fc_stat.elsRcvRPS++;
lpfc_els_rcv_rps(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPL:
phba->fc_stat.elsRcvRPL++;
lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RNID:
phba->fc_stat.elsRcvRNID++;
lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
default:
@@ -3568,7 +3591,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
"%d:0115 Unknown ELS command x%x received from "
"NPORT x%x\n", phba->brd_no, cmd, did);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index adb086009ae..d586c3d3b0d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -56,28 +56,63 @@ static uint8_t lpfcAlpaArray[] = {
static void lpfc_disc_timeout_handler(struct lpfc_hba *);
-static void
-lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+void
+lpfc_terminate_rport_io(struct fc_rport *rport)
{
- uint8_t *name = (uint8_t *)&ndlp->nlp_portname;
- int warn_on = 0;
+ struct lpfc_rport_data *rdata;
+ struct lpfc_nodelist * ndlp;
+ struct lpfc_hba *phba;
- spin_lock_irq(phba->host->host_lock);
- if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ rdata = rport->dd_data;
+ ndlp = rdata->pnode;
+
+ if (!ndlp) {
+ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ printk(KERN_ERR "Cannot find remote node"
+ " to terminate I/O Data x%x\n",
+ rport->port_id);
return;
}
- /*
- * If a discovery event readded nodev_timer after timer
- * firing and before processing the timer, cancel the
- * nlp_tmofunc.
- */
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
+ phba = ndlp->nlp_phba;
+
spin_lock_irq(phba->host->host_lock);
+ if (ndlp->nlp_sid != NLP_NO_SID) {
+ lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ }
+ spin_unlock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
+ return;
+}
+
+/*
+ * This function will be called when dev_loss_tmo fire.
+ */
+void
+lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+{
+ struct lpfc_rport_data *rdata;
+ struct lpfc_nodelist * ndlp;
+ uint8_t *name;
+ int warn_on = 0;
+ struct lpfc_hba *phba;
+
+ rdata = rport->dd_data;
+ ndlp = rdata->pnode;
+
+ if (!ndlp) {
+ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ printk(KERN_ERR "Cannot find remote node"
+ " for rport in dev_loss_tmo_callbk x%x\n",
+ rport->port_id);
+ return;
+ }
+
+ name = (uint8_t *)&ndlp->nlp_portname;
+ phba = ndlp->nlp_phba;
+
+ spin_lock_irq(phba->host->host_lock);
if (ndlp->nlp_sid != NLP_NO_SID) {
warn_on = 1;
@@ -85,11 +120,14 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
+ if (phba->fc_flag & FC_UNLOADING)
+ warn_on = 0;
+
spin_unlock_irq(phba->host->host_lock);
if (warn_on) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0203 Nodev timeout on "
+ "%d:0203 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
phba->brd_no,
@@ -99,7 +137,7 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
ndlp->nlp_state, ndlp->nlp_rpi);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0204 Nodev timeout on "
+ "%d:0204 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
phba->brd_no,
@@ -109,7 +147,12 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
ndlp->nlp_state, ndlp->nlp_rpi);
}
- lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ ndlp->rport = NULL;
+ rdata->pnode = NULL;
+
+ if (!(phba->fc_flag & FC_UNLOADING))
+ lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+
return;
}
@@ -127,11 +170,6 @@ lpfc_work_list_done(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
free_evt = 1;
switch (evtp->evt) {
- case LPFC_EVT_NODEV_TMO:
- ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
- lpfc_process_nodev_timeout(phba, ndlp);
- free_evt = 0;
- break;
case LPFC_EVT_ELS_RETRY:
ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
lpfc_els_retry_delay_handler(ndlp);
@@ -340,6 +378,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
}
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_LINKDOWN, 0);
+
/* Clean up any firmware default rpi's */
if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
lpfc_unreg_did(phba, 0xffffffff, mb);
@@ -374,16 +415,6 @@ lpfc_linkdown(struct lpfc_hba * phba)
rc = lpfc_disc_state_machine(phba, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
- /* Check config parameter use-adisc or FCP-2 */
- if ((rc != NLP_STE_FREED_NODE) &&
- (phba->cfg_use_adisc == 0) &&
- !(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE)) {
- /* We know we will have to relogin, so
- * unreglogin the rpi right now to fail
- * any outstanding I/Os quickly.
- */
- lpfc_unreg_rpi(phba, ndlp);
- }
}
}
@@ -427,6 +458,9 @@ lpfc_linkup(struct lpfc_hba * phba)
struct list_head *listp, *node_list[7];
int i;
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_LINKUP, 0);
+
spin_lock_irq(phba->host->host_lock);
phba->hba_state = LPFC_LINK_UP;
phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
@@ -638,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_wwpn)
+ u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
memcpy((uint8_t *) & phba->fc_nodename,
(uint8_t *) & phba->fc_sparam.nodeName,
sizeof (struct lpfc_name));
@@ -1084,7 +1120,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
fc_remote_port_rolechg(rport, rport_ids.roles);
if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < MAX_FCP_TARGET)) {
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
@@ -1098,8 +1134,11 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
struct fc_rport *rport = ndlp->rport;
struct lpfc_rport_data *rdata = rport->dd_data;
- ndlp->rport = NULL;
- rdata->pnode = NULL;
+ if (rport->scsi_target_id == -1) {
+ ndlp->rport = NULL;
+ rdata->pnode = NULL;
+ }
+
fc_remote_port_delete(rport);
return;
@@ -1227,17 +1266,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
phba->fc_unmap_cnt++;
phba->nport_event_cnt++;
- /* stop nodev tmo if running */
- if (nlp->nlp_flag & NLP_NODEV_TMO) {
- nlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&nlp->nlp_tmofunc);
- spin_lock_irq(phba->host->host_lock);
- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
- list_del_init(&nlp->nodev_timeout_evt.
- evt_listp);
-
- }
nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
nlp->nlp_type |= NLP_FC_NODE;
break;
@@ -1248,17 +1276,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
phba->fc_map_cnt++;
phba->nport_event_cnt++;
- /* stop nodev tmo if running */
- if (nlp->nlp_flag & NLP_NODEV_TMO) {
- nlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&nlp->nlp_tmofunc);
- spin_lock_irq(phba->host->host_lock);
- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
- list_del_init(&nlp->nodev_timeout_evt.
- evt_listp);
-
- }
nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
break;
case NLP_NPR_LIST:
@@ -1267,11 +1284,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
phba->fc_npr_cnt++;
- if (!(nlp->nlp_flag & NLP_NODEV_TMO))
- mod_timer(&nlp->nlp_tmofunc,
- jiffies + HZ * phba->cfg_nodev_tmo);
-
- nlp->nlp_flag |= NLP_NODEV_TMO;
nlp->nlp_flag &= ~NLP_RCV_PLOGI;
break;
case NLP_JUST_DQ:
@@ -1301,7 +1313,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
* already. If we have, and it's a scsi entity, be
* sure to unblock any attached scsi devices
*/
- if (!nlp->rport)
+ if ((!nlp->rport) || (nlp->rport->port_state ==
+ FC_PORTSTATE_BLOCKED))
lpfc_register_remote_port(phba, nlp);
/*
@@ -1313,7 +1326,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
if ((rport_add == mapped) &&
((!nlp->rport) ||
(nlp->rport->scsi_target_id == -1) ||
- (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) {
+ (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
spin_lock_irq(phba->host->host_lock);
nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
@@ -1557,6 +1570,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
}
+
+ spin_lock_irq(phba->host->host_lock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -1569,18 +1584,16 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
mempool_free(mb, phba->mbox_mem_pool);
}
}
+ spin_unlock_irq(phba->host->host_lock);
lpfc_els_abort(phba,ndlp,0);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~(NLP_NODEV_TMO|NLP_DELAY_TMO);
+ ndlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
ndlp->nlp_last_elscmd = 0;
del_timer_sync(&ndlp->nlp_delayfunc);
- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
if (!list_empty(&ndlp->els_retry_evt.evt_listp))
list_del_init(&ndlp->els_retry_evt.evt_listp);
@@ -1597,16 +1610,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
int
lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
- if (ndlp->nlp_flag & NLP_NODEV_TMO) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
-
- }
-
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
lpfc_cancel_retry_delay_tmo(phba, ndlp);
@@ -1782,7 +1785,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to REGLOGIN */
/* FIND node DID reglogin */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID reglogin"
+ "%d:0901 FIND node DID reglogin"
" Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1805,7 +1808,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to PRLI */
/* FIND node DID prli */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID prli "
+ "%d:0902 FIND node DID prli "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1828,7 +1831,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to NPR */
/* FIND node DID npr */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID npr "
+ "%d:0903 FIND node DID npr "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1851,7 +1854,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to UNUSED */
/* FIND node DID unused */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID unused "
+ "%d:0905 FIND node DID unused "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -2335,7 +2338,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!initlinkmbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
+ "%d:0206 Device Discovery "
"completion error\n",
phba->brd_no);
phba->hba_state = LPFC_HBA_ERROR;
@@ -2365,7 +2368,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
if (!clearlambox) {
clrlaerr = 1;
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
+ "%d:0207 Device Discovery "
"completion error\n",
phba->brd_no);
phba->hba_state = LPFC_HBA_ERROR;
@@ -2421,34 +2424,6 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
return;
}
-static void
-lpfc_nodev_timeout(unsigned long ptr)
-{
- struct lpfc_hba *phba;
- struct lpfc_nodelist *ndlp;
- unsigned long iflag;
- struct lpfc_work_evt *evtp;
-
- ndlp = (struct lpfc_nodelist *)ptr;
- phba = ndlp->nlp_phba;
- evtp = &ndlp->nodev_timeout_evt;
- spin_lock_irqsave(phba->host->host_lock, iflag);
-
- if (!list_empty(&evtp->evt_listp)) {
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
- return;
- }
- evtp->evt_arg1 = ndlp;
- evtp->evt = LPFC_EVT_NODEV_TMO;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
- wake_up(phba->work_wait);
-
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
- return;
-}
-
-
/*
* This routine handles processing a NameServer REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
@@ -2572,11 +2547,7 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
uint32_t did)
{
memset(ndlp, 0, sizeof (struct lpfc_nodelist));
- INIT_LIST_HEAD(&ndlp->nodev_timeout_evt.evt_listp);
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
- init_timer(&ndlp->nlp_tmofunc);
- ndlp->nlp_tmofunc.function = lpfc_nodev_timeout;
- ndlp->nlp_tmofunc.data = (unsigned long)ndlp;
init_timer(&ndlp->nlp_delayfunc);
ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 908d0f27706..4cdf3464267 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -71,6 +71,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
uint16_t offset = 0;
static char licensed[56] =
"key unlock for use with gnu public licensed code only\0";
+ static int init_key = 1;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
@@ -82,10 +83,13 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
phba->hba_state = LPFC_INIT_MBX_CMDS;
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
- uint32_t *ptext = (uint32_t *) licensed;
+ if (init_key) {
+ uint32_t *ptext = (uint32_t *) licensed;
- for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
- *ptext = cpu_to_be32(*ptext);
+ for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
+ *ptext = cpu_to_be32(*ptext);
+ init_key = 0;
+ }
lpfc_read_nv(phba, pmb);
memset((char*)mb->un.varRDnvp.rsvd3, 0,
@@ -264,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
kfree(mp);
pmb->context1 = NULL;
+ 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,
sizeof (struct lpfc_name));
memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
@@ -405,19 +411,26 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
/* MBOX buffer will be freed in mbox compl */
- i = 0;
+ return (0);
+}
+
+static int
+lpfc_discovery_wait(struct lpfc_hba *phba)
+{
+ int i = 0;
+
while ((phba->hba_state != LPFC_HBA_READY) ||
(phba->num_disc_nodes) || (phba->fc_prli_sent) ||
((phba->fc_map_cnt == 0) && (i<2)) ||
- (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
+ (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
/* Check every second for 30 retries. */
i++;
if (i > 30) {
- break;
+ return -ETIMEDOUT;
}
if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
/* The link is down. Set linkdown timeout */
- break;
+ return -ETIMEDOUT;
}
/* Delay for 1 second to give discovery time to complete. */
@@ -425,12 +438,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
- /* Since num_disc_nodes keys off of PLOGI, delay a bit to let
- * any potential PRLIs to flush thru the SLI sub-system.
- */
- msleep(50);
-
- return (0);
+ return 0;
}
/************************************************************************/
@@ -505,6 +513,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
+ uint32_t event_data;
if (phba->work_hs & HS_FFER6) {
/* Re-establishing Link */
@@ -549,6 +558,11 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
phba->brd_no, phba->work_hs,
phba->work_status[0], phba->work_status[1]);
+ event_data = FC_REG_DUMP_EVENT;
+ fc_host_post_vendor_event(phba->host, fc_get_event_number(),
+ sizeof(event_data), (char *) &event_data,
+ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
lpfc_offline(phba);
phba->hba_state = LPFC_HBA_ERROR;
@@ -939,12 +953,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
"10-port ", "PCIe"};
break;
default:
- m = (typeof(m)){ 0 };
+ m = (typeof(m)){ NULL };
break;
}
break;
default:
- m = (typeof(m)){ 0 };
+ m = (typeof(m)){ NULL };
break;
}
@@ -1339,7 +1353,8 @@ lpfc_offline(struct lpfc_hba * phba)
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
unsigned long iflag;
- int i = 0;
+ int i;
+ int cnt = 0;
if (!phba)
return 0;
@@ -1348,20 +1363,31 @@ lpfc_offline(struct lpfc_hba * phba)
return 0;
psli = &phba->sli;
- pring = &psli->ring[psli->fcp_ring];
lpfc_linkdown(phba);
+ lpfc_sli_flush_mbox_queue(phba);
- /* The linkdown event takes 30 seconds to timeout. */
- while (pring->txcmplq_cnt) {
- mdelay(10);
- if (i++ > 3000)
- break;
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ /* The linkdown event takes 30 seconds to timeout. */
+ while (pring->txcmplq_cnt) {
+ mdelay(10);
+ if (cnt++ > 3000) {
+ lpfc_printf_log(phba,
+ KERN_WARNING, LOG_INIT,
+ "%d:0466 Outstanding IO when "
+ "bringing Adapter offline\n",
+ phba->brd_no);
+ break;
+ }
+ }
}
+
/* stop all timers associated with this hba */
lpfc_stop_timer(phba);
phba->work_hba_events = 0;
+ phba->work_ha = 0;
lpfc_printf_log(phba,
KERN_WARNING,
@@ -1451,7 +1477,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_put_host;
host->unique_id = phba->brd_no;
- init_MUTEX(&phba->hba_can_block);
INIT_LIST_HEAD(&phba->ctrspbuflist);
INIT_LIST_HEAD(&phba->rnidrspbuflist);
INIT_LIST_HEAD(&phba->freebufList);
@@ -1600,7 +1625,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_iocbq;
}
- /* We can rely on a queue depth attribute only after SLI HBA setup */
+ /*
+ * Set initial can_queue value since 0 is no longer supported and
+ * scsi_add_host will fail. This will be adjusted later based on the
+ * max xri value determined in hba setup.
+ */
host->can_queue = phba->cfg_hba_queue_depth - 10;
/* Tell the midlayer we support 16 byte commands */
@@ -1620,7 +1649,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (error)
goto out_remove_host;
- error = request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ,
+ error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -1640,6 +1669,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_irq;
}
+ /*
+ * hba setup may have changed the hba_queue_depth so we need to adjust
+ * the value of can_queue.
+ */
+ host->can_queue = phba->cfg_hba_queue_depth - 10;
+
+ lpfc_discovery_wait(phba);
+
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
spin_lock_irq(phba->host->host_lock);
lpfc_poll_start_timer(phba);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e42f22aaf71..4d016c2a1b2 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -651,3 +651,19 @@ lpfc_mbox_get(struct lpfc_hba * phba)
return mbq;
}
+
+int
+lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
+{
+ switch (cmd) {
+ case MBX_WRITE_NV: /* 0x03 */
+ case MBX_UPDATE_CFG: /* 0x1B */
+ case MBX_DOWN_LOAD: /* 0x1C */
+ case MBX_DEL_LD_ENTRY: /* 0x1D */
+ case MBX_LOAD_AREA: /* 0x81 */
+ case MBX_FLASH_WR_ULA: /* 0x98 */
+ case MBX_LOAD_EXP_ROM: /* 0x9C */
+ return LPFC_MBOX_TMO_FLASH_CMD;
+ }
+ return LPFC_MBOX_TMO;
+}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 07017658ac5..066292d3995 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -133,6 +133,11 @@ lpfc_mem_free(struct lpfc_hba * phba)
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
+
+ /* Free the iocb lookup array */
+ kfree(psli->iocbq_lookup);
+ psli->iocbq_lookup = NULL;
+
}
void *
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 27d60ad897c..d5f415007db 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -179,7 +179,7 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0201 Abort outstanding I/O on NPort x%x "
+ "%d:0205 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
@@ -393,6 +393,20 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
mbox->context2 = ndlp;
ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
+ /*
+ * If there is an outstanding PLOGI issued, abort it before
+ * sending ACC rsp for received PLOGI. If pending plogi
+ * is not canceled here, the plogi will be rejected by
+ * remote port and will be retried. On a configuration with
+ * single discovery thread, this will cause a huge delay in
+ * discovery. Also this will cause multiple state machines
+ * running in parallel for this node.
+ */
+ if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(phba, ndlp, 1);
+ }
+
lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
return 1;
@@ -1110,6 +1124,17 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
phba->brd_no,
did, mb->mbxStatus, phba->hba_state);
+ /*
+ * If RegLogin failed due to lack of HBA resources do not
+ * retry discovery.
+ */
+ if (mb->mbxStatus == MBXERR_RPI_FULL) {
+ ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ return ndlp->nlp_state;
+ }
+
/* Put ndlp in npr list set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
spin_lock_irq(phba->host->host_lock);
@@ -1590,7 +1615,13 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
lpfc_rcv_padisc(phba, ndlp, cmdiocb);
- if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ /*
+ * Do not start discovery if discovery is about to start
+ * 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_NPR_ADISC) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
@@ -1782,7 +1813,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba,
*/
/*
* For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
* expire, all effected nodes will receive a DEVICE_RM event.
*/
/*
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 7dc4c2e6bed..97ae98dc95d 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -21,6 +21,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -41,20 +42,6 @@
#define LPFC_ABORT_WAIT 2
-static inline void
-lpfc_block_requests(struct lpfc_hba * phba)
-{
- down(&phba->hba_can_block);
- scsi_block_requests(phba->host);
-}
-
-static inline void
-lpfc_unblock_requests(struct lpfc_hba * phba)
-{
- scsi_unblock_requests(phba->host);
- up(&phba->hba_can_block);
-}
-
/*
* This routine allocates a scsi buffer, which contains all the necessary
* information needed to initiate a SCSI I/O. The non-DMAable buffer region
@@ -167,22 +154,6 @@ static void
lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
{
unsigned long iflag = 0;
- /*
- * There are only two special cases to consider. (1) the scsi command
- * requested scatter-gather usage or (2) the scsi command allocated
- * a request buffer, but did not request use_sg. There is a third
- * case, but it does not require resource deallocation.
- */
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->pCmd = NULL;
@@ -296,6 +267,27 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
}
static void
+lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+{
+ /*
+ * There are only two special cases to consider. (1) the scsi command
+ * requested scatter-gather usage or (2) the scsi command allocated
+ * a request buffer, but did not request use_sg. There is a third
+ * case, but it does not require resource deallocation.
+ */
+ if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
+ dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
+ psb->seg_cnt, psb->pCmd->sc_data_direction);
+ } else {
+ if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
+ dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
+ psb->pCmd->request_bufflen,
+ psb->pCmd->sc_data_direction);
+ }
+ }
+}
+
+static void
lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
@@ -468,6 +460,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
cmd->scsi_done(cmd);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
}
@@ -525,6 +518,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
}
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
@@ -623,6 +617,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
static int
lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd,
+ unsigned int lun,
uint8_t task_mgmt_cmd)
{
struct lpfc_sli *psli;
@@ -641,8 +636,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
- int_to_scsilun(lpfc_cmd->pCmd->device->lun,
- &lpfc_cmd->fcp_cmnd->fcp_lun);
+ int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun);
fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
piocb->ulpCommand = CMD_FCP_ICMND64_CR;
@@ -669,14 +663,16 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
static int
lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
- unsigned tgt_id, struct lpfc_rport_data *rdata)
+ unsigned tgt_id, unsigned int lun,
+ struct lpfc_rport_data *rdata)
{
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
+ FCP_TARGET_RESET);
if (!ret)
return FAILED;
@@ -836,6 +832,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
out_host_busy_free_buf:
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
@@ -845,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static void
+lpfc_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));
+
+ spin_lock_irq(shost->host_lock);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irq(shost->host_lock);
+ msleep(1000);
+ spin_lock_irq(shost->host_lock);
+ }
+ spin_unlock_irq(shost->host_lock);
+ return;
+}
static int
lpfc_abort_handler(struct scsi_cmnd *cmnd)
@@ -859,7 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
unsigned int loop_count = 0;
int ret = SUCCESS;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
@@ -923,7 +935,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
spin_lock_irq(phba->host->host_lock);
if (++loop_count
- > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
break;
}
@@ -945,7 +957,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
cmnd->device->lun, cmnd->serial_number);
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -963,11 +974,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
int ret = FAILED;
int cnt, loopcnt;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
/*
* If target is not in a MAPPED state, delay the reset until
- * target is rediscovered or nodev timeout expires.
+ * target is rediscovered or devloss timeout expires.
*/
while ( 1 ) {
if (!pnode)
@@ -986,12 +997,12 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (lpfc_cmd == NULL)
goto out;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->timeout = 60;
lpfc_cmd->scsi_hba = phba;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
+ FCP_LUN_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1018,7 +1029,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
cmd_status = iocbqrsp->iocb.ulpStatus;
lpfc_sli_release_iocbq(phba, iocbqrsp);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
/*
* All outstanding txcmplq I/Os should have been aborted by the device.
@@ -1040,7 +1050,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
spin_lock_irq(phba->host->host_lock);
if (++loopcnt
- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
cnt = lpfc_sli_sum_iocb(phba,
@@ -1057,6 +1067,8 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
}
out_free_scsi_buf:
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 SCSI layer issued LUN reset (%d, %d) "
"Data: x%x x%x x%x\n",
@@ -1065,7 +1077,6 @@ out_free_scsi_buf:
out:
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -1080,7 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
int cnt, loopcnt;
struct lpfc_scsi_buf * lpfc_cmd;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -1089,7 +1100,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->scsi_hba = phba;
/*
@@ -1097,7 +1107,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* targets known to the driver. Should any target reset
* fail, this routine returns failure to the midlayer.
*/
- for (i = 0; i < MAX_FCP_TARGET; i++) {
+ for (i = 0; i < LPFC_MAX_TARGET; i++) {
/* Search the mapped list for this target ID */
match = 0;
list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
@@ -1109,11 +1119,11 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba,
- i, ndlp->rport->dd_data);
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
+ ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0713 Bus Reset on target %d failed\n",
+ "%d:0700 Bus Reset on target %d failed\n",
phba->brd_no, i);
err_count++;
}
@@ -1141,7 +1151,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
spin_lock_irq(phba->host->host_lock);
if (++loopcnt
- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
cnt = lpfc_sli_sum_iocb(phba,
@@ -1163,7 +1173,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
phba->brd_no, ret);
out:
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -1240,7 +1249,7 @@ lpfc_slave_configure(struct scsi_device *sdev)
* target pointer is stored in the starget_data for the
* driver's sysfs entry point functions.
*/
- rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5;
+ rport->dev_loss_tmo = phba->cfg_devloss_tmo;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_poll_fcp_ring(phba);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index bb69a7a1ec5..70f4d5a1348 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -191,35 +191,12 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
{
- uint16_t iotag;
-
list_add_tail(&piocb->list, &pring->txcmplq);
pring->txcmplq_cnt++;
if (unlikely(pring->ringno == LPFC_ELS_RING))
mod_timer(&phba->els_tmofunc,
jiffies + HZ * (phba->fc_ratov << 1));
- if (pring->fast_lookup) {
- /* Setup fast lookup based on iotag for completion */
- iotag = piocb->iocb.ulpIoTag;
- if (iotag && (iotag < pring->fast_iotag))
- *(pring->fast_lookup + iotag) = piocb;
- else {
-
- /* Cmd ring <ringno> put: iotag <iotag> greater then
- configured max <fast_iotag> wd0 <icmd> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
- "%d:0316 Cmd ring %d put: iotag x%x "
- "greater then configured max x%x "
- "wd0 x%x\n",
- phba->brd_no,
- pring->ringno, iotag,
- pring->fast_iotag,
- *(((uint32_t *)(&piocb->iocb)) + 7));
- }
- }
return (0);
}
@@ -343,7 +320,8 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
kfree(old_arr);
return iotag;
}
- }
+ } else
+ spin_unlock_irq(phba->host->host_lock);
lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
"%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
@@ -601,7 +579,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
/* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
<status> */
lpfc_printf_log(phba,
- KERN_ERR,
+ KERN_WARNING,
LOG_MBOX | LOG_SLI,
"%d:0304 Stray Mailbox Interrupt "
"mbxCommand x%x mbxStatus x%x\n",
@@ -992,9 +970,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
* resources need to be recovered.
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
- printk(KERN_INFO "%s: IOCB cmd 0x%x processed."
- " Skipping completion\n", __FUNCTION__,
- irsp->ulpCommand);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0314 IOCB cmd 0x%x"
+ " processed. Skipping"
+ " completion", phba->brd_no,
+ irsp->ulpCommand);
break;
}
@@ -1127,7 +1107,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
if (unlikely(irsp->ulpStatus)) {
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0326 Rsp Ring %d error: IOCB Data: "
+ "%d:0336 Rsp Ring %d error: IOCB Data: "
"x%x x%x x%x x%x x%x x%x x%x x%x\n",
phba->brd_no, pring->ringno,
irsp->un.ulpWord[0], irsp->un.ulpWord[1],
@@ -1145,9 +1125,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
* resources need to be recovered.
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
- printk(KERN_INFO "%s: IOCB cmd 0x%x processed. "
- "Skipping completion\n", __FUNCTION__,
- irsp->ulpCommand);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0333 IOCB cmd 0x%x"
+ " processed. Skipping"
+ " completion\n", phba->brd_no,
+ irsp->ulpCommand);
break;
}
@@ -1178,7 +1160,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0321 Unknown IOCB command "
+ "%d:0334 Unknown IOCB command "
"Data: x%x, x%x x%x x%x x%x\n",
phba->brd_no, type, irsp->ulpCommand,
irsp->ulpStatus, irsp->ulpIoTag,
@@ -1261,7 +1243,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
- "%d:0312 Ring %d handler: portRspPut %d "
+ "%d:0303 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
phba->brd_no,
pring->ringno, portRspPut, portRspMax);
@@ -1406,7 +1388,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
- "%d:0321 Unknown IOCB command "
+ "%d:0335 Unknown IOCB command "
"Data: x%x x%x x%x x%x\n",
phba->brd_no,
irsp->ulpCommand,
@@ -1422,11 +1404,11 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
next_iocb,
&saveq->list,
list) {
+ list_del(&rspiocbp->list);
lpfc_sli_release_iocbq(phba,
rspiocbp);
}
}
-
lpfc_sli_release_iocbq(phba, saveq);
}
}
@@ -1570,8 +1552,8 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
void lpfc_reset_barrier(struct lpfc_hba * phba)
{
- uint32_t * resp_buf;
- uint32_t * mbox_buf;
+ uint32_t __iomem *resp_buf;
+ uint32_t __iomem *mbox_buf;
volatile uint32_t mbox;
uint32_t hc_copy;
int i;
@@ -1587,7 +1569,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
* Tell the other part of the chip to suspend temporarily all
* its DMA activity.
*/
- resp_buf = (uint32_t *)phba->MBslimaddr;
+ resp_buf = phba->MBslimaddr;
/* Disable the error attention */
hc_copy = readl(phba->HCregaddr);
@@ -1605,7 +1587,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;
writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
- mbox_buf = (uint32_t *)phba->MBslimaddr;
+ mbox_buf = phba->MBslimaddr;
writel(mbox, mbox_buf);
for (i = 0;
@@ -1734,15 +1716,13 @@ lpfc_sli_brdreset(struct lpfc_hba * phba)
phba->fc_myDID = 0;
phba->fc_prevDID = 0;
- psli->sli_flag = 0;
-
/* Turn off parity checking and serr during the physical reset */
pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
pci_write_config_word(phba->pcidev, PCI_COMMAND,
(cfg_value &
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
- psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA);
/* Now toggle INITFF bit in the Host Control Register */
writel(HC_INITFF, phba->HCregaddr);
mdelay(1);
@@ -1783,7 +1763,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no,
+ "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
phba->hba_state, psli->sli_flag);
word0 = 0;
@@ -1805,7 +1785,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
skip_post = 0;
word0 = 0; /* This is really setting up word1 */
}
- to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t);
+ to_slim = phba->MBslimaddr + sizeof (uint32_t);
writel(*(uint32_t *) mb, to_slim);
readl(to_slim); /* flush */
@@ -1815,6 +1795,9 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
+ memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
+ psli->stats_start = get_seconds();
+
if (skip_post)
mdelay(100);
else
@@ -1925,6 +1908,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
}
while (resetcount < 2 && !done) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
phba->hba_state = LPFC_STATE_UNKNOWN;
lpfc_sli_brdrestart(phba);
msleep(2500);
@@ -1932,6 +1918,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
if (rc)
break;
+ spin_lock_irq(phba->host->host_lock);
+ phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
resetcount++;
/* Call pre CONFIG_PORT mailbox command initialization. A value of 0
@@ -2217,7 +2206,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
return (MBX_NOT_FINISHED);
}
/* timeout active mbox command */
- mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO);
+ mod_timer(&psli->mbox_tmo, (jiffies +
+ (HZ * lpfc_mbox_tmo_val(phba, mb->mbxCommand))));
}
/* Mailbox cmd <cmd> issue */
@@ -2277,7 +2267,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
break;
case MBX_POLL:
- i = 0;
psli->mbox_active = NULL;
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* First read mbox status word */
@@ -2291,11 +2280,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* Read the HBA Host Attention Register */
ha_copy = readl(phba->HAregaddr);
+ i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
+ i *= 1000; /* Convert to ms */
+
/* Wait for command to complete */
while (((word0 & OWN_CHIP) == OWN_CHIP) ||
(!(ha_copy & HA_MBATT) &&
(phba->hba_state > LPFC_WARM_START))) {
- if (i++ >= 100) {
+ if (i-- <= 0) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
spin_unlock_irqrestore(phba->host->host_lock,
drvr_flag);
@@ -2313,7 +2305,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* Can be in interrupt context, do not sleep */
/* (or might be called with interrupts disabled) */
- mdelay(i);
+ mdelay(1);
spin_lock_irqsave(phba->host->host_lock, drvr_flag);
@@ -2659,8 +2651,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
INIT_LIST_HEAD(&(pring->txq));
- kfree(pring->fast_lookup);
- pring->fast_lookup = NULL;
}
spin_unlock_irqrestore(phba->host->host_lock, flags);
@@ -3030,7 +3020,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
if (timeleft == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0329 IOCB wait timeout error - no "
+ "%d:0338 IOCB wait timeout error - no "
"wake response Data x%x\n",
phba->brd_no, timeout);
retval = IOCB_TIMEDOUT;
@@ -3110,6 +3100,24 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
return retval;
}
+int
+lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+{
+ int i = 0;
+
+ while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+ if (i++ > LPFC_MBOX_TMO * 1000)
+ return 1;
+
+ if (lpfc_sli_handle_mb_event(phba) == 0)
+ i = 0;
+
+ msleep(1);
+ }
+
+ return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+}
+
irqreturn_t
lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
{
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a52d6c6cf08..e26de680935 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -135,8 +135,6 @@ struct lpfc_sli_ring {
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
uint32_t iotag_max; /* max iotag value to use */
- struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by
- iotag */
struct list_head txq;
uint16_t txq_cnt; /* current length of queue */
uint16_t txq_max; /* max length */
@@ -174,6 +172,18 @@ struct lpfc_sli_stat {
uint32_t mbox_busy; /* Mailbox cmd busy */
};
+/* Structure to store link status values when port stats are reset */
+struct lpfc_lnk_stat {
+ uint32_t link_failure_count;
+ uint32_t loss_of_sync_count;
+ uint32_t loss_of_signal_count;
+ uint32_t prim_seq_protocol_err_count;
+ uint32_t invalid_tx_word_count;
+ uint32_t invalid_crc_count;
+ uint32_t error_frames;
+ uint32_t link_events;
+};
+
/* Structure used to hold SLI information */
struct lpfc_sli {
uint32_t num_rings;
@@ -203,6 +213,8 @@ struct lpfc_sli {
struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */
size_t iocbq_lookup_len; /* current lengs of the array */
uint16_t last_iotag; /* last allocated IOTAG */
+ unsigned long stats_start; /* in seconds */
+ struct lpfc_lnk_stat lnk_stat_offsets;
};
/* Given a pointer to the start of the ring, and the slot number of
@@ -213,3 +225,9 @@ struct lpfc_sli {
#define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox
command */
+#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write
+ * or erase cmds. This is especially
+ * long because of the potential of
+ * multiple flash erases that can be
+ * spawned.
+ */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 6b737568b83..ac417908b40 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.6"
+#define LPFC_DRIVER_VERSION "8.1.10"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 93edaa8696c..6422de72bf4 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -378,7 +378,7 @@ static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
for (i = 0; i < nseg; ++i) {
@@ -431,7 +431,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
struct fsc_state *state;
struct Scsi_Host *host;
void *dma_cmd_space;
- unsigned char *clkprop;
+ const unsigned char *clkprop;
int proplen, rc = -ENODEV;
if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index e31fadd6190..118206d68c6 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -43,9 +43,6 @@
/* #define DEBUG_MAC_ESP */
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
-
extern void esp_handle(struct NCR_ESP *esp);
extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -639,13 +636,13 @@ static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
static void dma_ints_off(struct NCR_ESP * esp)
{
- mac_turnoff_irq(esp->irq);
+ disable_irq(esp->irq);
}
static void dma_ints_on(struct NCR_ESP * esp)
{
- mac_turnon_irq(esp->irq);
+ enable_irq(esp->irq);
}
/*
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 777f9bcd117..a942a21dd87 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -65,9 +65,6 @@
#define RESET_BOOT
#define DRIVER_SETUP
-#define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
-#define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
-
extern void via_scsi_clear(void);
#ifdef RESET_BOOT
@@ -351,7 +348,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
- mac_disable_irq(IRQ_MAC_SCSI);
+ disable_irq(IRQ_MAC_SCSI);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
@@ -369,7 +366,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
barrier();
/* switch on SCSI IRQ again */
- mac_enable_irq(IRQ_MAC_SCSI);
+ enable_irq(IRQ_MAC_SCSI);
printk(KERN_INFO " done\n" );
}
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 5d2cefb5e52..b87bef69ba0 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -2822,9 +2822,7 @@ mega_print_inquiry(char *page, char *scsi_inq)
i = scsi_inq[0] & 0x1f;
- len += sprintf(page+len, " Type: %s ",
- i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
- "Unknown ");
+ len += sprintf(page+len, " Type: %s ", scsi_device_type(i));
len += sprintf(page+len,
" ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
@@ -3658,8 +3656,9 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
* Send the request sense data also, irrespective of
* whether the user has asked for it or not.
*/
- copy_to_user(upthru->reqsensearea,
- pthru->reqsensearea, 14);
+ if (copy_to_user(upthru->reqsensearea,
+ pthru->reqsensearea, 14))
+ rval = -EFAULT;
freemem_and_return:
if( pthru->dataxferlen ) {
@@ -4714,7 +4713,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ?
megaraid_isr_memmapped : megaraid_isr_iomapped,
- SA_SHIRQ, "megaraid", adapter)) {
+ IRQF_SHARED, "megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", irq);
goto out_free_scb_list;
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 4675343228a..8cd0bd1d0f7 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -37,6 +37,12 @@
#define LSI_MAX_CHANNELS 16
#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1)
+#define HBA_SIGNATURE_64_BIT 0x299
+#define PCI_CONF_AMISIG64 0xa4
+
+#define MEGA_SCSI_INQ_EVPD 1
+#define MEGA_INVALID_FIELD_IN_CDB 0x24
+
/**
* scb_t - scsi command control block
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
index bdaee144a1c..b8aa34202ec 100644
--- a/drivers/scsi/megaraid/megaraid_ioctl.h
+++ b/drivers/scsi/megaraid/megaraid_ioctl.h
@@ -132,6 +132,10 @@ typedef struct uioc {
/* Driver Data: */
void __user * user_data;
uint32_t user_data_len;
+
+ /* 64bit alignment */
+ uint32_t pad_for_64bit_align;
+
mraid_passthru_t __user *user_pthru;
mraid_passthru_t *pthru32;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index bec1424eda8..266b3910846 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mbox.c
- * Version : v2.20.4.8 (Apr 11 2006)
+ * Version : v2.20.4.9 (Jul 16 2006)
*
* Authors:
* Atul Mukker <Atul.Mukker@lsil.com>
@@ -330,6 +330,21 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
NULL,
};
+/**
+ * megaraid_change_queue_depth - Change the device's queue depth
+ * @sdev: scsi device struct
+ * @qdepth: depth to set
+ *
+ * Return value:
+ * actual depth set
+ **/
+static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ if (qdepth > MBOX_MAX_SCSI_CMDS)
+ qdepth = MBOX_MAX_SCSI_CMDS;
+ scsi_adjust_queue_depth(sdev, 0, qdepth);
+ return sdev->queue_depth;
+}
/*
* Scsi host template for megaraid unified driver
@@ -343,6 +358,7 @@ static struct scsi_host_template megaraid_template_g = {
.eh_device_reset_handler = megaraid_reset_handler,
.eh_bus_reset_handler = megaraid_reset_handler,
.eh_host_reset_handler = megaraid_reset_handler,
+ .change_queue_depth = megaraid_change_queue_depth,
.use_clustering = ENABLE_CLUSTERING,
.sdev_attrs = megaraid_sdev_attrs,
.shost_attrs = megaraid_shost_attrs,
@@ -714,12 +730,13 @@ megaraid_io_detach(adapter_t *adapter)
* . Allocate memory required for all the commands
* . Use internal library of FW routines, build up complete soft state
*/
-static int __init
+static int __devinit
megaraid_init_mbox(adapter_t *adapter)
{
struct pci_dev *pdev;
mraid_device_t *raid_dev;
int i;
+ uint32_t magic64;
adapter->ito = MBOX_TIMEOUT;
@@ -767,7 +784,7 @@ megaraid_init_mbox(adapter_t *adapter)
//
// request IRQ and register the interrupt service routine
- if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
+ if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid",
adapter)) {
con_log(CL_ANN, (KERN_WARNING
@@ -863,12 +880,33 @@ megaraid_init_mbox(adapter_t *adapter)
// Set the DMA mask to 64-bit. All supported controllers as capable of
// DMA in this range
- if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK) != 0) {
-
- con_log(CL_ANN, (KERN_WARNING
- "megaraid: could not set DMA mask for 64-bit.\n"));
+ pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64);
+
+ if (((magic64 == HBA_SIGNATURE_64_BIT) &&
+ ((adapter->pdev->subsystem_device !=
+ 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 &&
+ adapter->pdev->device == PCI_DEVICE_ID_VERDE) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_DOBSON) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) {
+ if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: DMA mask for 64-bit failed\n"));
- goto out_free_sysfs_res;
+ if (pci_set_dma_mask (adapter->pdev, DMA_32BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: 32-bit DMA mask failed\n"));
+ goto out_free_sysfs_res;
+ }
+ }
}
// setup tasklet for DPC
@@ -1622,6 +1660,14 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
rdev->last_disp |= (1L << SCP2CHANNEL(scp));
}
+ if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
+ scp->sense_buffer[0] = 0x70;
+ scp->sense_buffer[2] = ILLEGAL_REQUEST;
+ scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB;
+ scp->result = CHECK_CONDITION << 1;
+ return NULL;
+ }
+
/* Fall through */
case READ_CAPACITY:
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 868fb0ec93e..2b5a3285f79 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -21,8 +21,8 @@
#include "megaraid_ioctl.h"
-#define MEGARAID_VERSION "2.20.4.8"
-#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)"
+#define MEGARAID_VERSION "2.20.4.9"
+#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)"
/*
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index e8f534fb336..d85b9a8f1b8 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mm.c
- * Version : v2.20.2.6 (Mar 7 2005)
+ * Version : v2.20.2.7 (Jul 16 2006)
*
* Common management module
*/
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
index 3d9e67d6849..c8762b2b8ed 100644
--- a/drivers/scsi/megaraid/megaraid_mm.h
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -27,9 +27,9 @@
#include "megaraid_ioctl.h"
-#define LSI_COMMON_MOD_VERSION "2.20.2.6"
+#define LSI_COMMON_MOD_VERSION "2.20.2.7"
#define LSI_COMMON_MOD_EXT_VERSION \
- "(Release Date: Mon Mar 7 00:01:03 EST 2005)"
+ "(Release Date: Sun Jul 16 00:01:03 EST 2006)"
#define LSI_DBGLVL dbglevel
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 0c9516ff636..4cab5b534b2 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.02.04
+ * Version : v00.00.03.01
*
* Authors:
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -53,25 +53,15 @@ MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
*/
static struct pci_device_id megasas_pci_table[] = {
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_LSI_SAS1078R, // ppc IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {
- PCI_VENDOR_ID_DELL,
- PCI_DEVICE_ID_DELL_PERC5, // xscale IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {0} /* Terminating entry */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
+ /* xscale IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
+ /* ppc IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
+ /* xscale IOP, vega */
+ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+ /* xscale IOP */
+ {}
};
MODULE_DEVICE_TABLE(pci, megasas_pci_table);
@@ -289,9 +279,14 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
* @regs: MFI register set
*/
static inline void
-megasas_disable_intr(struct megasas_register_set __iomem * regs)
+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 */
@@ -1260,7 +1255,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Bring it to READY state; assuming max wait 2 secs
*/
- megasas_disable_intr(instance->reg_set);
+ megasas_disable_intr(instance);
writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
max_wait = 10;
@@ -1757,6 +1752,11 @@ static int megasas_init_mfi(struct megasas_instance *instance)
init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
/*
+ * disable the intr before firing the init frame to FW
+ */
+ megasas_disable_intr(instance);
+
+ /*
* Issue the init frame in polled mode
*/
if (megasas_issue_polled(instance, cmd)) {
@@ -2191,7 +2191,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, SA_SHIRQ, "megasas", instance)) {
+ if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
goto fail_irq;
}
@@ -2234,7 +2234,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->reg_set);
+ megasas_disable_intr(instance);
free_irq(instance->pdev->irq, instance);
megasas_release_mfi(instance);
@@ -2364,7 +2364,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_set_drvdata(instance->pdev, NULL);
- megasas_disable_intr(instance->reg_set);
+ megasas_disable_intr(instance);
free_irq(instance->pdev->irq, instance);
@@ -2838,7 +2838,7 @@ static int __init megasas_init(void)
/*
* Register ourselves as PCI hotplug module
*/
- rval = pci_module_init(&megasas_pci_driver);
+ rval = pci_register_driver(&megasas_pci_driver);
if (rval) {
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 927d6ffef05..3531a14222a 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,16 @@
/**
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.02.04"
-#define MEGASAS_RELDATE "Feb 03, 2006"
-#define MEGASAS_EXT_VERSION "Fri Feb 03 14:31:44 PST 2006"
+#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"
+
+/*
+ * Device IDs
+ */
+#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060
+#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413
+
/*
* =====================================
* MegaRAID SAS MFI firmware definitions
@@ -554,7 +561,11 @@ struct megasas_ctrl_info {
#define MFI_POLL_TIMEOUT_SECS 10
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
-#define PCI_DEVICE_ID_LSI_SAS1078R 0x00000060
+
+/*
+* register set for both 1068 and 1078 controllers
+* structure extended for 1078 registers
+*/
struct megasas_register_set {
u32 reserved_0[4]; /*0000h*/
@@ -1150,10 +1161,10 @@ struct compat_megasas_iocpacket {
struct compat_iovec sgl[MAX_IOCTL_SGE];
} __attribute__ ((packed));
+#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket)
#endif
#define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket)
-#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket)
#define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen)
struct megasas_mgmt_info {
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index f852421002e..683fc7ae4b8 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -18,7 +18,6 @@
* - retry arbitration if lost (unless higher levels do this for us)
* - power down the chip when no device is detected
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -1269,7 +1268,7 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
if (cmd->use_sg > 0) {
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
@@ -1757,16 +1756,23 @@ static void set_mesh_power(struct mesh_state *ms, int state)
pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
msleep(10);
}
-}
+}
#ifdef CONFIG_PM
-static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
+static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
{
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (state.event == mdev->ofdev.dev.power.power_state.event || state.event < 2)
+ switch (mesg.event) {
+ case PM_EVENT_SUSPEND:
+ case PM_EVENT_FREEZE:
+ break;
+ default:
+ return 0;
+ }
+ if (mesg.event == mdev->ofdev.dev.power.power_state.event)
return 0;
scsi_block_requests(ms->host);
@@ -1781,7 +1787,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
disable_irq(ms->meshintr);
set_mesh_power(ms, 0);
- mdev->ofdev.dev.power.power_state = state;
+ mdev->ofdev.dev.power.power_state = mesg;
return 0;
}
@@ -1851,7 +1857,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mesh = macio_get_of_node(mdev);
struct pci_dev* pdev = macio_get_pci_dev(mdev);
- int tgt, *cfp, minper;
+ int tgt, minper;
+ const int *cfp;
struct mesh_state *ms;
struct Scsi_Host *mesh_host;
void *dma_cmd_space;
@@ -1940,7 +1947,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
ms->tgts[tgt].current_req = NULL;
}
- if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
+ if ((cfp = get_property(mesh, "clock-frequency", NULL)))
ms->clk_freq = *cfp;
else {
printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index cb367c2c5c7..9b991b746d1 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -29,7 +29,7 @@ static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned char flags = 0x01;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -57,7 +57,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
m147_pcc->dma_cntrl = 0;
@@ -112,7 +112,7 @@ int mvme147_detect(struct scsi_host_template *tpnt)
return 0;
}
-static int mvme147_bus_reset(Scsi_Cmnd *cmd)
+static int mvme147_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
index 2f56d69bd18..32aee85434d 100644
--- a/drivers/scsi/mvme147.h
+++ b/drivers/scsi/mvme147.h
@@ -12,10 +12,6 @@
int mvme147_detect(struct scsi_host_template *);
int mvme147_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 6ab035590ee..b28712df0b7 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -5118,8 +5118,7 @@ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp)
cp->host_status &= ~HS_SKIPMASK;
cp->start.schedule.l_paddr =
cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
- list_del(&cp->link_ccbq);
- list_add_tail(&cp->link_ccbq, &lp->skip_ccbq);
+ list_move_tail(&cp->link_ccbq, &lp->skip_ccbq);
if (cp->queued) {
--lp->queuedccbs;
}
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 0e4e46a0133..78818b6684f 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -53,10 +53,8 @@
#ifndef NCR53C8XX_H
#define NCR53C8XX_H
-#include <linux/config.h>
#include <scsi/scsi_host.h>
-#include <linux/config.h>
/*
** If you want a driver as small as possible, donnot define the
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 5c55e152e71..bfb4f49e125 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -2866,8 +2866,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
*/
nsp32_do_bus_reset(data);
- ret = request_irq(host->irq, do_nsp32_isr,
- SA_SHIRQ | SA_SAMPLE_RANDOM, "nsp32", data);
+ ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data);
if (ret < 0) {
nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 "
"SCSI PCI controller. Interrupt: %d", host->irq);
@@ -2886,12 +2885,19 @@ static int nsp32_detect(struct scsi_host_template *sht)
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- scsi_add_host (host, &PCIDEV->dev);
+ ret = scsi_add_host(host, &PCIDEV->dev);
+ if (ret) {
+ nsp32_msg(KERN_ERR, "failed to add scsi host");
+ goto free_region;
+ }
scsi_scan_host(host);
#endif
pci_set_drvdata(PCIDEV, host);
return DETECT_OK;
+ free_region:
+ release_region(host->io_port, host->n_io_port);
+
free_irq:
free_irq(host->irq, data);
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index dee426f8c07..dd67a68c5c2 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -6,7 +6,6 @@
* Based on cyber_esp.c
*/
-#include <linux/config.h>
#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS)
#define USE_BOTTOM_HALF
@@ -198,7 +197,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = (__u32) cmd_buffer;
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"BSC Oktagon SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/oktagon_io.S b/drivers/scsi/oktagon_io.S
index 08ce8d80d8f..8a7340b0270 100644
--- a/drivers/scsi/oktagon_io.S
+++ b/drivers/scsi/oktagon_io.S
@@ -23,7 +23,6 @@ int oktag_from_io(long *addr,long *paddr,long len)
* is moved to/from the IO register.
*/
-#include <linux/config.h>
#ifdef CONFIG_APUS
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 011d4d6ca9f..1e426f5d0ed 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -3,7 +3,6 @@
*/
#include <asm/byteorder.h>
-#include <linux/config.h>
#include <linux/completion.h>
/* FIXME - rename and use the following two types or delete them!
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 1bf96ed8f93..1434209a8ac 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -454,7 +454,7 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", instance)) {
+ if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED, "pas16", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 231f9c311c6..0d4c04e1f3d 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1623,7 +1623,7 @@ static int nsp_cs_probe(struct pcmcia_device *link)
/* Interrupt handler */
link->irq.Handler = &nspintr;
link->irq.Instance = info;
- link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM);
+ link->irq.Attributes |= IRQF_SHARED;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 9f59827707f..0b65099acb1 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -799,7 +799,7 @@ next_entry:
data = (struct sym53c500_data *)host->hostdata;
if (irq_level > 0) {
- if (request_irq(irq_level, SYM53C500_intr, SA_SHIRQ, "SYM53C500", host)) {
+ if (request_irq(irq_level, SYM53C500_intr, IRQF_SHARED, "SYM53C500", host)) {
printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);
goto err_free_scsi;
}
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
deleted file mode 100644
index 7ebe8e03aa9..00000000000
--- a/drivers/scsi/pdc_adma.c
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * pdc_adma.c - Pacific Digital Corporation ADMA
- *
- * Maintained by: Mark Lord <mlord@pobox.com>
- *
- * Copyright 2005 Mark Lord
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- *
- * Supports ATA disks in single-packet ADMA mode.
- * Uses PIO for everything else.
- *
- * TODO: Use ADMA transfers for ATAPI devices, when possible.
- * This requires careful attention to a number of quirks of the chip.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <asm/io.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "pdc_adma"
-#define DRV_VERSION "0.04"
-
-/* macro to calculate base address for ATA regs */
-#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
-
-/* macro to calculate base address for ADMA regs */
-#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
-
-enum {
- ADMA_PORTS = 2,
- ADMA_CPB_BYTES = 40,
- ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
- ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES,
-
- ADMA_DMA_BOUNDARY = 0xffffffff,
-
- /* global register offsets */
- ADMA_MODE_LOCK = 0x00c7,
-
- /* per-channel register offsets */
- ADMA_CONTROL = 0x0000, /* ADMA control */
- ADMA_STATUS = 0x0002, /* ADMA status */
- ADMA_CPB_COUNT = 0x0004, /* CPB count */
- ADMA_CPB_CURRENT = 0x000c, /* current CPB address */
- ADMA_CPB_NEXT = 0x000c, /* next CPB address */
- ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */
- ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */
- ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */
-
- /* ADMA_CONTROL register bits */
- aNIEN = (1 << 8), /* irq mask: 1==masked */
- aGO = (1 << 7), /* packet trigger ("Go!") */
- aRSTADM = (1 << 5), /* ADMA logic reset */
- aPIOMD4 = 0x0003, /* PIO mode 4 */
-
- /* ADMA_STATUS register bits */
- aPSD = (1 << 6),
- aUIRQ = (1 << 4),
- aPERR = (1 << 0),
-
- /* CPB bits */
- cDONE = (1 << 0),
- cVLD = (1 << 0),
- cDAT = (1 << 2),
- cIEN = (1 << 3),
-
- /* PRD bits */
- pORD = (1 << 4),
- pDIRO = (1 << 5),
- pEND = (1 << 7),
-
- /* ATA register flags */
- rIGN = (1 << 5),
- rEND = (1 << 7),
-
- /* ATA register addresses */
- ADMA_REGS_CONTROL = 0x0e,
- ADMA_REGS_SECTOR_COUNT = 0x12,
- ADMA_REGS_LBA_LOW = 0x13,
- ADMA_REGS_LBA_MID = 0x14,
- ADMA_REGS_LBA_HIGH = 0x15,
- ADMA_REGS_DEVICE = 0x16,
- ADMA_REGS_COMMAND = 0x17,
-
- /* PCI device IDs */
- board_1841_idx = 0, /* ADMA 2-port controller */
-};
-
-typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t;
-
-struct adma_port_priv {
- u8 *pkt;
- dma_addr_t pkt_dma;
- adma_state_t state;
-};
-
-static int adma_ata_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static irqreturn_t adma_intr (int irq, void *dev_instance,
- struct pt_regs *regs);
-static int adma_port_start(struct ata_port *ap);
-static void adma_host_stop(struct ata_host_set *host_set);
-static void adma_port_stop(struct ata_port *ap);
-static void adma_phy_reset(struct ata_port *ap);
-static void adma_qc_prep(struct ata_queued_cmd *qc);
-static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
-static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
-static void adma_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 adma_bmdma_status(struct ata_port *ap);
-static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
-
-static struct scsi_host_template adma_ata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ENABLE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ADMA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations adma_ata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .check_atapi_dma = adma_check_atapi_dma,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
- .phy_reset = adma_phy_reset,
- .qc_prep = adma_qc_prep,
- .qc_issue = adma_qc_issue,
- .eng_timeout = adma_eng_timeout,
- .data_xfer = ata_mmio_data_xfer,
- .irq_handler = adma_intr,
- .irq_clear = adma_irq_clear,
- .port_start = adma_port_start,
- .port_stop = adma_port_stop,
- .host_stop = adma_host_stop,
- .bmdma_stop = adma_bmdma_stop,
- .bmdma_status = adma_bmdma_status,
-};
-
-static struct ata_port_info adma_port_info[] = {
- /* board_1841_idx */
- {
- .sht = &adma_ata_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO,
- .pio_mask = 0x10, /* pio4 */
- .udma_mask = 0x1f, /* udma0-4 */
- .port_ops = &adma_ata_ops,
- },
-};
-
-static const struct pci_device_id adma_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_1841_idx },
-
- { } /* terminate list */
-};
-
-static struct pci_driver adma_ata_pci_driver = {
- .name = DRV_NAME,
- .id_table = adma_ata_pci_tbl,
- .probe = adma_ata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static int adma_check_atapi_dma(struct ata_queued_cmd *qc)
-{
- return 1; /* ATAPI DMA not yet supported */
-}
-
-static void adma_bmdma_stop(struct ata_queued_cmd *qc)
-{
- /* nothing */
-}
-
-static u8 adma_bmdma_status(struct ata_port *ap)
-{
- return 0;
-}
-
-static void adma_irq_clear(struct ata_port *ap)
-{
- /* nothing */
-}
-
-static void adma_reset_engine(void __iomem *chan)
-{
- /* reset ADMA to idle state */
- writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
- udelay(2);
- writew(aPIOMD4, chan + ADMA_CONTROL);
- udelay(2);
-}
-
-static void adma_reinit_engine(struct ata_port *ap)
-{
- struct adma_port_priv *pp = ap->private_data;
- void __iomem *mmio_base = ap->host_set->mmio_base;
- void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
-
- /* mask/clear ATA interrupts */
- writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
- ata_check_status(ap);
-
- /* reset the ADMA engine */
- adma_reset_engine(chan);
-
- /* set in-FIFO threshold to 0x100 */
- writew(0x100, chan + ADMA_FIFO_IN);
-
- /* set CPB pointer */
- writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT);
-
- /* set out-FIFO threshold to 0x100 */
- writew(0x100, chan + ADMA_FIFO_OUT);
-
- /* set CPB count */
- writew(1, chan + ADMA_CPB_COUNT);
-
- /* read/discard ADMA status */
- readb(chan + ADMA_STATUS);
-}
-
-static inline void adma_enter_reg_mode(struct ata_port *ap)
-{
- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
-
- writew(aPIOMD4, chan + ADMA_CONTROL);
- readb(chan + ADMA_STATUS); /* flush */
-}
-
-static void adma_phy_reset(struct ata_port *ap)
-{
- struct adma_port_priv *pp = ap->private_data;
-
- pp->state = adma_state_idle;
- adma_reinit_engine(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
-static void adma_eng_timeout(struct ata_port *ap)
-{
- struct adma_port_priv *pp = ap->private_data;
-
- if (pp->state != adma_state_idle) /* healthy paranoia */
- pp->state = adma_state_mmio;
- adma_reinit_engine(ap);
- ata_eng_timeout(ap);
-}
-
-static int adma_fill_sg(struct ata_queued_cmd *qc)
-{
- struct scatterlist *sg;
- struct ata_port *ap = qc->ap;
- struct adma_port_priv *pp = ap->private_data;
- u8 *buf = pp->pkt;
- int i = (2 + buf[3]) * 8;
- u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
-
- ata_for_each_sg(sg, qc) {
- u32 addr;
- u32 len;
-
- addr = (u32)sg_dma_address(sg);
- *(__le32 *)(buf + i) = cpu_to_le32(addr);
- i += 4;
-
- len = sg_dma_len(sg) >> 3;
- *(__le32 *)(buf + i) = cpu_to_le32(len);
- i += 4;
-
- if (ata_sg_is_last(sg, qc))
- pFLAGS |= pEND;
- buf[i++] = pFLAGS;
- buf[i++] = qc->dev->dma_mode & 0xf;
- buf[i++] = 0; /* pPKLW */
- buf[i++] = 0; /* reserved */
-
- *(__le32 *)(buf + i)
- = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
- i += 4;
-
- VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
- (unsigned long)addr, len);
- }
- return i;
-}
-
-static void adma_qc_prep(struct ata_queued_cmd *qc)
-{
- struct adma_port_priv *pp = qc->ap->private_data;
- u8 *buf = pp->pkt;
- u32 pkt_dma = (u32)pp->pkt_dma;
- int i = 0;
-
- VPRINTK("ENTER\n");
-
- adma_enter_reg_mode(qc->ap);
- if (qc->tf.protocol != ATA_PROT_DMA) {
- ata_qc_prep(qc);
- return;
- }
-
- buf[i++] = 0; /* Response flags */
- buf[i++] = 0; /* reserved */
- buf[i++] = cVLD | cDAT | cIEN;
- i++; /* cLEN, gets filled in below */
-
- *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */
- i += 4; /* cNCPB */
- i += 4; /* cPRD, gets filled in below */
-
- buf[i++] = 0; /* reserved */
- buf[i++] = 0; /* reserved */
- buf[i++] = 0; /* reserved */
- buf[i++] = 0; /* reserved */
-
- /* ATA registers; must be a multiple of 4 */
- buf[i++] = qc->tf.device;
- buf[i++] = ADMA_REGS_DEVICE;
- if ((qc->tf.flags & ATA_TFLAG_LBA48)) {
- buf[i++] = qc->tf.hob_nsect;
- buf[i++] = ADMA_REGS_SECTOR_COUNT;
- buf[i++] = qc->tf.hob_lbal;
- buf[i++] = ADMA_REGS_LBA_LOW;
- buf[i++] = qc->tf.hob_lbam;
- buf[i++] = ADMA_REGS_LBA_MID;
- buf[i++] = qc->tf.hob_lbah;
- buf[i++] = ADMA_REGS_LBA_HIGH;
- }
- buf[i++] = qc->tf.nsect;
- buf[i++] = ADMA_REGS_SECTOR_COUNT;
- buf[i++] = qc->tf.lbal;
- buf[i++] = ADMA_REGS_LBA_LOW;
- buf[i++] = qc->tf.lbam;
- buf[i++] = ADMA_REGS_LBA_MID;
- buf[i++] = qc->tf.lbah;
- buf[i++] = ADMA_REGS_LBA_HIGH;
- buf[i++] = 0;
- buf[i++] = ADMA_REGS_CONTROL;
- buf[i++] = rIGN;
- buf[i++] = 0;
- buf[i++] = qc->tf.command;
- buf[i++] = ADMA_REGS_COMMAND | rEND;
-
- buf[3] = (i >> 3) - 2; /* cLEN */
- *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */
-
- i = adma_fill_sg(qc);
- wmb(); /* flush PRDs and pkt to memory */
-#if 0
- /* dump out CPB + PRDs for debug */
- {
- int j, len = 0;
- static char obuf[2048];
- for (j = 0; j < i; ++j) {
- len += sprintf(obuf+len, "%02x ", buf[j]);
- if ((j & 7) == 7) {
- printk("%s\n", obuf);
- len = 0;
- }
- }
- if (len)
- printk("%s\n", obuf);
- }
-#endif
-}
-
-static inline void adma_packet_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
-
- VPRINTK("ENTER, ap %p\n", ap);
-
- /* fire up the ADMA engine */
- writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
-}
-
-static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
-{
- struct adma_port_priv *pp = qc->ap->private_data;
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- pp->state = adma_state_pkt;
- adma_packet_start(qc);
- return 0;
-
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
- default:
- break;
- }
-
- pp->state = adma_state_mmio;
- return ata_qc_issue_prot(qc);
-}
-
-static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
-{
- unsigned int handled = 0, port_no;
- u8 __iomem *mmio_base = host_set->mmio_base;
-
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
- struct ata_port *ap = host_set->ports[port_no];
- struct adma_port_priv *pp;
- struct ata_queued_cmd *qc;
- void __iomem *chan = ADMA_REGS(mmio_base, port_no);
- u8 status = readb(chan + ADMA_STATUS);
-
- if (status == 0)
- continue;
- handled = 1;
- adma_enter_reg_mode(ap);
- if (ap->flags & ATA_FLAG_DISABLED)
- continue;
- pp = ap->private_data;
- if (!pp || pp->state != adma_state_pkt)
- continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- if ((status & (aPERR | aPSD | aUIRQ)))
- qc->err_mask |= AC_ERR_OTHER;
- else if (pp->pkt[0] != cDONE)
- qc->err_mask |= AC_ERR_OTHER;
-
- ata_qc_complete(qc);
- }
- }
- return handled;
-}
-
-static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
-{
- unsigned int handled = 0, port_no;
-
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
- struct ata_port *ap;
- ap = host_set->ports[port_no];
- if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
- struct ata_queued_cmd *qc;
- struct adma_port_priv *pp = ap->private_data;
- if (!pp || pp->state != adma_state_mmio)
- continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-
- /* check main status, clearing INTRQ */
- u8 status = ata_check_status(ap);
- if ((status & ATA_BUSY))
- continue;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
-
- /* complete taskfile transaction */
- pp->state = adma_state_idle;
- qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
- handled = 1;
- }
- }
- }
- return handled;
-}
-
-static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int handled = 0;
-
- VPRINTK("ENTER\n");
-
- spin_lock(&host_set->lock);
- handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set);
- spin_unlock(&host_set->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr =
- port->data_addr = base + 0x000;
- port->error_addr =
- port->feature_addr = base + 0x004;
- port->nsect_addr = base + 0x008;
- port->lbal_addr = base + 0x00c;
- port->lbam_addr = base + 0x010;
- port->lbah_addr = base + 0x014;
- port->device_addr = base + 0x018;
- port->status_addr =
- port->command_addr = base + 0x01c;
- port->altstatus_addr =
- port->ctl_addr = base + 0x038;
-}
-
-static int adma_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct adma_port_priv *pp;
- int rc;
-
- rc = ata_port_start(ap);
- if (rc)
- return rc;
- adma_enter_reg_mode(ap);
- rc = -ENOMEM;
- pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
- if (!pp)
- goto err_out;
- pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
- if (!pp->pkt)
- goto err_out_kfree;
- /* paranoia? */
- if ((pp->pkt_dma & 7) != 0) {
- printk("bad alignment for pp->pkt_dma: %08x\n",
- (u32)pp->pkt_dma);
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- goto err_out_kfree;
- }
- memset(pp->pkt, 0, ADMA_PKT_BYTES);
- ap->private_data = pp;
- adma_reinit_engine(ap);
- return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-static void adma_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct adma_port_priv *pp = ap->private_data;
-
- adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no));
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
-}
-
-static void adma_host_stop(struct ata_host_set *host_set)
-{
- unsigned int port_no;
-
- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no));
-
- ata_pci_host_stop(host_set);
-}
-
-static void adma_host_init(unsigned int chip_id,
- struct ata_probe_ent *probe_ent)
-{
- unsigned int port_no;
- void __iomem *mmio_base = probe_ent->mmio_base;
-
- /* enable/lock aGO operation */
- writeb(7, mmio_base + ADMA_MODE_LOCK);
-
- /* reset the ADMA logic */
- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(mmio_base, port_no));
-}
-
-static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
-{
- int rc;
-
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- return rc;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
- return 0;
-}
-
-static int adma_ata_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int rc, port_no;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
-
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- rc = adma_set_dma_masks(pdev, mmio_base);
- if (rc)
- goto err_out_iounmap;
-
- probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = adma_port_info[board_idx].sht;
- probe_ent->host_flags = adma_port_info[board_idx].host_flags;
- probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
- probe_ent->port_ops = adma_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
- probe_ent->n_ports = ADMA_PORTS;
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- adma_ata_setup_port(&probe_ent->port[port_no],
- ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
- }
-
- pci_set_master(pdev);
-
- /* initialize adapter */
- adma_host_init(board_idx, probe_ent);
-
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != ADMA_PORTS)
- goto err_out_iounmap;
- return 0;
-
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
-}
-
-static int __init adma_ata_init(void)
-{
- return pci_module_init(&adma_ata_pci_driver);
-}
-
-static void __exit adma_ata_exit(void)
-{
- pci_unregister_driver(&adma_ata_pci_driver);
-}
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(adma_ata_init);
-module_exit(adma_ata_exit);
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 83a67179993..0bd9c60e645 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-#include <linux/config.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -170,8 +169,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->request->rq_status = RQ_SCSI_BUSY;
SCpnt->done = pluto_detect_done;
- SCpnt->bufflen = 256;
- SCpnt->buffer = fcs[i].inquiry;
SCpnt->request_bufflen = 256;
SCpnt->request_buffer = fcs[i].inquiry;
PLD(("set up %d %08lx\n", i, (long)SCpnt))
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 108910f512e..b0eba39f208 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -6,11 +6,8 @@
* (c) 1995,1996 Grant R. Guenther, grant@torque.net,
* under the terms of the GNU General Public License.
*
- * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
- * campbell@torque.net
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index f6e1a1574bb..7511df3588e 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -2,7 +2,7 @@
* the Iomega ZIP drive
*
* (c) 1996 Grant R. Guenther grant@torque.net
- * David Campbell campbell@torque.net
+ * David Campbell
*
* All comments to David.
*/
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 680f6063954..8953991462d 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -192,7 +192,7 @@
- Don't walk the entire list in qla1280_putq_t() just to directly
grab the pointer to the last element afterwards
Rev 3.23.5 Beta August 9, 2001, Jes Sorensen
- - Don't use SA_INTERRUPT, it's use is deprecated for this kinda driver
+ - Don't use IRQF_DISABLED, it's use is deprecated for this kinda driver
Rev 3.23.4 Beta August 8, 2001, Jes Sorensen
- Set dev->max_sectors to 1024
Rev 3.23.3 Beta August 6, 2001, Jes Sorensen
@@ -331,7 +331,6 @@
*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
@@ -4210,7 +4209,7 @@ qla1280_setup(char *s)
}
-static int
+static int __init
qla1280_get_token(char *str)
{
char *sep;
@@ -4370,7 +4369,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Disable ISP interrupts. */
qla1280_disable_intrs(ha);
- if (request_irq(pdev->irq, qla1280_intr_handler, SA_SHIRQ,
+ if (request_irq(pdev->irq, qla1280_intr_handler, IRQF_SHARED,
"qla1280", ha)) {
printk("qla1280 : Failed to reserve interrupt %d already "
"in use\n", pdev->irq);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index e96d58ded57..87f90c4f08e 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
+ char *rbuf = (char *)ha->fw_dump;
if (ha->fw_dump_reading == 0)
return 0;
- if (off > ha->fw_dump_buffer_len)
- return 0;
- if (off + count > ha->fw_dump_buffer_len)
- count = ha->fw_dump_buffer_len - off;
+ if (off > ha->fw_dump_len)
+ return 0;
+ if (off + count > ha->fw_dump_len)
+ count = ha->fw_dump_len - off;
- memcpy(buf, &ha->fw_dump_buffer[off], count);
+ memcpy(buf, &rbuf[off], count);
return (count);
}
@@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
int reading;
- uint32_t dump_size;
if (off != 0)
return (0);
@@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
reading = simple_strtol(buf, NULL, 10);
switch (reading) {
case 0:
- if (ha->fw_dump_reading == 1) {
- qla_printk(KERN_INFO, ha,
- "Firmware dump cleared on (%ld).\n", ha->host_no);
+ if (!ha->fw_dump_reading)
+ break;
- vfree(ha->fw_dump_buffer);
- ha->fw_dump_buffer = NULL;
- ha->fw_dump_reading = 0;
- ha->fw_dumped = 0;
- }
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump cleared on (%ld).\n", ha->host_no);
+
+ ha->fw_dump_reading = 0;
+ ha->fw_dumped = 0;
break;
case 1:
if (ha->fw_dumped && !ha->fw_dump_reading) {
ha->fw_dump_reading = 1;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
- dump_size = FW_DUMP_SIZE_24XX;
- else {
- dump_size = FW_DUMP_SIZE_1M;
- if (ha->fw_memory_size < 0x20000)
- dump_size = FW_DUMP_SIZE_128K;
- else if (ha->fw_memory_size < 0x80000)
- dump_size = FW_DUMP_SIZE_512K;
- }
- ha->fw_dump_buffer = (char *)vmalloc(dump_size);
- if (ha->fw_dump_buffer == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Unable to allocate memory for firmware "
- "dump buffer (%d).\n", dump_size);
-
- ha->fw_dump_reading = 0;
- return (count);
- }
qla_printk(KERN_INFO, ha,
- "Firmware dump ready for read on (%ld).\n",
+ "Raw firmware dump ready for read on (%ld).\n",
ha->host_no);
- memset(ha->fw_dump_buffer, 0, dump_size);
- ha->isp_ops.ascii_fw_dump(ha);
- ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
}
break;
+ case 2:
+ qla2x00_alloc_fw_dump(ha);
+ break;
}
return (count);
}
@@ -313,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
if (!capable(CAP_SYS_ADMIN) || off != 0)
return 0;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
- return -ENOTSUPP;
-
/* Read NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
@@ -335,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)
return 0;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
- return -ENOTSUPP;
-
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
@@ -357,6 +332,53 @@ static struct bin_attribute sysfs_vpd_attr = {
.write = qla2x00_sysfs_write_vpd,
};
+static ssize_t
+qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ uint16_t iter, addr, offset;
+ int rval;
+
+ if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
+ return 0;
+
+ addr = 0xa0;
+ for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
+ iter++, offset += SFP_BLOCK_SIZE) {
+ if (iter == 4) {
+ /* Skip to next device address. */
+ addr = 0xa2;
+ offset = 0;
+ }
+
+ rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset,
+ SFP_BLOCK_SIZE);
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to read SFP data (%x/%x/%x).\n", rval,
+ addr, offset);
+ count = 0;
+ break;
+ }
+ memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE);
+ buf += SFP_BLOCK_SIZE;
+ }
+
+ return count;
+}
+
+static struct bin_attribute sysfs_sfp_attr = {
+ .attr = {
+ .name = "sfp",
+ .mode = S_IRUSR | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = SFP_DEV_SIZE * 2,
+ .read = qla2x00_sysfs_read_sfp,
+};
+
void
qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
{
@@ -367,7 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
sysfs_create_bin_file(&host->shost_gendev.kobj,
&sysfs_optrom_ctl_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_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);
+ }
}
void
@@ -380,7 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
sysfs_remove_bin_file(&host->shost_gendev.kobj,
&sysfs_optrom_ctl_attr);
- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_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);
+ }
if (ha->beacon_blink_led == 1)
ha->isp_ops.beacon_off(ha);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 74e54713aa7..f6ed6962bc2 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -8,7 +8,34 @@
#include <linux/delay.h>
-static int qla_uprintf(char **, char *, ...);
+static inline void
+qla2xxx_prep_dump(scsi_qla_host_t *ha, struct qla2xxx_fw_dump *fw_dump)
+{
+ fw_dump->fw_major_version = htonl(ha->fw_major_version);
+ fw_dump->fw_minor_version = htonl(ha->fw_minor_version);
+ fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version);
+ fw_dump->fw_attributes = htonl(ha->fw_attributes);
+
+ fw_dump->vendor = htonl(ha->pdev->vendor);
+ fw_dump->device = htonl(ha->pdev->device);
+ fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor);
+ fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device);
+}
+
+static inline void *
+qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
+{
+ /* Request queue. */
+ memcpy(ptr, ha->request_ring, ha->request_q_length *
+ sizeof(request_t));
+
+ /* Response queue. */
+ ptr += ha->request_q_length * sizeof(request_t);
+ memcpy(ptr, ha->response_ring, ha->response_q_length *
+ sizeof(response_t));
+
+ return ptr + (ha->response_q_length * sizeof(response_t));
+}
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
@@ -49,10 +76,11 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla2300_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp23;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->hccr = RD_REG_WORD(&reg->hccr);
+ fw->hccr = htons(RD_REG_WORD(&reg->hccr));
/* Pause RISC. */
WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
@@ -73,85 +101,86 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = (uint16_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
- fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++)
- fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x50);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2200);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2400);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2600);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2800);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2A00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2C00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2E00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x10);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->frame_buf_hdw_reg[cnt] =
+ htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x20);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x30);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
/* Reset RISC. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -226,7 +255,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->risc_ram[cnt] = mb2;
+ fw->risc_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -285,7 +314,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->stack_ram[cnt] = mb2;
+ fw->stack_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -345,12 +374,15 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->data_ram[cnt] = mb2;
+ fw->data_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS)
+ qla2xxx_copy_queues(ha, &fw->data_ram[cnt]);
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -369,193 +401,6 @@ qla2300_fw_dump_failed:
}
/**
- * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
- * @ha: HA context
- */
-void
-qla2300_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- char fw_info[30];
- struct qla2300_fw_dump *fw;
- uint32_t data_ram_cnt;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
- ha->isp_ops.fw_version_str(ha, fw_info));
-
- qla_uprintf(&uiter, "\n[==>BEG]\n");
-
- qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
-
- qla_uprintf(&uiter, "PBIU Registers:");
- for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers:");
- for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nDMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCode RAM Dump:");
- for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800);
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nStack RAM Dump:");
- for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000);
- }
- qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nData RAM Dump:");
- data_ram_cnt = ha->fw_memory_size - 0x11000 + 1;
- for (cnt = 0; cnt < data_ram_cnt; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000);
- }
- qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
-}
-
-/**
* qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware.
* @ha: HA context
* @hardware_locked: Called with the hardware_lock
@@ -591,10 +436,11 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla2100_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp21;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->hccr = RD_REG_WORD(&reg->hccr);
+ fw->hccr = htons(RD_REG_WORD(&reg->hccr));
/* Pause RISC. */
WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
@@ -608,79 +454,81 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = (uint16_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
if (cnt == 8) {
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0);
+ dmp_reg = (uint16_t __iomem *)
+ ((uint8_t __iomem *)reg + 0xe0);
}
- fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
}
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2100);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2200);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2300);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2400);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2500);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2600);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2700);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x10);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->frame_buf_hdw_reg[cnt] =
+ htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x20);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x30);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
/* Reset the ISP. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -755,12 +603,15 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->risc_ram[cnt] = mb2;
+ fw->risc_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS)
+ qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]);
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -778,179 +629,6 @@ qla2100_fw_dump_failed:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-/**
- * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
- * @ha: HA context
- */
-void
-qla2100_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- char fw_info[30];
- struct qla2100_fw_dump *fw;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
- ha->isp_ops.fw_version_str(ha, fw_info));
-
- qla_uprintf(&uiter, "\n[==>BEG]\n");
-
- qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
-
- qla_uprintf(&uiter, "PBIU Registers:");
- for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers:");
- for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nDMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC SRAM:");
- for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000);
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
-
- return;
-}
-
-static int
-qla_uprintf(char **uiter, char *fmt, ...)
-{
- int iter, len;
- char buf[128];
- va_list args;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- for (iter = 0; iter < len; iter++, *uiter += 1)
- *uiter[0] = buf[iter];
-
- return (len);
-}
-
-
void
qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
{
@@ -967,6 +645,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
unsigned long flags;
struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt;
+ void *eft;
risc_address = ext_mem_cnt = 0;
memset(mb, 0, sizeof(mb));
@@ -987,10 +666,11 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla24xx_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp24;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->host_status = RD_REG_DWORD(&reg->host_status);
+ fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
@@ -1012,7 +692,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Host interface registers. */
dmp_reg = (uint32_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1024,470 +704,471 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0000000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0100000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0200000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0300000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0400000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0500000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0600000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg));
/* Mailbox registers. */
mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = RD_REG_WORD(mbx_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
- fw->xseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Receive sequence registers. */
iter_reg = fw->rseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
- fw->rseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Command DMA registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Queues. */
iter_reg = fw->req0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->resp0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->req1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt2_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt3_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt4_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xmt_data_dma_reg[cnt] =
+ htonl(RD_REG_DWORD(dmp_reg++));
/* Receive DMA registers. */
iter_reg = fw->rcvt0_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->rcvt1_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* RISC registers. */
iter_reg = fw->risc_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Local memory controller registers. */
iter_reg = fw->lmc_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Fibre Protocol Module registers. */
iter_reg = fw->fpm_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Frame Buffer registers. */
iter_reg = fw->fb_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Reset RISC. */
WRT_REG_DWORD(&reg->ctrl_status,
@@ -1577,7 +1258,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb[0] & MBS_MASK;
- fw->code_ram[cnt] = (mb[3] << 16) | mb[2];
+ fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -1627,12 +1308,18 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb[0] & MBS_MASK;
- fw->ext_mem[cnt] = (mb[3] << 16) | mb[2];
+ fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS) {
+ eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]);
+ if (ha->eft)
+ memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size));
+ }
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -1650,252 +1337,6 @@ qla24xx_fw_dump_failed:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-void
-qla24xx_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- struct qla24xx_fw_dump *fw;
- uint32_t ext_mem_cnt;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "ISP FW Version %d.%02d.%02d Attributes %04x\n",
- ha->fw_major_version, ha->fw_minor_version,
- ha->fw_subminor_version, ha->fw_attributes);
-
- qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status);
-
- qla_uprintf(&uiter, "\nHost Interface Registers");
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nShadow Registers");
- for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers");
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ GP Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ-0 Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ-1 Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ GP Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-0 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-1 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-2 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCommand DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->cmd_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRequest0 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->req0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->req0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nResponse0 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->resp0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->resp0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRequest1 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->req1_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->req1_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT0 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT1 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt1_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt1_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT2 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt2_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt2_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT3 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt3_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt3_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT4 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt4_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt4_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT Data DMA Common Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRCV Thread 0 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->rcvt0_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRCV Thread 1 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->rcvt1_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP Registers");
- for (cnt = 0; cnt < sizeof(fw->risc_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nLMC Registers");
- for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->lmc_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM Hardware Registers");
- for (cnt = 0; cnt < sizeof(fw->fpm_hdw_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->fpm_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFB Hardware Registers");
- for (cnt = 0; cnt < sizeof(fw->fb_hdw_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->fb_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCode RAM");
- for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%08x: ", cnt + 0x20000);
- }
- qla_uprintf(&uiter, "%08x ", fw->code_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nExternal Memory");
- ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
- for (cnt = 0; cnt < ext_mem_cnt; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%08x: ", cnt + 0x100000);
- }
- qla_uprintf(&uiter, "%08x ", fw->ext_mem[cnt]);
- }
-
- qla_uprintf(&uiter, "\n[<==END] ISP Debug Dump");
-}
-
-
/****************************************************************************/
/* Driver Debug Functions. */
/****************************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index ab6afeaa2f2..533425338e0 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -37,134 +37,86 @@
/*
* Macros use for debugging the driver.
*/
-#undef ENTER_TRACE
-#if defined(ENTER_TRACE)
-#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
-#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
-#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
-#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
-#else
-#define ENTER(x) do {} while (0)
-#define LEAVE(x) do {} while (0)
-#define ENTER_INTR(x) do {} while (0)
-#define LEAVE_INTR(x) do {} while (0)
-#endif
-#if DEBUG_QLA2100
-#define DEBUG(x) do {x;} while (0);
-#else
-#define DEBUG(x) do {} while (0);
-#endif
+#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_1)
-#define DEBUG1(x) do {x;} while (0);
+#define DEBUG1(x) do {x;} while (0)
#else
-#define DEBUG1(x) do {} while (0);
+#define DEBUG1(x) do {} while (0)
#endif
-#if defined(QL_DEBUG_LEVEL_2)
-#define DEBUG2(x) do {x;} while (0);
-#define DEBUG2_3(x) do {x;} while (0);
-#define DEBUG2_3_11(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
-#define DEBUG2_11(x) do {x;} while (0);
-#define DEBUG2_13(x) do {x;} while (0);
-#else
-#define DEBUG2(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)
#if defined(QL_DEBUG_LEVEL_3)
-#define DEBUG3(x) do {x;} while (0);
-#define DEBUG2_3(x) do {x;} while (0);
-#define DEBUG2_3_11(x) do {x;} while (0);
-#define DEBUG3_11(x) do {x;} while (0);
+#define DEBUG3(x) do {x;} while (0)
+#define DEBUG3_11(x) do {x;} while (0)
#else
-#define DEBUG3(x) do {} while (0);
- #if !defined(QL_DEBUG_LEVEL_2)
- #define DEBUG2_3(x) do {} while (0);
- #endif
+#define DEBUG3(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_4)
-#define DEBUG4(x) do {x;} while (0);
+#define DEBUG4(x) do {x;} while (0)
#else
-#define DEBUG4(x) do {} while (0);
+#define DEBUG4(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_5)
-#define DEBUG5(x) do {x;} while (0);
+#define DEBUG5(x) do {x;} while (0)
#else
-#define DEBUG5(x) do {} while (0);
+#define DEBUG5(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_7)
-#define DEBUG7(x) do {x;} while (0);
+#define DEBUG7(x) do {x;} while (0)
#else
-#define DEBUG7(x) do {} while (0);
+#define DEBUG7(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_9)
-#define DEBUG9(x) do {x;} while (0);
-#define DEBUG9_10(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
+#define DEBUG9(x) do {x;} while (0)
+#define DEBUG9_10(x) do {x;} while (0)
#else
-#define DEBUG9(x) do {} while (0);
+#define DEBUG9(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_10)
-#define DEBUG10(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
-#define DEBUG9_10(x) do {x;} while (0);
+#define DEBUG10(x) do {x;} while (0)
+#define DEBUG9_10(x) do {x;} while (0)
#else
-#define DEBUG10(x) do {} while (0);
- #if !defined(DEBUG2_9_10)
- #define DEBUG2_9_10(x) do {} while (0);
- #endif
+#define DEBUG10(x) do {} while (0)
#if !defined(DEBUG9_10)
- #define DEBUG9_10(x) do {} while (0);
+ #define DEBUG9_10(x) do {} while (0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_11)
-#define DEBUG11(x) do{x;} while(0);
-#if !defined(DEBUG2_11)
-#define DEBUG2_11(x) do{x;} while(0);
-#endif
-#if !defined(DEBUG2_3_11)
-#define DEBUG2_3_11(x) do{x;} while(0);
-#endif
+#define DEBUG11(x) do{x;} while(0)
#if !defined(DEBUG3_11)
-#define DEBUG3_11(x) do{x;} while(0);
+#define DEBUG3_11(x) do{x;} while(0)
#endif
#else
-#define DEBUG11(x) do{} while(0);
- #if !defined(QL_DEBUG_LEVEL_2)
- #define DEBUG2_11(x) do{} while(0);
- #if !defined(QL_DEBUG_LEVEL_3)
- #define DEBUG2_3_11(x) do{} while(0);
- #endif
- #endif
+#define DEBUG11(x) do{} while(0)
#if !defined(QL_DEBUG_LEVEL_3)
- #define DEBUG3_11(x) do{} while(0);
+ #define DEBUG3_11(x) do{} while(0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_12)
-#define DEBUG12(x) do {x;} while (0);
+#define DEBUG12(x) do {x;} while (0)
#else
-#define DEBUG12(x) do {} while (0);
+#define DEBUG12(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_13)
#define DEBUG13(x) do {x;} while (0)
-#if !defined(DEBUG2_13)
-#define DEBUG2_13(x) do {x;} while(0)
-#endif
#else
#define DEBUG13(x) do {} while (0)
-#if !defined(QL_DEBUG_LEVEL_2)
-#define DEBUG2_13(x) do {} while(0)
-#endif
#endif
#if defined(QL_DEBUG_LEVEL_14)
@@ -176,9 +128,6 @@
/*
* Firmware Dump structure definition
*/
-#define FW_DUMP_SIZE_128K 0xBC000
-#define FW_DUMP_SIZE_512K 0x2FC000
-#define FW_DUMP_SIZE_1M 0x5FC000
struct qla2300_fw_dump {
uint16_t hccr;
@@ -224,8 +173,6 @@ struct qla2100_fw_dump {
uint16_t risc_ram[0xf000];
};
-#define FW_DUMP_SIZE_24XX 0x2B0000
-
struct qla24xx_fw_dump {
uint32_t host_status;
uint32_t host_reg[32];
@@ -257,3 +204,39 @@ struct qla24xx_fw_dump {
uint32_t code_ram[0x2000];
uint32_t ext_mem[1];
};
+
+#define EFT_NUM_BUFFERS 4
+#define EFT_BYTES_PER_BUFFER 0x4000
+#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
+
+struct qla2xxx_fw_dump {
+ uint8_t signature[4];
+ uint32_t version;
+
+ uint32_t fw_major_version;
+ uint32_t fw_minor_version;
+ uint32_t fw_subminor_version;
+ uint32_t fw_attributes;
+
+ uint32_t vendor;
+ uint32_t device;
+ uint32_t subsystem_vendor;
+ uint32_t subsystem_device;
+
+ uint32_t fixed_size;
+ uint32_t mem_size;
+ uint32_t req_q_size;
+ uint32_t rsp_q_size;
+
+ uint32_t eft_size;
+ uint32_t eft_addr_l;
+ uint32_t eft_addr_h;
+
+ uint32_t header_size;
+
+ union {
+ struct qla2100_fw_dump isp21;
+ struct qla2300_fw_dump isp23;
+ struct qla24xx_fw_dump isp24;
+ } isp;
+};
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index d6f6579cfd2..0930260aec2 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -487,6 +487,7 @@ typedef struct {
#define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */
#define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */
/* used. */
+#define MBA_TRACE_NOTIFICATION 0x8028 /* Trace/Diagnostic notification. */
#define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */
#define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */
#define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */
@@ -608,7 +609,9 @@ typedef struct {
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
#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. */
+#define MBC_READ_SFP 0x31 /* Read SFP Data. */
#define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */
#define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */
#define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */
@@ -618,6 +621,9 @@ typedef struct {
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
+#define TC_ENABLE 4
+#define TC_DISABLE 5
+
/* Firmware return data sizes */
#define FCAL_MAP_SIZE 128
@@ -1997,7 +2003,6 @@ struct isp_operations {
uint32_t);
void (*fw_dump) (struct scsi_qla_host *, int);
- void (*ascii_fw_dump) (struct scsi_qla_host *);
int (*beacon_on) (struct scsi_qla_host *);
int (*beacon_off) (struct scsi_qla_host *);
@@ -2041,6 +2046,7 @@ typedef struct scsi_qla_host {
uint32_t enable_led_scheme :1;
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
+ uint32_t disable_serdes :1;
} flags;
atomic_t loop_state;
@@ -2134,7 +2140,7 @@ typedef struct scsi_qla_host {
mempool_t *srb_mempool;
/* This spinlock is used to protect "io transactions", you must
- * aquire it before doing any IO to the card, eg with RD_REG*() and
+ * acquire it before doing any IO to the card, eg with RD_REG*() and
* WRT_REG*() for the duration of your entire commandtransaction.
*
* This spinlock is of lower priority than the io request lock.
@@ -2238,6 +2244,11 @@ typedef struct scsi_qla_host {
struct sns_cmd_pkt *sns_cmd;
dma_addr_t sns_cmd_dma;
+#define SFP_DEV_SIZE 256
+#define SFP_BLOCK_SIZE 64
+ void *sfp_data;
+ dma_addr_t sfp_data_dma;
+
struct task_struct *dpc_thread;
uint8_t dpc_active; /* DPC routine is active */
@@ -2303,11 +2314,12 @@ typedef struct scsi_qla_host {
uint16_t fw_seriallink_options24[4];
/* Firmware dump information. */
- void *fw_dump;
+ struct qla2xxx_fw_dump *fw_dump;
+ uint32_t fw_dump_len;
int fw_dumped;
int fw_dump_reading;
- char *fw_dump_buffer;
- int fw_dump_buffer_len;
+ dma_addr_t eft_dma;
+ void *eft;
uint8_t host_str[16];
uint32_t pci_attr;
diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h
index a8fc0ffc7fc..dd435410dfa 100644
--- a/drivers/scsi/qla2xxx/qla_devtbl.h
+++ b/drivers/scsi/qla2xxx/qla_devtbl.h
@@ -1,4 +1,4 @@
-#define QLA_MODEL_NAMES 0x4A
+#define QLA_MODEL_NAMES 0x57
/*
* Adapter model names and descriptions.
@@ -76,6 +76,19 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
"QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */
"QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */
"QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */
- " ", " ", /* 0x148 */
+ "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */
"QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */
+ " ", " ", /* 0x14a */
+ " ", " ", /* 0x14b */
+ "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */
+ "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */
+ "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */
+ " ", " ", /* 0x14f */
+ " ", " ", /* 0x150 */
+ " ", " ", /* 0x151 */
+ "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */
+ "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */
+ " ", " ", /* 0x154 */
+ "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */
+ "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */
};
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 3af478663be..a0a722cf423 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -141,7 +141,7 @@ struct nvram_24xx {
* BIT 2 = Enable Memory Map BIOS
* BIT 3 = Enable Selectable Boot
* BIT 4 = Disable RISC code load
- * BIT 5 =
+ * BIT 5 = Disable Serdes
* BIT 6 =
* BIT 7 =
*
@@ -278,7 +278,7 @@ struct init_cb_24xx {
uint16_t response_q_length;
uint16_t request_q_length;
- uint16_t link_down_timeout; /* Milliseconds. */
+ uint16_t link_down_on_nos; /* Milliseconds. */
uint16_t prio_request_q_length;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 164d53ccbfd..8311ac2b93a 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -31,13 +31,9 @@ extern void qla2x00_update_fw_options(struct scsi_qla_host *);
extern void qla24xx_update_fw_options(scsi_qla_host_t *);
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
-extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *);
-
-extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t);
extern int qla2x00_loop_resync(scsi_qla_host_t *);
-extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
@@ -51,6 +47,8 @@ extern int qla2x00_abort_isp(scsi_qla_host_t *);
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 *);
+
/*
* Global Data in qla_os.c source file.
*/
@@ -61,6 +59,8 @@ extern int qlport_down_retry;
extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
+extern int ql2xallocfwdump;
+extern int extended_error_logging;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -80,8 +80,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_iocb.c source file.
*/
-extern void qla2x00_isp_cmd(scsi_qla_host_t *);
-
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
@@ -204,6 +202,12 @@ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
qla2x00_stop_firmware(scsi_qla_host_t *);
+extern int
+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);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -254,9 +258,6 @@ extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
-extern void qla2100_ascii_fw_dump(scsi_qla_host_t *);
-extern void qla2300_ascii_fw_dump(scsi_qla_host_t *);
-extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *);
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
@@ -280,13 +281,6 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
/*
- * Global Function Prototypes in qla_xioctl.c source file.
- */
-#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0)
-#define qla2x00_alloc_ioctl_mem(ha) (0)
-#define qla2x00_free_ioctl_mem(ha) do { } while (0)
-
-/*
* Global Function Prototypes in qla_attr.c source file.
*/
struct class_device_attribute;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index aef093db597..859649160ca 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -39,6 +39,8 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
static int qla2x00_restart_isp(scsi_qla_host_t *);
+static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev);
+
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@@ -89,6 +91,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
ha->isp_ops.nvram_config(ha);
+ if (ha->flags.disable_serdes) {
+ /* Mask HBA via NVRAM settings? */
+ qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
+ "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
+ ha->port_name[0], ha->port_name[1],
+ ha->port_name[2], ha->port_name[3],
+ ha->port_name[4], ha->port_name[5],
+ ha->port_name[6], ha->port_name[7]);
+ return QLA_FUNCTION_FAILED;
+ }
+
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
retry = 10;
@@ -770,29 +783,104 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
return rval;
}
-static void
+void
qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
{
- uint32_t dump_size = 0;
+ int rval;
+ uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
+ eft_size;
+ dma_addr_t eft_dma;
+ void *eft;
+
+ if (ha->fw_dump) {
+ qla_printk(KERN_WARNING, ha,
+ "Firmware dump previously allocated.\n");
+ return;
+ }
ha->fw_dumped = 0;
+ fixed_size = mem_size = eft_size = 0;
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
- dump_size = sizeof(struct qla2100_fw_dump);
+ fixed_size = sizeof(struct qla2100_fw_dump);
} else if (IS_QLA23XX(ha)) {
- dump_size = sizeof(struct qla2300_fw_dump);
- dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t);
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- dump_size = sizeof(struct qla24xx_fw_dump);
- dump_size += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t);
+ fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
+ mem_size = (ha->fw_memory_size - 0x11000 + 1) *
+ sizeof(uint16_t);
+ } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+ mem_size = (ha->fw_memory_size - 0x100000 + 1) *
+ sizeof(uint32_t);
+
+ /* Allocate memory for Extended Trace Buffer. */
+ eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
+ GFP_KERNEL);
+ if (!eft) {
+ qla_printk(KERN_WARNING, ha, "Unable to allocate "
+ "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+ goto cont_alloc;
+ }
+
+ rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
+ EFT_NUM_BUFFERS);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha, "Unable to initialize "
+ "EFT (%d).\n", rval);
+ dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
+ eft_dma);
+ goto cont_alloc;
+ }
+
+ qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
+ EFT_SIZE / 1024);
+
+ eft_size = EFT_SIZE;
+ memset(eft, 0, eft_size);
+ ha->eft_dma = eft_dma;
+ ha->eft = eft;
}
+cont_alloc:
+ req_q_size = ha->request_q_length * sizeof(request_t);
+ rsp_q_size = ha->response_q_length * sizeof(response_t);
+
+ dump_size = offsetof(struct qla2xxx_fw_dump, isp);
+ dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
+ eft_size;
ha->fw_dump = vmalloc(dump_size);
- if (ha->fw_dump)
- qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware "
- "dump...\n", dump_size / 1024);
- else
+ if (!ha->fw_dump) {
qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
"firmware dump!!!\n", dump_size / 1024);
+
+ if (ha->eft) {
+ dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
+ ha->eft_dma);
+ ha->eft = NULL;
+ ha->eft_dma = 0;
+ }
+ return;
+ }
+
+ qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
+ dump_size / 1024);
+
+ ha->fw_dump_len = dump_size;
+ ha->fw_dump->signature[0] = 'Q';
+ ha->fw_dump->signature[1] = 'L';
+ ha->fw_dump->signature[2] = 'G';
+ ha->fw_dump->signature[3] = 'C';
+ ha->fw_dump->version = __constant_htonl(1);
+
+ ha->fw_dump->fixed_size = htonl(fixed_size);
+ ha->fw_dump->mem_size = htonl(mem_size);
+ ha->fw_dump->req_q_size = htonl(req_q_size);
+ ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
+
+ ha->fw_dump->eft_size = htonl(eft_size);
+ ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
+ ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
+
+ ha->fw_dump->header_size =
+ htonl(offsetof(struct qla2xxx_fw_dump, isp));
}
/**
@@ -810,8 +898,6 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
dma_addr_t request_dma;
request_t *request_ring;
- qla2x00_alloc_fw_dump(ha);
-
/* Valid only on recent ISPs. */
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return;
@@ -883,6 +969,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
&ha->fw_subminor_version,
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
+
+ if (ql2xallocfwdump)
+ qla2x00_alloc_fw_dump(ha);
}
} else {
DEBUG2(printk(KERN_INFO
@@ -1186,8 +1275,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
rval = QLA_FUNCTION_FAILED;
if (atomic_read(&ha->loop_down_timer) &&
- (fw_state >= FSTATE_LOSS_OF_SYNC ||
- fw_state == FSTATE_WAIT_AL_PA)) {
+ fw_state != FSTATE_READY) {
/* Loop down. Timeout on min_wait for states
* other than Wait for Login.
*/
@@ -1555,6 +1643,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
/*
* Set host adapter parameters.
*/
+ if (nv->host_p[0] & BIT_7)
+ extended_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))
@@ -1563,6 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
+ ha->flags.disable_serdes = 0;
ha->operating_mode =
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -1701,7 +1792,7 @@ qla2x00_rport_del(void *data)
*
* Returns a pointer to the allocated fcport, or NULL, if none available.
*/
-fc_port_t *
+static fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
{
fc_port_t *fcport;
@@ -2258,8 +2349,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
}
/* Remove device from the new list and add it to DB */
- list_del(&fcport->list);
- list_add_tail(&fcport->list, &ha->fcports);
+ list_move_tail(&fcport->list, &ha->fcports);
/* Login and update database */
qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
@@ -2498,7 +2588,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
* Context:
* Kernel context.
*/
-int
+static int
qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
{
int rval;
@@ -2973,6 +3063,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
int
qla2x00_abort_isp(scsi_qla_host_t *ha)
{
+ int rval;
unsigned long flags = 0;
uint16_t cnt;
srb_t *sp;
@@ -3029,6 +3120,16 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+
+ if (ha->eft) {
+ rval = qla2x00_trace_control(ha, TC_ENABLE,
+ ha->eft_dma, EFT_NUM_BUFFERS);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to reinitialize EFT "
+ "(%d).\n", rval);
+ }
+ }
} else { /* failed the ISP abort */
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
@@ -3049,14 +3150,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_abort_cnt--;
DEBUG(printk("qla%ld: ISP abort - "
"retry remaining %d\n",
- ha->host_no, ha->isp_abort_cnt);)
+ ha->host_no, ha->isp_abort_cnt));
status = 1;
}
} else {
ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
DEBUG(printk("qla2x00(%ld): ISP error recovery "
"- retrying (%d) more times\n",
- ha->host_no, ha->isp_abort_cnt);)
+ ha->host_no, ha->isp_abort_cnt));
set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
status = 1;
}
@@ -3070,7 +3171,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
} else {
DEBUG(printk(KERN_INFO
"qla2x00_abort_isp(%ld): exiting.\n",
- ha->host_no);)
+ ha->host_no));
}
return(status);
@@ -3146,7 +3247,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
if (!(status = qla2x00_fw_ready(ha))) {
DEBUG(printk("%s(): Start configure loop, "
- "status = %d\n", __func__, status);)
+ "status = %d\n", __func__, status));
/* Issue a marker after FW becomes ready. */
qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
@@ -3170,7 +3271,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
__func__,
- status);)
+ status));
}
return (status);
}
@@ -3290,7 +3391,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
nv->node_name[6] = 0x55;
nv->node_name[7] = 0x86;
nv->login_retry_count = __constant_cpu_to_le16(8);
- nv->link_down_timeout = __constant_cpu_to_le16(200);
nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
nv->login_timeout = __constant_cpu_to_le16(0);
nv->firmware_options_1 =
@@ -3319,7 +3419,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
*dptr1++ = *dptr2++;
icb->login_retry_count = nv->login_retry_count;
- icb->link_down_timeout = nv->link_down_timeout;
+ icb->link_down_on_nos = nv->link_down_on_nos;
/* Copy 2nd segment. */
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
@@ -3374,6 +3474,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->flags.enable_lip_full_login = 1;
ha->flags.enable_target_reset = 1;
ha->flags.enable_led_scheme = 0;
+ ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -3473,7 +3574,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
return (rval);
}
-int
+static int
qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
{
int rval;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 8c769cfaa14..c5b3c610a32 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -15,6 +15,7 @@ static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
+static void qla2x00_isp_cmd(scsi_qla_host_t *ha);
/**
* qla2x00_get_cmd_direction() - Determine control_flag data direction.
@@ -470,6 +471,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
+ host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
@@ -574,7 +576,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
*
* Note: The caller must hold the hardware lock before calling this routine.
*/
-void
+static void
qla2x00_isp_cmd(scsi_qla_host_t *ha)
{
device_reg_t __iomem *reg = ha->iobase;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b28ac0a27e2..de0613135f7 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -395,10 +395,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL);
-
break;
case MBA_LOOP_UP: /* Loop Up Event */
@@ -418,9 +414,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
link_speed);
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL);
break;
case MBA_LOOP_DOWN: /* Loop Down Event */
@@ -439,9 +432,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->link_data_rate = LDR_UNKNOWN;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);
break;
case MBA_LIP_RESET: /* LIP reset occurred */
@@ -460,10 +450,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->operating_mode = LOOP;
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL);
-
break;
case MBA_POINT_TO_POINT: /* Point-to-Point */
@@ -545,9 +531,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL);
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
@@ -584,9 +567,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(RSCN_UPDATE, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]);
break;
/* case MBA_RIO_RESPONSE: */
@@ -607,6 +587,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
"%04x.\n", ha->host_no, mb[1], mb[2], mb[3]));
break;
+
+ case MBA_TRACE_NOTIFICATION:
+ DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
+ ha->host_no, mb[1], mb[2]));
+ break;
}
}
@@ -1452,8 +1437,8 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
__func__, ha->host_no, pkt, pkt->handle));
- DEBUG9(printk("%s: ct pkt dump:\n", __func__);)
- DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx));)
+ DEBUG9(printk("%s: ct pkt dump:\n", __func__));
+ DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx)));
/* Validate handle. */
if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d6cb3bd1a29..879f281e2ea 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -13,13 +13,13 @@ qla2x00_mbx_sem_timeout(unsigned long data)
{
struct semaphore *sem_ptr = (struct semaphore *)data;
- DEBUG11(printk("qla2x00_sem_timeout: entered.\n");)
+ DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
if (sem_ptr != NULL) {
up(sem_ptr);
}
- DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");)
+ DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
}
/*
@@ -61,7 +61,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
rval = QLA_SUCCESS;
abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
/*
* Wait for active mailbox commands to finish by waiting at most tov
@@ -72,7 +72,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
/* Timeout occurred. Return error. */
DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
- "Exiting.\n", __func__, ha->host_no);)
+ "Exiting.\n", __func__, ha->host_no));
return QLA_FUNCTION_TIMEOUT;
}
}
@@ -86,7 +86,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n",
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -131,14 +131,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
/* Unlock mbx registers and wait for interrupt */
DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. "
- "jiffies=%lx.\n", __func__, ha->host_no, jiffies);)
+ "jiffies=%lx.\n", __func__, ha->host_no, jiffies));
/* Wait for mbx cmd completion until timeout */
if (!abort_active && io_lock_on) {
/* sleep on completion semaphore */
DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
init_timer(&tmp_intr_timer);
tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
@@ -147,11 +147,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
(void (*)(unsigned long))qla2x00_mbx_sem_timeout;
DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
- ha->host_no);)
+ ha->host_no));
add_timer(&tmp_intr_timer);
DEBUG11(printk("%s(%ld): going to unlock & sleep. "
- "time=0x%lx.\n", __func__, ha->host_no, jiffies);)
+ "time=0x%lx.\n", __func__, ha->host_no, jiffies));
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
@@ -170,14 +170,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
down(&ha->mbx_intr_sem);
DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
- ha->host_no, jiffies);)
+ ha->host_no, jiffies));
clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
/* delete the timer */
del_timer(&tmp_intr_timer);
} else {
DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
- ha->host_no, command);)
+ ha->host_no, command));
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
@@ -209,7 +209,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
uint16_t *iptr2;
DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__,
- ha->host_no, command);)
+ ha->host_no, command));
/* Got interrupt. Clear the flag. */
ha->flags.mbox_int = 0;
@@ -266,7 +266,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (!abort_active) {
DEBUG11(printk("%s(%ld): checking for additional resp "
- "interrupt.\n", __func__, ha->host_no);)
+ "interrupt.\n", __func__, ha->host_no));
/* polling mode for non isp_abort commands. */
qla2x00_poll(ha);
@@ -277,9 +277,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (!io_lock_on || (mcp->flags & IOCTL_CMD)) {
/* not in dpc. schedule it for dpc to take over. */
DEBUG(printk("%s(%ld): timeout schedule "
- "isp_abort_needed.\n", __func__, ha->host_no);)
+ "isp_abort_needed.\n", __func__, ha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout schedule "
- "isp_abort_needed.\n", __func__, ha->host_no);)
+ "isp_abort_needed.\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
"Mailbox command timeout occured. Scheduling ISP "
"abort.\n");
@@ -288,9 +288,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
} else if (!abort_active) {
/* call abort directly since we are in the DPC thread */
DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout calling "
- "abort_isp\n", __func__, ha->host_no);)
+ "abort_isp\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
"Mailbox command timeout occured. Issuing ISP "
"abort.\n");
@@ -303,9 +303,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
}
clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
DEBUG(printk("%s(%ld): finished abort_isp\n", __func__,
- ha->host_no);)
+ ha->host_no));
DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
}
}
@@ -316,9 +316,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (rval) {
DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
"mbx2=%x, cmd=%x ****\n", __func__, ha->host_no,
- mcp->mb[0], mcp->mb[1], mcp->mb[2], command);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[2], command));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -394,7 +394,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
mcp->out_mb = MBX_0;
@@ -424,10 +424,10 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
} else {
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
- __func__, ha->host_no, mcp->mb[1]);)
+ __func__, ha->host_no, mcp->mb[1]));
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__,
- ha->host_no);)
+ ha->host_no));
}
}
@@ -611,7 +611,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no));
mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
mcp->mb[1] = 0xAAAA;
@@ -639,11 +639,11 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -671,7 +671,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_VERIFY_CHECKSUM;
mcp->out_mb = MBX_0;
@@ -694,9 +694,9 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));)
+ (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1])));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -743,9 +743,9 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
sts_entry_t *sts_entry = (sts_entry_t *) buffer;
@@ -781,7 +781,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no));
fcport = sp->fcport;
@@ -813,11 +813,11 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
sp->flags |= SRB_ABORT_PENDING;
DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -848,7 +848,7 @@ qla2x00_abort_target(fc_port_t *fcport)
if (fcport == NULL)
return 0;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
mcp->mb[0] = MBC_ABORT_TARGET;
@@ -872,11 +872,11 @@ qla2x00_abort_target(fc_port_t *fcport)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_abort_target(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -912,7 +912,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
mcp->out_mb = MBX_0;
@@ -933,11 +933,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -968,7 +968,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_RETRY_COUNT;
mcp->out_mb = MBX_0;
@@ -980,7 +980,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n",
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
} else {
/* Convert returned data and check our values. */
*r_a_tov = mcp->mb[3] / 2;
@@ -992,7 +992,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
}
DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d "
- "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);)
+ "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov));
}
return rval;
@@ -1023,7 +1023,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
mcp->mb[2] = MSW(ha->init_cb_dma);
@@ -1043,11 +1043,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x "
"mb0=%x.\n",
- ha->host_no, rval, mcp->mb[0]);)
+ ha->host_no, rval, mcp->mb[0]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1079,7 +1079,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
struct port_database_24xx *pd24;
dma_addr_t pd_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
pd24 = NULL;
pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
@@ -1220,7 +1220,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
mcp->out_mb = MBX_0;
@@ -1235,11 +1235,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): "
- "failed=%x.\n", ha->host_no, rval);)
+ "failed=%x.\n", ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1272,7 +1272,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_PORT_NAME;
mcp->out_mb = MBX_1|MBX_0;
@@ -1292,7 +1292,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
if (name != NULL) {
/* This function returns name in big endian. */
@@ -1307,7 +1307,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
}
DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1335,7 +1335,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
@@ -1364,10 +1364,10 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n",
- __func__, ha->host_no, rval);)
+ __func__, ha->host_no, rval));
} else {
/*EMPTY*/
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -1400,10 +1400,10 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total "
- "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);)
+ "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov));
mcp->mb[0] = MBC_SEND_SNS_COMMAND;
mcp->mb[1] = cmd_size;
@@ -1421,12 +1421,12 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
- "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+ "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
- "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+ "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
} else {
/*EMPTY*/
- DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no));
}
return rval;
@@ -1442,7 +1442,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
dma_addr_t lg_dma;
uint32_t iop[2];
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
if (lg == NULL) {
@@ -1458,13 +1458,15 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI);
if (opt & BIT_0)
lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI);
+ if (opt & BIT_1)
+ lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI);
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else if (lg->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -1505,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
break;
}
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
iop[0] = le32_to_cpu(lg->io_parameter[0]);
@@ -1559,7 +1561,7 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no));
mcp->mb[0] = MBC_LOGIN_FABRIC_PORT;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1604,11 +1606,11 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x "
"mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[2]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[2]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1643,7 +1645,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb_ret, opt);
- DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_LOGIN_LOOP_PORT;
if (HAS_EXTENDED_IDS(ha))
@@ -1677,13 +1679,13 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
"mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
"mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
} else {
/*EMPTY*/
- DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return (rval);
@@ -1697,7 +1699,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
struct logio_entry_24xx *lg;
dma_addr_t lg_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
if (lg == NULL) {
@@ -1718,7 +1720,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else if (lg->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -1729,10 +1731,10 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
"-- completion status (%x) ioparam=%x/%x.\n", __func__,
ha->host_no, le16_to_cpu(lg->comp_status),
le32_to_cpu(lg->io_parameter[0]),
- le32_to_cpu(lg->io_parameter[1]));)
+ le32_to_cpu(lg->io_parameter[1])));
} else {
/*EMPTY*/
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1765,7 +1767,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT;
mcp->out_mb = MBX_1|MBX_0;
@@ -1785,11 +1787,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x "
- "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);)
+ "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1818,7 +1820,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
mcp->mb[1] = 0;
@@ -1833,11 +1835,11 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1864,7 +1866,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
if (id_list == NULL)
return QLA_FUNCTION_FAILED;
@@ -1893,11 +1895,11 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
*entries = mcp->mb[1];
DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1936,7 +1938,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__,
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
} else {
DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
"mb7=%x mb10=%x.\n", __func__, ha->host_no,
@@ -2045,7 +2047,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
link_stat_t *stat_buf;
dma_addr_t stat_buf_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
if (stat_buf == NULL) {
@@ -2083,7 +2085,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
if (rval == QLA_SUCCESS) {
if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
- __func__, ha->host_no, mcp->mb[0]);)
+ __func__, ha->host_no, mcp->mb[0]));
status[0] = mcp->mb[0];
rval = BIT_1;
} else {
@@ -2108,12 +2110,12 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
stat_buf->prim_seq_err_cnt,
stat_buf->inval_xmit_word_cnt,
- stat_buf->inval_crc_cnt);)
+ stat_buf->inval_crc_cnt));
}
} else {
/* Failed. */
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
- ha->host_no, rval);)
+ ha->host_no, rval));
rval = BIT_1;
}
@@ -2132,7 +2134,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
uint32_t *sbuf, *siter;
dma_addr_t sbuf_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
if (dwords > (DMA_POOL_SIZE / 4)) {
DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
@@ -2196,7 +2198,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
dma_addr_t abt_dma;
uint32_t handle;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
fcport = sp->fcport;
@@ -2229,7 +2231,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
- __func__, ha->host_no, rval);)
+ __func__, ha->host_no, rval));
} else if (abt->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -2238,10 +2240,10 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
} else if (abt->nport_handle != __constant_cpu_to_le16(0)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__, ha->host_no,
- le16_to_cpu(abt->nport_handle));)
+ le16_to_cpu(abt->nport_handle)));
rval = QLA_FUNCTION_FAILED;
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
sp->flags |= SRB_ABORT_PENDING;
}
@@ -2268,7 +2270,7 @@ qla24xx_abort_target(fc_port_t *fcport)
if (fcport == NULL)
return 0;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
@@ -2290,7 +2292,7 @@ qla24xx_abort_target(fc_port_t *fcport)
rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
goto atarget_done;
} else if (tsk->p.sts.entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
@@ -2302,7 +2304,7 @@ qla24xx_abort_target(fc_port_t *fcport)
__constant_cpu_to_le16(CS_COMPLETE)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__,
- ha->host_no, le16_to_cpu(tsk->p.sts.comp_status));)
+ ha->host_no, le16_to_cpu(tsk->p.sts.comp_status)));
rval = QLA_FUNCTION_FAILED;
goto atarget_done;
}
@@ -2311,9 +2313,9 @@ qla24xx_abort_target(fc_port_t *fcport)
rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
atarget_done:
@@ -2460,3 +2462,81 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
return rval;
}
+
+int
+qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
+ uint16_t buffers)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_TRACE_CONTROL;
+ mcp->mb[1] = ctrl;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ if (ctrl == TC_ENABLE) {
+ mcp->mb[2] = LSW(eft_dma);
+ mcp->mb[3] = MSW(eft_dma);
+ mcp->mb[4] = LSW(MSD(eft_dma));
+ mcp->mb[5] = MSW(MSD(eft_dma));
+ mcp->mb[6] = buffers;
+ mcp->mb[7] = buffers;
+ mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
+ }
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+ __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
+
+int
+qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+ uint16_t off, uint16_t count)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_READ_SFP;
+ mcp->mb[1] = addr;
+ mcp->mb[2] = MSW(sfp_dma);
+ mcp->mb[3] = LSW(sfp_dma);
+ mcp->mb[6] = MSW(MSD(sfp_dma));
+ mcp->mb[7] = LSW(MSD(sfp_dma));
+ mcp->mb[8] = count;
+ mcp->mb[9] = off;
+ mcp->mb[10] = 0;
+ mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+ ha->host_no, rval, mcp->mb[0]));
+ } 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 ccaad0b08d3..65cbe2f5eea 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -39,14 +39,14 @@ MODULE_PARM_DESC(ql2xlogintimeout,
int qlport_down_retry = 30;
module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(qlport_down_retry,
- "Maximum number of command retries to a port that returns"
+ "Maximum number of command retries to a port that returns "
"a PORT-DOWN status.");
int ql2xplogiabsentdevice;
module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xplogiabsentdevice,
"Option to enable PLOGI to devices that are not present after "
- "a Fabric scan. This is needed for several broken switches."
+ "a Fabric scan. This is needed for several broken switches. "
"Default is 0 - no PLOGI. 1 - perfom PLOGI.");
int ql2xloginretrycount = 0;
@@ -54,6 +54,19 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xloginretrycount,
"Specify an alternate value for the NVRAM login retry count.");
+int ql2xallocfwdump = 1;
+module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xallocfwdump,
+ "Option to enable allocation of memory for a firmware dump "
+ "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,
+ "Option to enable extended error logging, "
+ "Default is 0 - no logging. 1 - log errors.");
+
static void qla2x00_free_device(scsi_qla_host_t *);
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
@@ -624,7 +637,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",
__func__, ha->host_no, sp, serial));
- DEBUG3(qla2x00_print_scsi_cmd(cmd);)
+ DEBUG3(qla2x00_print_scsi_cmd(cmd));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops.abort_command(ha, sp)) {
@@ -731,7 +744,6 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -742,8 +754,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -766,7 +777,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
#endif
} else {
DEBUG2(printk(KERN_INFO
- "%s failed: loop not ready\n",__func__);)
+ "%s failed: loop not ready\n",__func__));
}
if (ret == FAILED) {
@@ -862,7 +873,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -873,8 +883,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -923,7 +932,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -934,8 +942,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -1021,12 +1028,12 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
/* Empty */
DEBUG2_3(printk("%s(%ld): **** FAILED ****\n",
__func__,
- ha->host_no);)
+ ha->host_no));
} else {
/* Empty */
DEBUG3(printk("%s(%ld): exiting normally.\n",
__func__,
- ha->host_no);)
+ ha->host_no));
}
return(status);
@@ -1324,7 +1331,8 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha)
/*
* PCI driver interface
*/
-static int qla2x00_probe_one(struct pci_dev *pdev)
+static int __devinit
+qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret = -ENODEV;
device_reg_t __iomem *reg;
@@ -1405,7 +1413,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
ha->isp_ops.fw_dump = qla2100_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump;
ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
if (IS_QLA2100(ha)) {
@@ -1432,7 +1439,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.pci_config = qla2300_pci_config;
ha->isp_ops.intr_handler = qla2300_intr_handler;
ha->isp_ops.fw_dump = qla2300_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump;
ha->isp_ops.beacon_on = qla2x00_beacon_on;
ha->isp_ops.beacon_off = qla2x00_beacon_off;
ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
@@ -1469,7 +1475,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
ha->isp_ops.fw_dump = qla24xx_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump;
ha->isp_ops.read_optrom = qla24xx_read_optrom_data;
ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
ha->isp_ops.beacon_on = qla24xx_beacon_on;
@@ -1541,7 +1546,7 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
host->transportt = qla2xxx_transport_template;
ret = request_irq(pdev->irq, ha->isp_ops.intr_handler,
- SA_INTERRUPT|SA_SHIRQ, QLA2XXX_DRIVER_NAME, ha);
+ IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
if (ret) {
qla_printk(KERN_WARNING, ha,
"Failed to reserve interrupt %d already in use.\n",
@@ -1640,7 +1645,8 @@ probe_out:
return ret;
}
-static void qla2x00_remove_one(struct pci_dev *pdev)
+static void __devexit
+qla2x00_remove_one(struct pci_dev *pdev)
{
scsi_qla_host_t *ha;
@@ -1678,6 +1684,9 @@ qla2x00_free_device(scsi_qla_host_t *ha)
kthread_stop(t);
}
+ if (ha->eft)
+ qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+
/* Stop currently executing firmware. */
qla2x00_stop_firmware(ha);
@@ -1899,17 +1908,6 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
}
memset(ha->init_cb, 0, ha->init_cb_size);
- /* Allocate ioctl related memory. */
- if (qla2x00_alloc_ioctl_mem(ha)) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - ioctl_mem\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - "
@@ -1972,6 +1970,26 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
continue;
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
+
+ if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ /*
+ * Get consistent memory allocated for SFP
+ * block.
+ */
+ ha->sfp_data = dma_pool_alloc(ha->s_dma_pool,
+ GFP_KERNEL, &ha->sfp_data_dma);
+ if (ha->sfp_data == NULL) {
+ qla_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - "
+ "sfp_data\n");
+
+ qla2x00_mem_free(ha);
+ msleep(100);
+
+ continue;
+ }
+ memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
+ }
}
/* Done all allocations without any error. */
@@ -2006,12 +2024,16 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
return;
}
- /* free ioctl memory */
- qla2x00_free_ioctl_mem(ha);
-
/* free sp pool */
qla2x00_free_sp_pool(ha);
+ if (ha->fw_dump) {
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+ vfree(ha->fw_dump);
+ }
+
if (ha->sns_cmd)
dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
ha->sns_cmd, ha->sns_cmd_dma);
@@ -2020,6 +2042,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
ha->ct_sns, ha->ct_sns_dma);
+ if (ha->sfp_data)
+ dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
+
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
@@ -2043,6 +2068,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
(ha->request_q_length + 1) * sizeof(request_t),
ha->request_ring, ha->request_dma);
+ ha->eft = NULL;
+ ha->eft_dma = 0;
ha->sns_cmd = NULL;
ha->sns_cmd_dma = 0;
ha->ct_sns = NULL;
@@ -2071,13 +2098,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
}
INIT_LIST_HEAD(&ha->fcports);
- vfree(ha->fw_dump);
- vfree(ha->fw_dump_buffer);
-
ha->fw_dump = NULL;
ha->fw_dumped = 0;
ha->fw_dump_reading = 0;
- ha->fw_dump_buffer = NULL;
vfree(ha->optrom_buffer);
}
@@ -2215,9 +2238,6 @@ qla2x00_do_dpc(void *data)
next_loopid = 0;
list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
-
/*
* If the port is not ONLINE then try to login
* to it if we haven't run out of retries.
@@ -2617,40 +2637,16 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
-static int __devinit
-qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- return qla2x00_probe_one(pdev);
-}
-
-static void __devexit
-qla2xxx_remove_one(struct pci_dev *pdev)
-{
- qla2x00_remove_one(pdev);
-}
-
static struct pci_driver qla2xxx_pci_driver = {
.name = QLA2XXX_DRIVER_NAME,
.driver = {
.owner = THIS_MODULE,
},
.id_table = qla2xxx_pci_tbl,
- .probe = qla2xxx_probe_one,
- .remove = __devexit_p(qla2xxx_remove_one),
+ .probe = qla2x00_probe_one,
+ .remove = __devexit_p(qla2x00_remove_one),
};
-static inline int
-qla2x00_pci_module_init(void)
-{
- return pci_module_init(&qla2xxx_pci_driver);
-}
-
-static inline void
-qla2x00_pci_module_exit(void)
-{
- pci_unregister_driver(&qla2xxx_pci_driver);
-}
-
/**
* qla2x00_module_init - Module initialization.
**/
@@ -2670,16 +2666,16 @@ qla2x00_module_init(void)
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
-#if DEBUG_QLA2100
- strcat(qla2x00_version_str, "-debug");
-#endif
+ if (extended_error_logging)
+ strcat(qla2x00_version_str, "-debug");
+
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
if (!qla2xxx_transport_template)
return -ENODEV;
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
- ret = qla2x00_pci_module_init();
+ ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
@@ -2693,7 +2689,7 @@ qla2x00_module_init(void)
static void __exit
qla2x00_module_exit(void)
{
- qla2x00_pci_module_exit();
+ pci_unregister_driver(&qla2xxx_pci_driver);
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6b315521bd8..971259032ef 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.05-k2"
+#define QLA2XXX_VERSION "8.01.07-k1"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
-#define QLA_DRIVER_PATCH_VER 5
+#define QLA_DRIVER_PATCH_VER 7
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 2203103adce..5b2f0741a55 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
- * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
-
-
#define MAX_TARGETS 16
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
@@ -57,7 +55,6 @@
static struct qlogicpti *qptichain = NULL;
static DEFINE_SPINLOCK(qptichain_lock);
-static int qptis_running = 0;
#define PACKB(a, b) (((a)<<4)|(b))
@@ -721,7 +718,7 @@ static int __init qpti_register_irq(struct qlogicpti *qpti)
* sanely maintain.
*/
if (request_irq(qpti->irq, qpti_intr,
- SA_SHIRQ, "Qlogic/PTI", qpti))
+ IRQF_SHARED, "Qlogic/PTI", qpti))
goto fail;
printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
@@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return 0;
}
-/* Detect all PTI Qlogic ISP's in the machine. */
-static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
-{
- struct qlogicpti *qpti;
- struct Scsi_Host *qpti_host;
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int nqptis = 0, nqptis_in_use = 0;
-
- tpnt->proc_name = "qlogicpti";
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- /* Is this a red snapper? */
- if (strcmp(sdev->prom_name, "ptisp") &&
- strcmp(sdev->prom_name, "PTI,ptisp") &&
- strcmp(sdev->prom_name, "QLGC,isp") &&
- strcmp(sdev->prom_name, "SUNW,isp"))
- continue;
-
- /* Sometimes Antares cards come up not completely
- * setup, and we get a report of a zero IRQ.
- * Skip over them in such cases so we survive.
- */
- if (sdev->irqs[0] == 0) {
- printk("qpti%d: Adapter reports no interrupt, "
- "skipping over this card.", nqptis);
- continue;
- }
-
- /* Yep, register and allocate software state. */
- qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
- if (!qpti_host) {
- printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
- continue;
- }
- qpti = (struct qlogicpti *) qpti_host->hostdata;
-
- /* We are wide capable, 16 targets. */
- qpti_host->max_id = MAX_TARGETS;
-
- /* Setup back pointers and misc. state. */
- qpti->qhost = qpti_host;
- qpti->sdev = sdev;
- qpti->qpti_id = nqptis++;
- qpti->prom_node = sdev->prom_node;
- prom_getstring(qpti->prom_node, "name",
- qpti->prom_name,
- sizeof(qpti->prom_name));
-
- /* This is not correct, actually. There's a switch
- * on the PTI cards that put them into "emulation"
- * mode- i.e., report themselves as QLGC,isp
- * instead of PTI,ptisp. The only real substantive
- * difference between non-pti and pti cards is
- * the tmon register. Which is possibly even
- * there for Qlogic cards, but non-functional.
- */
- qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
-
- qpti_chain_add(qpti);
- if (qpti_map_regs(qpti) < 0)
- goto fail_unlink;
-
- if (qpti_register_irq(qpti) < 0)
- goto fail_unmap_regs;
-
- qpti_get_scsi_id(qpti);
- qpti_get_bursts(qpti);
- qpti_get_clock(qpti);
-
- /* Clear out scsi_cmnd array. */
- memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
-
- if (qpti_map_queues(qpti) < 0)
- goto fail_free_irq;
-
- /* Load the firmware. */
- if (qlogicpti_load_firmware(qpti))
- goto fail_unmap_queues;
- if (qpti->is_pti) {
- /* Check the PTI status reg. */
- if (qlogicpti_verify_tmon(qpti))
- goto fail_unmap_queues;
- }
-
- /* Reset the ISP and init res/req queues. */
- if (qlogicpti_reset_hardware(qpti_host))
- goto fail_unmap_queues;
-
- printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
- qpti->fware_minrev, qpti->fware_micrev);
- {
- char buffer[60];
-
- prom_getstring (qpti->prom_node,
- "isp-fcode", buffer, 60);
- if (buffer[0])
- printk("(Firmware %s)", buffer);
- if (prom_getbool(qpti->prom_node, "differential"))
- qpti->differential = 1;
- }
-
- printk (" [%s Wide, using %s interface]\n",
- (qpti->ultra ? "Ultra" : "Fast"),
- (qpti->differential ? "differential" : "single ended"));
-
- nqptis_in_use++;
- continue;
-
- fail_unmap_queues:
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
- fail_free_irq:
- free_irq(qpti->irq, qpti);
-
- fail_unmap_regs:
- sbus_iounmap(qpti->qregs,
- qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
- fail_unlink:
- qpti_chain_del(qpti);
- scsi_unregister(qpti->qhost);
- }
- }
- if (nqptis)
- printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
- nqptis, nqptis_in_use);
- qptis_running = nqptis_in_use;
- return nqptis;
-}
-
-static int qlogicpti_release(struct Scsi_Host *host)
-{
- struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
-
- /* Remove visibility from IRQ handlers. */
- qpti_chain_del(qpti);
-
- /* Shut up the card. */
- sbus_writew(0, qpti->qregs + SBUS_CTRL);
-
- /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
- free_irq(qpti->irq, qpti);
-
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
-
- sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
-
- return 0;
-}
-
const char *qlogicpti_info(struct Scsi_Host *host)
{
static char buf[80];
@@ -1044,7 +874,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
if (Cmnd->use_sg) {
int sg_count;
- sg = (struct scatterlist *) Cmnd->buffer;
+ sg = (struct scatterlist *) Cmnd->request_buffer;
sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
ds = cmd->dataseg;
@@ -1448,7 +1278,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
if (Cmnd->use_sg) {
sbus_unmap_sg(qpti->sdev,
- (struct scatterlist *)Cmnd->buffer,
+ (struct scatterlist *)Cmnd->request_buffer,
Cmnd->use_sg,
Cmnd->sc_data_direction);
} else {
@@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return return_status;
}
-static struct scsi_host_template driver_template = {
- .detect = qlogicpti_detect,
- .release = qlogicpti_release,
+static struct scsi_host_template qpti_template = {
+ .module = THIS_MODULE,
+ .name = "qlogicpti",
.info = qlogicpti_info,
.queuecommand = qlogicpti_queuecommand_slow,
.eh_abort_handler = qlogicpti_abort,
@@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
};
+static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ static int nqptis;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct scsi_host_template *tpnt = match->data;
+ struct Scsi_Host *host;
+ struct qlogicpti *qpti;
+ char *fcode;
+
+ /* Sometimes Antares cards come up not completely
+ * setup, and we get a report of a zero IRQ.
+ */
+ if (sdev->irqs[0] == 0)
+ return -ENODEV;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
+ if (!host)
+ return -ENOMEM;
+
+ qpti = (struct qlogicpti *) host->hostdata;
+
+ host->max_id = MAX_TARGETS;
+ qpti->qhost = host;
+ qpti->sdev = sdev;
+ qpti->qpti_id = nqptis;
+ qpti->prom_node = sdev->prom_node;
+ strcpy(qpti->prom_name, sdev->ofdev.node->name);
+ qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
+
+ if (qpti_map_regs(qpti) < 0)
+ goto fail_unlink;
+
+ if (qpti_register_irq(qpti) < 0)
+ goto fail_unmap_regs;
+
+ qpti_get_scsi_id(qpti);
+ qpti_get_bursts(qpti);
+ qpti_get_clock(qpti);
+
+ /* Clear out scsi_cmnd array. */
+ memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
+
+ if (qpti_map_queues(qpti) < 0)
+ goto fail_free_irq;
+
+ /* Load the firmware. */
+ if (qlogicpti_load_firmware(qpti))
+ goto fail_unmap_queues;
+ if (qpti->is_pti) {
+ /* Check the PTI status reg. */
+ if (qlogicpti_verify_tmon(qpti))
+ goto fail_unmap_queues;
+ }
+
+ /* Reset the ISP and init res/req queues. */
+ if (qlogicpti_reset_hardware(host))
+ goto fail_unmap_queues;
+
+ if (scsi_add_host(host, &dev->dev))
+ goto fail_unmap_queues;
+
+ printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
+ qpti->fware_minrev, qpti->fware_micrev);
+
+ fcode = of_get_property(dp, "isp-fcode", NULL);
+ if (fcode && fcode[0])
+ printk("(Firmware %s)", fcode);
+ if (of_find_property(dp, "differential", NULL) != NULL)
+ qpti->differential = 1;
+
+ printk (" [%s Wide, using %s interface]\n",
+ (qpti->ultra ? "Ultra" : "Fast"),
+ (qpti->differential ? "differential" : "single ended"));
+
+ dev_set_drvdata(&sdev->ofdev.dev, qpti);
+
+ qpti_chain_add(qpti);
+
+ scsi_scan_host(host);
+ nqptis++;
+
+ return 0;
+
+fail_unmap_queues:
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+fail_unmap_regs:
+ sbus_iounmap(qpti->qregs,
+ qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+fail_free_irq:
+ free_irq(qpti->irq, qpti);
+
+fail_unlink:
+ scsi_host_put(host);
+
+ return -ENODEV;
+}
+
+static int __devexit qpti_sbus_remove(struct of_device *dev)
+{
+ struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+
+ qpti_chain_del(qpti);
+
+ scsi_remove_host(qpti->qhost);
+
+ /* Shut up the card. */
+ sbus_writew(0, qpti->qregs + SBUS_CTRL);
+
+ /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
+ free_irq(qpti->irq, qpti);
+
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+ sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+ scsi_host_put(qpti->qhost);
+
+ return 0;
+}
+
+static struct of_device_id qpti_match[] = {
+ {
+ .name = "ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "PTI,ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "QLGC,isp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "SUNW,isp",
+ .data = &qpti_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, qpti_match);
+
+static struct of_platform_driver qpti_sbus_driver = {
+ .name = "qpti",
+ .match_table = qpti_match,
+ .probe = qpti_sbus_probe,
+ .remove = __devexit_p(qpti_sbus_remove),
+};
-#include "scsi_module.c"
+static int __init qpti_init(void)
+{
+ return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit qpti_exit(void)
+{
+ of_unregister_driver(&qpti_sbus_driver);
+}
+MODULE_DESCRIPTION("QlogicISP SBUS driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0");
+module_init(qpti_init);
+module_exit(qpti_exit);
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
deleted file mode 100644
index 4a71578df3c..00000000000
--- a/drivers/scsi/sata_mv.c
+++ /dev/null
@@ -1,2468 +0,0 @@
-/*
- * sata_mv.c - Marvell SATA support
- *
- * Copyright 2005: EMC Corporation, all rights reserved.
- * Copyright 2005 Red Hat, Inc. All rights reserved.
- *
- * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
- *
- * 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; version 2 of the License.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-
-#define DRV_NAME "sata_mv"
-#define DRV_VERSION "0.7"
-
-enum {
- /* BAR's are enumerated in terms of pci_resource_start() terms */
- MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
- MV_IO_BAR = 2, /* offset 0x18: IO space */
- MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
-
- MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
- MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
-
- MV_PCI_REG_BASE = 0,
- MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
- MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
- MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
- MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
- MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
- MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
-
- MV_SATAHC0_REG_BASE = 0x20000,
- MV_FLASH_CTL = 0x1046c,
- MV_GPIO_PORT_CTL = 0x104f0,
- MV_RESET_CFG = 0x180d8,
-
- MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
- MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
- MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
- MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
-
- MV_USE_Q_DEPTH = ATA_DEF_QUEUE,
-
- MV_MAX_Q_DEPTH = 32,
- MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
-
- /* CRQB needs alignment on a 1KB boundary. Size == 1KB
- * CRPB needs alignment on a 256B boundary. Size == 256B
- * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
- * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
- */
- MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
- MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
- MV_MAX_SG_CT = 176,
- MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
- MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
-
- MV_PORTS_PER_HC = 4,
- /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
- MV_PORT_HC_SHIFT = 2,
- /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
- MV_PORT_MASK = 3,
-
- /* Host Flags */
- MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
- MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
- MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
- MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
-
- CRQB_FLAG_READ = (1 << 0),
- CRQB_TAG_SHIFT = 1,
- CRQB_CMD_ADDR_SHIFT = 8,
- CRQB_CMD_CS = (0x2 << 11),
- CRQB_CMD_LAST = (1 << 15),
-
- CRPB_FLAG_STATUS_SHIFT = 8,
-
- EPRD_FLAG_END_OF_TBL = (1 << 31),
-
- /* PCI interface registers */
-
- PCI_COMMAND_OFS = 0xc00,
-
- PCI_MAIN_CMD_STS_OFS = 0xd30,
- STOP_PCI_MASTER = (1 << 2),
- PCI_MASTER_EMPTY = (1 << 3),
- GLOB_SFT_RST = (1 << 4),
-
- MV_PCI_MODE = 0xd00,
- MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
- MV_PCI_DISC_TIMER = 0xd04,
- MV_PCI_MSI_TRIGGER = 0xc38,
- MV_PCI_SERR_MASK = 0xc28,
- MV_PCI_XBAR_TMOUT = 0x1d04,
- MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
- MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
- MV_PCI_ERR_ATTRIBUTE = 0x1d48,
- MV_PCI_ERR_COMMAND = 0x1d50,
-
- PCI_IRQ_CAUSE_OFS = 0x1d58,
- PCI_IRQ_MASK_OFS = 0x1d5c,
- PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
-
- HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
- HC_MAIN_IRQ_MASK_OFS = 0x1d64,
- PORT0_ERR = (1 << 0), /* shift by port # */
- PORT0_DONE = (1 << 1), /* shift by port # */
- HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
- HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
- PCI_ERR = (1 << 18),
- TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
- TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
- PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
- GPIO_INT = (1 << 22),
- SELF_INT = (1 << 23),
- TWSI_INT = (1 << 24),
- HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
- HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
- PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
- HC_MAIN_RSVD),
-
- /* SATAHC registers */
- HC_CFG_OFS = 0,
-
- HC_IRQ_CAUSE_OFS = 0x14,
- CRPB_DMA_DONE = (1 << 0), /* shift by port # */
- HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
- DEV_IRQ = (1 << 8), /* shift by port # */
-
- /* Shadow block registers */
- SHD_BLK_OFS = 0x100,
- SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
-
- /* SATA registers */
- SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
- SATA_ACTIVE_OFS = 0x350,
- PHY_MODE3 = 0x310,
- PHY_MODE4 = 0x314,
- PHY_MODE2 = 0x330,
- MV5_PHY_MODE = 0x74,
- MV5_LT_MODE = 0x30,
- MV5_PHY_CTL = 0x0C,
- SATA_INTERFACE_CTL = 0x050,
-
- MV_M2_PREAMP_MASK = 0x7e0,
-
- /* Port registers */
- EDMA_CFG_OFS = 0,
- EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
- EDMA_CFG_NCQ = (1 << 5),
- EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
- EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
- EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
-
- EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
- EDMA_ERR_IRQ_MASK_OFS = 0xc,
- EDMA_ERR_D_PAR = (1 << 0),
- EDMA_ERR_PRD_PAR = (1 << 1),
- EDMA_ERR_DEV = (1 << 2),
- EDMA_ERR_DEV_DCON = (1 << 3),
- EDMA_ERR_DEV_CON = (1 << 4),
- EDMA_ERR_SERR = (1 << 5),
- EDMA_ERR_SELF_DIS = (1 << 7),
- EDMA_ERR_BIST_ASYNC = (1 << 8),
- EDMA_ERR_CRBQ_PAR = (1 << 9),
- EDMA_ERR_CRPB_PAR = (1 << 10),
- EDMA_ERR_INTRL_PAR = (1 << 11),
- EDMA_ERR_IORDY = (1 << 12),
- EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
- EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
- EDMA_ERR_LNK_DATA_RX = (0xf << 17),
- EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
- EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
- EDMA_ERR_TRANS_PROTO = (1 << 31),
- EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
- EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
- EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
- EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
- EDMA_ERR_LNK_DATA_RX |
- EDMA_ERR_LNK_DATA_TX |
- EDMA_ERR_TRANS_PROTO),
-
- EDMA_REQ_Q_BASE_HI_OFS = 0x10,
- EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
-
- EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
- EDMA_REQ_Q_PTR_SHIFT = 5,
-
- EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
- EDMA_RSP_Q_IN_PTR_OFS = 0x20,
- EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
- EDMA_RSP_Q_PTR_SHIFT = 3,
-
- EDMA_CMD_OFS = 0x28,
- EDMA_EN = (1 << 0),
- EDMA_DS = (1 << 1),
- ATA_RST = (1 << 2),
-
- EDMA_IORDY_TMOUT = 0x34,
- EDMA_ARB_CFG = 0x38,
-
- /* Host private flags (hp_flags) */
- MV_HP_FLAG_MSI = (1 << 0),
- MV_HP_ERRATA_50XXB0 = (1 << 1),
- MV_HP_ERRATA_50XXB2 = (1 << 2),
- MV_HP_ERRATA_60X1B2 = (1 << 3),
- MV_HP_ERRATA_60X1C0 = (1 << 4),
- MV_HP_ERRATA_XX42A0 = (1 << 5),
- MV_HP_50XX = (1 << 6),
- MV_HP_GEN_IIE = (1 << 7),
-
- /* Port private flags (pp_flags) */
- MV_PP_FLAG_EDMA_EN = (1 << 0),
- MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
-};
-
-#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
-#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
-#define IS_GEN_I(hpriv) IS_50XX(hpriv)
-#define IS_GEN_II(hpriv) IS_60XX(hpriv)
-#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
-
-enum {
- /* Our DMA boundary is determined by an ePRD being unable to handle
- * anything larger than 64KB
- */
- MV_DMA_BOUNDARY = 0xffffU,
-
- EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
-
- EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
-};
-
-enum chip_type {
- chip_504x,
- chip_508x,
- chip_5080,
- chip_604x,
- chip_608x,
- chip_6042,
- chip_7042,
-};
-
-/* Command ReQuest Block: 32B */
-struct mv_crqb {
- __le32 sg_addr;
- __le32 sg_addr_hi;
- __le16 ctrl_flags;
- __le16 ata_cmd[11];
-};
-
-struct mv_crqb_iie {
- __le32 addr;
- __le32 addr_hi;
- __le32 flags;
- __le32 len;
- __le32 ata_cmd[4];
-};
-
-/* Command ResPonse Block: 8B */
-struct mv_crpb {
- __le16 id;
- __le16 flags;
- __le32 tmstmp;
-};
-
-/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
-struct mv_sg {
- __le32 addr;
- __le32 flags_size;
- __le32 addr_hi;
- __le32 reserved;
-};
-
-struct mv_port_priv {
- struct mv_crqb *crqb;
- dma_addr_t crqb_dma;
- struct mv_crpb *crpb;
- dma_addr_t crpb_dma;
- struct mv_sg *sg_tbl;
- dma_addr_t sg_tbl_dma;
- u32 pp_flags;
-};
-
-struct mv_port_signal {
- u32 amps;
- u32 pre;
-};
-
-struct mv_host_priv;
-struct mv_hw_ops {
- void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port);
- void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
- void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
- void __iomem *mmio);
- int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int n_hc);
- void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
- void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
-};
-
-struct mv_host_priv {
- u32 hp_flags;
- struct mv_port_signal signal[8];
- const struct mv_hw_ops *ops;
-};
-
-static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static void mv_phy_reset(struct ata_port *ap);
-static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
-static void mv_host_stop(struct ata_host_set *host_set);
-static int mv_port_start(struct ata_port *ap);
-static void mv_port_stop(struct ata_port *ap);
-static void mv_qc_prep(struct ata_queued_cmd *qc);
-static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
-static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static void mv_eng_timeout(struct ata_port *ap);
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-
-static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port);
-static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
- void __iomem *mmio);
-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int n_hc);
-static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
-
-static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port);
-static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
- void __iomem *mmio);
-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int n_hc);
-static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
-static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port_no);
-static void mv_stop_and_reset(struct ata_port *ap);
-
-static struct scsi_host_template mv_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = MV_USE_Q_DEPTH,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = MV_MAX_SG_CT / 2,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = MV_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations mv5_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .phy_reset = mv_phy_reset,
-
- .qc_prep = mv_qc_prep,
- .qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
-
- .eng_timeout = mv_eng_timeout,
-
- .irq_handler = mv_interrupt,
- .irq_clear = mv_irq_clear,
-
- .scr_read = mv5_scr_read,
- .scr_write = mv5_scr_write,
-
- .port_start = mv_port_start,
- .port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
-};
-
-static const struct ata_port_operations mv6_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .phy_reset = mv_phy_reset,
-
- .qc_prep = mv_qc_prep,
- .qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
-
- .eng_timeout = mv_eng_timeout,
-
- .irq_handler = mv_interrupt,
- .irq_clear = mv_irq_clear,
-
- .scr_read = mv_scr_read,
- .scr_write = mv_scr_write,
-
- .port_start = mv_port_start,
- .port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
-};
-
-static const struct ata_port_operations mv_iie_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .phy_reset = mv_phy_reset,
-
- .qc_prep = mv_qc_prep_iie,
- .qc_issue = mv_qc_issue,
-
- .eng_timeout = mv_eng_timeout,
-
- .irq_handler = mv_interrupt,
- .irq_clear = mv_irq_clear,
-
- .scr_read = mv_scr_read,
- .scr_write = mv_scr_write,
-
- .port_start = mv_port_start,
- .port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
-};
-
-static const struct ata_port_info mv_port_info[] = {
- { /* chip_504x */
- .sht = &mv_sht,
- .host_flags = MV_COMMON_FLAGS,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv5_ops,
- },
- { /* chip_508x */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv5_ops,
- },
- { /* chip_5080 */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv5_ops,
- },
- { /* chip_604x */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv6_ops,
- },
- { /* chip_608x */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- MV_FLAG_DUAL_HC),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv6_ops,
- },
- { /* chip_6042 */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv_iie_ops,
- },
- { /* chip_7042 */
- .sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- MV_FLAG_DUAL_HC),
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &mv_iie_ops,
- },
-};
-
-static const struct pci_device_id mv_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
-
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
-
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
- {} /* terminate list */
-};
-
-static struct pci_driver mv_pci_driver = {
- .name = DRV_NAME,
- .id_table = mv_pci_tbl,
- .probe = mv_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static const struct mv_hw_ops mv5xxx_ops = {
- .phy_errata = mv5_phy_errata,
- .enable_leds = mv5_enable_leds,
- .read_preamp = mv5_read_preamp,
- .reset_hc = mv5_reset_hc,
- .reset_flash = mv5_reset_flash,
- .reset_bus = mv5_reset_bus,
-};
-
-static const struct mv_hw_ops mv6xxx_ops = {
- .phy_errata = mv6_phy_errata,
- .enable_leds = mv6_enable_leds,
- .read_preamp = mv6_read_preamp,
- .reset_hc = mv6_reset_hc,
- .reset_flash = mv6_reset_flash,
- .reset_bus = mv_reset_pci_bus,
-};
-
-/*
- * module options
- */
-static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
-
-
-/*
- * Functions
- */
-
-static inline void writelfl(unsigned long data, void __iomem *addr)
-{
- writel(data, addr);
- (void) readl(addr); /* flush to avoid PCI posted write */
-}
-
-static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
-{
- return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
-}
-
-static inline unsigned int mv_hc_from_port(unsigned int port)
-{
- return port >> MV_PORT_HC_SHIFT;
-}
-
-static inline unsigned int mv_hardport_from_port(unsigned int port)
-{
- return port & MV_PORT_MASK;
-}
-
-static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
- unsigned int port)
-{
- return mv_hc_base(base, mv_hc_from_port(port));
-}
-
-static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
-{
- return mv_hc_base_from_port(base, port) +
- MV_SATAHC_ARBTR_REG_SZ +
- (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
-}
-
-static inline void __iomem *mv_ap_base(struct ata_port *ap)
-{
- return mv_port_base(ap->host_set->mmio_base, ap->port_no);
-}
-
-static inline int mv_get_hc_count(unsigned long host_flags)
-{
- return ((host_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
-}
-
-static void mv_irq_clear(struct ata_port *ap)
-{
-}
-
-/**
- * mv_start_dma - Enable eDMA engine
- * @base: port base address
- * @pp: port private data
- *
- * Verify the local cache of the eDMA state is accurate with a
- * WARN_ON.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
-{
- if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
- writelfl(EDMA_EN, base + EDMA_CMD_OFS);
- pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
- }
- WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
-}
-
-/**
- * mv_stop_dma - Disable eDMA engine
- * @ap: ATA channel to manipulate
- *
- * Verify the local cache of the eDMA state is accurate with a
- * WARN_ON.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_stop_dma(struct ata_port *ap)
-{
- void __iomem *port_mmio = mv_ap_base(ap);
- struct mv_port_priv *pp = ap->private_data;
- u32 reg;
- int i;
-
- if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
- /* Disable EDMA if active. The disable bit auto clears.
- */
- writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- } else {
- WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
- }
-
- /* now properly wait for the eDMA to stop */
- for (i = 1000; i > 0; i--) {
- reg = readl(port_mmio + EDMA_CMD_OFS);
- if (!(EDMA_EN & reg)) {
- break;
- }
- udelay(100);
- }
-
- if (EDMA_EN & reg) {
- ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
- /* FIXME: Consider doing a reset here to recover */
- }
-}
-
-#ifdef ATA_DEBUG
-static void mv_dump_mem(void __iomem *start, unsigned bytes)
-{
- int b, w;
- for (b = 0; b < bytes; ) {
- DPRINTK("%p: ", start + b);
- for (w = 0; b < bytes && w < 4; w++) {
- printk("%08x ",readl(start + b));
- b += sizeof(u32);
- }
- printk("\n");
- }
-}
-#endif
-
-static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
-{
-#ifdef ATA_DEBUG
- int b, w;
- u32 dw;
- for (b = 0; b < bytes; ) {
- DPRINTK("%02x: ", b);
- for (w = 0; b < bytes && w < 4; w++) {
- (void) pci_read_config_dword(pdev,b,&dw);
- printk("%08x ",dw);
- b += sizeof(u32);
- }
- printk("\n");
- }
-#endif
-}
-static void mv_dump_all_regs(void __iomem *mmio_base, int port,
- struct pci_dev *pdev)
-{
-#ifdef ATA_DEBUG
- void __iomem *hc_base = mv_hc_base(mmio_base,
- port >> MV_PORT_HC_SHIFT);
- void __iomem *port_base;
- int start_port, num_ports, p, start_hc, num_hcs, hc;
-
- if (0 > port) {
- start_hc = start_port = 0;
- num_ports = 8; /* shld be benign for 4 port devs */
- num_hcs = 2;
- } else {
- start_hc = port >> MV_PORT_HC_SHIFT;
- start_port = port;
- num_ports = num_hcs = 1;
- }
- DPRINTK("All registers for port(s) %u-%u:\n", start_port,
- num_ports > 1 ? num_ports - 1 : start_port);
-
- if (NULL != pdev) {
- DPRINTK("PCI config space regs:\n");
- mv_dump_pci_cfg(pdev, 0x68);
- }
- DPRINTK("PCI regs:\n");
- mv_dump_mem(mmio_base+0xc00, 0x3c);
- mv_dump_mem(mmio_base+0xd00, 0x34);
- mv_dump_mem(mmio_base+0xf00, 0x4);
- mv_dump_mem(mmio_base+0x1d00, 0x6c);
- for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
- hc_base = mv_hc_base(mmio_base, hc);
- DPRINTK("HC regs (HC %i):\n", hc);
- mv_dump_mem(hc_base, 0x1c);
- }
- for (p = start_port; p < start_port + num_ports; p++) {
- port_base = mv_port_base(mmio_base, p);
- DPRINTK("EDMA regs (port %i):\n",p);
- mv_dump_mem(port_base, 0x54);
- DPRINTK("SATA regs (port %i):\n",p);
- mv_dump_mem(port_base+0x300, 0x60);
- }
-#endif
-}
-
-static unsigned int mv_scr_offset(unsigned int sc_reg_in)
-{
- unsigned int ofs;
-
- switch (sc_reg_in) {
- case SCR_STATUS:
- case SCR_CONTROL:
- case SCR_ERROR:
- ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
- break;
- case SCR_ACTIVE:
- ofs = SATA_ACTIVE_OFS; /* active is not with the others */
- break;
- default:
- ofs = 0xffffffffU;
- break;
- }
- return ofs;
-}
-
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
-{
- unsigned int ofs = mv_scr_offset(sc_reg_in);
-
- if (0xffffffffU != ofs) {
- return readl(mv_ap_base(ap) + ofs);
- } else {
- return (u32) ofs;
- }
-}
-
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
-{
- unsigned int ofs = mv_scr_offset(sc_reg_in);
-
- if (0xffffffffU != ofs) {
- writelfl(val, mv_ap_base(ap) + ofs);
- }
-}
-
-/**
- * mv_host_stop - Host specific cleanup/stop routine.
- * @host_set: host data structure
- *
- * Disable ints, cleanup host memory, call general purpose
- * host_stop.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_host_stop(struct ata_host_set *host_set)
-{
- struct mv_host_priv *hpriv = host_set->private_data;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
-
- if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
- kfree(hpriv);
- ata_host_stop(host_set);
-}
-
-static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
-{
- dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
-}
-
-static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
-{
- u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
-
- /* set up non-NCQ EDMA configuration */
- cfg &= ~0x1f; /* clear queue depth */
- cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
- cfg &= ~(1 << 9); /* disable equeue */
-
- if (IS_GEN_I(hpriv))
- cfg |= (1 << 8); /* enab config burst size mask */
-
- else if (IS_GEN_II(hpriv))
- cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
-
- else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* dis RX PM port mask */
- cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
- cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
- cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab host q cache */
- cfg |= (1 << 22); /* enab cutthrough */
- }
-
- writelfl(cfg, port_mmio + EDMA_CFG_OFS);
-}
-
-/**
- * mv_port_start - Port specific init/start routine.
- * @ap: ATA channel to manipulate
- *
- * Allocate and point to DMA memory, init port private memory,
- * zero indices.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static int mv_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct mv_host_priv *hpriv = ap->host_set->private_data;
- struct mv_port_priv *pp;
- void __iomem *port_mmio = mv_ap_base(ap);
- void *mem;
- dma_addr_t mem_dma;
- int rc = -ENOMEM;
-
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp)
- goto err_out;
- memset(pp, 0, sizeof(*pp));
-
- mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
- if (!mem)
- goto err_out_pp;
- memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
-
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- goto err_out_priv;
-
- /* First item in chunk of DMA memory:
- * 32-slot command request table (CRQB), 32 bytes each in size
- */
- pp->crqb = mem;
- pp->crqb_dma = mem_dma;
- mem += MV_CRQB_Q_SZ;
- mem_dma += MV_CRQB_Q_SZ;
-
- /* Second item:
- * 32-slot command response table (CRPB), 8 bytes each in size
- */
- pp->crpb = mem;
- pp->crpb_dma = mem_dma;
- mem += MV_CRPB_Q_SZ;
- mem_dma += MV_CRPB_Q_SZ;
-
- /* Third item:
- * Table of scatter-gather descriptors (ePRD), 16 bytes each
- */
- pp->sg_tbl = mem;
- pp->sg_tbl_dma = mem_dma;
-
- mv_edma_cfg(hpriv, port_mmio);
-
- writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
- writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
- port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl(pp->crqb_dma & 0xffffffff,
- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- else
- writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
-
- writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl(pp->crpb_dma & 0xffffffff,
- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
- else
- writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
-
- writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
- port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
-
- /* Don't turn on EDMA here...do it before DMA commands only. Else
- * we'll be unable to send non-data, PIO, etc due to restricted access
- * to shadow regs.
- */
- ap->private_data = pp;
- return 0;
-
-err_out_priv:
- mv_priv_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
-}
-
-/**
- * mv_port_stop - Port specific cleanup/stop routine.
- * @ap: ATA channel to manipulate
- *
- * Stop DMA, cleanup port memory.
- *
- * LOCKING:
- * This routine uses the host_set lock to protect the DMA stop.
- */
-static void mv_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct mv_port_priv *pp = ap->private_data;
- unsigned long flags;
-
- spin_lock_irqsave(&ap->host_set->lock, flags);
- mv_stop_dma(ap);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- ap->private_data = NULL;
- ata_pad_free(ap, dev);
- mv_priv_free(pp, dev);
- kfree(pp);
-}
-
-/**
- * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
- * @qc: queued command whose SG list to source from
- *
- * Populate the SG list and mark the last entry.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_fill_sg(struct ata_queued_cmd *qc)
-{
- struct mv_port_priv *pp = qc->ap->private_data;
- unsigned int i = 0;
- struct scatterlist *sg;
-
- ata_for_each_sg(sg, qc) {
- dma_addr_t addr;
- u32 sg_len, len, offset;
-
- addr = sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & MV_DMA_BOUNDARY;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
-
- pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
- pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
- pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
-
- sg_len -= len;
- addr += len;
-
- if (!sg_len && ata_sg_is_last(sg, qc))
- pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
- i++;
- }
- }
-}
-
-static inline unsigned mv_inc_q_index(unsigned index)
-{
- return (index + 1) & MV_MAX_Q_DEPTH_MASK;
-}
-
-static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
-{
- u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
- (last ? CRQB_CMD_LAST : 0);
- *cmdw = cpu_to_le16(tmp);
-}
-
-/**
- * mv_qc_prep - Host specific command preparation.
- * @qc: queued command to prepare
- *
- * This routine simply redirects to the general purpose routine
- * if command is not DMA. Else, it handles prep of the CRQB
- * (command request block), does some sanity checking, and calls
- * the SG load routine.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_qc_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct mv_port_priv *pp = ap->private_data;
- __le16 *cw;
- struct ata_taskfile *tf;
- u16 flags = 0;
- unsigned in_index;
-
- if (ATA_PROT_DMA != qc->tf.protocol)
- return;
-
- /* Fill in command request block
- */
- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
- flags |= CRQB_FLAG_READ;
- WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
- flags |= qc->tag << CRQB_TAG_SHIFT;
-
- /* get current queue index from hardware */
- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
-
- pp->crqb[in_index].sg_addr =
- cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
- pp->crqb[in_index].sg_addr_hi =
- cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
- pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
-
- cw = &pp->crqb[in_index].ata_cmd[0];
- tf = &qc->tf;
-
- /* Sadly, the CRQB cannot accomodate all registers--there are
- * only 11 bytes...so we must pick and choose required
- * registers based on the command. So, we drop feature and
- * hob_feature for [RW] DMA commands, but they are needed for
- * NCQ. NCQ will drop hob_nsect.
- */
- switch (tf->command) {
- case ATA_CMD_READ:
- case ATA_CMD_READ_EXT:
- case ATA_CMD_WRITE:
- case ATA_CMD_WRITE_EXT:
- case ATA_CMD_WRITE_FUA_EXT:
- mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
- break;
-#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
- case ATA_CMD_FPDMA_READ:
- case ATA_CMD_FPDMA_WRITE:
- mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
- mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
- break;
-#endif /* FIXME: remove this line when NCQ added */
- default:
- /* The only other commands EDMA supports in non-queued and
- * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
- * of which are defined/used by Linux. If we get here, this
- * driver needs work.
- *
- * FIXME: modify libata to give qc_prep a return value and
- * return error here.
- */
- BUG_ON(tf->command);
- break;
- }
- mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
- mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
- mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
- mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
- mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
- mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
- mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
- mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
- mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
-
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
- mv_fill_sg(qc);
-}
-
-/**
- * mv_qc_prep_iie - Host specific command preparation.
- * @qc: queued command to prepare
- *
- * This routine simply redirects to the general purpose routine
- * if command is not DMA. Else, it handles prep of the CRQB
- * (command request block), does some sanity checking, and calls
- * the SG load routine.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct mv_port_priv *pp = ap->private_data;
- struct mv_crqb_iie *crqb;
- struct ata_taskfile *tf;
- unsigned in_index;
- u32 flags = 0;
-
- if (ATA_PROT_DMA != qc->tf.protocol)
- return;
-
- /* Fill in Gen IIE command request block
- */
- if (!(qc->tf.flags & ATA_TFLAG_WRITE))
- flags |= CRQB_FLAG_READ;
-
- WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
- flags |= qc->tag << CRQB_TAG_SHIFT;
-
- /* get current queue index from hardware */
- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
-
- crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
- crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
- crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
- crqb->flags = cpu_to_le32(flags);
-
- tf = &qc->tf;
- crqb->ata_cmd[0] = cpu_to_le32(
- (tf->command << 16) |
- (tf->feature << 24)
- );
- crqb->ata_cmd[1] = cpu_to_le32(
- (tf->lbal << 0) |
- (tf->lbam << 8) |
- (tf->lbah << 16) |
- (tf->device << 24)
- );
- crqb->ata_cmd[2] = cpu_to_le32(
- (tf->hob_lbal << 0) |
- (tf->hob_lbam << 8) |
- (tf->hob_lbah << 16) |
- (tf->hob_feature << 24)
- );
- crqb->ata_cmd[3] = cpu_to_le32(
- (tf->nsect << 0) |
- (tf->hob_nsect << 8)
- );
-
- if (!(qc->flags & ATA_QCFLAG_DMAMAP))
- return;
- mv_fill_sg(qc);
-}
-
-/**
- * mv_qc_issue - Initiate a command to the host
- * @qc: queued command to start
- *
- * This routine simply redirects to the general purpose routine
- * if command is not DMA. Else, it sanity checks our local
- * caches of the request producer/consumer indices then enables
- * DMA and bumps the request producer index.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
-{
- void __iomem *port_mmio = mv_ap_base(qc->ap);
- struct mv_port_priv *pp = qc->ap->private_data;
- unsigned in_index;
- u32 in_ptr;
-
- if (ATA_PROT_DMA != qc->tf.protocol) {
- /* We're about to send a non-EDMA capable command to the
- * port. Turn off EDMA so there won't be problems accessing
- * shadow block, etc registers.
- */
- mv_stop_dma(qc->ap);
- return ata_qc_issue_prot(qc);
- }
-
- in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
- in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
-
- /* until we do queuing, the queue should be empty at this point */
- WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
-
- in_index = mv_inc_q_index(in_index); /* now incr producer index */
-
- mv_start_dma(port_mmio, pp);
-
- /* and write the request in pointer to kick the EDMA to life */
- in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
- in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
- writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- return 0;
-}
-
-/**
- * mv_get_crpb_status - get status from most recently completed cmd
- * @ap: ATA channel to manipulate
- *
- * This routine is for use when the port is in DMA mode, when it
- * will be using the CRPB (command response block) method of
- * returning command completion information. We check indices
- * are good, grab status, and bump the response consumer index to
- * prove that we're up to date.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 mv_get_crpb_status(struct ata_port *ap)
-{
- void __iomem *port_mmio = mv_ap_base(ap);
- struct mv_port_priv *pp = ap->private_data;
- unsigned out_index;
- u32 out_ptr;
- u8 ata_status;
-
- out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
- out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
-
- ata_status = le16_to_cpu(pp->crpb[out_index].flags)
- >> CRPB_FLAG_STATUS_SHIFT;
-
- /* increment our consumer index... */
- out_index = mv_inc_q_index(out_index);
-
- /* and, until we do NCQ, there should only be 1 CRPB waiting */
- WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
- >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
-
- /* write out our inc'd consumer index so EDMA knows we're caught up */
- out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
- out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
- writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
-
- /* Return ATA status register for completed CRPB */
- return ata_status;
-}
-
-/**
- * mv_err_intr - Handle error interrupts on the port
- * @ap: ATA channel to manipulate
- * @reset_allowed: bool: 0 == don't trigger from reset here
- *
- * In most cases, just clear the interrupt and move on. However,
- * some cases require an eDMA reset, which is done right before
- * the COMRESET in mv_phy_reset(). The SERR case requires a
- * clear of pending errors in the SATA SERROR register. Finally,
- * if the port disabled DMA, update our cached copy to match.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_err_intr(struct ata_port *ap, int reset_allowed)
-{
- void __iomem *port_mmio = mv_ap_base(ap);
- u32 edma_err_cause, serr = 0;
-
- edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- if (EDMA_ERR_SERR & edma_err_cause) {
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
- }
- if (EDMA_ERR_SELF_DIS & edma_err_cause) {
- struct mv_port_priv *pp = ap->private_data;
- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- }
- DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
- "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
-
- /* Clear EDMA now that SERR cleanup done */
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- /* check for fatal here and recover if needed */
- if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
- mv_stop_and_reset(ap);
-}
-
-/**
- * mv_host_intr - Handle all interrupts on the given host controller
- * @host_set: host specific structure
- * @relevant: port error bits relevant to this host controller
- * @hc: which host controller we're to look at
- *
- * Read then write clear the HC interrupt status then walk each
- * port connected to the HC and see if it needs servicing. Port
- * success ints are reported in the HC interrupt status reg, the
- * port error ints are reported in the higher level main
- * interrupt status register and thus are passed in via the
- * 'relevant' argument.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
- unsigned int hc)
-{
- void __iomem *mmio = host_set->mmio_base;
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
- struct ata_queued_cmd *qc;
- u32 hc_irq_cause;
- int shift, port, port0, hard_port, handled;
- unsigned int err_mask;
-
- if (hc == 0) {
- port0 = 0;
- } else {
- port0 = MV_PORTS_PER_HC;
- }
-
- /* we'll need the HC success int register in most cases */
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- if (hc_irq_cause) {
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
- }
-
- VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
- hc,relevant,hc_irq_cause);
-
- for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
- u8 ata_status = 0;
- struct ata_port *ap = host_set->ports[port];
- struct mv_port_priv *pp = ap->private_data;
-
- hard_port = mv_hardport_from_port(port); /* range 0..3 */
- handled = 0; /* ensure ata_status is set if handled++ */
-
- /* Note that DEV_IRQ might happen spuriously during EDMA,
- * and should be ignored in such cases.
- * The cause of this is still under investigation.
- */
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- /* EDMA: check for response queue interrupt */
- if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
- ata_status = mv_get_crpb_status(ap);
- handled = 1;
- }
- } else {
- /* PIO: check for device (drive) interrupt */
- if ((DEV_IRQ << hard_port) & hc_irq_cause) {
- ata_status = readb((void __iomem *)
- ap->ioaddr.status_addr);
- handled = 1;
- /* ignore spurious intr if drive still BUSY */
- if (ata_status & ATA_BUSY) {
- ata_status = 0;
- handled = 0;
- }
- }
- }
-
- if (ap && (ap->flags & ATA_FLAG_DISABLED))
- continue;
-
- err_mask = ac_err_mask(ata_status);
-
- shift = port << 1; /* (port * 2) */
- if (port >= MV_PORTS_PER_HC) {
- shift++; /* skip bit 8 in the HC Main IRQ reg */
- }
- if ((PORT0_ERR << shift) & relevant) {
- mv_err_intr(ap, 1);
- err_mask |= AC_ERR_OTHER;
- handled = 1;
- }
-
- if (handled) {
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
- VPRINTK("port %u IRQ found for qc, "
- "ata_status 0x%x\n", port,ata_status);
- /* mark qc status appropriately */
- if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
- qc->err_mask |= err_mask;
- ata_qc_complete(qc);
- }
- }
- }
- }
- VPRINTK("EXIT\n");
-}
-
-/**
- * mv_interrupt -
- * @irq: unused
- * @dev_instance: private data; in this case the host structure
- * @regs: unused
- *
- * Read the read only register to determine if any host
- * controllers have pending interrupts. If so, call lower level
- * routine to handle. Also check for PCI errors which are only
- * reported here.
- *
- * LOCKING:
- * This routine holds the host_set lock while processing pending
- * interrupts.
- */
-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = host_set->mmio_base;
- struct mv_host_priv *hpriv;
- u32 irq_stat;
-
- irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
-
- /* check the cases where we either have nothing pending or have read
- * a bogus register value which can indicate HW removal or PCI fault
- */
- if (!irq_stat || (0xffffffffU == irq_stat)) {
- return IRQ_NONE;
- }
-
- n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
- spin_lock(&host_set->lock);
-
- for (hc = 0; hc < n_hcs; hc++) {
- u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
- if (relevant) {
- mv_host_intr(host_set, relevant, hc);
- handled++;
- }
- }
-
- hpriv = host_set->private_data;
- if (IS_60XX(hpriv)) {
- /* deal with the interrupt coalescing bits */
- if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
- }
- }
-
- if (PCI_ERR & irq_stat) {
- printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
- readl(mmio + PCI_IRQ_CAUSE_OFS));
-
- DPRINTK("All regs @ PCI error\n");
- mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev));
-
- writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
- handled++;
- }
- spin_unlock(&host_set->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
-{
- void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
- unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
-
- return hc_mmio + ofs;
-}
-
-static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
-{
- unsigned int ofs;
-
- switch (sc_reg_in) {
- case SCR_STATUS:
- case SCR_ERROR:
- case SCR_CONTROL:
- ofs = sc_reg_in * sizeof(u32);
- break;
- default:
- ofs = 0xffffffffU;
- break;
- }
- return ofs;
-}
-
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
-{
- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
- unsigned int ofs = mv5_scr_offset(sc_reg_in);
-
- if (ofs != 0xffffffffU)
- return readl(mmio + ofs);
- else
- return (u32) ofs;
-}
-
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
-{
- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
- unsigned int ofs = mv5_scr_offset(sc_reg_in);
-
- if (ofs != 0xffffffffU)
- writelfl(val, mmio + ofs);
-}
-
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
-{
- u8 rev_id;
- int early_5080;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
- early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
-
- if (!early_5080) {
- u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
- tmp |= (1 << 0);
- writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
- }
-
- mv_reset_pci_bus(pdev, mmio);
-}
-
-static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
-{
- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
-}
-
-static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
- void __iomem *mmio)
-{
- void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
- u32 tmp;
-
- tmp = readl(phy_mmio + MV5_PHY_MODE);
-
- hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
- hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
-}
-
-static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
-{
- u32 tmp;
-
- writel(0, mmio + MV_GPIO_PORT_CTL);
-
- /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
-
- tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
- tmp |= ~(1 << 0);
- writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
-}
-
-static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port)
-{
- void __iomem *phy_mmio = mv5_phy_base(mmio, port);
- const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
- u32 tmp;
- int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
-
- if (fix_apm_sq) {
- tmp = readl(phy_mmio + MV5_LT_MODE);
- tmp |= (1 << 19);
- writel(tmp, phy_mmio + MV5_LT_MODE);
-
- tmp = readl(phy_mmio + MV5_PHY_CTL);
- tmp &= ~0x3;
- tmp |= 0x1;
- writel(tmp, phy_mmio + MV5_PHY_CTL);
- }
-
- tmp = readl(phy_mmio + MV5_PHY_MODE);
- tmp &= ~mask;
- tmp |= hpriv->signal[port].pre;
- tmp |= hpriv->signal[port].amps;
- writel(tmp, phy_mmio + MV5_PHY_MODE);
-}
-
-
-#undef ZERO
-#define ZERO(reg) writel(0, port_mmio + (reg))
-static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port)
-{
- void __iomem *port_mmio = mv_port_base(mmio, port);
-
- writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
-
- mv_channel_reset(hpriv, mmio, port);
-
- ZERO(0x028); /* command */
- writel(0x11f, port_mmio + EDMA_CFG_OFS);
- ZERO(0x004); /* timer */
- ZERO(0x008); /* irq err cause */
- ZERO(0x00c); /* irq err mask */
- ZERO(0x010); /* rq bah */
- ZERO(0x014); /* rq inp */
- ZERO(0x018); /* rq outp */
- ZERO(0x01c); /* respq bah */
- ZERO(0x024); /* respq outp */
- ZERO(0x020); /* respq inp */
- ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
-}
-#undef ZERO
-
-#define ZERO(reg) writel(0, hc_mmio + (reg))
-static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int hc)
-{
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
- u32 tmp;
-
- ZERO(0x00c);
- ZERO(0x010);
- ZERO(0x014);
- ZERO(0x018);
-
- tmp = readl(hc_mmio + 0x20);
- tmp &= 0x1c1c1c1c;
- tmp |= 0x03030303;
- writel(tmp, hc_mmio + 0x20);
-}
-#undef ZERO
-
-static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int n_hc)
-{
- unsigned int hc, port;
-
- for (hc = 0; hc < n_hc; hc++) {
- for (port = 0; port < MV_PORTS_PER_HC; port++)
- mv5_reset_hc_port(hpriv, mmio,
- (hc * MV_PORTS_PER_HC) + port);
-
- mv5_reset_one_hc(hpriv, mmio, hc);
- }
-
- return 0;
-}
-
-#undef ZERO
-#define ZERO(reg) writel(0, mmio + (reg))
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
-{
- u32 tmp;
-
- tmp = readl(mmio + MV_PCI_MODE);
- tmp &= 0xff00ffff;
- writel(tmp, mmio + MV_PCI_MODE);
-
- ZERO(MV_PCI_DISC_TIMER);
- ZERO(MV_PCI_MSI_TRIGGER);
- writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
- ZERO(HC_MAIN_IRQ_MASK_OFS);
- ZERO(MV_PCI_SERR_MASK);
- ZERO(PCI_IRQ_CAUSE_OFS);
- ZERO(PCI_IRQ_MASK_OFS);
- ZERO(MV_PCI_ERR_LOW_ADDRESS);
- ZERO(MV_PCI_ERR_HIGH_ADDRESS);
- ZERO(MV_PCI_ERR_ATTRIBUTE);
- ZERO(MV_PCI_ERR_COMMAND);
-}
-#undef ZERO
-
-static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
-{
- u32 tmp;
-
- mv5_reset_flash(hpriv, mmio);
-
- tmp = readl(mmio + MV_GPIO_PORT_CTL);
- tmp &= 0x3;
- tmp |= (1 << 5) | (1 << 6);
- writel(tmp, mmio + MV_GPIO_PORT_CTL);
-}
-
-/**
- * mv6_reset_hc - Perform the 6xxx global soft reset
- * @mmio: base address of the HBA
- *
- * This routine only applies to 6xxx parts.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int n_hc)
-{
- void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
- int i, rc = 0;
- u32 t;
-
- /* Following procedure defined in PCI "main command and status
- * register" table.
- */
- t = readl(reg);
- writel(t | STOP_PCI_MASTER, reg);
-
- for (i = 0; i < 1000; i++) {
- udelay(1);
- t = readl(reg);
- if (PCI_MASTER_EMPTY & t) {
- break;
- }
- }
- if (!(PCI_MASTER_EMPTY & t)) {
- printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
- rc = 1;
- goto done;
- }
-
- /* set reset */
- i = 5;
- do {
- writel(t | GLOB_SFT_RST, reg);
- t = readl(reg);
- udelay(1);
- } while (!(GLOB_SFT_RST & t) && (i-- > 0));
-
- if (!(GLOB_SFT_RST & t)) {
- printk(KERN_ERR DRV_NAME ": can't set global reset\n");
- rc = 1;
- goto done;
- }
-
- /* clear reset and *reenable the PCI master* (not mentioned in spec) */
- i = 5;
- do {
- writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
- t = readl(reg);
- udelay(1);
- } while ((GLOB_SFT_RST & t) && (i-- > 0));
-
- if (GLOB_SFT_RST & t) {
- printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
- rc = 1;
- }
-done:
- return rc;
-}
-
-static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
- void __iomem *mmio)
-{
- void __iomem *port_mmio;
- u32 tmp;
-
- tmp = readl(mmio + MV_RESET_CFG);
- if ((tmp & (1 << 0)) == 0) {
- hpriv->signal[idx].amps = 0x7 << 8;
- hpriv->signal[idx].pre = 0x1 << 5;
- return;
- }
-
- port_mmio = mv_port_base(mmio, idx);
- tmp = readl(port_mmio + PHY_MODE2);
-
- hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
- hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
-}
-
-static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
-{
- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
-}
-
-static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port)
-{
- void __iomem *port_mmio = mv_port_base(mmio, port);
-
- u32 hp_flags = hpriv->hp_flags;
- int fix_phy_mode2 =
- hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
- int fix_phy_mode4 =
- hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
- u32 m2, tmp;
-
- if (fix_phy_mode2) {
- m2 = readl(port_mmio + PHY_MODE2);
- m2 &= ~(1 << 16);
- m2 |= (1 << 31);
- writel(m2, port_mmio + PHY_MODE2);
-
- udelay(200);
-
- m2 = readl(port_mmio + PHY_MODE2);
- m2 &= ~((1 << 16) | (1 << 31));
- writel(m2, port_mmio + PHY_MODE2);
-
- udelay(200);
- }
-
- /* who knows what this magic does */
- tmp = readl(port_mmio + PHY_MODE3);
- tmp &= ~0x7F800000;
- tmp |= 0x2A800000;
- writel(tmp, port_mmio + PHY_MODE3);
-
- if (fix_phy_mode4) {
- u32 m4;
-
- m4 = readl(port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- tmp = readl(port_mmio + 0x310);
-
- m4 = (m4 & ~(1 << 1)) | (1 << 0);
-
- writel(m4, port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- writel(tmp, port_mmio + 0x310);
- }
-
- /* Revert values of pre-emphasis and signal amps to the saved ones */
- m2 = readl(port_mmio + PHY_MODE2);
-
- m2 &= ~MV_M2_PREAMP_MASK;
- m2 |= hpriv->signal[port].amps;
- m2 |= hpriv->signal[port].pre;
- m2 &= ~(1 << 16);
-
- /* according to mvSata 3.6.1, some IIE values are fixed */
- if (IS_GEN_IIE(hpriv)) {
- m2 &= ~0xC30FF01F;
- m2 |= 0x0000900F;
- }
-
- writel(m2, port_mmio + PHY_MODE2);
-}
-
-static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
- unsigned int port_no)
-{
- void __iomem *port_mmio = mv_port_base(mmio, port_no);
-
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
-
- if (IS_60XX(hpriv)) {
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
- ifctl |= (1 << 7); /* enable gen2i speed */
- ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
- }
-
- udelay(25); /* allow reset propagation */
-
- /* Spec never mentions clearing the bit. Marvell's driver does
- * clear the bit, however.
- */
- writelfl(0, port_mmio + EDMA_CMD_OFS);
-
- hpriv->ops->phy_errata(hpriv, mmio, port_no);
-
- if (IS_50XX(hpriv))
- mdelay(1);
-}
-
-static void mv_stop_and_reset(struct ata_port *ap)
-{
- struct mv_host_priv *hpriv = ap->host_set->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
-
- mv_stop_dma(ap);
-
- mv_channel_reset(hpriv, mmio, ap->port_no);
-
- __mv_phy_reset(ap, 0);
-}
-
-static inline void __msleep(unsigned int msec, int can_sleep)
-{
- if (can_sleep)
- msleep(msec);
- else
- mdelay(msec);
-}
-
-/**
- * __mv_phy_reset - Perform eDMA reset followed by COMRESET
- * @ap: ATA channel to manipulate
- *
- * Part of this is taken from __sata_phy_reset and modified to
- * not sleep since this routine gets called from interrupt level.
- *
- * LOCKING:
- * Inherited from caller. This is coded to safe to call at
- * interrupt level, i.e. it does not sleep.
- */
-static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
-{
- struct mv_port_priv *pp = ap->private_data;
- struct mv_host_priv *hpriv = ap->host_set->private_data;
- void __iomem *port_mmio = mv_ap_base(ap);
- struct ata_taskfile tf;
- struct ata_device *dev = &ap->device[0];
- unsigned long timeout;
- int retry = 5;
- u32 sstatus;
-
- VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
-
- DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
-
- /* Issue COMRESET via SControl */
-comreset_retry:
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
- __msleep(1, can_sleep);
-
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
- __msleep(20, can_sleep);
-
- timeout = jiffies + msecs_to_jiffies(200);
- do {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
- sstatus &= 0x3;
- if ((sstatus == 3) || (sstatus == 0))
- break;
-
- __msleep(1, can_sleep);
- } while (time_before(jiffies, timeout));
-
- /* work around errata */
- if (IS_60XX(hpriv) &&
- (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
- (retry-- > 0))
- goto comreset_retry;
-
- DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
-
- if (ata_port_online(ap)) {
- ata_port_probe(ap);
- } else {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
- ata_port_printk(ap, KERN_INFO,
- "no device found (phy stat %08x)\n", sstatus);
- ata_port_disable(ap);
- return;
- }
- ap->cbl = ATA_CBL_SATA;
-
- /* even after SStatus reflects that device is ready,
- * it seems to take a while for link to be fully
- * established (and thus Status no longer 0x80/0x7F),
- * so we poll a bit for that, here.
- */
- retry = 20;
- while (1) {
- u8 drv_stat = ata_check_status(ap);
- if ((drv_stat != 0x80) && (drv_stat != 0x7f))
- break;
- __msleep(500, can_sleep);
- if (retry-- <= 0)
- break;
- }
-
- tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
- tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
- tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
- tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
-
- dev->class = ata_dev_classify(&tf);
- if (!ata_dev_enabled(dev)) {
- VPRINTK("Port disabled post-sig: No device present.\n");
- ata_port_disable(ap);
- }
-
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-
- VPRINTK("EXIT\n");
-}
-
-static void mv_phy_reset(struct ata_port *ap)
-{
- __mv_phy_reset(ap, 1);
-}
-
-/**
- * mv_eng_timeout - Routine called by libata when SCSI times out I/O
- * @ap: ATA channel to manipulate
- *
- * Intent is to clear all pending error conditions, reset the
- * chip/bus, fail the command, and move on.
- *
- * LOCKING:
- * This routine holds the host_set lock while failing the command.
- */
-static void mv_eng_timeout(struct ata_port *ap)
-{
- struct ata_queued_cmd *qc;
- unsigned long flags;
-
- ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
- DPRINTK("All regs @ start of eng_timeout\n");
- mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
- to_pci_dev(ap->host_set->dev));
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
- ap->host_set->mmio_base, ap, qc, qc->scsicmd,
- &qc->scsicmd->cmnd);
-
- spin_lock_irqsave(&ap->host_set->lock, flags);
- mv_err_intr(ap, 0);
- mv_stop_and_reset(ap);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
- if (qc->flags & ATA_QCFLAG_ACTIVE) {
- qc->err_mask |= AC_ERR_TIMEOUT;
- ata_eh_qc_complete(qc);
- }
-}
-
-/**
- * mv_port_init - Perform some early initialization on a single port.
- * @port: libata data structure storing shadow register addresses
- * @port_mmio: base address of the port
- *
- * Initialize shadow register mmio addresses, clear outstanding
- * interrupts on the port, and unmask interrupts for the future
- * start of the port.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
-{
- unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
- unsigned serr_ofs;
-
- /* PIO related setup
- */
- port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
- port->error_addr =
- port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
- port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
- port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
- port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
- port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
- port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
- port->status_addr =
- port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
- /* special case: control/altstatus doesn't have ATA_REG_ address */
- port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
-
- /* unused: */
- port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
-
- /* Clear any currently outstanding port interrupt conditions */
- serr_ofs = mv_scr_offset(SCR_ERROR);
- writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
-
- /* unmask all EDMA error interrupts */
- writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
-
- VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
- readl(port_mmio + EDMA_CFG_OFS),
- readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
- readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
-}
-
-static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
- unsigned int board_idx)
-{
- u8 rev_id;
- u32 hp_flags = hpriv->hp_flags;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
- switch(board_idx) {
- case chip_5080:
- hpriv->ops = &mv5xxx_ops;
- hp_flags |= MV_HP_50XX;
-
- switch (rev_id) {
- case 0x1:
- hp_flags |= MV_HP_ERRATA_50XXB0;
- break;
- case 0x3:
- hp_flags |= MV_HP_ERRATA_50XXB2;
- break;
- default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying 50XXB2 workarounds to unknown rev\n");
- hp_flags |= MV_HP_ERRATA_50XXB2;
- break;
- }
- break;
-
- case chip_504x:
- case chip_508x:
- hpriv->ops = &mv5xxx_ops;
- hp_flags |= MV_HP_50XX;
-
- switch (rev_id) {
- case 0x0:
- hp_flags |= MV_HP_ERRATA_50XXB0;
- break;
- case 0x3:
- hp_flags |= MV_HP_ERRATA_50XXB2;
- break;
- default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying B2 workarounds to unknown rev\n");
- hp_flags |= MV_HP_ERRATA_50XXB2;
- break;
- }
- break;
-
- case chip_604x:
- case chip_608x:
- hpriv->ops = &mv6xxx_ops;
-
- switch (rev_id) {
- case 0x7:
- hp_flags |= MV_HP_ERRATA_60X1B2;
- break;
- case 0x9:
- hp_flags |= MV_HP_ERRATA_60X1C0;
- break;
- default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying B2 workarounds to unknown rev\n");
- hp_flags |= MV_HP_ERRATA_60X1B2;
- break;
- }
- break;
-
- case chip_7042:
- case chip_6042:
- hpriv->ops = &mv6xxx_ops;
-
- hp_flags |= MV_HP_GEN_IIE;
-
- switch (rev_id) {
- case 0x0:
- hp_flags |= MV_HP_ERRATA_XX42A0;
- break;
- case 0x1:
- hp_flags |= MV_HP_ERRATA_60X1C0;
- break;
- default:
- dev_printk(KERN_WARNING, &pdev->dev,
- "Applying 60X1C0 workarounds to unknown rev\n");
- hp_flags |= MV_HP_ERRATA_60X1C0;
- break;
- }
- break;
-
- default:
- printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
- return 1;
- }
-
- hpriv->hp_flags = hp_flags;
-
- return 0;
-}
-
-/**
- * mv_init_host - Perform some early initialization of the host.
- * @pdev: host PCI device
- * @probe_ent: early data struct representing the host
- *
- * If possible, do an early global reset of the host. Then do
- * our port init and clear/unmask all/relevant host interrupts.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
- unsigned int board_idx)
-{
- int rc = 0, n_hc, port, hc;
- void __iomem *mmio = probe_ent->mmio_base;
- struct mv_host_priv *hpriv = probe_ent->private_data;
-
- /* global interrupt mask */
- writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
-
- rc = mv_chip_id(pdev, hpriv, board_idx);
- if (rc)
- goto done;
-
- n_hc = mv_get_hc_count(probe_ent->host_flags);
- probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
-
- for (port = 0; port < probe_ent->n_ports; port++)
- hpriv->ops->read_preamp(hpriv, port, mmio);
-
- rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
- if (rc)
- goto done;
-
- hpriv->ops->reset_flash(hpriv, mmio);
- hpriv->ops->reset_bus(pdev, mmio);
- hpriv->ops->enable_leds(hpriv, mmio);
-
- for (port = 0; port < probe_ent->n_ports; port++) {
- if (IS_60XX(hpriv)) {
- void __iomem *port_mmio = mv_port_base(mmio, port);
-
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
- ifctl |= (1 << 7); /* enable gen2i speed */
- ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
- }
-
- hpriv->ops->phy_errata(hpriv, mmio, port);
- }
-
- for (port = 0; port < probe_ent->n_ports; port++) {
- void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&probe_ent->port[port], port_mmio);
- }
-
- for (hc = 0; hc < n_hc; hc++) {
- void __iomem *hc_mmio = mv_hc_base(mmio, hc);
-
- VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
- "(before clear)=0x%08x\n", hc,
- readl(hc_mmio + HC_CFG_OFS),
- readl(hc_mmio + HC_IRQ_CAUSE_OFS));
-
- /* Clear any currently outstanding hc interrupt conditions */
- writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
- }
-
- /* Clear any currently outstanding host interrupt conditions */
- writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
-
- /* and unmask interrupt generation for host regs */
- writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
- writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
-
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
- "PCI int cause/mask=0x%08x/0x%08x\n",
- readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
- readl(mmio + HC_MAIN_IRQ_MASK_OFS),
- readl(mmio + PCI_IRQ_CAUSE_OFS),
- readl(mmio + PCI_IRQ_MASK_OFS));
-
-done:
- return rc;
-}
-
-/**
- * mv_print_info - Dump key info to kernel log for perusal.
- * @probe_ent: early data struct representing the host
- *
- * FIXME: complete this.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_print_info(struct ata_probe_ent *probe_ent)
-{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- struct mv_host_priv *hpriv = probe_ent->private_data;
- u8 rev_id, scc;
- const char *scc_s;
-
- /* Use this to determine the HW stepping of the chip so we know
- * what errata to workaround
- */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
- pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
- if (scc == 0)
- scc_s = "SCSI";
- else if (scc == 0x01)
- scc_s = "RAID";
- else
- scc_s = "unknown";
-
- dev_printk(KERN_INFO, &pdev->dev,
- "%u slots %u ports %s mode IRQ via %s\n",
- (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
- scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
-}
-
-/**
- * mv_init_one - handle a positive probe of a Marvell host
- * @pdev: PCI device found
- * @ent: PCI device ID entry for the matched host
- *
- * LOCKING:
- * Inherited from caller.
- */
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version = 0;
- struct ata_probe_ent *probe_ent = NULL;
- struct mv_host_priv *hpriv;
- unsigned int board_idx = (unsigned int)ent->driver_data;
- void __iomem *mmio_base;
- int pci_dev_busy = 0, rc;
-
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc) {
- return rc;
- }
- pci_set_master(pdev);
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- probe_ent->sht = mv_port_info[board_idx].sht;
- probe_ent->host_flags = mv_port_info[board_idx].host_flags;
- probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
- probe_ent->port_ops = mv_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
- probe_ent->private_data = hpriv;
-
- /* initialize adapter */
- rc = mv_init_host(pdev, probe_ent, board_idx);
- if (rc) {
- goto err_out_hpriv;
- }
-
- /* Enable interrupts */
- if (msi && pci_enable_msi(pdev) == 0) {
- hpriv->hp_flags |= MV_HP_FLAG_MSI;
- } else {
- pci_intx(pdev, 1);
- }
-
- mv_dump_pci_cfg(pdev, 0x68);
- mv_print_info(probe_ent);
-
- if (ata_device_add(probe_ent) == 0) {
- rc = -ENODEV; /* No devices discovered */
- goto err_out_dev_add;
- }
-
- kfree(probe_ent);
- return 0;
-
-err_out_dev_add:
- if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy) {
- pci_disable_device(pdev);
- }
-
- return rc;
-}
-
-static int __init mv_init(void)
-{
- return pci_module_init(&mv_pci_driver);
-}
-
-static void __exit mv_exit(void)
-{
- pci_unregister_driver(&mv_pci_driver);
-}
-
-MODULE_AUTHOR("Brett Russ");
-MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
-
-module_init(mv_init);
-module_exit(mv_exit);
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
deleted file mode 100644
index d18e7e0932e..00000000000
--- a/drivers/scsi/sata_nv.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * sata_nv.c - NVIDIA nForce SATA
- *
- * Copyright 2004 NVIDIA Corp. All rights reserved.
- * Copyright 2004 Andrew Chew
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * No hardware documentation available outside of NVIDIA.
- * This driver programs the NVIDIA SATA controller in a similar
- * fashion as with other PCI IDE BMDMA controllers, with a few
- * NV-specific details such as register offsets, SATA phy location,
- * hotplug info, etc.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_nv"
-#define DRV_VERSION "0.9"
-
-enum {
- NV_PORTS = 2,
- NV_PIO_MASK = 0x1f,
- NV_MWDMA_MASK = 0x07,
- NV_UDMA_MASK = 0x7f,
- NV_PORT0_SCR_REG_OFFSET = 0x00,
- NV_PORT1_SCR_REG_OFFSET = 0x40,
-
- /* INT_STATUS/ENABLE */
- NV_INT_STATUS = 0x10,
- NV_INT_ENABLE = 0x11,
- NV_INT_STATUS_CK804 = 0x440,
- NV_INT_ENABLE_CK804 = 0x441,
-
- /* INT_STATUS/ENABLE bits */
- NV_INT_DEV = 0x01,
- NV_INT_PM = 0x02,
- NV_INT_ADDED = 0x04,
- NV_INT_REMOVED = 0x08,
-
- NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */
-
- NV_INT_ALL = 0x0f,
- NV_INT_MASK = NV_INT_DEV |
- NV_INT_ADDED | NV_INT_REMOVED,
-
- /* INT_CONFIG */
- NV_INT_CONFIG = 0x12,
- NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
-
- // For PCI config register 20
- NV_MCP_SATA_CFG_20 = 0x50,
- NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04,
-};
-
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void nv_ck804_host_stop(struct ata_host_set *host_set);
-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-
-static void nv_nf2_freeze(struct ata_port *ap);
-static void nv_nf2_thaw(struct ata_port *ap);
-static void nv_ck804_freeze(struct ata_port *ap);
-static void nv_ck804_thaw(struct ata_port *ap);
-static void nv_error_handler(struct ata_port *ap);
-
-enum nv_host_type
-{
- GENERIC,
- NFORCE2,
- NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
- CK804
-};
-
-static const struct pci_device_id nv_pci_tbl[] = {
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
- { 0, } /* terminate list */
-};
-
-static struct pci_driver nv_pci_driver = {
- .name = DRV_NAME,
- .id_table = nv_pci_tbl,
- .probe = nv_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static struct scsi_host_template nv_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations nv_generic_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .exec_command = ata_exec_command,
- .check_status = ata_check_status,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = nv_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
- .irq_handler = nv_generic_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = nv_scr_read,
- .scr_write = nv_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
-};
-
-static const struct ata_port_operations nv_nf2_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .exec_command = ata_exec_command,
- .check_status = ata_check_status,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .freeze = nv_nf2_freeze,
- .thaw = nv_nf2_thaw,
- .error_handler = nv_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
- .irq_handler = nv_nf2_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = nv_scr_read,
- .scr_write = nv_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
-};
-
-static const struct ata_port_operations nv_ck804_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .exec_command = ata_exec_command,
- .check_status = ata_check_status,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .freeze = nv_ck804_freeze,
- .thaw = nv_ck804_thaw,
- .error_handler = nv_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
- .irq_handler = nv_ck804_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = nv_scr_read,
- .scr_write = nv_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = nv_ck804_host_stop,
-};
-
-static struct ata_port_info nv_port_info[] = {
- /* generic */
- {
- .sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = NV_PIO_MASK,
- .mwdma_mask = NV_MWDMA_MASK,
- .udma_mask = NV_UDMA_MASK,
- .port_ops = &nv_generic_ops,
- },
- /* nforce2/3 */
- {
- .sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = NV_PIO_MASK,
- .mwdma_mask = NV_MWDMA_MASK,
- .udma_mask = NV_UDMA_MASK,
- .port_ops = &nv_nf2_ops,
- },
- /* ck804 */
- {
- .sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = NV_PIO_MASK,
- .mwdma_mask = NV_MWDMA_MASK,
- .udma_mask = NV_UDMA_MASK,
- .port_ops = &nv_ck804_ops,
- },
-};
-
-MODULE_AUTHOR("NVIDIA");
-MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int i;
- unsigned int handled = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&host_set->lock, flags);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap;
-
- ap = host_set->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += ata_host_intr(ap, qc);
- else
- // No request pending? Clear interrupt status
- // anyway, in case there's one pending.
- ap->ops->check_status(ap);
- }
-
- }
-
- spin_unlock_irqrestore(&host_set->lock, flags);
-
- return IRQ_RETVAL(handled);
-}
-
-static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
-{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
- int handled;
-
- /* freeze if hotplugged */
- if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
- ata_port_freeze(ap);
- return 1;
- }
-
- /* bail out if not our interrupt */
- if (!(irq_stat & NV_INT_DEV))
- return 0;
-
- /* DEV interrupt w/ no active qc? */
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ata_check_status(ap);
- return 1;
- }
-
- /* handle interrupt */
- handled = ata_host_intr(ap, qc);
- if (unlikely(!handled)) {
- /* spurious, clear it */
- ata_check_status(ap);
- }
-
- return 1;
-}
-
-static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
-{
- int i, handled = 0;
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
-
- if (ap && !(ap->flags & ATA_FLAG_DISABLED))
- handled += nv_host_intr(ap, irq_stat);
-
- irq_stat >>= NV_INT_PORT_SHIFT;
- }
-
- return IRQ_RETVAL(handled);
-}
-
-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- u8 irq_stat;
- irqreturn_t ret;
-
- spin_lock(&host_set->lock);
- irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
- ret = nv_do_interrupt(host_set, irq_stat);
- spin_unlock(&host_set->lock);
-
- return ret;
-}
-
-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- u8 irq_stat;
- irqreturn_t ret;
-
- spin_lock(&host_set->lock);
- irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
- ret = nv_do_interrupt(host_set, irq_stat);
- spin_unlock(&host_set->lock);
-
- return ret;
-}
-
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
-
- return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
-
- iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-static void nv_nf2_freeze(struct ata_port *ap)
-{
- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
- int shift = ap->port_no * NV_INT_PORT_SHIFT;
- u8 mask;
-
- mask = inb(scr_addr + NV_INT_ENABLE);
- mask &= ~(NV_INT_ALL << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
-}
-
-static void nv_nf2_thaw(struct ata_port *ap)
-{
- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
- int shift = ap->port_no * NV_INT_PORT_SHIFT;
- u8 mask;
-
- outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
-
- mask = inb(scr_addr + NV_INT_ENABLE);
- mask |= (NV_INT_MASK << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
-}
-
-static void nv_ck804_freeze(struct ata_port *ap)
-{
- void __iomem *mmio_base = ap->host_set->mmio_base;
- int shift = ap->port_no * NV_INT_PORT_SHIFT;
- u8 mask;
-
- mask = readb(mmio_base + NV_INT_ENABLE_CK804);
- mask &= ~(NV_INT_ALL << shift);
- writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
-}
-
-static void nv_ck804_thaw(struct ata_port *ap)
-{
- void __iomem *mmio_base = ap->host_set->mmio_base;
- int shift = ap->port_no * NV_INT_PORT_SHIFT;
- u8 mask;
-
- writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);
-
- mask = readb(mmio_base + NV_INT_ENABLE_CK804);
- mask |= (NV_INT_MASK << shift);
- writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
-}
-
-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
-{
- unsigned int dummy;
-
- /* SATA hardreset fails to retrieve proper device signature on
- * some controllers. Don't classify on hardreset. For more
- * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
- */
- return sata_std_hardreset(ap, &dummy);
-}
-
-static void nv_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
- nv_hardreset, ata_std_postreset);
-}
-
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version = 0;
- struct ata_port_info *ppi;
- struct ata_probe_ent *probe_ent;
- int pci_dev_busy = 0;
- int rc;
- u32 bar;
- unsigned long base;
-
- // Make sure this is a SATA controller by counting the number of bars
- // (NVIDIA SATA controllers will always have six bars). Otherwise,
- // it's an IDE controller and we ignore it.
- for (bar=0; bar<6; bar++)
- if (pci_resource_start(pdev, bar) == 0)
- return -ENODEV;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- goto err_out;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out_disable;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- rc = -ENOMEM;
-
- ppi = &nv_port_info[ent->driver_data];
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- goto err_out_regions;
-
- probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
- if (!probe_ent->mmio_base) {
- rc = -EIO;
- goto err_out_free_ent;
- }
-
- base = (unsigned long)probe_ent->mmio_base;
-
- probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
- probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
-
- /* enable SATA space for CK804 */
- if (ent->driver_data == CK804) {
- u8 regval;
-
- pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
- regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
- pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
- }
-
- pci_set_master(pdev);
-
- rc = ata_device_add(probe_ent);
- if (rc != NV_PORTS)
- goto err_out_iounmap;
-
- kfree(probe_ent);
-
- return 0;
-
-err_out_iounmap:
- pci_iounmap(pdev, probe_ent->mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out_disable:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
-err_out:
- return rc;
-}
-
-static void nv_ck804_host_stop(struct ata_host_set *host_set)
-{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
- u8 regval;
-
- /* disable SATA space for CK804 */
- pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
- regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
- pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
-
- ata_pci_host_stop(host_set);
-}
-
-static int __init nv_init(void)
-{
- return pci_module_init(&nv_pci_driver);
-}
-
-static void __exit nv_exit(void)
-{
- pci_unregister_driver(&nv_pci_driver);
-}
-
-module_init(nv_init);
-module_exit(nv_exit);
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
deleted file mode 100644
index b2b6ed5216e..00000000000
--- a/drivers/scsi/sata_promise.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * sata_promise.c - Promise SATA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2004 Red Hat, 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware information only available under NDA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-#include "sata_promise.h"
-
-#define DRV_NAME "sata_promise"
-#define DRV_VERSION "1.04"
-
-
-enum {
- PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
- PDC_TBG_MODE = 0x41, /* TBG mode */
- PDC_FLASH_CTL = 0x44, /* Flash control register */
- PDC_PCI_CTL = 0x48, /* PCI control and status register */
- PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
- PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
- PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
- PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
- PDC_SLEW_CTL = 0x470, /* slew rate control reg */
-
- PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
- (1<<8) | (1<<9) | (1<<10),
-
- board_2037x = 0, /* FastTrak S150 TX2plus */
- board_20319 = 1, /* FastTrak S150 TX4 */
- board_20619 = 2, /* FastTrak TX4000 */
- board_20771 = 3, /* FastTrak TX2300 */
- board_2057x = 4, /* SATAII150 Tx2plus */
- board_40518 = 5, /* SATAII150 Tx4 */
-
- PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
-
- PDC_RESET = (1 << 11), /* HDMA reset */
-
- PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
- ATA_FLAG_PIO_POLLING,
-};
-
-
-struct pdc_port_priv {
- u8 *pkt;
- dma_addr_t pkt_dma;
-};
-
-struct pdc_host_priv {
- int hotplug_offset;
-};
-
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void pdc_eng_timeout(struct ata_port *ap);
-static int pdc_port_start(struct ata_port *ap);
-static void pdc_port_stop(struct ata_port *ap);
-static void pdc_pata_phy_reset(struct ata_port *ap);
-static void pdc_sata_phy_reset(struct ata_port *ap);
-static void pdc_qc_prep(struct ata_queued_cmd *qc);
-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc_irq_clear(struct ata_port *ap);
-static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
-static void pdc_host_stop(struct ata_host_set *host_set);
-
-
-static struct scsi_host_template pdc_ata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations pdc_sata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = pdc_tf_load_mmio,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = pdc_exec_command_mmio,
- .dev_select = ata_std_dev_select,
-
- .phy_reset = pdc_sata_phy_reset,
-
- .qc_prep = pdc_qc_prep,
- .qc_issue = pdc_qc_issue_prot,
- .eng_timeout = pdc_eng_timeout,
- .data_xfer = ata_mmio_data_xfer,
- .irq_handler = pdc_interrupt,
- .irq_clear = pdc_irq_clear,
-
- .scr_read = pdc_sata_scr_read,
- .scr_write = pdc_sata_scr_write,
- .port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
-};
-
-static const struct ata_port_operations pdc_pata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = pdc_tf_load_mmio,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = pdc_exec_command_mmio,
- .dev_select = ata_std_dev_select,
-
- .phy_reset = pdc_pata_phy_reset,
-
- .qc_prep = pdc_qc_prep,
- .qc_issue = pdc_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
- .eng_timeout = pdc_eng_timeout,
- .irq_handler = pdc_interrupt,
- .irq_clear = pdc_irq_clear,
-
- .port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
-};
-
-static const struct ata_port_info pdc_port_info[] = {
- /* board_2037x */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
- },
-
- /* board_20319 */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
- },
-
- /* board_20619 */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_pata_ops,
- },
-
- /* board_20771 */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
- },
-
- /* board_2057x */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
- },
-
- /* board_40518 */
- {
- .sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
- },
-};
-
-static const struct pci_device_id pdc_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
-
- { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_40518 },
-
- { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20619 },
-
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20771 },
- { } /* terminate list */
-};
-
-
-static struct pci_driver pdc_ata_pci_driver = {
- .name = DRV_NAME,
- .id_table = pdc_ata_pci_tbl,
- .probe = pdc_ata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-
-static int pdc_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct pdc_port_priv *pp;
- int rc;
-
- rc = ata_port_start(ap);
- if (rc)
- return rc;
-
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
-
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
-
- ap->private_data = pp;
-
- return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
-}
-
-
-static void pdc_host_stop(struct ata_host_set *host_set)
-{
- struct pdc_host_priv *hp = host_set->private_data;
-
- ata_pci_host_stop(host_set);
-
- kfree(hp);
-}
-
-
-static void pdc_reset_port(struct ata_port *ap)
-{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
- unsigned int i;
- u32 tmp;
-
- for (i = 11; i > 0; i--) {
- tmp = readl(mmio);
- if (tmp & PDC_RESET)
- break;
-
- udelay(100);
-
- tmp |= PDC_RESET;
- writel(tmp, mmio);
- }
-
- tmp &= ~PDC_RESET;
- writel(tmp, mmio);
- readl(mmio); /* flush */
-}
-
-static void pdc_sata_phy_reset(struct ata_port *ap)
-{
- pdc_reset_port(ap);
- sata_phy_reset(ap);
-}
-
-static void pdc_pata_cbl_detect(struct ata_port *ap)
-{
- u8 tmp;
- void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
-
- tmp = readb(mmio);
-
- if (tmp & 0x01) {
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
- } else
- ap->cbl = ATA_CBL_PATA80;
-}
-
-static void pdc_pata_phy_reset(struct ata_port *ap)
-{
- pdc_pata_cbl_detect(ap);
- pdc_reset_port(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-static void pdc_qc_prep(struct ata_queued_cmd *qc)
-{
- struct pdc_port_priv *pp = qc->ap->private_data;
- unsigned int i;
-
- VPRINTK("ENTER\n");
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- ata_qc_prep(qc);
- /* fall through */
-
- case ATA_PROT_NODATA:
- i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
- qc->dev->devno, pp->pkt);
-
- if (qc->tf.flags & ATA_TFLAG_LBA48)
- i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
- else
- i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
-
- pdc_pkt_footer(&qc->tf, pp->pkt, i);
- break;
-
- default:
- break;
- }
-}
-
-static void pdc_eng_timeout(struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- u8 drv_stat;
- struct ata_queued_cmd *qc;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- spin_lock_irqsave(&host_set->lock, flags);
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- ata_port_printk(ap, KERN_ERR, "command timeout\n");
- drv_stat = ata_wait_idle(ap);
- qc->err_mask |= __ac_err_mask(drv_stat);
- break;
-
- default:
- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-
- ata_port_printk(ap, KERN_ERR,
- "unknown timeout, cmd 0x%x stat 0x%x\n",
- qc->tf.command, drv_stat);
-
- qc->err_mask |= ac_err_mask(drv_stat);
- break;
- }
-
- spin_unlock_irqrestore(&host_set->lock, flags);
- ata_eh_qc_complete(qc);
- DPRINTK("EXIT\n");
-}
-
-static inline unsigned int pdc_host_intr( struct ata_port *ap,
- struct ata_queued_cmd *qc)
-{
- unsigned int handled = 0;
- u32 tmp;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
-
- tmp = readl(mmio);
- if (tmp & PDC_ERR_MASK) {
- qc->err_mask |= AC_ERR_DEV;
- pdc_reset_port(ap);
- }
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
- ata_qc_complete(qc);
- handled = 1;
- break;
-
- default:
- ap->stats.idle_irq++;
- break;
- }
-
- return handled;
-}
-
-static void pdc_irq_clear(struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
-
- readl(mmio + PDC_INT_SEQMASK);
-}
-
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct ata_port *ap;
- u32 mask = 0;
- unsigned int i, tmp;
- unsigned int handled = 0;
- void __iomem *mmio_base;
-
- VPRINTK("ENTER\n");
-
- if (!host_set || !host_set->mmio_base) {
- VPRINTK("QUICK EXIT\n");
- return IRQ_NONE;
- }
-
- mmio_base = host_set->mmio_base;
-
- /* reading should also clear interrupts */
- mask = readl(mmio_base + PDC_INT_SEQMASK);
-
- if (mask == 0xffffffff) {
- VPRINTK("QUICK EXIT 2\n");
- return IRQ_NONE;
- }
-
- spin_lock(&host_set->lock);
-
- mask &= 0xffff; /* only 16 tags possible */
- if (!mask) {
- VPRINTK("QUICK EXIT 3\n");
- goto done_irq;
- }
-
- writel(mask, mmio_base + PDC_INT_SEQMASK);
-
- for (i = 0; i < host_set->n_ports; i++) {
- VPRINTK("port %u\n", i);
- ap = host_set->ports[i];
- tmp = mask & (1 << (i + 1));
- if (tmp && ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += pdc_host_intr(ap, qc);
- }
- }
-
- VPRINTK("EXIT\n");
-
-done_irq:
- spin_unlock(&host_set->lock);
- return IRQ_RETVAL(handled);
-}
-
-static inline void pdc_packet_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_port_priv *pp = ap->private_data;
- unsigned int port_no = ap->port_no;
- u8 seq = (u8) (port_no + 1);
-
- VPRINTK("ENTER, ap %p\n", ap);
-
- writel(0x00000001, ap->host_set->mmio_base + (seq * 4));
- readl(ap->host_set->mmio_base + (seq * 4)); /* flush */
-
- pp->pkt[2] = seq;
- wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
-}
-
-static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
-{
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- pdc_packet_start(qc);
- return 0;
-
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
- default:
- break;
- }
-
- return ata_qc_issue_prot(qc);
-}
-
-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
- ata_tf_load(ap, tf);
-}
-
-
-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
- ata_exec_command(ap, tf);
-}
-
-
-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr = base;
- port->data_addr = base;
- port->feature_addr =
- port->error_addr = base + 0x4;
- port->nsect_addr = base + 0x8;
- port->lbal_addr = base + 0xc;
- port->lbam_addr = base + 0x10;
- port->lbah_addr = base + 0x14;
- port->device_addr = base + 0x18;
- port->command_addr =
- port->status_addr = base + 0x1c;
- port->altstatus_addr =
- port->ctl_addr = base + 0x38;
-}
-
-
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
-{
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hp = pe->private_data;
- int hotplug_offset = hp->hotplug_offset;
- u32 tmp;
-
- /*
- * Except for the hotplug stuff, this is voodoo from the
- * Promise driver. Label this entire section
- * "TODO: figure out why we do this"
- */
-
- /* change FIFO_SHD to 8 dwords, enable BMR_BURST */
- tmp = readl(mmio + PDC_FLASH_CTL);
- tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
- writel(tmp, mmio + PDC_FLASH_CTL);
-
- /* clear plug/unplug flags for all ports */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff, mmio + hotplug_offset);
-
- /* mask plug/unplug ints */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff0000, mmio + hotplug_offset);
-
- /* reduce TBG clock to 133 Mhz. */
- tmp = readl(mmio + PDC_TBG_MODE);
- tmp &= ~0x30000; /* clear bit 17, 16*/
- tmp |= 0x10000; /* set bit 17:16 = 0:1 */
- writel(tmp, mmio + PDC_TBG_MODE);
-
- readl(mmio + PDC_TBG_MODE); /* flush */
- msleep(10);
-
- /* adjust slew rate control register. */
- tmp = readl(mmio + PDC_SLEW_CTL);
- tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
- tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
- writel(tmp, mmio + PDC_SLEW_CTL);
-}
-
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- struct pdc_host_priv *hp;
- unsigned long base;
- void __iomem *mmio_base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
- int rc;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hp = kzalloc(sizeof(*hp), GFP_KERNEL);
- if (hp == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- /* Set default hotplug offset */
- hp->hotplug_offset = PDC_SATA_PLUG_CSR;
- probe_ent->private_data = hp;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
-
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
-
- probe_ent->port[0].scr_addr = base + 0x400;
- probe_ent->port[1].scr_addr = base + 0x500;
-
- /* notice 4-port boards */
- switch (board_idx) {
- case board_40518:
- /* Override hotplug offset for SATAII150 */
- hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
- /* Fall through */
- case board_20319:
- probe_ent->n_ports = 4;
-
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
-
- probe_ent->port[2].scr_addr = base + 0x600;
- probe_ent->port[3].scr_addr = base + 0x700;
- break;
- case board_2057x:
- /* Override hotplug offset for SATAII150 */
- hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
- /* Fall through */
- case board_2037x:
- probe_ent->n_ports = 2;
- break;
- case board_20771:
- probe_ent->n_ports = 2;
- break;
- case board_20619:
- probe_ent->n_ports = 4;
-
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
-
- probe_ent->port[2].scr_addr = base + 0x600;
- probe_ent->port[3].scr_addr = base + 0x700;
- break;
- default:
- BUG();
- break;
- }
-
- pci_set_master(pdev);
-
- /* initialize adapter */
- pdc_host_init(board_idx, probe_ent);
-
- /* FIXME: Need any other frees than hp? */
- if (!ata_device_add(probe_ent))
- kfree(hp);
-
- kfree(probe_ent);
-
- return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-
-static int __init pdc_ata_init(void)
-{
- return pci_module_init(&pdc_ata_pci_driver);
-}
-
-
-static void __exit pdc_ata_exit(void)
-{
- pci_unregister_driver(&pdc_ata_pci_driver);
-}
-
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(pdc_ata_init);
-module_exit(pdc_ata_exit);
diff --git a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h
deleted file mode 100644
index 6ee5e190262..00000000000
--- a/drivers/scsi/sata_promise.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * sata_promise.h - Promise SATA common definitions and inline funcs
- *
- * Copyright 2003-2004 Red Hat, 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- */
-
-#ifndef __SATA_PROMISE_H__
-#define __SATA_PROMISE_H__
-
-#include <linux/ata.h>
-
-enum pdc_packet_bits {
- PDC_PKT_READ = (1 << 2),
- PDC_PKT_NODATA = (1 << 3),
-
- PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
- PDC_PKT_CLEAR_BSY = (1 << 4),
- PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
- PDC_LAST_REG = (1 << 3),
-
- PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
-};
-
-static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
- dma_addr_t sg_table,
- unsigned int devno, u8 *buf)
-{
- u8 dev_reg;
- u32 *buf32 = (u32 *) buf;
-
- /* set control bits (byte 0), zero delay seq id (byte 3),
- * and seq id (byte 2)
- */
- switch (tf->protocol) {
- case ATA_PROT_DMA:
- if (!(tf->flags & ATA_TFLAG_WRITE))
- buf32[0] = cpu_to_le32(PDC_PKT_READ);
- else
- buf32[0] = 0;
- break;
-
- case ATA_PROT_NODATA:
- buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
- break;
-
- default:
- BUG();
- break;
- }
-
- buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
- buf32[2] = 0; /* no next-packet */
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[13] = dev_reg;
-
- /* device control register */
- buf[14] = (1 << 5) | PDC_REG_DEVCTL;
- buf[15] = tf->ctl;
-
- return 16; /* offset of next byte */
-}
-
-static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
- unsigned int i)
-{
- if (tf->flags & ATA_TFLAG_DEVICE) {
- buf[i++] = (1 << 5) | ATA_REG_DEVICE;
- buf[i++] = tf->device;
- }
-
- /* and finally the command itself; also includes end-of-pkt marker */
- buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
- buf[i++] = tf->command;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(1 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (1 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->feature;
-
- buf[i++] = (1 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->nsect;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->lbal;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->lbam;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(2 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (2 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->hob_feature;
- buf[i++] = tf->feature;
-
- buf[i++] = (2 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->hob_nsect;
- buf[i++] = tf->nsect;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->hob_lbal;
- buf[i++] = tf->lbal;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->hob_lbam;
- buf[i++] = tf->lbam;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->hob_lbah;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-
-#endif /* __SATA_PROMISE_H__ */
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
deleted file mode 100644
index 98ddc25655f..00000000000
--- a/drivers/scsi/sata_qstor.c
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * sata_qstor.c - Pacific Digital Corporation QStor SATA
- *
- * Maintained by: Mark Lord <mlord@pobox.com>
- *
- * Copyright 2005 Pacific Digital Corporation.
- * (OSL/GPL code release authorized by Jalil Fadavi).
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <asm/io.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_qstor"
-#define DRV_VERSION "0.06"
-
-enum {
- QS_PORTS = 4,
- QS_MAX_PRD = LIBATA_MAX_PRD,
- QS_CPB_ORDER = 6,
- QS_CPB_BYTES = (1 << QS_CPB_ORDER),
- QS_PRD_BYTES = QS_MAX_PRD * 16,
- QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES,
-
- /* global register offsets */
- QS_HCF_CNFG3 = 0x0003, /* host configuration offset */
- QS_HID_HPHY = 0x0004, /* host physical interface info */
- QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */
- QS_HST_SFF = 0x0100, /* host status fifo offset */
- QS_HVS_SERD3 = 0x0393, /* PHY enable offset */
-
- /* global control bits */
- QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */
- QS_CNFG3_GSRST = 0x01, /* global chip reset */
- QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/
-
- /* per-channel register offsets */
- QS_CCF_CPBA = 0x0710, /* chan CPB base address */
- QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */
- QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */
- QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */
- QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */
- QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */
- QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */
- QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */
- QS_CCT_CFF = 0x0a00, /* chan command fifo offset */
-
- /* channel control bits */
- QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */
- QS_CTR0_CLER = (1 << 2), /* clear channel errors */
- QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */
- QS_CTR1_RCHN = (1 << 4), /* reset channel logic */
- QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */
-
- /* pkt sub-field headers */
- QS_HCB_HDR = 0x01, /* Host Control Block header */
- QS_DCB_HDR = 0x02, /* Device Control Block header */
-
- /* pkt HCB flag bits */
- QS_HF_DIRO = (1 << 0), /* data DIRection Out */
- QS_HF_DAT = (1 << 3), /* DATa pkt */
- QS_HF_IEN = (1 << 4), /* Interrupt ENable */
- QS_HF_VLD = (1 << 5), /* VaLiD pkt */
-
- /* pkt DCB flag bits */
- QS_DF_PORD = (1 << 2), /* Pio OR Dma */
- QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */
-
- /* PCI device IDs */
- board_2068_idx = 0, /* QStor 4-port SATA/RAID */
-};
-
-enum {
- QS_DMA_BOUNDARY = ~0UL
-};
-
-typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
-
-struct qs_port_priv {
- u8 *pkt;
- dma_addr_t pkt_dma;
- qs_state_t state;
-};
-
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
-static int qs_port_start(struct ata_port *ap);
-static void qs_host_stop(struct ata_host_set *host_set);
-static void qs_port_stop(struct ata_port *ap);
-static void qs_phy_reset(struct ata_port *ap);
-static void qs_qc_prep(struct ata_queued_cmd *qc);
-static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
-static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
-static void qs_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 qs_bmdma_status(struct ata_port *ap);
-static void qs_irq_clear(struct ata_port *ap);
-static void qs_eng_timeout(struct ata_port *ap);
-
-static struct scsi_host_template qs_ata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = QS_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
- .use_clustering = ENABLE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = QS_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations qs_ata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .check_atapi_dma = qs_check_atapi_dma,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
- .phy_reset = qs_phy_reset,
- .qc_prep = qs_qc_prep,
- .qc_issue = qs_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
- .eng_timeout = qs_eng_timeout,
- .irq_handler = qs_intr,
- .irq_clear = qs_irq_clear,
- .scr_read = qs_scr_read,
- .scr_write = qs_scr_write,
- .port_start = qs_port_start,
- .port_stop = qs_port_stop,
- .host_stop = qs_host_stop,
- .bmdma_stop = qs_bmdma_stop,
- .bmdma_status = qs_bmdma_status,
-};
-
-static const struct ata_port_info qs_port_info[] = {
- /* board_2068_idx */
- {
- .sht = &qs_ata_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET |
- //FIXME ATA_FLAG_SRST |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
- .pio_mask = 0x10, /* pio4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &qs_ata_ops,
- },
-};
-
-static const struct pci_device_id qs_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2068_idx },
-
- { } /* terminate list */
-};
-
-static struct pci_driver qs_ata_pci_driver = {
- .name = DRV_NAME,
- .id_table = qs_ata_pci_tbl,
- .probe = qs_ata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
-{
- return 1; /* ATAPI DMA not supported */
-}
-
-static void qs_bmdma_stop(struct ata_queued_cmd *qc)
-{
- /* nothing */
-}
-
-static u8 qs_bmdma_status(struct ata_port *ap)
-{
- return 0;
-}
-
-static void qs_irq_clear(struct ata_port *ap)
-{
- /* nothing */
-}
-
-static inline void qs_enter_reg_mode(struct ata_port *ap)
-{
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
-
- writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
- readb(chan + QS_CCT_CTR0); /* flush */
-}
-
-static inline void qs_reset_channel_logic(struct ata_port *ap)
-{
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
-
- writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
- readb(chan + QS_CCT_CTR0); /* flush */
- qs_enter_reg_mode(ap);
-}
-
-static void qs_phy_reset(struct ata_port *ap)
-{
- struct qs_port_priv *pp = ap->private_data;
-
- pp->state = qs_state_idle;
- qs_reset_channel_logic(ap);
- sata_phy_reset(ap);
-}
-
-static void qs_eng_timeout(struct ata_port *ap)
-{
- struct qs_port_priv *pp = ap->private_data;
-
- if (pp->state != qs_state_idle) /* healthy paranoia */
- pp->state = qs_state_mmio;
- qs_reset_channel_logic(ap);
- ata_eng_timeout(ap);
-}
-
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return ~0U;
- return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
-}
-
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
- writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
-}
-
-static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
-{
- struct scatterlist *sg;
- struct ata_port *ap = qc->ap;
- struct qs_port_priv *pp = ap->private_data;
- unsigned int nelem;
- u8 *prd = pp->pkt + QS_CPB_BYTES;
-
- WARN_ON(qc->__sg == NULL);
- WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
- nelem = 0;
- ata_for_each_sg(sg, qc) {
- u64 addr;
- u32 len;
-
- addr = sg_dma_address(sg);
- *(__le64 *)prd = cpu_to_le64(addr);
- prd += sizeof(u64);
-
- len = sg_dma_len(sg);
- *(__le32 *)prd = cpu_to_le32(len);
- prd += sizeof(u64);
-
- VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
- (unsigned long long)addr, len);
- nelem++;
- }
-
- return nelem;
-}
-
-static void qs_qc_prep(struct ata_queued_cmd *qc)
-{
- struct qs_port_priv *pp = qc->ap->private_data;
- u8 dflags = QS_DF_PORD, *buf = pp->pkt;
- u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
- u64 addr;
- unsigned int nelem;
-
- VPRINTK("ENTER\n");
-
- qs_enter_reg_mode(qc->ap);
- if (qc->tf.protocol != ATA_PROT_DMA) {
- ata_qc_prep(qc);
- return;
- }
-
- nelem = qs_fill_sg(qc);
-
- if ((qc->tf.flags & ATA_TFLAG_WRITE))
- hflags |= QS_HF_DIRO;
- if ((qc->tf.flags & ATA_TFLAG_LBA48))
- dflags |= QS_DF_ELBA;
-
- /* host control block (HCB) */
- buf[ 0] = QS_HCB_HDR;
- buf[ 1] = hflags;
- *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
- *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
- addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
- *(__le64 *)(&buf[16]) = cpu_to_le64(addr);
-
- /* device control block (DCB) */
- buf[24] = QS_DCB_HDR;
- buf[28] = dflags;
-
- /* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
-}
-
-static inline void qs_packet_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
-
- VPRINTK("ENTER, ap %p\n", ap);
-
- writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
- wmb(); /* flush PRDs and pkt to memory */
- writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
- readl(chan + QS_CCT_CFF); /* flush */
-}
-
-static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
-{
- struct qs_port_priv *pp = qc->ap->private_data;
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
-
- pp->state = qs_state_pkt;
- qs_packet_start(qc);
- return 0;
-
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
- default:
- break;
- }
-
- pp->state = qs_state_mmio;
- return ata_qc_issue_prot(qc);
-}
-
-static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
-{
- unsigned int handled = 0;
- u8 sFFE;
- u8 __iomem *mmio_base = host_set->mmio_base;
-
- do {
- u32 sff0 = readl(mmio_base + QS_HST_SFF);
- u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
- u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
- sFFE = sff1 >> 31; /* empty flag */
-
- if (sEVLD) {
- u8 sDST = sff0 >> 16; /* dev status */
- u8 sHST = sff1 & 0x3f; /* host status */
- unsigned int port_no = (sff1 >> 8) & 0x03;
- struct ata_port *ap = host_set->ports[port_no];
-
- DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
- sff1, sff0, port_no, sHST, sDST);
- handled = 1;
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
- struct qs_port_priv *pp = ap->private_data;
- if (!pp || pp->state != qs_state_pkt)
- continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- switch (sHST) {
- case 0: /* successful CPB */
- case 3: /* device error */
- pp->state = qs_state_idle;
- qs_enter_reg_mode(qc->ap);
- qc->err_mask |= ac_err_mask(sDST);
- ata_qc_complete(qc);
- break;
- default:
- break;
- }
- }
- }
- }
- } while (!sFFE);
- return handled;
-}
-
-static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
-{
- unsigned int handled = 0, port_no;
-
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
- struct ata_port *ap;
- ap = host_set->ports[port_no];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
- struct qs_port_priv *pp = ap->private_data;
- if (!pp || pp->state != qs_state_mmio)
- continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-
- /* check main status, clearing INTRQ */
- u8 status = ata_check_status(ap);
- if ((status & ATA_BUSY))
- continue;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
-
- /* complete taskfile transaction */
- pp->state = qs_state_idle;
- qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
- handled = 1;
- }
- }
- }
- return handled;
-}
-
-static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int handled = 0;
-
- VPRINTK("ENTER\n");
-
- spin_lock(&host_set->lock);
- handled = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
- spin_unlock(&host_set->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr =
- port->data_addr = base + 0x400;
- port->error_addr =
- port->feature_addr = base + 0x408; /* hob_feature = 0x409 */
- port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */
- port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */
- port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */
- port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */
- port->device_addr = base + 0x430;
- port->status_addr =
- port->command_addr = base + 0x438;
- port->altstatus_addr =
- port->ctl_addr = base + 0x440;
- port->scr_addr = base + 0xc00;
-}
-
-static int qs_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct qs_port_priv *pp;
- void __iomem *mmio_base = ap->host_set->mmio_base;
- void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
- u64 addr;
- int rc;
-
- rc = ata_port_start(ap);
- if (rc)
- return rc;
- qs_enter_reg_mode(ap);
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
- memset(pp->pkt, 0, QS_PKT_BYTES);
- ap->private_data = pp;
-
- addr = (u64)pp->pkt_dma;
- writel((u32) addr, chan + QS_CCF_CPBA);
- writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
- return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-static void qs_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct qs_port_priv *pp = ap->private_data;
-
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
- pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
-}
-
-static void qs_host_stop(struct ata_host_set *host_set)
-{
- void __iomem *mmio_base = host_set->mmio_base;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
-
- writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
- writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
-
- pci_iounmap(pdev, mmio_base);
-}
-
-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
-{
- void __iomem *mmio_base = pe->mmio_base;
- unsigned int port_no;
-
- writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
- writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
-
- /* reset each channel in turn */
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
- u8 __iomem *chan = mmio_base + (port_no * 0x4000);
- writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
- writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
- readb(chan + QS_CCT_CTR0); /* flush */
- }
- writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
-
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
- u8 __iomem *chan = mmio_base + (port_no * 0x4000);
- /* set FIFO depths to same settings as Windows driver */
- writew(32, chan + QS_CFC_HUFT);
- writew(32, chan + QS_CFC_HDFT);
- writew(10, chan + QS_CFC_DUFT);
- writew( 8, chan + QS_CFC_DDFT);
- /* set CPB size in bytes, as a power of two */
- writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP);
- }
- writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
-}
-
-/*
- * The QStor understands 64-bit buses, and uses 64-bit fields
- * for DMA pointers regardless of bus width. We just have to
- * make sure our DMA masks are set appropriately for whatever
- * bridge lies between us and the QStor, and then the DMA mapping
- * code will ensure we only ever "see" appropriate buffer addresses.
- * If we're 32-bit limited somewhere, then our 64-bit fields will
- * just end up with zeros in the upper 32-bits, without any special
- * logic required outside of this routine (below).
- */
-static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
-{
- u32 bus_info = readl(mmio_base + QS_HID_HPHY);
- int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
-
- if (have_64bit_bus &&
- !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
- return rc;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- return rc;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
- }
- return 0;
-}
-
-static int qs_ata_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int rc, port_no;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
-
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- rc = qs_set_dma_masks(pdev, mmio_base);
- if (rc)
- goto err_out_iounmap;
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = qs_port_info[board_idx].sht;
- probe_ent->host_flags = qs_port_info[board_idx].host_flags;
- probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
- probe_ent->port_ops = qs_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
- probe_ent->n_ports = QS_PORTS;
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- unsigned long chan = (unsigned long)mmio_base +
- (port_no * 0x4000);
- qs_ata_setup_port(&probe_ent->port[port_no], chan);
- }
-
- pci_set_master(pdev);
-
- /* initialize adapter */
- qs_host_init(board_idx, probe_ent);
-
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != QS_PORTS)
- goto err_out_iounmap;
- return 0;
-
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
-}
-
-static int __init qs_ata_init(void)
-{
- return pci_module_init(&qs_ata_pci_driver);
-}
-
-static void __exit qs_ata_exit(void)
-{
- pci_unregister_driver(&qs_ata_pci_driver);
-}
-
-MODULE_AUTHOR("Mark Lord");
-MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(qs_ata_init);
-module_exit(qs_ata_exit);
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
deleted file mode 100644
index bc9f918a7f2..00000000000
--- a/drivers/scsi/sata_sil.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * sata_sil.c - Silicon Image SATA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2005 Red Hat, Inc.
- * Copyright 2003 Benjamin Herrenschmidt
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Documentation for SiI 3112:
- * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
- *
- * Other errata and documentation available under NDA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_sil"
-#define DRV_VERSION "1.0"
-
-enum {
- /*
- * host flags
- */
- SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
- SIL_FLAG_MOD15WRITE = (1 << 30),
-
- SIL_DFL_HOST_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
-
- /*
- * Controller IDs
- */
- sil_3112 = 0,
- sil_3512 = 1,
- sil_3114 = 2,
-
- /*
- * Register offsets
- */
- SIL_SYSCFG = 0x48,
-
- /*
- * Register bits
- */
- /* SYSCFG */
- SIL_MASK_IDE0_INT = (1 << 22),
- SIL_MASK_IDE1_INT = (1 << 23),
- SIL_MASK_IDE2_INT = (1 << 24),
- SIL_MASK_IDE3_INT = (1 << 25),
- SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
- SIL_MASK_4PORT = SIL_MASK_2PORT |
- SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
-
- /* BMDMA/BMDMA2 */
- SIL_INTR_STEERING = (1 << 1),
-
- SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */
- SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */
- SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */
- SIL_DMA_ACTIVE = (1 << 16), /* DMA running */
- SIL_DMA_ERROR = (1 << 17), /* PCI bus error */
- SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */
- SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */
- SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */
- SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */
- SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */
-
- /* SIEN */
- SIL_SIEN_N = (1 << 16), /* triggered by SError.N */
-
- /*
- * Others
- */
- SIL_QUIRK_MOD15WRITE = (1 << 0),
- SIL_QUIRK_UDMA5MAX = (1 << 1),
-};
-
-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void sil_post_set_mode (struct ata_port *ap);
-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static void sil_freeze(struct ata_port *ap);
-static void sil_thaw(struct ata_port *ap);
-
-
-static const struct pci_device_id sil_pci_tbl[] = {
- { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
- { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
- { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { } /* terminate list */
-};
-
-
-/* TODO firmware versions should be added - eric */
-static const struct sil_drivelist {
- const char * product;
- unsigned int quirk;
-} sil_blacklist [] = {
- { "ST320012AS", SIL_QUIRK_MOD15WRITE },
- { "ST330013AS", SIL_QUIRK_MOD15WRITE },
- { "ST340017AS", SIL_QUIRK_MOD15WRITE },
- { "ST360015AS", SIL_QUIRK_MOD15WRITE },
- { "ST380013AS", SIL_QUIRK_MOD15WRITE },
- { "ST380023AS", SIL_QUIRK_MOD15WRITE },
- { "ST3120023AS", SIL_QUIRK_MOD15WRITE },
- { "ST3160023AS", SIL_QUIRK_MOD15WRITE },
- { "ST3120026AS", SIL_QUIRK_MOD15WRITE },
- { "ST3200822AS", SIL_QUIRK_MOD15WRITE },
- { "ST340014ASL", SIL_QUIRK_MOD15WRITE },
- { "ST360014ASL", SIL_QUIRK_MOD15WRITE },
- { "ST380011ASL", SIL_QUIRK_MOD15WRITE },
- { "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
- { "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
- { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
- { }
-};
-
-static struct pci_driver sil_pci_driver = {
- .name = DRV_NAME,
- .id_table = sil_pci_tbl,
- .probe = sil_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static struct scsi_host_template sil_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations sil_ops = {
- .port_disable = ata_port_disable,
- .dev_config = sil_dev_config,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
- .post_set_mode = sil_post_set_mode,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
- .freeze = sil_freeze,
- .thaw = sil_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = sil_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = sil_scr_read,
- .scr_write = sil_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
-};
-
-static const struct ata_port_info sil_port_info[] = {
- /* sil_3112 */
- {
- .sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil_ops,
- },
- /* sil_3512 */
- {
- .sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil_ops,
- },
- /* sil_3114 */
- {
- .sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil_ops,
- },
-};
-
-/* per-port register offsets */
-/* TODO: we can probably calculate rather than use a table */
-static const struct {
- unsigned long tf; /* ATA taskfile register block */
- unsigned long ctl; /* ATA control/altstatus register block */
- unsigned long bmdma; /* DMA register block */
- unsigned long bmdma2; /* DMA register block #2 */
- unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
- unsigned long scr; /* SATA control register block */
- unsigned long sien; /* SATA Interrupt Enable register */
- unsigned long xfer_mode;/* data transfer mode register */
- unsigned long sfis_cfg; /* SATA FIS reception config register */
-} sil_port[] = {
- /* port 0 ... */
- { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
- { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
- { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
- { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
- /* ... port 3 */
-};
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-static int slow_down = 0;
-module_param(slow_down, int, 0444);
-MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
-
-
-static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
-{
- u8 cache_line = 0;
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
- return cache_line;
-}
-
-static void sil_post_set_mode (struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- struct ata_device *dev;
- void __iomem *addr =
- host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
- u32 tmp, dev_mode[2];
- unsigned int i;
-
- for (i = 0; i < 2; i++) {
- dev = &ap->device[i];
- if (!ata_dev_enabled(dev))
- dev_mode[i] = 0; /* PIO0/1/2 */
- else if (dev->flags & ATA_DFLAG_PIO)
- dev_mode[i] = 1; /* PIO3/4 */
- else
- dev_mode[i] = 3; /* UDMA */
- /* value 2 indicates MDMA */
- }
-
- tmp = readl(addr);
- tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
- tmp |= dev_mode[0];
- tmp |= (dev_mode[1] << 4);
- writel(tmp, addr);
- readl(addr); /* flush */
-}
-
-static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
-{
- unsigned long offset = ap->ioaddr.scr_addr;
-
- switch (sc_reg) {
- case SCR_STATUS:
- return offset + 4;
- case SCR_ERROR:
- return offset + 8;
- case SCR_CONTROL:
- return offset;
- default:
- /* do nothing */
- break;
- }
-
- return 0;
-}
-
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
- if (mmio)
- return readl(mmio);
- return 0xffffffffU;
-}
-
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
- if (mmio)
- writel(val, mmio);
-}
-
-static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
-{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
- u8 status;
-
- if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
- u32 serror;
-
- /* SIEN doesn't mask SATA IRQs on some 3112s. Those
- * controllers continue to assert IRQ as long as
- * SError bits are pending. Clear SError immediately.
- */
- serror = sil_scr_read(ap, SCR_ERROR);
- sil_scr_write(ap, SCR_ERROR, serror);
-
- /* Trigger hotplug and accumulate SError only if the
- * port isn't already frozen. Otherwise, PHY events
- * during hardreset makes controllers with broken SIEN
- * repeat probing needlessly.
- */
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
- ata_ehi_hotplugged(&ap->eh_info);
- ap->eh_info.serror |= serror;
- }
-
- goto freeze;
- }
-
- if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
- goto freeze;
-
- /* Check whether we are expecting interrupt in this state */
- switch (ap->hsm_task_state) {
- case HSM_ST_FIRST:
- /* Some pre-ATAPI-4 devices assert INTRQ
- * at this state when ready to receive CDB.
- */
-
- /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
- * The flag was turned on only for atapi devices.
- * No need to check is_atapi_taskfile(&qc->tf) again.
- */
- if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
- goto err_hsm;
- break;
- case HSM_ST_LAST:
- if (qc->tf.protocol == ATA_PROT_DMA ||
- qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
- /* clear DMA-Start bit */
- ap->ops->bmdma_stop(qc);
-
- if (bmdma2 & SIL_DMA_ERROR) {
- qc->err_mask |= AC_ERR_HOST_BUS;
- ap->hsm_task_state = HSM_ST_ERR;
- }
- }
- break;
- case HSM_ST:
- break;
- default:
- goto err_hsm;
- }
-
- /* check main status, clearing INTRQ */
- status = ata_chk_status(ap);
- if (unlikely(status & ATA_BUSY))
- goto err_hsm;
-
- /* ack bmdma irq events */
- ata_bmdma_irq_clear(ap);
-
- /* kick HSM in the ass */
- ata_hsm_move(ap, qc, status, 0);
-
- return;
-
- err_hsm:
- qc->err_mask |= AC_ERR_HSM;
- freeze:
- ata_port_freeze(ap);
-}
-
-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- void __iomem *mmio_base = host_set->mmio_base;
- int handled = 0;
- int i;
-
- spin_lock(&host_set->lock);
-
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
- u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
-
- if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
- continue;
-
- if (bmdma2 == 0xffffffff ||
- !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
- continue;
-
- sil_host_intr(ap, bmdma2);
- handled = 1;
- }
-
- spin_unlock(&host_set->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void sil_freeze(struct ata_port *ap)
-{
- void __iomem *mmio_base = ap->host_set->mmio_base;
- u32 tmp;
-
- /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
- writel(0, mmio_base + sil_port[ap->port_no].sien);
-
- /* plug IRQ */
- tmp = readl(mmio_base + SIL_SYSCFG);
- tmp |= SIL_MASK_IDE0_INT << ap->port_no;
- writel(tmp, mmio_base + SIL_SYSCFG);
- readl(mmio_base + SIL_SYSCFG); /* flush */
-}
-
-static void sil_thaw(struct ata_port *ap)
-{
- void __iomem *mmio_base = ap->host_set->mmio_base;
- u32 tmp;
-
- /* clear IRQ */
- ata_chk_status(ap);
- ata_bmdma_irq_clear(ap);
-
- /* turn on SATA IRQ */
- writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
-
- /* turn on IRQ */
- tmp = readl(mmio_base + SIL_SYSCFG);
- tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
- writel(tmp, mmio_base + SIL_SYSCFG);
-}
-
-/**
- * sil_dev_config - Apply device/host-specific errata fixups
- * @ap: Port containing device to be examined
- * @dev: Device to be examined
- *
- * After the IDENTIFY [PACKET] DEVICE step is complete, and a
- * device is known to be present, this function is called.
- * We apply two errata fixups which are specific to Silicon Image,
- * a Seagate and a Maxtor fixup.
- *
- * For certain Seagate devices, we must limit the maximum sectors
- * to under 8K.
- *
- * For certain Maxtor devices, we must not program the drive
- * beyond udma5.
- *
- * Both fixups are unfairly pessimistic. As soon as I get more
- * information on these errata, I will create a more exhaustive
- * list, and apply the fixups to only the specific
- * devices/hosts/firmwares that need it.
- *
- * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
- * The Maxtor quirk is in the blacklist, but I'm keeping the original
- * pessimistic fix for the following reasons...
- * - There seems to be less info on it, only one device gleaned off the
- * Windows driver, maybe only one is affected. More info would be greatly
- * appreciated.
- * - But then again UDMA5 is hardly anything to complain about
- */
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
-{
- unsigned int n, quirks = 0;
- unsigned char model_num[41];
-
- ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
-
- for (n = 0; sil_blacklist[n].product; n++)
- if (!strcmp(sil_blacklist[n].product, model_num)) {
- quirks = sil_blacklist[n].quirk;
- break;
- }
-
- /* limit requests to 15 sectors */
- if (slow_down ||
- ((ap->flags & SIL_FLAG_MOD15WRITE) &&
- (quirks & SIL_QUIRK_MOD15WRITE))) {
- ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
- "(mod15write workaround)\n");
- dev->max_sectors = 15;
- return;
- }
-
- /* limit to udma5 */
- if (quirks & SIL_QUIRK_UDMA5MAX) {
- ata_dev_printk(dev, KERN_INFO,
- "applying Maxtor errata fix %s\n", model_num);
- dev->udma_mask &= ATA_UDMA5;
- return;
- }
-}
-
-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- void __iomem *mmio_base;
- int rc;
- unsigned int i;
- int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = pci_dev_to_dev(pdev);
- probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
- probe_ent->sht = sil_port_info[ent->driver_data].sht;
- probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
- probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
- probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
- probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
-
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- probe_ent->mmio_base = mmio_base;
-
- base = (unsigned long) mmio_base;
-
- for (i = 0; i < probe_ent->n_ports; i++) {
- probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
- probe_ent->port[i].altstatus_addr =
- probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
- probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
- probe_ent->port[i].scr_addr = base + sil_port[i].scr;
- ata_std_ports(&probe_ent->port[i]);
- }
-
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-static int __init sil_init(void)
-{
- return pci_module_init(&sil_pci_driver);
-}
-
-static void __exit sil_exit(void)
-{
- pci_unregister_driver(&sil_pci_driver);
-}
-
-
-module_init(sil_init);
-module_exit(sil_exit);
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
deleted file mode 100644
index c8b477c6724..00000000000
--- a/drivers/scsi/sata_sil24.c
+++ /dev/null
@@ -1,1181 +0,0 @@
-/*
- * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers
- *
- * Copyright 2005 Tejun Heo
- *
- * Based on preview driver from Silicon Image.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-
-#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.24"
-
-/*
- * Port request block (PRB) 32 bytes
- */
-struct sil24_prb {
- __le16 ctrl;
- __le16 prot;
- __le32 rx_cnt;
- u8 fis[6 * 4];
-};
-
-/*
- * Scatter gather entry (SGE) 16 bytes
- */
-struct sil24_sge {
- __le64 addr;
- __le32 cnt;
- __le32 flags;
-};
-
-/*
- * Port multiplier
- */
-struct sil24_port_multiplier {
- __le32 diag;
- __le32 sactive;
-};
-
-enum {
- /*
- * Global controller registers (128 bytes @ BAR0)
- */
- /* 32 bit regs */
- HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */
- HOST_CTRL = 0x40,
- HOST_IRQ_STAT = 0x44,
- HOST_PHY_CFG = 0x48,
- HOST_BIST_CTRL = 0x50,
- HOST_BIST_PTRN = 0x54,
- HOST_BIST_STAT = 0x58,
- HOST_MEM_BIST_STAT = 0x5c,
- HOST_FLASH_CMD = 0x70,
- /* 8 bit regs */
- HOST_FLASH_DATA = 0x74,
- HOST_TRANSITION_DETECT = 0x75,
- HOST_GPIO_CTRL = 0x76,
- HOST_I2C_ADDR = 0x78, /* 32 bit */
- HOST_I2C_DATA = 0x7c,
- HOST_I2C_XFER_CNT = 0x7e,
- HOST_I2C_CTRL = 0x7f,
-
- /* HOST_SLOT_STAT bits */
- HOST_SSTAT_ATTN = (1 << 31),
-
- /* HOST_CTRL bits */
- HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */
- HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */
- HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
- HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
- HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
-
- /*
- * Port registers
- * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
- */
- PORT_REGS_SIZE = 0x2000,
-
- PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
- PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
-
- PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
- /* 32 bit regs */
- PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */
- PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */
- PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */
- PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */
- PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */
- PORT_ACTIVATE_UPPER_ADDR= 0x101c,
- PORT_EXEC_FIFO = 0x1020, /* command execution fifo */
- PORT_CMD_ERR = 0x1024, /* command error number */
- PORT_FIS_CFG = 0x1028,
- PORT_FIFO_THRES = 0x102c,
- /* 16 bit regs */
- PORT_DECODE_ERR_CNT = 0x1040,
- PORT_DECODE_ERR_THRESH = 0x1042,
- PORT_CRC_ERR_CNT = 0x1044,
- PORT_CRC_ERR_THRESH = 0x1046,
- PORT_HSHK_ERR_CNT = 0x1048,
- PORT_HSHK_ERR_THRESH = 0x104a,
- /* 32 bit regs */
- PORT_PHY_CFG = 0x1050,
- PORT_SLOT_STAT = 0x1800,
- PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */
- PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */
- PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */
- PORT_SCONTROL = 0x1f00,
- PORT_SSTATUS = 0x1f04,
- PORT_SERROR = 0x1f08,
- PORT_SACTIVE = 0x1f0c,
-
- /* PORT_CTRL_STAT bits */
- PORT_CS_PORT_RST = (1 << 0), /* port reset */
- PORT_CS_DEV_RST = (1 << 1), /* device reset */
- PORT_CS_INIT = (1 << 2), /* port initialize */
- PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */
- PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */
- PORT_CS_RESUME = (1 << 6), /* port resume */
- PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */
- PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */
- PORT_CS_RDY = (1 << 31), /* port ready to accept commands */
-
- /* PORT_IRQ_STAT/ENABLE_SET/CLR */
- /* bits[11:0] are masked */
- PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */
- PORT_IRQ_ERROR = (1 << 1), /* command execution error */
- PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */
- PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */
- PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */
- PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */
- PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */
- PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */
- PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */
- PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */
- PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
- PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
-
- DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
- PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
- PORT_IRQ_UNK_FIS,
-
- /* bits[27:16] are unmasked (raw) */
- PORT_IRQ_RAW_SHIFT = 16,
- PORT_IRQ_MASKED_MASK = 0x7ff,
- PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT),
-
- /* ENABLE_SET/CLR specific, intr steering - 2 bit field */
- PORT_IRQ_STEER_SHIFT = 30,
- PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT),
-
- /* PORT_CMD_ERR constants */
- PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */
- PORT_CERR_SDB = 2, /* Error bit in SDB FIS */
- PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */
- PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */
- PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */
- PORT_CERR_DIRECTION = 6, /* Data direction mismatch */
- PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */
- PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */
- PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */
- PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */
- PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */
- PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */
- PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */
- PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */
- PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */
- PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */
- PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */
- PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */
- PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */
- PORT_CERR_XFR_MSTABRT = 34, /* PSD ecode 10 - master abort */
- PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
- PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
-
- /* bits of PRB control field */
- PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */
- PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */
- PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */
- PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */
- PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */
-
- /* PRB protocol field */
- PRB_PROT_PACKET = (1 << 0),
- PRB_PROT_TCQ = (1 << 1),
- PRB_PROT_NCQ = (1 << 2),
- PRB_PROT_READ = (1 << 3),
- PRB_PROT_WRITE = (1 << 4),
- PRB_PROT_TRANSPARENT = (1 << 5),
-
- /*
- * Other constants
- */
- SGE_TRM = (1 << 31), /* Last SGE in chain */
- SGE_LNK = (1 << 30), /* linked list
- Points to SGT, not SGE */
- SGE_DRD = (1 << 29), /* discard data read (/dev/null)
- data address ignored */
-
- SIL24_MAX_CMDS = 31,
-
- /* board id */
- BID_SIL3124 = 0,
- BID_SIL3132 = 1,
- BID_SIL3131 = 2,
-
- /* host flags */
- SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
- SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
-
- IRQ_STAT_4PORTS = 0xf,
-};
-
-struct sil24_ata_block {
- struct sil24_prb prb;
- struct sil24_sge sge[LIBATA_MAX_PRD];
-};
-
-struct sil24_atapi_block {
- struct sil24_prb prb;
- u8 cdb[16];
- struct sil24_sge sge[LIBATA_MAX_PRD - 1];
-};
-
-union sil24_cmd_block {
- struct sil24_ata_block ata;
- struct sil24_atapi_block atapi;
-};
-
-static struct sil24_cerr_info {
- unsigned int err_mask, action;
- const char *desc;
-} sil24_cerr_db[] = {
- [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
- "device error" },
- [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
- "device error via D2H FIS" },
- [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
- "device error via SDB FIS" },
- [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
- "error in data FIS" },
- [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
- "failed to transmit command FIS" },
- [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "protocol mismatch" },
- [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "data directon mismatch" },
- [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "ran out of SGEs while writing" },
- [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "ran out of SGEs while reading" },
- [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "invalid data directon for ATAPI CDB" },
- [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
- "SGT no on qword boundary" },
- [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI target abort while fetching SGT" },
- [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI master abort while fetching SGT" },
- [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI parity error while fetching SGT" },
- [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
- "PRB not on qword boundary" },
- [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI target abort while fetching PRB" },
- [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI master abort while fetching PRB" },
- [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI parity error while fetching PRB" },
- [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "undefined error while transferring data" },
- [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI target abort while transferring data" },
- [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI master abort while transferring data" },
- [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
- "PCI parity error while transferring data" },
- [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
- "FIS received while sending service FIS" },
-};
-
-/*
- * ap->private_data
- *
- * The preview driver always returned 0 for status. We emulate it
- * here from the previous interrupt.
- */
-struct sil24_port_priv {
- union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
- dma_addr_t cmd_block_dma; /* DMA base addr for them */
- struct ata_taskfile tf; /* Cached taskfile registers */
-};
-
-/* ap->host_set->private_data */
-struct sil24_host_priv {
- void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
- void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
-};
-
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
-static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static void sil24_qc_prep(struct ata_queued_cmd *qc);
-static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
-static void sil24_irq_clear(struct ata_port *ap);
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static void sil24_freeze(struct ata_port *ap);
-static void sil24_thaw(struct ata_port *ap);
-static void sil24_error_handler(struct ata_port *ap);
-static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
-static int sil24_port_start(struct ata_port *ap);
-static void sil24_port_stop(struct ata_port *ap);
-static void sil24_host_stop(struct ata_host_set *host_set);
-static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-
-static const struct pci_device_id sil24_pci_tbl[] = {
- { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
- { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
- { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
- { } /* terminate list */
-};
-
-static struct pci_driver sil24_pci_driver = {
- .name = DRV_NAME,
- .id_table = sil24_pci_tbl,
- .probe = sil24_init_one,
- .remove = ata_pci_remove_one, /* safe? */
-};
-
-static struct scsi_host_template sil24_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .change_queue_depth = ata_scsi_change_queue_depth,
- .can_queue = SIL24_MAX_CMDS,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations sil24_ops = {
- .port_disable = ata_port_disable,
-
- .dev_config = sil24_dev_config,
-
- .check_status = sil24_check_status,
- .check_altstatus = sil24_check_status,
- .dev_select = ata_noop_dev_select,
-
- .tf_read = sil24_tf_read,
-
- .qc_prep = sil24_qc_prep,
- .qc_issue = sil24_qc_issue,
-
- .irq_handler = sil24_interrupt,
- .irq_clear = sil24_irq_clear,
-
- .scr_read = sil24_scr_read,
- .scr_write = sil24_scr_write,
-
- .freeze = sil24_freeze,
- .thaw = sil24_thaw,
- .error_handler = sil24_error_handler,
- .post_internal_cmd = sil24_post_internal_cmd,
-
- .port_start = sil24_port_start,
- .port_stop = sil24_port_stop,
- .host_stop = sil24_host_stop,
-};
-
-/*
- * Use bits 30-31 of host_flags to encode available port numbers.
- * Current maxium is 4.
- */
-#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
-#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
-
-static struct ata_port_info sil24_port_info[] = {
- /* sil_3124 */
- {
- .sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
- SIL24_FLAG_PCIX_IRQ_WOC,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil24_ops,
- },
- /* sil_3132 */
- {
- .sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil24_ops,
- },
- /* sil_3131/sil_3531 */
- {
- .sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &sil24_ops,
- },
-};
-
-static int sil24_tag(int tag)
-{
- if (unlikely(ata_tag_internal(tag)))
- return 0;
- return tag;
-}
-
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
-
- if (dev->cdb_len == 16)
- writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
-}
-
-static inline void sil24_update_tf(struct ata_port *ap)
-{
- struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- struct sil24_prb __iomem *prb = port;
- u8 fis[6 * 4];
-
- memcpy_fromio(fis, prb->fis, 6 * 4);
- ata_tf_from_fis(fis, &pp->tf);
-}
-
-static u8 sil24_check_status(struct ata_port *ap)
-{
- struct sil24_port_priv *pp = ap->private_data;
- return pp->tf.command;
-}
-
-static int sil24_scr_map[] = {
- [SCR_CONTROL] = 0,
- [SCR_STATUS] = 1,
- [SCR_ERROR] = 2,
- [SCR_ACTIVE] = 3,
-};
-
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
-{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
- if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
- void __iomem *addr;
- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
- return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
- }
- return 0xffffffffU;
-}
-
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
-{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
- if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
- void __iomem *addr;
- addr = scr_addr + sil24_scr_map[sc_reg] * 4;
- writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
- }
-}
-
-static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct sil24_port_priv *pp = ap->private_data;
- *tf = pp->tf;
-}
-
-static int sil24_init_port(struct ata_port *ap)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- u32 tmp;
-
- writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
- ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_INIT, PORT_CS_INIT, 10, 100);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_RDY, 0, 10, 100);
-
- if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
- return -EIO;
- return 0;
-}
-
-static int sil24_softreset(struct ata_port *ap, unsigned int *class)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- struct sil24_port_priv *pp = ap->private_data;
- struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
- dma_addr_t paddr = pp->cmd_block_dma;
- u32 mask, irq_stat;
- const char *reason;
-
- DPRINTK("ENTER\n");
-
- if (ata_port_offline(ap)) {
- DPRINTK("PHY reports no device\n");
- *class = ATA_DEV_NONE;
- goto out;
- }
-
- /* put the port into known state */
- if (sil24_init_port(ap)) {
- reason ="port not ready";
- goto err;
- }
-
- /* do SRST */
- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
- prb->fis[1] = 0; /* no PM yet */
-
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, ATA_TMOUT_BOOT / HZ * 1000);
-
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- if (irq_stat & PORT_IRQ_ERROR)
- reason = "SRST command error";
- else
- reason = "timeout";
- goto err;
- }
-
- sil24_update_tf(ap);
- *class = ata_dev_classify(&pp->tf);
-
- if (*class == ATA_DEV_UNKNOWN)
- *class = ATA_DEV_NONE;
-
- out:
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
-
- err:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
- return -EIO;
-}
-
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- const char *reason;
- int tout_msec, rc;
- u32 tmp;
-
- /* sil24 does the right thing(tm) without any protection */
- sata_set_spd(ap);
-
- tout_msec = 100;
- if (ata_port_online(ap))
- tout_msec = 5000;
-
- writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
-
- /* SStatus oscillates between zero and valid status after
- * DEV_RST, debounce it.
- */
- rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
- if (rc) {
- reason = "PHY debouncing failed";
- goto err;
- }
-
- if (tmp & PORT_CS_DEV_RST) {
- if (ata_port_offline(ap))
- return 0;
- reason = "link not ready";
- goto err;
- }
-
- /* Sil24 doesn't store signature FIS after hardreset, so we
- * can't wait for BSY to clear. Some devices take a long time
- * to get ready and those devices will choke if we don't wait
- * for BSY clearance here. Tell libata to perform follow-up
- * softreset.
- */
- return -EAGAIN;
-
- err:
- ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
- return -EIO;
-}
-
-static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
- struct sil24_sge *sge)
-{
- struct scatterlist *sg;
- unsigned int idx = 0;
-
- ata_for_each_sg(sg, qc) {
- sge->addr = cpu_to_le64(sg_dma_address(sg));
- sge->cnt = cpu_to_le32(sg_dma_len(sg));
- if (ata_sg_is_last(sg, qc))
- sge->flags = cpu_to_le32(SGE_TRM);
- else
- sge->flags = 0;
-
- sge++;
- idx++;
- }
-}
-
-static void sil24_qc_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct sil24_port_priv *pp = ap->private_data;
- union sil24_cmd_block *cb;
- struct sil24_prb *prb;
- struct sil24_sge *sge;
- u16 ctrl = 0;
-
- cb = &pp->cmd_block[sil24_tag(qc->tag)];
-
- switch (qc->tf.protocol) {
- case ATA_PROT_PIO:
- case ATA_PROT_DMA:
- case ATA_PROT_NCQ:
- case ATA_PROT_NODATA:
- prb = &cb->ata.prb;
- sge = cb->ata.sge;
- break;
-
- case ATA_PROT_ATAPI:
- case ATA_PROT_ATAPI_DMA:
- case ATA_PROT_ATAPI_NODATA:
- prb = &cb->atapi.prb;
- sge = cb->atapi.sge;
- memset(cb->atapi.cdb, 0, 32);
- memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
-
- if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- ctrl = PRB_CTRL_PACKET_WRITE;
- else
- ctrl = PRB_CTRL_PACKET_READ;
- }
- break;
-
- default:
- prb = NULL; /* shut up, gcc */
- sge = NULL;
- BUG();
- }
-
- prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
-
- if (qc->flags & ATA_QCFLAG_DMAMAP)
- sil24_fill_sg(qc, sge);
-}
-
-static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- unsigned int tag = sil24_tag(qc->tag);
- dma_addr_t paddr;
- void __iomem *activate;
-
- paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
- activate = port + PORT_CMD_ACTIVATE + tag * 8;
-
- writel((u32)paddr, activate);
- writel((u64)paddr >> 32, activate + 4);
-
- return 0;
-}
-
-static void sil24_irq_clear(struct ata_port *ap)
-{
- /* unused */
-}
-
-static void sil24_freeze(struct ata_port *ap)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
-
- /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
- * PORT_IRQ_ENABLE instead.
- */
- writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
-}
-
-static void sil24_thaw(struct ata_port *ap)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- u32 tmp;
-
- /* clear IRQ */
- tmp = readl(port + PORT_IRQ_STAT);
- writel(tmp, port + PORT_IRQ_STAT);
-
- /* turn IRQ back on */
- writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
-}
-
-static void sil24_error_intr(struct ata_port *ap)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- struct ata_eh_info *ehi = &ap->eh_info;
- int freeze = 0;
- u32 irq_stat;
-
- /* on error, we need to clear IRQ explicitly */
- irq_stat = readl(port + PORT_IRQ_STAT);
- writel(irq_stat, port + PORT_IRQ_STAT);
-
- /* first, analyze and record host port events */
- ata_ehi_clear_desc(ehi);
-
- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
-
- if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s",
- irq_stat & PORT_IRQ_PHYRDY_CHG ?
- "PHY RDY changed" : "device exchanged");
- freeze = 1;
- }
-
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi , ", unknown FIS");
- freeze = 1;
- }
-
- /* deal with command error */
- if (irq_stat & PORT_IRQ_ERROR) {
- struct sil24_cerr_info *ci = NULL;
- unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- u32 cerr;
-
- /* analyze CMD_ERR */
- cerr = readl(port + PORT_CMD_ERR);
- if (cerr < ARRAY_SIZE(sil24_cerr_db))
- ci = &sil24_cerr_db[cerr];
-
- if (ci && ci->desc) {
- err_mask |= ci->err_mask;
- action |= ci->action;
- ata_ehi_push_desc(ehi, ", %s", ci->desc);
- } else {
- err_mask |= AC_ERR_OTHER;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown command error %d",
- cerr);
- }
-
- /* record error info */
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc) {
- sil24_update_tf(ap);
- qc->err_mask |= err_mask;
- } else
- ehi->err_mask |= err_mask;
-
- ehi->action |= action;
- }
-
- /* freeze or abort */
- if (freeze)
- ata_port_freeze(ap);
- else
- ata_port_abort(ap);
-}
-
-static void sil24_finish_qc(struct ata_queued_cmd *qc)
-{
- if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(qc->ap);
-}
-
-static inline void sil24_host_intr(struct ata_port *ap)
-{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- u32 slot_stat, qc_active;
- int rc;
-
- slot_stat = readl(port + PORT_SLOT_STAT);
-
- if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
- sil24_error_intr(ap);
- return;
- }
-
- if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
-
- qc_active = slot_stat & ~HOST_SSTAT_ATTN;
- rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
- if (rc > 0)
- return;
- if (rc < 0) {
- struct ata_eh_info *ehi = &ap->eh_info;
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_SOFTRESET;
- ata_port_freeze(ap);
- return;
- }
-
- if (ata_ratelimit())
- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
- slot_stat, ap->active_tag, ap->sactive);
-}
-
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct sil24_host_priv *hpriv = host_set->private_data;
- unsigned handled = 0;
- u32 status;
- int i;
-
- status = readl(hpriv->host_base + HOST_IRQ_STAT);
-
- if (status == 0xffffffff) {
- printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
- "PCI fault or device removal?\n");
- goto out;
- }
-
- if (!(status & IRQ_STAT_4PORTS))
- goto out;
-
- spin_lock(&host_set->lock);
-
- for (i = 0; i < host_set->n_ports; i++)
- if (status & (1 << i)) {
- struct ata_port *ap = host_set->ports[i];
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- sil24_host_intr(host_set->ports[i]);
- handled++;
- } else
- printk(KERN_ERR DRV_NAME
- ": interrupt from disabled port %d\n", i);
- }
-
- spin_unlock(&host_set->lock);
- out:
- return IRQ_RETVAL(handled);
-}
-
-static void sil24_error_handler(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
-
- if (sil24_init_port(ap)) {
- ata_eh_freeze_port(ap);
- ehc->i.action |= ATA_EH_HARDRESET;
- }
-
- /* perform recovery */
- ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
- ata_std_postreset);
-}
-
-static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
- /* make DMA engine forget about the failed command */
- if (qc->err_mask)
- sil24_init_port(ap);
-}
-
-static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
-{
- const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
-
- dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
-}
-
-static int sil24_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct sil24_port_priv *pp;
- union sil24_cmd_block *cb;
- size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
- dma_addr_t cb_dma;
- int rc = -ENOMEM;
-
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp)
- goto err_out;
-
- pp->tf.command = ATA_DRDY;
-
- cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
- if (!cb)
- goto err_out_pp;
- memset(cb, 0, cb_size);
-
- rc = ata_pad_alloc(ap, dev);
- if (rc)
- goto err_out_pad;
-
- pp->cmd_block = cb;
- pp->cmd_block_dma = cb_dma;
-
- ap->private_data = pp;
-
- return 0;
-
-err_out_pad:
- sil24_cblk_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
-}
-
-static void sil24_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct sil24_port_priv *pp = ap->private_data;
-
- sil24_cblk_free(pp, dev);
- ata_pad_free(ap, dev);
- kfree(pp);
-}
-
-static void sil24_host_stop(struct ata_host_set *host_set)
-{
- struct sil24_host_priv *hpriv = host_set->private_data;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
-
- pci_iounmap(pdev, hpriv->host_base);
- pci_iounmap(pdev, hpriv->port_base);
- kfree(hpriv);
-}
-
-static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version = 0;
- unsigned int board_id = (unsigned int)ent->driver_data;
- struct ata_port_info *pinfo = &sil24_port_info[board_id];
- struct ata_probe_ent *probe_ent = NULL;
- struct sil24_host_priv *hpriv = NULL;
- void __iomem *host_base = NULL;
- void __iomem *port_base = NULL;
- int i, rc;
- u32 tmp;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto out_disable;
-
- rc = -ENOMEM;
- /* map mmio registers */
- host_base = pci_iomap(pdev, 0, 0);
- if (!host_base)
- goto out_free;
- port_base = pci_iomap(pdev, 2, 0);
- if (!port_base)
- goto out_free;
-
- /* allocate & init probe_ent and hpriv */
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- goto out_free;
-
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- goto out_free;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = pinfo->sht;
- probe_ent->host_flags = pinfo->host_flags;
- probe_ent->pio_mask = pinfo->pio_mask;
- probe_ent->mwdma_mask = pinfo->mwdma_mask;
- probe_ent->udma_mask = pinfo->udma_mask;
- probe_ent->port_ops = pinfo->port_ops;
- probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags);
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = port_base;
- probe_ent->private_data = hpriv;
-
- hpriv->host_base = host_base;
- hpriv->port_base = port_base;
-
- /*
- * Configure the device
- */
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
- goto out_free;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- goto out_free;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- goto out_free;
- }
- }
-
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
- /* Apply workaround for completion IRQ loss on PCI-X errata */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
- tmp = readl(host_base + HOST_CTRL);
- if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying completion IRQ loss on PCI-X "
- "errata fix\n");
- else
- probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
- }
-
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
- for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
-
- probe_ent->port[i].cmd_addr = portu;
- probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
-
- ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
- }
-
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
-
- kfree(probe_ent);
- return 0;
-
- out_free:
- if (host_base)
- pci_iounmap(pdev, host_base);
- if (port_base)
- pci_iounmap(pdev, port_base);
- kfree(probe_ent);
- kfree(hpriv);
- pci_release_regions(pdev);
- out_disable:
- pci_disable_device(pdev);
- return rc;
-}
-
-static int __init sil24_init(void)
-{
- return pci_module_init(&sil24_pci_driver);
-}
-
-static void __exit sil24_exit(void)
-{
- pci_unregister_driver(&sil24_pci_driver);
-}
-
-MODULE_AUTHOR("Tejun Heo");
-MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, sil24_pci_tbl);
-
-module_init(sil24_init);
-module_exit(sil24_exit);
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
deleted file mode 100644
index 809d337ed64..00000000000
--- a/drivers/scsi/sata_sis.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * sata_sis.c - Silicon Integrated Systems SATA
- *
- * Maintained by: Uwe Koziolek
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2004 Uwe Koziolek
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available under NDA.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_sis"
-#define DRV_VERSION "0.6"
-
-enum {
- sis_180 = 0,
- SIS_SCR_PCI_BAR = 5,
-
- /* PCI configuration registers */
- SIS_GENCTL = 0x54, /* IDE General Control register */
- SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */
- SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */
- SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */
- SIS_PMR = 0x90, /* port mapping register */
- SIS_PMR_COMBINED = 0x30,
-
- /* random bits */
- SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */
-
- GENCTL_IOMAPPED_SCR = (1 << 26), /* if set, SCRs are in IO space */
-};
-
-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-
-static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { } /* terminate list */
-};
-
-
-static struct pci_driver sis_pci_driver = {
- .name = DRV_NAME,
- .id_table = sis_pci_tbl,
- .probe = sis_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static struct scsi_host_template sis_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = ATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations sis_ops = {
- .port_disable = ata_port_disable,
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = sis_scr_read,
- .scr_write = sis_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
-};
-
-static struct ata_port_info sis_port_info = {
- .sht = &sis_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x7,
- .udma_mask = 0x7f,
- .port_ops = &sis_ops,
-};
-
-
-MODULE_AUTHOR("Uwe Koziolek");
-MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
-{
- unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
-
- if (port_no) {
- if (device == 0x182)
- addr += SIS182_SATA1_OFS;
- else
- addr += SIS180_SATA1_OFS;
- }
-
- return addr;
-}
-
-static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
- u32 val, val2 = 0;
- u8 pmr;
-
- if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return 0xffffffff;
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
- pci_read_config_dword(pdev, cfg_addr, &val);
-
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
-
- return val|val2;
-}
-
-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
- u8 pmr;
-
- if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
- return;
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
- pci_write_config_dword(pdev, cfg_addr, val);
-
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- pci_write_config_dword(pdev, cfg_addr+0x10, val);
-}
-
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- u32 val, val2 = 0;
- u8 pmr;
-
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
-
- if (ap->flags & SIS_FLAG_CFGSCR)
- return sis_scr_cfg_read(ap, sc_reg);
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
- val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
-
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
-
- return val | val2;
-}
-
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- u8 pmr;
-
- if (sc_reg > SCR_CONTROL)
- return;
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
-
- if (ap->flags & SIS_FLAG_CFGSCR)
- sis_scr_cfg_write(ap, sc_reg, val);
- else {
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
- }
-}
-
-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- int rc;
- u32 genctl;
- struct ata_port_info *ppi;
- int pci_dev_busy = 0;
- u8 pmr;
- u8 port2_start;
-
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- ppi = &sis_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- /* check and see if the SCRs are in IO space or PCI cfg space */
- pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
- if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
-
- /* if hardware thinks SCRs are in IO space, but there are
- * no IO resources assigned, change to PCI cfg space.
- */
- if ((!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) &&
- ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
- (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
- genctl &= ~GENCTL_IOMAPPED_SCR;
- pci_write_config_dword(pdev, SIS_GENCTL, genctl);
- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
- }
-
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
- if (ent->device != 0x182) {
- if ((pmr & SIS_PMR_COMBINED) == 0) {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 180/181 chipset in SATA mode\n");
- port2_start = 64;
- }
- else {
- dev_printk(KERN_INFO, &pdev->dev,
- "Detected SiS 180/181 chipset in combined mode\n");
- port2_start=0;
- }
- }
- else {
- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n");
- port2_start = 0x20;
- }
-
- if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
- probe_ent->port[0].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR);
- probe_ent->port[1].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
- }
-
- pci_set_master(pdev);
- pci_intx(pdev, 1);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_regions:
- pci_release_regions(pdev);
-
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
-}
-
-static int __init sis_init(void)
-{
- return pci_module_init(&sis_pci_driver);
-}
-
-static void __exit sis_exit(void)
-{
- pci_unregister_driver(&sis_pci_driver);
-}
-
-module_init(sis_init);
-module_exit(sis_exit);
-
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
deleted file mode 100644
index c94b870cf37..00000000000
--- a/drivers/scsi/sata_svw.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * sata_svw.c - ServerWorks / Apple K2 SATA
- *
- * Maintained by: Benjamin Herrenschmidt <benh@kernel.crashing.org> and
- * Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *
- * Bits from Jeff Garzik, Copyright RedHat, Inc.
- *
- * This driver probably works with non-Apple versions of the
- * Broadcom chipset...
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available under NDA.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#ifdef CONFIG_PPC_OF
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif /* CONFIG_PPC_OF */
-
-#define DRV_NAME "sata_svw"
-#define DRV_VERSION "1.8"
-
-enum {
- /* Taskfile registers offsets */
- K2_SATA_TF_CMD_OFFSET = 0x00,
- K2_SATA_TF_DATA_OFFSET = 0x00,
- K2_SATA_TF_ERROR_OFFSET = 0x04,
- K2_SATA_TF_NSECT_OFFSET = 0x08,
- K2_SATA_TF_LBAL_OFFSET = 0x0c,
- K2_SATA_TF_LBAM_OFFSET = 0x10,
- K2_SATA_TF_LBAH_OFFSET = 0x14,
- K2_SATA_TF_DEVICE_OFFSET = 0x18,
- K2_SATA_TF_CMDSTAT_OFFSET = 0x1c,
- K2_SATA_TF_CTL_OFFSET = 0x20,
-
- /* DMA base */
- K2_SATA_DMA_CMD_OFFSET = 0x30,
-
- /* SCRs base */
- K2_SATA_SCR_STATUS_OFFSET = 0x40,
- K2_SATA_SCR_ERROR_OFFSET = 0x44,
- K2_SATA_SCR_CONTROL_OFFSET = 0x48,
-
- /* Others */
- K2_SATA_SICR1_OFFSET = 0x80,
- K2_SATA_SICR2_OFFSET = 0x84,
- K2_SATA_SIM_OFFSET = 0x88,
-
- /* Port stride */
- K2_SATA_PORT_OFFSET = 0x100,
-};
-
-static u8 k2_stat_check_status(struct ata_port *ap);
-
-
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, ioaddr->ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
- } else if (is_addr) {
- writew(tf->feature, ioaddr->feature_addr);
- writew(tf->nsect, ioaddr->nsect_addr);
- writew(tf->lbal, ioaddr->lbal_addr);
- writew(tf->lbam, ioaddr->lbam_addr);
- writew(tf->lbah, ioaddr->lbah_addr);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE)
- writeb(tf->device, ioaddr->device_addr);
-
- ata_wait_idle(ap);
-}
-
-
-static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u16 nsect, lbal, lbam, lbah, feature;
-
- tf->command = k2_stat_check_status(ap);
- tf->device = readw(ioaddr->device_addr);
- feature = readw(ioaddr->error_addr);
- nsect = readw(ioaddr->nsect_addr);
- lbal = readw(ioaddr->lbal_addr);
- lbam = readw(ioaddr->lbam_addr);
- lbah = readw(ioaddr->lbah_addr);
-
- tf->feature = feature;
- tf->nsect = nsect;
- tf->lbal = lbal;
- tf->lbam = lbam;
- tf->lbah = lbah;
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- tf->hob_feature = feature >> 8;
- tf->hob_nsect = nsect >> 8;
- tf->hob_lbal = lbal >> 8;
- tf->hob_lbam = lbam >> 8;
- tf->hob_lbah = lbah >> 8;
- }
-}
-
-/**
- * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
- /* load PRD table addr. */
- mb(); /* make sure PRD table writes are visible to controller */
- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = readb(mmio + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- writeb(dmactl, mmio + ATA_DMA_CMD);
-
- /* issue r/w command if this is not a ATA DMA command*/
- if (qc->tf.protocol != ATA_PROT_DMA)
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-/**
- * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = readb(mmio + ATA_DMA_CMD);
- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
- /* There is a race condition in certain SATA controllers that can
- be seen when the r/w command is given to the controller before the
- host DMA is started. On a Read command, the controller would initiate
- the command to the drive even before it sees the DMA start. When there
- are very fast drives connected to the controller, or when the data request
- hits in the drive cache, there is the possibility that the drive returns a part
- or all of the requested data to the controller before the DMA start is issued.
- In this case, the controller would become confused as to what to do with the data.
- In the worst case when all the data is returned back to the controller, the
- controller could hang. In other cases it could return partial data returning
- in data corruption. This problem has been seen in PPC systems and can also appear
- on an system with very fast disks, where the SATA controller is sitting behind a
- number of bridges, and hence there is significant latency between the r/w command
- and the start command. */
- /* issue r/w command if the access is to ATA*/
- if (qc->tf.protocol == ATA_PROT_DMA)
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-
-static u8 k2_stat_check_status(struct ata_port *ap)
-{
- return readl((void *) ap->ioaddr.status_addr);
-}
-
-#ifdef CONFIG_PPC_OF
-/*
- * k2_sata_proc_info
- * inout : decides on the direction of the dataflow and the meaning of the
- * variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file
- * from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer
- * else number of bytes in the buffer
- */
-static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
- off_t offset, int count, int inout)
-{
- struct ata_port *ap;
- struct device_node *np;
- int len, index;
-
- /* Find the ata_port */
- ap = ata_shost_to_port(shost);
- if (ap == NULL)
- return 0;
-
- /* Find the OF node for the PCI device proper */
- np = pci_device_to_OF_node(to_pci_dev(ap->host_set->dev));
- if (np == NULL)
- return 0;
-
- /* Match it to a port node */
- index = (ap == ap->host_set->ports[0]) ? 0 : 1;
- for (np = np->child; np != NULL; np = np->sibling) {
- u32 *reg = (u32 *)get_property(np, "reg", NULL);
- if (!reg)
- continue;
- if (index == *reg)
- break;
- }
- if (np == NULL)
- return 0;
-
- len = sprintf(page, "devspec: %s\n", np->full_name);
-
- return len;
-}
-#endif /* CONFIG_PPC_OF */
-
-
-static struct scsi_host_template k2_sata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
-#ifdef CONFIG_PPC_OF
- .proc_info = k2_sata_proc_info,
-#endif
- .bios_param = ata_std_bios_param,
-};
-
-
-static const struct ata_port_operations k2_sata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = k2_sata_tf_load,
- .tf_read = k2_sata_tf_read,
- .check_status = k2_stat_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = k2_bmdma_setup_mmio,
- .bmdma_start = k2_bmdma_start_mmio,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = k2_sata_scr_read,
- .scr_write = k2_sata_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
-};
-
-static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
- port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
- port->feature_addr =
- port->error_addr = base + K2_SATA_TF_ERROR_OFFSET;
- port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET;
- port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET;
- port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET;
- port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET;
- port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET;
- port->command_addr =
- port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET;
- port->altstatus_addr =
- port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET;
- port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET;
- port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET;
-}
-
-
-static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- void __iomem *mmio_base;
- int pci_dev_busy = 0;
- int rc;
- int i;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- /*
- * If this driver happens to only be useful on Apple's K2, then
- * we should check that here as it has a normal Serverworks ID
- */
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
- /*
- * Check if we have resources mapped at all (second function may
- * have been disabled by firmware)
- */
- if (pci_resource_len(pdev, 5) == 0)
- return -ENODEV;
-
- /* Request PCI regions */
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- /* Clear a magic bit in SCR1 according to Darwin, those help
- * some funky seagate drives (though so far, those were already
- * set by the firmware on the machines I had access to)
- */
- writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
- mmio_base + K2_SATA_SICR1_OFFSET);
-
- /* Clear SATA error & interrupts we don't use */
- writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
- writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
-
- probe_ent->sht = &k2_sata_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO;
- probe_ent->port_ops = &k2_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x7;
- probe_ent->udma_mask = 0x7f;
-
- /* different controllers have different number of ports - currently 4 or 8 */
- /* All ports are on the same function. Multi-function device is no
- * longer available. This should not be seen in any system. */
- for (i = 0; i < ent->driver_data; i++)
- k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-/* 0x240 is device ID for Apple K2 device
- * 0x241 is device ID for Serverworks Frodo4
- * 0x242 is device ID for Serverworks Frodo8
- * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
- * controller
- * */
-static const struct pci_device_id k2_sata_pci_tbl[] = {
- { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { }
-};
-
-
-static struct pci_driver k2_sata_pci_driver = {
- .name = DRV_NAME,
- .id_table = k2_sata_pci_tbl,
- .probe = k2_sata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-
-static int __init k2_sata_init(void)
-{
- return pci_module_init(&k2_sata_pci_driver);
-}
-
-
-static void __exit k2_sata_exit(void)
-{
- pci_unregister_driver(&k2_sata_pci_driver);
-}
-
-
-MODULE_AUTHOR("Benjamin Herrenschmidt");
-MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(k2_sata_init);
-module_exit(k2_sata_exit);
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
deleted file mode 100644
index 7f864410f7c..00000000000
--- a/drivers/scsi/sata_sx4.c
+++ /dev/null
@@ -1,1502 +0,0 @@
-/*
- * sata_sx4.c - Promise SATA
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2003-2004 Red Hat, 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available under NDA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-#include "sata_promise.h"
-
-#define DRV_NAME "sata_sx4"
-#define DRV_VERSION "0.9"
-
-
-enum {
- PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
-
- PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
- PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
-
- PDC_20621_SEQCTL = 0x400,
- PDC_20621_SEQMASK = 0x480,
- PDC_20621_GENERAL_CTL = 0x484,
- PDC_20621_PAGE_SIZE = (32 * 1024),
-
- /* chosen, not constant, values; we design our own DIMM mem map */
- PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
- PDC_20621_DIMM_BASE = 0x00200000,
- PDC_20621_DIMM_DATA = (64 * 1024),
- PDC_DIMM_DATA_STEP = (256 * 1024),
- PDC_DIMM_WINDOW_STEP = (8 * 1024),
- PDC_DIMM_HOST_PRD = (6 * 1024),
- PDC_DIMM_HOST_PKT = (128 * 0),
- PDC_DIMM_HPKT_PRD = (128 * 1),
- PDC_DIMM_ATA_PKT = (128 * 2),
- PDC_DIMM_APKT_PRD = (128 * 3),
- PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
- PDC_PAGE_WINDOW = 0x40,
- PDC_PAGE_DATA = PDC_PAGE_WINDOW +
- (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
- PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
-
- PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
-
- PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
- (1<<23),
-
- board_20621 = 0, /* FastTrak S150 SX4 */
-
- PDC_RESET = (1 << 11), /* HDMA reset */
-
- PDC_MAX_HDMA = 32,
- PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
-
- PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
- PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
- PDC_MAX_DIMM_MODULE = 0x02,
- PDC_I2C_CONTROL_OFFSET = 0x48,
- PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
- PDC_DIMM0_CONTROL_OFFSET = 0x80,
- PDC_DIMM1_CONTROL_OFFSET = 0x84,
- PDC_SDRAM_CONTROL_OFFSET = 0x88,
- PDC_I2C_WRITE = 0x00000000,
- PDC_I2C_READ = 0x00000040,
- PDC_I2C_START = 0x00000080,
- PDC_I2C_MASK_INT = 0x00000020,
- PDC_I2C_COMPLETE = 0x00010000,
- PDC_I2C_NO_ACK = 0x00100000,
- PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
- PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
- PDC_DIMM_SPD_ROW_NUM = 3,
- PDC_DIMM_SPD_COLUMN_NUM = 4,
- PDC_DIMM_SPD_MODULE_ROW = 5,
- PDC_DIMM_SPD_TYPE = 11,
- PDC_DIMM_SPD_FRESH_RATE = 12,
- PDC_DIMM_SPD_BANK_NUM = 17,
- PDC_DIMM_SPD_CAS_LATENCY = 18,
- PDC_DIMM_SPD_ATTRIBUTE = 21,
- PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
- PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
- PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
- PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
- PDC_DIMM_SPD_SYSTEM_FREQ = 126,
- PDC_CTL_STATUS = 0x08,
- PDC_DIMM_WINDOW_CTLR = 0x0C,
- PDC_TIME_CONTROL = 0x3C,
- PDC_TIME_PERIOD = 0x40,
- PDC_TIME_COUNTER = 0x44,
- PDC_GENERAL_CTLR = 0x484,
- PCI_PLL_INIT = 0x8A531824,
- PCI_X_TCOUNT = 0xEE1E5CFF
-};
-
-
-struct pdc_port_priv {
- u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
- u8 *pkt;
- dma_addr_t pkt_dma;
-};
-
-struct pdc_host_priv {
- void __iomem *dimm_mmio;
-
- unsigned int doing_hdma;
- unsigned int hdma_prod;
- unsigned int hdma_cons;
- struct {
- struct ata_queued_cmd *qc;
- unsigned int seq;
- unsigned long pkt_ofs;
- } hdma[32];
-};
-
-
-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static void pdc_eng_timeout(struct ata_port *ap);
-static void pdc_20621_phy_reset (struct ata_port *ap);
-static int pdc_port_start(struct ata_port *ap);
-static void pdc_port_stop(struct ata_port *ap);
-static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host_set *host_set);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
- u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
- void *psource, u32 offset, u32 size);
-#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
- void *psource, u32 offset, u32 size);
-static void pdc20621_irq_clear(struct ata_port *ap);
-static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
-
-
-static struct scsi_host_template pdc_sata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations pdc_20621_ops = {
- .port_disable = ata_port_disable,
- .tf_load = pdc_tf_load_mmio,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = pdc_exec_command_mmio,
- .dev_select = ata_std_dev_select,
- .phy_reset = pdc_20621_phy_reset,
- .qc_prep = pdc20621_qc_prep,
- .qc_issue = pdc20621_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
- .eng_timeout = pdc_eng_timeout,
- .irq_handler = pdc20621_interrupt,
- .irq_clear = pdc20621_irq_clear,
- .port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc20621_host_stop,
-};
-
-static const struct ata_port_info pdc_port_info[] = {
- /* board_20621 */
- {
- .sht = &pdc_sata_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
- .pio_mask = 0x1f, /* pio0-4 */
- .mwdma_mask = 0x07, /* mwdma0-2 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_20621_ops,
- },
-
-};
-
-static const struct pci_device_id pdc_sata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20621 },
- { } /* terminate list */
-};
-
-
-static struct pci_driver pdc_sata_pci_driver = {
- .name = DRV_NAME,
- .id_table = pdc_sata_pci_tbl,
- .probe = pdc_sata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-
-static void pdc20621_host_stop(struct ata_host_set *host_set)
-{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
- struct pdc_host_priv *hpriv = host_set->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
-
- pci_iounmap(pdev, dimm_mmio);
- kfree(hpriv);
-
- pci_iounmap(pdev, host_set->mmio_base);
-}
-
-static int pdc_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct pdc_port_priv *pp;
- int rc;
-
- rc = ata_port_start(ap);
- if (rc)
- return rc;
-
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- memset(pp, 0, sizeof(*pp));
-
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
-
- ap->private_data = pp;
-
- return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host_set->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
-}
-
-
-static void pdc_20621_phy_reset (struct ata_port *ap)
-{
- VPRINTK("ENTER\n");
- ap->cbl = ATA_CBL_SATA;
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output ATA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
- VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output Host DMA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
-
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
- unsigned int devno, u8 *buf,
- unsigned int portno)
-{
- unsigned int i, dw;
- u32 *buf32 = (u32 *) buf;
- u8 dev_reg;
-
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
-
- i = PDC_DIMM_ATA_PKT;
-
- /*
- * Set up ATA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- buf[i++] = PDC_PKT_READ;
- else if (tf->protocol == ATA_PROT_NODATA)
- buf[i++] = PDC_PKT_NODATA;
- else
- buf[i++] = 0;
- buf[i++] = 0; /* reserved */
- buf[i++] = portno + 1; /* seq. id */
- buf[i++] = 0xff; /* delay seq. id */
-
- /* dimm dma S/G, and next-pkt */
- dw = i >> 2;
- if (tf->protocol == ATA_PROT_NODATA)
- buf32[dw] = 0;
- else
- buf32[dw] = cpu_to_le32(dimm_sg);
- buf32[dw + 1] = 0;
- i += 8;
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[i++] = dev_reg;
-
- /* device control register */
- buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
- buf[i++] = tf->ctl;
-
- return i;
-}
-
-static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno)
-{
- unsigned int dw;
- u32 tmp, *buf32 = (u32 *) buf;
-
- unsigned int host_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PRD;
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
- VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
-
- dw = PDC_DIMM_HOST_PKT >> 2;
-
- /*
- * Set up Host DMA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- tmp = PDC_PKT_READ;
- else
- tmp = 0;
- tmp |= ((portno + 1 + 4) << 16); /* seq. id */
- tmp |= (0xff << 24); /* delay seq. id */
- buf32[dw + 0] = cpu_to_le32(tmp);
- buf32[dw + 1] = cpu_to_le32(host_sg);
- buf32[dw + 2] = cpu_to_le32(dimm_sg);
- buf32[dw + 3] = 0;
-
- VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PKT,
- buf32[dw + 0],
- buf32[dw + 1],
- buf32[dw + 2],
- buf32[dw + 3]);
-}
-
-static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
-{
- struct scatterlist *sg;
- struct ata_port *ap = qc->ap;
- struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
- unsigned int portno = ap->port_no;
- unsigned int i, idx, total_len = 0, sgt_len;
- u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
-
- WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- * Build S/G table
- */
- idx = 0;
- ata_for_each_sg(sg, qc) {
- buf[idx++] = cpu_to_le32(sg_dma_address(sg));
- buf[idx++] = cpu_to_le32(sg_dma_len(sg));
- total_len += sg_dma_len(sg);
- }
- buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
- sgt_len = idx * 4;
-
- /*
- * Build ATA, host DMA packets
- */
- pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
-
- pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
-
- if (qc->tf.flags & ATA_TFLAG_LBA48)
- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
- else
- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
-
- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
-
- /* copy three S/G tables and two packets to DIMM MMIO window */
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
- PDC_DIMM_HOST_PRD,
- &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
-
- /* force host FIFO dump */
- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
-
- readl(dimm_mmio); /* MMIO PCI posting flush */
-
- VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
-}
-
-static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
- unsigned int portno = ap->port_no;
- unsigned int i;
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
-
- if (qc->tf.flags & ATA_TFLAG_LBA48)
- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
- else
- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
-
- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
-
- /* copy three S/G tables and two packets to DIMM MMIO window */
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
-
- /* force host FIFO dump */
- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
-
- readl(dimm_mmio); /* MMIO PCI posting flush */
-
- VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
-}
-
-static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
-{
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- pdc20621_dma_prep(qc);
- break;
- case ATA_PROT_NODATA:
- pdc20621_nodata_prep(qc);
- break;
- default:
- break;
- }
-}
-
-static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
- readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
-}
-
-static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
-
- if (!pp->doing_hdma) {
- __pdc20621_push_hdma(qc, seq, pkt_ofs);
- pp->doing_hdma = 1;
- return;
- }
-
- pp->hdma[idx].qc = qc;
- pp->hdma[idx].seq = seq;
- pp->hdma[idx].pkt_ofs = pkt_ofs;
- pp->hdma_prod++;
-}
-
-static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
-
- /* if nothing on queue, we're done */
- if (pp->hdma_prod == pp->hdma_cons) {
- pp->doing_hdma = 0;
- return;
- }
-
- __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
- pp->hdma[idx].pkt_ofs);
- pp->hdma_cons++;
-}
-
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
- dimm_mmio += PDC_DIMM_HOST_PKT;
-
- printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
- printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
- printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
- printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
-}
-#else
-static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
-#endif /* ATA_VERBOSE_DEBUG */
-
-static void pdc20621_packet_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- unsigned int port_no = ap->port_no;
- void __iomem *mmio = host_set->mmio_base;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 seq = (u8) (port_no + 1);
- unsigned int port_ofs;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- wmb(); /* flush PRD, pkt writes */
-
- port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
-
- /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
- if (rw && qc->tf.protocol == ATA_PROT_DMA) {
- seq += 4;
-
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
- VPRINTK("queued ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_HOST_PKT,
- port_ofs + PDC_DIMM_HOST_PKT,
- seq);
- } else {
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_ATA_PKT,
- port_ofs + PDC_DIMM_ATA_PKT,
- seq);
- }
-}
-
-static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
-{
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- pdc20621_packet_start(qc);
- return 0;
-
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
- default:
- break;
- }
-
- return ata_qc_issue_prot(qc);
-}
-
-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
- struct ata_queued_cmd *qc,
- unsigned int doing_hdma,
- void __iomem *mmio)
-{
- unsigned int port_no = ap->port_no;
- unsigned int port_ofs =
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
- u8 status;
- unsigned int handled = 0;
-
- VPRINTK("ENTER\n");
-
- if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
-
- /* step two - DMA from DIMM to host */
- if (doing_hdma) {
- VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- /* get drive status; clear intr; complete txn */
- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
- ata_qc_complete(qc);
- pdc20621_pop_hdma(qc);
- }
-
- /* step one - exec ATA command */
- else {
- u8 seq = (u8) (port_no + 1 + 4);
- VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit hdma pkt */
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq,
- port_ofs + PDC_DIMM_HOST_PKT);
- }
- handled = 1;
-
- } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
-
- /* step one - DMA from host to DIMM */
- if (doing_hdma) {
- u8 seq = (u8) (port_no + 1);
- VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit ata pkt */
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4));
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- }
-
- /* step two - execute ATA command */
- else {
- VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- /* get drive status; clear intr; complete txn */
- qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
- ata_qc_complete(qc);
- pdc20621_pop_hdma(qc);
- }
- handled = 1;
-
- /* command completion, but no data xfer */
- } else if (qc->tf.protocol == ATA_PROT_NODATA) {
-
- status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
- qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
- handled = 1;
-
- } else {
- ap->stats.idle_irq++;
- }
-
- return handled;
-}
-
-static void pdc20621_irq_clear(struct ata_port *ap)
-{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
-
- mmio += PDC_CHIP0_OFS;
-
- readl(mmio + PDC_20621_SEQMASK);
-}
-
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct ata_port *ap;
- u32 mask = 0;
- unsigned int i, tmp, port_no;
- unsigned int handled = 0;
- void __iomem *mmio_base;
-
- VPRINTK("ENTER\n");
-
- if (!host_set || !host_set->mmio_base) {
- VPRINTK("QUICK EXIT\n");
- return IRQ_NONE;
- }
-
- mmio_base = host_set->mmio_base;
-
- /* reading should also clear interrupts */
- mmio_base += PDC_CHIP0_OFS;
- mask = readl(mmio_base + PDC_20621_SEQMASK);
- VPRINTK("mask == 0x%x\n", mask);
-
- if (mask == 0xffffffff) {
- VPRINTK("QUICK EXIT 2\n");
- return IRQ_NONE;
- }
- mask &= 0xffff; /* only 16 tags possible */
- if (!mask) {
- VPRINTK("QUICK EXIT 3\n");
- return IRQ_NONE;
- }
-
- spin_lock(&host_set->lock);
-
- for (i = 1; i < 9; i++) {
- port_no = i - 1;
- if (port_no > 3)
- port_no -= 4;
- if (port_no >= host_set->n_ports)
- ap = NULL;
- else
- ap = host_set->ports[port_no];
- tmp = mask & (1 << i);
- VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
- if (tmp && ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += pdc20621_host_intr(ap, qc, (i > 4),
- mmio_base);
- }
- }
-
- spin_unlock(&host_set->lock);
-
- VPRINTK("mask == 0x%x\n", mask);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static void pdc_eng_timeout(struct ata_port *ap)
-{
- u8 drv_stat;
- struct ata_host_set *host_set = ap->host_set;
- struct ata_queued_cmd *qc;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- spin_lock_irqsave(&host_set->lock, flags);
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- ata_port_printk(ap, KERN_ERR, "command timeout\n");
- qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
- break;
-
- default:
- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-
- ata_port_printk(ap, KERN_ERR,
- "unknown timeout, cmd 0x%x stat 0x%x\n",
- qc->tf.command, drv_stat);
-
- qc->err_mask |= ac_err_mask(drv_stat);
- break;
- }
-
- spin_unlock_irqrestore(&host_set->lock, flags);
- ata_eh_qc_complete(qc);
- DPRINTK("EXIT\n");
-}
-
-static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
- ata_tf_load(ap, tf);
-}
-
-
-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
- ata_exec_command(ap, tf);
-}
-
-
-static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr = base;
- port->data_addr = base;
- port->feature_addr =
- port->error_addr = base + 0x4;
- port->nsect_addr = base + 0x8;
- port->lbal_addr = base + 0xc;
- port->lbam_addr = base + 0x10;
- port->lbah_addr = base + 0x14;
- port->device_addr = base + 0x18;
- port->command_addr =
- port->status_addr = base + 0x1c;
- port->altstatus_addr =
- port->ctl_addr = base + 0x38;
-}
-
-
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
- u32 offset, u32 size)
-{
- u32 window_size;
- u16 idx;
- u8 page_mask;
- long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
- idx = (u16) (offset / window_size);
-
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
-
- offset -= (idx * window_size);
- idx++;
- dist = ((long) (window_size - (offset + size))) >= 0 ? size :
- (long) (window_size - offset);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
- dist);
-
- psource += dist;
- size -= dist;
- for (; (long) size >= (long) window_size ;) {
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- window_size / 4);
- psource += window_size;
- size -= window_size;
- idx ++;
- }
-
- if (size) {
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- size / 4);
- }
-}
-#endif
-
-
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
- u32 offset, u32 size)
-{
- u32 window_size;
- u16 idx;
- u8 page_mask;
- long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
- idx = (u16) (offset / window_size);
-
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- offset -= (idx * window_size);
- idx++;
- dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
- (long) (window_size - offset);
- memcpy_toio(dimm_mmio + offset / 4, psource, dist);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
-
- psource += dist;
- size -= dist;
- for (; (long) size >= (long) window_size ;) {
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_toio(dimm_mmio, psource, window_size / 4);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- psource += window_size;
- size -= window_size;
- idx ++;
- }
-
- if (size) {
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_toio(dimm_mmio, psource, size / 4);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- }
-}
-
-
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
- u32 subaddr, u32 *pdata)
-{
- void __iomem *mmio = pe->mmio_base;
- u32 i2creg = 0;
- u32 status;
- u32 count =0;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- i2creg |= device << 24;
- i2creg |= subaddr << 16;
-
- /* Set the device and subaddress */
- writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
- readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
-
- /* Write Control to perform read operation, mask int */
- writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
- mmio + PDC_I2C_CONTROL_OFFSET);
-
- for (count = 0; count <= 1000; count ++) {
- status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
- if (status & PDC_I2C_COMPLETE) {
- status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
- break;
- } else if (count == 1000)
- return 0;
- }
-
- *pdata = (status >> 8) & 0x000000ff;
- return 1;
-}
-
-
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
-{
- u32 data=0 ;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
- if (data == 100)
- return 100;
- } else
- return 0;
-
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
- if(data <= 0x75)
- return 133;
- } else
- return 0;
-
- return 0;
-}
-
-
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
-{
- u32 spd0[50];
- u32 data = 0;
- int size, i;
- u8 bdimmsize;
- void __iomem *mmio = pe->mmio_base;
- static const struct {
- unsigned int reg;
- unsigned int ofs;
- } pdc_i2c_read_data [] = {
- { PDC_DIMM_SPD_TYPE, 11 },
- { PDC_DIMM_SPD_FRESH_RATE, 12 },
- { PDC_DIMM_SPD_COLUMN_NUM, 4 },
- { PDC_DIMM_SPD_ATTRIBUTE, 21 },
- { PDC_DIMM_SPD_ROW_NUM, 3 },
- { PDC_DIMM_SPD_BANK_NUM, 17 },
- { PDC_DIMM_SPD_MODULE_ROW, 5 },
- { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
- { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
- { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
- { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
- { PDC_DIMM_SPD_CAS_LATENCY, 18 },
- };
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- pdc_i2c_read_data[i].reg,
- &spd0[pdc_i2c_read_data[i].ofs]);
-
- data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
- data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
- ((((spd0[27] + 9) / 10) - 1) << 8) ;
- data |= (((((spd0[29] > spd0[28])
- ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
- data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
-
- if (spd0[18] & 0x08)
- data |= ((0x03) << 14);
- else if (spd0[18] & 0x04)
- data |= ((0x02) << 14);
- else if (spd0[18] & 0x01)
- data |= ((0x01) << 14);
- else
- data |= (0 << 14);
-
- /*
- Calculate the size of bDIMMSize (power of 2) and
- merge the DIMM size by program start/end address.
- */
-
- bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
- size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
- data |= (((size / 16) - 1) << 16);
- data |= (0 << 23);
- data |= 8;
- writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
- readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
- return size;
-}
-
-
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
-{
- u32 data, spd0;
- int error, i;
- void __iomem *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- Set To Default : DIMM Module Global Control Register (0x022259F1)
- DIMM Arbitration Disable (bit 20)
- DIMM Data/Control Output Driving Selection (bit12 - bit15)
- Refresh Enable (bit 17)
- */
-
- data = 0x022259F1;
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
-
- /* Turn on for ECC */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
- if (spd0 == 0x02) {
- data |= (0x01 << 16);
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
- printk(KERN_ERR "Local DIMM ECC Enabled\n");
- }
-
- /* DIMM Initialization Select/Enable (bit 18/19) */
- data &= (~(1<<18));
- data |= (1<<19);
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
-
- error = 1;
- for (i = 1; i <= 10; i++) { /* polling ~5 secs */
- data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
- if (!(data & (1<<19))) {
- error = 0;
- break;
- }
- msleep(i*100);
- }
- return error;
-}
-
-
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
-{
- int speed, size, length;
- u32 addr,spd0,pci_status;
- u32 tmp=0;
- u32 time_period=0;
- u32 tcount=0;
- u32 ticks=0;
- u32 clock=0;
- u32 fparam=0;
- void __iomem *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /* Initialize PLL based upon PCI Bus Frequency */
-
- /* Initialize Time Period Register */
- writel(0xffffffff, mmio + PDC_TIME_PERIOD);
- time_period = readl(mmio + PDC_TIME_PERIOD);
- VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
-
- /* Enable timer */
- writel(0x00001a0, mmio + PDC_TIME_CONTROL);
- readl(mmio + PDC_TIME_CONTROL);
-
- /* Wait 3 seconds */
- msleep(3000);
-
- /*
- When timer is enabled, counter is decreased every internal
- clock cycle.
- */
-
- tcount = readl(mmio + PDC_TIME_COUNTER);
- VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
-
- /*
- If SX4 is on PCI-X bus, after 3 seconds, the timer counter
- register should be >= (0xffffffff - 3x10^8).
- */
- if(tcount >= PCI_X_TCOUNT) {
- ticks = (time_period - tcount);
- VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
-
- clock = (ticks / 300000);
- VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
-
- clock = (clock * 33);
- VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
-
- /* PLL F Param (bit 22:16) */
- fparam = (1400000 / clock) - 2;
- VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
-
- /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
- pci_status = (0x8a001824 | (fparam << 16));
- } else
- pci_status = PCI_PLL_INIT;
-
- /* Initialize PLL. */
- VPRINTK("pci_status: 0x%x\n", pci_status);
- writel(pci_status, mmio + PDC_CTL_STATUS);
- readl(mmio + PDC_CTL_STATUS);
-
- /*
- Read SPD of DIMM by I2C interface,
- and program the DIMM Module Controller.
- */
- if (!(speed = pdc20621_detect_dimm(pe))) {
- printk(KERN_ERR "Detect Local DIMM Fail\n");
- return 1; /* DIMM error */
- }
- VPRINTK("Local DIMM Speed = %d\n", speed);
-
- /* Programming DIMM0 Module Control Register (index_CID0:80h) */
- size = pdc20621_prog_dimm0(pe);
- VPRINTK("Local DIMM Size = %dMB\n",size);
-
- /* Programming DIMM Module Global Control Register (index_CID0:88h) */
- if (pdc20621_prog_dimm_global(pe)) {
- printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
- return 1;
- }
-
-#ifdef ATA_VERBOSE_DEBUG
- {
- u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
- 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
- '1','.','1','0',
- '9','8','0','3','1','6','1','2',0,0};
- u8 test_parttern2[40] = {0};
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
- 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
- }
-#endif
-
- /* ECC initiliazation. */
-
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
- if (spd0 == 0x02) {
- VPRINTK("Start ECC initialization\n");
- addr = 0;
- length = size * 1024 * 1024;
- while (addr < length) {
- pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
- sizeof(u32));
- addr += sizeof(u32);
- }
- VPRINTK("Finish ECC initialization\n");
- }
- return 0;
-}
-
-
-static void pdc_20621_init(struct ata_probe_ent *pe)
-{
- u32 tmp;
- void __iomem *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- * Select page 0x40 for our 32k DIMM window
- */
- tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
- tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
- writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
-
- /*
- * Reset Host DMA
- */
- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
- tmp |= PDC_RESET;
- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
-
- udelay(10);
-
- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
- tmp &= ~PDC_RESET;
- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
-}
-
-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- void __iomem *mmio_base;
- void __iomem *dimm_mmio = NULL;
- struct pdc_host_priv *hpriv = NULL;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
- int rc;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- dimm_mmio = pci_iomap(pdev, 4, 0);
- if (!dimm_mmio) {
- kfree(hpriv);
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- hpriv->dimm_mmio = dimm_mmio;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
-
- probe_ent->private_data = hpriv;
- base += PDC_CHIP0_OFS;
-
- probe_ent->n_ports = 4;
- pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
- pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
- pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
-
- pci_set_master(pdev);
-
- /* initialize adapter */
- /* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent)) {
- rc = -ENOMEM;
- goto err_out_iounmap_dimm;
- }
- pdc_20621_init(probe_ent);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_iounmap_dimm: /* only get to this label if 20621 */
- kfree(hpriv);
- pci_iounmap(pdev, dimm_mmio);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-
-static int __init pdc_sata_init(void)
-{
- return pci_module_init(&pdc_sata_pci_driver);
-}
-
-
-static void __exit pdc_sata_exit(void)
-{
- pci_unregister_driver(&pdc_sata_pci_driver);
-}
-
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Promise SATA low-level driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(pdc_sata_init);
-module_exit(pdc_sata_exit);
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
deleted file mode 100644
index f668c997e9a..00000000000
--- a/drivers/scsi/sata_uli.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * sata_uli.c - ULi Electronics SATA
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available under NDA.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_uli"
-#define DRV_VERSION "0.6"
-
-enum {
- uli_5289 = 0,
- uli_5287 = 1,
- uli_5281 = 2,
-
- uli_max_ports = 4,
-
- /* PCI configuration registers */
- ULI5287_BASE = 0x90, /* sata0 phy SCR registers */
- ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */
- ULI5281_BASE = 0x60, /* sata0 phy SCR registers */
- ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */
-};
-
-struct uli_priv {
- unsigned int scr_cfg_addr[uli_max_ports];
-};
-
-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-
-static const struct pci_device_id uli_pci_tbl[] = {
- { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
- { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
- { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
- { } /* terminate list */
-};
-
-
-static struct pci_driver uli_pci_driver = {
- .name = DRV_NAME,
- .id_table = uli_pci_tbl,
- .probe = uli_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static struct scsi_host_template uli_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations uli_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
-
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
-
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
-
- .scr_read = uli_scr_read,
- .scr_write = uli_scr_write,
-
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
-};
-
-static struct ata_port_info uli_port_info = {
- .sht = &uli_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 */
- .port_ops = &uli_ops,
-};
-
-
-MODULE_AUTHOR("Peer Chen");
-MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
-{
- struct uli_priv *hpriv = ap->host_set->private_data;
- return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
-}
-
-static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
- u32 val;
-
- pci_read_config_dword(pdev, cfg_addr, &val);
- return val;
-}
-
-static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
-
- pci_write_config_dword(pdev, cfg_addr, val);
-}
-
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
-
- return uli_scr_cfg_read(ap, sc_reg);
-}
-
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
- return;
-
- uli_scr_cfg_write(ap, sc_reg, val);
-}
-
-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi;
- int rc;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
- struct uli_priv *hpriv;
-
- if (!printed_version++)
- dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- ppi = &uli_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_probe_ent;
- }
-
- probe_ent->private_data = hpriv;
-
- switch (board_idx) {
- case uli_5287:
- hpriv->scr_cfg_addr[0] = ULI5287_BASE;
- hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
- probe_ent->n_ports = 4;
-
- probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
- probe_ent->port[2].altstatus_addr =
- probe_ent->port[2].ctl_addr =
- (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
- hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
-
- probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
- probe_ent->port[3].altstatus_addr =
- probe_ent->port[3].ctl_addr =
- (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
- hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
-
- ata_std_ports(&probe_ent->port[2]);
- ata_std_ports(&probe_ent->port[3]);
- break;
-
- case uli_5289:
- hpriv->scr_cfg_addr[0] = ULI5287_BASE;
- hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
- break;
-
- case uli_5281:
- hpriv->scr_cfg_addr[0] = ULI5281_BASE;
- hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS;
- break;
-
- default:
- BUG();
- break;
- }
-
- pci_set_master(pdev);
- pci_intx(pdev, 1);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_probe_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
-}
-
-static int __init uli_init(void)
-{
- return pci_module_init(&uli_pci_driver);
-}
-
-static void __exit uli_exit(void)
-{
- pci_unregister_driver(&uli_pci_driver);
-}
-
-
-module_init(uli_init);
-module_exit(uli_exit);
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
deleted file mode 100644
index 322890b400a..00000000000
--- a/drivers/scsi/sata_via.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * sata_via.c - VIA Serial ATA controllers
- *
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
- * Please ALWAYS copy linux-ide@vger.kernel.org
- on emails.
- *
- * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
- * Copyright 2003-2004 Jeff Garzik
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Hardware documentation available under NDA.
- *
- *
- * To-do list:
- * - VT6421 PATA support
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-#include <asm/io.h>
-
-#define DRV_NAME "sata_via"
-#define DRV_VERSION "1.2"
-
-enum board_ids_enum {
- vt6420,
- vt6421,
-};
-
-enum {
- SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
- SATA_INT_GATE = 0x41, /* SATA interrupt gating */
- SATA_NATIVE_MODE = 0x42, /* Native mode enable */
- SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
-
- PORT0 = (1 << 1),
- PORT1 = (1 << 0),
- ALL_PORTS = PORT0 | PORT1,
- N_PORTS = 2,
-
- NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
-
- SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
- SATA_2DEV = (1 << 5), /* SATA is master/slave */
-};
-
-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-
-static const struct pci_device_id svia_pci_tbl[] = {
- { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
- { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
-
- { } /* terminate list */
-};
-
-static struct pci_driver svia_pci_driver = {
- .name = DRV_NAME,
- .id_table = svia_pci_tbl,
- .probe = svia_init_one,
- .remove = ata_pci_remove_one,
-};
-
-static struct scsi_host_template svia_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-static const struct ata_port_operations svia_sata_ops = {
- .port_disable = ata_port_disable,
-
- .tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
- .check_status = ata_check_status,
- .exec_command = ata_exec_command,
- .dev_select = ata_std_dev_select,
-
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
-
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
-
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
-
- .irq_handler = ata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
-
- .scr_read = svia_scr_read,
- .scr_write = svia_scr_write,
-
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
-};
-
-static struct ata_port_info svia_port_info = {
- .sht = &svia_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
- .pio_mask = 0x1f,
- .mwdma_mask = 0x07,
- .udma_mask = 0x7f,
- .port_ops = &svia_sata_ops,
-};
-
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
-}
-
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
- outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
-}
-
-static const unsigned int svia_bar_sizes[] = {
- 8, 4, 8, 4, 16, 256
-};
-
-static const unsigned int vt6421_bar_sizes[] = {
- 16, 16, 16, 16, 32, 128
-};
-
-static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
-{
- return addr + (port * 128);
-}
-
-static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
-{
- return addr + (port * 64);
-}
-
-static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
- struct pci_dev *pdev,
- unsigned int port)
-{
- unsigned long reg_addr = pci_resource_start(pdev, port);
- unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
- unsigned long scr_addr;
-
- probe_ent->port[port].cmd_addr = reg_addr;
- probe_ent->port[port].altstatus_addr =
- probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
- probe_ent->port[port].bmdma_addr = bmdma_addr;
-
- scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
- probe_ent->port[port].scr_addr = scr_addr;
-
- ata_std_ports(&probe_ent->port[port]);
-}
-
-static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
-{
- struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi = &svia_port_info;
-
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return NULL;
-
- probe_ent->port[0].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 0);
- probe_ent->port[1].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 1);
-
- return probe_ent;
-}
-
-static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
-{
- struct ata_probe_ent *probe_ent;
- unsigned int i;
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- return NULL;
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = &svia_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
- probe_ent->port_ops = &svia_sata_ops;
- probe_ent->n_ports = N_PORTS;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x07;
- probe_ent->udma_mask = 0x7f;
-
- for (i = 0; i < N_PORTS; i++)
- vt6421_init_addrs(probe_ent, pdev, i);
-
- return probe_ent;
-}
-
-static void svia_configure(struct pci_dev *pdev)
-{
- u8 tmp8;
-
- pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
- dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
- (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
-
- /* make sure SATA channels are enabled */
- pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
- if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channels (0x%x)\n",
- (int) tmp8);
- tmp8 |= ALL_PORTS;
- pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
- }
-
- /* make sure interrupts for each channel sent to us */
- pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
- if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channel interrupts (0x%x)\n",
- (int) tmp8);
- tmp8 |= ALL_PORTS;
- pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
- }
-
- /* make sure native mode is enabled */
- pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
- if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
- dev_printk(KERN_DEBUG, &pdev->dev,
- "enabling SATA channel native mode (0x%x)\n",
- (int) tmp8);
- tmp8 |= NATIVE_MODE_ALL;
- pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
- }
-}
-
-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- unsigned int i;
- int rc;
- struct ata_probe_ent *probe_ent;
- int board_id = (int) ent->driver_data;
- const int *bar_sizes;
- int pci_dev_busy = 0;
- u8 tmp8;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- if (board_id == vt6420) {
- pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
- if (tmp8 & SATA_2DEV) {
- dev_printk(KERN_ERR, &pdev->dev,
- "SATA master/slave not supported (0x%x)\n",
- (int) tmp8);
- rc = -EIO;
- goto err_out_regions;
- }
-
- bar_sizes = &svia_bar_sizes[0];
- } else {
- bar_sizes = &vt6421_bar_sizes[0];
- }
-
- for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
- if ((pci_resource_start(pdev, i) == 0) ||
- (pci_resource_len(pdev, i) < bar_sizes[i])) {
- dev_printk(KERN_ERR, &pdev->dev,
- "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
- i,
- pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
- rc = -ENODEV;
- goto err_out_regions;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out_regions;
-
- if (board_id == vt6420)
- probe_ent = vt6420_init_probe_ent(pdev);
- else
- probe_ent = vt6421_init_probe_ent(pdev);
-
- if (!probe_ent) {
- dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
- rc = -ENOMEM;
- goto err_out_regions;
- }
-
- svia_configure(pdev);
-
- pci_set_master(pdev);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-static int __init svia_init(void)
-{
- return pci_module_init(&svia_pci_driver);
-}
-
-static void __exit svia_exit(void)
-{
- pci_unregister_driver(&svia_pci_driver);
-}
-
-module_init(svia_init);
-module_exit(svia_exit);
-
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
deleted file mode 100644
index 6d0c4f18e65..00000000000
--- a/drivers/scsi/sata_vsc.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
- *
- * Maintained by: Jeremy Higdon @ SGI
- * Please ALWAYS copy linux-ide@vger.kernel.org
- * on emails.
- *
- * Copyright 2004 SGI
- *
- * Bits from Jeff Garzik, Copyright RedHat, 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * libata documentation is available via 'make {ps|pdf}docs',
- * as Documentation/DocBook/libata.*
- *
- * Vitesse hardware documentation presumably available under NDA.
- * Intel 31244 (same hardware interface) documentation presumably
- * available from http://developer.intel.com/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/device.h>
-#include <scsi/scsi_host.h>
-#include <linux/libata.h>
-
-#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "1.2"
-
-enum {
- /* Interrupt register offsets (from chip base address) */
- VSC_SATA_INT_STAT_OFFSET = 0x00,
- VSC_SATA_INT_MASK_OFFSET = 0x04,
-
- /* Taskfile registers offsets */
- VSC_SATA_TF_CMD_OFFSET = 0x00,
- VSC_SATA_TF_DATA_OFFSET = 0x00,
- VSC_SATA_TF_ERROR_OFFSET = 0x04,
- VSC_SATA_TF_FEATURE_OFFSET = 0x06,
- VSC_SATA_TF_NSECT_OFFSET = 0x08,
- VSC_SATA_TF_LBAL_OFFSET = 0x0c,
- VSC_SATA_TF_LBAM_OFFSET = 0x10,
- VSC_SATA_TF_LBAH_OFFSET = 0x14,
- VSC_SATA_TF_DEVICE_OFFSET = 0x18,
- VSC_SATA_TF_STATUS_OFFSET = 0x1c,
- VSC_SATA_TF_COMMAND_OFFSET = 0x1d,
- VSC_SATA_TF_ALTSTATUS_OFFSET = 0x28,
- VSC_SATA_TF_CTL_OFFSET = 0x29,
-
- /* DMA base */
- VSC_SATA_UP_DESCRIPTOR_OFFSET = 0x64,
- VSC_SATA_UP_DATA_BUFFER_OFFSET = 0x6C,
- VSC_SATA_DMA_CMD_OFFSET = 0x70,
-
- /* SCRs base */
- VSC_SATA_SCR_STATUS_OFFSET = 0x100,
- VSC_SATA_SCR_ERROR_OFFSET = 0x104,
- VSC_SATA_SCR_CONTROL_OFFSET = 0x108,
-
- /* Port stride */
- VSC_SATA_PORT_OFFSET = 0x200,
-
- /* Error interrupt status bit offsets */
- VSC_SATA_INT_ERROR_CRC = 0x40,
- VSC_SATA_INT_ERROR_T = 0x20,
- VSC_SATA_INT_ERROR_P = 0x10,
- VSC_SATA_INT_ERROR_R = 0x8,
- VSC_SATA_INT_ERROR_E = 0x4,
- VSC_SATA_INT_ERROR_M = 0x2,
- VSC_SATA_INT_PHY_CHANGE = 0x1,
- VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC | VSC_SATA_INT_ERROR_T | \
- VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
- VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
- VSC_SATA_INT_PHY_CHANGE),
-};
-
-
-#define is_vsc_sata_int_err(port_idx, int_status) \
- (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
-
-
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
-{
- if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
-{
- if (sc_reg > SCR_CONTROL)
- return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
-}
-
-
-static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
-{
- void __iomem *mask_addr;
- u8 mask;
-
- mask_addr = ap->host_set->mmio_base +
- VSC_SATA_INT_MASK_OFFSET + ap->port_no;
- mask = readb(mask_addr);
- if (ctl & ATA_NIEN)
- mask |= 0x80;
- else
- mask &= 0x7F;
- writeb(mask, mask_addr);
-}
-
-
-static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
-
- /*
- * The only thing the ctl register is used for is SRST.
- * That is not enabled or disabled via tf_load.
- * However, if ATA_NIEN is changed, then we need to change the interrupt register.
- */
- if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
- ap->last_ctl = tf->ctl;
- vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
- }
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
- writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
- writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
- writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
- writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
- } else if (is_addr) {
- writew(tf->feature, ioaddr->feature_addr);
- writew(tf->nsect, ioaddr->nsect_addr);
- writew(tf->lbal, ioaddr->lbal_addr);
- writew(tf->lbam, ioaddr->lbam_addr);
- writew(tf->lbah, ioaddr->lbah_addr);
- }
-
- if (tf->flags & ATA_TFLAG_DEVICE)
- writeb(tf->device, ioaddr->device_addr);
-
- ata_wait_idle(ap);
-}
-
-
-static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u16 nsect, lbal, lbam, lbah, feature;
-
- tf->command = ata_check_status(ap);
- tf->device = readw(ioaddr->device_addr);
- feature = readw(ioaddr->error_addr);
- nsect = readw(ioaddr->nsect_addr);
- lbal = readw(ioaddr->lbal_addr);
- lbam = readw(ioaddr->lbam_addr);
- lbah = readw(ioaddr->lbah_addr);
-
- tf->feature = feature;
- tf->nsect = nsect;
- tf->lbal = lbal;
- tf->lbam = lbam;
- tf->lbah = lbah;
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- tf->hob_feature = feature >> 8;
- tf->hob_nsect = nsect >> 8;
- tf->hob_lbal = lbal >> 8;
- tf->hob_lbam = lbam >> 8;
- tf->hob_lbah = lbah >> 8;
- }
-}
-
-
-/*
- * vsc_sata_interrupt
- *
- * Read the interrupt register and process for the devices that have them pending.
- */
-static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- unsigned int i;
- unsigned int handled = 0;
- u32 int_status;
-
- spin_lock(&host_set->lock);
-
- int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
-
- for (i = 0; i < host_set->n_ports; i++) {
- if (int_status & ((u32) 0xFF << (8 * i))) {
- struct ata_port *ap;
-
- ap = host_set->ports[i];
-
- if (is_vsc_sata_int_err(i, int_status)) {
- u32 err_status;
- printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
- err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
- handled++;
- }
-
- if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += ata_host_intr(ap, qc);
- else if (is_vsc_sata_int_err(i, int_status)) {
- /*
- * On some chips (i.e. Intel 31244), an error
- * interrupt will sneak in at initialization
- * time (phy state changes). Clearing the SCR
- * error register is not required, but it prevents
- * the phy state change interrupts from recurring
- * later.
- */
- u32 err_status;
- err_status = vsc_sata_scr_read(ap, SCR_ERROR);
- printk(KERN_DEBUG "%s: clearing interrupt, "
- "status %x; sata err status %x\n",
- __FUNCTION__,
- int_status, err_status);
- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
- /* Clear interrupt status */
- ata_chk_status(ap);
- handled++;
- }
- }
- }
- }
-
- spin_unlock(&host_set->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-
-static struct scsi_host_template vsc_sata_sht = {
- .module = THIS_MODULE,
- .name = DRV_NAME,
- .ioctl = ata_scsi_ioctl,
- .queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
- .this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
- .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
- .emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
- .proc_name = DRV_NAME,
- .dma_boundary = ATA_DMA_BOUNDARY,
- .slave_configure = ata_scsi_slave_config,
- .slave_destroy = ata_scsi_slave_destroy,
- .bios_param = ata_std_bios_param,
-};
-
-
-static const struct ata_port_operations vsc_sata_ops = {
- .port_disable = ata_port_disable,
- .tf_load = vsc_sata_tf_load,
- .tf_read = vsc_sata_tf_read,
- .exec_command = ata_exec_command,
- .check_status = ata_check_status,
- .dev_select = ata_std_dev_select,
- .bmdma_setup = ata_bmdma_setup,
- .bmdma_start = ata_bmdma_start,
- .bmdma_stop = ata_bmdma_stop,
- .bmdma_status = ata_bmdma_status,
- .qc_prep = ata_qc_prep,
- .qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
- .post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = vsc_sata_interrupt,
- .irq_clear = ata_bmdma_irq_clear,
- .scr_read = vsc_sata_scr_read,
- .scr_write = vsc_sata_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
-};
-
-static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
-{
- port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
- port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
- port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET;
- port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET;
- port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET;
- port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET;
- port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET;
- port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET;
- port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET;
- port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET;
- port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET;
- port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET;
- port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
- port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
- port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
- writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
- writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
-}
-
-
-static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- int pci_dev_busy = 0;
- void __iomem *mmio_base;
- int rc;
-
- if (!printed_version++)
- dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
-
- rc = pci_enable_device(pdev);
- if (rc)
- return rc;
-
- /*
- * Check if we have needed resource mapped.
- */
- if (pci_resource_len(pdev, 0) == 0) {
- rc = -ENODEV;
- goto err_out;
- }
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
-
- /*
- * Use 32 bit DMA mask, because 64 bit address support is poor.
- */
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc)
- goto err_out_regions;
-
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- mmio_base = pci_iomap(pdev, 0, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- /*
- * Due to a bug in the chip, the default cache line size can't be used
- */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
-
- probe_ent->sht = &vsc_sata_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO;
- probe_ent->port_ops = &vsc_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x07;
- probe_ent->udma_mask = 0x7f;
-
- /* We have 4 ports per PCI function */
- vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
-
- pci_set_master(pdev);
-
- /*
- * Config offset 0x98 is "Extended Control and Status Register 0"
- * Default value is (1 << 28). All bits except bit 28 are reserved in
- * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
- * If bit 28 is clear, each port has its own LED.
- */
- pci_write_config_dword(pdev, 0x98, 0);
-
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
-
- return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-
-/*
- * Intel 31244 is supposed to be identical.
- * Compatibility is untested as of yet.
- */
-static const struct pci_device_id vsc_sata_pci_tbl[] = {
- { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174,
- PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244,
- PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
- { }
-};
-
-
-static struct pci_driver vsc_sata_pci_driver = {
- .name = DRV_NAME,
- .id_table = vsc_sata_pci_tbl,
- .probe = vsc_sata_init_one,
- .remove = ata_pci_remove_one,
-};
-
-
-static int __init vsc_sata_init(void)
-{
- return pci_module_init(&vsc_sata_pci_driver);
-}
-
-
-static void __exit vsc_sata_exit(void)
-{
- pci_unregister_driver(&vsc_sata_pci_driver);
-}
-
-
-MODULE_AUTHOR("Jeremy Higdon");
-MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
-MODULE_VERSION(DRV_VERSION);
-
-module_init(vsc_sata_init);
-module_exit(vsc_sata_exit);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2ab7df0dcfe..7a054f9d1ee 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -96,7 +96,11 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
-const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
+/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
+ * You may not alter any existing entry (although adding new ones is
+ * encouraged once assigned by ANSI/INCITS T10
+ */
+static const char *const scsi_device_types[] = {
"Direct-Access ",
"Sequential-Access",
"Printer ",
@@ -107,13 +111,29 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
"Optical Device ",
"Medium Changer ",
"Communications ",
- "Unknown ",
- "Unknown ",
+ "ASC IT8 ",
+ "ASC IT8 ",
"RAID ",
"Enclosure ",
"Direct-Access-RBC",
+ "Optical card ",
+ "Bridge controller",
+ "Object storage ",
+ "Automation/Drive ",
};
-EXPORT_SYMBOL(scsi_device_types);
+
+const char * scsi_device_type(unsigned type)
+{
+ if (type == 0x1e)
+ return "Well-known LUN ";
+ if (type == 0x1f)
+ return "No Device ";
+ if (type > ARRAY_SIZE(scsi_device_types))
+ return "Unknown ";
+ return scsi_device_types[type];
+}
+
+EXPORT_SYMBOL(scsi_device_type);
struct scsi_host_cmd_pool {
kmem_cache_t *slab;
@@ -346,7 +366,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
- cmd->buffer, cmd->bufflen,
+ cmd->request_buffer, cmd->request_bufflen,
cmd->done,
sdev->host->hostt->queuecommand);
@@ -661,11 +681,6 @@ void __scsi_done(struct scsi_cmnd *cmd)
*/
int scsi_retry_command(struct scsi_cmnd *cmd)
{
- /*
- * Restore the SCSI command state.
- */
- scsi_setup_cmd_retry(cmd);
-
/*
* Zero the sense information from the last time we tried
* this command.
@@ -711,10 +726,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- /*
- * We can get here with use_sg=0, causing a panic in the upper level
- */
- cmd->use_sg = cmd->old_use_sg;
cmd->done(cmd);
}
EXPORT_SYMBOL(scsi_finish_command);
@@ -844,14 +855,14 @@ EXPORT_SYMBOL(scsi_track_queue_full);
*/
int scsi_device_get(struct scsi_device *sdev)
{
- if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
+ if (sdev->sdev_state == SDEV_DEL)
return -ENXIO;
if (!get_device(&sdev->sdev_gendev))
return -ENXIO;
- if (!try_module_get(sdev->host->hostt->module)) {
- put_device(&sdev->sdev_gendev);
- return -ENXIO;
- }
+ /* We can fail this if we're doing SCSI operations
+ * from module exit (like cache flush) */
+ try_module_get(sdev->host->hostt->module);
+
return 0;
}
EXPORT_SYMBOL(scsi_device_get);
@@ -866,7 +877,14 @@ EXPORT_SYMBOL(scsi_device_get);
*/
void scsi_device_put(struct scsi_device *sdev)
{
- module_put(sdev->host->hostt->module);
+ 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)
+ module_put(module);
+#endif
put_device(&sdev->sdev_gendev);
}
EXPORT_SYMBOL(scsi_device_put);
@@ -1108,6 +1126,8 @@ static int __init init_scsi(void)
for_each_possible_cpu(i)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
+ scsi_netlink_init();
+
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
@@ -1128,6 +1148,7 @@ cleanup_queue:
static void __exit exit_scsi(void)
{
+ scsi_netlink_exit();
scsi_sysfs_unregister();
scsi_exit_sysctl();
scsi_exit_hosts();
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index f51e466893e..d5a55fae60e 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -20,8 +20,6 @@
#ifndef _SCSI_H
#define _SCSI_H
-#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
-
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 5a5d2af8ee4..9c0f35820e3 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1,5 +1,4 @@
/*
- * linux/kernel/scsi_debug.c
* vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
* Copyright (C) 1992 Eric Youngdale
* Simulate a host adapter with 2 disks attached. Do a lot of checking
@@ -8,7 +7,9 @@
* ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* This version is more generic, simulating a variable number of disk
- * (or disk like devices) sharing a common amount of RAM
+ * (or disk like devices) sharing a common amount of RAM. To be more
+ * realistic, the simulated devices have the transport attributes of
+ * SAS disks.
*
*
* For documentation see http://www.torque.net/sg/sdebug26.html
@@ -24,7 +25,6 @@
* module options to "modprobe scsi_debug num_tgts=2" [20021221]
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -51,18 +51,22 @@
#include "scsi_logging.h"
#include "scsi_debug.h"
-#define SCSI_DEBUG_VERSION "1.75"
-static const char * scsi_debug_version_date = "20050113";
+#define SCSI_DEBUG_VERSION "1.80"
+static const char * scsi_debug_version_date = "20060914";
/* Additional Sense Code (ASC) used */
-#define NO_ADDED_SENSE 0x0
+#define NO_ADDITIONAL_SENSE 0x0
+#define LOGICAL_UNIT_NOT_READY 0x4
#define UNRECOVERED_READ_ERR 0x11
+#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
#define ADDR_OUT_OF_RANGE 0x21
#define INVALID_FIELD_IN_CDB 0x24
+#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define POWERON_RESET 0x29
#define SAVING_PARAMS_UNSUP 0x39
-#define THRESHHOLD_EXCEEDED 0x5d
+#define THRESHOLD_EXCEEDED 0x5d
+#define LOW_POWER_COND_ON 0x5e
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
@@ -81,6 +85,10 @@ static const char * scsi_debug_version_date = "20050113";
#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
#define DEF_PTYPE 0
#define DEF_D_SENSE 0
+#define DEF_NO_LUN_0 0
+#define DEF_VIRTUAL_GB 0
+#define DEF_FAKE_RW 0
+#define DEF_VPD_USE_HOSTNO 1
/* bit mask values for scsi_debug_opts */
#define SCSI_DEBUG_OPT_NOISE 1
@@ -107,6 +115,7 @@ static const char * scsi_debug_version_date = "20050113";
/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
* or "peripheral device" addressing (value 0) */
#define SAM2_LUN_ADDRESS_METHOD 0
+#define SAM2_WLUN_REPORT_LUNS 0xc101
static int scsi_debug_add_host = DEF_NUM_HOST;
static int scsi_debug_delay = DEF_DELAY;
@@ -119,13 +128,18 @@ static int scsi_debug_opts = DEF_OPTS;
static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
static int scsi_debug_dsense = DEF_D_SENSE;
+static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
+static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
+static int scsi_debug_fake_rw = DEF_FAKE_RW;
+static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
static int scsi_debug_cmnd_count = 0;
#define DEV_READONLY(TGT) (0)
#define DEV_REMOVEABLE(TGT) (0)
-static unsigned long sdebug_store_size; /* in bytes */
+static unsigned int sdebug_store_size; /* in bytes */
+static unsigned int sdebug_store_sectors;
static sector_t sdebug_capacity; /* in sectors */
/* old BIOS stuff, kernel may get rid of them but some mode sense pages
@@ -150,7 +164,9 @@ struct sdebug_dev_info {
unsigned int target;
unsigned int lun;
struct sdebug_host_info *sdbg_host;
+ unsigned int wlun;
char reset;
+ char stopped;
char used;
};
@@ -194,11 +210,11 @@ static struct scsi_host_template sdebug_driver_template = {
.bios_param = scsi_debug_biosparam,
.can_queue = SCSI_DEBUG_CANQUEUE,
.this_id = 7,
- .sg_tablesize = 64,
- .cmd_per_lun = 3,
- .max_sectors = 4096,
+ .sg_tablesize = 256,
+ .cmd_per_lun = 16,
+ .max_sectors = 0xffff,
.unchecked_isa_dma = 0,
- .use_clustering = DISABLE_CLUSTERING,
+ .use_clustering = ENABLE_CLUSTERING,
.module = THIS_MODULE,
};
@@ -226,19 +242,32 @@ static struct device_driver sdebug_driverfs_driver = {
static const int check_condition_result =
(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0x2, 0x4b};
+static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+
/* function declarations */
static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
struct sdebug_dev_info * devip);
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_readcap(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
-static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target,
+static int resp_readcap16(struct scsi_cmnd * SCpnt,
+ struct sdebug_dev_info * devip);
+static int resp_mode_sense(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip);
-static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip);
-static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip);
+static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
+ struct sdebug_dev_info * devip);
+static int resp_log_sense(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip);
+static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip);
+static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip);
static int resp_report_luns(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
@@ -249,8 +278,8 @@ static void timer_intr_handler(unsigned long);
static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
int asc, int asq);
-static int check_reset(struct scsi_cmnd * SCpnt,
- struct sdebug_dev_info * devip);
+static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
+ struct sdebug_dev_info * devip);
static int schedule_resp(struct scsi_cmnd * cmnd,
struct sdebug_dev_info * devip,
done_funct_t done, int scsi_result, int delta_jiff);
@@ -258,9 +287,11 @@ 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 dev_id_num,
- const char * dev_id_str, int dev_id_str_len);
-static void do_create_driverfs_files(void);
+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_88(unsigned char * arr, int target_dev_id);
+static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
static int sdebug_add_adapter(void);
@@ -275,18 +306,22 @@ static
int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
- int block, upper_blk, num, k;
+ int len, k, j;
+ unsigned int num;
+ unsigned long long lba;
int errsts = 0;
- int target = scmd_id(SCpnt);
+ int target = SCpnt->device->id;
struct sdebug_dev_info * devip = NULL;
int inj_recovered = 0;
+ int delay_override = 0;
if (done == NULL)
return 0; /* assume mid level reprocessing command */
+ SCpnt->resid = 0;
if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
printk(KERN_INFO "scsi_debug: cmd ");
- for (k = 0, num = SCpnt->cmd_len; k < num; ++k)
+ for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
printk("%02x ", (int)cmd[k]);
printk("\n");
}
@@ -297,7 +332,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
DID_NO_CONNECT << 16, 0);
}
- if (SCpnt->device->lun >= scsi_debug_max_luns)
+ if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
+ (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
devip = devInfoReg(SCpnt->device);
@@ -316,118 +352,154 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
inj_recovered = 1; /* to reads and writes below */
}
+ if (devip->wlun) {
+ switch (*cmd) {
+ case INQUIRY:
+ case REQUEST_SENSE:
+ case TEST_UNIT_READY:
+ case REPORT_LUNS:
+ break; /* only allowable wlun commands */
+ default:
+ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+ printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
+ "not supported for wlun\n", *cmd);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_OPCODE, 0);
+ errsts = check_condition_result;
+ return schedule_resp(SCpnt, devip, done, errsts,
+ 0);
+ }
+ }
+
switch (*cmd) {
case INQUIRY: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_inquiry(SCpnt, target, devip);
break;
case REQUEST_SENSE: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_requests(SCpnt, devip);
break;
case REZERO_UNIT: /* actually this is REWIND for SSC */
case START_STOP:
- errsts = check_reset(SCpnt, devip);
+ errsts = resp_start_stop(SCpnt, devip);
break;
case ALLOW_MEDIUM_REMOVAL:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 1, devip)))
break;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Medium removal %s\n",
cmd[4] ? "inhibited" : "enabled");
break;
case SEND_DIAGNOSTIC: /* mandatory */
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case TEST_UNIT_READY: /* mandatory */
- errsts = check_reset(SCpnt, devip);
+ delay_override = 1;
+ errsts = check_readiness(SCpnt, 0, devip);
break;
case RESERVE:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RESERVE_10:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE_10:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case READ_CAPACITY:
errsts = resp_readcap(SCpnt, devip);
break;
+ case SERVICE_ACTION_IN:
+ if (SAI_READ_CAPACITY_16 != cmd[1]) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+ errsts = resp_readcap16(SCpnt, devip);
+ break;
case READ_16:
case READ_12:
case READ_10:
case READ_6:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
+ if (scsi_debug_fake_rw)
break;
- upper_blk = 0;
if ((*cmd) == READ_16) {
- upper_blk = cmd[5] + (cmd[4] << 8) +
- (cmd[3] << 16) + (cmd[2] << 24);
- block = cmd[9] + (cmd[8] << 8) +
- (cmd[7] << 16) + (cmd[6] << 24);
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+ lba <<= 8;
+ lba += cmd[2 + j];
+ }
num = cmd[13] + (cmd[12] << 8) +
(cmd[11] << 16) + (cmd[10] << 24);
} else if ((*cmd) == READ_12) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[9] + (cmd[8] << 8) +
(cmd[7] << 16) + (cmd[6] << 24);
} else if ((*cmd) == READ_10) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[8] + (cmd[7] << 8);
- } else {
- block = cmd[3] + (cmd[2] << 8) +
+ } else { /* READ (6) */
+ lba = cmd[3] + (cmd[2] << 8) +
((cmd[1] & 0x1f) << 16);
- num = cmd[4];
+ num = (0 == cmd[4]) ? 256 : cmd[4];
}
- errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+ errsts = resp_read(SCpnt, lba, num, devip);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
- THRESHHOLD_EXCEEDED, 0);
+ THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
}
break;
case REPORT_LUNS: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_report_luns(SCpnt, devip);
break;
case VERIFY: /* 10 byte SBC-2 command */
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 0, devip);
break;
case WRITE_16:
case WRITE_12:
case WRITE_10:
case WRITE_6:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
+ if (scsi_debug_fake_rw)
break;
- upper_blk = 0;
if ((*cmd) == WRITE_16) {
- upper_blk = cmd[5] + (cmd[4] << 8) +
- (cmd[3] << 16) + (cmd[2] << 24);
- block = cmd[9] + (cmd[8] << 8) +
- (cmd[7] << 16) + (cmd[6] << 24);
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+ lba <<= 8;
+ lba += cmd[2 + j];
+ }
num = cmd[13] + (cmd[12] << 8) +
(cmd[11] << 16) + (cmd[10] << 24);
} else if ((*cmd) == WRITE_12) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[9] + (cmd[8] << 8) +
(cmd[7] << 16) + (cmd[6] << 24);
} else if ((*cmd) == WRITE_10) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[8] + (cmd[7] << 8);
- } else {
- block = cmd[3] + (cmd[2] << 8) +
+ } else { /* WRITE (6) */
+ lba = cmd[3] + (cmd[2] << 8) +
((cmd[1] & 0x1f) << 16);
- num = cmd[4];
+ num = (0 == cmd[4]) ? 256 : cmd[4];
}
- errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+ errsts = resp_write(SCpnt, lba, num, devip);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
- THRESHHOLD_EXCEEDED, 0);
+ THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
}
break;
@@ -435,20 +507,31 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
case MODE_SENSE_10:
errsts = resp_mode_sense(SCpnt, target, devip);
break;
+ case MODE_SELECT:
+ errsts = resp_mode_select(SCpnt, 1, devip);
+ break;
+ case MODE_SELECT_10:
+ errsts = resp_mode_select(SCpnt, 0, devip);
+ break;
+ case LOG_SENSE:
+ errsts = resp_log_sense(SCpnt, devip);
+ break;
case SYNCHRONIZE_CACHE:
- errsts = check_reset(SCpnt, devip);
+ delay_override = 1;
+ errsts = check_readiness(SCpnt, 0, devip);
break;
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
"supported\n", *cmd);
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 1, devip)))
break; /* Unit attention takes precedence */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
errsts = check_condition_result;
break;
}
- return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
+ return schedule_resp(SCpnt, devip, done, errsts,
+ (delay_override ? 0 : scsi_debug_delay));
}
static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
@@ -460,7 +543,8 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
/* return -ENOTTY; // correct return but upsets fdisk */
}
-static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
+static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
+ struct sdebug_dev_info * devip)
{
if (devip->reset) {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
@@ -470,6 +554,14 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
return check_condition_result;
}
+ if ((0 == reset_only) && devip->stopped) {
+ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+ printk(KERN_INFO "scsi_debug: Reporting Not "
+ "ready: initializing command required\n");
+ mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
+ 0x2);
+ return check_condition_result;
+ }
return 0;
}
@@ -493,7 +585,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
req_len = scp->request_bufflen;
act_len = (req_len < arr_len) ? req_len : arr_len;
memcpy(scp->request_buffer, arr, act_len);
- scp->resid = req_len - act_len;
+ if (scp->resid)
+ scp->resid -= act_len;
+ else
+ scp->resid = req_len - act_len;
return 0;
}
sgpnt = (struct scatterlist *)scp->request_buffer;
@@ -516,7 +611,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
}
req_len += sgpnt->length;
}
- scp->resid = req_len - act_len;
+ if (scp->resid)
+ scp->resid -= act_len;
+ else
+ scp->resid = req_len - act_len;
return 0;
}
@@ -567,12 +665,14 @@ 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 dev_id_num,
- const char * dev_id_str, int dev_id_str_len)
+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)
{
- int num;
+ int num, port_a;
+ char b[32];
- /* Two identification descriptors: */
+ port_a = target_dev_id + 1;
/* T10 vendor identifier field format (faked) */
arr[0] = 0x2; /* ASCII */
arr[1] = 0x1;
@@ -583,25 +683,246 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
num = 8 + 16 + dev_id_str_len;
arr[3] = num;
num += 4;
- /* NAA IEEE registered identifier (faked) */
- arr[num] = 0x1; /* binary */
- arr[num + 1] = 0x3;
- arr[num + 2] = 0x0;
- arr[num + 3] = 0x8;
- arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */
- arr[num + 5] = 0x23;
- arr[num + 6] = 0x45;
- arr[num + 7] = 0x60;
- arr[num + 8] = (dev_id_num >> 24);
- arr[num + 9] = (dev_id_num >> 16) & 0xff;
- arr[num + 10] = (dev_id_num >> 8) & 0xff;
- arr[num + 11] = dev_id_num & 0xff;
- return num + 12;
+ if (dev_id_num >= 0) {
+ /* NAA-5, Logical unit identifier (binary) */
+ arr[num++] = 0x1; /* binary (not necessarily sas) */
+ arr[num++] = 0x3; /* PIV=0, lu, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
+ arr[num++] = 0x33;
+ arr[num++] = 0x33;
+ arr[num++] = 0x30;
+ arr[num++] = (dev_id_num >> 24);
+ arr[num++] = (dev_id_num >> 16) & 0xff;
+ arr[num++] = (dev_id_num >> 8) & 0xff;
+ arr[num++] = dev_id_num & 0xff;
+ /* Target relative port number */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x94; /* PIV=1, target port, rel port */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x4; /* length */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x1; /* relative port A */
+ }
+ /* NAA-5, Target port identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* piv=1, target port, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_a >> 24);
+ arr[num++] = (port_a >> 16) & 0xff;
+ arr[num++] = (port_a >> 8) & 0xff;
+ arr[num++] = port_a & 0xff;
+ /* NAA-5, Target device identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0xa3; /* piv=1, target device, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (target_dev_id >> 24);
+ arr[num++] = (target_dev_id >> 16) & 0xff;
+ arr[num++] = (target_dev_id >> 8) & 0xff;
+ arr[num++] = target_dev_id & 0xff;
+ /* SCSI name string: Target device identifier */
+ arr[num++] = 0x63; /* proto=sas, UTF-8 */
+ arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
+ arr[num++] = 0x0;
+ arr[num++] = 24;
+ memcpy(arr + num, "naa.52222220", 12);
+ num += 12;
+ snprintf(b, sizeof(b), "%08X", target_dev_id);
+ memcpy(arr + num, b, 8);
+ num += 8;
+ memset(arr + num, 0, 4);
+ num += 4;
+ return num;
+}
+
+
+static unsigned char vpd84_data[] = {
+/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
+ 0x22,0x22,0x22,0x0,0xbb,0x1,
+ 0x22,0x22,0x22,0x0,0xbb,0x2,
+};
+
+static int inquiry_evpd_84(unsigned char * arr)
+{
+ memcpy(arr, vpd84_data, sizeof(vpd84_data));
+ return sizeof(vpd84_data);
+}
+
+static int inquiry_evpd_85(unsigned char * arr)
+{
+ int num = 0;
+ const char * na1 = "https://www.kernel.org/config";
+ const char * na2 = "http://www.kernel.org/log";
+ int plen, olen;
+
+ arr[num++] = 0x1; /* lu, storage config */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ olen = strlen(na1);
+ plen = olen + 1;
+ if (plen % 4)
+ plen = ((plen / 4) + 1) * 4;
+ arr[num++] = plen; /* length, null termianted, padded */
+ memcpy(arr + num, na1, olen);
+ memset(arr + num + olen, 0, plen - olen);
+ num += plen;
+
+ arr[num++] = 0x4; /* lu, logging */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ olen = strlen(na2);
+ plen = olen + 1;
+ if (plen % 4)
+ plen = ((plen / 4) + 1) * 4;
+ arr[num++] = plen; /* length, null terminated, padded */
+ memcpy(arr + num, na2, olen);
+ memset(arr + num + olen, 0, plen - olen);
+ num += plen;
+
+ return num;
+}
+
+/* SCSI ports VPD page */
+static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
+{
+ int num = 0;
+ int port_a, port_b;
+
+ port_a = target_dev_id + 1;
+ port_b = port_a + 1;
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x1; /* relative port 1 (primary) */
+ memset(arr + num, 0, 6);
+ num += 6;
+ arr[num++] = 0x0;
+ arr[num++] = 12; /* length tp descriptor */
+ /* naa-5 target port identifier (A) */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* PIV=1, target port, NAA */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x8; /* length */
+ arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_a >> 24);
+ arr[num++] = (port_a >> 16) & 0xff;
+ arr[num++] = (port_a >> 8) & 0xff;
+ arr[num++] = port_a & 0xff;
+
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x2; /* relative port 2 (secondary) */
+ memset(arr + num, 0, 6);
+ num += 6;
+ arr[num++] = 0x0;
+ arr[num++] = 12; /* length tp descriptor */
+ /* naa-5 target port identifier (B) */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* PIV=1, target port, NAA */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x8; /* length */
+ arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_b >> 24);
+ arr[num++] = (port_b >> 16) & 0xff;
+ arr[num++] = (port_b >> 8) & 0xff;
+ arr[num++] = port_b & 0xff;
+
+ return num;
+}
+
+
+static unsigned char vpd89_data[] = {
+/* from 4th byte */ 0,0,0,0,
+'l','i','n','u','x',' ',' ',' ',
+'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
+'1','2','3','4',
+0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+0xec,0,0,0,
+0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
+0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
+0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
+0x53,0x41,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x10,0x80,
+0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
+0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
+0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
+0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
+0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
+0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
+0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
+0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
+0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
+};
+
+static int inquiry_evpd_89(unsigned char * arr)
+{
+ memcpy(arr, vpd89_data, sizeof(vpd89_data));
+ return sizeof(vpd89_data);
+}
+
+
+static unsigned char vpdb0_data[] = {
+ /* from 4th byte */ 0,0,0,4,
+ 0,0,0x4,0,
+ 0,0,0,64,
+};
+
+static int inquiry_evpd_b0(unsigned char * arr)
+{
+ memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
+ if (sdebug_store_sectors > 0x400) {
+ arr[4] = (sdebug_store_sectors >> 24) & 0xff;
+ arr[5] = (sdebug_store_sectors >> 16) & 0xff;
+ arr[6] = (sdebug_store_sectors >> 8) & 0xff;
+ arr[7] = sdebug_store_sectors & 0xff;
+ }
+ return sizeof(vpdb0_data);
}
#define SDEBUG_LONG_INQ_SZ 96
-#define SDEBUG_MAX_INQ_ARR_SZ 128
+#define SDEBUG_MAX_INQ_ARR_SZ 584
static int resp_inquiry(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip)
@@ -609,64 +930,115 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
unsigned char pq_pdt;
unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
unsigned char *cmd = (unsigned char *)scp->cmnd;
- int alloc_len;
+ int alloc_len, n;
alloc_len = (cmd[3] << 8) + cmd[4];
memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
- pq_pdt = (scsi_debug_ptype & 0x1f);
+ if (devip->wlun)
+ pq_pdt = 0x1e; /* present, wlun */
+ else if (scsi_debug_no_lun_0 && (0 == devip->lun))
+ pq_pdt = 0x7f; /* not present, no device type */
+ else
+ pq_pdt = (scsi_debug_ptype & 0x1f);
arr[0] = pq_pdt;
if (0x2 & cmd[1]) { /* CMDDT bit set */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
} else if (0x1 & cmd[1]) { /* EVPD bit set */
- int dev_id_num, len;
- char dev_id_str[6];
+ int lu_id_num, target_dev_id, len;
+ char lu_id_str[6];
+ int host_no = devip->sdbg_host->shost->host_no;
- dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
- (devip->target * 1000) + devip->lun;
- len = scnprintf(dev_id_str, 6, "%d", dev_id_num);
+ if (0 == scsi_debug_vpd_use_hostno)
+ host_no = 0;
+ lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
+ (devip->target * 1000) + devip->lun);
+ target_dev_id = ((host_no + 1) * 2000) +
+ (devip->target * 1000) - 3;
+ len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
if (0 == cmd[2]) { /* supported vital product data pages */
- arr[3] = 3;
- arr[4] = 0x0; /* this page */
- arr[5] = 0x80; /* unit serial number */
- arr[6] = 0x83; /* device identification */
+ arr[1] = cmd[2]; /*sanity */
+ n = 4;
+ arr[n++] = 0x0; /* this page */
+ arr[n++] = 0x80; /* unit serial number */
+ arr[n++] = 0x83; /* device identification */
+ arr[n++] = 0x84; /* software interface ident. */
+ arr[n++] = 0x85; /* management network addresses */
+ arr[n++] = 0x86; /* extended inquiry */
+ arr[n++] = 0x87; /* mode page policy */
+ arr[n++] = 0x88; /* SCSI ports */
+ arr[n++] = 0x89; /* ATA information */
+ arr[n++] = 0xb0; /* Block limits (SBC) */
+ arr[3] = n - 4; /* number of supported VPD pages */
} else if (0x80 == cmd[2]) { /* unit serial number */
- arr[1] = 0x80;
+ arr[1] = cmd[2]; /*sanity */
arr[3] = len;
- memcpy(&arr[4], dev_id_str, len);
+ memcpy(&arr[4], lu_id_str, len);
} else if (0x83 == cmd[2]) { /* device identification */
- arr[1] = 0x83;
- arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
- dev_id_str, len);
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_83(&arr[4], 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]);
+ } else if (0x85 == cmd[2]) { /* Management network addresses */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_85(&arr[4]);
+ } else if (0x86 == cmd[2]) { /* extended inquiry */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = 0x3c; /* number of following entries */
+ arr[4] = 0x0; /* no protection stuff */
+ arr[5] = 0x7; /* head of q, ordered + simple q's */
+ } else if (0x87 == cmd[2]) { /* mode page policy */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = 0x8; /* number of following entries */
+ arr[4] = 0x2; /* disconnect-reconnect mp */
+ arr[6] = 0x80; /* mlus, shared */
+ arr[8] = 0x18; /* protocol specific lu */
+ arr[10] = 0x82; /* mlus, per initiator port */
+ } else if (0x88 == cmd[2]) { /* SCSI Ports */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
+ } else if (0x89 == cmd[2]) { /* ATA information */
+ arr[1] = cmd[2]; /*sanity */
+ n = inquiry_evpd_89(&arr[4]);
+ arr[2] = (n >> 8);
+ arr[3] = (n & 0xff);
+ } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_b0(&arr[4]);
} else {
/* Illegal request, invalid field in cdb */
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
return check_condition_result;
}
+ len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
return fill_from_dev_buffer(scp, arr,
- min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ));
+ min(len, SDEBUG_MAX_INQ_ARR_SZ));
}
/* 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;
- arr[6] = 0x1; /* claim: ADDR16 */
+ arr[6] = 0x10; /* claim: MultiP */
/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
- arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
+ arr[7] = 0xa; /* claim: LINKED + CMDQUE */
memcpy(&arr[8], inq_vendor_id, 8);
memcpy(&arr[16], inq_product_id, 16);
memcpy(&arr[32], inq_product_rev, 4);
/* version descriptors (2 bytes each) follow */
- arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */
- arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */
+ arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
+ arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
+ n = 62;
if (scsi_debug_ptype == 0) {
- arr[62] = 0x1; arr[63] = 0x80; /* SBC */
+ arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
} else if (scsi_debug_ptype == 1) {
- arr[62] = 0x2; arr[63] = 0x00; /* SSC */
+ 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,
min(alloc_len, SDEBUG_LONG_INQ_SZ));
}
@@ -677,46 +1049,128 @@ static int resp_requests(struct scsi_cmnd * scp,
unsigned char * sbuff;
unsigned char *cmd = (unsigned char *)scp->cmnd;
unsigned char arr[SDEBUG_SENSE_LEN];
+ int want_dsense;
int len = 18;
- memset(arr, 0, SDEBUG_SENSE_LEN);
+ memset(arr, 0, sizeof(arr));
if (devip->reset == 1)
- mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+ mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
+ want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
sbuff = devip->sense_buff;
- if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
- /* DESC bit set and sense_buff in fixed format */
- arr[0] = 0x72;
- arr[1] = sbuff[2]; /* sense key */
- arr[2] = sbuff[12]; /* asc */
- arr[3] = sbuff[13]; /* ascq */
- len = 8;
- } else
+ if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
+ if (want_dsense) {
+ arr[0] = 0x72;
+ arr[1] = 0x0; /* NO_SENSE in sense_key */
+ arr[2] = THRESHOLD_EXCEEDED;
+ arr[3] = 0xff; /* TEST set and MRIE==6 */
+ } else {
+ arr[0] = 0x70;
+ arr[2] = 0x0; /* NO_SENSE in sense_key */
+ arr[7] = 0xa; /* 18 byte sense buffer */
+ arr[12] = THRESHOLD_EXCEEDED;
+ arr[13] = 0xff; /* TEST set and MRIE==6 */
+ }
+ } else {
memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
- mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+ if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
+ /* DESC bit set and sense_buff in fixed format */
+ memset(arr, 0, sizeof(arr));
+ arr[0] = 0x72;
+ arr[1] = sbuff[2]; /* sense key */
+ arr[2] = sbuff[12]; /* asc */
+ arr[3] = sbuff[13]; /* ascq */
+ len = 8;
+ }
+ }
+ mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
return fill_from_dev_buffer(scp, arr, len);
}
+static int resp_start_stop(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+ int power_cond, errsts, start;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ power_cond = (cmd[4] & 0xf0) >> 4;
+ if (power_cond) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
+ start = cmd[4] & 1;
+ if (start == devip->stopped)
+ devip->stopped = !start;
+ return 0;
+}
+
#define SDEBUG_READCAP_ARR_SZ 8
static int resp_readcap(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned char arr[SDEBUG_READCAP_ARR_SZ];
- unsigned long capac;
+ unsigned int capac;
int errsts;
- if ((errsts = check_reset(scp, devip)))
+ if ((errsts = check_readiness(scp, 1, devip)))
return errsts;
+ /* following just in case virtual_gb changed */
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
- capac = (unsigned long)sdebug_capacity - 1;
- arr[0] = (capac >> 24);
- arr[1] = (capac >> 16) & 0xff;
- arr[2] = (capac >> 8) & 0xff;
- arr[3] = capac & 0xff;
+ if (sdebug_capacity < 0xffffffff) {
+ capac = (unsigned int)sdebug_capacity - 1;
+ arr[0] = (capac >> 24);
+ arr[1] = (capac >> 16) & 0xff;
+ arr[2] = (capac >> 8) & 0xff;
+ arr[3] = capac & 0xff;
+ } else {
+ arr[0] = 0xff;
+ arr[1] = 0xff;
+ arr[2] = 0xff;
+ arr[3] = 0xff;
+ }
arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
arr[7] = SECT_SIZE_PER(target) & 0xff;
return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
}
+#define SDEBUG_READCAP16_ARR_SZ 32
+static int resp_readcap16(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+ unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
+ unsigned long long capac;
+ int errsts, k, alloc_len;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
+ + cmd[13]);
+ /* following just in case virtual_gb changed */
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
+ capac = sdebug_capacity - 1;
+ for (k = 0; k < 8; ++k, capac >>= 8)
+ arr[7 - k] = capac & 0xff;
+ arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
+ arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
+ arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ arr[11] = SECT_SIZE_PER(target) & 0xff;
+ return fill_from_dev_buffer(scp, arr,
+ min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
+}
+
/* <<Following mode page info copied from ST318451LW>> */
static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
@@ -772,47 +1226,123 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
{ /* Control mode page for mode_sense */
- unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+ unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
+ unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
0, 0, 0x2, 0x4b};
if (scsi_debug_dsense)
ctrl_m_pg[2] |= 0x4;
+ else
+ ctrl_m_pg[2] &= ~0x4;
memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
if (1 == pcontrol)
- memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
+ memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
+ else if (2 == pcontrol)
+ memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
return sizeof(ctrl_m_pg);
}
+
static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
{ /* Informational Exceptions control mode page for mode_sense */
- unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
- 0, 0, 0x0, 0x0};
+ unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+ unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+
memcpy(p, iec_m_pg, sizeof(iec_m_pg));
if (1 == pcontrol)
- memset(p + 2, 0, sizeof(iec_m_pg) - 2);
+ memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
+ else if (2 == pcontrol)
+ memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
return sizeof(iec_m_pg);
}
+static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
+{ /* SAS SSP mode page - short format for mode_sense */
+ unsigned char sas_sf_m_pg[] = {0x19, 0x6,
+ 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
+
+ memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
+ if (1 == pcontrol)
+ memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
+ return sizeof(sas_sf_m_pg);
+}
+
+
+static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
+ int target_dev_id)
+{ /* SAS phy control and discover mode page for mode_sense */
+ unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
+ 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
+ 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
+ 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
+ 0x2, 0, 0, 0, 0, 0, 0, 0,
+ 0x88, 0x99, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
+ 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
+ 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
+ 0x3, 0, 0, 0, 0, 0, 0, 0,
+ 0x88, 0x99, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ int port_a, port_b;
+
+ port_a = target_dev_id + 1;
+ port_b = port_a + 1;
+ memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
+ p[20] = (port_a >> 24);
+ p[21] = (port_a >> 16) & 0xff;
+ p[22] = (port_a >> 8) & 0xff;
+ p[23] = port_a & 0xff;
+ p[48 + 20] = (port_b >> 24);
+ p[48 + 21] = (port_b >> 16) & 0xff;
+ p[48 + 22] = (port_b >> 8) & 0xff;
+ p[48 + 23] = port_b & 0xff;
+ if (1 == pcontrol)
+ memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
+ return sizeof(sas_pcd_m_pg);
+}
+
+static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
+{ /* SAS SSP shared protocol specific port mode subpage */
+ unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
+ if (1 == pcontrol)
+ memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
+ return sizeof(sas_sha_m_pg);
+}
+
#define SDEBUG_MAX_MSENSE_SZ 256
static int resp_mode_sense(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip)
{
- unsigned char dbd;
- int pcontrol, pcode, subpcode;
+ unsigned char dbd, llbaa;
+ int pcontrol, pcode, subpcode, bd_len;
unsigned char dev_spec;
- int alloc_len, msense_6, offset, len, errsts;
+ int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
unsigned char * ap;
unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
unsigned char *cmd = (unsigned char *)scp->cmnd;
- if ((errsts = check_reset(scp, devip)))
+ if ((errsts = check_readiness(scp, 1, devip)))
return errsts;
- dbd = cmd[1] & 0x8;
+ dbd = !!(cmd[1] & 0x8);
pcontrol = (cmd[2] & 0xc0) >> 6;
pcode = cmd[2] & 0x3f;
subpcode = cmd[3];
msense_6 = (MODE_SENSE == cmd[0]);
+ llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
+ if ((0 == scsi_debug_ptype) && (0 == dbd))
+ bd_len = llbaa ? 16 : 8;
+ else
+ bd_len = 0;
alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
if (0x3 == pcontrol) { /* Saving values not supported */
@@ -820,17 +1350,63 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
0);
return check_condition_result;
}
- dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
+ target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
+ (devip->target * 1000) - 3;
+ /* set DPOFUA bit for disks */
+ if (0 == scsi_debug_ptype)
+ dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
+ else
+ dev_spec = 0x0;
if (msense_6) {
arr[2] = dev_spec;
+ arr[3] = bd_len;
offset = 4;
} else {
arr[3] = dev_spec;
+ if (16 == bd_len)
+ arr[4] = 0x1; /* set LONGLBA bit */
+ arr[7] = bd_len; /* assume 255 or less */
offset = 8;
}
ap = arr + offset;
+ if ((bd_len > 0) && (0 == sdebug_capacity)) {
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ }
+ if (8 == bd_len) {
+ if (sdebug_capacity > 0xfffffffe) {
+ ap[0] = 0xff;
+ ap[1] = 0xff;
+ ap[2] = 0xff;
+ ap[3] = 0xff;
+ } else {
+ ap[0] = (sdebug_capacity >> 24) & 0xff;
+ ap[1] = (sdebug_capacity >> 16) & 0xff;
+ ap[2] = (sdebug_capacity >> 8) & 0xff;
+ ap[3] = sdebug_capacity & 0xff;
+ }
+ ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ ap[7] = SECT_SIZE_PER(target) & 0xff;
+ offset += bd_len;
+ ap = arr + offset;
+ } else if (16 == bd_len) {
+ unsigned long long capac = sdebug_capacity;
+
+ for (k = 0; k < 8; ++k, capac >>= 8)
+ ap[7 - k] = capac & 0xff;
+ ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
+ ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
+ ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ ap[15] = SECT_SIZE_PER(target) & 0xff;
+ offset += bd_len;
+ ap = arr + offset;
+ }
- if (0 != subpcode) { /* TODO: Control Extension page */
+ if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
+ /* TODO: Control Extension page */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
@@ -856,17 +1432,45 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
len = resp_ctrl_m_pg(ap, pcontrol, target);
offset += len;
break;
+ case 0x19: /* if spc==1 then sas phy, control+discover */
+ if ((subpcode > 0x2) && (subpcode < 0xff)) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ len = 0;
+ if ((0x0 == subpcode) || (0xff == subpcode))
+ len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
+ if ((0x1 == subpcode) || (0xff == subpcode))
+ len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
+ target_dev_id);
+ if ((0x2 == subpcode) || (0xff == subpcode))
+ len += resp_sas_sha_m_spg(ap + len, pcontrol);
+ offset += len;
+ break;
case 0x1c: /* Informational Exceptions Mode page, all devices */
len = resp_iec_m_pg(ap, pcontrol, target);
offset += len;
break;
case 0x3f: /* Read all Mode pages */
- len = resp_err_recov_pg(ap, pcontrol, target);
- len += resp_disconnect_pg(ap + len, pcontrol, target);
- len += resp_format_pg(ap + len, pcontrol, target);
- len += resp_caching_pg(ap + len, pcontrol, target);
- len += resp_ctrl_m_pg(ap + len, pcontrol, target);
- len += resp_iec_m_pg(ap + len, pcontrol, target);
+ if ((0 == subpcode) || (0xff == subpcode)) {
+ len = resp_err_recov_pg(ap, pcontrol, target);
+ len += resp_disconnect_pg(ap + len, pcontrol, target);
+ len += resp_format_pg(ap + len, pcontrol, target);
+ len += resp_caching_pg(ap + len, pcontrol, target);
+ len += resp_ctrl_m_pg(ap + len, pcontrol, target);
+ len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
+ if (0xff == subpcode) {
+ len += resp_sas_pcd_m_spg(ap + len, pcontrol,
+ target, target_dev_id);
+ len += resp_sas_sha_m_spg(ap + len, pcontrol);
+ }
+ len += resp_iec_m_pg(ap + len, pcontrol, target);
+ } else {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
offset += len;
break;
default:
@@ -883,71 +1487,314 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
}
-static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip)
+#define SDEBUG_MAX_MSELECT_SZ 512
+
+static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
+ struct sdebug_dev_info * devip)
+{
+ int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
+ int param_len, res, errsts, mpage;
+ unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ memset(arr, 0, sizeof(arr));
+ pf = cmd[1] & 0x10;
+ sp = cmd[1] & 0x1;
+ param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
+ if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ res = fetch_to_dev_buffer(scp, arr, param_len);
+ if (-1 == res)
+ return (DID_ERROR << 16);
+ else if ((res < param_len) &&
+ (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+ printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
+ " IO sent=%d bytes\n", param_len, res);
+ md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
+ bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
+ if (md_len > 2) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+ }
+ off = bd_len + (mselect6 ? 4 : 8);
+ mpage = arr[off] & 0x3f;
+ ps = !!(arr[off] & 0x80);
+ if (ps) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+ }
+ spf = !!(arr[off] & 0x40);
+ pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
+ (arr[off + 1] + 2);
+ if ((pg_len + off) > param_len) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ PARAMETER_LIST_LENGTH_ERR, 0);
+ return check_condition_result;
+ }
+ switch (mpage) {
+ case 0xa: /* Control Mode page */
+ if (ctrl_m_pg[1] == arr[off + 1]) {
+ memcpy(ctrl_m_pg + 2, arr + off + 2,
+ sizeof(ctrl_m_pg) - 2);
+ scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
+ return 0;
+ }
+ break;
+ case 0x1c: /* Informational Exceptions Mode page */
+ if (iec_m_pg[1] == arr[off + 1]) {
+ memcpy(iec_m_pg + 2, arr + off + 2,
+ sizeof(iec_m_pg) - 2);
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+}
+
+static int resp_temp_l_pg(unsigned char * arr)
+{
+ unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
+ 0x0, 0x1, 0x3, 0x2, 0x0, 65,
+ };
+
+ memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
+ return sizeof(temp_l_pg);
+}
+
+static int resp_ie_l_pg(unsigned char * arr)
+{
+ unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
+ };
+
+ memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
+ if (iec_m_pg[2] & 0x4) { /* TEST bit set */
+ arr[4] = THRESHOLD_EXCEEDED;
+ arr[5] = 0xff;
+ }
+ return sizeof(ie_l_pg);
+}
+
+#define SDEBUG_MAX_LSENSE_SZ 512
+
+static int resp_log_sense(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
+ unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ memset(arr, 0, sizeof(arr));
+ ppc = cmd[1] & 0x2;
+ sp = cmd[1] & 0x1;
+ if (ppc || sp) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ pcontrol = (cmd[2] & 0xc0) >> 6;
+ pcode = cmd[2] & 0x3f;
+ subpcode = cmd[3] & 0xff;
+ alloc_len = (cmd[7] << 8) + cmd[8];
+ arr[0] = pcode;
+ if (0 == subpcode) {
+ switch (pcode) {
+ case 0x0: /* Supported log pages log page */
+ n = 4;
+ arr[n++] = 0x0; /* this page */
+ arr[n++] = 0xd; /* Temperature */
+ arr[n++] = 0x2f; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ case 0xd: /* Temperature log page */
+ arr[3] = resp_temp_l_pg(arr + 4);
+ break;
+ case 0x2f: /* Informational exceptions log page */
+ arr[3] = resp_ie_l_pg(arr + 4);
+ break;
+ default:
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ } else if (0xff == subpcode) {
+ arr[0] |= 0x40;
+ arr[1] = subpcode;
+ switch (pcode) {
+ case 0x0: /* Supported log pages and subpages log page */
+ n = 4;
+ arr[n++] = 0x0;
+ arr[n++] = 0x0; /* 0,0 page */
+ arr[n++] = 0x0;
+ arr[n++] = 0xff; /* this page */
+ arr[n++] = 0xd;
+ arr[n++] = 0x0; /* Temperature */
+ arr[n++] = 0x2f;
+ arr[n++] = 0x0; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ case 0xd: /* Temperature subpages */
+ n = 4;
+ arr[n++] = 0xd;
+ arr[n++] = 0x0; /* Temperature */
+ arr[3] = n - 4;
+ break;
+ case 0x2f: /* Informational exceptions subpages */
+ n = 4;
+ arr[n++] = 0x2f;
+ arr[n++] = 0x0; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ default:
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ } else {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
+ return fill_from_dev_buffer(scp, arr,
+ min(len, SDEBUG_MAX_INQ_ARR_SZ));
+}
+
+static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip)
{
unsigned long iflags;
+ unsigned int block, from_bottom;
+ unsigned long long u;
int ret;
- if (upper_blk || (block + num > sdebug_capacity)) {
+ if (lba + num > sdebug_capacity) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
0);
return check_condition_result;
}
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
- (block <= OPT_MEDIUM_ERR_ADDR) &&
- ((block + num) > OPT_MEDIUM_ERR_ADDR)) {
+ (lba <= OPT_MEDIUM_ERR_ADDR) &&
+ ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
+ /* claim unrecoverable read error */
mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
0);
- /* claim unrecoverable read error */
+ /* set info field and valid bit for fixed descriptor */
+ if (0x70 == (devip->sense_buff[0] & 0x7f)) {
+ devip->sense_buff[0] |= 0x80; /* Valid bit */
+ ret = OPT_MEDIUM_ERR_ADDR;
+ devip->sense_buff[3] = (ret >> 24) & 0xff;
+ devip->sense_buff[4] = (ret >> 16) & 0xff;
+ devip->sense_buff[5] = (ret >> 8) & 0xff;
+ devip->sense_buff[6] = ret & 0xff;
+ }
return check_condition_result;
}
read_lock_irqsave(&atomic_rw, iflags);
- ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
- num * SECT_SIZE);
+ if ((lba + num) <= sdebug_store_sectors)
+ ret = fill_from_dev_buffer(SCpnt,
+ fake_storep + (lba * SECT_SIZE),
+ num * SECT_SIZE);
+ else {
+ /* modulo when one arg is 64 bits needs do_div() */
+ u = lba;
+ block = do_div(u, sdebug_store_sectors);
+ from_bottom = 0;
+ if ((block + num) > sdebug_store_sectors)
+ from_bottom = (block + num) - sdebug_store_sectors;
+ ret = fill_from_dev_buffer(SCpnt,
+ fake_storep + (block * SECT_SIZE),
+ (num - from_bottom) * SECT_SIZE);
+ if ((0 == ret) && (from_bottom > 0))
+ ret = fill_from_dev_buffer(SCpnt, fake_storep,
+ from_bottom * SECT_SIZE);
+ }
read_unlock_irqrestore(&atomic_rw, iflags);
return ret;
}
-static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip)
+static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip)
{
unsigned long iflags;
+ unsigned int block, to_bottom;
+ unsigned long long u;
int res;
- if (upper_blk || (block + num > sdebug_capacity)) {
+ if (lba + num > sdebug_capacity) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
0);
return check_condition_result;
}
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
write_lock_irqsave(&atomic_rw, iflags);
- res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
- num * SECT_SIZE);
+ if ((lba + num) <= sdebug_store_sectors)
+ res = fetch_to_dev_buffer(SCpnt,
+ fake_storep + (lba * SECT_SIZE),
+ num * SECT_SIZE);
+ else {
+ /* modulo when one arg is 64 bits needs do_div() */
+ u = lba;
+ block = do_div(u, sdebug_store_sectors);
+ to_bottom = 0;
+ if ((block + num) > sdebug_store_sectors)
+ to_bottom = (block + num) - sdebug_store_sectors;
+ res = fetch_to_dev_buffer(SCpnt,
+ fake_storep + (block * SECT_SIZE),
+ (num - to_bottom) * SECT_SIZE);
+ if ((0 == res) && (to_bottom > 0))
+ res = fetch_to_dev_buffer(SCpnt, fake_storep,
+ to_bottom * SECT_SIZE);
+ }
write_unlock_irqrestore(&atomic_rw, iflags);
if (-1 == res)
return (DID_ERROR << 16);
else if ((res < (num * SECT_SIZE)) &&
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
- printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, "
+ printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
" IO sent=%d bytes\n", num * SECT_SIZE, res);
return 0;
}
-#define SDEBUG_RLUN_ARR_SZ 128
+#define SDEBUG_RLUN_ARR_SZ 256
static int resp_report_luns(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned int alloc_len;
- int lun_cnt, i, upper;
+ int lun_cnt, i, upper, num, n, wlun, lun;
unsigned char *cmd = (unsigned char *)scp->cmnd;
int select_report = (int)cmd[2];
struct scsi_lun *one_lun;
unsigned char arr[SDEBUG_RLUN_ARR_SZ];
+ unsigned char * max_addr;
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
- if ((alloc_len < 16) || (select_report > 2)) {
+ if ((alloc_len < 4) || (select_report > 2)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
@@ -955,18 +1802,37 @@ static int resp_report_luns(struct scsi_cmnd * scp,
/* can produce response with up to 16k luns (lun 0 to lun 16383) */
memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
lun_cnt = scsi_debug_max_luns;
- arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
- arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
- lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
- sizeof(struct scsi_lun)), lun_cnt);
+ if (1 == select_report)
+ lun_cnt = 0;
+ else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
+ --lun_cnt;
+ wlun = (select_report > 0) ? 1 : 0;
+ num = lun_cnt + wlun;
+ arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
+ arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
+ n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
+ sizeof(struct scsi_lun)), num);
+ if (n < num) {
+ wlun = 0;
+ lun_cnt = n;
+ }
one_lun = (struct scsi_lun *) &arr[8];
- for (i = 0; i < lun_cnt; i++) {
- upper = (i >> 8) & 0x3f;
+ max_addr = arr + SDEBUG_RLUN_ARR_SZ;
+ for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
+ ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
+ i++, lun++) {
+ upper = (lun >> 8) & 0x3f;
if (upper)
one_lun[i].scsi_lun[0] =
(upper | (SAM2_LUN_ADDRESS_METHOD << 6));
- one_lun[i].scsi_lun[1] = i & 0xff;
+ one_lun[i].scsi_lun[1] = lun & 0xff;
}
+ if (wlun) {
+ one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
+ one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
+ i++;
+ }
+ alloc_len = (unsigned char *)(one_lun + i) - arr;
return fill_from_dev_buffer(scp, arr,
min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
}
@@ -1002,7 +1868,8 @@ static void timer_intr_handler(unsigned long indx)
static int scsi_debug_slave_alloc(struct scsi_device * sdp)
{
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_alloc\n");
+ printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
return 0;
}
@@ -1011,7 +1878,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
struct sdebug_dev_info * devip;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_configure\n");
+ printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
devip = devInfoReg(sdp);
@@ -1019,6 +1887,7 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
if (sdp->host->cmd_per_lun)
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
sdp->host->cmd_per_lun);
+ blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
return 0;
}
@@ -1028,7 +1897,8 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp)
(struct sdebug_dev_info *)sdp->hostdata;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_destroy\n");
+ printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (devip) {
/* make this slot avaliable for re-use */
devip->used = 0;
@@ -1085,6 +1955,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
open_devip->sense_buff[0] = 0x70;
open_devip->sense_buff[7] = 0xa;
}
+ if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
+ open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
return open_devip;
}
return NULL;
@@ -1273,7 +2145,7 @@ static void __init sdebug_build_parts(unsigned char * ramp)
printk(KERN_WARNING "scsi_debug:build_parts: reducing "
"partitions to %d\n", SDEBUG_MAX_PARTS);
}
- num_sectors = (int)(sdebug_store_size / SECT_SIZE);
+ num_sectors = (int)sdebug_store_sectors;
sectors_per_part = (num_sectors - sdebug_sectors_per)
/ scsi_debug_num_parts;
heads_by_sects = sdebug_heads * sdebug_sectors_per;
@@ -1316,9 +2188,9 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
if (scsi_result) {
struct scsi_device * sdp = cmnd->device;
- sdev_printk(KERN_INFO, sdp,
- "non-zero result=0x%x\n",
- scsi_result);
+ printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
+ "non-zero result=0x%x\n", sdp->host->host_no,
+ sdp->channel, sdp->id, sdp->lun, scsi_result);
}
}
if (cmnd && devip) {
@@ -1365,21 +2237,28 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
}
}
-/* 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.
+/* Note: The following macros create attribute files in the
+ /sys/module/scsi_debug/parameters directory. Unfortunately this
+ driver is unaware of a change and cannot trigger auxiliary actions
+ as it can when the corresponding attribute in the
+ /sys/bus/pseudo/drivers/scsi_debug directory is changed.
*/
-module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */
-module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */
-module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);
-module_param_named(dsense, scsi_debug_dsense, int, 0);
-module_param_named(every_nth, scsi_debug_every_nth, int, 0);
-module_param_named(max_luns, scsi_debug_max_luns, int, 0);
-module_param_named(num_parts, scsi_debug_num_parts, int, 0);
-module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);
-module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */
-module_param_named(ptype, scsi_debug_ptype, int, 0);
-module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);
+module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
+module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
+module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
+module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
+module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
+module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
+module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
+module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
+module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
+module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
+module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
+module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
+module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
+module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
+module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
+ S_IRUGO | S_IWUSR);
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -1388,15 +2267,19 @@ MODULE_VERSION(SCSI_DEBUG_VERSION);
MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
-MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs");
-MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)");
+MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
+MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
-MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");
+MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
+MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
+MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
-MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");
-MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");
+MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
+MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
+MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
+MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
static char sdebug_info[256];
@@ -1548,6 +2431,42 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp,
DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
sdebug_dsense_store);
+static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
+}
+static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_fake_rw = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
+ sdebug_fake_rw_store);
+
+static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
+}
+static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_no_lun_0 = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
+ sdebug_no_lun_0_store);
+
static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
@@ -1623,6 +2542,29 @@ static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
}
DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
+static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
+}
+static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_virtual_gb = n;
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
+ sdebug_virtual_gb_store);
+
static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
@@ -1660,29 +2602,65 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp,
DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
sdebug_add_host_store);
-static void do_create_driverfs_files(void)
+static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
+ char * buf)
{
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
+}
+static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_vpd_use_hostno = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
+ sdebug_vpd_use_hostno_store);
+
+/* Note: The following function creates attribute files in the
+ /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
+ files (over those found in the /sys/module/scsi_debug/parameters
+ directory) is that auxiliary actions can be triggered when an attribute
+ is changed. For example see: sdebug_add_host_store() above.
+ */
+static int do_create_driverfs_files(void)
+{
+ int ret;
+
+ ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+ return ret;
}
static void do_remove_driverfs_files(void)
{
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
- driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
@@ -1692,14 +2670,20 @@ static void do_remove_driverfs_files(void)
static int __init scsi_debug_init(void)
{
- unsigned long sz;
+ unsigned int sz;
int host_to_add;
int k;
+ int ret;
if (scsi_debug_dev_size_mb < 1)
scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
- sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576;
- sdebug_capacity = sdebug_store_size / SECT_SIZE;
+ sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
+ sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
@@ -1728,12 +2712,32 @@ static int __init scsi_debug_init(void)
if (scsi_debug_num_parts > 0)
sdebug_build_parts(fake_storep);
- init_all_queued();
+ ret = device_register(&pseudo_primary);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
+ ret);
+ goto free_vm;
+ }
+ ret = bus_register(&pseudo_lld_bus);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
+ ret);
+ goto dev_unreg;
+ }
+ ret = driver_register(&sdebug_driverfs_driver);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
+ ret);
+ goto bus_unreg;
+ }
+ ret = do_create_driverfs_files();
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
+ ret);
+ goto del_files;
+ }
- device_register(&pseudo_primary);
- bus_register(&pseudo_lld_bus);
- driver_register(&sdebug_driverfs_driver);
- do_create_driverfs_files();
+ init_all_queued();
sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
@@ -1753,6 +2757,18 @@ static int __init scsi_debug_init(void)
scsi_debug_add_host);
}
return 0;
+
+del_files:
+ do_remove_driverfs_files();
+ driver_unregister(&sdebug_driverfs_driver);
+bus_unreg:
+ bus_unregister(&pseudo_lld_bus);
+dev_unreg:
+ device_unregister(&pseudo_primary);
+free_vm:
+ vfree(fake_storep);
+
+ return ret;
}
static void __exit scsi_debug_exit(void)
@@ -1813,7 +2829,7 @@ static int sdebug_add_adapter(void)
struct sdebug_dev_info *sdbg_devinfo;
struct list_head *lh, *lh_sf;
- sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
+ sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
if (NULL == sdbg_host) {
printk(KERN_ERR "%s: out of memory at line %d\n",
@@ -1825,7 +2841,7 @@ static int sdebug_add_adapter(void)
devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
for (k = 0; k < devs_per_host; k++) {
- sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo), GFP_KERNEL);
+ sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
if (NULL == sdbg_devinfo) {
printk(KERN_ERR "%s: out of memory at line %d\n",
__FUNCTION__, __LINE__);
@@ -1906,7 +2922,7 @@ static int sdebug_driver_probe(struct device * dev)
hpnt->max_id = scsi_debug_num_tgts + 1;
else
hpnt->max_id = scsi_debug_num_tgts;
- hpnt->max_lun = scsi_debug_max_luns;
+ hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
error = scsi_add_host(hpnt, &sdbg_host->dev);
if (error) {
@@ -1960,7 +2976,7 @@ static void sdebug_max_tgts_luns(void)
hpnt->max_id = scsi_debug_num_tgts + 1;
else
hpnt->max_id = scsi_debug_num_tgts;
- hpnt->max_lun = scsi_debug_max_luns;
+ hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
}
spin_unlock(&sdebug_host_list_lock);
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index fb5cb4c9ac6..3d0429bc14a 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -162,7 +162,7 @@ static struct {
{"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
- {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
+ {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
{"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
{"HP", "C1557A", NULL, BLIST_FORCELUN},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 6a7a60fc0a4..3d355d05461 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -460,19 +460,71 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
**/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+ int cmnd_size, int timeout, int copy_sense)
{
struct scsi_device *sdev = scmd->device;
struct Scsi_Host *shost = sdev->host;
- DECLARE_COMPLETION(done);
+ int old_result = scmd->result;
+ DECLARE_COMPLETION_ONSTACK(done);
unsigned long timeleft;
unsigned long flags;
+ unsigned char old_cmnd[MAX_COMMAND_SIZE];
+ enum dma_data_direction old_data_direction;
+ unsigned short old_use_sg;
+ unsigned char old_cmd_len;
+ unsigned old_bufflen;
+ void *old_buffer;
int rtn;
+ /*
+ * We need saved copies of a number of fields - this is because
+ * error handling may need to overwrite these with different values
+ * to run different commands, and once error handling is complete,
+ * we will need to restore these values prior to running the actual
+ * command.
+ */
+ old_buffer = scmd->request_buffer;
+ old_bufflen = scmd->request_bufflen;
+ memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ old_data_direction = scmd->sc_data_direction;
+ old_cmd_len = scmd->cmd_len;
+ old_use_sg = scmd->use_sg;
+
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ memcpy(scmd->cmnd, cmnd, cmnd_size);
+
+ if (copy_sense) {
+ int 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)
+ return FAILED;
+ } else {
+ scmd->request_buffer = NULL;
+ scmd->request_bufflen = 0;
+ scmd->sc_data_direction = DMA_NONE;
+ }
+
+ scmd->underflow = 0;
+ scmd->use_sg = 0;
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+
if (sdev->scsi_level <= SCSI_2)
scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
(sdev->lun << 5 & 0xe0);
+ /*
+ * Zero the sense buffer. The scsi spec mandates that any
+ * untransferred sense data should be interpreted as being zero.
+ */
+ memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
shost->eh_action = &done;
spin_lock_irqsave(shost->host_lock, flags);
@@ -522,6 +574,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
rtn = FAILED;
}
+
+ /*
+ * Last chance to have valid sense data.
+ */
+ if (copy_sense) {
+ if (!SCSI_SENSE_VALID(scmd)) {
+ memcpy(scmd->sense_buffer, scmd->request_buffer,
+ sizeof(scmd->sense_buffer));
+ }
+ kfree(scmd->request_buffer);
+ }
+
+
+ /*
+ * Restore original data
+ */
+ scmd->request_buffer = old_buffer;
+ scmd->request_bufflen = old_bufflen;
+ memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
+ scmd->sc_data_direction = old_data_direction;
+ scmd->cmd_len = old_cmd_len;
+ scmd->use_sg = old_use_sg;
+ scmd->result = old_result;
return rtn;
}
@@ -537,56 +612,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
static int scsi_request_sense(struct scsi_cmnd *scmd)
{
static unsigned char generic_sense[6] =
- {REQUEST_SENSE, 0, 0, 0, 252, 0};
- unsigned char *scsi_result;
- int saved_result;
- int rtn;
-
- memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
-
- scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0));
+ {REQUEST_SENSE, 0, 0, 0, 252, 0};
-
- if (unlikely(!scsi_result)) {
- printk(KERN_ERR "%s: cannot allocate scsi_result.\n",
- __FUNCTION__);
- return FAILED;
- }
-
- /*
- * zero the sense buffer. some host adapters automatically always
- * request sense, so it is not a good idea that
- * scmd->request_buffer and scmd->sense_buffer point to the same
- * address (db). 0 is not a valid sense code.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
- memset(scsi_result, 0, 252);
-
- saved_result = scmd->result;
- scmd->request_buffer = scsi_result;
- scmd->request_bufflen = 252;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->underflow = 0;
-
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
-
- /* last chance to have valid sense data */
- if(!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, scmd->request_buffer,
- sizeof(scmd->sense_buffer));
- }
-
- kfree(scsi_result);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
- return rtn;
+ return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
}
/**
@@ -605,12 +633,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
{
scmd->device->host->host_failed--;
scmd->eh_eflags = 0;
-
- /*
- * set this back so that the upper level can correctly free up
- * things.
- */
- scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_entry, done_q);
}
EXPORT_SYMBOL(scsi_eh_finish_cmd);
@@ -715,47 +737,23 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd)
{
static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
int retry_cnt = 1, rtn;
- int saved_result;
retry_tur:
- memcpy(scmd->cmnd, tur_command, sizeof(tur_command));
-
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+ rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
-
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
-
- /*
- * hey, we are done. let's look to see what happened.
- */
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
__FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
- else if (rtn == NEEDS_RETRY) {
+
+ switch (rtn) {
+ case NEEDS_RETRY:
if (retry_cnt--)
goto retry_tur;
+ /*FALLTHRU*/
+ case SUCCESS:
return 0;
+ default:
+ return 1;
}
- return 1;
}
/**
@@ -837,44 +835,16 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
{
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
- int rtn;
- int saved_result;
-
- if (!scmd->device->allow_restart)
- return 1;
- memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
-
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
-
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
+ if (scmd->device->allow_restart) {
+ int rtn;
- rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
+ rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+ START_UNIT_TIMEOUT, 0);
+ if (rtn == SUCCESS)
+ return 0;
+ }
- /*
- * hey, we are done. let's look to see what happened.
- */
- SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
- __FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
return 1;
}
@@ -1672,7 +1642,9 @@ int
scsi_reset_provider(struct scsi_device *dev, int flag)
{
struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+ struct Scsi_Host *shost = dev->host;
struct request req;
+ unsigned long flags;
int rtn;
scmd->request = &req;
@@ -1682,8 +1654,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scmd->scsi_done = scsi_reset_provider_done_command;
scmd->done = NULL;
- scmd->buffer = NULL;
- scmd->bufflen = 0;
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
@@ -1699,6 +1669,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
*/
scmd->pid = 0;
+ spin_lock_irqsave(shost->host_lock, flags);
+ shost->tmf_in_progress = 1;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
switch (flag) {
case SCSI_TRY_RESET_DEVICE:
rtn = scsi_try_bus_device_reset(scmd);
@@ -1717,6 +1691,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
rtn = FAILED;
}
+ spin_lock_irqsave(shost->host_lock, flags);
+ shost->tmf_in_progress = 0;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ /*
+ * be sure to wake up anyone who was sleeping or had their queue
+ * suspended while we performed the TMF.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,
+ printk("%s: waking up host to restart after TMF\n",
+ __FUNCTION__));
+
+ wake_up(&shost->host_wait);
+
+ scsi_run_host_queues(shost);
+
scsi_next_command(scmd);
return rtn;
}
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index a89c4115cfb..32293f45166 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -110,11 +110,8 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
sshdr.asc, sshdr.ascq);
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) {
- printk(KERN_INFO "Device not ready. Make sure"
- " there is a disc in the drive.\n");
+ if (sdev->removable)
break;
- }
case UNIT_ATTENTION:
if (sdev->removable) {
sdev->changed = 1;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3d04a9f386a..d6743b959a7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -436,60 +436,16 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
*
* Arguments: cmd - command that is ready to be queued.
*
- * Returns: Nothing
- *
* Notes: This function has the job of initializing a number of
* fields related to error handling. Typically this will
* be called once for each command, as required.
*/
-static int scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
{
cmd->serial_number = 0;
-
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
-
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- /*
- * We need saved copies of a number of fields - this is because
- * error handling may need to overwrite these with different values
- * to run different commands, and once error handling is complete,
- * we will need to restore these values prior to running the actual
- * command.
- */
- cmd->old_use_sg = cmd->use_sg;
- cmd->old_cmd_len = cmd->cmd_len;
- cmd->sc_old_data_direction = cmd->sc_data_direction;
- cmd->old_underflow = cmd->underflow;
- memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
- cmd->buffer = cmd->request_buffer;
- cmd->bufflen = cmd->request_bufflen;
-
- return 1;
-}
-
-/*
- * Function: scsi_setup_cmd_retry()
- *
- * Purpose: Restore the command state for a retry
- *
- * Arguments: cmd - command to be restored
- *
- * Returns: Nothing
- *
- * Notes: Immediately prior to retrying a command, we need
- * to restore certain fields that we saved above.
- */
-void scsi_setup_cmd_retry(struct scsi_cmnd *cmd)
-{
- memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd));
- cmd->request_buffer = cmd->buffer;
- cmd->request_bufflen = cmd->bufflen;
- cmd->use_sg = cmd->old_use_sg;
- cmd->cmd_len = cmd->old_cmd_len;
- cmd->sc_data_direction = cmd->sc_old_data_direction;
- cmd->underflow = cmd->old_underflow;
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -595,7 +551,15 @@ static void scsi_run_queue(struct request_queue *q)
list_del_init(&sdev->starved_entry);
spin_unlock_irqrestore(shost->host_lock, flags);
- blk_run_queue(sdev->request_queue);
+
+ if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
+ !test_and_set_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags)) {
+ blk_run_queue(sdev->request_queue);
+ clear_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags);
+ } else
+ blk_run_queue(sdev->request_queue);
spin_lock_irqsave(shost->host_lock, flags);
if (unlikely(!list_empty(&sdev->starved_entry)))
@@ -807,22 +771,13 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
*/
static void scsi_release_buffers(struct scsi_cmnd *cmd)
{
- struct request *req = cmd->request;
-
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- */
if (cmd->use_sg)
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
- else if (cmd->request_buffer != req->buffer)
- kfree(cmd->request_buffer);
/*
* Zero these out. They now point to freed memory, and it is
* dangerous to hang onto the pointers.
*/
- cmd->buffer = NULL;
- cmd->bufflen = 0;
cmd->request_buffer = NULL;
cmd->request_bufflen = 0;
}
@@ -855,11 +810,10 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
* b) We can just use scsi_requeue_command() here. This would
* be used if we just wanted to retry, for example.
*/
-void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
- unsigned int block_bytes)
+void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
int result = cmd->result;
- int this_count = cmd->bufflen;
+ int this_count = cmd->request_bufflen;
request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request;
int clear_errors = 1;
@@ -867,28 +821,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
int sense_valid = 0;
int sense_deferred = 0;
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- * For the case of a READ, we need to copy the data out of the
- * bounce buffer and into the real buffer.
- */
- if (cmd->use_sg)
- scsi_free_sgtable(cmd->buffer, cmd->sglist_len);
- else if (cmd->buffer != req->buffer) {
- if (rq_data_dir(req) == READ) {
- unsigned long flags;
- char *to = bio_kmap_irq(req->bio, &flags);
- memcpy(to, cmd->buffer, cmd->bufflen);
- bio_kunmap_irq(to, &flags);
- }
- kfree(cmd->buffer);
- }
+ scsi_release_buffers(cmd);
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
+
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result;
if (result) {
@@ -909,99 +849,73 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
}
/*
- * Zero these out. They now point to freed memory, and it is
- * dangerous to hang onto the pointers.
- */
- cmd->buffer = NULL;
- cmd->bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->request_bufflen = 0;
-
- /*
* Next deal with any sectors which we were able to correctly
* handle.
*/
- if (good_bytes >= 0) {
- SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
- req->nr_sectors, good_bytes));
- SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
+ SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, "
+ "%d bytes done.\n",
+ req->nr_sectors, good_bytes));
+ SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
- if (clear_errors)
- req->errors = 0;
- /*
- * If multiple sectors are requested in one buffer, then
- * they will have been finished off by the first command.
- * If not, then we have a multi-buffer command.
- *
- * If block_bytes != 0, it means we had a medium error
- * of some sort, and that we want to mark some number of
- * sectors as not uptodate. Thus we want to inhibit
- * requeueing right here - we will requeue down below
- * when we handle the bad sectors.
- */
+ if (clear_errors)
+ req->errors = 0;
- /*
- * If the command completed without error, then either
- * finish off the rest of the command, or start a new one.
- */
- if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
- return;
- }
- /*
- * Now, if we were good little boys and girls, Santa left us a request
- * sense buffer. We can extract information from this, so we
- * can choose a block to remap, etc.
+ /* A number of bytes were successfully read. If there
+ * are leftovers and there is some kind of error
+ * (result != 0), retry the rest.
+ */
+ if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
+ return;
+
+ /* good_bytes = 0, or (inclusive) there were leftovers and
+ * result = 0, so scsi_end_request couldn't retry.
*/
if (sense_valid && !sense_deferred) {
switch (sshdr.sense_key) {
case UNIT_ATTENTION:
if (cmd->device->removable) {
- /* detected disc change. set a bit
+ /* Detected disc change. Set a bit
* and quietly refuse further access.
*/
cmd->device->changed = 1;
- scsi_end_request(cmd, 0,
- this_count, 1);
+ scsi_end_request(cmd, 0, this_count, 1);
return;
} else {
- /*
- * Must have been a power glitch, or a
- * bus reset. Could not have been a
- * media change, so we just retry the
- * request and see what happens.
- */
+ /* Must have been a power glitch, or a
+ * bus reset. Could not have been a
+ * media change, so we just retry the
+ * request and see what happens.
+ */
scsi_requeue_command(q, cmd);
return;
}
break;
case ILLEGAL_REQUEST:
- /*
- * If we had an ILLEGAL REQUEST returned, then we may
- * have performed an unsupported command. The only
- * thing this should be would be a ten byte read where
- * only a six byte read was supported. Also, on a
- * system where READ CAPACITY failed, we may have read
- * past the end of the disk.
- */
+ /* If we had an ILLEGAL REQUEST returned, then
+ * we may have performed an unsupported
+ * command. The only thing this should be
+ * would be a ten byte read where only a six
+ * byte read was supported. Also, on a system
+ * where READ CAPACITY failed, we may have
+ * read past the end of the disk.
+ */
if ((cmd->device->use_10_for_rw &&
sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
(cmd->cmnd[0] == READ_10 ||
cmd->cmnd[0] == WRITE_10)) {
cmd->device->use_10_for_rw = 0;
- /*
- * This will cause a retry with a 6-byte
- * command.
+ /* This will cause a retry with a
+ * 6-byte command.
*/
scsi_requeue_command(q, cmd);
- result = 0;
+ return;
} else {
scsi_end_request(cmd, 0, this_count, 1);
return;
}
break;
case NOT_READY:
- /*
- * If the device is in the process of becoming
+ /* If the device is in the process of becoming
* ready, or has a temporary blockage, retry.
*/
if (sshdr.asc == 0x04) {
@@ -1021,7 +935,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
}
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "Device not ready: ");
+ "Device not ready: ");
scsi_print_sense_hdr("", &sshdr);
}
scsi_end_request(cmd, 0, this_count, 1);
@@ -1029,21 +943,21 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
case VOLUME_OVERFLOW:
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "Volume overflow, CDB: ");
- __scsi_print_command(cmd->data_cmnd);
+ "Volume overflow, CDB: ");
+ __scsi_print_command(cmd->cmnd);
scsi_print_sense("", cmd);
}
- scsi_end_request(cmd, 0, block_bytes, 1);
+ /* See SSC3rXX or current. */
+ scsi_end_request(cmd, 0, this_count, 1);
return;
default:
break;
}
- } /* driver byte != 0 */
+ }
if (host_byte(result) == DID_RESET) {
- /*
- * Third party bus reset or reset for error
- * recovery reasons. Just retry the request
- * and see what happens.
+ /* Third party bus reset or reset for error recovery
+ * reasons. Just retry the request and see what
+ * happens.
*/
scsi_requeue_command(q, cmd);
return;
@@ -1051,21 +965,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
if (result) {
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "SCSI error: return code = 0x%x\n", result);
-
+ "SCSI error: return code = 0x%08x\n",
+ result);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
}
- /*
- * Mark a single buffer as not uptodate. Queue the remainder.
- * We sometimes get this cruft in the event that a medium error
- * isn't properly reported.
- */
- block_bytes = req->hard_cur_sectors << 9;
- if (!block_bytes)
- block_bytes = req->data_len;
- scsi_end_request(cmd, 0, block_bytes, 1);
}
+ scsi_end_request(cmd, 0, this_count, !result);
}
EXPORT_SYMBOL(scsi_io_completion);
@@ -1169,7 +1075,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
* successfully. Since this is a REQ_BLOCK_PC command the
* caller should check the request's errors value
*/
- scsi_io_completion(cmd, cmd->bufflen, 0);
+ scsi_io_completion(cmd, cmd->request_bufflen);
}
static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
@@ -2050,6 +1956,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
switch (oldstate) {
case SDEV_CREATED:
case SDEV_RUNNING:
+ case SDEV_QUIESCE:
case SDEV_OFFLINE:
case SDEV_BLOCK:
break;
@@ -2060,6 +1967,9 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_DEL:
switch (oldstate) {
+ case SDEV_CREATED:
+ case SDEV_RUNNING:
+ case SDEV_OFFLINE:
case SDEV_CANCEL:
break;
default:
diff --git a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h
index a3e2af6a846..1f65139e14f 100644
--- a/drivers/scsi/scsi_logging.h
+++ b/drivers/scsi/scsi_logging.h
@@ -1,7 +1,6 @@
#ifndef _SCSI_LOGGING_H
#define _SCSI_LOGGING_H
-#include <linux/config.h>
/*
* This defines the scsi logging feature. It is a means by which the user
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
new file mode 100644
index 00000000000..1b59b27e887
--- /dev/null
+++ b/drivers/scsi/scsi_netlink.c
@@ -0,0 +1,199 @@
+/*
+ * scsi_netlink.c - SCSI Transport Netlink Interface
+ *
+ * Copyright (C) 2006 James Smart, Emulex Corporation
+ *
+ * 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/time.h>
+#include <linux/jiffies.h>
+#include <linux/security.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+
+#include <scsi/scsi_netlink.h>
+#include "scsi_priv.h"
+
+struct sock *scsi_nl_sock = NULL;
+EXPORT_SYMBOL_GPL(scsi_nl_sock);
+
+
+/**
+ * scsi_nl_rcv_msg -
+ * Receive message handler. Extracts message from a receive buffer.
+ * Validates message header and calls appropriate transport message handler
+ *
+ * @skb: socket receive buffer
+ *
+ **/
+static void
+scsi_nl_rcv_msg(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct scsi_nl_hdr *hdr;
+ uint32_t rlen;
+ int err;
+
+ while (skb->len >= NLMSG_SPACE(0)) {
+ err = 0;
+
+ nlh = (struct nlmsghdr *) skb->data;
+ if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
+ (skb->len < nlh->nlmsg_len)) {
+ printk(KERN_WARNING "%s: discarding partial skb\n",
+ __FUNCTION__);
+ return;
+ }
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+
+ if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
+ err = -EBADMSG;
+ goto next_msg;
+ }
+
+ hdr = NLMSG_DATA(nlh);
+ if ((hdr->version != SCSI_NL_VERSION) ||
+ (hdr->magic != SCSI_NL_MAGIC)) {
+ err = -EPROTOTYPE;
+ goto next_msg;
+ }
+
+ if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto next_msg;
+ }
+
+ if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
+ printk(KERN_WARNING "%s: discarding partial message\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /*
+ * We currently don't support anyone sending us a message
+ */
+
+next_msg:
+ if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
+ netlink_ack(skb, nlh, err);
+
+ skb_pull(skb, rlen);
+ }
+}
+
+
+/**
+ * scsi_nl_rcv_msg -
+ * Receive handler for a socket. Extracts a received message buffer from
+ * the socket, and starts message processing.
+ *
+ * @sk: socket
+ * @len: unused
+ *
+ **/
+static void
+scsi_nl_rcv(struct sock *sk, int len)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+ scsi_nl_rcv_msg(skb);
+ kfree_skb(skb);
+ }
+}
+
+
+/**
+ * scsi_nl_rcv_event -
+ * Event handler for a netlink socket.
+ *
+ * @this: event notifier block
+ * @event: event type
+ * @ptr: event payload
+ *
+ **/
+static int
+scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct netlink_notify *n = ptr;
+
+ if (n->protocol != NETLINK_SCSITRANSPORT)
+ return NOTIFY_DONE;
+
+ /*
+ * Currently, we are not tracking PID's, etc. There is nothing
+ * to handle.
+ */
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block scsi_netlink_notifier = {
+ .notifier_call = scsi_nl_rcv_event,
+};
+
+
+/**
+ * scsi_netlink_init -
+ * Called by SCSI subsystem to intialize the SCSI transport netlink
+ * interface
+ *
+ **/
+void
+scsi_netlink_init(void)
+{
+ int error;
+
+ error = netlink_register_notifier(&scsi_netlink_notifier);
+ if (error) {
+ printk(KERN_ERR "%s: register of event handler failed - %d\n",
+ __FUNCTION__, error);
+ return;
+ }
+
+ scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
+ SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE);
+ if (!scsi_nl_sock) {
+ printk(KERN_ERR "%s: register of recieve handler failed\n",
+ __FUNCTION__);
+ netlink_unregister_notifier(&scsi_netlink_notifier);
+ }
+
+ return;
+}
+
+
+/**
+ * scsi_netlink_exit -
+ * Called by SCSI subsystem to disable the SCSI transport netlink
+ * interface
+ *
+ **/
+void
+scsi_netlink_exit(void)
+{
+ if (scsi_nl_sock) {
+ sock_release(scsi_nl_sock->sk_socket);
+ netlink_unregister_notifier(&scsi_netlink_notifier);
+ }
+
+ return;
+}
+
+
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index a1727a0e1bd..5d023d44e5e 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -1,7 +1,6 @@
#ifndef _SCSI_PRIV_H
#define _SCSI_PRIV_H
-#include <linux/config.h>
#include <linux/device.h>
struct request_queue;
@@ -9,6 +8,7 @@ struct scsi_cmnd;
struct scsi_device;
struct scsi_host_template;
struct Scsi_Host;
+struct scsi_nl_hdr;
/*
@@ -58,7 +58,6 @@ extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
/* scsi_lib.c */
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
-extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_next_command(struct scsi_cmnd *cmd);
@@ -112,12 +111,22 @@ extern void __scsi_remove_device(struct scsi_device *);
extern struct bus_type scsi_bus_type;
+/* scsi_netlink.c */
+#ifdef CONFIG_SCSI_NETLINK
+extern void scsi_netlink_init(void);
+extern void scsi_netlink_exit(void);
+extern struct sock *scsi_nl_sock;
+#else
+static inline void scsi_netlink_init(void) {}
+static inline void scsi_netlink_exit(void) {}
+#endif
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
*/
-#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT (HZ*60)
+#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */
extern int scsi_internal_device_block(struct scsi_device *sdev);
extern int scsi_internal_device_unblock(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 55200e4fdf1..524a5f7a519 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -178,9 +178,7 @@ static int proc_print_scsidevice(struct device *dev, void *data)
seq_printf(s, "\n");
- seq_printf(s, " Type: %s ",
- sdev->type < MAX_SCSI_DEVICE_CODE ?
- scsi_device_types[(int) sdev->type] : "Unknown ");
+ seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
seq_printf(s, " ANSI"
" SCSI revision: %02x", (sdev->scsi_level - 1) ?
sdev->scsi_level - 1 : 1);
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h
index d76e6e3d8ca..e1edab45a37 100644
--- a/drivers/scsi/scsi_sas_internal.h
+++ b/drivers/scsi/scsi_sas_internal.h
@@ -2,7 +2,8 @@
#define _SCSI_SAS_INTERNAL_H
#define SAS_HOST_ATTRS 0
-#define SAS_PORT_ATTRS 17
+#define SAS_PHY_ATTRS 17
+#define SAS_PORT_ATTRS 1
#define SAS_RPORT_ATTRS 7
#define SAS_END_DEV_ATTRS 3
#define SAS_EXPANDER_ATTRS 7
@@ -13,12 +14,14 @@ struct sas_internal {
struct sas_domain_function_template *dft;
struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
- struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
+ struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS];
+ struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS];
struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
struct transport_container phy_attr_cont;
+ struct transport_container port_attr_cont;
struct transport_container rphy_attr_cont;
struct transport_container end_dev_attr_cont;
struct transport_container expander_attr_cont;
@@ -28,7 +31,8 @@ struct sas_internal {
* needed by scsi_sysfs.c
*/
struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
- struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
+ struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1];
+ struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1];
struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0f7e6f94d66..fd9e281c3bf 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -25,7 +25,6 @@
* or a LUN is seen that cannot have a device attached to it.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -135,59 +134,6 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
}
/**
- * print_inquiry - printk the inquiry information
- * @inq_result: printk this SCSI INQUIRY
- *
- * Description:
- * printk the vendor, model, and other information found in the
- * INQUIRY data in @inq_result.
- *
- * Notes:
- * Remove this, and replace with a hotplug event that logs any
- * relevant information.
- **/
-static void print_inquiry(unsigned char *inq_result)
-{
- int i;
-
- printk(KERN_NOTICE " Vendor: ");
- for (i = 8; i < 16; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk(" Model: ");
- for (i = 16; i < 32; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk(" Rev: ");
- for (i = 32; i < 36; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk("\n");
-
- i = inq_result[0] & 0x1f;
-
- printk(KERN_NOTICE " Type: %s ",
- i <
- MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
- "Unknown ");
- printk(" ANSI SCSI revision: %02x",
- inq_result[2] & 0x07);
- if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
- printk(" CCS\n");
- else
- printk("\n");
-}
-
-/**
* scsi_alloc_sdev - allocate and setup a scsi_Device
*
* Description:
@@ -320,6 +266,18 @@ static struct scsi_target *__scsi_find_target(struct device *parent,
return found_starget;
}
+/**
+ * scsi_alloc_target - allocate a new or find an existing target
+ * @parent: parent of the target (need not be a scsi host)
+ * @channel: target channel number (zero if no channels)
+ * @id: target id number
+ *
+ * Return an existing target if one exists, provided it hasn't already
+ * gone into STARGET_DEL state, otherwise allocate a new target.
+ *
+ * The target is returned with an incremented reference, so the caller
+ * is responsible for both reaping and doing a last put
+ */
static struct scsi_target *scsi_alloc_target(struct device *parent,
int channel, uint id)
{
@@ -385,14 +343,15 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
return NULL;
}
}
+ get_device(dev);
return starget;
found:
found_target->reap_ref++;
spin_unlock_irqrestore(shost->host_lock, flags);
- put_device(parent);
if (found_target->state != STARGET_DEL) {
+ put_device(parent);
kfree(starget);
return found_target;
}
@@ -451,6 +410,32 @@ void scsi_target_reap(struct scsi_target *starget)
}
/**
+ * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string
+ * @s: INQUIRY result string to sanitize
+ * @len: length of the string
+ *
+ * Description:
+ * The SCSI spec says that INQUIRY vendor, product, and revision
+ * strings must consist entirely of graphic ASCII characters,
+ * padded on the right with spaces. Since not all devices obey
+ * this rule, we will replace non-graphic or non-ASCII characters
+ * with spaces. Exception: a NUL character is interpreted as a
+ * string terminator, so all the following characters are set to
+ * spaces.
+ **/
+static void sanitize_inquiry_string(unsigned char *s, int len)
+{
+ int terminated = 0;
+
+ for (; len > 0; (--len, ++s)) {
+ if (*s == 0)
+ terminated = 1;
+ if (terminated || *s < 0x20 || *s > 0x7e)
+ *s = ' ';
+ }
+}
+
+/**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
* @sdev: scsi_device to probe
* @inq_result: area to store the INQUIRY result
@@ -464,7 +449,7 @@ void scsi_target_reap(struct scsi_target *starget)
* INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
* are copied to the scsi_device any flags value is stored in *@bflags.
**/
-static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
+static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
int result_len, int *bflags)
{
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -523,7 +508,11 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
}
if (result == 0) {
- response_len = (unsigned char) inq_result[4] + 5;
+ sanitize_inquiry_string(&inq_result[8], 8);
+ sanitize_inquiry_string(&inq_result[16], 16);
+ sanitize_inquiry_string(&inq_result[32], 4);
+
+ response_len = inq_result[4] + 5;
if (response_len > 255)
response_len = first_inquiry_len; /* sanity */
@@ -629,7 +618,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
* SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
* SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
**/
-static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
+static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
+ int *bflags)
{
/*
* XXX do not save the inquiry, since it can change underneath us,
@@ -654,9 +644,8 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (*bflags & BLIST_ISROM) {
/*
* It would be better to modify sdev->type, and set
- * sdev->removable, but then the print_inquiry() output
- * would not show TYPE_ROM; if print_inquiry() is removed
- * the issue goes away.
+ * sdev->removable; this can now be done since
+ * print_inquiry has gone away.
*/
inq_result[0] = TYPE_ROM;
inq_result[1] |= 0x80; /* removable */
@@ -685,8 +674,6 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
}
- print_inquiry(inq_result);
-
/*
* For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
* spec says: The device server is capable of supporting the
@@ -716,6 +703,12 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (inq_result[7] & 0x10)
sdev->sdtr = 1;
+ sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d "
+ "ANSI: %d%s\n", scsi_device_type(sdev->type),
+ sdev->vendor, sdev->model, sdev->rev,
+ sdev->inq_periph_qual, inq_result[2] & 0x07,
+ (inq_result[3] & 0x0f) == 1 ? " CCS" : "");
+
/*
* End sysfs code.
*/
@@ -810,6 +803,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
static inline void scsi_destroy_sdev(struct scsi_device *sdev)
{
+ scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
@@ -943,11 +937,26 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
}
/*
- * Non-standard SCSI targets may set the PDT to 0x1f (unknown or
- * no device type) instead of using the Peripheral Qualifier to
- * indicate that no LUN is present. For example, USB UFI does this.
+ * Some targets may set slight variations of PQ and PDT to signal
+ * that no LUN is present, so don't add sdev in these cases.
+ * Two specific examples are:
+ * 1) NetApp targets: return PQ=1, PDT=0x1f
+ * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
+ * in the UFI 1.0 spec (we cannot rely on reserved bits).
+ *
+ * References:
+ * 1) SCSI SPC-3, pp. 145-146
+ * PQ=1: "A peripheral device having the specified peripheral
+ * device type is not connected to this logical unit. However, the
+ * device server is capable of supporting the specified peripheral
+ * device type on this logical unit."
+ * PDT=0x1f: "Unknown or no device type"
+ * 2) USB UFI 1.0, p. 20
+ * PDT=00h Direct-access device (floppy)
+ * PDT=1Fh none (no FDD connected to the requested logical unit)
*/
- if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) {
+ if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
+ (result[0] & 0x1f) == 0x1f) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: peripheral device type"
" of 31, no device added\n"));
@@ -1345,7 +1354,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (!starget)
return ERR_PTR(-ENOMEM);
- get_device(&starget->dev);
mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
@@ -1404,7 +1412,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
if (!starget)
return;
- get_device(&starget->dev);
if (lun != SCAN_WILD_CARD) {
/*
* Scan for a specific host/chan/id/lun.
@@ -1586,7 +1593,8 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
if (sdev) {
sdev->sdev_gendev.parent = get_device(&starget->dev);
sdev->borken = 0;
- }
+ } else
+ scsi_target_reap(starget);
put_device(&starget->dev);
out:
mutex_unlock(&shost->scan_mutex);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5ec7a4fb014..e7fe565b96d 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -6,7 +6,6 @@
* Created to pull SCSI mid layer sysfs routines into one file.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index f2db7a41cf1..38c215a78f6 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -32,6 +32,9 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <scsi/scsi_netlink_fc.h>
#include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
@@ -93,6 +96,29 @@ fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
#define FC_PORTTYPE_MAX_NAMELEN 50
+/* Convert fc_host_event_code values to ascii string name */
+static const struct {
+ enum fc_host_event_code value;
+ char *name;
+} fc_host_event_code_names[] = {
+ { FCH_EVT_LIP, "lip" },
+ { FCH_EVT_LINKUP, "link_up" },
+ { FCH_EVT_LINKDOWN, "link_down" },
+ { FCH_EVT_LIPRESET, "lip_reset" },
+ { FCH_EVT_RSCN, "rscn" },
+ { FCH_EVT_ADAPTER_CHANGE, "adapter_chg" },
+ { FCH_EVT_PORT_UNKNOWN, "port_unknown" },
+ { FCH_EVT_PORT_ONLINE, "port_online" },
+ { FCH_EVT_PORT_OFFLINE, "port_offline" },
+ { FCH_EVT_PORT_FABRIC, "port_fabric" },
+ { FCH_EVT_LINK_UNKNOWN, "link_unknown" },
+ { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" },
+};
+fc_enum_name_search(host_event_code, fc_host_event_code,
+ fc_host_event_code_names)
+#define FC_HOST_EVENT_CODE_MAX_NAMELEN 30
+
+
/* Convert fc_port_state values to ascii string name */
static struct {
enum fc_port_state value;
@@ -216,6 +242,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
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);
/*
@@ -223,7 +250,7 @@ static void fc_scsi_scan_rport(void *data);
* Increase these values if you add attributes
*/
#define FC_STARGET_NUM_ATTRS 3
-#define FC_RPORT_NUM_ATTRS 9
+#define FC_RPORT_NUM_ATTRS 10
#define FC_HOST_NUM_ATTRS 17
struct fc_internal {
@@ -301,8 +328,6 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
fc_host->supported_classes = FC_COS_UNSPECIFIED;
memset(fc_host->supported_fc4s, 0,
sizeof(fc_host->supported_fc4s));
- memset(fc_host->symbolic_name, 0,
- sizeof(fc_host->symbolic_name));
fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
fc_host->maxframe_size = -1;
memset(fc_host->serial_number, 0,
@@ -315,6 +340,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
sizeof(fc_host->active_fc4s));
fc_host->speed = FC_PORTSPEED_UNKNOWN;
fc_host->fabric_name = -1;
+ memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name));
+ memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname));
fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN;
@@ -368,7 +395,7 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class,
* should insulate the loss of a remote port.
* The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
*/
-static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT;
+static unsigned int fc_dev_loss_tmo = 60; /* seconds */
module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dev_loss_tmo,
@@ -377,10 +404,184 @@ MODULE_PARM_DESC(dev_loss_tmo,
" exceeded, the scsi target is removed. Value should be"
" between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+/**
+ * Netlink Infrastructure
+ **/
+
+static atomic_t fc_event_seq;
+
+/**
+ * fc_get_event_number - Obtain the next sequential FC event number
+ *
+ * Notes:
+ * We could have inline'd this, but it would have required fc_event_seq to
+ * be exposed. For now, live with the subroutine call.
+ * Atomic used to avoid lock/unlock...
+ **/
+u32
+fc_get_event_number(void)
+{
+ return atomic_add_return(1, &fc_event_seq);
+}
+EXPORT_SYMBOL(fc_get_event_number);
+
+
+/**
+ * fc_host_post_event - called to post an even on an fc_host.
+ *
+ * @shost: host the event occurred on
+ * @event_number: fc event number obtained from get_fc_event_number()
+ * @event_code: fc_host event being posted
+ * @event_data: 32bits of data for the event being posted
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void
+fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code, u32 event_data)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct fc_nl_event *event;
+ const char *name;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ goto send_fail;
+ }
+
+ len = FC_NL_MSGALIGN(sizeof(*event));
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ goto send_fail;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+ skblen - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ goto send_fail_skb;
+ }
+ event = NLMSG_DATA(nlh);
+
+ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
+ FC_NL_ASYNC_EVENT, len);
+ event->seconds = get_seconds();
+ event->vendor_id = 0;
+ event->host_no = shost->host_no;
+ event->event_datalen = sizeof(u32); /* bytes */
+ event->event_num = event_number;
+ event->event_code = event_code;
+ event->event_data = event_data;
+
+ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
+ GFP_KERNEL);
+ if (err && (err != -ESRCH)) /* filter no recipient errors */
+ /* nlmsg_multicast already kfree_skb'd */
+ goto send_fail;
+
+ return;
+
+send_fail_skb:
+ kfree_skb(skb);
+send_fail:
+ name = get_fc_host_event_code_name(event_code);
+ printk(KERN_WARNING
+ "%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
+ __FUNCTION__, shost->host_no,
+ (name) ? name : "<unknown>", event_data, err);
+ return;
+}
+EXPORT_SYMBOL(fc_host_post_event);
+
+
+/**
+ * fc_host_post_vendor_event - called to post a vendor unique event on
+ * a fc_host
+ *
+ * @shost: host the event occurred on
+ * @event_number: fc event number obtained from get_fc_event_number()
+ * @data_len: amount, in bytes, of vendor unique data
+ * @data_buf: pointer to vendor unique data
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void
+fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
+ u32 data_len, char * data_buf, u64 vendor_id)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct fc_nl_event *event;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ goto send_vendor_fail;
+ }
+
+ len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ goto send_vendor_fail;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+ skblen - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ goto send_vendor_fail_skb;
+ }
+ event = NLMSG_DATA(nlh);
+
+ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
+ FC_NL_ASYNC_EVENT, len);
+ event->seconds = get_seconds();
+ event->vendor_id = vendor_id;
+ event->host_no = shost->host_no;
+ event->event_datalen = data_len; /* bytes */
+ event->event_num = event_number;
+ event->event_code = FCH_EVT_VENDOR_UNIQUE;
+ memcpy(&event->event_data, data_buf, data_len);
+
+ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
+ GFP_KERNEL);
+ if (err && (err != -ESRCH)) /* filter no recipient errors */
+ /* nlmsg_multicast already kfree_skb'd */
+ goto send_vendor_fail;
+
+ return;
+
+send_vendor_fail_skb:
+ kfree_skb(skb);
+send_vendor_fail:
+ printk(KERN_WARNING
+ "%s: Dropped Event : host %d vendor_unique - err %d\n",
+ __FUNCTION__, shost->host_no, err);
+ return;
+}
+EXPORT_SYMBOL(fc_host_post_vendor_event);
+
+
static __init int fc_transport_init(void)
{
- int error = transport_class_register(&fc_host_class);
+ int error;
+
+ atomic_set(&fc_event_seq, 0);
+
+ error = transport_class_register(&fc_host_class);
if (error)
return error;
error = transport_class_register(&fc_rport_class);
@@ -424,11 +625,14 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
struct fc_rport *rport = transport_class_to_rport(cdev); \
struct Scsi_Host *shost = rport_to_shost(rport); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
(rport->port_state == FC_PORTSTATE_DELETED) || \
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
return -EBUSY; \
- val = simple_strtoul(buf, NULL, 0); \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
i->f->set_rport_##field(rport, val); \
return count; \
}
@@ -510,6 +714,13 @@ static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO, \
if (i->f->show_rport_##field) \
count++
+#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \
+{ \
+ i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+ i->rport_attrs[count] = &i->private_rport_attrs[count]; \
+ count++; \
+}
+
/* The FC Transport Remote Port Attributes: */
@@ -542,12 +753,14 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf,
struct fc_rport *rport = transport_class_to_rport(cdev);
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
+ char *cp;
if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
(rport->port_state == FC_PORTSTATE_DELETED) ||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
- val = simple_strtoul(buf, NULL, 0);
- if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ val = simple_strtoul(buf, &cp, 0);
+ if ((*cp && (*cp != '\n')) ||
+ (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
return -EINVAL;
i->f->set_rport_dev_loss_tmo(rport, val);
return count;
@@ -597,6 +810,44 @@ static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);
+/*
+ * fast_io_fail_tmo attribute
+ */
+static ssize_t
+show_fc_rport_fast_io_fail_tmo (struct class_device *cdev, char *buf)
+{
+ struct fc_rport *rport = transport_class_to_rport(cdev);
+
+ if (rport->fast_io_fail_tmo == -1)
+ return snprintf(buf, 5, "off\n");
+ return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo);
+}
+
+static ssize_t
+store_fc_rport_fast_io_fail_tmo(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ int val;
+ char *cp;
+ struct fc_rport *rport = transport_class_to_rport(cdev);
+
+ if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
+ (rport->port_state == FC_PORTSTATE_DELETED) ||
+ (rport->port_state == FC_PORTSTATE_NOTPRESENT))
+ return -EBUSY;
+ if (strncmp(buf, "off", 3) == 0)
+ rport->fast_io_fail_tmo = -1;
+ else {
+ val = simple_strtoul(buf, &cp, 0);
+ if ((*cp && (*cp != '\n')) ||
+ (val < 0) || (val >= rport->dev_loss_tmo))
+ return -EINVAL;
+ rport->fast_io_fail_tmo = val;
+ }
+ return count;
+}
+static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
+ show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo);
/*
@@ -682,12 +933,34 @@ store_fc_host_##field(struct class_device *cdev, const char *buf, \
int val; \
struct Scsi_Host *shost = transport_class_to_shost(cdev); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
\
- val = simple_strtoul(buf, NULL, 0); \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
i->f->set_host_##field(shost, val); \
return count; \
}
+#define fc_host_store_str_function(field, slen) \
+static ssize_t \
+store_fc_host_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ unsigned int cnt=count; \
+ \
+ /* count may include a LF at end of string */ \
+ if (buf[cnt-1] == '\n') \
+ cnt--; \
+ if (cnt > ((slen) - 1)) \
+ return -EINVAL; \
+ memcpy(fc_host_##field(shost), buf, cnt); \
+ i->f->set_host_##field(shost); \
+ return count; \
+}
+
#define fc_host_rd_attr(field, format_string, sz) \
fc_host_show_function(field, format_string, sz, ) \
static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \
@@ -815,7 +1088,6 @@ fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
unsigned long long);
-fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -858,6 +1130,13 @@ fc_host_rd_attr(port_id, "0x%06x\n", 20);
fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN);
fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
+fc_host_rd_attr(symbolic_name, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1);
+
+fc_private_host_show_function(system_hostname, "%s\n",
+ FC_SYMBOLIC_NAME_SIZE + 1, )
+fc_host_store_str_function(system_hostname, FC_SYMBOLIC_NAME_SIZE)
+static FC_CLASS_DEVICE_ATTR(host, system_hostname, S_IRUGO | S_IWUSR,
+ show_fc_host_system_hostname, store_fc_host_system_hostname);
/* Private Host Attributes */
@@ -1223,7 +1502,6 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_HOST_ATTRIBUTE_RD(permanent_port_name);
SETUP_HOST_ATTRIBUTE_RD(supported_classes);
SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
- SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
SETUP_HOST_ATTRIBUTE_RD(serial_number);
@@ -1234,6 +1512,8 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_HOST_ATTRIBUTE_RD(active_fc4s);
SETUP_HOST_ATTRIBUTE_RD(speed);
SETUP_HOST_ATTRIBUTE_RD(fabric_name);
+ SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
+ SETUP_HOST_ATTRIBUTE_RW(system_hostname);
/* Transport-managed attributes */
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
@@ -1257,6 +1537,8 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
+ if (ft->terminate_rport_io)
+ SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);
BUG_ON(count > FC_RPORT_NUM_ATTRS);
@@ -1284,7 +1566,9 @@ EXPORT_SYMBOL(fc_release_transport);
* @work: Work to queue for execution.
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 - work queued for execution
+ * 0 - work is already queued
+ * -EINVAL - work queue doesn't exist
**/
static int
fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
@@ -1326,7 +1610,7 @@ fc_flush_work(struct Scsi_Host *shost)
* @delay: jiffies to delay the work queuing
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 on success / 0 already queued / < 0 for error
**/
static int
fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
@@ -1341,6 +1625,9 @@ 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);
}
@@ -1433,12 +1720,23 @@ fc_starget_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
+ struct fc_internal *i = to_fc_internal(shost->transportt);
- scsi_target_unblock(&rport->dev);
+ /*
+ * Involve the LLDD if possible. All io on the rport is to
+ * be terminated, either as part of the dev_loss_tmo callback
+ * processing, or via the terminate_rport_io function.
+ */
+ if (i->f->dev_loss_tmo_callbk)
+ i->f->dev_loss_tmo_callbk(rport);
+ else if (i->f->terminate_rport_io)
+ i->f->terminate_rport_io(rport);
spin_lock_irqsave(shost->host_lock, flags);
if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
spin_unlock_irqrestore(shost->host_lock, flags);
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
@@ -1461,10 +1759,7 @@ fc_rport_final_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);
-
- /* Delete SCSI target and sdevs */
- if (rport->scsi_target_id != -1)
- fc_starget_delete(data);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
/*
* if a scan is pending, flush the SCSI Host work_q so that
@@ -1473,10 +1768,19 @@ fc_rport_final_delete(void *data)
if (rport->flags & FC_RPORT_SCAN_PENDING)
scsi_flush_work(shost);
+ /* Delete SCSI target and sdevs */
+ if (rport->scsi_target_id != -1)
+ fc_starget_delete(data);
+ else if (i->f->dev_loss_tmo_callbk)
+ i->f->dev_loss_tmo_callbk(rport);
+ else if (i->f->terminate_rport_io)
+ i->f->terminate_rport_io(rport);
+
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
- put_device(&shost->shost_gendev);
+ put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ put_device(dev); /* for self-reference */
}
@@ -1523,8 +1827,10 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
if (fci->f->dd_fcrport_size)
rport->dd_data = &rport[1];
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);
@@ -1537,13 +1843,13 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
- get_device(&shost->shost_gendev);
+ get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
dev = &rport->dev;
- device_initialize(dev);
- dev->parent = get_device(&shost->shost_gendev);
+ device_initialize(dev); /* takes self reference */
+ dev->parent = get_device(&shost->shost_gendev); /* parent reference */
dev->release = fc_rport_dev_release;
sprintf(dev->bus_id, "rport-%d:%d-%d",
shost->host_no, channel, rport->number);
@@ -1567,10 +1873,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
delete_rport:
transport_destroy_device(dev);
- put_device(dev->parent);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
- put_device(&shost->shost_gendev);
+ put_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
kfree(rport);
@@ -1689,11 +1994,13 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* restart the target */
/*
- * Stop the target timer first. Take no action
+ * Stop the target timers first. Take no action
* on the del_timer failure as the state
* machine state change will validate the
* transaction.
*/
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(work))
fc_flush_devloss(shost);
@@ -1707,6 +2014,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+
return rport;
}
}
@@ -1762,9 +2071,10 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
- }
-
- spin_unlock_irqrestore(shost->host_lock, flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+ } else
+ spin_unlock_irqrestore(shost->host_lock, flags);
return rport;
}
@@ -1834,6 +2144,7 @@ void
fc_remote_port_delete(struct fc_rport *rport)
{
struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
int timeout = rport->dev_loss_tmo;
unsigned long flags;
@@ -1864,6 +2175,12 @@ fc_remote_port_delete(struct fc_rport *rport)
scsi_target_block(&rport->dev);
+ /* see if we need to kill io faster than waiting for device loss */
+ if ((rport->fast_io_fail_tmo != -1) &&
+ (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io))
+ fc_queue_devloss_work(shost, &rport->fail_io_work,
+ rport->fast_io_fail_tmo * HZ);
+
/* cap the length the devices can be blocked until they are deleted */
fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
}
@@ -1923,6 +2240,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
* machine state change will validate the
* transaction.
*/
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
@@ -1938,6 +2257,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
}
}
EXPORT_SYMBOL(fc_remote_port_rolechg);
@@ -1970,8 +2290,9 @@ fc_timeout_deleted_rport(void *data)
dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: no longer"
" a FCP target, removing starget\n");
- fc_queue_work(shost, &rport->stgt_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+ fc_queue_work(shost, &rport->stgt_delete_work);
return;
}
@@ -2035,17 +2356,37 @@ fc_timeout_deleted_rport(void *data)
* went away and didn't come back - we'll remove
* all attached scsi devices.
*/
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scsi_target_unblock(&rport->dev);
fc_queue_work(shost, &rport->stgt_delete_work);
+}
- spin_unlock_irqrestore(shost->host_lock, flags);
+/**
+ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
+ * disconnected SCSI target.
+ *
+ * @data: 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)
+{
+ struct fc_rport *rport = (struct fc_rport *)data;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+
+ if (rport->port_state != FC_PORTSTATE_BLOCKED)
+ return;
+
+ i->f->terminate_rport_io(rport);
}
/**
* fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
*
- * Will unblock the target (in case it went away and has now come back),
- * then invoke a scan.
- *
* @data: remote port to be scanned.
**/
static void
@@ -2057,7 +2398,6 @@ fc_scsi_scan_rport(void *data)
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
- scsi_target_unblock(&rport->dev);
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 5569fdcfd62..7b0019cccce 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -34,6 +34,7 @@
#define ISCSI_SESSION_ATTRS 11
#define ISCSI_CONN_ATTRS 11
#define ISCSI_HOST_ATTRS 0
+#define ISCSI_TRANSPORT_VERSION "2.0-685"
struct iscsi_internal {
int daemon_pid;
@@ -228,14 +229,11 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
static void iscsi_session_release(struct device *dev)
{
struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
- struct iscsi_transport *transport = session->transport;
struct Scsi_Host *shost;
shost = iscsi_session_to_shost(session);
scsi_host_put(shost);
- kfree(session->targetname);
kfree(session);
- module_put(transport->owner);
}
static int iscsi_is_session_dev(const struct device *dev)
@@ -251,10 +249,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
mutex_lock(&ihost->mutex);
list_for_each_entry(session, &ihost->sessions, host_list) {
- if ((channel == SCAN_WILD_CARD ||
- channel == session->channel) &&
+ if ((channel == SCAN_WILD_CARD || channel == 0) &&
(id == SCAN_WILD_CARD || id == session->target_id))
- scsi_scan_target(&session->dev, session->channel,
+ scsi_scan_target(&session->dev, 0,
session->target_id, lun, 1);
}
mutex_unlock(&ihost->mutex);
@@ -291,80 +288,92 @@ void iscsi_block_session(struct iscsi_cls_session *session)
}
EXPORT_SYMBOL_GPL(iscsi_block_session);
-/**
- * iscsi_create_session - create iscsi class session
- * @shost: scsi host
- * @transport: iscsi transport
- *
- * This can be called from a LLD or iscsi_transport.
- **/
struct iscsi_cls_session *
-iscsi_create_session(struct Scsi_Host *shost,
- struct iscsi_transport *transport, int channel)
+iscsi_alloc_session(struct Scsi_Host *shost,
+ struct iscsi_transport *transport)
{
- struct iscsi_host *ihost;
struct iscsi_cls_session *session;
- int err;
-
- if (!try_module_get(transport->owner))
- return NULL;
session = kzalloc(sizeof(*session) + transport->sessiondata_size,
GFP_KERNEL);
if (!session)
- goto module_put;
+ return NULL;
+
session->transport = transport;
session->recovery_tmo = 120;
INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
INIT_LIST_HEAD(&session->host_list);
INIT_LIST_HEAD(&session->sess_list);
+ /* this is released in the dev's release function */
+ scsi_host_get(shost);
+ session->dev.parent = &shost->shost_gendev;
+ session->dev.release = iscsi_session_release;
+ device_initialize(&session->dev);
if (transport->sessiondata_size)
session->dd_data = &session[1];
+ return session;
+}
+EXPORT_SYMBOL_GPL(iscsi_alloc_session);
- /* this is released in the dev's release function */
- scsi_host_get(shost);
- ihost = shost->shost_data;
+int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
+{
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ struct iscsi_host *ihost;
+ int err;
+ ihost = shost->shost_data;
session->sid = iscsi_session_nr++;
- session->channel = channel;
- session->target_id = ihost->next_target_id++;
+ session->target_id = target_id;
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
session->sid);
- session->dev.parent = &shost->shost_gendev;
- session->dev.release = iscsi_session_release;
- err = device_register(&session->dev);
+ err = device_add(&session->dev);
if (err) {
dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
"register session's dev\n");
- goto free_session;
+ goto release_host;
}
transport_register_device(&session->dev);
mutex_lock(&ihost->mutex);
list_add(&session->host_list, &ihost->sessions);
mutex_unlock(&ihost->mutex);
+ return 0;
- return session;
-
-free_session:
- kfree(session);
-module_put:
- module_put(transport->owner);
- return NULL;
+release_host:
+ scsi_host_put(shost);
+ return err;
}
-
-EXPORT_SYMBOL_GPL(iscsi_create_session);
+EXPORT_SYMBOL_GPL(iscsi_add_session);
/**
- * iscsi_destroy_session - destroy iscsi session
- * @session: iscsi_session
+ * iscsi_create_session - create iscsi class session
+ * @shost: scsi host
+ * @transport: iscsi transport
*
- * Can be called by a LLD or iscsi_transport. There must not be
- * any running connections.
+ * This can be called from a LLD or iscsi_transport.
**/
-int iscsi_destroy_session(struct iscsi_cls_session *session)
+struct iscsi_cls_session *
+iscsi_create_session(struct Scsi_Host *shost,
+ struct iscsi_transport *transport,
+ unsigned int target_id)
+{
+ struct iscsi_cls_session *session;
+
+ session = iscsi_alloc_session(shost, transport);
+ if (!session)
+ return NULL;
+
+ if (iscsi_add_session(session, target_id)) {
+ iscsi_free_session(session);
+ return NULL;
+ }
+ return session;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_session);
+
+void iscsi_remove_session(struct iscsi_cls_session *session)
{
struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_host *ihost = shost->shost_data;
@@ -376,19 +385,88 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
list_del(&session->host_list);
mutex_unlock(&ihost->mutex);
+ scsi_remove_target(&session->dev);
+
transport_unregister_device(&session->dev);
- device_unregister(&session->dev);
- return 0;
+ device_del(&session->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_remove_session);
+
+void iscsi_free_session(struct iscsi_cls_session *session)
+{
+ put_device(&session->dev);
}
+EXPORT_SYMBOL_GPL(iscsi_free_session);
+
+/**
+ * iscsi_destroy_session - destroy iscsi session
+ * @session: iscsi_session
+ *
+ * Can be called by a LLD or iscsi_transport. There must not be
+ * any running connections.
+ **/
+int iscsi_destroy_session(struct iscsi_cls_session *session)
+{
+ iscsi_remove_session(session);
+ iscsi_free_session(session);
+ return 0;
+}
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;
- kfree(conn->persistent_address);
+ mempool_zone_destroy(conn->z_pdu);
+ mempool_zone_destroy(conn->z_error);
+
kfree(conn);
put_device(parent);
}
@@ -398,6 +476,31 @@ 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
@@ -430,9 +533,12 @@ 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;
+ goto free_conn_pools;
snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
session->sid, cid);
@@ -449,6 +555,8 @@ 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;
@@ -496,20 +604,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb)
return (struct list_head *)&skb->cb;
}
-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 void
mempool_zone_complete(struct mempool_zone *zone)
{
@@ -529,37 +623,6 @@ mempool_zone_complete(struct mempool_zone *zone)
spin_unlock_irqrestore(&zone->freelock, flags);
}
-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 mempool_zone_destroy(struct mempool_zone *zp)
-{
- mempool_destroy(zp->pool);
- kfree(zp);
-}
-
static struct sk_buff*
mempool_zone_get_skb(struct mempool_zone *zone)
{
@@ -572,6 +635,27 @@ mempool_zone_get_skb(struct mempool_zone *zone)
}
static int
+iscsi_broadcast_skb(struct mempool_zone *zone, 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)
{
unsigned long flags;
@@ -666,7 +750,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
ev->r.connerror.cid = conn->cid;
ev->r.connerror.sid = iscsi_conn_get_sid(conn);
- iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid);
+ iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC);
dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
error);
@@ -767,6 +851,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
return err;
}
+/**
+ * iscsi_if_destroy_session_done - send session destr. completion event
+ * @conn: last connection for session
+ *
+ * This is called by HW iscsi LLDs to notify userpsace that its HW has
+ * removed a session.
+ **/
+int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_internal *priv;
+ struct iscsi_cls_session *session;
+ struct Scsi_Host *shost;
+ struct iscsi_uevent *ev;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ unsigned long flags;
+ int rc, len = NLMSG_SPACE(sizeof(*ev));
+
+ priv = iscsi_if_transport_lookup(conn->transport);
+ if (!priv)
+ return -EINVAL;
+
+ 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);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+ return -ENOMEM;
+ }
+
+ nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+ ev = NLMSG_DATA(nlh);
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_KEVENT_DESTROY_SESSION;
+ ev->r.d_session.host_no = shost->host_no;
+ ev->r.d_session.sid = session->sid;
+
+ /*
+ * 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);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session destruction event. Check iscsi daemon\n");
+
+ spin_lock_irqsave(&sesslock, flags);
+ list_del(&session->sess_list);
+ spin_unlock_irqrestore(&sesslock, flags);
+
+ spin_lock_irqsave(&connlock, flags);
+ conn->active = 0;
+ list_del(&conn->conn_list);
+ spin_unlock_irqrestore(&connlock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
+
+/**
+ * iscsi_if_create_session_done - send session creation completion event
+ * @conn: leading connection for session
+ *
+ * This is called by HW iscsi LLDs to notify userpsace that its HW has
+ * created a session or a existing session is back in the logged in state.
+ **/
+int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_internal *priv;
+ struct iscsi_cls_session *session;
+ struct Scsi_Host *shost;
+ struct iscsi_uevent *ev;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ unsigned long flags;
+ int rc, len = NLMSG_SPACE(sizeof(*ev));
+
+ priv = iscsi_if_transport_lookup(conn->transport);
+ if (!priv)
+ return -EINVAL;
+
+ 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);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+ return -ENOMEM;
+ }
+
+ nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+ ev = NLMSG_DATA(nlh);
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_UEVENT_CREATE_SESSION;
+ ev->r.c_session_ret.host_no = shost->host_no;
+ ev->r.c_session_ret.sid = session->sid;
+
+ /*
+ * 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);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event. Check iscsi daemon\n");
+
+ spin_lock_irqsave(&sesslock, flags);
+ list_add(&session->sess_list, &sesslist);
+ spin_unlock_irqrestore(&sesslock, flags);
+
+ spin_lock_irqsave(&connlock, flags);
+ list_add(&conn->conn_list, &connlist);
+ conn->active = 1;
+ spin_unlock_irqrestore(&connlock, flags);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
+
static int
iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
{
@@ -812,26 +1021,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
return -ENOMEM;
}
- 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");
- goto destroy_conn;
- }
-
- 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");
- goto free_pdu_pool;
- }
-
ev->r.c_conn_ret.sid = session->sid;
ev->r.c_conn_ret.cid = conn->cid;
@@ -841,13 +1030,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
spin_unlock_irqrestore(&connlock, flags);
return 0;
-
-free_pdu_pool:
- mempool_zone_destroy(conn->z_pdu);
-destroy_conn:
- if (transport->destroy_conn)
- transport->destroy_conn(conn->dd_data);
- return -ENOMEM;
}
static int
@@ -855,7 +1037,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
{
unsigned long flags;
struct iscsi_cls_conn *conn;
- struct mempool_zone *z_error, *z_pdu;
conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
if (!conn)
@@ -865,35 +1046,18 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
list_del(&conn->conn_list);
spin_unlock_irqrestore(&connlock, flags);
- z_pdu = conn->z_pdu;
- z_error = conn->z_error;
-
if (transport->destroy_conn)
transport->destroy_conn(conn);
-
- mempool_zone_destroy(z_pdu);
- mempool_zone_destroy(z_error);
-
return 0;
}
-static void
-iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data)
-{
- if (ev->u.set_param.len != sizeof(uint32_t))
- BUG();
- memcpy(value, data, min_t(uint32_t, sizeof(uint32_t),
- ev->u.set_param.len));
-}
-
static int
iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
char *data = (char*)ev + sizeof(*ev);
struct iscsi_cls_conn *conn;
struct iscsi_cls_session *session;
- int err = 0;
- uint32_t value = 0;
+ int err = 0, value = 0;
session = iscsi_session_lookup(ev->u.set_param.sid);
conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
@@ -902,42 +1066,13 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
switch (ev->u.set_param.param) {
case ISCSI_PARAM_SESS_RECOVERY_TMO:
- iscsi_copy_param(ev, &value, data);
+ sscanf(data, "%d", &value);
if (value != 0)
session->recovery_tmo = value;
break;
- case ISCSI_PARAM_TARGET_NAME:
- /* this should not change between logins */
- if (session->targetname)
- return 0;
-
- session->targetname = kstrdup(data, GFP_KERNEL);
- if (!session->targetname)
- return -ENOMEM;
- break;
- case ISCSI_PARAM_TPGT:
- iscsi_copy_param(ev, &value, data);
- session->tpgt = value;
- break;
- case ISCSI_PARAM_PERSISTENT_PORT:
- iscsi_copy_param(ev, &value, data);
- conn->persistent_port = value;
- break;
- case ISCSI_PARAM_PERSISTENT_ADDRESS:
- /*
- * this is the address returned in discovery so it should
- * not change between logins.
- */
- if (conn->persistent_address)
- return 0;
-
- conn->persistent_address = kstrdup(data, GFP_KERNEL);
- if (!conn->persistent_address)
- return -ENOMEM;
- break;
default:
- iscsi_copy_param(ev, &value, data);
- err = transport->set_param(conn, ev->u.set_param.param, value);
+ err = transport->set_param(conn, ev->u.set_param.param,
+ data, ev->u.set_param.len);
}
return err;
@@ -978,6 +1113,21 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
}
static int
+iscsi_tgt_dscvr(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct sockaddr *dst_addr;
+
+ if (!transport->tgt_dscvr)
+ return -EINVAL;
+
+ dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
+ return transport->tgt_dscvr(ev->u.tgt_dscvr.type,
+ ev->u.tgt_dscvr.host_no,
+ ev->u.tgt_dscvr.enable, dst_addr);
+}
+
+static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
int err = 0;
@@ -1065,6 +1215,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
break;
+ case ISCSI_UEVENT_TGT_DSCVR:
+ err = iscsi_tgt_dscvr(transport, ev);
+ break;
default:
err = -EINVAL;
break;
@@ -1147,49 +1300,31 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name = \
/*
* iSCSI connection attrs
*/
-#define iscsi_conn_int_attr_show(param, format) \
-static ssize_t \
-show_conn_int_param_##param(struct class_device *cdev, char *buf) \
-{ \
- uint32_t value = 0; \
- struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- \
- t->get_conn_param(conn, param, &value); \
- return snprintf(buf, 20, format"\n", value); \
-}
-
-#define iscsi_conn_int_attr(field, param, format) \
- iscsi_conn_int_attr_show(param, format) \
-static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \
- NULL);
-
-iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u");
-iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u");
-iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d");
-iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d");
-iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
-iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
-iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d");
-iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d");
-iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u");
-
-#define iscsi_conn_str_attr_show(param) \
+#define iscsi_conn_attr_show(param) \
static ssize_t \
-show_conn_str_param_##param(struct class_device *cdev, char *buf) \
+show_conn_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
struct iscsi_transport *t = conn->transport; \
- return t->get_conn_str_param(conn, param, buf); \
+ return t->get_conn_param(conn, param, buf); \
}
-#define iscsi_conn_str_attr(field, param) \
- iscsi_conn_str_attr_show(param) \
-static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \
+#define iscsi_conn_attr(field, param) \
+ iscsi_conn_attr_show(param) \
+static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
NULL);
-iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
-iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
+iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
+iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
+iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
+iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
+iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
+iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
+iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
+iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
+iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
+iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
+iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
#define iscsi_cdev_to_session(_cdev) \
iscsi_dev_to_session(_cdev->dev)
@@ -1197,61 +1332,36 @@ iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
/*
* iSCSI session attrs
*/
-#define iscsi_session_int_attr_show(param, format) \
-static ssize_t \
-show_session_int_param_##param(struct class_device *cdev, char *buf) \
-{ \
- uint32_t value = 0; \
- struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- t->get_session_param(session, param, &value); \
- return snprintf(buf, 20, format"\n", value); \
-}
-
-#define iscsi_session_int_attr(field, param, format) \
- iscsi_session_int_attr_show(param, format) \
-static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \
- NULL);
-
-iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d");
-iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu");
-iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d");
-iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u");
-iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u");
-iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d");
-iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d");
-iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d");
-iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d");
-
-#define iscsi_session_str_attr_show(param) \
+#define iscsi_session_attr_show(param) \
static ssize_t \
-show_session_str_param_##param(struct class_device *cdev, char *buf) \
+show_session_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
struct iscsi_transport *t = session->transport; \
- return t->get_session_str_param(session, param, buf); \
+ return t->get_session_param(session, param, buf); \
}
-#define iscsi_session_str_attr(field, param) \
- iscsi_session_str_attr_show(param) \
-static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \
+#define iscsi_session_attr(field, param) \
+ iscsi_session_attr_show(param) \
+static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
NULL);
-iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME);
+iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME);
+iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN);
+iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T);
+iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN);
+iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST);
+iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST);
+iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN);
+iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN);
+iscsi_session_attr(erl, ISCSI_PARAM_ERL);
+iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT);
-/*
- * Private session and conn attrs. userspace uses several iscsi values
- * to identify each session between reboots. Some of these values may not
- * be present in the iscsi_transport/LLD driver becuase userspace handles
- * login (and failback for login redirect) so for these type of drivers
- * the class manages the attrs and values for the iscsi_transport/LLD
- */
#define iscsi_priv_session_attr_show(field, format) \
static ssize_t \
-show_priv_session_##field(struct class_device *cdev, char *buf) \
+show_priv_session_##field(struct class_device *cdev, char *buf) \
{ \
- struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
return sprintf(buf, format"\n", session->field); \
}
@@ -1259,31 +1369,15 @@ show_priv_session_##field(struct class_device *cdev, char *buf) \
iscsi_priv_session_attr_show(field, format) \
static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
NULL)
-iscsi_priv_session_attr(targetname, "%s");
-iscsi_priv_session_attr(tpgt, "%d");
iscsi_priv_session_attr(recovery_tmo, "%d");
-#define iscsi_priv_conn_attr_show(field, format) \
-static ssize_t \
-show_priv_conn_##field(struct class_device *cdev, char *buf) \
-{ \
- struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- return sprintf(buf, format"\n", conn->field); \
-}
-
-#define iscsi_priv_conn_attr(field, format) \
- iscsi_priv_conn_attr_show(field, format) \
-static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \
- NULL)
-iscsi_priv_conn_attr(persistent_address, "%s");
-iscsi_priv_conn_attr(persistent_port, "%d");
-
#define SETUP_PRIV_SESSION_RD_ATTR(field) \
do { \
priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
count++; \
} while (0)
+
#define SETUP_SESSION_RD_ATTR(field, param_flag) \
do { \
if (tt->param_mask & param_flag) { \
@@ -1292,12 +1386,6 @@ do { \
} \
} while (0)
-#define SETUP_PRIV_CONN_RD_ATTR(field) \
-do { \
- priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \
- count++; \
-} while (0)
-
#define SETUP_CONN_RD_ATTR(field, param_flag) \
do { \
if (tt->param_mask & param_flag) { \
@@ -1388,6 +1476,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
if (!priv)
return NULL;
INIT_LIST_HEAD(&priv->list);
+ priv->daemon_pid = -1;
priv->iscsi_transport = tt;
priv->t.user_scan = iscsi_user_scan;
@@ -1424,16 +1513,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
-
- if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS)
- SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
- else
- SETUP_PRIV_CONN_RD_ATTR(persistent_address);
-
- if (tt->param_mask & ISCSI_PERSISTENT_PORT)
- SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
- else
- SETUP_PRIV_CONN_RD_ATTR(persistent_port);
+ SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
+ SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
BUG_ON(count > ISCSI_CONN_ATTRS);
priv->conn_attrs[count] = NULL;
@@ -1453,18 +1534,10 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
+ SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
+ SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
- if (tt->param_mask & ISCSI_TARGET_NAME)
- SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
- else
- SETUP_PRIV_SESSION_RD_ATTR(targetname);
-
- if (tt->param_mask & ISCSI_TPGT)
- SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
- else
- SETUP_PRIV_SESSION_RD_ATTR(tpgt);
-
BUG_ON(count > ISCSI_SESSION_ATTRS);
priv->session_attrs[count] = NULL;
@@ -1541,6 +1614,9 @@ static __init int iscsi_transport_init(void)
{
int err;
+ printk(KERN_INFO "Loading iSCSI transport class v%s.",
+ ISCSI_TRANSPORT_VERSION);
+
err = class_register(&iscsi_transport_class);
if (err)
return err;
@@ -1606,3 +1682,4 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI Transport Interface");
MODULE_LICENSE("GPL");
+MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 1fe6b2d0185..b5b0c2cba96 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -41,6 +41,7 @@ struct sas_host_attrs {
struct mutex lock;
u32 next_target_id;
u32 next_expander_id;
+ int next_port_id;
};
#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
@@ -76,6 +77,24 @@ get_sas_##title##_names(u32 table_key, char *buf) \
return len; \
}
+#define sas_bitfield_name_set(title, table) \
+static ssize_t \
+set_sas_##title##_names(u32 *table_key, const char *buf) \
+{ \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(table); i++) { \
+ len = strlen(table[i].name); \
+ if (strncmp(buf, table[i].name, len) == 0 && \
+ (buf[len] == '\n' || buf[len] == '\0')) { \
+ *table_key = table[i].value; \
+ return 0; \
+ } \
+ } \
+ return -EINVAL; \
+}
+
#define sas_bitfield_name_search(title, table) \
static ssize_t \
get_sas_##title##_names(u32 table_key, char *buf) \
@@ -130,7 +149,7 @@ static struct {
{ SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
};
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
-
+sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
/*
* SAS host attributes
@@ -146,6 +165,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
mutex_init(&sas_host->lock);
sas_host->next_target_id = 0;
sas_host->next_expander_id = 0;
+ sas_host->next_port_id = 0;
return 0;
}
@@ -174,12 +194,29 @@ static int sas_host_match(struct attribute_container *cont,
static int do_sas_phy_delete(struct device *dev, void *data)
{
- if (scsi_is_sas_phy(dev))
+ int pass = (int)(unsigned long)data;
+
+ if (pass == 0 && scsi_is_sas_port(dev))
+ sas_port_delete(dev_to_sas_port(dev));
+ else if (pass == 1 && scsi_is_sas_phy(dev))
sas_phy_delete(dev_to_phy(dev));
return 0;
}
/**
+ * sas_remove_children -- tear down a devices SAS data structures
+ * @dev: device belonging to the sas object
+ *
+ * Removes all SAS PHYs and remote PHYs for a given object
+ */
+void sas_remove_children(struct device *dev)
+{
+ device_for_each_child(dev, (void *)0, do_sas_phy_delete);
+ device_for_each_child(dev, (void *)1, do_sas_phy_delete);
+}
+EXPORT_SYMBOL(sas_remove_children);
+
+/**
* sas_remove_host -- tear down a Scsi_Host's SAS data structures
* @shost: Scsi Host that is torn down
*
@@ -188,13 +225,13 @@ static int do_sas_phy_delete(struct device *dev, void *data)
*/
void sas_remove_host(struct Scsi_Host *shost)
{
- device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
+ sas_remove_children(&shost->shost_gendev);
}
EXPORT_SYMBOL(sas_remove_host);
/*
- * SAS Port attributes
+ * SAS Phy attributes
*/
#define sas_phy_show_simple(field, name, format_string, cast) \
@@ -234,10 +271,39 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \
return get_sas_linkspeed_names(phy->field, buf); \
}
+/* Fudge to tell if we're minimum or maximum */
+#define sas_phy_store_linkspeed(field) \
+static ssize_t \
+store_sas_phy_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct sas_phy *phy = transport_class_to_phy(cdev); \
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
+ struct sas_internal *i = to_sas_internal(shost->transportt); \
+ u32 value; \
+ struct sas_phy_linkrates rates = {0}; \
+ int error; \
+ \
+ error = set_sas_linkspeed_names(&value, buf); \
+ if (error) \
+ return error; \
+ rates.field = value; \
+ error = i->f->set_phy_speed(phy, &rates); \
+ \
+ return error ? error : count; \
+}
+
+#define sas_phy_linkspeed_rw_attr(field) \
+ sas_phy_show_linkspeed(field) \
+ sas_phy_store_linkspeed(field) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \
+ store_sas_phy_##field)
+
#define sas_phy_linkspeed_attr(field) \
sas_phy_show_linkspeed(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
+
#define sas_phy_show_linkerror(field) \
static ssize_t \
show_sas_phy_##field(struct class_device *cdev, char *buf) \
@@ -247,9 +313,6 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \
struct sas_internal *i = to_sas_internal(shost->transportt); \
int error; \
\
- if (!phy->local_attached) \
- return -EINVAL; \
- \
error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
if (error) \
return error; \
@@ -280,9 +343,6 @@ static ssize_t do_sas_phy_reset(struct class_device *cdev,
struct sas_internal *i = to_sas_internal(shost->transportt);
int error;
- if (!phy->local_attached)
- return -EINVAL;
-
error = i->f->phy_reset(phy, hard_reset);
if (error)
return error;
@@ -310,12 +370,12 @@ sas_phy_protocol_attr(identify.target_port_protocols,
sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
unsigned long long);
sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
-sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
+//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
sas_phy_linkspeed_attr(negotiated_linkrate);
sas_phy_linkspeed_attr(minimum_linkrate_hw);
-sas_phy_linkspeed_attr(minimum_linkrate);
+sas_phy_linkspeed_rw_attr(minimum_linkrate);
sas_phy_linkspeed_attr(maximum_linkrate_hw);
-sas_phy_linkspeed_attr(maximum_linkrate);
+sas_phy_linkspeed_rw_attr(maximum_linkrate);
sas_phy_linkerror_attr(invalid_dword_count);
sas_phy_linkerror_attr(running_disparity_error_count);
sas_phy_linkerror_attr(loss_of_dword_sync_count);
@@ -378,9 +438,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
device_initialize(&phy->dev);
phy->dev.parent = get_device(parent);
phy->dev.release = sas_phy_release;
+ INIT_LIST_HEAD(&phy->port_siblings);
if (scsi_is_sas_expander_device(parent)) {
struct sas_rphy *rphy = dev_to_rphy(parent);
- sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no,
+ sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no,
rphy->scsi_target_id, number);
} else
sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
@@ -440,8 +501,8 @@ sas_phy_delete(struct sas_phy *phy)
{
struct device *dev = &phy->dev;
- if (phy->rphy)
- sas_rphy_delete(phy->rphy);
+ /* this happens if the phy is still part of a port when deleted */
+ BUG_ON(!list_empty(&phy->port_siblings));
transport_remove_device(dev);
device_del(dev);
@@ -464,6 +525,310 @@ int scsi_is_sas_phy(const struct device *dev)
EXPORT_SYMBOL(scsi_is_sas_phy);
/*
+ * SAS Port attributes
+ */
+#define sas_port_show_simple(field, name, format_string, cast) \
+static ssize_t \
+show_sas_port_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_port *port = transport_class_to_sas_port(cdev); \
+ \
+ return snprintf(buf, 20, format_string, cast port->field); \
+}
+
+#define sas_port_simple_attr(field, name, format_string, type) \
+ sas_port_show_simple(field, name, format_string, (type)) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
+
+sas_port_simple_attr(num_phys, num_phys, "%d\n", int);
+
+static DECLARE_TRANSPORT_CLASS(sas_port_class,
+ "sas_port", NULL, NULL, NULL);
+
+static int sas_port_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_port(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->port_attr_cont.ac == cont;
+}
+
+
+static void sas_port_release(struct device *dev)
+{
+ struct sas_port *port = dev_to_sas_port(dev);
+
+ BUG_ON(!list_empty(&port->phy_list));
+
+ put_device(dev->parent);
+ kfree(port);
+}
+
+static void sas_port_create_link(struct sas_port *port,
+ struct sas_phy *phy)
+{
+ sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id);
+ sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
+}
+
+static void sas_port_delete_link(struct sas_port *port,
+ struct sas_phy *phy)
+{
+ sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id);
+ sysfs_remove_link(&phy->dev.kobj, "port");
+}
+
+/** sas_port_alloc - allocate and initialize a SAS port structure
+ *
+ * @parent: parent device
+ * @port_id: port number
+ *
+ * Allocates a SAS port structure. It will be added to the device tree
+ * below the device specified by @parent which must be either a Scsi_Host
+ * or a sas_expander_device.
+ *
+ * Returns %NULL on error
+ */
+struct sas_port *sas_port_alloc(struct device *parent, int port_id)
+{
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_port *port;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return NULL;
+
+ port->port_identifier = port_id;
+
+ device_initialize(&port->dev);
+
+ port->dev.parent = get_device(parent);
+ port->dev.release = sas_port_release;
+
+ mutex_init(&port->phy_list_mutex);
+ INIT_LIST_HEAD(&port->phy_list);
+
+ if (scsi_is_sas_expander_device(parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent);
+ sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no,
+ rphy->scsi_target_id, port->port_identifier);
+ } else
+ sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no,
+ port->port_identifier);
+
+ transport_setup_device(&port->dev);
+
+ return port;
+}
+EXPORT_SYMBOL(sas_port_alloc);
+
+/** sas_port_alloc_num - allocate and initialize a SAS port structure
+ *
+ * @parent: parent device
+ *
+ * Allocates a SAS port structure and a number to go with it. This
+ * interface is really for adapters where the port number has no
+ * meansing, so the sas class should manage them. It will be added to
+ * the device tree below the device specified by @parent which must be
+ * either a Scsi_Host or a sas_expander_device.
+ *
+ * Returns %NULL on error
+ */
+struct sas_port *sas_port_alloc_num(struct device *parent)
+{
+ int index;
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ /* FIXME: use idr for this eventually */
+ mutex_lock(&sas_host->lock);
+ if (scsi_is_sas_expander_device(parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent);
+ struct sas_expander_device *exp = rphy_to_expander_device(rphy);
+
+ index = exp->next_port_id++;
+ } else
+ index = sas_host->next_port_id++;
+ mutex_unlock(&sas_host->lock);
+ return sas_port_alloc(parent, index);
+}
+EXPORT_SYMBOL(sas_port_alloc_num);
+
+/**
+ * sas_port_add - add a SAS port to the device hierarchy
+ *
+ * @port: port to be added
+ *
+ * publishes a port to the rest of the system
+ */
+int sas_port_add(struct sas_port *port)
+{
+ int error;
+
+ /* No phys should be added until this is made visible */
+ BUG_ON(!list_empty(&port->phy_list));
+
+ error = device_add(&port->dev);
+
+ if (error)
+ return error;
+
+ transport_add_device(&port->dev);
+ transport_configure_device(&port->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(sas_port_add);
+
+/**
+ * sas_port_free -- free a SAS PORT
+ * @port: SAS PORT to free
+ *
+ * Frees the specified SAS PORT.
+ *
+ * Note:
+ * This function must only be called on a PORT that has not
+ * sucessfully been added using sas_port_add().
+ */
+void sas_port_free(struct sas_port *port)
+{
+ transport_destroy_device(&port->dev);
+ put_device(&port->dev);
+}
+EXPORT_SYMBOL(sas_port_free);
+
+/**
+ * sas_port_delete -- remove SAS PORT
+ * @port: SAS PORT to remove
+ *
+ * Removes the specified SAS PORT. If the SAS PORT has an
+ * associated phys, unlink them from the port as well.
+ */
+void sas_port_delete(struct sas_port *port)
+{
+ struct device *dev = &port->dev;
+ struct sas_phy *phy, *tmp_phy;
+
+ if (port->rphy) {
+ sas_rphy_delete(port->rphy);
+ port->rphy = NULL;
+ }
+
+ mutex_lock(&port->phy_list_mutex);
+ list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
+ port_siblings) {
+ sas_port_delete_link(port, phy);
+ list_del_init(&phy->port_siblings);
+ }
+ mutex_unlock(&port->phy_list_mutex);
+
+ if (port->is_backlink) {
+ struct device *parent = port->dev.parent;
+
+ sysfs_remove_link(&port->dev.kobj, parent->bus_id);
+ port->is_backlink = 0;
+ }
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+EXPORT_SYMBOL(sas_port_delete);
+
+/**
+ * scsi_is_sas_port -- check if a struct device represents a SAS port
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS Port, %0 else
+ */
+int scsi_is_sas_port(const struct device *dev)
+{
+ return dev->release == sas_port_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_port);
+
+/**
+ * sas_port_add_phy - add another phy to a port to form a wide port
+ * @port: port to add the phy to
+ * @phy: phy to add
+ *
+ * When a port is initially created, it is empty (has no phys). All
+ * ports must have at least one phy to operated, and all wide ports
+ * must have at least two. The current code makes no difference
+ * between ports and wide ports, but the only object that can be
+ * connected to a remote device is a port, so ports must be formed on
+ * all devices with phys if they're connected to anything.
+ */
+void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
+{
+ mutex_lock(&port->phy_list_mutex);
+ if (unlikely(!list_empty(&phy->port_siblings))) {
+ /* make sure we're already on this port */
+ struct sas_phy *tmp;
+
+ list_for_each_entry(tmp, &port->phy_list, port_siblings)
+ if (tmp == phy)
+ break;
+ /* If this trips, you added a phy that was already
+ * part of a different port */
+ if (unlikely(tmp != phy)) {
+ dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id);
+ BUG();
+ }
+ } else {
+ sas_port_create_link(port, phy);
+ list_add_tail(&phy->port_siblings, &port->phy_list);
+ port->num_phys++;
+ }
+ mutex_unlock(&port->phy_list_mutex);
+}
+EXPORT_SYMBOL(sas_port_add_phy);
+
+/**
+ * sas_port_delete_phy - remove a phy from a port or wide port
+ * @port: port to remove the phy from
+ * @phy: phy to remove
+ *
+ * This operation is used for tearing down ports again. It must be
+ * done to every port or wide port before calling sas_port_delete.
+ */
+void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
+{
+ mutex_lock(&port->phy_list_mutex);
+ sas_port_delete_link(port, phy);
+ list_del_init(&phy->port_siblings);
+ port->num_phys--;
+ mutex_unlock(&port->phy_list_mutex);
+}
+EXPORT_SYMBOL(sas_port_delete_phy);
+
+void sas_port_mark_backlink(struct sas_port *port)
+{
+ struct device *parent = port->dev.parent->parent->parent;
+
+ if (port->is_backlink)
+ return;
+ port->is_backlink = 1;
+ sysfs_create_link(&port->dev.kobj, &parent->kobj,
+ parent->bus_id);
+
+}
+EXPORT_SYMBOL(sas_port_mark_backlink);
+
+/*
* SAS remote PHY attributes.
*/
@@ -525,7 +890,7 @@ show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf)
* Only devices behind an expander are supported, because the
* enclosure identifier is a SMP feature.
*/
- if (phy->local_attached)
+ if (scsi_is_sas_phy_local(phy))
return -EINVAL;
error = i->f->get_enclosure_identifier(rphy, &identifier);
@@ -546,7 +911,7 @@ show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf)
struct sas_internal *i = to_sas_internal(shost->transportt);
int val;
- if (phy->local_attached)
+ if (scsi_is_sas_phy_local(phy))
return -EINVAL;
val = i->f->get_bay_identifier(rphy);
@@ -767,7 +1132,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
* Returns:
* SAS PHY allocated or %NULL if the allocation failed.
*/
-struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
+struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
{
struct Scsi_Host *shost = dev_to_shost(&parent->dev);
struct sas_end_device *rdev;
@@ -780,8 +1145,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
device_initialize(&rdev->rphy.dev);
rdev->rphy.dev.parent = get_device(&parent->dev);
rdev->rphy.dev.release = sas_end_device_release;
- sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d",
- shost->host_no, parent->port_identifier, parent->number);
+ if (scsi_is_sas_expander_device(parent->dev.parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
+ sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d",
+ shost->host_no, rphy->scsi_target_id, parent->port_identifier);
+ } else
+ sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d",
+ shost->host_no, parent->port_identifier);
rdev->rphy.identify.device_type = SAS_END_DEVICE;
sas_rphy_initialize(&rdev->rphy);
transport_setup_device(&rdev->rphy.dev);
@@ -798,7 +1168,7 @@ EXPORT_SYMBOL(sas_end_device_alloc);
* Returns:
* SAS PHY allocated or %NULL if the allocation failed.
*/
-struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
+struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
enum sas_device_type type)
{
struct Scsi_Host *shost = dev_to_shost(&parent->dev);
@@ -837,7 +1207,7 @@ EXPORT_SYMBOL(sas_expander_alloc);
*/
int sas_rphy_add(struct sas_rphy *rphy)
{
- struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+ struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
struct sas_identify *identify = &rphy->identify;
@@ -865,7 +1235,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
if (identify->device_type == SAS_END_DEVICE &&
rphy->scsi_target_id != -1) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, ~0, 0);
}
@@ -910,7 +1280,7 @@ void
sas_rphy_delete(struct sas_rphy *rphy)
{
struct device *dev = &rphy->dev;
- struct sas_phy *parent = dev_to_phy(dev->parent);
+ struct sas_port *parent = dev_to_sas_port(dev->parent);
struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
@@ -920,7 +1290,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
break;
case SAS_EDGE_EXPANDER_DEVICE:
case SAS_FANOUT_EXPANDER_DEVICE:
- device_for_each_child(dev, NULL, do_sas_phy_delete);
+ sas_remove_children(dev);
break;
default:
break;
@@ -967,15 +1337,13 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
mutex_lock(&sas_host->lock);
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
- struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
-
if (rphy->identify.device_type != SAS_END_DEVICE ||
rphy->scsi_target_id == -1)
continue;
- if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
+ if ((channel == SCAN_WILD_CARD || channel == 0) &&
(id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, lun, 1);
}
}
@@ -989,13 +1357,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
* Setup / Teardown code
*/
-#define SETUP_TEMPLATE(attrb, field, perm, test) \
+#define SETUP_TEMPLATE(attrb, field, perm, test) \
i->private_##attrb[count] = class_device_attr_##field; \
i->private_##attrb[count].attr.mode = perm; \
i->attrb[count] = &i->private_##attrb[count]; \
if (test) \
count++
+#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \
+ i->private_##attrb[count] = class_device_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ if (ro_test) { \
+ i->private_##attrb[count].attr.mode = ro_perm; \
+ i->private_##attrb[count].store = NULL; \
+ } \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
#define SETUP_RPORT_ATTRIBUTE(field) \
SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
@@ -1003,16 +1381,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
-#define SETUP_PORT_ATTRIBUTE(field) \
+#define SETUP_PHY_ATTRIBUTE(field) \
SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
-#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \
+#define SETUP_PHY_ATTRIBUTE_RW(field) \
+ SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
+ !i->f->set_phy_speed, S_IRUGO)
+
+#define SETUP_PORT_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \
SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
-#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \
+#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
-#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \
+#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
#define SETUP_END_DEV_ATTRIBUTE(field) \
@@ -1048,6 +1433,11 @@ sas_attach_transport(struct sas_function_template *ft)
i->phy_attr_cont.ac.match = sas_phy_match;
transport_container_register(&i->phy_attr_cont);
+ i->port_attr_cont.ac.class = &sas_port_class.class;
+ i->port_attr_cont.ac.attrs = &i->port_attrs[0];
+ i->port_attr_cont.ac.match = sas_port_match;
+ transport_container_register(&i->port_attr_cont);
+
i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
i->rphy_attr_cont.ac.match = sas_rphy_match;
@@ -1066,30 +1456,35 @@ sas_attach_transport(struct sas_function_template *ft)
i->f = ft;
count = 0;
+ SETUP_PORT_ATTRIBUTE(num_phys);
i->host_attrs[count] = NULL;
count = 0;
- SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
- SETUP_PORT_ATTRIBUTE(target_port_protocols);
- SETUP_PORT_ATTRIBUTE(device_type);
- SETUP_PORT_ATTRIBUTE(sas_address);
- SETUP_PORT_ATTRIBUTE(phy_identifier);
- SETUP_PORT_ATTRIBUTE(port_identifier);
- SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
- SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
- SETUP_PORT_ATTRIBUTE(minimum_linkrate);
- SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
- SETUP_PORT_ATTRIBUTE(maximum_linkrate);
-
- SETUP_PORT_ATTRIBUTE(invalid_dword_count);
- SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
- SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
- SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
- SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset);
- SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
+ SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
+ SETUP_PHY_ATTRIBUTE(target_port_protocols);
+ SETUP_PHY_ATTRIBUTE(device_type);
+ SETUP_PHY_ATTRIBUTE(sas_address);
+ SETUP_PHY_ATTRIBUTE(phy_identifier);
+ //SETUP_PHY_ATTRIBUTE(port_identifier);
+ SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
+ SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
+ SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
+ SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
+ SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
+
+ SETUP_PHY_ATTRIBUTE(invalid_dword_count);
+ SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
+ SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
+ SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
+ SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
+ SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
i->phy_attrs[count] = NULL;
count = 0;
+ SETUP_PORT_ATTRIBUTE(num_phys);
+ i->port_attrs[count] = NULL;
+
+ count = 0;
SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
SETUP_RPORT_ATTRIBUTE(rphy_device_type);
@@ -1131,6 +1526,7 @@ void sas_release_transport(struct scsi_transport_template *t)
transport_container_unregister(&i->t.host_attrs);
transport_container_unregister(&i->phy_attr_cont);
+ transport_container_unregister(&i->port_attr_cont);
transport_container_unregister(&i->rphy_attr_cont);
transport_container_unregister(&i->end_dev_attr_cont);
transport_container_unregister(&i->expander_attr_cont);
@@ -1149,9 +1545,12 @@ static __init int sas_transport_init(void)
error = transport_class_register(&sas_phy_class);
if (error)
goto out_unregister_transport;
- error = transport_class_register(&sas_rphy_class);
+ error = transport_class_register(&sas_port_class);
if (error)
goto out_unregister_phy;
+ error = transport_class_register(&sas_rphy_class);
+ if (error)
+ goto out_unregister_port;
error = transport_class_register(&sas_end_dev_class);
if (error)
goto out_unregister_rphy;
@@ -1165,6 +1564,8 @@ static __init int sas_transport_init(void)
transport_class_unregister(&sas_end_dev_class);
out_unregister_rphy:
transport_class_unregister(&sas_rphy_class);
+ out_unregister_port:
+ transport_class_unregister(&sas_port_class);
out_unregister_phy:
transport_class_unregister(&sas_phy_class);
out_unregister_transport:
@@ -1178,6 +1579,7 @@ static void __exit sas_transport_exit(void)
{
transport_class_unregister(&sas_host_class);
transport_class_unregister(&sas_phy_class);
+ transport_class_unregister(&sas_port_class);
transport_class_unregister(&sas_rphy_class);
transport_class_unregister(&sas_end_dev_class);
transport_class_unregister(&sas_expander_class);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index ace49d5bd9c..9f070f0d0f2 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -18,7 +18,6 @@
* 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/config.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -48,6 +47,7 @@
/* Private data accessors (keep these out of the header file) */
#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
struct spi_internal {
@@ -241,6 +241,7 @@ static int spi_setup_transport_attrs(struct transport_container *tc,
spi_pcomp_en(starget) = 0;
spi_hold_mcs(starget) = 0;
spi_dv_pending(starget) = 0;
+ spi_dv_in_progress(starget) = 0;
spi_initial_dv(starget) = 0;
mutex_init(&spi_dv_mutex(starget));
@@ -831,28 +832,37 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
DV_SET(period, spi_min_period(starget));
/* try QAS requests; this should be harmless to set if the
* target supports it */
- if (scsi_device_qas(sdev))
+ if (scsi_device_qas(sdev)) {
DV_SET(qas, 1);
- /* Also try IU transfers */
- if (scsi_device_ius(sdev))
+ } else {
+ DV_SET(qas, 0);
+ }
+
+ if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+ /* This u320 (or u640). Set IU transfers */
DV_SET(iu, 1);
- if (spi_min_period(starget) < 9) {
- /* This u320 (or u640). Ignore the coupled parameters
- * like DT and IU, but set the optional ones */
+ /* Then set the optional parameters */
DV_SET(rd_strm, 1);
DV_SET(wr_flow, 1);
DV_SET(rti, 1);
if (spi_min_period(starget) == 8)
DV_SET(pcomp_en, 1);
+ } else {
+ DV_SET(iu, 0);
}
+
/* now that we've done all this, actually check the bus
* signal type (if known). Some devices are stupid on
* a SE bus and still claim they can try LVD only settings */
if (i->f->get_signalling)
i->f->get_signalling(shost);
if (spi_signalling(shost) == SPI_SIGNAL_SE ||
- spi_signalling(shost) == SPI_SIGNAL_HVD)
+ spi_signalling(shost) == SPI_SIGNAL_HVD ||
+ !scsi_device_dt(sdev)) {
DV_SET(dt, 0);
+ } else {
+ DV_SET(dt, 1);
+ }
/* Do the read only INQUIRY tests */
spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
spi_dv_device_compare_inquiry);
@@ -908,6 +918,10 @@ spi_dv_device(struct scsi_device *sdev)
if (unlikely(scsi_device_get(sdev)))
return;
+ if (unlikely(spi_dv_in_progress(starget)))
+ return;
+ spi_dv_in_progress(starget) = 1;
+
buffer = kzalloc(len, GFP_KERNEL);
if (unlikely(!buffer))
@@ -939,6 +953,7 @@ spi_dv_device(struct scsi_device *sdev)
out_free:
kfree(buffer);
out_put:
+ spi_dv_in_progress(starget) = 0;
scsi_device_put(sdev);
}
EXPORT_SYMBOL(spi_dv_device);
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index b78354fc4b1..cd68a66c7bb 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -57,6 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable);
int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
{
unsigned char *p;
+ u64 capacity64 = capacity; /* Suppress gcc warning */
int ret;
p = scsi_bios_ptable(bdev);
@@ -68,7 +69,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
(unsigned int *)ip + 0, (unsigned int *)ip + 1);
kfree(p);
- if (ret == -1) {
+ if (ret == -1 && capacity64 < (1ULL << 32)) {
/* pick some standard mapping with at most 1024 cylinders,
and at most 62 sectors per track - this works up to
7905 MB */
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 35419901124..638cff41d43 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -32,7 +32,6 @@
* than the level indicated above to trigger output.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -208,6 +207,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
return count;
}
+static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (sdp->type != TYPE_DISK)
+ return -EINVAL;
+
+ sdp->allow_restart = simple_strtoul(buf, NULL, 10);
+
+ return count;
+}
+
static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -223,10 +239,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
+static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+
+ return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
+}
+
static struct class_device_attribute sd_disk_attrs[] = {
__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
sd_store_cache_type),
__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
+ __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
+ sd_store_allow_restart),
__ATTR_NULL,
};
@@ -477,8 +502,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[4] = (unsigned char) this_count;
SCpnt->cmnd[5] = 0;
}
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * sdp->sector_size;
+ SCpnt->request_bufflen = this_count * sdp->sector_size;
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -891,11 +915,10 @@ static struct block_device_operations sd_fops = {
static void sd_rw_intr(struct scsi_cmnd * SCpnt)
{
int result = SCpnt->result;
- int this_count = SCpnt->request_bufflen;
- int good_bytes = (result == 0 ? this_count : 0);
- sector_t block_sectors = 1;
- u64 first_err_block;
- sector_t error_sector;
+ unsigned int xfer_size = SCpnt->request_bufflen;
+ unsigned int good_bytes = result ? 0 : xfer_size;
+ u64 start_lba = SCpnt->request->sector;
+ u64 bad_lba;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
@@ -906,7 +929,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
-
#ifdef CONFIG_SCSI_LOGGING
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->request->rq_disk->disk_name, result));
@@ -916,89 +938,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
sshdr.sense_key, sshdr.asc, sshdr.ascq));
}
#endif
- /*
- Handle MEDIUM ERRORs that indicate partial success. Since this is a
- relatively rare error condition, no care is taken to avoid
- unnecessary additional work such as memcpy's that could be avoided.
- */
- if (driver_byte(result) != 0 &&
- sense_valid && !sense_deferred) {
- switch (sshdr.sense_key) {
- case MEDIUM_ERROR:
- if (!blk_fs_request(SCpnt->request))
- break;
- info_valid = scsi_get_sense_info_fld(
- SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
- &first_err_block);
- /*
- * May want to warn and skip if following cast results
- * in actual truncation (if sector_t < 64 bits)
- */
- error_sector = (sector_t)first_err_block;
- if (SCpnt->request->bio != NULL)
- block_sectors = bio_sectors(SCpnt->request->bio);
- switch (SCpnt->device->sector_size) {
- case 1024:
- error_sector <<= 1;
- if (block_sectors < 2)
- block_sectors = 2;
- break;
- case 2048:
- error_sector <<= 2;
- if (block_sectors < 4)
- block_sectors = 4;
- break;
- case 4096:
- error_sector <<=3;
- if (block_sectors < 8)
- block_sectors = 8;
- break;
- case 256:
- error_sector >>= 1;
- break;
- default:
- break;
- }
+ if (driver_byte(result) != DRIVER_SENSE &&
+ (!sense_valid || sense_deferred))
+ goto out;
- error_sector &= ~(block_sectors - 1);
- good_bytes = (error_sector - SCpnt->request->sector) << 9;
- if (good_bytes < 0 || good_bytes >= this_count)
- good_bytes = 0;
+ switch (sshdr.sense_key) {
+ case HARDWARE_ERROR:
+ case MEDIUM_ERROR:
+ if (!blk_fs_request(SCpnt->request))
+ goto out;
+ info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ &bad_lba);
+ if (!info_valid)
+ goto out;
+ if (xfer_size <= SCpnt->device->sector_size)
+ goto out;
+ switch (SCpnt->device->sector_size) {
+ case 256:
+ start_lba <<= 1;
break;
-
- case RECOVERED_ERROR: /* an error occurred, but it recovered */
- case NO_SENSE: /* LLDD got sense data */
- /*
- * Inform the user, but make sure that it's not treated
- * as a hard error.
- */
- scsi_print_sense("sd", SCpnt);
- SCpnt->result = 0;
- memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- good_bytes = this_count;
+ case 512:
break;
-
- case ILLEGAL_REQUEST:
- if (SCpnt->device->use_10_for_rw &&
- (SCpnt->cmnd[0] == READ_10 ||
- SCpnt->cmnd[0] == WRITE_10))
- SCpnt->device->use_10_for_rw = 0;
- if (SCpnt->device->use_10_for_ms &&
- (SCpnt->cmnd[0] == MODE_SENSE_10 ||
- SCpnt->cmnd[0] == MODE_SELECT_10))
- SCpnt->device->use_10_for_ms = 0;
+ case 1024:
+ start_lba >>= 1;
+ break;
+ case 2048:
+ start_lba >>= 2;
+ break;
+ case 4096:
+ start_lba >>= 3;
break;
-
default:
+ /* Print something here with limiting frequency. */
+ goto out;
break;
}
+ /* This computation should always be done in terms of
+ * the resolution of the device's medium.
+ */
+ good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size;
+ break;
+ case RECOVERED_ERROR:
+ case NO_SENSE:
+ /* Inform the user, but make sure that it's not treated
+ * as a hard error.
+ */
+ scsi_print_sense("sd", SCpnt);
+ SCpnt->result = 0;
+ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ good_bytes = xfer_size;
+ break;
+ case ILLEGAL_REQUEST:
+ if (SCpnt->device->use_10_for_rw &&
+ (SCpnt->cmnd[0] == READ_10 ||
+ SCpnt->cmnd[0] == WRITE_10))
+ SCpnt->device->use_10_for_rw = 0;
+ if (SCpnt->device->use_10_for_ms &&
+ (SCpnt->cmnd[0] == MODE_SENSE_10 ||
+ SCpnt->cmnd[0] == MODE_SELECT_10))
+ SCpnt->device->use_10_for_ms = 0;
+ break;
+ default:
+ break;
}
- /*
- * This calls the generic completion function, now that we know
- * how many actual sectors finished, and how many sectors we need
- * to say have failed.
- */
- scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+ out:
+ scsi_io_completion(SCpnt, good_bytes);
}
static int media_not_present(struct scsi_disk *sdkp,
@@ -1210,7 +1215,7 @@ repeat:
/* Either no media are present but the drive didn't tell us,
or they are present but the read capacity command fails */
/* sdkp->media_present = 0; -- not always correct */
- sdkp->capacity = 0x200000; /* 1 GB - random */
+ sdkp->capacity = 0; /* unknown mapped to zero - as usual */
return;
} else if (the_result && longrc) {
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 7fa4da4ea64..2679ea8bff1 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -497,7 +497,7 @@ int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
return 0;
hostno = instance->host_no;
- if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
+ if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
return 0;
}
@@ -1002,7 +1002,7 @@ connect_loop:
}
#endif
- buffer = (struct scatterlist *) SCint->buffer;
+ buffer = (struct scatterlist *) SCint->request_buffer;
len = buffer->length;
data = page_address(buffer->page) + buffer->offset;
} else {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 98b9312ba8d..34f9343ed0a 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -18,8 +18,8 @@
*
*/
-static int sg_version_num = 30533; /* 2 digits for each component */
-#define SG_VERSION_STR "3.5.33"
+static int sg_version_num = 30534; /* 2 digits for each component */
+#define SG_VERSION_STR "3.5.34"
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
@@ -28,7 +28,6 @@ static int sg_version_num = 30533; /* 2 digits for each component */
* (otherwise the macros compile to empty statements).
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
@@ -61,7 +60,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
-static char *sg_version_date = "20050908";
+static char *sg_version_date = "20060818";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -1165,7 +1164,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
len = vma->vm_end - sa;
len = (len < sg->length) ? len : sg->length;
if (offset < len) {
- page = sg->page;
+ page = virt_to_page(page_address(sg->page) + offset);
get_page(page); /* increment page count */
break;
}
@@ -1402,6 +1401,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
Sg_device *sdp = NULL;
struct cdev * cdev = NULL;
int error, k;
+ unsigned long iflags;
disk = alloc_disk(1);
if (!disk) {
@@ -1429,7 +1429,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
if (error)
- goto out;
+ goto cdev_add_err;
sdp->cdev = cdev;
if (sg_sysfs_valid) {
@@ -1456,6 +1456,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
return 0;
+cdev_add_err:
+ write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ kfree(sg_dev_arr[k]);
+ sg_dev_arr[k] = NULL;
+ sg_nr_dev--;
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+
out:
put_disk(disk);
if (cdev)
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 7cd366fcc57..4f1db6f2aae 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -97,7 +97,7 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
}
static inline
-void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
+void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
{
unsigned long len = cmd->SCp.this_residual;
void *addr = cmd->SCp.ptr;
@@ -129,7 +129,7 @@ void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
hcp->desc.cntinfo = HPCDMA_EOX;
}
-static int dma_setup(Scsi_Cmnd *cmd, int datainp)
+static int dma_setup(struct scsi_cmnd *cmd, int datainp)
{
struct ip22_hostdata *hdata = HDATA(cmd->device->host);
struct hpc3_scsiregs *hregs =
@@ -163,7 +163,7 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp)
return 0;
}
-static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
struct ip22_hostdata *hdata = HDATA(instance);
@@ -305,7 +305,7 @@ static int sgiwd93_release(struct Scsi_Host *instance)
return 1;
}
-static int sgiwd93_bus_reset(Scsi_Cmnd *cmd)
+static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 255886a9ac5..551baccec52 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/blkdev.h>
@@ -134,7 +133,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
host->this_id = scsi_id;
host->base = base_addr;
host->irq = irq;
- if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "sim710", host)) {
+ if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) {
printk(KERN_ERR "sim710: request_irq failed\n");
goto out_put_host;
}
@@ -283,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/sr.c b/drivers/scsi/sr.c
index ebf6579ed69..fae6e95a629 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
* how many actual sectors finished, and how many sectors we need
* to say have failed.
*/
- scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+ scsi_io_completion(SCpnt, good_bytes);
}
static int sr_init_command(struct scsi_cmnd * SCpnt)
@@ -360,7 +360,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
"mismatch count %d, bytes %d\n",
size, SCpnt->request_bufflen);
if (SCpnt->request_bufflen > size)
- SCpnt->request_bufflen = SCpnt->bufflen = size;
+ SCpnt->request_bufflen = size;
}
}
@@ -387,8 +387,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (this_count > 0xffff) {
this_count = 0xffff;
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * s_size;
+ SCpnt->request_bufflen = this_count * s_size;
}
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 9dde8df2f5c..a3e9d0f2eb5 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -34,7 +34,6 @@
* HP 6020 writers now supported.
*/
-#include <linux/config.h>
#include <linux/cdrom.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1272dd249af..7f669b60067 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -368,7 +368,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (cmdstatp->have_sense)
- __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
@@ -384,9 +384,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
scode != VOLUME_OVERFLOW &&
SRpnt->cmd[0] != MODE_SENSE &&
SRpnt->cmd[0] != TEST_UNIT_READY) {
- printk(KERN_WARNING "%s: Error with sense data: ", name);
- __scsi_print_sense("st", SRpnt->sense,
- SCSI_SENSE_BUFFERSIZE);
+
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
}
@@ -2818,7 +2817,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
undone == 0) {
- ioctl_result = 0; /* EOF written succesfully at EOM */
+ ioctl_result = 0; /* EOF written successfully at EOM */
if (fileno >= 0)
fileno++;
STps->drv_file = fileno;
@@ -3599,7 +3598,6 @@ static struct st_buffer *
tb->use_sg = max_sg;
tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
- tb->in_use = 1;
tb->dma = need_dma;
tb->buffer_size = got;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 411209048d7..05a5cae126e 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -31,7 +31,6 @@ struct st_request {
/* The tape buffer descriptor. */
struct st_buffer {
- unsigned char in_use;
unsigned char dma; /* DMA-able buffer */
unsigned char do_dio; /* direct i/o set up? */
int buffer_size;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
new file mode 100644
index 00000000000..3cf3106a29b
--- /dev/null
+++ b/drivers/scsi/stex.c
@@ -0,0 +1,1252 @@
+/*
+ * SuperTrak EX Series Storage Controller driver for Linux
+ *
+ * Copyright (C) 2005, 2006 Promise Technology 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Written By:
+ * Ed Lin <promise_linux@promise.com>
+ *
+ * Version: 2.9.0.13
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#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_OEM 0
+#define ST_BUILD_VER 13
+
+enum {
+ /* MU register offset */
+ IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */
+ IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */
+ OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */
+ OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */
+ IDBL = 0x20, /* MU_INBOUND_DOORBELL */
+ IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */
+ IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */
+ ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */
+ OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */
+ OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */
+
+ /* MU register value */
+ MU_INBOUND_DOORBELL_HANDSHAKE = 1,
+ MU_INBOUND_DOORBELL_REQHEADCHANGED = 2,
+ MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4,
+ MU_INBOUND_DOORBELL_HMUSTOPPED = 8,
+ MU_INBOUND_DOORBELL_RESET = 16,
+
+ MU_OUTBOUND_DOORBELL_HANDSHAKE = 1,
+ MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2,
+ MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4,
+ MU_OUTBOUND_DOORBELL_BUSCHANGE = 8,
+ MU_OUTBOUND_DOORBELL_HASEVENT = 16,
+
+ /* MU status code */
+ MU_STATE_STARTING = 1,
+ MU_STATE_FMU_READY_FOR_HANDSHAKE = 2,
+ MU_STATE_SEND_HANDSHAKE_FRAME = 3,
+ MU_STATE_STARTED = 4,
+ MU_STATE_RESETTING = 5,
+
+ MU_MAX_DELAY_TIME = 240000,
+ MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
+ HMU_PARTNER_TYPE = 2,
+
+ /* firmware returned values */
+ SRB_STATUS_SUCCESS = 0x01,
+ SRB_STATUS_ERROR = 0x04,
+ SRB_STATUS_BUSY = 0x05,
+ SRB_STATUS_INVALID_REQUEST = 0x06,
+ SRB_STATUS_SELECTION_TIMEOUT = 0x0A,
+ SRB_SEE_SENSE = 0x80,
+
+ /* task attribute */
+ TASK_ATTRIBUTE_SIMPLE = 0x0,
+ TASK_ATTRIBUTE_HEADOFQUEUE = 0x1,
+ TASK_ATTRIBUTE_ORDERED = 0x2,
+ TASK_ATTRIBUTE_ACA = 0x4,
+
+ /* request count, etc. */
+ MU_MAX_REQUEST = 32,
+
+ /* one message wasted, use MU_MAX_REQUEST+1
+ to handle MU_MAX_REQUEST messages */
+ MU_REQ_COUNT = (MU_MAX_REQUEST + 1),
+ MU_STATUS_COUNT = (MU_MAX_REQUEST + 1),
+
+ STEX_CDB_LENGTH = MAX_COMMAND_SIZE,
+ REQ_VARIABLE_LEN = 1024,
+ STATUS_VAR_LEN = 128,
+ ST_CAN_QUEUE = MU_MAX_REQUEST,
+ ST_CMD_PER_LUN = MU_MAX_REQUEST,
+ ST_MAX_SG = 32,
+
+ /* sg flags */
+ SG_CF_EOT = 0x80, /* end of table */
+ SG_CF_64B = 0x40, /* 64 bit item */
+ SG_CF_HOST = 0x20, /* sg in host memory */
+
+ ST_MAX_ARRAY_SUPPORTED = 16,
+ ST_MAX_TARGET_NUM = (ST_MAX_ARRAY_SUPPORTED+1),
+ ST_MAX_LUN_PER_TARGET = 16,
+
+ st_shasta = 0,
+ st_vsc = 1,
+
+ PASSTHRU_REQ_TYPE = 0x00000001,
+ PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
+ ST_INTERNAL_TIMEOUT = 30,
+
+ /* vendor specific commands of Promise */
+ ARRAY_CMD = 0xe0,
+ CONTROLLER_CMD = 0xe1,
+ DEBUGGING_CMD = 0xe2,
+ PASSTHRU_CMD = 0xe3,
+
+ PASSTHRU_GET_ADAPTER = 0x05,
+ PASSTHRU_GET_DRVVER = 0x10,
+ CTLR_POWER_STATE_CHANGE = 0x0e,
+ CTLR_POWER_SAVING = 0x01,
+
+ PASSTHRU_SIGNATURE = 0x4e415041,
+
+ INQUIRY_EVPD = 0x01,
+};
+
+struct st_sgitem {
+ u8 ctrl; /* SG_CF_xxx */
+ u8 reserved[3];
+ __le32 count;
+ __le32 addr;
+ __le32 addr_hi;
+};
+
+struct st_sgtable {
+ __le16 sg_count;
+ __le16 max_sg_count;
+ __le32 sz_in_byte;
+ struct st_sgitem table[ST_MAX_SG];
+};
+
+struct handshake_frame {
+ __le32 rb_phy; /* request payload queue physical address */
+ __le32 rb_phy_hi;
+ __le16 req_sz; /* size of each request payload */
+ __le16 req_cnt; /* count of reqs the buffer can hold */
+ __le16 status_sz; /* size of each status payload */
+ __le16 status_cnt; /* count of status the buffer can hold */
+ __le32 hosttime; /* seconds from Jan 1, 1970 (GMT) */
+ __le32 hosttime_hi;
+ u8 partner_type; /* who sends this frame */
+ u8 reserved0[7];
+ __le32 partner_ver_major;
+ __le32 partner_ver_minor;
+ __le32 partner_ver_oem;
+ __le32 partner_ver_build;
+ u32 reserved1[4];
+};
+
+struct req_msg {
+ __le16 tag;
+ u8 lun;
+ u8 target;
+ u8 task_attr;
+ u8 task_manage;
+ u8 prd_entry;
+ u8 payload_sz; /* payload size in 4-byte */
+ u8 cdb[STEX_CDB_LENGTH];
+ u8 variable[REQ_VARIABLE_LEN];
+};
+
+struct status_msg {
+ __le16 tag;
+ u8 lun;
+ u8 target;
+ u8 srb_status;
+ u8 scsi_status;
+ u8 reserved;
+ u8 payload_sz; /* payload size in 4-byte */
+ u8 variable[STATUS_VAR_LEN];
+};
+
+struct ver_info {
+ u32 major;
+ u32 minor;
+ u32 oem;
+ u32 build;
+ u32 reserved[2];
+};
+
+struct st_frame {
+ u32 base[6];
+ u32 rom_addr;
+
+ struct ver_info drv_ver;
+ struct ver_info bios_ver;
+
+ u32 bus;
+ u32 slot;
+ u32 irq_level;
+ u32 irq_vec;
+ u32 id;
+ u32 subid;
+
+ u32 dimm_size;
+ u8 dimm_type;
+ u8 reserved[3];
+
+ u32 channel;
+ u32 reserved1;
+};
+
+struct st_drvver {
+ u32 major;
+ u32 minor;
+ u32 oem;
+ u32 build;
+ u32 signature[2];
+ u8 console_id;
+ u8 host_no;
+ u8 reserved0[2];
+ u32 reserved[3];
+};
+
+#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))
+
+struct st_ccb {
+ struct req_msg *req;
+ struct scsi_cmnd *cmd;
+
+ void *sense_buffer;
+ unsigned int sense_bufflen;
+ int sg_count;
+
+ u32 req_type;
+ u8 srb_status;
+ u8 scsi_status;
+};
+
+struct st_hba {
+ void __iomem *mmio_base; /* iomapped PCI memory space */
+ void *dma_mem;
+ dma_addr_t dma_handle;
+
+ struct Scsi_Host *host;
+ struct pci_dev *pdev;
+
+ u32 req_head;
+ u32 req_tail;
+ u32 status_head;
+ u32 status_tail;
+
+ struct status_msg *status_buffer;
+ void *copy_buffer; /* temp buffer for driver-handled commands */
+ struct st_ccb ccb[MU_MAX_REQUEST];
+ struct st_ccb *wait_ccb;
+ wait_queue_head_t waitq;
+
+ unsigned int mu_status;
+ int out_req_cnt;
+
+ unsigned int cardtype;
+};
+
+static const char console_inq_page[] =
+{
+ 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30,
+ 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */
+ 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */
+ 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */
+ 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */
+ 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */
+ 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */
+ 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20
+};
+
+MODULE_AUTHOR("Ed Lin");
+MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ST_DRIVER_VERSION);
+
+static void stex_gettime(__le32 *time)
+{
+ struct timeval tv;
+ do_gettimeofday(&tv);
+
+ *time = cpu_to_le32(tv.tv_sec & 0xffffffff);
+ *(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
+}
+
+static struct status_msg *stex_get_status(struct st_hba *hba)
+{
+ struct status_msg *status =
+ hba->status_buffer + hba->status_tail;
+
+ ++hba->status_tail;
+ hba->status_tail %= MU_STATUS_COUNT;
+
+ return status;
+}
+
+static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ cmd->sense_buffer[0] = 0x70; /* fixed format, current */
+ cmd->sense_buffer[2] = sk;
+ cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
+ cmd->sense_buffer[12] = asc;
+ cmd->sense_buffer[13] = ascq;
+}
+
+static void stex_invalid_field(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ /* "Invalid field in cbd" */
+ stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ done(cmd);
+}
+
+static struct req_msg *stex_alloc_req(struct st_hba *hba)
+{
+ struct req_msg *req = ((struct req_msg *)hba->dma_mem) +
+ hba->req_head;
+
+ ++hba->req_head;
+ hba->req_head %= MU_REQ_COUNT;
+
+ return req;
+}
+
+static int stex_map_sg(struct st_hba *hba,
+ struct req_msg *req, struct st_ccb *ccb)
+{
+ struct pci_dev *pdev = hba->pdev;
+ struct scsi_cmnd *cmd;
+ dma_addr_t dma_handle;
+ struct scatterlist *src;
+ struct st_sgtable *dst;
+ int i;
+
+ cmd = ccb->cmd;
+ dst = (struct st_sgtable *)req->variable;
+ dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
+ dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
+
+ if (cmd->use_sg) {
+ int n_elem;
+
+ src = (struct scatterlist *) cmd->request_buffer;
+ n_elem = pci_map_sg(pdev, src,
+ cmd->use_sg, cmd->sc_data_direction);
+ if (n_elem <= 0)
+ return -EIO;
+
+ ccb->sg_count = n_elem;
+ dst->sg_count = cpu_to_le16((u16)n_elem);
+
+ for (i = 0; i < n_elem; i++, src++) {
+ dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
+ dst->table[i].addr =
+ cpu_to_le32(sg_dma_address(src) & 0xffffffff);
+ dst->table[i].addr_hi =
+ cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
+ dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
+ }
+ dst->table[--i].ctrl |= SG_CF_EOT;
+ return 0;
+ }
+
+ dma_handle = pci_map_single(pdev, cmd->request_buffer,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ cmd->SCp.dma_handle = dma_handle;
+
+ ccb->sg_count = 1;
+ dst->sg_count = cpu_to_le16(1);
+ dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
+ dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
+ dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
+ dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
+
+ return 0;
+}
+
+static void stex_internal_copy(struct scsi_cmnd *cmd,
+ const void *src, size_t *count, int sg_count)
+{
+ size_t lcount;
+ size_t len;
+ void *s, *d, *base = NULL;
+ if (*count > cmd->request_bufflen)
+ *count = cmd->request_bufflen;
+ lcount = *count;
+ while (lcount) {
+ len = lcount;
+ s = (void *)src;
+ if (cmd->use_sg) {
+ size_t offset = *count - lcount;
+ s += offset;
+ base = scsi_kmap_atomic_sg(cmd->request_buffer,
+ sg_count, &offset, &len);
+ if (base == NULL) {
+ *count -= lcount;
+ return;
+ }
+ d = base + offset;
+ } else
+ d = cmd->request_buffer;
+
+ memcpy(d, s, len);
+
+ lcount -= len;
+ if (cmd->use_sg)
+ scsi_kunmap_atomic_sg(base);
+ }
+}
+
+static int stex_direct_copy(struct scsi_cmnd *cmd,
+ const void *src, size_t count)
+{
+ struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+ size_t cp_len = count;
+ int n_elem = 0;
+
+ if (cmd->use_sg) {
+ n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ if (n_elem <= 0)
+ return 0;
+ }
+
+ stex_internal_copy(cmd, src, &cp_len, n_elem);
+
+ if (cmd->use_sg)
+ pci_unmap_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ return cp_len == count;
+}
+
+static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
+{
+ struct st_frame *p;
+ size_t count = sizeof(struct st_frame);
+
+ p = hba->copy_buffer;
+ memset(p->base, 0, sizeof(u32)*6);
+ *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
+ p->rom_addr = 0;
+
+ p->drv_ver.major = ST_VER_MAJOR;
+ p->drv_ver.minor = ST_VER_MINOR;
+ p->drv_ver.oem = ST_OEM;
+ p->drv_ver.build = ST_BUILD_VER;
+
+ p->bus = hba->pdev->bus->number;
+ p->slot = hba->pdev->devfn;
+ p->irq_level = 0;
+ p->irq_vec = hba->pdev->irq;
+ p->id = hba->pdev->vendor << 16 | hba->pdev->device;
+ p->subid =
+ hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
+
+ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
+}
+
+static void
+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++;
+
+ writel(hba->req_head, hba->mmio_base + IMR0);
+ writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL);
+ readl(hba->mmio_base + IDBL); /* flush */
+}
+
+static int
+stex_slave_alloc(struct scsi_device *sdev)
+{
+ /* Cheat: usually extracted from Inquiry data */
+ sdev->tagged_supported = 1;
+
+ scsi_activate_tcq(sdev, sdev->host->can_queue);
+
+ return 0;
+}
+
+static int
+stex_slave_config(struct scsi_device *sdev)
+{
+ sdev->use_10_for_rw = 1;
+ sdev->use_10_for_ms = 1;
+ sdev->timeout = 60 * HZ;
+ sdev->tagged_supported = 1;
+
+ return 0;
+}
+
+static void
+stex_slave_destroy(struct scsi_device *sdev)
+{
+ scsi_deactivate_tcq(sdev, 1);
+}
+
+static int
+stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+{
+ struct st_hba *hba;
+ struct Scsi_Host *host;
+ unsigned int id,lun;
+ struct req_msg *req;
+ u16 tag;
+ host = cmd->device->host;
+ id = cmd->device->id;
+ lun = cmd->device->channel; /* firmware lun issue work around */
+ hba = (struct st_hba *) &host->hostdata[0];
+
+ switch (cmd->cmnd[0]) {
+ case MODE_SENSE_10:
+ {
+ static char ms10_caching_page[12] =
+ { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 };
+ unsigned char page;
+ page = cmd->cmnd[2] & 0x3f;
+ if (page == 0x8 || page == 0x3f) {
+ stex_direct_copy(cmd, ms10_caching_page,
+ sizeof(ms10_caching_page));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ } else
+ stex_invalid_field(cmd, done);
+ return 0;
+ }
+ case INQUIRY:
+ if (id != ST_MAX_ARRAY_SUPPORTED)
+ break;
+ if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) {
+ stex_direct_copy(cmd, console_inq_page,
+ sizeof(console_inq_page));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ } else
+ stex_invalid_field(cmd, done);
+ return 0;
+ case PASSTHRU_CMD:
+ if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
+ struct st_drvver ver;
+ ver.major = ST_VER_MAJOR;
+ ver.minor = ST_VER_MINOR;
+ ver.oem = ST_OEM;
+ ver.build = ST_BUILD_VER;
+ ver.signature[0] = PASSTHRU_SIGNATURE;
+ ver.console_id = ST_MAX_ARRAY_SUPPORTED;
+ ver.host_no = hba->host->host_no;
+ cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ?
+ DID_OK << 16 | COMMAND_COMPLETE << 8 :
+ DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ return 0;
+ }
+ default:
+ break;
+ }
+
+ cmd->scsi_done = done;
+
+ tag = cmd->request->tag;
+
+ if (unlikely(tag >= host->can_queue))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ req = stex_alloc_req(hba);
+ req->lun = lun;
+ req->target = id;
+
+ /* cdb */
+ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
+
+ hba->ccb[tag].cmd = cmd;
+ hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE;
+ hba->ccb[tag].sense_buffer = cmd->sense_buffer;
+ hba->ccb[tag].req_type = 0;
+
+ if (cmd->sc_data_direction != DMA_NONE)
+ stex_map_sg(hba, req, &hba->ccb[tag]);
+
+ stex_send_cmd(hba, req, tag);
+ return 0;
+}
+
+static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
+{
+ if (cmd->sc_data_direction != DMA_NONE) {
+ if (cmd->use_sg)
+ pci_unmap_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ else
+ pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ }
+}
+
+static void stex_scsi_done(struct st_ccb *ccb)
+{
+ struct scsi_cmnd *cmd = ccb->cmd;
+ int result;
+
+ if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) {
+ result = ccb->scsi_status;
+ switch (ccb->scsi_status) {
+ case SAM_STAT_GOOD:
+ result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SAM_STAT_CHECK_CONDITION:
+ result |= DRIVER_SENSE << 24;
+ break;
+ case SAM_STAT_BUSY:
+ result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
+ break;
+ default:
+ result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ break;
+ }
+ }
+ else if (ccb->srb_status & SRB_SEE_SENSE)
+ result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION;
+ else switch (ccb->srb_status) {
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_BUSY:
+ result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_INVALID_REQUEST:
+ case SRB_STATUS_ERROR:
+ default:
+ result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ break;
+ }
+
+ cmd->result = result;
+ cmd->scsi_done(cmd);
+}
+
+static void stex_copy_data(struct st_ccb *ccb,
+ struct status_msg *resp, unsigned int variable)
+{
+ size_t count = variable;
+ if (resp->scsi_status != SAM_STAT_GOOD) {
+ if (ccb->sense_buffer != NULL)
+ memcpy(ccb->sense_buffer, resp->variable,
+ min(variable, ccb->sense_bufflen));
+ return;
+ }
+
+ if (ccb->cmd == NULL)
+ return;
+ stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
+}
+
+static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
+{
+ void __iomem *base = hba->mmio_base;
+ struct status_msg *resp;
+ struct st_ccb *ccb;
+ unsigned int size;
+ u16 tag;
+
+ if (!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))
+ return;
+
+ /* status payloads */
+ hba->status_head = readl(base + OMR1);
+ if (unlikely(hba->status_head >= MU_STATUS_COUNT)) {
+ printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n",
+ pci_name(hba->pdev));
+ return;
+ }
+
+ if (unlikely(hba->mu_status != MU_STATE_STARTED ||
+ hba->out_req_cnt <= 0)) {
+ hba->status_tail = hba->status_head;
+ goto update_status;
+ }
+
+ while (hba->status_tail != hba->status_head) {
+ resp = stex_get_status(hba);
+ tag = le16_to_cpu(resp->tag);
+ if (unlikely(tag >= hba->host->can_queue)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): invalid tag\n", pci_name(hba->pdev));
+ continue;
+ }
+
+ ccb = &hba->ccb[tag];
+ if (hba->wait_ccb == ccb)
+ hba->wait_ccb = NULL;
+ if (unlikely(ccb->req == NULL)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): lagging req\n", pci_name(hba->pdev));
+ continue;
+ }
+
+ size = resp->payload_sz * sizeof(u32); /* payload size */
+ if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN ||
+ size > sizeof(*resp))) {
+ printk(KERN_WARNING DRV_NAME "(%s): bad status size\n",
+ pci_name(hba->pdev));
+ } else {
+ size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */
+ if (size)
+ stex_copy_data(ccb, resp, size);
+ }
+
+ ccb->srb_status = resp->srb_status;
+ ccb->scsi_status = resp->scsi_status;
+
+ if (likely(ccb->cmd != NULL)) {
+ 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--;
+ } else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
+ hba->out_req_cnt--;
+ if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) {
+ ccb->req_type = 0;
+ continue;
+ }
+ ccb->req_type = 0;
+ if (waitqueue_active(&hba->waitq))
+ wake_up(&hba->waitq);
+ }
+ }
+
+update_status:
+ writel(hba->status_head, base + IMR1);
+ readl(base + IMR1); /* flush */
+}
+
+static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs)
+{
+ struct st_hba *hba = __hba;
+ void __iomem *base = hba->mmio_base;
+ u32 data;
+ unsigned long flags;
+ int handled = 0;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ data = readl(base + ODBL);
+
+ if (data && data != 0xffffffff) {
+ /* clear the interrupt */
+ writel(data, base + ODBL);
+ readl(base + ODBL); /* flush */
+ stex_mu_intr(hba, data);
+ handled = 1;
+ }
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+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;
+
+ 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++) {
+ 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);
+
+ 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);
+ h->req_sz = cpu_to_le16(sizeof(struct req_msg));
+ h->req_cnt = cpu_to_le16(MU_REQ_COUNT);
+ h->status_sz = cpu_to_le16(sizeof(struct status_msg));
+ h->status_cnt = cpu_to_le16(MU_STATUS_COUNT);
+ stex_gettime(&h->hosttime);
+ h->partner_type = HMU_PARTNER_TYPE;
+
+ status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE;
+ writel(status_phys, base + IMR0);
+ readl(base + IMR0);
+ writel((status_phys >> 16) >> 16, base + IMR1);
+ readl(base + IMR1);
+
+ writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */
+ readl(base + OMR0);
+ writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
+ readl(base + IDBL); /* flush */
+
+ udelay(10);
+ for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
+ && i < MU_MAX_DELAY_TIME; i++) {
+ 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);
+ readl(base + OMR0);
+ writel(0, base + IMR1);
+ readl(base + IMR1);
+ writel(0, base + OMR1);
+ readl(base + OMR1); /* flush */
+ hba->mu_status = MU_STATE_STARTED;
+ return 0;
+}
+
+static int stex_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct st_hba *hba = (struct st_hba *)host->hostdata;
+ u16 tag = cmd->request->tag;
+ void __iomem *base;
+ u32 data;
+ int result = SUCCESS;
+ unsigned long flags;
+ base = hba->mmio_base;
+ spin_lock_irqsave(host->host_lock, flags);
+ if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
+ hba->wait_ccb = &hba->ccb[tag];
+ else {
+ for (tag = 0; tag < host->can_queue; tag++)
+ if (hba->ccb[tag].cmd == cmd) {
+ hba->wait_ccb = &hba->ccb[tag];
+ break;
+ }
+ if (tag >= host->can_queue)
+ goto out;
+ }
+
+ data = readl(base + ODBL);
+ if (data == 0 || data == 0xffffffff)
+ goto fail_out;
+
+ writel(data, base + ODBL);
+ readl(base + ODBL); /* flush */
+
+ stex_mu_intr(hba, data);
+
+ if (hba->wait_ccb == NULL) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): lost interrupt\n", pci_name(hba->pdev));
+ goto out;
+ }
+
+fail_out:
+ stex_unmap_sg(hba, cmd);
+ hba->wait_ccb->req = NULL; /* nullify the req's future return */
+ hba->wait_ccb = NULL;
+ result = FAILED;
+out:
+ spin_unlock_irqrestore(host->host_lock, flags);
+ return result;
+}
+
+static void stex_hard_reset(struct st_hba *hba)
+{
+ struct pci_bus *bus;
+ int i;
+ u16 pci_cmd;
+ u8 pci_bctl;
+
+ for (i = 0; i < 16; i++)
+ pci_read_config_dword(hba->pdev, i * 4,
+ &hba->pdev->saved_config_space[i]);
+
+ /* Reset secondary bus. Our controller(MU/ATU) is the only device on
+ secondary bus. Consult Intel 80331/3 developer's manual for detail */
+ bus = hba->pdev->bus;
+ pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
+ pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+ msleep(1);
+ 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++) {
+ pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);
+ if (pci_cmd & PCI_COMMAND_MASTER)
+ break;
+ msleep(1);
+ }
+
+ ssleep(5);
+ for (i = 0; i < 16; i++)
+ pci_write_config_dword(hba->pdev, i * 4,
+ hba->pdev->saved_config_space[i]);
+}
+
+static int stex_reset(struct scsi_cmnd *cmd)
+{
+ struct st_hba *hba;
+ unsigned long flags;
+ hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+
+ hba->mu_status = MU_STATE_RESETTING;
+
+ 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;
+ }
+ 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;
+}
+
+static int stex_biosparam(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int geom[])
+{
+ int heads = 255, sectors = 63, cylinders;
+
+ if (capacity < 0x200000) {
+ heads = 64;
+ sectors = 32;
+ }
+
+ cylinders = sector_div(capacity, heads * sectors);
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return 0;
+}
+
+static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .proc_name = DRV_NAME,
+ .bios_param = stex_biosparam,
+ .queuecommand = stex_queuecommand,
+ .slave_alloc = stex_slave_alloc,
+ .slave_configure = stex_slave_config,
+ .slave_destroy = stex_slave_destroy,
+ .eh_abort_handler = stex_abort,
+ .eh_host_reset_handler = stex_reset,
+ .can_queue = ST_CAN_QUEUE,
+ .this_id = -1,
+ .sg_tablesize = ST_MAX_SG,
+ .cmd_per_lun = ST_CMD_PER_LUN,
+};
+
+static int stex_set_dma_mask(struct pci_dev * pdev)
+{
+ int ret;
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+ return 0;
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!ret)
+ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ return ret;
+}
+
+static int __devinit
+stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct st_hba *hba;
+ struct Scsi_Host *host;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&driver_template, sizeof(struct st_hba));
+
+ if (!host) {
+ printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_disable;
+ }
+
+ hba = (struct st_hba *)host->hostdata;
+ memset(hba, 0, sizeof(struct st_hba));
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err < 0) {
+ printk(KERN_ERR DRV_NAME "(%s): request regions failed\n",
+ pci_name(pdev));
+ goto out_scsi_host_put;
+ }
+
+ hba->mmio_base = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if ( !hba->mmio_base) {
+ printk(KERN_ERR DRV_NAME "(%s): memory map failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ err = stex_set_dma_mask(pdev);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
+
+ hba->dma_mem = dma_alloc_coherent(&pdev->dev,
+ STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL);
+ if (!hba->dma_mem) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
+
+ hba->status_buffer =
+ (struct status_msg *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
+ 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 */
+ host->max_channel = ST_MAX_LUN_PER_TARGET - 1;
+ host->max_id = ST_MAX_TARGET_NUM;
+ host->max_lun = 1;
+ host->unique_id = host->host_no;
+ host->max_cmd_len = STEX_CDB_LENGTH;
+
+ hba->host = host;
+ hba->pdev = pdev;
+ init_waitqueue_head(&hba->waitq);
+
+ err = request_irq(pdev->irq, stex_intr, IRQF_SHARED, DRV_NAME, hba);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
+ pci_name(pdev));
+ goto out_pci_free;
+ }
+
+ err = stex_handshake(hba);
+ if (err)
+ goto out_free_irq;
+
+ err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
+ pci_name(pdev));
+ goto out_free_irq;
+ }
+
+ pci_set_drvdata(pdev, hba);
+
+ err = scsi_add_host(host, &pdev->dev);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n",
+ pci_name(pdev));
+ goto out_free_irq;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+out_free_irq:
+ free_irq(pdev->irq, hba);
+out_pci_free:
+ dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE,
+ hba->dma_mem, hba->dma_handle);
+out_iounmap:
+ iounmap(hba->mmio_base);
+out_release_regions:
+ pci_release_regions(pdev);
+out_scsi_host_put:
+ scsi_host_put(host);
+out_disable:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void stex_hba_stop(struct st_hba *hba)
+{
+ struct req_msg *req;
+ unsigned long flags;
+ unsigned long before;
+ u16 tag = 0;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ 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;
+
+ hba->ccb[tag].cmd = NULL;
+ hba->ccb[tag].sg_count = 0;
+ hba->ccb[tag].sense_bufflen = 0;
+ hba->ccb[tag].sense_buffer = NULL;
+ hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE;
+
+ stex_send_cmd(hba, req, tag);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ before = jiffies;
+ while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
+ return;
+ msleep(10);
+ }
+}
+
+static void stex_hba_free(struct st_hba *hba)
+{
+ free_irq(hba->pdev->irq, hba);
+
+ iounmap(hba->mmio_base);
+
+ pci_release_regions(hba->pdev);
+
+ dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE,
+ hba->dma_mem, hba->dma_handle);
+}
+
+static void stex_remove(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ scsi_remove_host(hba->host);
+
+ pci_set_drvdata(pdev, NULL);
+
+ stex_hba_stop(hba);
+
+ stex_hba_free(hba);
+
+ scsi_host_put(hba->host);
+
+ pci_disable_device(pdev);
+}
+
+static void stex_shutdown(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ stex_hba_stop(hba);
+}
+
+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 },
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
+
+static struct pci_driver stex_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = stex_pci_tbl,
+ .probe = stex_probe,
+ .remove = __devexit_p(stex_remove),
+ .shutdown = stex_shutdown,
+};
+
+static int __init stex_init(void)
+{
+ printk(KERN_INFO DRV_NAME
+ ": Promise SuperTrak EX Driver version: %s\n",
+ ST_DRIVER_VERSION);
+
+ return pci_register_driver(&stex_pci_driver);
+}
+
+static void __exit stex_exit(void)
+{
+ pci_unregister_driver(&stex_pci_driver);
+}
+
+module_init(stex_init);
+module_exit(stex_exit);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 25cced91c8a..2f8073b73bf 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -517,7 +517,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
@@ -535,7 +535,6 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
}
-#include <linux/config.h>
#include <linux/delay.h>
#if 1
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index cc990bed968..6b60536ac92 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -97,7 +97,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command);
esp->irq = 2;
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"SUN3X SCSI", esp->ehost)) {
esp_deallocate(esp);
return 0;
@@ -332,11 +332,11 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
struct scatterlist *sg = sp->SCp.buffer;
while (sz >= 0) {
- sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+ sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
sg[sz].offset, sg[sz].length);
sz--;
}
- sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -347,17 +347,17 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
- dvma_unmap((char *)sg[sz].dvma_address);
+ dvma_unmap((char *)sg[sz].dma_address);
sz--;
}
}
static void dma_advance_sg (Scsi_Cmnd *sp)
{
- sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static int sun3x_esp_release(struct Scsi_Host *instance)
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 48110376972..7519728dfc3 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -40,7 +40,6 @@
#ifndef SYM53C8XX_H
#define SYM53C8XX_H
-#include <linux/config.h>
/*
* DMA addressing mode.
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index ea82d3df63a..739d3ef46a4 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1547,7 +1547,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* If we synchonize the C code with SCRIPTS on interrupt,
* we do not want to share the INTR line at all.
*/
- if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) {
+ if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, np)) {
printf_err("%s: request irq %d failure\n",
sym_name(np), pdev->irq);
goto attach_failed;
@@ -2084,7 +2084,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895,
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index a446cda3f64..e022d3c71b5 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -40,7 +40,6 @@
#ifndef SYM_GLUE_H
#define SYM_GLUE_H
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/pci.h>
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index a24f661b027..2df6747cb76 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -260,7 +260,7 @@ found:
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", instance)) {
+ if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 91322aff241..9404ff3d4c7 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -218,7 +218,6 @@
#endif
#define DCBDEBUG1(x) C_NOP
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
@@ -2585,7 +2584,7 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
/* Reset Pending INT */
DC390_read8_(INT_Status, io_port);
- if (request_irq(pdev->irq, do_DC390_Interrupt, SA_SHIRQ,
+ if (request_irq(pdev->irq, do_DC390_Interrupt, IRQF_SHARED,
"tmscsim", pACB)) {
printk(KERN_ERR "DC390: register IRQ error!\n");
goto out_release_region;
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index d4495272fb4..9b66fa8d38d 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -9,7 +9,6 @@
#define _TMSCSIM_H
#include <linux/types.h>
-#include <linux/config.h>
#define SCSI_IRQ_NONE 255
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 33cd90fc657..57449611e71 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -405,7 +405,6 @@
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -873,7 +872,7 @@ static int port_detect \
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+ IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
goto freelock;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index e681681ab7a..0372aa9fa19 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -196,8 +196,8 @@ struct mscp {
u32 sense_data PACKED;
/* The following fields are for software only. They are included in
the MSCP structure because they are associated with SCSI requests. */
- void (*done)(Scsi_Cmnd *);
- Scsi_Cmnd *SCint;
+ void (*done) (struct scsi_cmnd *);
+ struct scsi_cmnd *SCint;
ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */
};
@@ -289,7 +289,7 @@ static const unsigned short ultrastor_ports_14f[] = {
static void ultrastor_interrupt(int, void *, struct pt_regs *);
static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
-static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
+static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
/* Always called with host lock held */
@@ -673,7 +673,7 @@ static const char *ultrastor_info(struct Scsi_Host * shpnt)
return buf;
}
-static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
+static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
{
struct scatterlist *sl;
long transfer_length = 0;
@@ -694,7 +694,8 @@ static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
mscp->transfer_data_length = transfer_length;
}
-static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+ void (*done) (struct scsi_cmnd *))
{
struct mscp *my_mscp;
#if ULTRASTOR_MAX_CMDS > 1
@@ -833,7 +834,7 @@ retry:
*/
-static int ultrastor_abort(Scsi_Cmnd *SCpnt)
+static int ultrastor_abort(struct scsi_cmnd *SCpnt)
{
#if ULTRASTOR_DEBUG & UD_ABORT
char out[108];
@@ -843,7 +844,7 @@ static int ultrastor_abort(Scsi_Cmnd *SCpnt)
unsigned int mscp_index;
unsigned char old_aborted;
unsigned long flags;
- void (*done)(Scsi_Cmnd *);
+ void (*done)(struct scsi_cmnd *);
struct Scsi_Host *host = SCpnt->device->host;
if(config.slot)
@@ -960,7 +961,7 @@ static int ultrastor_abort(Scsi_Cmnd *SCpnt)
return SUCCESS;
}
-static int ultrastor_host_reset(Scsi_Cmnd * SCpnt)
+static int ultrastor_host_reset(struct scsi_cmnd * SCpnt)
{
unsigned long flags;
int i;
@@ -1045,8 +1046,8 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned int mscp_index;
#endif
struct mscp *mscp;
- void (*done)(Scsi_Cmnd *);
- Scsi_Cmnd *SCtmp;
+ void (*done) (struct scsi_cmnd *);
+ struct scsi_cmnd *SCtmp;
#if ULTRASTOR_MAX_CMDS == 1
mscp = &config.mscp[0];
@@ -1079,7 +1080,7 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
if (icm_status == 3) {
- void (*done)(Scsi_Cmnd *) = mscp->done;
+ void (*done)(struct scsi_cmnd *) = mscp->done;
if (done) {
mscp->done = NULL;
mscp->SCint->result = DID_ABORT << 16;
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index da759a11def..a692905f95f 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -14,11 +14,13 @@
#define _ULTRASTOR_H
static int ultrastor_detect(struct scsi_host_template *);
-static const char *ultrastor_info(struct Scsi_Host * shpnt);
-static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int ultrastor_abort(Scsi_Cmnd *);
-static int ultrastor_host_reset(Scsi_Cmnd *);
-static int ultrastor_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
+static const char *ultrastor_info(struct Scsi_Host *shpnt);
+static int ultrastor_queuecommand(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
+static int ultrastor_abort(struct scsi_cmnd *);
+static int ultrastor_host_reset(struct scsi_cmnd *);
+static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
+ sector_t, int *);
#define ULTRASTOR_14F_MAX_SG 16
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 27307fe5a4c..2083454db51 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -71,7 +71,6 @@
* Richard Hirst <richard@sleepie.demon.co.uk> August 2000
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -374,7 +373,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 193ec517d25..edcb0365cf0 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -22,7 +22,6 @@
#ifndef WD33C93_H
#define WD33C93_H
-#include <linux/config.h>
#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */
#ifdef PROC_INTERFACE
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index e55f0ee7e7e..a0b61af48f1 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1250,7 +1250,7 @@ static int wd7000_init(Adapter * host)
return 0;
- if (request_irq(host->irq, wd7000_intr, SA_INTERRUPT, "wd7000", host)) {
+ if (request_irq(host->irq, wd7000_intr, IRQF_DISABLED, "wd7000", host)) {
printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0);
}
@@ -1391,7 +1391,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
*
*/
-static int wd7000_detect(struct scsi_host_template *tpnt)
+static __init int wd7000_detect(struct scsi_host_template *tpnt)
{
short present = 0, biosaddr_ptr, sig_ptr, i, pass;
short biosptr[NUM_CONFIGS];
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index a6cfbb3b361..4b5f908d35c 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -136,7 +136,7 @@ zalon_probe(struct parisc_device *dev)
if (!host)
goto fail;
- if (request_irq(dev->irq, ncr53c8xx_intr, SA_SHIRQ, "zalon", host)) {
+ if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
dev->dev.bus_id, dev->irq);
goto fail;