aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/aic94xx/aic94xx_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aic94xx/aic94xx_init.c')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c306
1 files changed, 239 insertions, 67 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 27852b43b90..c56741fc4b9 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -29,6 +29,8 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
#include <scsi/scsi_host.h>
@@ -36,6 +38,7 @@
#include "aic94xx_reg.h"
#include "aic94xx_hwi.h"
#include "aic94xx_seq.h"
+#include "aic94xx_sds.h"
/* The format is "version.release.patchlevel" */
#define ASD_DRIVER_VERSION "1.0.3"
@@ -54,8 +57,6 @@ MODULE_PARM_DESC(collector, "\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 int asd_scan_finished(struct Scsi_Host *, unsigned long);
static void asd_scan_start(struct Scsi_Host *);
@@ -67,7 +68,6 @@ static struct scsi_host_template aic94xx_sht = {
.queuecommand = sas_queuecommand,
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
- .slave_destroy = sas_slave_destroy,
.scan_finished = asd_scan_finished,
.scan_start = asd_scan_start,
.change_queue_depth = sas_change_queue_depth,
@@ -81,9 +81,11 @@ static struct scsi_host_template aic94xx_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
};
-static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+static int asd_map_memio(struct asd_ha_struct *asd_ha)
{
int err, i;
struct asd_ha_addrspace *io_handle;
@@ -131,7 +133,7 @@ Err:
return err;
}
-static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
{
struct asd_ha_addrspace *io_handle;
@@ -144,7 +146,7 @@ static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
pci_release_region(asd_ha->pcidev, 0);
}
-static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+static int 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];
@@ -168,12 +170,12 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
return err;
}
-static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+static void 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)
+static int asd_map_ha(struct asd_ha_struct *asd_ha)
{
int err;
u16 cmd_reg;
@@ -205,7 +207,7 @@ Err:
return err;
}
-static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
{
if (asd_ha->iospace)
asd_unmap_ioport(asd_ha);
@@ -219,17 +221,12 @@ static const char *asd_dev_rev[30] = {
[8] = "B0",
};
-static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+static int 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;
- }
+ asd_ha->revision_id = asd_ha->pcidev->revision;
+
err = -ENODEV;
if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
asd_printk("%s is revision %s (%X), which is not supported\n",
@@ -260,7 +257,7 @@ Err:
return err;
}
-static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+static int asd_aic9410_setup(struct asd_ha_struct *asd_ha)
{
int err = asd_common_setup(asd_ha);
@@ -275,7 +272,7 @@ static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
return 0;
}
-static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+static int asd_aic9405_setup(struct asd_ha_struct *asd_ha)
{
int err = asd_common_setup(asd_ha);
@@ -315,6 +312,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
}
static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+#define FLASH_CMD_NONE 0x00
+#define FLASH_CMD_UPDATE 0x01
+#define FLASH_CMD_VERIFY 0x02
+
+struct flash_command {
+ u8 command[8];
+ int code;
+};
+
+static struct flash_command flash_command_table[] =
+{
+ {"verify", FLASH_CMD_VERIFY},
+ {"update", FLASH_CMD_UPDATE},
+ {"", FLASH_CMD_NONE} /* Last entry should be NULL. */
+};
+
+struct error_bios {
+ char *reason;
+ int err_code;
+};
+
+static struct error_bios flash_error_table[] =
+{
+ {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE},
+ {"PCI ID mismatch", FAIL_CHECK_PCI_ID},
+ {"Checksum mismatch", FAIL_CHECK_SUM},
+ {"Unknown Error", FAIL_UNKNOWN},
+ {"Failed to verify.", FAIL_VERIFY},
+ {"Failed to reset flash chip.", FAIL_RESET_FLASH},
+ {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID},
+ {"Failed to erash flash chip.", FAIL_ERASE_FLASH},
+ {"Failed to program flash chip.", FAIL_WRITE_FLASH},
+ {"Flash in progress", FLASH_IN_PROGRESS},
+ {"Image file size Error", FAIL_FILE_SIZE},
+ {"Input parameter error", FAIL_PARAMETERS},
+ {"Out of memory", FAIL_OUT_MEMORY},
+ {"OK", 0} /* Last entry err_code = 0. */
+};
+
+static ssize_t asd_store_update_bios(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ char *cmd_ptr, *filename_ptr;
+ struct bios_file_header header, *hdr_ptr;
+ int res, i;
+ u32 csum = 0;
+ int flash_command = FLASH_CMD_NONE;
+ int err = 0;
+
+ cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+
+ if (!cmd_ptr) {
+ err = FAIL_OUT_MEMORY;
+ goto out;
+ }
+
+ filename_ptr = cmd_ptr + count;
+ res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
+ if (res != 2) {
+ err = FAIL_PARAMETERS;
+ goto out1;
+ }
+
+ for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
+ if (!memcmp(flash_command_table[i].command,
+ cmd_ptr, strlen(cmd_ptr))) {
+ flash_command = flash_command_table[i].code;
+ break;
+ }
+ }
+ if (flash_command == FLASH_CMD_NONE) {
+ err = FAIL_PARAMETERS;
+ goto out1;
+ }
+
+ if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
+ err = FLASH_IN_PROGRESS;
+ goto out1;
+ }
+ err = request_firmware(&asd_ha->bios_image,
+ filename_ptr,
+ &asd_ha->pcidev->dev);
+ if (err) {
+ asd_printk("Failed to load bios image file %s, error %d\n",
+ filename_ptr, err);
+ err = FAIL_OPEN_BIOS_FILE;
+ goto out1;
+ }
+
+ hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
+
+ if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
+ hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
+ (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
+ hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
+
+ ASD_DPRINTK("The PCI vendor or device id does not match\n");
+ ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
+ " pci vendor=%x pci dev=%x\n",
+ hdr_ptr->contrl_id.vendor,
+ hdr_ptr->contrl_id.device,
+ hdr_ptr->contrl_id.sub_vendor,
+ hdr_ptr->contrl_id.sub_device,
+ asd_ha->pcidev->vendor,
+ asd_ha->pcidev->device);
+ err = FAIL_CHECK_PCI_ID;
+ goto out2;
+ }
+
+ if (hdr_ptr->filelen != asd_ha->bios_image->size) {
+ err = FAIL_FILE_SIZE;
+ goto out2;
+ }
+
+ /* calculate checksum */
+ for (i = 0; i < hdr_ptr->filelen; i++)
+ csum += asd_ha->bios_image->data[i];
+
+ if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
+ ASD_DPRINTK("BIOS file checksum mismatch\n");
+ err = FAIL_CHECK_SUM;
+ goto out2;
+ }
+ if (flash_command == FLASH_CMD_UPDATE) {
+ asd_ha->bios_status = FLASH_IN_PROGRESS;
+ err = asd_write_flash_seg(asd_ha,
+ &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+ 0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+ if (!err)
+ err = asd_verify_flash_seg(asd_ha,
+ &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+ 0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+ } else {
+ asd_ha->bios_status = FLASH_IN_PROGRESS;
+ err = asd_verify_flash_seg(asd_ha,
+ &asd_ha->bios_image->data[sizeof(header)],
+ 0, hdr_ptr->filelen-sizeof(header));
+ }
+
+out2:
+ release_firmware(asd_ha->bios_image);
+out1:
+ kfree(cmd_ptr);
+out:
+ asd_ha->bios_status = err;
+
+ if (!err)
+ return count;
+ else
+ return -err;
+}
+
+static ssize_t asd_show_update_bios(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+
+ for (i = 0; flash_error_table[i].err_code != 0; i++) {
+ if (flash_error_table[i].err_code == asd_ha->bios_status)
+ break;
+ }
+ if (asd_ha->bios_status != FLASH_IN_PROGRESS)
+ asd_ha->bios_status = FLASH_OK;
+
+ return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
+ flash_error_table[i].err_code,
+ flash_error_table[i].reason);
+}
+
+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUSR,
+ asd_show_update_bios, asd_store_update_bios);
+
static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
{
int err;
@@ -330,9 +502,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
if (err)
goto err_biosb;
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
+ if (err)
+ goto err_update_bios;
return 0;
+err_update_bios:
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
err_biosb:
device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
err_rev:
@@ -345,12 +522,13 @@ 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);
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
}
/* The first entry, 0, is used for dynamic ids, the rest for devices
* we know about.
*/
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
const char * name;
int (*setup)(struct asd_ha_struct *asd_ha);
} asd_pcidev_data[] = {
@@ -366,7 +544,7 @@ static struct asd_pcidev_struct {
},
};
-static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+static 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,
@@ -384,7 +562,7 @@ static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
* 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)
+static void asd_free_edbs(struct asd_ha_struct *asd_ha)
{
struct asd_seq_data *seq = &asd_ha->seq;
int i;
@@ -395,7 +573,7 @@ static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
seq->edb_arr = NULL;
}
-static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+static void asd_free_escbs(struct asd_ha_struct *asd_ha)
{
struct asd_seq_data *seq = &asd_ha->seq;
int i;
@@ -410,7 +588,7 @@ static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
seq->escb_arr = NULL;
}
-static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+static void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
{
int i;
@@ -467,7 +645,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_dma_tok),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_dma_token_cache) {
asd_printk("couldn't create dma token cache\n");
return -ENOMEM;
@@ -479,7 +657,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_ascb),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_ascb_cache) {
asd_printk("couldn't create ascb cache\n");
goto Err;
@@ -508,9 +686,9 @@ 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);
+ kcalloc(ASD_MAX_PHYS, sizeof(*sas_phys), GFP_KERNEL);
struct asd_sas_port **sas_ports =
- kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL);
+ kcalloc(ASD_MAX_PHYS, sizeof(*sas_ports), GFP_KERNEL);
if (!sas_phys || !sas_ports) {
kfree(sas_phys);
@@ -553,10 +731,9 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
return err;
}
-static int __devinit asd_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
- struct asd_pcidev_struct *asd_dev;
+ const struct asd_pcidev_struct *asd_dev;
unsigned asd_id = (unsigned) id->driver_data;
struct asd_ha_struct *asd_ha;
struct Scsi_Host *shost;
@@ -585,12 +762,13 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
if (!asd_ha) {
asd_printk("out of memory\n");
- goto Err;
+ goto Err_put;
}
asd_ha->pcidev = dev;
- asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+ asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
asd_ha->sas_ha.lldd_ha = asd_ha;
+ asd_ha->bios_status = FLASH_OK;
asd_ha->name = asd_dev->name;
asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
@@ -602,34 +780,30 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
shost->max_cmd_len = 16;
err = scsi_add_host(shost, &dev->dev);
- if (err) {
- scsi_host_put(shost);
+ if (err)
goto Err_free;
- }
-
-
err = asd_dev->setup(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = -ENODEV;
- if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
- && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
+ if (!pci_set_dma_mask(dev, DMA_BIT_MASK(64))
+ && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64)))
;
- else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
- && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
+ else if (!pci_set_dma_mask(dev, DMA_BIT_MASK(32))
+ && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32)))
;
else {
asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
- goto Err_free;
+ goto Err_remove;
}
pci_set_drvdata(dev, asd_ha);
err = asd_map_ha(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = asd_create_ha_caches(asd_ha);
if (err)
@@ -696,9 +870,12 @@ Err_free_cache:
asd_destroy_ha_caches(asd_ha);
Err_unmap:
asd_unmap_ha(asd_ha);
+Err_remove:
+ scsi_remove_host(shost);
Err_free:
kfree(asd_ha);
- scsi_remove_host(shost);
+Err_put:
+ scsi_host_put(shost);
Err:
pci_disable_device(dev);
return err;
@@ -746,7 +923,7 @@ static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
}
}
-static void __devexit asd_pci_remove(struct pci_dev *dev)
+static void asd_pci_remove(struct pci_dev *dev)
{
struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
@@ -792,7 +969,7 @@ static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time)
if (time < HZ)
return 0;
/* Wait for discovery to finish */
- scsi_flush_work(shost);
+ sas_drain_work(SHOST_TO_SAS_HA(shost));
return 1;
}
@@ -822,7 +999,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
.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_I_T_nexus_reset = asd_I_T_nexus_reset,
.lldd_lu_reset = asd_lu_reset,
.lldd_query_task = asd_query_task,
@@ -830,25 +1007,20 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
.lldd_clear_nexus_ha = asd_clear_nexus_ha,
.lldd_control_phy = asd_control_phy,
+
+ .lldd_ata_set_dmamode = asd_set_dmamode,
};
-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_RAZOR1F),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
- 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},
+static const struct pci_device_id aic94xx_pci_table[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2},
{}
};
@@ -858,7 +1030,7 @@ 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),
+ .remove = asd_pci_remove,
};
static int __init aic94xx_init(void)