aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <jejb@mulgrave.(none)>2005-03-28 23:06:06 -0600
committerJames Bottomley <jejb@titanic.il.steeleye.com>2005-03-28 23:06:06 -0600
commit5b58635b4a9ad92c5a54a99181e1e13300e9e38b (patch)
tree0f9f31fe8bcaf0df6064b6607a062b0266f31cca
parenta51c32f119a2397517cb21d7fe561677fac6d288 (diff)
downloadhistory-5b58635b4a9ad92c5a54a99181e1e13300e9e38b.tar.gz
3ware 9000 driver update
From: adam radford <aradford@gmail.com> - Add support for PAE mode. - Add lun support. - Fix twa_remove() to free irq handler/unregister_chrdev() before shutting down the card. - Change to new 'change_queue_depth' api. (From James) - Fix 'handled=1' ISR usage, remove bogus IRQ check (from Jeff Garzik) - Remove un-needed eh_abort handler. - Add support for embedded firmware error strings. Signed-off-by: Adam Radford <linuxraid@amcc.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/3w-9xxx.c512
-rw-r--r--drivers/scsi/3w-9xxx.h88
2 files changed, 295 insertions, 305 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 199698597ba8e..a2b18f5a4f930 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -3,7 +3,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
- Copyright (C) 2004 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2005 Applied Micro Circuits 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
@@ -51,6 +51,14 @@
-------
2.26.02.000 - Driver cleanup for kernel submission.
2.26.02.001 - Replace schedule_timeout() calls with msleep().
+ 2.26.02.002 - Add support for PAE mode.
+ Add lun support.
+ Fix twa_remove() to free irq handler/unregister_chrdev()
+ before shutting down card.
+ Change to new 'change_queue_depth' api.
+ Fix 'handled=1' ISR usage, remove bogus IRQ check.
+ Remove un-needed eh_abort handler.
+ Add support for embedded firmware error strings.
*/
#include <linux/module.h>
@@ -73,7 +81,7 @@
#include "3w-9xxx.h"
/* Globals */
-static const char *twa_driver_version="2.26.02.001";
+#define TW_DRIVER_VERSION "2.26.02.002"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -83,6 +91,7 @@ extern struct timezone sys_tz;
MODULE_AUTHOR ("AMCC");
MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
/* Function prototypes */
static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
@@ -108,9 +117,9 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
@@ -126,7 +135,7 @@ static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
ssize_t len;
spin_lock_irqsave(tw_dev->host->host_lock, flags);
- len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n"
+ len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
"Current commands posted: %4d\n"
"Max commands posted: %4d\n"
"Current pending commands: %4d\n"
@@ -136,9 +145,8 @@ static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
"Last sector count: %4d\n"
"Max sector count: %4d\n"
"SCSI Host Resets: %4d\n"
- "SCSI Aborts/Timeouts: %4d\n"
"AEN's: %4d\n",
- twa_driver_version,
+ TW_DRIVER_VERSION,
tw_dev->posted_request_count,
tw_dev->max_posted_request_count,
tw_dev->pending_request_count,
@@ -148,40 +156,19 @@ static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
tw_dev->sector_count,
tw_dev->max_sector_count,
tw_dev->num_resets,
- tw_dev->num_aborts,
tw_dev->aen_count);
spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
return len;
} /* End twa_show_stats() */
/* This function will set a devices queue depth */
-static ssize_t twa_store_queue_depth(struct device *dev, const char *buf, size_t count)
+static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth)
{
- int queue_depth;
- struct scsi_device *sdev = to_scsi_device(dev);
-
- queue_depth = simple_strtoul(buf, NULL, 0);
if (queue_depth > TW_Q_LENGTH-2)
- return -EINVAL;
+ queue_depth = TW_Q_LENGTH-2;
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
-
- return count;
-} /* End twa_store_queue_depth() */
-
-/* Create sysfs 'queue_depth' entry */
-static struct device_attribute twa_queue_depth_attr = {
- .attr = {
- .name = "queue_depth",
- .mode = S_IRUSR | S_IWUSR,
- },
- .store = twa_store_queue_depth
-};
-
-/* Device attributes initializer */
-static struct device_attribute *twa_dev_attrs[] = {
- &twa_queue_depth_attr,
- NULL,
-};
+ return queue_depth;
+} /* End twa_change_queue_depth() */
/* Create sysfs 'stats' entry */
static struct class_device_attribute twa_host_stats_attr = {
@@ -265,7 +252,7 @@ static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
{
int request_id = 0;
char cdb[TW_MAX_CDB_LEN];
- TW_SG_Apache sglist[1];
+ TW_SG_Entry sglist[1];
int finished = 0, count = 0;
TW_Command_Full *full_command_packet;
TW_Command_Apache_Header *header;
@@ -286,7 +273,7 @@ static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
/* Initialize sglist */
- memset(&sglist, 0, sizeof(TW_SG_Apache));
+ memset(&sglist, 0, sizeof(TW_SG_Entry));
sglist[0].length = TW_SECTOR_SIZE;
sglist[0].address = tw_dev->generic_buffer_phys[request_id];
@@ -359,6 +346,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
TW_Event *event;
unsigned short aen;
char host[16];
+ char *error_str;
tw_dev->aen_count++;
@@ -385,6 +373,9 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
event->sequence_id = tw_dev->error_sequence_id;
tw_dev->error_sequence_id++;
+ /* Check for embedded error string */
+ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
+
header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
event->parameter_len = strlen(header->err_specific_desc);
memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
@@ -393,7 +384,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
host,
twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
- twa_string_lookup(twa_aen_table, aen),
+ error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
header->err_specific_desc);
else
tw_dev->aen_count--;
@@ -407,7 +398,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H
static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
{
char cdb[TW_MAX_CDB_LEN];
- TW_SG_Apache sglist[1];
+ TW_SG_Entry sglist[1];
TW_Command_Full *full_command_packet;
int retval = 1;
@@ -420,7 +411,7 @@ static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
/* Initialize sglist */
- memset(&sglist, 0, sizeof(TW_SG_Apache));
+ memset(&sglist, 0, sizeof(TW_SG_Entry));
sglist[0].length = TW_SECTOR_SIZE;
sglist[0].address = tw_dev->generic_buffer_phys[request_id];
@@ -558,18 +549,18 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
u32 init_connect_result = 0;
if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
- TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL,
- TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH,
- TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl,
+ TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
+ TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
+ TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
&fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
&fw_on_ctlr_build, &init_connect_result)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
goto out;
}
- tw_dev->working_srl = TW_CURRENT_FW_SRL;
- tw_dev->working_branch = TW_CURRENT_FW_BRANCH;
- tw_dev->working_build = TW_CURRENT_FW_BUILD;
+ tw_dev->working_srl = fw_on_ctlr_srl;
+ tw_dev->working_branch = fw_on_ctlr_branch;
+ tw_dev->working_build = fw_on_ctlr_build;
/* Try base mode compatibility */
if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
@@ -584,7 +575,7 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
goto out;
}
if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
- if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {
+ if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
} else {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
@@ -641,7 +632,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
/* Now allocate ioctl buf memory */
- cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
retval = TW_IOCTL_ERROR_OS_ENOMEM;
goto out2;
@@ -679,26 +670,28 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
/* Now wait for command to complete */
- timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+ /* See if we reset while waiting for the ioctl to complete */
+ if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+ clear_bit(TW_IN_RESET, &tw_dev->flags);
+ retval = TW_IOCTL_ERROR_OS_ERESTARTSYS;
+ goto out3;
+ }
- /* Check if we timed out, got a signal, or didn't get
- an interrupt */
- if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+ /* We timed out, and didn't get an interrupt */
+ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
/* Now we need to reset the board */
- if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {
- retval = timeout;
- } else {
- printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
- tw_dev->host->host_no, TW_DRIVER, 0xc,
- cmd);
- retval = TW_IOCTL_ERROR_OS_EIO;
- }
+ printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+ tw_dev->host->host_no, TW_DRIVER, 0xc,
+ cmd);
+ retval = TW_IOCTL_ERROR_OS_EIO;
spin_lock_irqsave(tw_dev->host->host_lock, flags);
tw_dev->state[request_id] = TW_S_COMPLETED;
twa_free_request_id(tw_dev, request_id);
tw_dev->posted_request_count--;
- twa_reset_device_extension(tw_dev);
spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+ twa_reset_device_extension(tw_dev, 1);
goto out3;
}
@@ -716,10 +709,16 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
tw_ioctl->driver_command.status = 0;
/* Copy compatiblity struct into ioctl data buffer */
tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
- strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));
+ strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
tw_compat_info->working_srl = tw_dev->working_srl;
tw_compat_info->working_branch = tw_dev->working_branch;
tw_compat_info->working_build = tw_dev->working_build;
+ tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL;
+ tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+ tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD;
+ tw_compat_info->driver_srl_low = TW_BASE_FW_SRL;
+ tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH;
+ tw_compat_info->driver_build_low = TW_BASE_FW_BUILD;
break;
case TW_IOCTL_GET_LAST_EVENT:
if (tw_dev->event_queue_wrapped) {
@@ -849,7 +848,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
retval = 0;
out3:
/* Now free ioctl buf memory */
- pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
out2:
up(&tw_dev->ioctl_sem);
out:
@@ -936,8 +935,13 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_
TW_Command_Full *full_command_packet;
unsigned short error;
int retval = 1;
+ char *error_str;
full_command_packet = tw_dev->command_packet_virt[request_id];
+
+ /* Check for embedded error string */
+ error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
+
/* Don't print error for Logical unit not supported during rollcall */
error = full_command_packet->header.status_block.error;
if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
@@ -946,15 +950,17 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_
tw_dev->host->host_no,
TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
full_command_packet->header.status_block.error,
+ error_str[0] == '\0' ?
twa_string_lookup(twa_error_table,
- full_command_packet->header.status_block.error),
+ full_command_packet->header.status_block.error) : error_str,
full_command_packet->header.err_specific_desc);
else
printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
full_command_packet->header.status_block.error,
+ error_str[0] == '\0' ?
twa_string_lookup(twa_error_table,
- full_command_packet->header.status_block.error),
+ full_command_packet->header.status_block.error) : error_str,
full_command_packet->header.err_specific_desc);
}
@@ -1075,10 +1081,9 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
tw_initconnect->request_id = request_id;
tw_initconnect->message_credits = message_credits;
tw_initconnect->features = set_features;
-#if BITS_PER_LONG > 32
- /* Turn on 64-bit sgl support */
- tw_initconnect->features |= 1;
-#endif
+
+ /* Turn on 64-bit sgl support if we need to */
+ tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
if (set_features & TW_EXTENDED_INIT_CONNECT) {
tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
@@ -1173,139 +1178,142 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *re
/* Get the per adapter lock */
spin_lock(tw_dev->host->host_lock);
- /* See if the interrupt matches this instance */
- if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
+ /* Read the registers */
+ status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
- handled = 1;
+ /* Check if this is our interrupt, otherwise bail */
+ if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+ goto twa_interrupt_bail;
- /* Read the registers */
- status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+ handled = 1;
- /* Check if this is our interrupt, otherwise bail */
- if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+ /* Check controller for errors */
+ if (twa_check_bits(status_reg_value)) {
+ if (twa_decode_bits(tw_dev, status_reg_value)) {
+ TW_CLEAR_ALL_INTERRUPTS(tw_dev);
goto twa_interrupt_bail;
+ }
+ }
+
+ /* Handle host interrupt */
+ if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+ TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+ /* Handle attention interrupt */
+ if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+ TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+ if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+ twa_get_request_id(tw_dev, &request_id);
+
+ error = twa_aen_read_queue(tw_dev, request_id);
+ if (error) {
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twa_free_request_id(tw_dev, request_id);
+ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+ }
+ }
+ }
- /* Check controller for errors */
- if (twa_check_bits(status_reg_value)) {
- if (twa_decode_bits(tw_dev, status_reg_value)) {
+ /* Handle command interrupt */
+ if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+ TW_MASK_COMMAND_INTERRUPT(tw_dev);
+ /* Drain as many pending commands as we can */
+ while (tw_dev->pending_request_count > 0) {
+ request_id = tw_dev->pending_queue[tw_dev->pending_head];
+ if (tw_dev->state[request_id] != TW_S_PENDING) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
TW_CLEAR_ALL_INTERRUPTS(tw_dev);
goto twa_interrupt_bail;
}
+ if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+ tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+ tw_dev->pending_request_count--;
+ } else {
+ /* If we get here, we will continue re-posting on the next command interrupt */
+ break;
+ }
}
+ }
- /* Handle host interrupt */
- if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
- TW_CLEAR_HOST_INTERRUPT(tw_dev);
-
- /* Handle attention interrupt */
- if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
- TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
- if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
- twa_get_request_id(tw_dev, &request_id);
-
- error = twa_aen_read_queue(tw_dev, request_id);
- if (error) {
- tw_dev->state[request_id] = TW_S_COMPLETED;
- twa_free_request_id(tw_dev, request_id);
- clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+ /* Handle response interrupt */
+ if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+
+ /* Drain the response queue from the board */
+ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+ /* Complete the response */
+ response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+ request_id = TW_RESID_OUT(response_que.response_id);
+ full_command_packet = tw_dev->command_packet_virt[request_id];
+ error = 0;
+ command_packet = &full_command_packet->command.oldcommand;
+ /* Check for command packet errors */
+ if (full_command_packet->command.newcommand.status != 0) {
+ if (tw_dev->srb[request_id] != 0) {
+ error = twa_fill_sense(tw_dev, request_id, 1, 1);
+ } else {
+ /* Skip ioctl error prints */
+ if (request_id != tw_dev->chrdev_request_id) {
+ error = twa_fill_sense(tw_dev, request_id, 0, 1);
+ }
}
}
- }
- /* Handle command interrupt */
- if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
- TW_MASK_COMMAND_INTERRUPT(tw_dev);
- /* Drain as many pending commands as we can */
- while (tw_dev->pending_request_count > 0) {
- request_id = tw_dev->pending_queue[tw_dev->pending_head];
- if (tw_dev->state[request_id] != TW_S_PENDING) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+ /* Check for correct state */
+ if (tw_dev->state[request_id] != TW_S_POSTED) {
+ if (tw_dev->srb[request_id] != 0) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
TW_CLEAR_ALL_INTERRUPTS(tw_dev);
goto twa_interrupt_bail;
}
- if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
- tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
- tw_dev->pending_request_count--;
- } else {
- /* If we get here, we will continue re-posting on the next command interrupt */
- break;
- }
}
- }
- /* Handle response interrupt */
- if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
-
- /* Drain the response queue from the board */
- while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
- /* Complete the response */
- response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
- request_id = TW_RESID_OUT(response_que.response_id);
- full_command_packet = tw_dev->command_packet_virt[request_id];
- error = 0;
- command_packet = &full_command_packet->command.oldcommand;
- /* Check for command packet errors */
- if (full_command_packet->command.newcommand.status != 0) {
- if (tw_dev->srb[request_id] != 0) {
- error = twa_fill_sense(tw_dev, request_id, 1, 1);
- } else {
- /* Skip ioctl error prints */
- if (request_id != tw_dev->chrdev_request_id) {
- error = twa_fill_sense(tw_dev, request_id, 0, 1);
- }
- }
+ /* Check for internal command completion */
+ if (tw_dev->srb[request_id] == 0) {
+ if (request_id != tw_dev->chrdev_request_id) {
+ if (twa_aen_complete(tw_dev, request_id))
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+ } else {
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+ wake_up(&tw_dev->ioctl_wqueue);
}
-
- /* Check for correct state */
- if (tw_dev->state[request_id] != TW_S_POSTED) {
- if (tw_dev->srb[request_id] != 0) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
- TW_CLEAR_ALL_INTERRUPTS(tw_dev);
- goto twa_interrupt_bail;
- }
+ } else {
+ twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+ /* If no error command was a success */
+ if (error == 0) {
+ tw_dev->srb[request_id]->result = (DID_OK << 16);
}
- /* Check for internal command completion */
- if (tw_dev->srb[request_id] == 0) {
- if (request_id != tw_dev->chrdev_request_id) {
- if (twa_aen_complete(tw_dev, request_id))
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
- } else {
- tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
- wake_up(&tw_dev->ioctl_wqueue);
- }
- } else {
- twa_scsiop_execute_scsi_complete(tw_dev, request_id);
- /* If no error command was a success */
- if (error == 0) {
- tw_dev->srb[request_id]->result = (DID_OK << 16);
- }
-
- /* If error, command failed */
- if (error == 1) {
- /* Ask for a host reset */
- tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- }
+ /* If error, command failed */
+ if (error == 1) {
+ /* Ask for a host reset */
+ tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ }
- /* Now complete the io */
- tw_dev->state[request_id] = TW_S_COMPLETED;
- twa_free_request_id(tw_dev, request_id);
- tw_dev->posted_request_count--;
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
- twa_unmap_scsi_data(tw_dev, request_id);
+ /* Report residual bytes for single sgl */
+ if ((tw_dev->srb[request_id]->use_sg <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+ if (full_command_packet->command.newcommand.sg_list[0].length < tw_dev->srb[request_id]->request_bufflen)
+ tw_dev->srb[request_id]->resid = tw_dev->srb[request_id]->request_bufflen - full_command_packet->command.newcommand.sg_list[0].length;
}
- /* Check for valid status after each drain */
- status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
- if (twa_check_bits(status_reg_value)) {
- if (twa_decode_bits(tw_dev, status_reg_value)) {
- TW_CLEAR_ALL_INTERRUPTS(tw_dev);
- goto twa_interrupt_bail;
- }
+ /* Now complete the io */
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twa_free_request_id(tw_dev, request_id);
+ tw_dev->posted_request_count--;
+ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+ twa_unmap_scsi_data(tw_dev, request_id);
+ }
+
+ /* Check for valid status after each drain */
+ status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+ if (twa_check_bits(status_reg_value)) {
+ if (twa_decode_bits(tw_dev, status_reg_value)) {
+ TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+ goto twa_interrupt_bail;
}
}
}
}
+
twa_interrupt_bail:
spin_unlock(tw_dev->host->host_lock);
return IRQ_RETVAL(handled);
@@ -1320,9 +1328,12 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
newcommand = &full_command_packet->command.newcommand;
- newcommand->request_id = request_id;
+ newcommand->request_id__lunl =
+ TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
newcommand->sg_list[0].length = length;
+ newcommand->sgl_entries__lunh =
+ TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1);
} else {
oldcommand = &full_command_packet->command.oldcommand;
oldcommand->request_id = request_id;
@@ -1332,6 +1343,9 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
sgl->length = length;
+
+ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+ oldcommand->size += 1;
}
}
} /* End twa_load_sgl() */
@@ -1486,7 +1500,7 @@ out:
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
{
u32 status_reg_value;
- unsigned long command_que_value;
+ dma_addr_t command_que_value;
int retval = 1;
command_que_value = tw_dev->command_packet_phys[request_id];
@@ -1517,11 +1531,13 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
goto out;
} else {
/* We successfully posted the command packet */
-#if BITS_PER_LONG > 32
- writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
-#else
- writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
-#endif
+ if (sizeof(dma_addr_t) > 4) {
+ command_que_value += TW_COMMAND_OFFSET;
+ writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+ writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+ } else {
+ writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+ }
tw_dev->state[request_id] = TW_S_POSTED;
tw_dev->posted_request_count++;
if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
@@ -1534,10 +1550,16 @@ out:
} /* End twa_post_command_packet() */
/* This function will reset a device extension */
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
{
int i = 0;
int retval = 1;
+ unsigned long flags = 0;
+
+ set_bit(TW_IN_RESET, &tw_dev->flags);
+ TW_DISABLE_INTERRUPTS(tw_dev);
+ TW_MASK_COMMAND_INTERRUPT(tw_dev);
+ spin_lock_irqsave(tw_dev->host->host_lock, flags);
/* Abort all requests that are in progress */
for (i = 0; i < TW_Q_LENGTH; i++) {
@@ -1564,16 +1586,21 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
tw_dev->pending_head = TW_Q_START;
tw_dev->pending_tail = TW_Q_START;
tw_dev->reset_print = 0;
- tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
- tw_dev->flags = 0;
- TW_DISABLE_INTERRUPTS(tw_dev);
+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
if (twa_reset_sequence(tw_dev, 1))
goto out;
- TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+ TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+ /* Wake up any ioctl that was pending before the reset */
+ if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
+ clear_bit(TW_IN_RESET, &tw_dev->flags);
+ } else {
+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+ wake_up(&tw_dev->ioctl_wqueue);
+ }
retval = 0;
out:
return retval;
@@ -1589,7 +1616,7 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
TW_SOFT_RESET(tw_dev);
/* Make sure controller is in a good state */
- if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
+ if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
do_soft_reset = 1;
tries++;
@@ -1660,38 +1687,6 @@ static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bde
return 0;
} /* End twa_scsi_biosparam() */
-/* This is the new scsi eh abort function */
-static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt)
-{
- int i;
- TW_Device_Extension *tw_dev = NULL;
- int retval = FAILED;
-
- tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-
- spin_unlock_irq(tw_dev->host->host_lock);
-
- tw_dev->num_aborts++;
-
- /* If we find any IO's in process, we have to reset the card */
- for (i = 0; i < TW_Q_LENGTH; i++) {
- if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) {
- printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n",
- tw_dev->host->host_no, TW_DRIVER, 0x2c,
- SCpnt->device->id, SCpnt->cmnd[0]);
- if (twa_reset_device_extension(tw_dev)) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort");
- goto out;
- }
- break;
- }
- }
- retval = SUCCESS;
-out:
- spin_lock_irq(tw_dev->host->host_lock);
- return retval;
-} /* End twa_scsi_eh_abort() */
-
/* This is the new scsi eh reset function */
static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
{
@@ -1704,14 +1699,14 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
tw_dev->num_resets++;
- printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no);
+ printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
/* Now reset the card and some of the device extension data */
- if (twa_reset_device_extension(tw_dev)) {
+ if (twa_reset_device_extension(tw_dev, 0)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
goto out;
}
- printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no);
+
retval = SUCCESS;
out:
spin_lock_irq(tw_dev->host->host_lock);
@@ -1724,6 +1719,14 @@ static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
int request_id, retval;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+ /* Check if this FW supports luns */
+ if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
+ SCpnt->result = (DID_BAD_TARGET << 16);
+ done(SCpnt);
+ retval = 0;
+ goto out;
+ }
+
/* Save done function into scsi_cmnd struct */
SCpnt->scsi_done = done;
@@ -1748,12 +1751,12 @@ static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
done(SCpnt);
retval = 0;
}
-
+out:
return retval;
} /* End twa_scsi_queue() */
/* This function hands scsi cdb's to the firmware */
-static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg)
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
{
TW_Command_Full *full_command_packet;
TW_Command_Apache *command_packet;
@@ -1787,12 +1790,16 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
else
memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
- if (srb)
+ if (srb) {
command_packet->unit = srb->device->id;
- else
+ command_packet->request_id__lunl =
+ TW_REQ_LUN_IN(srb->device->lun, request_id);
+ } else {
+ command_packet->request_id__lunl =
+ TW_REQ_LUN_IN(0, request_id);
command_packet->unit = 0;
+ }
- command_packet->request_id = request_id;
command_packet->sgl_offset = 16;
if (!sglistarg) {
@@ -1809,7 +1816,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
command_packet->sg_list[0].address = buffaddr;
command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
}
- command_packet->sgl_entries = 1;
+ command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), 1);
if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
@@ -1818,19 +1825,24 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
}
if (tw_dev->srb[request_id]->use_sg > 0) {
- sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
- if (sg_count == 0)
- goto out;
-
- for (i = 0; i < sg_count; i++) {
- command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
- command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
- if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+ if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+ command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+ command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+ } else {
+ sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+ if (sg_count == 0)
goto out;
+
+ for (i = 0; i < sg_count; i++) {
+ command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+ command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+ if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+ goto out;
+ }
}
}
- command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg;
+ command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg);
}
} else {
/* Internal cdb post */
@@ -1842,7 +1854,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
goto out;
}
}
- command_packet->sgl_entries = use_sg;
+ command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg);
}
if (srb) {
@@ -1903,7 +1915,7 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev)
}
/* Clear all interrupts just before exit */
- TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+ TW_CLEAR_ALL_INTERRUPTS(tw_dev);
} /* End __twa_shutdown() */
/* Wrapper for __twa_shutdown */
@@ -1946,9 +1958,9 @@ static struct scsi_host_template driver_template = {
.module = THIS_MODULE,
.name = "3ware 9000 Storage Controller",
.queuecommand = twa_scsi_queue,
- .eh_abort_handler = twa_scsi_eh_abort,
.eh_host_reset_handler = twa_scsi_eh_reset,
.bios_param = twa_scsi_biosparam,
+ .change_queue_depth = twa_change_queue_depth,
.can_queue = TW_Q_LENGTH-2,
.this_id = -1,
.sg_tablesize = TW_APACHE_MAX_SGL_LENGTH,
@@ -1956,7 +1968,6 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = twa_host_attrs,
- .sdev_attrs = twa_dev_attrs,
.emulated = 1
};
@@ -1976,7 +1987,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
pci_set_master(pdev);
- retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+ retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
if (retval) {
TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
goto out_disable_device;
@@ -2028,8 +2039,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
host->max_id = TW_MAX_UNITS;
host->max_cmd_len = TW_MAX_CDB_LEN;
- /* Luns and channels aren't supported by adapter */
- host->max_lun = 0;
+ /* Channels aren't supported by adapter */
+ host->max_lun = TW_MAX_LUNS(tw_dev->working_srl);
host->max_channel = 0;
/* Register the card with the kernel SCSI layer */
@@ -2095,23 +2106,24 @@ static void twa_remove(struct pci_dev *pdev)
scsi_remove_host(tw_dev->host);
- __twa_shutdown(tw_dev);
+ /* Unregister character device */
+ if (twa_major >= 0) {
+ unregister_chrdev(twa_major, "twa");
+ twa_major = -1;
+ }
/* Free up the IRQ */
free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+ /* Shutdown the card */
+ __twa_shutdown(tw_dev);
+
/* Free up the mem region */
pci_release_regions(pdev);
/* Free up device extension resources */
twa_free_device_extension(tw_dev);
- /* Unregister character device */
- if (twa_major >= 0) {
- unregister_chrdev(twa_major, "twa");
- twa_major = -1;
- }
-
scsi_host_put(tw_dev->host);
pci_disable_device(pdev);
twa_device_extension_count--;
@@ -2139,7 +2151,7 @@ static struct pci_driver twa_driver = {
/* This function is called on driver initialization */
static int __init twa_init(void)
{
- printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version);
+ printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
return pci_module_init(&twa_driver);
} /* End twa_init() */
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 29f70d531744c..8c8ecbed3b587 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -3,7 +3,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
- Copyright (C) 2004 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2005 Applied Micro Circuits 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
@@ -293,7 +293,6 @@ static twa_message_type twa_error_table[] = {
#define TW_RESPONSE_ID_MASK 0x00000FF0
/* PCI related defines */
-#define TW_DEVICE_NAME "3w-9xxx"
#define TW_NUMDEVICES 1
#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
#define TW_PCI_CLEAR_PCI_ABORT 0x2000
@@ -325,9 +324,9 @@ static twa_message_type twa_error_table[] = {
/* Compatibility defines */
#define TW_9000_ARCH_ID 0x5
-#define TW_CURRENT_FW_SRL 24
-#define TW_CURRENT_FW_BUILD 5
-#define TW_CURRENT_FW_BRANCH 1
+#define TW_CURRENT_DRIVER_SRL 28
+#define TW_CURRENT_DRIVER_BUILD 9
+#define TW_CURRENT_DRIVER_BRANCH 4
/* Phase defines */
#define TW_PHASE_INITIAL 0
@@ -346,19 +345,10 @@ static twa_message_type twa_error_table[] = {
#define TW_BUNDLED_FW_SAFE_TO_FLASH 0x4
#define TW_CTLR_FW_RECOMMENDS_FLASH 0x8
#define TW_CTLR_FW_COMPATIBLE 0x2
-#define TW_BASE_FW_SRL 0x17
+#define TW_BASE_FW_SRL 24
#define TW_BASE_FW_BRANCH 0
#define TW_BASE_FW_BUILD 1
-#if BITS_PER_LONG > 32
-#define TW_APACHE_MAX_SGL_LENGTH 72
-#define TW_ESCALADE_MAX_SGL_LENGTH 41
-#define TW_APACHE_CMD_PKT_SIZE 5
-#else
-#define TW_APACHE_MAX_SGL_LENGTH 109
-#define TW_ESCALADE_MAX_SGL_LENGTH 62
-#define TW_APACHE_CMD_PKT_SIZE 4
-#endif
-#define TW_ATA_PASS_SGL_MAX 60
+#define TW_FW_SRL_LUNS_SUPPORTED 28
#define TW_Q_LENGTH 256
#define TW_Q_START 0
#define TW_MAX_SLOT 32
@@ -366,7 +356,7 @@ static twa_message_type twa_error_table[] = {
#define TW_MAX_CMDS_PER_LUN 254
#define TW_MAX_RESPONSE_DRAIN 256
#define TW_MAX_AEN_DRAIN 40
-#define TW_IN_IOCTL 2
+#define TW_IN_RESET 2
#define TW_IN_CHRDEV_IOCTL 3
#define TW_IN_ATTENTION_LOOP 4
#define TW_MAX_SECTORS 256
@@ -424,13 +414,6 @@ static twa_message_type twa_error_table[] = {
#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER
#define TW_MESSAGE_SOURCE_LINUX_OS 9
#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS
-#if BITS_PER_LONG > 32
-#define TW_COMMAND_SIZE 5
-#define TW_DMA_MASK DMA_64BIT_MASK
-#else
-#define TW_COMMAND_SIZE 4
-#define TW_DMA_MASK DMA_32BIT_MASK
-#endif
#ifndef PCI_DEVICE_ID_3WARE_9000
#define PCI_DEVICE_ID_3WARE_9000 0x1002
#endif
@@ -451,14 +434,14 @@ static twa_message_type twa_error_table[] = {
/* reserved_1: 4, response_id: 8, reserved_2: 20 */
#define TW_RESID_OUT(x) ((x >> 4) & 0xff)
+/* request_id: 12, lun: 4 */
+#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff))
+#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
+
/* Macros */
#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
#define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
-#if BITS_PER_LONG > 32
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x20)
-#else
-#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x8)
-#endif
+#define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
@@ -480,12 +463,17 @@ printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,
else \
printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
}
+#define TW_MAX_LUNS(srl) (srl < TW_FW_SRL_LUNS_SUPPORTED ? 1 : 16)
+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 5 : 4)
+#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109)
+#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62)
+#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0)
#pragma pack(1)
/* Scatter Gather List Entry */
typedef struct TAG_TW_SG_Entry {
- unsigned long address;
+ dma_addr_t address;
u32 length;
} TW_SG_Entry;
@@ -506,42 +494,27 @@ typedef struct TW_Command {
struct {
u32 lba;
TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
- u32 padding[2]; /* pad to 512 bytes */
-#else
- u32 padding;
-#endif
+ dma_addr_t padding;
} io;
struct {
TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
- u32 padding[3];
-#else
- u32 padding[2];
-#endif
+ u32 padding;
+ dma_addr_t padding2;
} param;
} byte8_offset;
} TW_Command;
-/* Scatter gather element for 9000+ controllers */
-typedef struct TAG_TW_SG_Apache {
- unsigned long address;
- u32 length;
-} TW_SG_Apache;
-
/* Command Packet for 9000+ controllers */
typedef struct TAG_TW_Command_Apache {
unsigned char opcode__reserved;
unsigned char unit;
- unsigned short request_id;
+ unsigned short request_id__lunl;
unsigned char status;
unsigned char sgl_offset;
- unsigned short sgl_entries;
+ unsigned short sgl_entries__lunh;
unsigned char cdb[16];
- TW_SG_Apache sg_list[TW_APACHE_MAX_SGL_LENGTH];
-#if BITS_PER_LONG > 32
- unsigned char padding[8];
-#endif
+ TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
+ unsigned char padding[TW_PADDING_LENGTH];
} TW_Command_Apache;
/* New command packet header */
@@ -652,14 +625,20 @@ typedef struct TAG_TW_Compatibility_Info
unsigned short working_srl;
unsigned short working_branch;
unsigned short working_build;
+ unsigned short driver_srl_high;
+ unsigned short driver_branch_high;
+ unsigned short driver_build_high;
+ unsigned short driver_srl_low;
+ unsigned short driver_branch_low;
+ unsigned short driver_build_low;
} TW_Compatibility_Info;
typedef struct TAG_TW_Device_Extension {
u32 __iomem *base_addr;
unsigned long *generic_buffer_virt[TW_Q_LENGTH];
- unsigned long generic_buffer_phys[TW_Q_LENGTH];
+ dma_addr_t generic_buffer_phys[TW_Q_LENGTH];
TW_Command_Full *command_packet_virt[TW_Q_LENGTH];
- unsigned long command_packet_phys[TW_Q_LENGTH];
+ dma_addr_t command_packet_phys[TW_Q_LENGTH];
struct pci_dev *tw_pci_dev;
struct scsi_cmnd *srb[TW_Q_LENGTH];
unsigned char free_queue[TW_Q_LENGTH];
@@ -675,7 +654,6 @@ typedef struct TAG_TW_Device_Extension {
unsigned int max_pending_request_count;
unsigned int max_sgl_entries;
unsigned int sgl_entries;
- unsigned int num_aborts;
unsigned int num_resets;
unsigned int sector_count;
unsigned int max_sector_count;