[UBUNTU:scsi/3w-9xxx] Support for 3w-9650 and couple of fixes

Ante Karamatić ivoks at grad.hr
Thu Feb 15 03:37:46 UTC 2007


This is patch against dapper tree.

commit 22ad8f8dec6707eb6419d1c04ecd5976b5253a77
Author:  <ivoks at backup.(none)>
Date:   Thu Feb 15 03:51:55 2007 +0100

    [UBUNTU:scsi/3w-9xxx] Support for 3w-9650 and couple of fixes
    
    This update adds support for new 3ware 9650 controler and fixes
couple of issues in 3w-9xxx driver.
    
    Signed-off-by:  <ivoks at ubuntu.com>


 3w-9xxx.c |  285
+++++++++++++++++++++++++++++++++-----------------------------
 3w-9xxx.h |   32 +++---
 2 files changed, 170 insertions(+), 147 deletions(-)

diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index c53b3cc..09a2678 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -2,8 +2,9 @@
    3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
 
    Written By: Adam Radford <linuxraid at amcc.com>
+   Modifications By: Tom Couch <linuxraid at amcc.com>
 
-   Copyright (C) 2004-2005 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2006 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
@@ -61,6 +62,13 @@
                  Add support for embedded firmware error strings.
    2.26.02.003 - Correctly handle single sgl's with use_sg=1.
    2.26.02.004 - Add support for 9550SX controllers.
+   2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
+   2.26.02.006 - Fix 9550SX pchip reset timeout.
+                 Add big endian support.
+   2.26.02.007 - Disable local interrupts during kmap/unmap_atomic().
+   2.26.06.001 - Free irq handler in __twa_shutdown().
+                 Serialize reset code.
+                 Add support for 9650SE controllers.
 */
 
 #include <linux/module.h>
@@ -83,7 +91,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.004"
+#define TW_DRIVER_VERSION "2.26.06.001-2.6.15"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -206,7 +214,7 @@ static int twa_aen_complete(TW_Device_Ex
 
 	header = (TW_Command_Apache_Header
*)tw_dev->generic_buffer_virt[request_id];
 	tw_dev->posted_request_count--;
-	aen = header->status_block.error;
+	aen = le16_to_cpu(header->status_block.error);
 	full_command_packet = tw_dev->command_packet_virt[request_id];
 	command_packet = &full_command_packet->command.oldcommand;
 
@@ -303,7 +311,7 @@ static int twa_aen_drain_queue(TW_Device
 
 		tw_dev->posted_request_count--;
 		header = (TW_Command_Apache_Header
*)tw_dev->generic_buffer_virt[request_id];
-		aen = header->status_block.error;
+		aen = le16_to_cpu(header->status_block.error);
 		queue = 0;
 		count++;
 
@@ -363,7 +371,7 @@ static void twa_aen_queue_event(TW_Devic
 			tw_dev->aen_clobber = 1;
 	}
 
-	aen = header->status_block.error;
+	aen = le16_to_cpu(header->status_block.error);
 	memset(event, 0, sizeof(TW_Event));
 
 	event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
@@ -380,7 +388,7 @@ static void twa_aen_queue_event(TW_Devic
 
 	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);
+	memcpy(event->parameter_data, header->err_specific_desc,
event->parameter_len + (error_str[0] == '\0' ? 0 : (1 +
strlen(error_str))));
 	if (event->severity != TW_AEN_SEVERITY_DEBUG)
 		printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
 		       host,
@@ -460,24 +468,24 @@ static void twa_aen_sync_time(TW_Device_
 	command_packet = &full_command_packet->command.oldcommand;
 	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
 	command_packet->request_id = request_id;
-	command_packet->byte8_offset.param.sgl[0].address =
tw_dev->generic_buffer_phys[request_id];
-	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+	command_packet->byte8_offset.param.sgl[0].address =
TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
+	command_packet->byte8_offset.param.sgl[0].length =
cpu_to_le32(TW_SECTOR_SIZE);
 	command_packet->size = TW_COMMAND_SIZE;
-	command_packet->byte6_offset.parameter_count = 1;
+	command_packet->byte6_offset.parameter_count = cpu_to_le16(1);
 
 	/* Setup the param */
 	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
 	memset(param, 0, TW_SECTOR_SIZE);
-	param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep
table */
-	param->parameter_id = 0x3; /* SchedulerTime */
-	param->parameter_size_bytes = 4;
+	param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /*
Controller time keep table */
+	param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */
+	param->parameter_size_bytes = cpu_to_le16(4);
 
 	/* Convert system time in UTC to local time seconds since last 
            Sunday 12:00AM */
 	do_gettimeofday(&utc);
 	local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
 	schedulertime = local_time - (3 * 86400);
-	schedulertime = schedulertime % 604800;
+	schedulertime = cpu_to_le32(schedulertime % 604800);
 
 	memcpy(param->data, &schedulertime, sizeof(u32));
 
@@ -560,9 +568,9 @@ static int twa_check_srl(TW_Device_Exten
 		goto out;
 	}
 
-	tw_dev->working_srl = fw_on_ctlr_srl;
-	tw_dev->working_branch = fw_on_ctlr_branch;
-	tw_dev->working_build = fw_on_ctlr_build;
+	tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl;
+	tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch;
+	tw_dev->tw_compat_info.working_build = fw_on_ctlr_build;
 
 	/* Try base mode compatibility */
 	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
@@ -584,10 +592,23 @@ static int twa_check_srl(TW_Device_Exten
 			}
 			goto out;
 		}
-		tw_dev->working_srl = TW_BASE_FW_SRL;
-		tw_dev->working_branch = TW_BASE_FW_BRANCH;
-		tw_dev->working_build = TW_BASE_FW_BUILD;
-	}
+		tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL;
+		tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH;
+		tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD;
+	}
+
+	/* Load rest of compatibility struct */
+	strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION,
strlen(TW_DRIVER_VERSION));
+	tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
+	tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+	tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
+	tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL;
+	tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH;
+	tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD;
+	tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl;
+	tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch;
+	tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build;
+
 	retval = 0;
 out:
 	return retval;
@@ -625,7 +646,7 @@ static int twa_chrdev_ioctl(struct inode
 		goto out2;
 
 	/* Check data buffer size */
-	if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+	if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) {
 		retval = TW_IOCTL_ERROR_OS_EINVAL;
 		goto out2;
 	}
@@ -674,13 +695,6 @@ static int twa_chrdev_ioctl(struct inode
 		/* Now wait for command to complete */
 		timeout = wait_event_timeout(tw_dev->ioctl_wqueue,
tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
 
-		/* See if we reset while waiting for the ioctl to complete */
-		if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
-			clear_bit(TW_IN_RESET, &tw_dev->flags);
-			retval = TW_IOCTL_ERROR_OS_ERESTARTSYS;
-			goto out3;
-		}
-
 		/* We timed out, and didn't get an interrupt */
 		if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
 			/* Now we need to reset the board */
@@ -688,11 +702,6 @@ static int twa_chrdev_ioctl(struct inode
 			       tw_dev->host->host_no, TW_DRIVER, 0xc,
 			       cmd);
 			retval = TW_IOCTL_ERROR_OS_EIO;
-			spin_lock_irqsave(tw_dev->host->host_lock, flags);
-			tw_dev->state[request_id] = TW_S_COMPLETED;
-			twa_free_request_id(tw_dev, request_id);
-			tw_dev->posted_request_count--;
-			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 			twa_reset_device_extension(tw_dev, 1);
 			goto out3;
 		}
@@ -711,16 +720,7 @@ static int twa_chrdev_ioctl(struct inode
 		tw_ioctl->driver_command.status = 0;
 		/* Copy compatiblity struct into ioctl data buffer */
 		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
-		strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION,
strlen(TW_DRIVER_VERSION));
-		tw_compat_info->working_srl = tw_dev->working_srl;
-		tw_compat_info->working_branch = tw_dev->working_branch;
-		tw_compat_info->working_build = tw_dev->working_build;
-		tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL;
-		tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
-		tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD;
-		tw_compat_info->driver_srl_low = TW_BASE_FW_SRL;
-		tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH;
-		tw_compat_info->driver_build_low = TW_BASE_FW_BUILD;
+		memcpy(tw_compat_info, &tw_dev->tw_compat_info,
sizeof(TW_Compatibility_Info));
 		break;
 	case TW_IOCTL_GET_LAST_EVENT:
 		if (tw_dev->event_queue_wrapped) {
@@ -889,7 +889,8 @@ static int twa_decode_bits(TW_Device_Ext
 	}
 
 	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
-		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error:
clearing");
+		if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!
test_bit(TW_IN_RESET, &tw_dev->flags)))
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error:
clearing");
 		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
 	}
 
@@ -929,26 +930,21 @@ out:
 /* This function will clear the pchip/response queue on 9550SX */
 static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
 {
-	u32 status_reg_value, response_que_value;
-	int count = 0, retval = 1;
-
-	if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) {
-		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	u32 response_que_value = 0;
+	unsigned long before;
+	int retval = 1;
 
-		while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) &&
(count < TW_MAX_RESPONSE_DRAIN)) {
+	if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) ||
+	    (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) {
+		before = jiffies;
+		while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) !=
TW_9550SX_DRAIN_COMPLETED) {
 			response_que_value =
readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
-			if ((response_que_value & TW_9550SX_DRAIN_COMPLETED) ==
TW_9550SX_DRAIN_COMPLETED) {
-				/* P-chip settle time */
-				msleep(500);
-				retval = 0;
+			msleep(1);
+			if (time_after(jiffies, before + HZ * 30))
 				goto out;
-			}
-			status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
-			count++;
 		}
-		if (count == TW_MAX_RESPONSE_DRAIN)
-			goto out;
-		
+		/* P-chip settle time */
+		msleep(500);
 		retval = 0;
 	} else
 		retval = 0;
@@ -970,7 +966,7 @@ static int twa_fill_sense(TW_Device_Exte
 	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;
+	error = le16_to_cpu(full_command_packet->header.status_block.error);
 	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error !=
TW_ERROR_UNIT_OFFLINE)) {
 		if (print_host)
 			printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%
s.\n",
@@ -1028,7 +1024,7 @@ static void twa_free_request_id(TW_Devic
 	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
 } /* End twa_free_request_id() */
 
-/* This function will get parameter table entires from the firmware */
+/* This function will get parameter table entries from the firmware */
 static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id,
int table_id, int parameter_id, int parameter_size_bytes)
 {
 	TW_Command_Full *full_command_packet;
@@ -1045,18 +1041,18 @@ static void *twa_get_param(TW_Device_Ext
 	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
 	command_packet->size              = TW_COMMAND_SIZE;
 	command_packet->request_id        = request_id;
-	command_packet->byte6_offset.block_count = 1;
+	command_packet->byte6_offset.block_count = cpu_to_le16(1);
 
 	/* Now setup the param */
 	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
 	memset(param, 0, TW_SECTOR_SIZE);
-	param->table_id = table_id | 0x8000;
-	param->parameter_id = parameter_id;
-	param->parameter_size_bytes = parameter_size_bytes;
+	param->table_id = cpu_to_le16(table_id | 0x8000);
+	param->parameter_id = cpu_to_le16(parameter_id);
+	param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
 	param_value = tw_dev->generic_buffer_phys[request_id];
 
-	command_packet->byte8_offset.param.sgl[0].address = param_value;
-	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+	command_packet->byte8_offset.param.sgl[0].address =
TW_CPU_TO_SGL(param_value);
+	command_packet->byte8_offset.param.sgl[0].length =
cpu_to_le32(TW_SECTOR_SIZE);
 
 	/* Post the command packet to the board */
 	twa_post_command_packet(tw_dev, request_id, 1);
@@ -1105,18 +1101,20 @@ static int twa_initconnection(TW_Device_
 	tw_initconnect = (TW_Initconnect
*)&full_command_packet->command.oldcommand;
 	tw_initconnect->opcode__reserved = TW_OPRES_IN(0,
TW_OP_INIT_CONNECTION);
 	tw_initconnect->request_id = request_id;
-	tw_initconnect->message_credits = message_credits;
+	tw_initconnect->message_credits = cpu_to_le16(message_credits);
 	tw_initconnect->features = set_features;
 
 	/* Turn on 64-bit sgl support if we need to */
 	tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
 
+	tw_initconnect->features = cpu_to_le32(tw_initconnect->features);
+
 	if (set_features & TW_EXTENDED_INIT_CONNECT) {
 		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
-		tw_initconnect->fw_srl = current_fw_srl;
-		tw_initconnect->fw_arch_id = current_fw_arch_id;
-		tw_initconnect->fw_branch = current_fw_branch;
-		tw_initconnect->fw_build = current_fw_build;
+		tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl);
+		tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id);
+		tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch);
+		tw_initconnect->fw_build = cpu_to_le16(current_fw_build);
 	} else 
 		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
 
@@ -1128,11 +1126,11 @@ static int twa_initconnection(TW_Device_
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during
init connection");
 	} else {
 		if (set_features & TW_EXTENDED_INIT_CONNECT) {
-			*fw_on_ctlr_srl = tw_initconnect->fw_srl;
-			*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;
-			*fw_on_ctlr_branch = tw_initconnect->fw_branch;
-			*fw_on_ctlr_build = tw_initconnect->fw_build;
-			*init_connect_result = tw_initconnect->result;
+			*fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl);
+			*fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id);
+			*fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch);
+			*fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build);
+			*init_connect_result = le32_to_cpu(tw_initconnect->result);
 		}
 		retval = 0;
 	}
@@ -1213,6 +1211,10 @@ static irqreturn_t twa_interrupt(int irq
 
 	handled = 1;
 
+	/* If we are resetting, bail */
+	if (test_bit(TW_IN_RESET, &tw_dev->flags))
+		goto twa_interrupt_bail;
+
 	/* Check controller for errors */
 	if (twa_check_bits(status_reg_value)) {
 		if (twa_decode_bits(tw_dev, status_reg_value)) {
@@ -1354,12 +1356,12 @@ static void twa_load_sgl(TW_Command_Full
 
 	if
(TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) ==
TW_OP_EXECUTE_SCSI) {
 		newcommand = &full_command_packet->command.newcommand;
-		newcommand->request_id__lunl = 
-			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
-		newcommand->sg_list[0].address = dma_handle +
sizeof(TW_Ioctl_Buf_Apache) - 1;
-		newcommand->sg_list[0].length = length;
+		newcommand->request_id__lunl =
+			cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl),
request_id));
+		newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle +
sizeof(TW_Ioctl_Buf_Apache) - 1);
+		newcommand->sg_list[0].length = cpu_to_le32(length);
 		newcommand->sgl_entries__lunh =
-			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1);
+			cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh),
1));
 	} else {
 		oldcommand = &full_command_packet->command.oldcommand;
 		oldcommand->request_id = request_id;
@@ -1367,8 +1369,8 @@ static void twa_load_sgl(TW_Command_Full
 		if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
 			/* Load the sg list */
 			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;
+			sgl->address = TW_CPU_TO_SGL(dma_handle +
sizeof(TW_Ioctl_Buf_Apache) - 1);
+			sgl->length = cpu_to_le32(length);
 
 			if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
 				oldcommand->size += 1;
@@ -1387,7 +1389,7 @@ static int twa_map_scsi_sg_data(TW_Devic
 	if (cmd->use_sg == 0)
 		goto out;
 
-	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg,
DMA_BIDIRECTIONAL);
+	use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg,
DMA_BIDIRECTIONAL);
 
 	if (use_sg == 0) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter
gather list");
@@ -1407,7 +1409,7 @@ static dma_addr_t twa_map_scsi_single_da
 	dma_addr_t mapping;
 	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
 	struct pci_dev *pdev = tw_dev->tw_pci_dev;
-	int retval = 0;
+	dma_addr_t retval = 0;
 
 	if (cmd->request_bufflen == 0) {
 		retval = 0;
@@ -1530,6 +1532,13 @@ static int twa_post_command_packet(TW_De
 	int retval = 1;
 
 	command_que_value = tw_dev->command_packet_phys[request_id];
+
+	/* For 9650SE write low 4 bytes first */
+	if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+		command_que_value += TW_COMMAND_OFFSET;
+		writel((u32)command_que_value,
TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
+	}
+
 	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
 
 	if (twa_check_bits(status_reg_value))
@@ -1556,13 +1565,17 @@ static int twa_post_command_packet(TW_De
 		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
 		goto out;
 	} else {
-		/* We successfully posted the command packet */
-		if (sizeof(dma_addr_t) > 4) {
-			command_que_value += TW_COMMAND_OFFSET;
-			writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
-			writel((u32)((u64)command_que_value >> 32),
TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+		if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+			/* Now write upper 4 bytes */
+			writel((u32)((u64)command_que_value >> 32),
TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
 		} else {
-			writel(TW_COMMAND_OFFSET + command_que_value,
TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+			if (sizeof(dma_addr_t) > 4) {
+				command_que_value += TW_COMMAND_OFFSET;
+				writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+				writel((u32)((u64)command_que_value >> 32),
TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+			} else {
+				writel(TW_COMMAND_OFFSET + command_que_value,
TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+			}
 		}
 		tw_dev->state[request_id] = TW_S_POSTED;
 		tw_dev->posted_request_count++;
@@ -1619,14 +1632,9 @@ static int twa_reset_device_extension(TW
 		goto out;
 
 	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+	clear_bit(TW_IN_RESET, &tw_dev->flags);
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-	/* Wake up any ioctl that was pending before the reset */
-	if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) ||
(ioctl_reset)) {
-		clear_bit(TW_IN_RESET, &tw_dev->flags);
-	} else {
-		tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-		wake_up(&tw_dev->ioctl_wqueue);
-	}
 	retval = 0;
 out:
 	return retval;
@@ -1735,6 +1743,9 @@ static int twa_scsi_eh_reset(struct scsi
 		"WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting
card.\n",
 		TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
 
+	/* Make sure we are not issuing an ioctl or resetting from ioctl */
+	down(&tw_dev->ioctl_sem);
+
 	/* Now reset the card and some of the device extension data */
 	if (twa_reset_device_extension(tw_dev, 0)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed
during scsi host reset");
@@ -1743,6 +1754,7 @@ static int twa_scsi_eh_reset(struct scsi
 
 	retval = SUCCESS;
 out:
+	up(&tw_dev->ioctl_sem);
 	return retval;
 } /* End twa_scsi_eh_reset() */
 
@@ -1752,8 +1764,14 @@ static int twa_scsi_queue(struct scsi_cm
 	int request_id, retval;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension
*)SCpnt->device->host->hostdata;
 
+	/* If we are resetting due to timed out ioctl, report as busy */
+	if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+		retval = SCSI_MLQUEUE_HOST_BUSY;
+		goto out;
+	}
+
 	/* Check if this FW supports luns */
-	if ((SCpnt->device->lun != 0) && (tw_dev->working_srl <
TW_FW_SRL_LUNS_SUPPORTED)) {
+	if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl <
TW_FW_SRL_LUNS_SUPPORTED)) {
 		SCpnt->result = (DID_BAD_TARGET << 16);
 		done(SCpnt);
 		retval = 0;
@@ -1797,7 +1815,7 @@ static int twa_scsiop_execute_scsi(TW_De
 	int i, sg_count;
 	struct scsi_cmnd *srb = NULL;
 	struct scatterlist *sglist = NULL;
-	u32 buffaddr = 0x0;
+	dma_addr_t buffaddr = 0x0;
 	int retval = 1;
 
 	if (tw_dev->srb[request_id]) {
@@ -1826,10 +1844,10 @@ static int twa_scsiop_execute_scsi(TW_De
 	if (srb) {
 		command_packet->unit = srb->device->id;
 		command_packet->request_id__lunl =
-			TW_REQ_LUN_IN(srb->device->lun, request_id);
+			cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id));
 	} else {
 		command_packet->request_id__lunl =
-			TW_REQ_LUN_IN(0, request_id);
+			cpu_to_le16(TW_REQ_LUN_IN(0, request_id));
 		command_packet->unit = 0;
 	}
 
@@ -1839,8 +1857,8 @@ static int twa_scsiop_execute_scsi(TW_De
 		/* Map sglist from scsi layer to cmd packet */
 		if (tw_dev->srb[request_id]->use_sg == 0) {
 			if (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;
+				command_packet->sg_list[0].address =
TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
+				command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
 				if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE ||
tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)
 					memcpy(tw_dev->generic_buffer_virt[request_id],
tw_dev->srb[request_id]->request_buffer,
tw_dev->srb[request_id]->request_bufflen);
 			} else {
@@ -1848,12 +1866,12 @@ static int twa_scsiop_execute_scsi(TW_De
 				if (buffaddr == 0)
 					goto out;
 
-				command_packet->sg_list[0].address = buffaddr;
-				command_packet->sg_list[0].length =
tw_dev->srb[request_id]->request_bufflen;
+				command_packet->sg_list[0].address = TW_CPU_TO_SGL(buffaddr);
+				command_packet->sg_list[0].length =
cpu_to_le32(tw_dev->srb[request_id]->request_bufflen);
 			}
-			command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun
>> 4), 1);
+			command_packet->sgl_entries__lunh =
cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), 1));
 
-			if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
+			if (command_packet->sg_list[0].address &
TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
 				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address
during execute scsi");
 				goto out;
 			}
@@ -1867,35 +1885,35 @@ static int twa_scsiop_execute_scsi(TW_De
 					memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
 					kunmap_atomic(buf - sg->offset, KM_IRQ0);
 				}
-				command_packet->sg_list[0].address =
tw_dev->generic_buffer_phys[request_id];
-				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+				command_packet->sg_list[0].address =
TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
+				command_packet->sg_list[0].length = cpu_to_le32(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) {
+					command_packet->sg_list[i].address =
TW_CPU_TO_SGL(sg_dma_address(&sglist[i]));
+					command_packet->sg_list[i].length =
cpu_to_le32(sg_dma_len(&sglist[i]));
+					if (command_packet->sg_list[i].address &
TW_CPU_TO_SGL(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__lunh = TW_REQ_LUN_IN((srb->device->lun
>> 4), tw_dev->srb[request_id]->use_sg);
+			command_packet->sgl_entries__lunh =
cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4),
tw_dev->srb[request_id]->use_sg));
 		}
 	} else {
 		/* Internal cdb post */
 		for (i = 0; i < use_sg; i++) {
-			command_packet->sg_list[i].address = sglistarg[i].address;
-			command_packet->sg_list[i].length = sglistarg[i].length;
-			if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+			command_packet->sg_list[i].address =
TW_CPU_TO_SGL(sglistarg[i].address);
+			command_packet->sg_list[i].length =
cpu_to_le32(sglistarg[i].length);
+			if (command_packet->sg_list[i].address &
TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
 				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl
address during internal post");
 				goto out;
 			}
 		}
-		command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg);
+		command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0,
use_sg));
 	}
 
 	if (srb) {
@@ -1942,9 +1960,13 @@ static void twa_scsiop_execute_scsi_comp
 		}
 		if (tw_dev->srb[request_id]->use_sg == 1) {
 			struct scatterlist *sg = (struct scatterlist
*)tw_dev->srb[request_id]->request_buffer;
-			char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+			char *buf;
+			unsigned long flags = 0;
+			local_irq_save(flags);
+			buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
 			memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
 			kunmap_atomic(buf - sg->offset, KM_IRQ0);
+			local_irq_restore(flags);
 		}
 	}
 } /* End twa_scsiop_execute_scsi_complete() */
@@ -1955,6 +1977,9 @@ static void __twa_shutdown(TW_Device_Ext
 	/* Disable interrupts */
 	TW_DISABLE_INTERRUPTS(tw_dev);
 
+	/* Free up the IRQ */
+	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
 	printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n",
tw_dev->host->host_no);
 
 	/* Tell the card we are shutting down */
@@ -2006,7 +2031,6 @@ static void twa_unmap_scsi_data(TW_Devic
 /* scsi_host_template initializer */
 static struct scsi_host_template driver_template = {
 	.module			= THIS_MODULE,
-	.proc_name		= "3w-9xxx",
 	.name			= "3ware 9000 Storage Controller",
 	.queuecommand		= twa_scsi_queue,
 	.eh_host_reset_handler	= twa_scsi_eh_reset,
@@ -2090,11 +2114,15 @@ static int __devinit twa_probe(struct pc
 		goto out_release_mem_region;
 
 	/* Set host specific parameters */
-	host->max_id = TW_MAX_UNITS;
+	if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE)
+		host->max_id = TW_MAX_UNITS_9650SE;
+	else
+		host->max_id = TW_MAX_UNITS;
+
 	host->max_cmd_len = TW_MAX_CDB_LEN;
 
 	/* Channels aren't supported by adapter */
-	host->max_lun = TW_MAX_LUNS(tw_dev->working_srl);
+	host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl);
 	host->max_channel = 0;
 
 	/* Register the card with the kernel SCSI layer */
@@ -2114,8 +2142,8 @@ static int __devinit twa_probe(struct pc
 				     TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
 	       (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
 				     TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
-	       *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
-				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH));
+	       le32_to_cpu(*(int *)twa_get_param(tw_dev, 2,
TW_INFORMATION_TABLE,
+				     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);
@@ -2166,9 +2194,6 @@ static void twa_remove(struct pci_dev *p
 		twa_major = -1;
 	}
 
-	/* Free up the IRQ */
-	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
-
 	/* Shutdown the card */
 	__twa_shutdown(tw_dev);
 
@@ -2189,6 +2214,8 @@ static struct pci_device_id twa_pci_tbl[
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 46f22cd..4935801 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -2,8 +2,9 @@
    3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
 
    Written By: Adam Radford <linuxraid at amcc.com>
+   Modifications By: Tom Couch <linuxraid at amcc.com>
 
-   Copyright (C) 2004-2005 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2006 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
@@ -287,11 +288,7 @@ static twa_message_type twa_error_table[
 #define TW_STATUS_UNEXPECTED_BITS	       0x00F00000
 #define TW_STATUS_VALID_INTERRUPT              0x00DF0000
 
-/* RESPONSE QUEUE BIT DEFINITIONS */
-#define TW_RESPONSE_ID_MASK		       0x00000FF0
-
 /* PCI related defines */
-#define TW_NUMDEVICES 1
 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
 #define TW_PCI_CLEAR_PCI_ABORT     0x2000
 
@@ -337,6 +334,7 @@ static twa_message_type twa_error_table[
 #define TW_ALIGNMENT_9000                     4  /* 4 bytes */
 #define TW_ALIGNMENT_9000_SGL                 0x3
 #define TW_MAX_UNITS			      16
+#define TW_MAX_UNITS_9650SE		      32
 #define TW_INIT_MESSAGE_CREDITS		      0x100
 #define TW_INIT_COMMAND_PACKET_SIZE	      0x3
 #define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED  0x6
@@ -356,7 +354,6 @@ static twa_message_type twa_error_table[
 #define TW_MAX_RESPONSE_DRAIN		      256
 #define TW_MAX_AEN_DRAIN		      40
 #define TW_IN_RESET                           2
-#define TW_IN_CHRDEV_IOCTL                    3
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
@@ -419,6 +416,9 @@ static twa_message_type twa_error_table[
 #ifndef PCI_DEVICE_ID_3WARE_9550SX
 #define PCI_DEVICE_ID_3WARE_9550SX 0x1003
 #endif
+#ifndef PCI_DEVICE_ID_3WARE_9650SE
+#define PCI_DEVICE_ID_3WARE_9650SE 0x1004
+#endif
 
 /* Bitmask macros to eliminate bitfields */
 
@@ -444,6 +444,7 @@ static twa_message_type twa_error_table[
 #define TW_CONTROL_REG_ADDR(x) (x->base_addr)
 #define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr +
0x4)
 #define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ?
((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem
*)x->base_addr + 0x8))
+#define TW_COMMAND_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem
*)x->base_addr + 0x20)
 #define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem
*)x->base_addr + 0xC)
 #define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem
*)x->base_addr + 0x30)
 #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT,
TW_CONTROL_REG_ADDR(x)))
@@ -471,6 +472,7 @@ printk(KERN_WARNING "3w-9xxx: ERROR: (0x
 #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)
+#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) :
cpu_to_le32(x))
 
 #pragma pack(1)
 
@@ -614,13 +616,6 @@ typedef union TAG_TW_Response_Queue {
 	u32 value;
 } TW_Response_Queue;
 
-typedef struct TAG_TW_Info {
-	char *buffer;
-	int length;
-	int offset;
-	int position;
-} TW_Info;
-
 /* Compatibility information structure */
 typedef struct TAG_TW_Compatibility_Info
 {
@@ -634,8 +629,13 @@ typedef struct TAG_TW_Compatibility_Info
 	unsigned short driver_srl_low;
 	unsigned short driver_branch_low;
 	unsigned short driver_build_low;
+	unsigned short fw_on_ctlr_srl;
+	unsigned short fw_on_ctlr_branch;
+	unsigned short fw_on_ctlr_build;
 } TW_Compatibility_Info;
 
+#pragma pack()
+
 typedef struct TAG_TW_Device_Extension {
 	u32                     __iomem *base_addr;
 	unsigned long	       	*generic_buffer_virt[TW_Q_LENGTH];
@@ -674,12 +674,8 @@ typedef struct TAG_TW_Device_Extension {
 	wait_queue_head_t	ioctl_wqueue;
 	struct semaphore	ioctl_sem;
 	char			aen_clobber;
-	unsigned short		working_srl;
-	unsigned short		working_branch;
-	unsigned short		working_build;
+	TW_Compatibility_Info	tw_compat_info;
 } TW_Device_Extension;

-#pragma pack()
-
 #endif /* _3W_9XXX_H */







More information about the kernel-team mailing list