public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/3] 3ware 5/6/7/8000 driver v1.26.02.000
@ 2004-09-09 21:21 Adam Radford
  0 siblings, 0 replies; only message in thread
From: Adam Radford @ 2004-09-09 21:21 UTC (permalink / raw)
  To: linux-scsi

diff -Naur linux-2.6.9-rc1-bk15/drivers/scsi/3w-xxxx.c linux-2.6.9-rc1-bk16/drivers/scsi/3w-xxxx.c
--- linux-2.6.9-rc1-bk15/drivers/scsi/3w-xxxx.c	2004-08-14 03:56:22.000000000 -0700
+++ linux-2.6.9-rc1-bk16/drivers/scsi/3w-xxxx.c	2004-09-08 17:41:45.000000000 -0700
@@ -1369,1263 +1288,737 @@
 
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
-	spin_lock_init(&tw_dev->tw_lock);
 	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
+	init_MUTEX(&tw_dev->ioctl_sem);
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
 	return 0;
 } /* End tw_initialize_device_extension() */
 
-/* This function will get unit info from the controller */
-int tw_initialize_units(TW_Device_Extension *tw_dev) 
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
 {
-	int found = 0;
-	unsigned char request_id = 0;
-	TW_Command *command_packet;
-	TW_Param *param;
-	int i, imax, num_units = 0;
-	unsigned long command_que_value;
-	u32 command_que_addr;
-	u32 response_que_addr;
-	TW_Response_Queue response_queue;
-	unsigned long param_value;
-	unsigned char *is_unit_present;
-
-	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
+	int use_sg;
 
-	command_que_addr = tw_dev->registers.command_que_addr;
-	response_que_addr = tw_dev->registers.response_que_addr;
-  
-	/* Setup the command packet */
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+	
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+	
+	if (use_sg == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SGLIST;
+	cmd->SCp.have_data_in = use_sg;
+	
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	dma_addr_t mapping;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+	if (mapping == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SINGLE;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
+static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+
+	switch(cmd->SCp.phase) {
+		case TW_PHASE_SINGLE:
+			pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+			break;
+		case TW_PHASE_SGLIST:
+			pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+			break;
+	}
+} /* End tw_unmap_scsi_data() */
+
+/* This function will reset a device extension */
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) 
+{
+	int i = 0;
+	struct scsi_cmnd *srb;
+	unsigned long flags = 0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
+
+	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++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) && 
+		    (tw_dev->state[i] != TW_S_INITIAL) &&
+		    (tw_dev->state[i] != TW_S_COMPLETED)) {
+			srb = tw_dev->srb[i];
+			if (srb != NULL) {
+				srb->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
+			}
+		}
+	}
+
+	/* Reset queues and counts */
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->posted_request_count = 0;
+	tw_dev->pending_request_count = 0;
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
+
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+	if (tw_reset_sequence(tw_dev)) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
+		return 1;
+	}
+	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);
+	}
+
+	return 0;
+} /* End tw_reset_device_extension() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int geom[]) 
+{
+	int heads, sectors, cylinders;
+	TW_Device_Extension *tw_dev;
+	
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
+	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+	heads = 64;
+	sectors = 32;
+	cylinders = sector_div(capacity, heads * sectors);
+
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = sector_div(capacity, heads * sectors);
+	}
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
+	geom[0] = heads;			 
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+} /* End tw_scsi_biosparam() */
+
+/* This is the new scsi eh reset function */
+static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) 
+{
+	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_resets++;
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: WARNING: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, SCpnt->device->id, SCpnt->cmnd[0]);
+
+	/* Now reset the card and some of the device extension data */
+	if (tw_reset_device_extension(tw_dev, 0)) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
+		goto out;
+	}
+
+	retval = SUCCESS;
+out:
+	spin_lock_irq(tw_dev->host->host_lock);
+	return retval;
+} /* End tw_scsi_eh_reset() */
+
+/* This function handles scsi inquiry commands */
+static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
+
+	/* Initialize command packet */
 	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 	if (command_packet == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet virtual address.\n");
 		return 1;
 	}
 	memset(command_packet, 0, sizeof(TW_Sector));
-	command_packet->byte0.opcode      = TW_OP_GET_PARAM;
-	command_packet->byte0.sgl_offset  = 2;
-	command_packet->size              = 4;
-	command_packet->request_id        = request_id;
-	command_packet->byte3.unit        = 0;
-	command_packet->byte3.host_id     = 0;
-	command_packet->status            = 0;
-	command_packet->flags             = 0;
-	command_packet->byte6.block_count = 1;
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
 
 	/* Now setup the param */
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment virtual address.\n");
 		return 1;
 	}
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
 	memset(param, 0, sizeof(TW_Sector));
-	param->table_id = 3;       /* unit summary table */
-	param->parameter_id = 3;   /* unitstatus parameter */
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
 	param->parameter_size_bytes = TW_MAX_UNITS;
 	param_value = tw_dev->alignment_physical_address[request_id];
 	if (param_value == 0) {
-		printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n");
 		return 1;
 	}
 
 	command_packet->byte8.param.sgl[0].address = param_value;
 	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-	/* Post the command packet to the board */
 	command_que_value = tw_dev->command_packet_physical_address[request_id];
 	if (command_que_value == 0) {
-		printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n");
 		return 1;
 	}
-	outl(command_que_value, command_que_addr);
 
-	/* Poll for completion */
-	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
-		response_queue.value = inl(response_que_addr);
-		request_id = (unsigned char)response_queue.u.response_id;
-		if (request_id != 0) {
-			/* unexpected request id */
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-			return 1;
-		}
-		if (command_packet->status != 0) {
-			/* bad response */
-			tw_decode_sense(tw_dev, request_id, 0);
-			return 1;
-		}
-		found = 1;
-	}
-	if (found == 0) {
-		/* response never received */
-		printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_inquiry() */
+
+/* This function is called by the isr to complete an inquiry command */
+static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *is_unit_present;
+	unsigned char *request_buffer;
+	TW_Param *param;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
+
+	/* Fill request buffer */
+	if (tw_dev->srb[request_id]->request_buffer == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n");
 		return 1;
 	}
+	request_buffer = tw_dev->srb[request_id]->request_buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+	request_buffer[1] = 0;	       /* Device type modifier */
+	request_buffer[2] = 0;	       /* No ansi/iso compliance */
+	request_buffer[4] = 31;	       /* Additional length */
+	memcpy(&request_buffer[8], "3ware   ", 8);	 /* Vendor ID */
+	sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
+	memcpy(&request_buffer[32], tw_driver_version, 3);
 
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-	is_unit_present = (unsigned char *)&(param->data[0]);
-  
-	/* Show all units present */
-	imax = TW_MAX_UNITS;
-	for(i=0; i<imax; i++) {
-		if (is_unit_present[i] == 0) {
-			tw_dev->is_unit_present[i] = FALSE;
-		} else {
-		  if (is_unit_present[i] & TW_UNIT_ONLINE) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): Unit %d found.\n", i);
-			tw_dev->is_unit_present[i] = TRUE;
-			num_units++;
-		  }
-		}
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n");
+		return 1;
 	}
-	tw_dev->num_units = num_units;
+	is_unit_present = &(param->data[0]);
 
-	if (num_units == 0) {
-		dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
-		return 1;
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
 	}
 
 	return 0;
-} /* End tw_initialize_units() */
+} /* End tw_scsiop_inquiry_complete() */
 
-/* This function is the interrupt service routine */
-static irqreturn_t tw_interrupt(int irq, void *dev_instance,
-					struct pt_regs *regs) 
+/* This function handles scsi mode_sense commands */
+static int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-	int request_id;
-	u32 status_reg_addr, status_reg_value;
-	u32 response_que_addr;
-	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
-	TW_Response_Queue response_que;
-	int error = 0, retval = 0;
-	unsigned long flags = 0;
+	TW_Param *param;
 	TW_Command *command_packet;
-	int handled = 0;
+	unsigned long command_que_value;
+	unsigned long param_value;
 
-	dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
 
-	/* See if we are already running on another processor */
-	if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
-		return IRQ_NONE;
+	/* Only page control = 0, page code = 0x8 (cache page) supported */
+	if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		tw_dev->srb[request_id]->result = (DID_OK << 16);
+		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+		return 0;
+	}
 
-	/* Get the host lock for io completions */
-	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+	/* Now read firmware cache setting for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
+		return 1;
+	}
 
-	/* See if the interrupt matches this instance */
-	if (tw_dev->tw_pci_dev->irq == irq) {
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
 
-		handled = 1;
-		/* Make sure io isn't queueing */
-		spin_lock(&tw_dev->tw_lock);
+	/* Setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
+		return 1;
+	}
 
-		/* Read the registers */
-		status_reg_addr = tw_dev->registers.status_reg_addr;
-		response_que_addr = tw_dev->registers.response_que_addr;
-		status_reg_value = inl(status_reg_addr);
-
-		/* Check if this is our interrupt, otherwise bail */
-		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
-			goto tw_interrupt_bail;
-
-		/* Check controller for errors */
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-			if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-				tw_clear_all_interrupts(tw_dev);
-				goto tw_interrupt_bail;
-			}
-		}
-
-		/* Handle host interrupt */
-		if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
-			tw_clear_host_interrupt(tw_dev);
-		}
-
-		/* Handle attention interrupt */
-		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
-			tw_clear_attention_interrupt(tw_dev);
-			tw_state_request_start(tw_dev, &request_id);
-			error = tw_aen_read_queue(tw_dev, request_id);
-			if (error) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
-				tw_dev->state[request_id] = TW_S_COMPLETED;
-				tw_state_request_finish(tw_dev, request_id);
-			}
-		}
-
-		/* Handle command interrupt */
-		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
-			/* 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) {
-					printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
-					break;
-				}
-				if (tw_post_command_packet(tw_dev, request_id)==0) {
-					if (tw_dev->pending_head == TW_Q_LENGTH-1) {
-						tw_dev->pending_head = TW_Q_START;
-					} else {
-						tw_dev->pending_head = tw_dev->pending_head + 1;
-					}
-					tw_dev->pending_request_count--;
-				} else {
-					/* If we get here, we will continue re-posting on the next command interrupt */
-					break;
-				}
-			}
-			/* If there are no more pending requests, we mask command interrupt */
-			if (tw_dev->pending_request_count == 0) 
-				tw_mask_command_interrupt(tw_dev);
-		}
-
-		/* 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) {
-				/* Read response queue register */
-				response_que.value = inl(response_que_addr);
-				request_id = response_que.u.response_id;
-				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-				error = 0;
-
-				/* Check for bad response */
-				if (command_packet->status != 0) {
-					/* If internal command, don't error, don't fill sense */
-					if (tw_dev->srb[request_id] == 0) {
-						tw_decode_sense(tw_dev, request_id, 0);
-					} else {
-						error = tw_decode_sense(tw_dev, request_id, 1);
-					}
-				}
-
-				/* Check for correct state */
-				if (tw_dev->state[request_id] != TW_S_POSTED) {
-					/* Handle timed out ioctl's */
-					if (tw_dev->srb[request_id] != 0) {
-						if (tw_dev->srb[request_id]->cmnd[0] != TW_IOCTL) {
-							printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
-							error = 1;
-						}
-					}
-				}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id;
+	param->parameter_id = 7; /* unit flags */
+	param->parameter_size_bytes = 1;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
+		return 1;
+	}
 
-				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
+		return 1;
+	}
 
-				/* Check for internal command completion */
-				if (tw_dev->srb[request_id] == 0) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					/* Check for chrdev ioctl completion */
-					if (request_id != tw_dev->chrdev_request_id) {
-						retval = tw_aen_complete(tw_dev, request_id);
-						if (retval) {
-							printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
-						}
-					} else {
-						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-						wake_up(&tw_dev->ioctl_wqueue);
-					}
-				} else {
-				switch (tw_dev->srb[request_id]->cmnd[0]) {
-					case READ_10:
-					case READ_6:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
-						break;
-					case WRITE_10:
-					case WRITE_6:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
-						break;
-					case TEST_UNIT_READY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
-						error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
-						break;
-					case INQUIRY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
-						error = tw_scsiop_inquiry_complete(tw_dev, request_id);
-						break;
-					case READ_CAPACITY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
-						error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
-						break;
-					case MODE_SENSE:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
-						error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
-						break;
-					case SYNCHRONIZE_CACHE:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
-						break;
-					case TW_IOCTL:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n");
-						error = tw_ioctl_complete(tw_dev, request_id);
-						break;
-					default:
-						printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
-						error = 1;
-					}
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+	
+	return 0;
+} /* End tw_scsiop_mode_sense() */
 
-					/* If no error command was a success */
-					if (error == 0) {
-						tw_dev->srb[request_id]->result = (DID_OK << 16);
-					}
+/* This function is called by the isr to complete a mode sense command */
+static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	unsigned char *flags;
+	unsigned char *request_buffer;
 
-					/* If error, command failed */
-					if (error == 1) {
-						/* Ask for a host reset */
-						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-					}
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
 
-					/* Now complete the io */
-					if ((error != TW_ISR_DONT_COMPLETE)) {
-						tw_dev->state[request_id] = TW_S_COMPLETED;
-						tw_state_request_finish(tw_dev, request_id);
-						tw_dev->posted_request_count--;
-						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	flags = (char *)&(param->data[0]);
+	request_buffer = tw_dev->srb[request_id]->buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
 
-						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-					}
-				}
-				
-				/* Check for valid status after each drain */
-				status_reg_value = inl(status_reg_addr);
-				if (tw_check_bits(status_reg_value)) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-					if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-						tw_clear_all_interrupts(tw_dev);
-						goto tw_interrupt_bail;
-					}
-				}
-			}
-		}
-tw_interrupt_bail:
-		spin_unlock(&tw_dev->tw_lock);
-	} else
-		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+	request_buffer[0] = 0xf;        /* mode data length */
+	request_buffer[1] = 0;          /* default medium type */
+	request_buffer[2] = 0x10;       /* dpo/fua support on */
+	request_buffer[3] = 0;          /* no block descriptors */
+	request_buffer[4] = 0x8;        /* caching page */
+	request_buffer[5] = 0xa;        /* page length */
+	if (*flags & 0x1)
+		request_buffer[6] = 0x4;        /* WCE on */
+	else
+		request_buffer[6] = 0x0;        /* WCE off */
 
-	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
-	clear_bit(TW_IN_INTR, &tw_dev->flags);
-	return IRQ_RETVAL(handled);
-} /* End tw_interrupt() */
+	return 0;
+} /* End tw_scsiop_mode_sense_complete() */
 
-/* This function handles ioctls from userspace to the driver */
-int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
+/* This function handles scsi read_capacity commands */
+static int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
 {
-	unsigned char opcode;
-	int bufflen, error = 0;
 	TW_Param *param;
-	TW_Command *command_packet, *command_save;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
 	unsigned long param_value;
-	TW_Ioctl *ioctl = NULL;
-	TW_Passthru *passthru = NULL;
-	int tw_aen_code, i, use_sg;
-	unsigned long *data_ptr;
-	int total_bytes = 0, posted = 0;
-	dma_addr_t dma_handle;
-	struct timeval before, timeout;
 
-	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
-	if (ioctl == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Request buffer NULL.\n");
-		tw_dev->state[request_id] = TW_S_COMPLETED;
-		tw_state_request_finish(tw_dev, request_id);
-		tw_dev->srb[request_id]->result = (DID_OK << 16);
-		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-		return 0;
-	}
-	bufflen = tw_dev->srb[request_id]->request_bufflen;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
 
 	/* Initialize command packet */
 	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
 	if (command_packet == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad command packet virtual address.\n");
-		tw_dev->state[request_id] = TW_S_COMPLETED;
-		tw_state_request_finish(tw_dev, request_id);
-		tw_dev->srb[request_id]->result = (DID_OK << 16);
-		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-		return 0;
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet virtual address.\n");
+		return 1;
 	}
 	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.block_count = 1;
 
-	/* Initialize param */
+	/* Now setup the param */
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment virtual address.\n");
-		tw_dev->state[request_id] = TW_S_COMPLETED;
-		tw_state_request_finish(tw_dev, request_id);
-		tw_dev->srb[request_id]->result = (DID_OK << 16);
-		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-		return 0;
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n");
+		return 1;
 	}
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
 	memset(param, 0, sizeof(TW_Sector));
-
-	dprintk(KERN_NOTICE "opcode = %d table_id = %d parameter_id = %d parameter_size_bytes = %d\n", ioctl->opcode, ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-	opcode = ioctl->opcode;
-
-	switch (opcode) {
-		case TW_OP_NOP:
-			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_NOP.\n");
-			command_packet->byte0.opcode = TW_OP_NOP;
-			break;
-		case TW_OP_GET_PARAM:
-			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n");
-			command_packet->byte0.opcode = TW_OP_GET_PARAM;
-			command_packet->byte3.unit = ioctl->unit_index;
-			param->table_id = ioctl->table_id;
-			param->parameter_id = ioctl->parameter_id;
-			param->parameter_size_bytes = ioctl->parameter_size_bytes;
-			tw_dev->ioctl_size[request_id] = ioctl->parameter_size_bytes;
-			dprintk(KERN_NOTICE "table_id = %d parameter_id = %d parameter_size_bytes %d\n", param->table_id, param->parameter_id, param->parameter_size_bytes);
-			break;
-		case TW_OP_SET_PARAM:
-			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
-			ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-			if (ioctl->data != NULL) {
-				command_packet->byte0.opcode = TW_OP_SET_PARAM;
-				param->table_id = ioctl->table_id;
-				param->parameter_id = ioctl->parameter_id;
-				param->parameter_size_bytes = ioctl->parameter_size_bytes;
-				memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
-				break;
-			} else {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-				return 1;
-			}
-		case TW_OP_AEN_LISTEN:
-			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
-			if (tw_dev->aen_head == tw_dev->aen_tail) {
-				/* aen queue empty */
-				dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Aen queue empty.\n");
-				tw_aen_code = TW_AEN_QUEUE_EMPTY;
-				memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes);
-			} else {
-				/* Copy aen queue entry to request buffer */
-				dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Returning aen 0x%x\n", tw_dev->aen_queue[tw_dev->aen_head]);
-				tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
-				memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes);
-				if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-					tw_dev->aen_head = TW_Q_START;
-				} else {
-					tw_dev->aen_head = tw_dev->aen_head + 1;
-				}
-			}
-			tw_dev->state[request_id] = TW_S_COMPLETED;
-			tw_state_request_finish(tw_dev, request_id);
-			tw_dev->srb[request_id]->result = (DID_OK << 16);
-			tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-			return 0;
-		case TW_ATA_PASSTHRU:
-			if (ioctl->data != NULL) {
-				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-				command_packet->request_id = request_id;
-			} else {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-				return 1;
-			}
-
-			passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id];
-			/* Don't load sg_list for non-data ATA cmds */
-			if ((passthru->param != 0) && (passthru->param != 0x8)) {
-				passthru->sg_list[0].length = passthru->sector_count*512;
-				if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
-					printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
-					return 1;
-				}
-				passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
-			}
-			tw_post_command_packet(tw_dev, request_id);
-			return 0;
-		case TW_CMD_PACKET:
-			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET.\n");
-			if (ioctl->data != NULL) {
-				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-				command_packet->request_id = request_id;
-				tw_post_command_packet(tw_dev, request_id);
-				return 0;
-			} else {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-				return 1;
-			}
-		case TW_CMD_PACKET_WITH_DATA:
-			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
-			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
-			if (command_save == NULL) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
-				return 1;
-			}
-			if (ioctl->data != NULL) {
-				/* Copy down the command packet */
-				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-				memcpy(command_save, ioctl->data, sizeof(TW_Command));
-				command_packet->request_id = request_id;
-
-				/* Now deal with the two possible sglists */
-				if (command_packet->byte0.sgl_offset == 2) {
-					use_sg = command_packet->size - 3;
-					for (i=0;i<use_sg;i++)
-						total_bytes+=command_packet->byte8.param.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
-
-					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
-						return 1;
-					}
-
-					/* Copy param sglist into the kernel */
-					data_ptr = tw_dev->ioctl_data[request_id];
-					for (i=0;i<use_sg;i++) {
-						if (command_packet->byte8.param.sgl[i].address != 0) {
-							error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
-							if (error) {
-								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
-								goto tw_ioctl_bail;
-							}
-						} else {
-							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
-							tw_dev->srb[request_id]->result = (DID_RESET << 16);
-							goto tw_ioctl_bail;
-						}
-						data_ptr+=command_packet->byte8.param.sgl[i].length;
-					}
-					command_packet->size = 4;
-					command_packet->byte8.param.sgl[0].address = dma_handle;
-					command_packet->byte8.param.sgl[0].length = total_bytes;
-				}
-				if (command_packet->byte0.sgl_offset == 3) {
-					use_sg = command_packet->size - 4;
-					for (i=0;i<use_sg;i++)
-						total_bytes+=command_packet->byte8.io.sgl[i].length;
-					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
-
-					if (!tw_dev->ioctl_data[request_id]) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
-						return 1;
-					}
-					if (command_packet->byte0.opcode == TW_OP_WRITE) {
-						/* Copy io sglist into the kernel */
-						data_ptr = tw_dev->ioctl_data[request_id];
-						for (i=0;i<use_sg;i++) {
-							if (command_packet->byte8.io.sgl[i].address != 0) {
-								error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
-								if (error) {
-									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
-									goto tw_ioctl_bail;
-								}
-							} else {
-								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
-								tw_dev->srb[request_id]->result = (DID_RESET << 16);
-								goto tw_ioctl_bail;
-							}
-							data_ptr+=command_packet->byte8.io.sgl[i].length;
-						}
-					}
-					command_packet->size = 5;
-					command_packet->byte8.io.sgl[0].address = dma_handle;
-					command_packet->byte8.io.sgl[0].length = total_bytes;
-				}
-
-				spin_unlock(&tw_dev->tw_lock);
-				spin_unlock_irq(tw_dev->host->host_lock);
-
-				set_bit(TW_IN_IOCTL, &tw_dev->flags);
-
-				/* Finally post the command packet */
-				tw_post_command_packet(tw_dev, request_id);
-				posted = 1;
-				do_gettimeofday(&before);
-
-			tw_ioctl_retry:
-				mdelay(TW_IOCTL_WAIT_TIME);
-				if (test_bit(TW_IN_IOCTL, &tw_dev->flags)) {
-					do_gettimeofday(&timeout);
-					if (before.tv_sec + TW_IOCTL_TIMEOUT < timeout.tv_sec) {
-						spin_lock_irq(tw_dev->host->host_lock);
-						spin_lock(&tw_dev->tw_lock);
-						goto tw_ioctl_bail;
-					} else {
-						goto tw_ioctl_retry;
-					}
-				}
-
-				spin_lock_irq(tw_dev->host->host_lock);
-				spin_lock(&tw_dev->tw_lock);
-
-				if (signal_pending(current)) {
-					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
-					tw_dev->srb[request_id]->result = (DID_OK << 16);
-					goto tw_ioctl_bail;
-				}
-
-				tw_dev->srb[request_id]->result = (DID_OK << 16);
-				/* Now copy up the param or io sglist to userspace */
-				if (command_packet->byte0.sgl_offset == 2) {
-					use_sg = command_save->size - 3;
-					data_ptr = tw_dev->ioctl_data[request_id];
-					for (i=0;i<use_sg;i++) {
-						if (command_save->byte8.param.sgl[i].address != 0) {
-							error = copy_to_user((void *)(unsigned long)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
-							if (error) {
-								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
-								goto tw_ioctl_bail;
-							}
-							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
-							data_ptr+=command_save->byte8.param.sgl[i].length;
-						} else {
-							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
-							tw_dev->srb[request_id]->result = (DID_RESET << 16);
-							goto tw_ioctl_bail;
-						}
-					}
-				}
-				if (command_packet->byte0.sgl_offset == 3) {
-					use_sg = command_save->size - 4;
-					if (command_packet->byte0.opcode == TW_OP_READ) {
-						data_ptr = tw_dev->ioctl_data[request_id];
-						for(i=0;i<use_sg;i++) {
-							if (command_save->byte8.io.sgl[i].address != 0) {
-								error = copy_to_user((void *)(unsigned long)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
-								if (error) {
-									dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
-									goto tw_ioctl_bail;
-								}
-								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
-								data_ptr+=command_save->byte8.io.sgl[i].length;
-							} else {
-								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
-								tw_dev->srb[request_id]->result = (DID_RESET << 16);
-								goto tw_ioctl_bail;
-							}
-						}
-					}
-				}
-				
-			tw_ioctl_bail:
-
-				/* Free up sglist memory */
-				if (tw_dev->ioctl_data[request_id])
-					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
-				else
-					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
-				
-				/* Now complete the io */
-				tw_dev->state[request_id] = TW_S_COMPLETED;
-				tw_state_request_finish(tw_dev, request_id);
-				if (posted)
-					tw_dev->posted_request_count--;
-				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-				return 0;
-			} else {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-				return 1;
-			}
-		default:
-			dprintk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
-			tw_dev->state[request_id] = TW_S_COMPLETED;
-			tw_state_request_finish(tw_dev, request_id);
-			tw_dev->srb[request_id]->result = (DID_OK << 16);
-			tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-			return 0;
-	}
-
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + 
+	tw_dev->srb[request_id]->device->id;
+	param->parameter_id = 4;	/* unitcapacity parameter */
+	param->parameter_size_bytes = 4;
 	param_value = tw_dev->alignment_physical_address[request_id];
 	if (param_value == 0) {
-		printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment physical address.\n");
-		tw_dev->state[request_id] = TW_S_COMPLETED;
-		tw_state_request_finish(tw_dev, request_id);
-		tw_dev->srb[request_id]->result = (DID_OK << 16);
-		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment physical address.\n");
+		return 1;
 	}
-
+  
 	command_packet->byte8.param.sgl[0].address = param_value;
 	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-	command_packet->byte0.sgl_offset = 2;
-	command_packet->size = 4;
-	command_packet->request_id = request_id;
-	command_packet->byte3.host_id = 0;
-	command_packet->status = 0;
-	command_packet->flags = 0;
-	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n");
+		return 1;
+	}
 
 	/* Now try to post the command to the board */
 	tw_post_command_packet(tw_dev, request_id);
-
+  
 	return 0;
-} /* End tw_ioctl() */
+} /* End tw_scsiop_read_capacity() */
 
-/* This function is called by the isr to complete ioctl requests */
-int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
+/* This function is called by the isr to complete a readcapacity command */
+static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id)
 {
 	unsigned char *param_data;
-	unsigned char *buff;
+	u32 capacity;
+	char *buff;
 	TW_Param *param;
-	TW_Ioctl *ioctl = NULL;
-	TW_Passthru *passthru = NULL;
-	TW_Command *command_packet;
 
-	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
-	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
+
 	buff = tw_dev->srb[request_id]->request_buffer;
 	if (buff == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n");
 		return 1;
 	}
-
-	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-	if (command_packet == NULL) {
-		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
+	memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
 		return 1;
 	}
+	param_data = &(param->data[0]);
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
+	capacity = (param_data[3] << 24) | (param_data[2] << 16) | 
+		   (param_data[1] << 8) | param_data[0];
 
-	ioctl = (TW_Ioctl *)buff;
-	switch (ioctl->opcode) {
-		case TW_ATA_PASSTHRU:
-			passthru = (TW_Passthru *)ioctl->data;
-			/* Don't return data for non-data ATA cmds */
-			if ((passthru->param != 0) && (passthru->param != 0x8))
-				memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
-			else {
-				/* For non-data cmds, return cmd pkt */
-				if (tw_dev->srb[request_id]->request_bufflen >= sizeof(TW_Command))
-					memcpy(buff, tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
-			}
-			break;
-		case TW_CMD_PACKET_WITH_DATA:
-			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
-			clear_bit(TW_IN_IOCTL, &tw_dev->flags);
-			return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
-		default:
-			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
-			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-			if (param == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Bad alignment virtual address.\n");
-				return 1;
-			}
-			param_data = &(param->data[0]);
-			memcpy(buff, param_data, tw_dev->ioctl_size[request_id]);
-	}
-	return 0;
-} /* End tw_ioctl_complete() */
+	/* Subtract one sector to fix get last sector ioctl */
+	capacity -= 1;
 
-static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
-{
-	int use_sg;
-	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
 
-	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-	
-	if (cmd->use_sg == 0)
-		return 0;
+	/* Number of LBA's */
+	buff[0] = (capacity >> 24);
+	buff[1] = (capacity >> 16) & 0xff;
+	buff[2] = (capacity >> 8) & 0xff;
+	buff[3] = capacity & 0xff;
 
-	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
-	
-	if (use_sg == 0) {
-		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
-		return 0;
-	}
+	/* Block size in bytes (512) */
+	buff[4] = (TW_BLOCK_SIZE >> 24);
+	buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
+	buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
+	buff[7] = TW_BLOCK_SIZE & 0xff;
 
-	cmd->SCp.phase = 2;
-	cmd->SCp.have_data_in = use_sg;
-	
-	return use_sg;
-} /* End tw_map_scsi_sg_data() */
+	return 0;
+} /* End tw_scsiop_read_capacity_complete() */
 
-static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+/* This function handles scsi read or write commands */
+static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
 {
-	dma_addr_t mapping;
-	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
-
-	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg;
+	struct scsi_cmnd *srb;
+	struct scatterlist *sglist;
 
-	if (cmd->request_bufflen == 0)
-		return 0;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
 
-	mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, dma_dir);
+	if (tw_dev->srb[request_id]->request_buffer == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
+		return 1;
+	}
+	sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+	srb = tw_dev->srb[request_id];
 
-	if (mapping == 0) {
-		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
-		return 0;
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n");
+		return 1;
 	}
 
-	cmd->SCp.phase = 1;
-	cmd->SCp.have_data_in = mapping;
+	if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) {
+		command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_READ);
+	} else {
+		command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_WRITE);
+	}
 
-	return mapping;
-} /* End tw_map_scsi_single_data() */
+	command_packet->size = 3;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, srb->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
 
-/* This function will mask the command interrupt */
-void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
-{
-	u32 control_reg_addr, control_reg_value;
-	
-	control_reg_addr = tw_dev->registers.control_reg_addr;
-	control_reg_value = TW_CONTROL_MASK_COMMAND_INTERRUPT;
-	outl(control_reg_value, control_reg_addr);
-} /* End tw_mask_command_interrupt() */
+	if (srb->cmnd[0] == WRITE_10) {
+		if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
+			command_packet->flags = 1;
+	}
 
-/* This function will poll the status register for a flag */
-int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
-{
-	u32 status_reg_addr, status_reg_value;
-	struct timeval before, timeout;
+	if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
+		lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
+		num_sectors = (u32)srb->cmnd[4];
+	} else {
+		lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
+		num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+	}
+  
+	/* Update sector statistic */
+	tw_dev->sector_count = num_sectors;
+	if (tw_dev->sector_count > tw_dev->max_sector_count)
+		tw_dev->max_sector_count = tw_dev->sector_count;
+  
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors);
+	command_packet->byte8.io.lba = lba;
+	command_packet->byte6.block_count = num_sectors;
 
-	status_reg_addr = tw_dev->registers.status_reg_addr;
-	do_gettimeofday(&before);
-	status_reg_value = inl(status_reg_addr);
+	/* Do this if there are no sg list entries */
+	if (tw_dev->srb[request_id]->use_sg == 0) {    
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		if (buffaddr == 0)
+			return 1;
 
-	if (tw_check_bits(status_reg_value)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value, 0);
+		command_packet->byte8.io.sgl[0].address = buffaddr;
+		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+		command_packet->size+=2;
 	}
-		
-	while ((status_reg_value & flag) != flag) {
-		status_reg_value = inl(status_reg_addr);
-
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
-		}
 
-		do_gettimeofday(&timeout);
-		if (before.tv_sec + seconds < timeout.tv_sec) { 
-			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
+	/* Do this if we have multiple sg list entries */
+	if (tw_dev->srb[request_id]->use_sg > 0) {
+		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		if (use_sg == 0)
 			return 1;
+
+		for (i=0;i<use_sg; i++) {
+			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
+			command_packet->size+=2;
 		}
-		mdelay(5);
 	}
-	return 0;
-} /* End tw_poll_status() */
 
-/* This function will poll the status register for disappearance of a flag */
-int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
-{
-	u32 status_reg_addr, status_reg_value;
-	struct timeval before, timeout;
-
-	status_reg_addr = tw_dev->registers.status_reg_addr;
-	do_gettimeofday(&before);
-	status_reg_value = inl(status_reg_addr);
+	/* Update SG statistics */
+	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+	if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+		tw_dev->max_sgl_entries = tw_dev->sgl_entries;
 
-	if (tw_check_bits(status_reg_value)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value, 0);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n");
+		return 1;
 	}
+      
+	/* Now try to post the command to the board */
+	tw_post_command_packet(tw_dev, request_id);
 
-	while ((status_reg_value & flag) != 0) {
-		status_reg_value = inl(status_reg_addr);
+	return 0;
+} /* End tw_scsiop_read_write() */
 
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value, 0);
-		}
-
-		do_gettimeofday(&timeout);
-		if (before.tv_sec + seconds < timeout.tv_sec) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n", flag);
-			return 1;
-		}
-		mdelay(5);
-	}
-	return 0;
-} /* End tw_poll_status_gone() */
-
-/* This function will attempt to post a command packet to the board */
-int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+/* This function will handle the request sense scsi command */
+static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-	u32 status_reg_addr, status_reg_value;
-	unsigned long command_que_value;
-	u32 command_que_addr;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
-	command_que_addr = tw_dev->registers.command_que_addr;
-	command_que_value = tw_dev->command_packet_physical_address[request_id];
-	status_reg_addr = tw_dev->registers.status_reg_addr;
-	status_reg_value = inl(status_reg_addr);
+	/* For now we just zero the request buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
 
-	if (tw_check_bits(status_reg_value)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value, 1);
-	}
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
 
-	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
-		/* We successfully posted the command packet */
-		outl(command_que_value, command_que_addr);
-		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) {
-			tw_dev->max_posted_request_count = tw_dev->posted_request_count;
-		}
-	} else {
-		/* Couldn't post the command packet, so we do it in the isr */
-		if (tw_dev->state[request_id] != TW_S_PENDING) {
-			tw_dev->state[request_id] = TW_S_PENDING;
-			tw_dev->pending_request_count++;
-			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
-				tw_dev->max_pending_request_count = tw_dev->pending_request_count;
-			}
-			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
-			if (tw_dev->pending_tail == TW_Q_LENGTH-1) {
-				tw_dev->pending_tail = TW_Q_START;
-			} else {
-				tw_dev->pending_tail = tw_dev->pending_tail + 1;
-			}
-		} 
-		tw_unmask_command_interrupt(tw_dev);
-		return 1;
-	}
 	return 0;
-} /* End tw_post_command_packet() */
+} /* End tw_scsiop_request_sense() */
 
-/* This function will reset a device extension */
-int tw_reset_device_extension(TW_Device_Extension *tw_dev) 
+/* This function will handle synchronize cache scsi command */
+static int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
 {
-	int imax = 0;
-	int i = 0;
-	Scsi_Cmnd *srb;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
-	imax = TW_Q_LENGTH;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
 
-	if (tw_reset_sequence(tw_dev)) {
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
+	/* Send firmware flush command for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
 		return 1;
 	}
 
-	/* Abort all requests that are in progress */
-	for (i=0;i<imax;i++) {
-		if ((tw_dev->state[i] != TW_S_FINISHED) && 
-		    (tw_dev->state[i] != TW_S_INITIAL) &&
-		    (tw_dev->state[i] != TW_S_COMPLETED)) {
-			srb = tw_dev->srb[i];
-			if (srb != NULL) {
-				srb->result = (DID_RESET << 16);
-				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
-				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
-			}
-		}
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_FLUSH_CACHE);
+	command_packet->size = 2;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
+		return 1;
 	}
 
-	/* Reset queues and counts */
-	for (i=0;i<imax;i++) {
-		tw_dev->free_queue[i] = i;
-		tw_dev->state[i] = TW_S_INITIAL;
-	}
-	tw_dev->free_head = TW_Q_START;
-	tw_dev->free_tail = TW_Q_START;
-	tw_dev->posted_request_count = 0;
-	tw_dev->pending_request_count = 0;
-	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;
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
 
 	return 0;
-} /* End tw_reset_device_extension() */
+} /* End tw_scsiop_synchronize_cache() */
 
-/* This function will reset a controller */
-int tw_reset_sequence(TW_Device_Extension *tw_dev) 
+/* This function will handle test unit ready scsi command */
+static int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
-	int error = 0;
-	int tries = 0;
-
-	/* Disable interrupts */
-	tw_disable_interrupts(tw_dev);
-
-	/* Reset the board */
-	while (tries < TW_MAX_RESET_TRIES) {
-		tw_soft_reset(tw_dev);
-
-		error = tw_aen_drain_queue(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
-			tries++;
-			continue;
-		}
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
 
-		/* Check for controller errors */
-		if (tw_check_errors(tw_dev)) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no);
-			tries++;
-			continue;
-		}
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
 
-		/* Now the controller is in a good state */
-		break;
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+		return 1;
 	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
 
-	if (tries >= TW_MAX_RESET_TRIES) {
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no);
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
 		return 1;
 	}
-
-	error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-	if (error) {
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no);
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
+	param->parameter_size_bytes = TW_MAX_UNITS;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
 		return 1;
 	}
 
-	/* Re-enable interrupts */
-	tw_enable_and_clear_interrupts(tw_dev);
-
-	return 0;
-} /* End tw_reset_sequence() */
-
-/* This funciton returns unit geometry in cylinders/heads/sectors */
-int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int geom[]) 
-{
-	int heads, sectors, cylinders;
-	TW_Device_Extension *tw_dev;
-	
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
-	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
-
-	heads = 64;
-	sectors = 32;
-	cylinders = (unsigned long)capacity / (heads * sectors);
-
-	if (capacity >= 0x200000) {
-		heads = 255;
-		sectors = 63;
-		cylinders = (unsigned long)capacity / (heads * sectors);
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+		return 1;
 	}
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
-	geom[0] = heads;			 
-	geom[1] = sectors;
-	geom[2] = cylinders;
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
 
 	return 0;
-} /* End tw_scsi_biosparam() */
-
-/* This function will find and initialize any cards */
-int tw_scsi_detect(Scsi_Host_Template *tw_host)
-{
-	int ret;
-	
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n");
-
-	printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", tw_driver_version);
-
-	ret = tw_findcards(tw_host);
-
-	return ret;
-} /* End tw_scsi_detect() */
+} /* End tw_scsiop_test_unit_ready() */
 
-/* This is the new scsi eh abort function */
-int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) 
+/* This function is called by the isr to complete a testunitready command */
+static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
 {
-	TW_Device_Extension *tw_dev=NULL;
-	int i = 0;
-
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_abort()\n");
+	unsigned char *is_unit_present;
+	TW_Param *param;
 
-	if (!SCpnt) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid Scsi_Cmnd.\n");
-		return (FAILED);
-	}
+	dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
 
-	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-	if (tw_dev == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid device extension.\n");
-		return (FAILED);
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+		return 1;
 	}
+	is_unit_present = &(param->data[0]);
 
-	spin_lock(&tw_dev->tw_lock);
-	tw_dev->num_aborts++;
-
-	/* If the command hasn't been posted yet, we can do the abort */
-	for (i=0;i<TW_Q_LENGTH;i++) {
-		if (tw_dev->srb[i] == SCpnt) {
-			if (tw_dev->state[i] == TW_S_STARTED) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-				tw_dev->state[i] = TW_S_COMPLETED;
-				tw_state_request_finish(tw_dev, i);
-				spin_unlock(&tw_dev->tw_lock);
-				return (SUCCESS);
-			}
-			if (tw_dev->state[i] == TW_S_PENDING) {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-				if (tw_dev->pending_head == TW_Q_LENGTH-1) {
-					tw_dev->pending_head = TW_Q_START;
-				} else {
-					tw_dev->pending_head = tw_dev->pending_head + 1;
-				}
-				tw_dev->pending_request_count--;
-				tw_dev->state[i] = TW_S_COMPLETED;
-				tw_state_request_finish(tw_dev, i);
-				spin_unlock(&tw_dev->tw_lock);
-				return (SUCCESS);
-			}
-			if (tw_dev->state[i] == TW_S_POSTED) {
-				/* If the command has already been posted, we have to reset the card */
-				printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-				/* We have to let AEN requests through before the reset */
-				spin_unlock(&tw_dev->tw_lock);
-				spin_unlock_irq(tw_dev->host->host_lock);
-				mdelay(TW_AEN_WAIT_TIME);
-				spin_lock_irq(tw_dev->host->host_lock);
-				spin_lock(&tw_dev->tw_lock);
-
-				if (tw_reset_device_extension(tw_dev)) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
-					spin_unlock(&tw_dev->tw_lock);
-					return (FAILED);
-				}
-			}
-		}
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
 	}
 
-	spin_unlock(&tw_dev->tw_lock);
-	return (SUCCESS);
-} /* End tw_scsi_eh_abort() */
+	return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
 
-/* This is the new scsi eh reset function */
-int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt) 
+/* This is the main scsi queue function to handle scsi opcodes */
+static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 
 {
-	TW_Device_Extension *tw_dev=NULL;
-
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_reset()\n");
-
-	if (!SCpnt) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid Scsi_Cmnd.\n");
-		return (FAILED);
-	}
-
-	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-	if (tw_dev == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid device extension.\n");
-		return (FAILED);
-	}
+	unsigned char *command = SCpnt->cmnd;
+	int request_id = 0;
+	int retval = 1;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
-	/* We have to let AEN requests through before the reset */
-	spin_unlock_irq(tw_dev->host->host_lock);
-	mdelay(TW_AEN_WAIT_TIME);
-	spin_lock_irq(tw_dev->host->host_lock);
+	/* Save done function into Scsi_Cmnd struct */
+	SCpnt->scsi_done = done;
+		 
+	/* Queue the command and get a request id */
+	tw_state_request_start(tw_dev, &request_id);
 
-	spin_lock(&tw_dev->tw_lock);
-	tw_dev->num_resets++;
+	/* Save the scsi command for use by the ISR */
+	tw_dev->srb[request_id] = SCpnt;
 
-	/* Now reset the card and some of the device extension data */
-	if (tw_reset_device_extension(tw_dev)) {
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
-		spin_unlock(&tw_dev->tw_lock);
-		return (FAILED);
-	}
-	printk(KERN_WARNING "3w-xxxx: scsi%d: Reset succeeded.\n", tw_dev->host->host_no);
-	spin_unlock(&tw_dev->tw_lock);
-
-	return (SUCCESS);
-} /* End tw_scsi_eh_reset() */
-
-/* This function handles input and output from /proc/scsi/3w-xxxx/x */
-int tw_scsi_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
-		      off_t offset, int length, int inout) 
-{
-	TW_Device_Extension *tw_dev = NULL;
-	TW_Info info;
-	int i;
-	int j;
-
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_proc_info()\n");
-
-	/* Find the correct device extension */
-	for (i=0;i<tw_device_extension_count;i++) 
-		if (tw_device_extension_list[i]->host->host_no == shost->host_no) 
-			tw_dev = tw_device_extension_list[i];
-	if (tw_dev == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n");
-		return (-EINVAL);
-	}
-
-	info.buffer = buffer;
-	info.length = length;
-	info.offset = offset;
-	info.position = 0;
-	
-	if (inout) {
-		/* Write */
-		if (strncmp(buffer, "debug", 5) == 0) {
-			printk(KERN_INFO "3w-xxxx: Posted commands:\n");
-			for (j=0;j<TW_Q_LENGTH;j++) {
-				if (tw_dev->state[j] == TW_S_POSTED) {
-					TW_Command *command = (TW_Command *)tw_dev->command_packet_virtual_address[j];
-					printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j);
-					printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode);
-					printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count);
-					printk(KERN_INFO "LBA: 0x%x\n", command->byte8.io.lba);
-					printk(KERN_INFO "Physical command packet addr: 0x%lx\n", tw_dev->command_packet_physical_address[j]);
-					printk(KERN_INFO "Scsi_Cmnd: %p\n", tw_dev->srb[j]);
-				}
-			}
-			printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head);
-			printk(KERN_INFO "3w-xxxx: Free_tail: %3d\n", tw_dev->free_tail);
-		} 
-		return length;
-	} else {
-		/* Read */
-		if (start) {
-			*start = buffer;
-		}
-		tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", shost->host_no);
-		tw_copy_info(&info, "Driver version: %s\n", tw_driver_version);
-		tw_copy_info(&info, "Current commands posted:       %3d\n", tw_dev->posted_request_count);
-		tw_copy_info(&info, "Max commands posted:           %3d\n", tw_dev->max_posted_request_count);
-		tw_copy_info(&info, "Current pending commands:      %3d\n", tw_dev->pending_request_count);
-		tw_copy_info(&info, "Max pending commands:          %3d\n", tw_dev->max_pending_request_count);
-		tw_copy_info(&info, "Last sgl length:               %3d\n", tw_dev->sgl_entries);
-		tw_copy_info(&info, "Max sgl length:                %3d\n", tw_dev->max_sgl_entries);
-		tw_copy_info(&info, "Last sector count:             %3d\n", tw_dev->sector_count);
-		tw_copy_info(&info, "Max sector count:              %3d\n", tw_dev->max_sector_count);
-		tw_copy_info(&info, "Resets:                        %3d\n", tw_dev->num_resets);
-		tw_copy_info(&info, "Aborts:                        %3d\n", tw_dev->num_aborts);
-		tw_copy_info(&info, "AEN's:                         %3d\n", tw_dev->aen_count);
-	}
-	if (info.position > info.offset) {
-		return (info.position - info.offset);
-	} else { 
-		return 0;
-	}
-} /* End tw_scsi_proc_info() */
-
-/* This is the main scsi queue function to handle scsi opcodes */
-int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) 
-{
-	unsigned char *command = SCpnt->cmnd;
-	int request_id = 0;
-	int error = 0;
-	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-
-	if (tw_dev == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
-		SCpnt->result = (DID_ERROR << 16);
-		done(SCpnt);
-		return 0;
-	}
-
-	spin_lock(&tw_dev->tw_lock);
-	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
-
-	/* Skip scsi command if it isn't for us */
-	if ((SCpnt->device->channel != 0) || (SCpnt->device->lun != 0)) {
-		SCpnt->result = (DID_BAD_TARGET << 16);
-		done(SCpnt);
-		spin_unlock(&tw_dev->tw_lock);
-		return 0;
-	}
-	
-	/* Save done function into Scsi_Cmnd struct */
-	SCpnt->scsi_done = done;
-		 
-	/* Queue the command and get a request id */
-	tw_state_request_start(tw_dev, &request_id);
-
-	/* Save the scsi command for use by the ISR */
-	tw_dev->srb[request_id] = SCpnt;
-
-	/* Initialize phase to zero */
-	SCpnt->SCp.phase = 0;
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = TW_PHASE_INITIAL;
 
 	switch (*command) {
 		case READ_10:


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-09-09 21:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-09 21:21 [PATCH 2/3] 3ware 5/6/7/8000 driver v1.26.02.000 Adam Radford

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox