| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  | ******************************************************************************* | 
					
						
							|  |  |  | **        O.S   : Linux | 
					
						
							|  |  |  | **   FILE NAME  : arcmsr_hba.c | 
					
						
							|  |  |  | **        BY    : Erich Chen | 
					
						
							|  |  |  | **   Description: SCSI RAID Device Driver for | 
					
						
							|  |  |  | **                ARECA RAID Host adapter | 
					
						
							|  |  |  | ******************************************************************************* | 
					
						
							|  |  |  | ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | **     Web site: www.areca.com.tw | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | **       E-mail: support@areca.com.tw | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | ** | 
					
						
							|  |  |  | ** This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  | ** it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  | ** published by the Free Software Foundation. | 
					
						
							|  |  |  | ** This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | ** GNU General Public License for more details. | 
					
						
							|  |  |  | ******************************************************************************* | 
					
						
							|  |  |  | ** Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  | ** modification, are permitted provided that the following conditions | 
					
						
							|  |  |  | ** are met: | 
					
						
							|  |  |  | ** 1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  | **    notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  | ** 2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  | **    notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  | **    documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  | ** 3. The name of the author may not be used to endorse or promote products | 
					
						
							|  |  |  | **    derived from this software without specific prior written permission. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 
					
						
							|  |  |  | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
					
						
							|  |  |  | ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 
					
						
							|  |  |  | ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 
					
						
							|  |  |  | ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT | 
					
						
							|  |  |  | ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  | ** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF | 
					
						
							|  |  |  | ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  | ******************************************************************************* | 
					
						
							|  |  |  | ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr | 
					
						
							|  |  |  | **     Firmware Specification, see Documentation/scsi/arcmsr_spec.txt | 
					
						
							|  |  |  | ******************************************************************************* | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/reboot.h>
 | 
					
						
							|  |  |  | #include <linux/spinlock.h>
 | 
					
						
							|  |  |  | #include <linux/pci_ids.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/moduleparam.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/delay.h>
 | 
					
						
							|  |  |  | #include <linux/dma-mapping.h>
 | 
					
						
							|  |  |  | #include <linux/timer.h>
 | 
					
						
							| 
									
										
										
										
											2010-08-16 21:20:07 -07:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | #include <linux/pci.h>
 | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | #include <linux/aer.h>
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | #include <asm/dma.h>
 | 
					
						
							|  |  |  | #include <asm/io.h>
 | 
					
						
							|  |  |  | #include <asm/system.h>
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_host.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_cmnd.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_tcq.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_device.h>
 | 
					
						
							|  |  |  | #include <scsi/scsi_transport.h>
 | 
					
						
							|  |  |  | #include <scsi/scsicam.h>
 | 
					
						
							|  |  |  | #include "arcmsr.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>"); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | MODULE_LICENSE("Dual BSD/GPL"); | 
					
						
							|  |  |  | MODULE_VERSION(ARCMSR_DRIVER_VERSION); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static int sleeptime = 10; | 
					
						
							|  |  |  | static int retrycount = 30; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | wait_queue_head_t wait_q; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, | 
					
						
							|  |  |  | 					struct scsi_cmnd *cmd); | 
					
						
							|  |  |  | static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static int arcmsr_abort(struct scsi_cmnd *); | 
					
						
							|  |  |  | static int arcmsr_bus_reset(struct scsi_cmnd *); | 
					
						
							|  |  |  | static int arcmsr_bios_param(struct scsi_device *sdev, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		struct block_device *bdev, sector_t capacity, int *info); | 
					
						
							|  |  |  | static int arcmsr_queue_command(struct scsi_cmnd *cmd, | 
					
						
							|  |  |  | 					void (*done) (struct scsi_cmnd *)); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static int arcmsr_probe(struct pci_dev *pdev, | 
					
						
							|  |  |  | 				const struct pci_device_id *id); | 
					
						
							|  |  |  | static void arcmsr_remove(struct pci_dev *pdev); | 
					
						
							|  |  |  | static void arcmsr_shutdown(struct pci_dev *pdev); | 
					
						
							|  |  |  | static void arcmsr_iop_init(struct AdapterControlBlock *acb); | 
					
						
							|  |  |  | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb); | 
					
						
							|  |  |  | static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_request_device_map(unsigned long pacb); | 
					
						
							|  |  |  | static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb); | 
					
						
							|  |  |  | static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_message_isr_bh_fn(struct work_struct *work); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB); | 
					
						
							|  |  |  | static void arcmsr_hardware_reset(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static const char *arcmsr_info(struct Scsi_Host *); | 
					
						
							|  |  |  | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, | 
					
						
							| 
									
										
										
										
											2009-10-15 17:46:39 -07:00
										 |  |  | 					  int queue_depth, int reason) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-15 17:46:39 -07:00
										 |  |  | 	if (reason != SCSI_QDEPTH_DEFAULT) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	if (queue_depth > ARCMSR_MAX_CMD_PERLUN) | 
					
						
							|  |  |  | 		queue_depth = ARCMSR_MAX_CMD_PERLUN; | 
					
						
							|  |  |  | 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); | 
					
						
							|  |  |  | 	return queue_depth; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct scsi_host_template arcmsr_scsi_host_template = { | 
					
						
							|  |  |  | 	.module			= THIS_MODULE, | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	.name			= "ARCMSR ARECA SATA/SAS RAID Controller" | 
					
						
							|  |  |  | 				ARCMSR_DRIVER_VERSION, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	.info			= arcmsr_info, | 
					
						
							|  |  |  | 	.queuecommand		= arcmsr_queue_command, | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	.eh_abort_handler		= arcmsr_abort, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	.eh_bus_reset_handler	= arcmsr_bus_reset, | 
					
						
							|  |  |  | 	.bios_param		= arcmsr_bios_param, | 
					
						
							|  |  |  | 	.change_queue_depth	= arcmsr_adjust_disk_queue_depth, | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	.can_queue		= ARCMSR_MAX_FREECCB_NUM, | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	.this_id			= ARCMSR_SCSI_INITIATOR_ID, | 
					
						
							|  |  |  | 	.sg_tablesize	        	= ARCMSR_DEFAULT_SG_ENTRIES,  | 
					
						
							|  |  |  | 	.max_sectors    	    	= ARCMSR_MAX_XFER_SECTORS_C,  | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN, | 
					
						
							|  |  |  | 	.use_clustering		= ENABLE_CLUSTERING, | 
					
						
							|  |  |  | 	.shost_attrs		= arcmsr_host_attrs, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static struct pci_device_id arcmsr_device_id_table[] = { | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, | 
					
						
							|  |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)}, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	{0, 0}, /* Terminating entry */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); | 
					
						
							|  |  |  | static struct pci_driver arcmsr_pci_driver = { | 
					
						
							|  |  |  | 	.name			= "arcmsr", | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	.id_table			= arcmsr_device_id_table, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	.probe			= arcmsr_probe, | 
					
						
							|  |  |  | 	.remove			= arcmsr_remove, | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 	.shutdown		= arcmsr_shutdown, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  | **************************************************************************** | 
					
						
							|  |  |  | **************************************************************************** | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 		struct Scsi_Host *shost = NULL; | 
					
						
							|  |  |  | 		int i, isleep; | 
					
						
							|  |  |  | 		shost = cmd->device->host; | 
					
						
							|  |  |  | 		isleep = sleeptime / 10; | 
					
						
							|  |  |  | 		if (isleep > 0) { | 
					
						
							|  |  |  | 			for (i = 0; i < isleep; i++) { | 
					
						
							|  |  |  | 				msleep(10000); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		isleep = sleeptime % 10; | 
					
						
							|  |  |  | 		if (isleep > 0) { | 
					
						
							|  |  |  | 			msleep(isleep*1000); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "wake-up\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B:{ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		dma_free_coherent(&acb->pdev->dev, | 
					
						
							|  |  |  | 			sizeof(struct MessageUnit_B), | 
					
						
							|  |  |  | 			acb->pmuB, acb->dma_coherent_handle_hbb_mu); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pci_dev *pdev = acb->pdev; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	switch (acb->adapter_type){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_A:{ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0)); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		if (!acb->pmuA) { | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B:{ | 
					
						
							|  |  |  | 		void __iomem *mem_base0, *mem_base1; | 
					
						
							|  |  |  | 		mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); | 
					
						
							|  |  |  | 		if (!mem_base0) { | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); | 
					
						
							|  |  |  | 		if (!mem_base1) { | 
					
						
							|  |  |  | 			iounmap(mem_base0); | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		acb->mem_base0 = mem_base0; | 
					
						
							|  |  |  | 		acb->mem_base1 = mem_base1; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C:{ | 
					
						
							|  |  |  | 		acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); | 
					
						
							|  |  |  | 		if (!acb->pmuC) { | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							|  |  |  | 			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/ | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_A:{ | 
					
						
							|  |  |  | 		iounmap(acb->pmuA); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B:{ | 
					
						
							|  |  |  | 		iounmap(acb->mem_base0); | 
					
						
							|  |  |  | 		iounmap(acb->mem_base1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C:{ | 
					
						
							|  |  |  | 		iounmap(acb->pmuC); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around.  On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable.  On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions.  Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller.  A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386.  I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs.  Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
	struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
	set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
	-	update_process_times(user_mode(regs));
	-	profile_tick(CPU_PROFILING, regs);
	+	update_process_times(user_mode(get_irq_regs()));
	+	profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
 (*) input_dev() is now gone entirely.  The regs pointer is no longer stored in
     the input_dev struct.
 (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking.  It does
     something different depending on whether it's been supplied with a regs
     pointer or not.
 (*) Various IRQ handler function pointers have been moved to type
     irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
											
										 
											2006-10-05 14:55:46 +01:00
										 |  |  | static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	irqreturn_t handle_state; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	struct AdapterControlBlock *acb = dev_id; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handle_state = arcmsr_interrupt(acb); | 
					
						
							|  |  |  | 	return handle_state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_bios_param(struct scsi_device *sdev, | 
					
						
							|  |  |  | 		struct block_device *bdev, sector_t capacity, int *geom) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret, heads, sectors, cylinders, total_capacity; | 
					
						
							|  |  |  | 	unsigned char *buffer;/* return copy of block device's partition table */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buffer = scsi_bios_ptable(bdev); | 
					
						
							|  |  |  | 	if (buffer) { | 
					
						
							|  |  |  | 		ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]); | 
					
						
							|  |  |  | 		kfree(buffer); | 
					
						
							|  |  |  | 		if (ret != -1) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	total_capacity = capacity; | 
					
						
							|  |  |  | 	heads = 64; | 
					
						
							|  |  |  | 	sectors = 32; | 
					
						
							|  |  |  | 	cylinders = total_capacity / (heads * sectors); | 
					
						
							|  |  |  | 	if (cylinders > 1024) { | 
					
						
							|  |  |  | 		heads = 255; | 
					
						
							|  |  |  | 		sectors = 63; | 
					
						
							|  |  |  | 		cylinders = total_capacity / (heads * sectors); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	geom[0] = heads; | 
					
						
							|  |  |  | 	geom[1] = sectors; | 
					
						
							|  |  |  | 	geom[2] = cylinders; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct pci_dev *pdev = acb->pdev; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	u16 dev_id; | 
					
						
							|  |  |  | 	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->dev_id = dev_id; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (dev_id) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case 0x1880: { | 
					
						
							|  |  |  | 		acb->adapter_type = ACB_ADAPTER_TYPE_C; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 0x1201: { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		acb->adapter_type = ACB_ADAPTER_TYPE_B; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	default: acb->adapter_type = ACB_ADAPTER_TYPE_A; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | }	 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							|  |  |  | 	uint32_t Index; | 
					
						
							|  |  |  | 	uint8_t Retries = 0x00; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		for (Index = 0; Index < 100; Index++) { | 
					
						
							|  |  |  | 			if (readl(®->outbound_intstatus) & | 
					
						
							|  |  |  | 					ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { | 
					
						
							|  |  |  | 				writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, | 
					
						
							|  |  |  | 					®->outbound_intstatus); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				return true; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			msleep(10); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}/*max 1 seconds*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} while (Retries++ < 20);/*max 20 sec*/ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							|  |  |  | 	uint32_t Index; | 
					
						
							|  |  |  | 	uint8_t Retries = 0x00; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		for (Index = 0; Index < 100; Index++) { | 
					
						
							|  |  |  | 			if (readl(reg->iop2drv_doorbell) | 
					
						
							|  |  |  | 				& ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							|  |  |  | 				writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN | 
					
						
							|  |  |  | 					, reg->iop2drv_doorbell); | 
					
						
							|  |  |  | 				writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				return true; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			msleep(10); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}/*max 1 seconds*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} while (Retries++ < 20);/*max 20 sec*/ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	unsigned char Retries = 0x00; | 
					
						
							|  |  |  | 	uint32_t Index; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		for (Index = 0; Index < 100; Index++) { | 
					
						
							|  |  |  | 			if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							|  |  |  | 				writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/ | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			/* one us delay	*/ | 
					
						
							|  |  |  | 			msleep(10); | 
					
						
							|  |  |  | 		} /*max 1 seconds*/ | 
					
						
							|  |  |  | 	} while (Retries++ < 20); /*max 20 sec*/ | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							|  |  |  | 	int retry_count = 30; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if (arcmsr_hba_wait_msgint_ready(acb)) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			retry_count--; | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
 | 
					
						
							|  |  |  | 			timeout, retry count down = %d \n", acb->host->host_no, retry_count); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (retry_count != 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							|  |  |  | 	int retry_count = 30; | 
					
						
							|  |  |  | 	writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if (arcmsr_hbb_wait_msgint_ready(acb)) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			retry_count--; | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
 | 
					
						
							|  |  |  | 			timeout,retry count down = %d \n", acb->host->host_no, retry_count); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (retry_count != 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */ | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		if (arcmsr_hbc_wait_msgint_ready(pACB)) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			retry_count--; | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
 | 
					
						
							|  |  |  | 			timeout,retry count down = %d \n", pACB->host->host_no, retry_count); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (retry_count != 0); | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		arcmsr_flush_hba_cache(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 		arcmsr_flush_hbb_cache(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		arcmsr_flush_hbc_cache(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct pci_dev *pdev = acb->pdev; | 
					
						
							|  |  |  | 	void *dma_coherent; | 
					
						
							|  |  |  | 	dma_addr_t dma_coherent_handle; | 
					
						
							|  |  |  | 	struct CommandControlBlock *ccb_tmp; | 
					
						
							|  |  |  | 	int i = 0, j = 0; | 
					
						
							|  |  |  | 	dma_addr_t cdb_phyaddr; | 
					
						
							|  |  |  | 	unsigned long roundup_ccbsize = 0, offset; | 
					
						
							|  |  |  | 	unsigned long max_xfer_len; | 
					
						
							|  |  |  | 	unsigned long max_sg_entrys; | 
					
						
							|  |  |  | 	uint32_t  firm_config_version; | 
					
						
							|  |  |  | 	for (i = 0; i < ARCMSR_MAX_TARGETID; i++) | 
					
						
							|  |  |  | 		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) | 
					
						
							|  |  |  | 			acb->devstate[i][j] = ARECA_RAID_GONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	max_xfer_len = ARCMSR_MAX_XFER_LEN; | 
					
						
							|  |  |  | 	max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; | 
					
						
							|  |  |  | 	firm_config_version = acb->firm_cfg_version; | 
					
						
							|  |  |  | 	if((firm_config_version & 0xFF) >= 3){ | 
					
						
							|  |  |  | 		max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ | 
					
						
							|  |  |  | 		max_sg_entrys = (max_xfer_len/4096);	 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	acb->host->max_sectors = max_xfer_len/512; | 
					
						
							|  |  |  | 	acb->host->sg_tablesize = max_sg_entrys; | 
					
						
							|  |  |  | 	roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); | 
					
						
							|  |  |  | 	acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32; | 
					
						
							|  |  |  | 	dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); | 
					
						
							|  |  |  | 	if(!dma_coherent){ | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	acb->dma_coherent = dma_coherent; | 
					
						
							|  |  |  | 	acb->dma_coherent_handle = dma_coherent_handle; | 
					
						
							|  |  |  | 	memset(dma_coherent, 0, acb->uncache_size); | 
					
						
							|  |  |  | 	offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent; | 
					
						
							|  |  |  | 	dma_coherent_handle = dma_coherent_handle + offset; | 
					
						
							|  |  |  | 	dma_coherent = (struct CommandControlBlock *)dma_coherent + offset; | 
					
						
							|  |  |  | 	ccb_tmp = dma_coherent; | 
					
						
							|  |  |  | 	acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; | 
					
						
							|  |  |  | 	for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ | 
					
						
							|  |  |  | 		cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 		ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5)); | 
					
						
							|  |  |  | 		acb->pccb_pool[i] = ccb_tmp; | 
					
						
							|  |  |  | 		ccb_tmp->acb = acb; | 
					
						
							|  |  |  | 		INIT_LIST_HEAD(&ccb_tmp->list); | 
					
						
							|  |  |  | 		list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); | 
					
						
							|  |  |  | 		ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); | 
					
						
							|  |  |  | 		dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_message_isr_bh_fn(struct work_struct *work)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_A: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			struct MessageUnit_A __iomem *reg  = acb->pmuA; | 
					
						
							|  |  |  | 			char *acb_dev_map = (char *)acb->device_map; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			uint32_t __iomem *signature = (uint32_t __iomem*) (®->message_rwbuffer[0]); | 
					
						
							|  |  |  | 			char __iomem *devicemap = (char __iomem*) (®->message_rwbuffer[21]); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			int target, lun; | 
					
						
							|  |  |  | 			struct scsi_device *psdev; | 
					
						
							|  |  |  | 			char diff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			atomic_inc(&acb->rq_map_token); | 
					
						
							|  |  |  | 			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 					diff = (*acb_dev_map)^readb(devicemap); | 
					
						
							|  |  |  | 					if (diff != 0) { | 
					
						
							|  |  |  | 						char temp; | 
					
						
							|  |  |  | 						*acb_dev_map = readb(devicemap); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 						temp =*acb_dev_map; | 
					
						
							|  |  |  | 						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { | 
					
						
							|  |  |  | 							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 								scsi_add_device(acb->host, 0, target, lun); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 								psdev = scsi_device_lookup(acb->host, 0, target, lun); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 								if (psdev != NULL ) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 									scsi_remove_device(psdev); | 
					
						
							|  |  |  | 									scsi_device_put(psdev); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							temp >>= 1; | 
					
						
							|  |  |  | 							diff >>= 1; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					devicemap++; | 
					
						
							|  |  |  | 					acb_dev_map++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 			struct MessageUnit_B *reg  = acb->pmuB; | 
					
						
							|  |  |  | 			char *acb_dev_map = (char *)acb->device_map; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			uint32_t __iomem *signature = (uint32_t __iomem*)(®->message_rwbuffer[0]); | 
					
						
							|  |  |  | 			char __iomem *devicemap = (char __iomem*)(®->message_rwbuffer[21]); | 
					
						
							|  |  |  | 			int target, lun; | 
					
						
							|  |  |  | 			struct scsi_device *psdev; | 
					
						
							|  |  |  | 			char diff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			atomic_inc(&acb->rq_map_token); | 
					
						
							|  |  |  | 			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { | 
					
						
							|  |  |  | 				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { | 
					
						
							|  |  |  | 					diff = (*acb_dev_map)^readb(devicemap); | 
					
						
							|  |  |  | 					if (diff != 0) { | 
					
						
							|  |  |  | 						char temp; | 
					
						
							|  |  |  | 						*acb_dev_map = readb(devicemap); | 
					
						
							|  |  |  | 						temp =*acb_dev_map; | 
					
						
							|  |  |  | 						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { | 
					
						
							|  |  |  | 							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	 | 
					
						
							|  |  |  | 								scsi_add_device(acb->host, 0, target, lun); | 
					
						
							|  |  |  | 							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { | 
					
						
							|  |  |  | 								psdev = scsi_device_lookup(acb->host, 0, target, lun); | 
					
						
							|  |  |  | 								if (psdev != NULL ) { | 
					
						
							|  |  |  | 									scsi_remove_device(psdev); | 
					
						
							|  |  |  | 									scsi_device_put(psdev); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							temp >>= 1; | 
					
						
							|  |  |  | 							diff >>= 1; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					devicemap++; | 
					
						
							|  |  |  | 					acb_dev_map++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 			struct MessageUnit_C *reg  = acb->pmuC; | 
					
						
							|  |  |  | 			char *acb_dev_map = (char *)acb->device_map; | 
					
						
							|  |  |  | 			uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); | 
					
						
							|  |  |  | 			char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			int target, lun; | 
					
						
							|  |  |  | 			struct scsi_device *psdev; | 
					
						
							|  |  |  | 			char diff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			atomic_inc(&acb->rq_map_token); | 
					
						
							|  |  |  | 			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { | 
					
						
							|  |  |  | 				for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) { | 
					
						
							|  |  |  | 					diff = (*acb_dev_map)^readb(devicemap); | 
					
						
							|  |  |  | 					if (diff != 0) { | 
					
						
							|  |  |  | 						char temp; | 
					
						
							|  |  |  | 						*acb_dev_map = readb(devicemap); | 
					
						
							|  |  |  | 						temp = *acb_dev_map; | 
					
						
							|  |  |  | 						for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { | 
					
						
							|  |  |  | 							if ((temp & 0x01) == 1 && (diff & 0x01) == 1) { | 
					
						
							|  |  |  | 								scsi_add_device(acb->host, 0, target, lun); | 
					
						
							|  |  |  | 							} else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) { | 
					
						
							|  |  |  | 								psdev = scsi_device_lookup(acb->host, 0, target, lun); | 
					
						
							|  |  |  | 								if (psdev != NULL) { | 
					
						
							|  |  |  | 									scsi_remove_device(psdev); | 
					
						
							|  |  |  | 									scsi_device_put(psdev); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							temp >>= 1; | 
					
						
							|  |  |  | 							diff >>= 1; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					devicemap++; | 
					
						
							|  |  |  | 					acb_dev_map++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct Scsi_Host *host; | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	uint8_t bus,dev_fun; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	int error; | 
					
						
							|  |  |  | 	error = pci_enable_device(pdev); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(!host){ | 
					
						
							|  |  |  |     		goto pci_disable_dev; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-06 19:01:13 -07:00
										 |  |  | 	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2009-04-06 19:01:15 -07:00
										 |  |  | 		error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(error){ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			printk(KERN_WARNING | 
					
						
							|  |  |  | 			       "scsi%d: No suitable DMA mask available\n", | 
					
						
							|  |  |  | 			       host->host_no); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			goto scsi_host_release; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	init_waitqueue_head(&wait_q); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	bus = pdev->bus->number; | 
					
						
							|  |  |  | 	dev_fun = pdev->devfn; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb = (struct AdapterControlBlock *) host->hostdata; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	memset(acb,0,sizeof(struct AdapterControlBlock)); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->pdev = pdev; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->host = host; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	host->max_lun = ARCMSR_MAX_TARGETLUN; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	host->max_id = ARCMSR_MAX_TARGETID;		/*16:8*/ | 
					
						
							|  |  |  | 	host->max_cmd_len = 16;	 			/*this is issue of 64bit LBA ,over 2T byte*/ | 
					
						
							|  |  |  | 	host->can_queue = ARCMSR_MAX_FREECCB_NUM;	/* max simultaneous cmds */		 | 
					
						
							|  |  |  | 	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;	     | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	host->this_id = ARCMSR_SCSI_INITIATOR_ID; | 
					
						
							|  |  |  | 	host->unique_id = (bus << 8) | dev_fun; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	pci_set_drvdata(pdev, host); | 
					
						
							|  |  |  | 	pci_set_master(pdev); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	error = pci_request_regions(pdev, "arcmsr"); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto scsi_host_release; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	spin_lock_init(&acb->eh_lock); | 
					
						
							|  |  |  | 	spin_lock_init(&acb->ccblist_lock); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			ACB_F_MESSAGE_RQBUFFER_CLEARED | | 
					
						
							|  |  |  | 			ACB_F_MESSAGE_WQBUFFER_READED); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&acb->ccb_free_list); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	arcmsr_define_adapter_type(acb); | 
					
						
							|  |  |  | 	error = arcmsr_remap_pciregion(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(!error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto pci_release_regs; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	error = arcmsr_get_firmware_spec(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(!error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto unmap_pci_region; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	error = arcmsr_alloc_ccb_pool(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto free_hbb_mu; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	arcmsr_iop_init(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	error = scsi_add_host(host, &pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto RAID_controller_stop; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(error){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto scsi_host_remove; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	host->irq = pdev->irq; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  |     	scsi_scan_host(host); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	atomic_set(&acb->rq_map_token, 16); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 	acb->fw_flag = FW_NORMAL; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	init_timer(&acb->eternal_timer); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 	acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 	add_timer(&acb->eternal_timer); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(arcmsr_alloc_sysfs_attr(acb)) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		goto out_free_sysfs; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | out_free_sysfs: | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | scsi_host_remove: | 
					
						
							|  |  |  | 	scsi_remove_host(host); | 
					
						
							|  |  |  | RAID_controller_stop: | 
					
						
							|  |  |  | 	arcmsr_stop_adapter_bgrb(acb); | 
					
						
							|  |  |  | 	arcmsr_flush_adapter_cache(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_free_ccb_pool(acb); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | free_hbb_mu: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	arcmsr_free_hbb_mu(acb); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | unmap_pci_region: | 
					
						
							|  |  |  | 	arcmsr_unmap_pciregion(acb); | 
					
						
							|  |  |  | pci_release_regs: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	pci_release_regions(pdev); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | scsi_host_release: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	scsi_host_put(host); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | pci_disable_dev: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	pci_disable_device(pdev); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	return -ENODEV; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hba_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'abort all outstanding command' timeout \n" | 
					
						
							|  |  |  | 			, acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'abort all outstanding command' timeout \n" | 
					
						
							|  |  |  | 			, acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 	if (!arcmsr_hbc_wait_msgint_ready(pACB)) { | 
					
						
							|  |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'abort all outstanding command' timeout \n" | 
					
						
							|  |  |  | 			, pACB->host->host_no); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	uint8_t rtnval = 0; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		rtnval = arcmsr_abort_hba_allcmd(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		rtnval = arcmsr_abort_hbb_allcmd(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		rtnval = arcmsr_abort_hbc_allcmd(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	return rtnval; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_B *reg = pacb->pmuB; | 
					
						
							|  |  |  | 	writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hbb_wait_msgint_ready(pacb)) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no); | 
					
						
							|  |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  |     	return true; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct scsi_cmnd *pcmd = ccb->pcmd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	scsi_dma_unmap(pcmd); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = ccb->acb; | 
					
						
							|  |  |  | 	struct scsi_cmnd *pcmd = ccb->pcmd; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	atomic_dec(&acb->ccboutstandingcount); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_pci_unmap_dma(ccb); | 
					
						
							|  |  |  | 	ccb->startdone = ARCMSR_CCB_DONE; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	spin_lock_irqsave(&acb->ccblist_lock, flags); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	list_add_tail(&ccb->list, &acb->ccb_free_list); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	spin_unlock_irqrestore(&acb->ccblist_lock, flags); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	pcmd->scsi_done(pcmd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct scsi_cmnd *pcmd = ccb->pcmd; | 
					
						
							|  |  |  | 	struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; | 
					
						
							|  |  |  | 	pcmd->result = DID_OK << 16; | 
					
						
							|  |  |  | 	if (sensebuffer) { | 
					
						
							|  |  |  | 		int sense_data_length = | 
					
						
							| 
									
										
										
										
											2008-01-13 15:46:13 +09:00
										 |  |  | 			sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE | 
					
						
							|  |  |  | 			? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE; | 
					
						
							|  |  |  | 		memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); | 
					
						
							|  |  |  | 		sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; | 
					
						
							|  |  |  | 		sensebuffer->Valid = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 orig_mask = 0; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	switch (acb->adapter_type) {	 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_A : { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		orig_mask = readl(®->outbound_intmask); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ | 
					
						
							|  |  |  | 						®->outbound_intmask); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B : { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		orig_mask = readl(reg->iop2drv_doorbell_mask); | 
					
						
							|  |  |  | 		writel(0, reg->iop2drv_doorbell_mask); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C:{ | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 		orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */ | 
					
						
							|  |  |  | 		writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return orig_mask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,  | 
					
						
							|  |  |  | 			struct CommandControlBlock *ccb, bool error) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							|  |  |  | 	uint8_t id, lun; | 
					
						
							|  |  |  | 	id = ccb->pcmd->device->id; | 
					
						
							|  |  |  | 	lun = ccb->pcmd->device->lun; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!error) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		if (acb->devstate[id][lun] == ARECA_RAID_GONE) | 
					
						
							|  |  |  | 			acb->devstate[id][lun] = ARECA_RAID_GOOD; | 
					
						
							|  |  |  | 			ccb->pcmd->result = DID_OK << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	}else{ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		switch (ccb->arcmsr_cdb.DeviceStatus) { | 
					
						
							|  |  |  | 		case ARCMSR_DEV_SELECT_TIMEOUT: { | 
					
						
							|  |  |  | 			acb->devstate[id][lun] = ARECA_RAID_GONE; | 
					
						
							|  |  |  | 			ccb->pcmd->result = DID_NO_CONNECT << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case ARCMSR_DEV_ABORTED: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case ARCMSR_DEV_INIT_FAIL: { | 
					
						
							|  |  |  | 			acb->devstate[id][lun] = ARECA_RAID_GONE; | 
					
						
							|  |  |  | 			ccb->pcmd->result = DID_BAD_TARGET << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case ARCMSR_DEV_CHECK_CONDITION: { | 
					
						
							|  |  |  | 			acb->devstate[id][lun] = ARECA_RAID_GOOD; | 
					
						
							|  |  |  | 			arcmsr_report_sense_info(ccb); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			printk(KERN_NOTICE | 
					
						
							|  |  |  | 				"arcmsr%d: scsi id = %d lun = %d isr get command error done, \
 | 
					
						
							|  |  |  | 				but got unknown DeviceStatus = 0x%x \n" | 
					
						
							|  |  |  | 				, acb->host->host_no | 
					
						
							|  |  |  | 				, id | 
					
						
							|  |  |  | 				, lun | 
					
						
							|  |  |  | 				, ccb->arcmsr_cdb.DeviceStatus); | 
					
						
							|  |  |  | 				acb->devstate[id][lun] = ARECA_RAID_GONE; | 
					
						
							|  |  |  | 				ccb->pcmd->result = DID_NO_CONNECT << 16; | 
					
						
							|  |  |  | 				arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int id, lun; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { | 
					
						
							|  |  |  | 		if (pCCB->startdone == ARCMSR_CCB_ABORTED) { | 
					
						
							|  |  |  | 			struct scsi_cmnd *abortcmd = pCCB->pcmd; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			if (abortcmd) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				id = abortcmd->device->id; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				lun = abortcmd->device->lun;				 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				abortcmd->result |= DID_ABORT << 16; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				arcmsr_ccb_complete(pCCB); | 
					
						
							|  |  |  | 				printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n", | 
					
						
							|  |  |  | 				acb->host->host_no, pCCB); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			return; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
 | 
					
						
							|  |  |  | 				done acb = '0x%p'" | 
					
						
							|  |  |  | 				"ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" | 
					
						
							|  |  |  | 				" ccboutstandingcount = %d \n" | 
					
						
							|  |  |  | 				, acb->host->host_no | 
					
						
							|  |  |  | 				, acb | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				, pCCB | 
					
						
							|  |  |  | 				, pCCB->acb | 
					
						
							|  |  |  | 				, pCCB->startdone | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				, atomic_read(&acb->ccboutstandingcount)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		  return; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	arcmsr_report_ccb_state(acb, pCCB, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	uint32_t flag_ccb; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct ARCMSR_CDB *pARCMSR_CDB; | 
					
						
							|  |  |  | 	bool error; | 
					
						
							|  |  |  | 	struct CommandControlBlock *pCCB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint32_t outbound_intstatus; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		outbound_intstatus = readl(®->outbound_intstatus) & | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 					acb->outbound_int_enable; | 
					
						
							|  |  |  | 		/*clear and abort all outbound posted Q*/ | 
					
						
							|  |  |  | 		writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		while(((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 			arcmsr_drain_donequeue(acb, pCCB, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/*clear all outbound posted Q*/ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { | 
					
						
							|  |  |  | 			if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { | 
					
						
							|  |  |  | 				writel(0, ®->done_qbuffer[i]); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 				pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 				error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 				arcmsr_drain_donequeue(acb, pCCB, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			reg->post_qbuffer[i] = 0; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		reg->doneq_index = 0; | 
					
						
							|  |  |  | 		reg->postq_index = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = acb->pmuC; | 
					
						
							|  |  |  | 		struct  ARCMSR_CDB *pARCMSR_CDB; | 
					
						
							|  |  |  | 		uint32_t flag_ccb, ccb_cdb_phy; | 
					
						
							|  |  |  | 		bool error; | 
					
						
							|  |  |  | 		struct CommandControlBlock *pCCB; | 
					
						
							|  |  |  | 		while ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { | 
					
						
							|  |  |  | 			/*need to do*/ | 
					
						
							|  |  |  | 			flag_ccb = readl(®->outbound_queueport_low); | 
					
						
							|  |  |  | 			ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | 
					
						
							|  |  |  | 			pARCMSR_CDB = (struct  ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; | 
					
						
							|  |  |  | 			arcmsr_drain_donequeue(acb, pCCB, error); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | static void arcmsr_remove(struct pci_dev *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct Scsi_Host *host = pci_get_drvdata(pdev); | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = | 
					
						
							|  |  |  | 		(struct AdapterControlBlock *) host->hostdata; | 
					
						
							|  |  |  | 	int poll_count = 0; | 
					
						
							|  |  |  | 	arcmsr_free_sysfs_attr(acb); | 
					
						
							|  |  |  | 	scsi_remove_host(host); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	flush_scheduled_work(); | 
					
						
							|  |  |  | 	del_timer_sync(&acb->eternal_timer); | 
					
						
							|  |  |  | 	arcmsr_disable_outbound_ints(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_stop_adapter_bgrb(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	arcmsr_flush_adapter_cache(acb);	 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER; | 
					
						
							|  |  |  | 	acb->acb_flags &= ~ACB_F_IOP_INITED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		if (!atomic_read(&acb->ccboutstandingcount)) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_interrupt(acb);/* FIXME: need spinlock */ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		msleep(25); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (atomic_read(&acb->ccboutstandingcount)) { | 
					
						
							|  |  |  | 		int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		arcmsr_abort_allcmd(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_done4abort_postqueue(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | 
					
						
							|  |  |  | 			struct CommandControlBlock *ccb = acb->pccb_pool[i]; | 
					
						
							|  |  |  | 			if (ccb->startdone == ARCMSR_CCB_START) { | 
					
						
							|  |  |  | 				ccb->startdone = ARCMSR_CCB_ABORTED; | 
					
						
							|  |  |  | 				ccb->pcmd->result = DID_ABORT << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	free_irq(pdev->irq, acb); | 
					
						
							|  |  |  | 	arcmsr_free_ccb_pool(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	arcmsr_free_hbb_mu(acb); | 
					
						
							|  |  |  | 	arcmsr_unmap_pciregion(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	pci_release_regions(pdev); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	scsi_host_put(host); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	pci_disable_device(pdev); | 
					
						
							|  |  |  | 	pci_set_drvdata(pdev, NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_shutdown(struct pci_dev *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct Scsi_Host *host = pci_get_drvdata(pdev); | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = | 
					
						
							|  |  |  | 		(struct AdapterControlBlock *)host->hostdata; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	del_timer_sync(&acb->eternal_timer); | 
					
						
							|  |  |  | 	arcmsr_disable_outbound_ints(acb); | 
					
						
							|  |  |  | 	flush_scheduled_work(); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_stop_adapter_bgrb(acb); | 
					
						
							|  |  |  | 	arcmsr_flush_adapter_cache(acb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_module_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int error = 0; | 
					
						
							|  |  |  | 	error = pci_register_driver(&arcmsr_pci_driver); | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_module_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pci_unregister_driver(&arcmsr_pci_driver); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module_init(arcmsr_module_init); | 
					
						
							|  |  |  | module_exit(arcmsr_module_exit); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 						u32 intmask_org) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 mask; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE| | 
					
						
							|  |  |  | 			     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		writel(mask, ®->outbound_intmask); | 
					
						
							|  |  |  | 		acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | | 
					
						
							|  |  |  | 			ARCMSR_IOP2DRV_DATA_READ_OK | | 
					
						
							|  |  |  | 			ARCMSR_IOP2DRV_CDB_DONE | | 
					
						
							|  |  |  | 			ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(mask, reg->iop2drv_doorbell_mask); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = acb->pmuC; | 
					
						
							|  |  |  | 		mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); | 
					
						
							|  |  |  | 		writel(intmask_org & mask, ®->host_int_mask); | 
					
						
							|  |  |  | 		acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | static int arcmsr_build_ccb(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; | 
					
						
							|  |  |  | 	int8_t *psge = (int8_t *)&arcmsr_cdb->u; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	__le32 address_lo, address_hi; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	int arccdbsize = 0x30; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	__le32 length = 0; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	struct scatterlist *sg; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	int nseg; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	ccb->pcmd = pcmd; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_cdb->TargetID = pcmd->device->id; | 
					
						
							|  |  |  | 	arcmsr_cdb->LUN = pcmd->device->lun; | 
					
						
							|  |  |  | 	arcmsr_cdb->Function = 1; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	arcmsr_cdb->Context = 0; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	nseg = scsi_dma_map(pcmd); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0)) | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 		return FAILED; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	scsi_for_each_sg(pcmd, sg, nseg, i) { | 
					
						
							|  |  |  | 		/* Get the physical address of the current data pointer */ | 
					
						
							|  |  |  | 		length = cpu_to_le32(sg_dma_len(sg)); | 
					
						
							|  |  |  | 		address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); | 
					
						
							|  |  |  | 		address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); | 
					
						
							|  |  |  | 		if (address_hi == 0) { | 
					
						
							|  |  |  | 			struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			pdma_sg->address = address_lo; | 
					
						
							|  |  |  | 			pdma_sg->length = length; | 
					
						
							|  |  |  | 			psge += sizeof (struct SG32ENTRY); | 
					
						
							|  |  |  | 			arccdbsize += sizeof (struct SG32ENTRY); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			pdma_sg->addresshigh = address_hi; | 
					
						
							|  |  |  | 			pdma_sg->address = address_lo; | 
					
						
							|  |  |  | 			pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); | 
					
						
							|  |  |  | 			psge += sizeof (struct SG64ENTRY); | 
					
						
							|  |  |  | 			arccdbsize += sizeof (struct SG64ENTRY); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	arcmsr_cdb->sgcount = (uint8_t)nseg; | 
					
						
							|  |  |  | 	arcmsr_cdb->DataLength = scsi_bufflen(pcmd); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if ( arccdbsize > 256) | 
					
						
							|  |  |  | 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; | 
					
						
							|  |  |  | 	if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 || pcmd->cmnd[0]|WRITE_12 ){ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	ccb->arc_cdb_size = arccdbsize; | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 	return SUCCESS; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; | 
					
						
							|  |  |  | 	atomic_inc(&acb->ccboutstandingcount); | 
					
						
							|  |  |  | 	ccb->startdone = ARCMSR_CCB_START; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			®->inbound_queueport); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				writel(cdb_phyaddr_pattern, ®->inbound_queueport); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint32_t ending_index, index = reg->postq_index; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); | 
					
						
							|  |  |  | 		writel(0, ®->post_qbuffer[ending_index]); | 
					
						
							|  |  |  | 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 						 ®->post_qbuffer[index]); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		index++; | 
					
						
							|  |  |  | 		index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ | 
					
						
							|  |  |  | 		reg->postq_index = index; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		uint32_t ccb_post_stamp, arc_cdb_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; | 
					
						
							|  |  |  | 		ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1); | 
					
						
							|  |  |  | 		if (acb->cdb_phyaddr_hi32) { | 
					
						
							|  |  |  | 			writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); | 
					
						
							|  |  |  | 			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hba_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | 
					
						
							|  |  |  | 			, acb->host->host_no); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | 
					
						
							|  |  |  | 			, acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 	if (!arcmsr_hbc_wait_msgint_ready(pACB)) { | 
					
						
							|  |  |  | 		printk(KERN_NOTICE | 
					
						
							|  |  |  | 			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n" | 
					
						
							|  |  |  | 			, pACB->host->host_no); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							|  |  |  | 		arcmsr_stop_hba_bgrb(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 		arcmsr_stop_hbb_bgrb(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		arcmsr_stop_hbc_bgrb(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | void arcmsr_iop_message_read(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C __iomem *reg = acb->pmuC; | 
					
						
							|  |  |  | 		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		/*
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		** push inbound doorbell tell iop, driver data write ok | 
					
						
							|  |  |  | 		** and wait reply on next hwinterrupt for next Qbuffer post | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		*/ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		** push inbound doorbell tell iop, driver data write ok | 
					
						
							|  |  |  | 		** and wait reply on next hwinterrupt for next Qbuffer post | 
					
						
							|  |  |  | 		*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C __iomem *reg = acb->pmuC; | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		** push inbound doorbell tell iop, driver data write ok | 
					
						
							|  |  |  | 		** and wait reply on next hwinterrupt for next Qbuffer post | 
					
						
							|  |  |  | 		*/ | 
					
						
							|  |  |  | 		writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:58 +00:00
										 |  |  | 	struct QBUFFER __iomem *qbuffer = NULL; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							|  |  |  | 		qbuffer = (struct QBUFFER __iomem *)®->message_rbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return qbuffer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:58 +00:00
										 |  |  | 	struct QBUFFER __iomem *pqbuffer = NULL; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							|  |  |  | 		pqbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B  *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return pqbuffer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct QBUFFER __iomem *prbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	struct QBUFFER *pQbuffer; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	uint8_t __iomem *iop_data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; | 
					
						
							|  |  |  | 	rqbuf_lastindex = acb->rqbuf_lastindex; | 
					
						
							|  |  |  | 	rqbuf_firstindex = acb->rqbuf_firstindex; | 
					
						
							|  |  |  | 	prbuffer = arcmsr_get_iop_rqbuffer(acb); | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	iop_data = (uint8_t __iomem *)prbuffer->data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	iop_len = prbuffer->data_len; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (my_empty_len >= iop_len) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		while (iop_len > 0) { | 
					
						
							|  |  |  | 			pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			memcpy(pQbuffer, iop_data, 1); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			rqbuf_lastindex++; | 
					
						
							|  |  |  | 			rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 			iop_data++; | 
					
						
							|  |  |  | 			iop_len--; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		acb->rqbuf_lastindex = rqbuf_lastindex; | 
					
						
							|  |  |  | 		arcmsr_iop_message_read(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; | 
					
						
							|  |  |  | 	if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { | 
					
						
							|  |  |  | 		uint8_t *pQbuffer; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct QBUFFER __iomem *pwbuffer; | 
					
						
							|  |  |  | 		uint8_t __iomem *iop_data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		int32_t allxfer_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); | 
					
						
							|  |  |  | 		pwbuffer = arcmsr_get_iop_wqbuffer(acb); | 
					
						
							|  |  |  | 		iop_data = (uint8_t __iomem *)pwbuffer->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ | 
					
						
							|  |  |  | 							(allxfer_len < 124)) { | 
					
						
							|  |  |  | 			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; | 
					
						
							|  |  |  | 			memcpy(iop_data, pQbuffer, 1); | 
					
						
							|  |  |  | 			acb->wqbuf_firstindex++; | 
					
						
							|  |  |  | 			acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 			iop_data++; | 
					
						
							|  |  |  | 			allxfer_len++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		pwbuffer->data_len = allxfer_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		arcmsr_iop_message_wrote(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { | 
					
						
							|  |  |  | 		acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t outbound_doorbell; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 	writel(outbound_doorbell, ®->outbound_doorbell); | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { | 
					
						
							|  |  |  | 		arcmsr_iop2drv_data_wrote_handle(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_iop2drv_data_read_handle(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t outbound_doorbell; | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	******************************************************************* | 
					
						
							|  |  |  | 	**  Maybe here we need to check wrqbuffer_lock is lock or not | 
					
						
							|  |  |  | 	**  DOORBELL: din! don! | 
					
						
							|  |  |  | 	**  check if there are any mail need to pack from firmware | 
					
						
							|  |  |  | 	******************************************************************* | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 	writel(outbound_doorbell, ®->outbound_doorbell_clear);/*clear interrupt*/ | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { | 
					
						
							|  |  |  | 		arcmsr_iop2drv_data_wrote_handle(pACB); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { | 
					
						
							|  |  |  | 		arcmsr_iop2drv_data_read_handle(pACB); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							|  |  |  | 		arcmsr_hbc_message_isr(pACB);    /* messenger of "driver to iop commands" */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t flag_ccb; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct ARCMSR_CDB *pARCMSR_CDB; | 
					
						
							|  |  |  | 	struct CommandControlBlock *pCCB; | 
					
						
							|  |  |  | 	bool error; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 		arcmsr_drain_donequeue(acb, pCCB, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t index; | 
					
						
							|  |  |  | 	uint32_t flag_ccb; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct ARCMSR_CDB *pARCMSR_CDB; | 
					
						
							|  |  |  | 	struct CommandControlBlock *pCCB; | 
					
						
							|  |  |  | 	bool error; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	index = reg->doneq_index; | 
					
						
							|  |  |  | 	while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { | 
					
						
							|  |  |  | 		writel(0, ®->done_qbuffer[index]); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 		arcmsr_drain_donequeue(acb, pCCB, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		index++; | 
					
						
							|  |  |  | 		index %= ARCMSR_MAX_HBB_POSTQUEUE; | 
					
						
							|  |  |  | 		reg->doneq_index = index; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *phbcmu; | 
					
						
							|  |  |  | 	struct ARCMSR_CDB *arcmsr_cdb; | 
					
						
							|  |  |  | 	struct CommandControlBlock *ccb; | 
					
						
							|  |  |  | 	uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; | 
					
						
							|  |  |  | 	int error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	phbcmu = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 	/* areca cdb command done */ | 
					
						
							|  |  |  | 	/* Use correct offset and size for syncing */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (readl(&phbcmu->host_int_status) & | 
					
						
							|  |  |  | 	ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ | 
					
						
							|  |  |  | 	/* check if command done with no error*/ | 
					
						
							|  |  |  | 	flag_ccb = readl(&phbcmu->outbound_queueport_low); | 
					
						
							|  |  |  | 	ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 	arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); | 
					
						
							|  |  |  | 	ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 	error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; | 
					
						
							|  |  |  | 	/* check if command done with no error */ | 
					
						
							|  |  |  | 	arcmsr_drain_donequeue(acb, ccb, error); | 
					
						
							|  |  |  | 	if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { | 
					
						
							|  |  |  | 		writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	throttling++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  | ********************************************************************************** | 
					
						
							|  |  |  | ** Handle a message interrupt | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | ** The only message interrupt we expect is in response to a query for the current adapter config.   | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | ** We want this in order to compare the drivemap so that we can detect newly-attached drives. | 
					
						
							|  |  |  | ********************************************************************************** | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_A *reg  = acb->pmuA; | 
					
						
							|  |  |  | 	/*clear interrupt and message state*/ | 
					
						
							|  |  |  | 	writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); | 
					
						
							|  |  |  | 	schedule_work(&acb->arcmsr_do_message_isr_bh); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_B *reg  = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	/*clear interrupt and message state*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	schedule_work(&acb->arcmsr_do_message_isr_bh); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  | ********************************************************************************** | 
					
						
							|  |  |  | ** Handle a message interrupt | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** The only message interrupt we expect is in response to a query for the | 
					
						
							|  |  |  | ** current adapter config. | 
					
						
							|  |  |  | ** We want this in order to compare the drivemap so that we can detect newly-attached drives. | 
					
						
							|  |  |  | ********************************************************************************** | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg  = acb->pmuC; | 
					
						
							|  |  |  | 	/*clear interrupt and message state*/ | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear); | 
					
						
							|  |  |  | 	schedule_work(&acb->arcmsr_do_message_isr_bh); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t outbound_intstatus; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	outbound_intstatus = readl(®->outbound_intstatus) & | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		acb->outbound_int_enable; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{ | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	writel(outbound_intstatus, ®->outbound_intstatus); | 
					
						
							|  |  |  | 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)	{ | 
					
						
							|  |  |  | 		arcmsr_hba_doorbell_isr(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { | 
					
						
							|  |  |  | 		arcmsr_hba_postqueue_isr(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) 	{ | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		/* messenger of "driver to iop commands" */ | 
					
						
							|  |  |  | 		arcmsr_hba_message_isr(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t outbound_doorbell; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	outbound_doorbell = readl(reg->iop2drv_doorbell) & | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				acb->outbound_int_enable; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	if (!outbound_doorbell) | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(~outbound_doorbell, reg->iop2drv_doorbell); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	/*in case the last action of doorbell interrupt clearance is cached,
 | 
					
						
							|  |  |  | 	this action can push HW to write down the clear bit*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	readl(reg->iop2drv_doorbell); | 
					
						
							|  |  |  | 	writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_iop2drv_data_wrote_handle(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { | 
					
						
							|  |  |  | 		arcmsr_iop2drv_data_read_handle(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { | 
					
						
							|  |  |  | 		arcmsr_hbb_postqueue_isr(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		/* messenger of "driver to iop commands" */ | 
					
						
							|  |  |  | 		arcmsr_hbb_message_isr(acb); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t host_interrupt_status; | 
					
						
							|  |  |  | 	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	********************************************* | 
					
						
							|  |  |  | 	**   check outbound intstatus | 
					
						
							|  |  |  | 	********************************************* | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	host_interrupt_status = readl(&phbcmu->host_int_status); | 
					
						
							|  |  |  | 	if (!host_interrupt_status) { | 
					
						
							|  |  |  | 		/*it must be share irq*/ | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* MU ioctl transfer doorbell interrupts*/ | 
					
						
							|  |  |  | 	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { | 
					
						
							|  |  |  | 		arcmsr_hbc_doorbell_isr(pACB);   /* messenger of "ioctl message read write" */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* MU post queue interrupts*/ | 
					
						
							|  |  |  | 	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { | 
					
						
							|  |  |  | 		arcmsr_hbc_postqueue_isr(pACB);  /* messenger of "scsi commands" */ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							|  |  |  | 		if (arcmsr_handle_hba_isr(acb)) { | 
					
						
							|  |  |  | 			return IRQ_NONE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 		if (arcmsr_handle_hbb_isr(acb)) { | 
					
						
							|  |  |  | 			return IRQ_NONE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	 case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		if (arcmsr_handle_hbc_isr(acb)) { | 
					
						
							|  |  |  | 			return IRQ_NONE; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_iop_parking(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (acb) { | 
					
						
							|  |  |  | 		/* stop adapter background rebuild */ | 
					
						
							|  |  |  | 		if (acb->acb_flags & ACB_F_MSG_START_BGRB) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			uint32_t intmask_org; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			acb->acb_flags &= ~ACB_F_MSG_START_BGRB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			arcmsr_stop_adapter_bgrb(acb); | 
					
						
							|  |  |  | 			arcmsr_flush_adapter_cache(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int32_t wqbuf_firstindex, wqbuf_lastindex; | 
					
						
							|  |  |  | 	uint8_t *pQbuffer; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct QBUFFER __iomem *pwbuffer; | 
					
						
							|  |  |  | 	uint8_t __iomem *iop_data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	int32_t allxfer_len = 0; | 
					
						
							|  |  |  | 	pwbuffer = arcmsr_get_iop_wqbuffer(acb); | 
					
						
							|  |  |  | 	iop_data = (uint8_t __iomem *)pwbuffer->data; | 
					
						
							|  |  |  | 	if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { | 
					
						
							|  |  |  | 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); | 
					
						
							|  |  |  | 		wqbuf_firstindex = acb->wqbuf_firstindex; | 
					
						
							|  |  |  | 		wqbuf_lastindex = acb->wqbuf_lastindex; | 
					
						
							|  |  |  | 		while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { | 
					
						
							|  |  |  | 			pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; | 
					
						
							|  |  |  | 			memcpy(iop_data, pQbuffer, 1); | 
					
						
							|  |  |  | 			wqbuf_firstindex++; | 
					
						
							|  |  |  | 			wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 			iop_data++; | 
					
						
							|  |  |  | 			allxfer_len++; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		acb->wqbuf_firstindex = wqbuf_firstindex; | 
					
						
							|  |  |  | 		pwbuffer->data_len = allxfer_len; | 
					
						
							|  |  |  | 		arcmsr_iop_message_wrote(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 					struct scsi_cmnd *cmd) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct CMD_MESSAGE_FIELD *pcmdmessagefld; | 
					
						
							|  |  |  | 	int retvalue = 0, transfer_len = 0; | 
					
						
							|  |  |  | 	char *buffer; | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	struct scatterlist *sg; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 | | 
					
						
							|  |  |  | 						(uint32_t ) cmd->cmnd[6] << 16 | | 
					
						
							|  |  |  | 						(uint32_t ) cmd->cmnd[7] << 8  | | 
					
						
							|  |  |  | 						(uint32_t ) cmd->cmnd[8]; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 						/* 4 bytes: Areca io control code */ | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	sg = scsi_sglist(cmd); | 
					
						
							| 
									
										
										
										
											2007-10-22 21:19:53 +02:00
										 |  |  | 	buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	if (scsi_sg_count(cmd) > 1) { | 
					
						
							|  |  |  | 		retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 		goto message_out; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	transfer_len += sg->length; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { | 
					
						
							|  |  |  | 		retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 		goto message_out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; | 
					
						
							|  |  |  | 	switch(controlcode) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_READ_RQBUFFER: { | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		unsigned char *ver_addr; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint8_t *pQbuffer, *ptmpQbuffer; | 
					
						
							|  |  |  | 		int32_t allxfer_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		ver_addr = kmalloc(1032, GFP_ATOMIC); | 
					
						
							|  |  |  | 		if (!ver_addr) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 			goto message_out; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		ptmpQbuffer = ver_addr; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) | 
					
						
							|  |  |  | 			&& (allxfer_len < 1031)) { | 
					
						
							|  |  |  | 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; | 
					
						
							|  |  |  | 			memcpy(ptmpQbuffer, pQbuffer, 1); | 
					
						
							|  |  |  | 			acb->rqbuf_firstindex++; | 
					
						
							|  |  |  | 			acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 			ptmpQbuffer++; | 
					
						
							|  |  |  | 			allxfer_len++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 			struct QBUFFER __iomem *prbuffer; | 
					
						
							|  |  |  | 			uint8_t __iomem *iop_data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			int32_t iop_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | 
					
						
							|  |  |  | 			prbuffer = arcmsr_get_iop_rqbuffer(acb); | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 			iop_data = prbuffer->data; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			iop_len = readl(&prbuffer->data_len); | 
					
						
							|  |  |  | 			while (iop_len > 0) { | 
					
						
							|  |  |  | 				acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); | 
					
						
							|  |  |  | 				acb->rqbuf_lastindex++; | 
					
						
							|  |  |  | 				acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 				iop_data++; | 
					
						
							|  |  |  | 				iop_len--; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			arcmsr_iop_message_read(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		pcmdmessagefld->cmdmessage.Length = allxfer_len; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							|  |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		kfree(ver_addr); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ARCMSR_MESSAGE_WRITE_WQBUFFER: { | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		unsigned char *ver_addr; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | 
					
						
							|  |  |  | 		uint8_t *pQbuffer, *ptmpuserbuffer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		ver_addr = kmalloc(1032, GFP_ATOMIC); | 
					
						
							|  |  |  | 		if (!ver_addr) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 			goto message_out; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							|  |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode =  | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							|  |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode =  | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 		ptmpuserbuffer = ver_addr; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		user_len = pcmdmessagefld->cmdmessage.Length; | 
					
						
							|  |  |  | 		memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); | 
					
						
							|  |  |  | 		wqbuf_lastindex = acb->wqbuf_lastindex; | 
					
						
							|  |  |  | 		wqbuf_firstindex = acb->wqbuf_firstindex; | 
					
						
							|  |  |  | 		if (wqbuf_lastindex != wqbuf_firstindex) { | 
					
						
							|  |  |  | 			struct SENSE_DATA *sensebuffer = | 
					
						
							|  |  |  | 				(struct SENSE_DATA *)cmd->sense_buffer; | 
					
						
							|  |  |  | 			arcmsr_post_ioctldata2iop(acb); | 
					
						
							|  |  |  | 			/* has error report sensedata */ | 
					
						
							|  |  |  | 			sensebuffer->ErrorCode = 0x70; | 
					
						
							|  |  |  | 			sensebuffer->SenseKey = ILLEGAL_REQUEST; | 
					
						
							|  |  |  | 			sensebuffer->AdditionalSenseLength = 0x0A; | 
					
						
							|  |  |  | 			sensebuffer->AdditionalSenseCode = 0x20; | 
					
						
							|  |  |  | 			sensebuffer->Valid = 1; | 
					
						
							|  |  |  | 			retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) | 
					
						
							|  |  |  | 				&(ARCMSR_MAX_QBUFFER - 1); | 
					
						
							|  |  |  | 			if (my_empty_len >= user_len) { | 
					
						
							|  |  |  | 				while (user_len > 0) { | 
					
						
							|  |  |  | 					pQbuffer = | 
					
						
							|  |  |  | 					&acb->wqbuffer[acb->wqbuf_lastindex]; | 
					
						
							|  |  |  | 					memcpy(pQbuffer, ptmpuserbuffer, 1); | 
					
						
							|  |  |  | 					acb->wqbuf_lastindex++; | 
					
						
							|  |  |  | 					acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | 
					
						
							|  |  |  | 					ptmpuserbuffer++; | 
					
						
							|  |  |  | 					user_len--; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | 
					
						
							|  |  |  | 					acb->acb_flags &= | 
					
						
							|  |  |  | 						~ACB_F_MESSAGE_WQBUFFER_CLEARED; | 
					
						
							|  |  |  | 					arcmsr_post_ioctldata2iop(acb); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* has error report sensedata */ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				struct SENSE_DATA *sensebuffer = | 
					
						
							|  |  |  | 					(struct SENSE_DATA *)cmd->sense_buffer; | 
					
						
							|  |  |  | 				sensebuffer->ErrorCode = 0x70; | 
					
						
							|  |  |  | 				sensebuffer->SenseKey = ILLEGAL_REQUEST; | 
					
						
							|  |  |  | 				sensebuffer->AdditionalSenseLength = 0x0A; | 
					
						
							|  |  |  | 				sensebuffer->AdditionalSenseCode = 0x20; | 
					
						
							|  |  |  | 				sensebuffer->Valid = 1; | 
					
						
							|  |  |  | 				retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-02-20 13:29:05 +00:00
										 |  |  | 			kfree(ver_addr); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint8_t *pQbuffer = acb->rqbuffer; | 
					
						
							|  |  |  | 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 
					
						
							|  |  |  | 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | 
					
						
							|  |  |  | 			arcmsr_iop_message_read(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; | 
					
						
							|  |  |  | 		acb->rqbuf_firstindex = 0; | 
					
						
							|  |  |  | 		acb->rqbuf_lastindex = 0; | 
					
						
							|  |  |  | 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint8_t *pQbuffer = acb->wqbuffer; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 
					
						
							|  |  |  | 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | 
					
						
							|  |  |  | 			arcmsr_iop_message_read(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		acb->acb_flags |= | 
					
						
							|  |  |  | 			(ACB_F_MESSAGE_WQBUFFER_CLEARED | | 
					
						
							|  |  |  | 				ACB_F_MESSAGE_WQBUFFER_READED); | 
					
						
							|  |  |  | 		acb->wqbuf_firstindex = 0; | 
					
						
							|  |  |  | 		acb->wqbuf_lastindex = 0; | 
					
						
							|  |  |  | 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint8_t *pQbuffer; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 
					
						
							|  |  |  | 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | 
					
						
							|  |  |  | 			arcmsr_iop_message_read(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		acb->acb_flags |= | 
					
						
							|  |  |  | 			(ACB_F_MESSAGE_WQBUFFER_CLEARED | 
					
						
							|  |  |  | 			| ACB_F_MESSAGE_RQBUFFER_CLEARED | 
					
						
							|  |  |  | 			| ACB_F_MESSAGE_WQBUFFER_READED); | 
					
						
							|  |  |  | 		acb->rqbuf_firstindex = 0; | 
					
						
							|  |  |  | 		acb->rqbuf_lastindex = 0; | 
					
						
							|  |  |  | 		acb->wqbuf_firstindex = 0; | 
					
						
							|  |  |  | 		acb->wqbuf_lastindex = 0; | 
					
						
							|  |  |  | 		pQbuffer = acb->rqbuffer; | 
					
						
							|  |  |  | 		memset(pQbuffer, 0, sizeof(struct QBUFFER)); | 
					
						
							|  |  |  | 		pQbuffer = acb->wqbuffer; | 
					
						
							|  |  |  | 		memset(pQbuffer, 0, sizeof(struct QBUFFER)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_RETURN_CODE_3F: { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_3F; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_SAY_HELLO: { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		int8_t *hello_string = "Hello! I am ARCMSR"; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_OK; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		memcpy(pcmdmessagefld->messagedatabuffer, hello_string | 
					
						
							|  |  |  | 			, (int16_t)strlen(hello_string)); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_SAY_GOODBYE: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		arcmsr_iop_parking(acb); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if(acb->fw_flag == FW_DEADLOCK) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			pcmdmessagefld->cmdmessage.ReturnCode = | 
					
						
							|  |  |  | 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		arcmsr_flush_adapter_cache(acb); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		retvalue = ARCMSR_MESSAGE_FAIL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	message_out: | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 	sg = scsi_sglist(cmd); | 
					
						
							|  |  |  | 	kunmap_atomic(buffer - sg->offset, KM_IRQ0); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	return retvalue; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct list_head *head = &acb->ccb_free_list; | 
					
						
							|  |  |  | 	struct CommandControlBlock *ccb = NULL; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	spin_lock_irqsave(&acb->ccblist_lock, flags); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	if (!list_empty(head)) { | 
					
						
							|  |  |  | 		ccb = list_entry(head->next, struct CommandControlBlock, list); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		list_del_init(&ccb->list); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	}else{ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		spin_unlock_irqrestore(&acb->ccblist_lock, flags); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	spin_unlock_irqrestore(&acb->ccblist_lock, flags); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	return ccb; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, | 
					
						
							|  |  |  | 		struct scsi_cmnd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (cmd->cmnd[0]) { | 
					
						
							|  |  |  | 	case INQUIRY: { | 
					
						
							|  |  |  | 		unsigned char inqdata[36]; | 
					
						
							|  |  |  | 		char *buffer; | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 		struct scatterlist *sg; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (cmd->device->lun) { | 
					
						
							|  |  |  | 			cmd->result = (DID_TIME_OUT << 16); | 
					
						
							|  |  |  | 			cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		inqdata[0] = TYPE_PROCESSOR; | 
					
						
							|  |  |  | 		/* Periph Qualifier & Periph Dev Type */ | 
					
						
							|  |  |  | 		inqdata[1] = 0; | 
					
						
							|  |  |  | 		/* rem media bit & Dev Type Modifier */ | 
					
						
							|  |  |  | 		inqdata[2] = 0; | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 		/* ISO, ECMA, & ANSI versions */ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		inqdata[4] = 31; | 
					
						
							|  |  |  | 		/* length of additional data */ | 
					
						
							|  |  |  | 		strncpy(&inqdata[8], "Areca   ", 8); | 
					
						
							|  |  |  | 		/* Vendor Identification */ | 
					
						
							|  |  |  | 		strncpy(&inqdata[16], "RAID controller ", 16); | 
					
						
							|  |  |  | 		/* Product Identification */ | 
					
						
							|  |  |  | 		strncpy(&inqdata[32], "R001", 4); /* Product Revision */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 		sg = scsi_sglist(cmd); | 
					
						
							| 
									
										
										
										
											2007-10-22 21:19:53 +02:00
										 |  |  | 		buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		memcpy(buffer, inqdata, sizeof(inqdata)); | 
					
						
							| 
									
										
										
										
											2007-05-14 19:25:56 +09:00
										 |  |  | 		sg = scsi_sglist(cmd); | 
					
						
							|  |  |  | 		kunmap_atomic(buffer - sg->offset, KM_IRQ0); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  | 	case WRITE_BUFFER: | 
					
						
							|  |  |  | 	case READ_BUFFER: { | 
					
						
							|  |  |  | 		if (arcmsr_iop_message_xfer(acb, cmd)) | 
					
						
							|  |  |  | 			cmd->result = (DID_ERROR << 16); | 
					
						
							|  |  |  | 		cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_queue_command(struct scsi_cmnd *cmd, | 
					
						
							|  |  |  | 	void (* done)(struct scsi_cmnd *)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct Scsi_Host *host = cmd->device->host; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	struct CommandControlBlock *ccb; | 
					
						
							|  |  |  | 	int target = cmd->device->id; | 
					
						
							|  |  |  | 	int lun = cmd->device->lun; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	uint8_t scsicmd = cmd->cmnd[0]; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	cmd->scsi_done = done; | 
					
						
							|  |  |  | 	cmd->host_scribble = NULL; | 
					
						
							|  |  |  | 	cmd->result = 0; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){ | 
					
						
							|  |  |  | 		if(acb->devstate[target][lun] == ARECA_RAID_GONE) { | 
					
						
							|  |  |  |     			cmd->result = (DID_NO_CONNECT << 16); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 	if (target == 16) { | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		/* virtual device for iop message transfer */ | 
					
						
							|  |  |  | 		arcmsr_handle_virtual_command(acb, cmd); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (atomic_read(&acb->ccboutstandingcount) >= | 
					
						
							|  |  |  | 			ARCMSR_MAX_OUTSTANDING_CMD) | 
					
						
							|  |  |  | 		return SCSI_MLQUEUE_HOST_BUSY; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) { | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	ccb = arcmsr_get_freeccb(acb); | 
					
						
							|  |  |  | 	if (!ccb) | 
					
						
							|  |  |  | 		return SCSI_MLQUEUE_HOST_BUSY; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) { | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 		cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); | 
					
						
							|  |  |  | 		cmd->scsi_done(cmd); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	arcmsr_post_ccb(acb, ccb); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	char *acb_firm_model = acb->firm_model; | 
					
						
							|  |  |  | 	char *acb_firm_version = acb->firm_version; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	char *acb_device_map = acb->device_map; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	char __iomem *iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); | 
					
						
							|  |  |  | 	char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	char __iomem *iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	int count; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hba_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 | 
					
						
							|  |  |  | 			miscellaneous data' timeout \n", acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	count = 8; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	while (count){ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		*acb_firm_model = readb(iop_firm_model); | 
					
						
							|  |  |  | 		acb_firm_model++; | 
					
						
							|  |  |  | 		iop_firm_model++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	count = 16; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	while (count){ | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		*acb_firm_version = readb(iop_firm_version); | 
					
						
							|  |  |  | 		acb_firm_version++; | 
					
						
							|  |  |  | 		iop_firm_version++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	count=16; | 
					
						
							|  |  |  | 	while(count){ | 
					
						
							|  |  |  | 		*acb_device_map = readb(iop_device_map); | 
					
						
							|  |  |  | 		acb_device_map++; | 
					
						
							|  |  |  | 		iop_device_map++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",  | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		acb->host->host_no, | 
					
						
							|  |  |  | 		acb->firm_version, | 
					
						
							|  |  |  | 		acb->firm_model); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	acb->signature = readl(®->message_rwbuffer[0]); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->firm_request_len = readl(®->message_rwbuffer[1]); | 
					
						
							|  |  |  | 	acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); | 
					
						
							|  |  |  | 	acb->firm_sdram_size = readl(®->message_rwbuffer[3]); | 
					
						
							|  |  |  | 	acb->firm_hd_channels = readl(®->message_rwbuffer[4]); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_cfg_version = readl(®->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/ | 
					
						
							|  |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	struct pci_dev *pdev = acb->pdev; | 
					
						
							|  |  |  | 	void *dma_coherent; | 
					
						
							|  |  |  | 	dma_addr_t dma_coherent_handle; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	char *acb_firm_model = acb->firm_model; | 
					
						
							|  |  |  | 	char *acb_firm_version = acb->firm_version; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	char *acb_device_map = acb->device_map; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	char __iomem *iop_firm_model; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_model,15,60-67*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	char __iomem *iop_firm_version; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_version,17,68-83*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	char __iomem *iop_device_map; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	/*firm_version,21,84-99*/ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	int count; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!dma_coherent){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	acb->dma_coherent_handle_hbb_mu = dma_coherent_handle; | 
					
						
							|  |  |  | 	reg = (struct MessageUnit_B *)dma_coherent; | 
					
						
							|  |  |  | 	acb->pmuB = reg; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK); | 
					
						
							|  |  |  | 	reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL); | 
					
						
							|  |  |  | 	reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK); | 
					
						
							|  |  |  | 	reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER); | 
					
						
							|  |  |  | 	reg->message_rbuffer =  (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER); | 
					
						
							|  |  |  | 	reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER); | 
					
						
							|  |  |  | 	iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]);	/*firm_model,15,60-67*/ | 
					
						
							|  |  |  | 	iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]);	/*firm_version,17,68-83*/ | 
					
						
							|  |  |  | 	iop_device_map = (char __iomem *)(®->message_rwbuffer[21]);	/*firm_version,21,84-99*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 | 
					
						
							|  |  |  | 			miscellaneous data' timeout \n", acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	count = 8; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	while (count){ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		*acb_firm_model = readb(iop_firm_model); | 
					
						
							|  |  |  | 		acb_firm_model++; | 
					
						
							|  |  |  | 		iop_firm_model++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	count = 16; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	while (count){ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		*acb_firm_version = readb(iop_firm_version); | 
					
						
							|  |  |  | 		acb_firm_version++; | 
					
						
							|  |  |  | 		iop_firm_version++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	count = 16; | 
					
						
							|  |  |  | 	while(count){ | 
					
						
							|  |  |  | 		*acb_device_map = readb(iop_device_map); | 
					
						
							|  |  |  | 		acb_device_map++; | 
					
						
							|  |  |  | 		iop_device_map++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		acb->host->host_no, | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		acb->firm_version, | 
					
						
							|  |  |  | 		acb->firm_model); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->signature = readl(®->message_rwbuffer[1]); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	/*firm_signature,1,00-03*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_request_len = readl(®->message_rwbuffer[2]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_request_len,1,04-07*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_numbers_queue = readl(®->message_rwbuffer[3]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_numbers_queue,2,08-11*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_sdram_size = readl(®->message_rwbuffer[4]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_sdram_size,3,12-15*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_hd_channels = readl(®->message_rwbuffer[5]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*firm_ide_channels,4,16-19*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->firm_cfg_version = readl(®->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/ | 
					
						
							|  |  |  | 	/*firm_ide_channels,4,16-19*/ | 
					
						
							|  |  |  | 	return true; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t intmask_org, Index, firmware_state = 0; | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = pACB->pmuC; | 
					
						
							|  |  |  | 	char *acb_firm_model = pACB->firm_model; | 
					
						
							|  |  |  | 	char *acb_firm_version = pACB->firm_version; | 
					
						
							|  |  |  | 	char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]);    /*firm_model,15,60-67*/ | 
					
						
							|  |  |  | 	char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]);  /*firm_version,17,68-83*/ | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 	/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 	intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */ | 
					
						
							|  |  |  | 	writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); | 
					
						
							|  |  |  | 	/* wait firmware ready */ | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		firmware_state = readl(®->outbound_msgaddr1); | 
					
						
							|  |  |  | 	} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); | 
					
						
							|  |  |  | 	/* post "get config" instruction */ | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 	/* wait message ready */ | 
					
						
							|  |  |  | 	for (Index = 0; Index < 2000; Index++) { | 
					
						
							|  |  |  | 		if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { | 
					
						
							|  |  |  | 			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);/*clear interrupt*/ | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		udelay(10); | 
					
						
							|  |  |  | 	} /*max 1 seconds*/ | 
					
						
							|  |  |  | 	if (Index >= 2000) { | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 | 
					
						
							|  |  |  | 			miscellaneous data' timeout \n", pACB->host->host_no); | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	count = 8; | 
					
						
							|  |  |  | 	while (count) { | 
					
						
							|  |  |  | 		*acb_firm_model = readb(iop_firm_model); | 
					
						
							|  |  |  | 		acb_firm_model++; | 
					
						
							|  |  |  | 		iop_firm_model++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	count = 16; | 
					
						
							|  |  |  | 	while (count) { | 
					
						
							|  |  |  | 		*acb_firm_version = readb(iop_firm_version); | 
					
						
							|  |  |  | 		acb_firm_version++; | 
					
						
							|  |  |  | 		iop_firm_version++; | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", | 
					
						
							|  |  |  | 		pACB->host->host_no, | 
					
						
							|  |  |  | 		pACB->firm_version, | 
					
						
							|  |  |  | 		pACB->firm_model); | 
					
						
							|  |  |  | 	pACB->firm_request_len = readl(®->msgcode_rwbuffer[1]);   /*firm_request_len,1,04-07*/ | 
					
						
							|  |  |  | 	pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/ | 
					
						
							|  |  |  | 	pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]);    /*firm_sdram_size,3,12-15*/ | 
					
						
							|  |  |  | 	pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]);  /*firm_ide_channels,4,16-19*/ | 
					
						
							|  |  |  | 	pACB->firm_cfg_version = readl(®->msgcode_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/ | 
					
						
							|  |  |  | 	/*all interrupt service will be enable at arcmsr_iop_init*/ | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	if (acb->adapter_type == ACB_ADAPTER_TYPE_A) | 
					
						
							|  |  |  | 		return arcmsr_get_hba_config(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	else if (acb->adapter_type == ACB_ADAPTER_TYPE_B) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return arcmsr_get_hbb_config(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		return arcmsr_get_hbc_config(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	struct CommandControlBlock *poll_ccb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	struct CommandControlBlock *ccb; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	struct ARCMSR_CDB *arcmsr_cdb; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int rtn; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	bool error; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	polling_hba_ccb_retry: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	poll_count++; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			if (poll_ccb_done){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				rtn = SUCCESS; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			}else { | 
					
						
							|  |  |  | 				msleep(25); | 
					
						
							|  |  |  | 				if (poll_count > 100){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 					rtn = FAILED; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				goto polling_hba_ccb_retry; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); | 
					
						
							|  |  |  | 		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		poll_ccb_done = (ccb == poll_ccb) ? 1:0; | 
					
						
							|  |  |  | 		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { | 
					
						
							|  |  |  | 			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { | 
					
						
							|  |  |  | 				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 					" poll command abort successfully \n" | 
					
						
							|  |  |  | 					, acb->host->host_no | 
					
						
							|  |  |  | 					, ccb->pcmd->device->id | 
					
						
							|  |  |  | 					, ccb->pcmd->device->lun | 
					
						
							|  |  |  | 					, ccb); | 
					
						
							|  |  |  | 				ccb->pcmd->result = DID_ABORT << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" | 
					
						
							|  |  |  | 				" command done ccb = '0x%p'" | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 				"ccboutstandingcount = %d \n" | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				, acb->host->host_no | 
					
						
							|  |  |  | 				, ccb | 
					
						
							|  |  |  | 				, atomic_read(&acb->ccboutstandingcount)); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 		arcmsr_report_ccb_state(acb, ccb, error); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	return rtn; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 					struct CommandControlBlock *poll_ccb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	struct ARCMSR_CDB *arcmsr_cdb; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	struct CommandControlBlock *ccb; | 
					
						
							|  |  |  | 	uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int index, rtn; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	bool error; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	polling_hbb_ccb_retry: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	poll_count++; | 
					
						
							|  |  |  | 	/* clear doorbell interrupt */ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	while(1){ | 
					
						
							|  |  |  | 		index = reg->doneq_index; | 
					
						
							|  |  |  | 		if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { | 
					
						
							|  |  |  | 			if (poll_ccb_done){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				rtn = SUCCESS; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			}else { | 
					
						
							|  |  |  | 				msleep(25); | 
					
						
							|  |  |  | 				if (poll_count > 100){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 					rtn = FAILED; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				goto polling_hbb_ccb_retry; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		writel(0, ®->done_qbuffer[index]); | 
					
						
							|  |  |  | 		index++; | 
					
						
							|  |  |  | 		/*if last index number set it to 0 */ | 
					
						
							|  |  |  | 		index %= ARCMSR_MAX_HBB_POSTQUEUE; | 
					
						
							|  |  |  | 		reg->doneq_index = index; | 
					
						
							|  |  |  | 		/* check if command done with no error*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); | 
					
						
							|  |  |  | 		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		poll_ccb_done = (ccb == poll_ccb) ? 1:0; | 
					
						
							|  |  |  | 		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { | 
					
						
							|  |  |  | 			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" | 
					
						
							|  |  |  | 					" poll command abort successfully \n" | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					,acb->host->host_no | 
					
						
							|  |  |  | 					,ccb->pcmd->device->id | 
					
						
							|  |  |  | 					,ccb->pcmd->device->lun | 
					
						
							|  |  |  | 					,ccb); | 
					
						
							|  |  |  | 				ccb->pcmd->result = DID_ABORT << 16; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" | 
					
						
							|  |  |  | 				" command done ccb = '0x%p'" | 
					
						
							|  |  |  | 				"ccboutstandingcount = %d \n" | 
					
						
							|  |  |  | 				, acb->host->host_no | 
					
						
							|  |  |  | 				, ccb | 
					
						
							|  |  |  | 				, atomic_read(&acb->ccboutstandingcount)); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		}  | 
					
						
							|  |  |  | 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; | 
					
						
							|  |  |  | 		arcmsr_report_ccb_state(acb, ccb, error); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return rtn; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 	uint32_t flag_ccb, ccb_cdb_phy; | 
					
						
							|  |  |  | 	struct ARCMSR_CDB *arcmsr_cdb; | 
					
						
							|  |  |  | 	bool error; | 
					
						
							|  |  |  | 	struct CommandControlBlock *pCCB; | 
					
						
							|  |  |  | 	uint32_t poll_ccb_done = 0, poll_count = 0; | 
					
						
							|  |  |  | 	int rtn; | 
					
						
							|  |  |  | polling_hbc_ccb_retry: | 
					
						
							|  |  |  | 	poll_count++; | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) { | 
					
						
							|  |  |  | 			if (poll_ccb_done) { | 
					
						
							|  |  |  | 				rtn = SUCCESS; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				msleep(25); | 
					
						
							|  |  |  | 				if (poll_count > 100) { | 
					
						
							|  |  |  | 					rtn = FAILED; | 
					
						
							|  |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				goto polling_hbc_ccb_retry; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		flag_ccb = readl(®->outbound_queueport_low); | 
					
						
							|  |  |  | 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); | 
					
						
							|  |  |  | 		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ | 
					
						
							|  |  |  | 		pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); | 
					
						
							|  |  |  | 		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0; | 
					
						
							|  |  |  | 		/* check ifcommand done with no error*/ | 
					
						
							|  |  |  | 		if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { | 
					
						
							|  |  |  | 			if (pCCB->startdone == ARCMSR_CCB_ABORTED) { | 
					
						
							|  |  |  | 				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" | 
					
						
							|  |  |  | 					" poll command abort successfully \n" | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 					, acb->host->host_no | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					, pCCB->pcmd->device->id | 
					
						
							|  |  |  | 					, pCCB->pcmd->device->lun | 
					
						
							|  |  |  | 					, pCCB); | 
					
						
							|  |  |  | 					pCCB->pcmd->result = DID_ABORT << 16; | 
					
						
							|  |  |  | 					arcmsr_ccb_complete(pCCB); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" | 
					
						
							|  |  |  | 				" command done ccb = '0x%p'" | 
					
						
							|  |  |  | 				"ccboutstandingcount = %d \n" | 
					
						
							|  |  |  | 				, acb->host->host_no | 
					
						
							|  |  |  | 				, pCCB | 
					
						
							|  |  |  | 				, atomic_read(&acb->ccboutstandingcount)); | 
					
						
							|  |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; | 
					
						
							|  |  |  | 		arcmsr_report_ccb_state(acb, pCCB, error); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	return rtn; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 					struct CommandControlBlock *poll_ccb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int rtn = 0; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	return rtn; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	uint32_t cdb_phyaddr, cdb_phyaddr_hi32; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	dma_addr_t dma_coherent_handle; | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	******************************************************************** | 
					
						
							|  |  |  | 	** here we need to tell iop 331 our freeccb.HighPart | 
					
						
							|  |  |  | 	** if freeccb.HighPart is not zero | 
					
						
							|  |  |  | 	******************************************************************** | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	dma_coherent_handle = acb->dma_coherent_handle; | 
					
						
							|  |  |  | 	cdb_phyaddr = (uint32_t)(dma_coherent_handle); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	*********************************************************************** | 
					
						
							|  |  |  | 	**    if adapter type B, set window of "post command Q" | 
					
						
							|  |  |  | 	*********************************************************************** | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		if (cdb_phyaddr_hi32 != 0) { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 			struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			uint32_t intmask_org; | 
					
						
							|  |  |  | 			intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							|  |  |  | 			writel(ARCMSR_SIGNATURE_SET_CONFIG, \ | 
					
						
							|  |  |  | 						®->message_rwbuffer[0]); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ | 
					
						
							|  |  |  | 							®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			if (!arcmsr_hba_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 				printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
 | 
					
						
							|  |  |  | 				part physical address timeout\n", | 
					
						
							|  |  |  | 				acb->host->host_no); | 
					
						
							|  |  |  | 				return 1; | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 		unsigned long post_queue_phyaddr; | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		uint32_t __iomem *rwbuffer; | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint32_t intmask_org; | 
					
						
							|  |  |  | 		intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							|  |  |  | 		reg->postq_index = 0; | 
					
						
							|  |  |  | 		reg->doneq_index = 0; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ | 
					
						
							|  |  |  | 				acb->host->host_no); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu; | 
					
						
							|  |  |  | 		rwbuffer = reg->message_rwbuffer; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/* driver "set config" signature */ | 
					
						
							|  |  |  | 		writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); | 
					
						
							|  |  |  | 		/* normal should be zero */ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(cdb_phyaddr_hi32, rwbuffer++); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/* postQ size (256 + 8)*4	 */ | 
					
						
							|  |  |  | 		writel(post_queue_phyaddr, rwbuffer++); | 
					
						
							|  |  |  | 		/* doneQ size (256 + 8)*4	 */ | 
					
						
							|  |  |  | 		writel(post_queue_phyaddr + 1056, rwbuffer++); | 
					
						
							|  |  |  | 		/* ccb maxQ size must be --> [(256 + 8)*4]*/ | 
					
						
							|  |  |  | 		writel(1056, rwbuffer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 			printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
 | 
					
						
							|  |  |  | 			timeout \n",acb->host->host_no); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		arcmsr_hbb_enable_driver_mode(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		if (cdb_phyaddr_hi32 != 0) { | 
					
						
							|  |  |  | 			struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (cdb_phyaddr_hi32 != 0) { | 
					
						
							|  |  |  | 				unsigned char Retries = 0x00; | 
					
						
							|  |  |  | 				do { | 
					
						
							|  |  |  | 					printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32); | 
					
						
							|  |  |  | 				} while (Retries++ < 100); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); | 
					
						
							|  |  |  | 			writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); | 
					
						
							|  |  |  | 			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 			writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 			if (!arcmsr_hbc_wait_msgint_ready(acb)) { | 
					
						
							|  |  |  | 				printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
 | 
					
						
							|  |  |  | 				timeout \n", acb->host->host_no); | 
					
						
							|  |  |  | 				return 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t firmware_state = 0; | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		do { | 
					
						
							|  |  |  | 			firmware_state = readl(®->outbound_msgaddr1); | 
					
						
							|  |  |  | 		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		do { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			firmware_state = readl(reg->iop2drv_doorbell); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			firmware_state = readl(®->outbound_msgaddr1); | 
					
						
							|  |  |  | 		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		acb->fw_flag = FW_NORMAL; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){ | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); | 
					
						
							|  |  |  | 		if (atomic_dec_and_test(&acb->rq_map_token)) | 
					
						
							|  |  |  | 			return; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_B __iomem *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { | 
					
						
							|  |  |  | 			atomic_set(&acb->rq_map_token,16); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); | 
					
						
							|  |  |  | 		if(atomic_dec_and_test(&acb->rq_map_token)) | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); | 
					
						
							|  |  |  | 		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C __iomem *reg = acb->pmuC; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 			atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); | 
					
						
							|  |  |  | 		if (atomic_dec_and_test(&acb->rq_map_token)) | 
					
						
							|  |  |  | 			return; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); | 
					
						
							|  |  |  | 		writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void arcmsr_request_device_map(unsigned long pacb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb; | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_A: { | 
					
						
							|  |  |  | 			arcmsr_request_hba_device_map(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_B: { | 
					
						
							|  |  |  | 			arcmsr_request_hbb_device_map(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 			arcmsr_request_hbc_device_map(acb); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	acb->acb_flags |= ACB_F_MSG_START_BGRB; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hba_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
 | 
					
						
							|  |  |  | 				rebulid' timeout \n", acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 	struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	acb->acb_flags |= ACB_F_MSG_START_BGRB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
 | 
					
						
							|  |  |  | 				rebulid' timeout \n",acb->host->host_no); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; | 
					
						
							|  |  |  | 	pACB->acb_flags |= ACB_F_MSG_START_BGRB; | 
					
						
							|  |  |  | 	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0); | 
					
						
							|  |  |  | 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); | 
					
						
							|  |  |  | 	if (!arcmsr_hbc_wait_msgint_ready(pACB)) { | 
					
						
							|  |  |  | 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
 | 
					
						
							|  |  |  | 				rebulid' timeout \n", pACB->host->host_no); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: | 
					
						
							|  |  |  | 		arcmsr_start_hba_bgrb(acb); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: | 
					
						
							|  |  |  | 		arcmsr_start_hbb_bgrb(acb); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: | 
					
						
							|  |  |  | 		arcmsr_start_hbc_bgrb(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_A __iomem *reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		uint32_t outbound_doorbell; | 
					
						
							|  |  |  | 		/* empty doorbell Qbuffer if door bell ringed */ | 
					
						
							|  |  |  | 		outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 		/*clear doorbell interrupt */ | 
					
						
							|  |  |  | 		writel(outbound_doorbell, ®->outbound_doorbell); | 
					
						
							|  |  |  | 		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_B: { | 
					
						
							| 
									
										
										
										
											2007-10-29 05:08:28 +00:00
										 |  |  | 		struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/*clear interrupt and message state*/ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); | 
					
						
							|  |  |  | 		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		/* let IOP know data has been read */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: { | 
					
						
							|  |  |  | 		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; | 
					
						
							|  |  |  | 		uint32_t outbound_doorbell; | 
					
						
							|  |  |  | 		/* empty doorbell Qbuffer if door bell ringed */ | 
					
						
							|  |  |  | 		outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 		writel(outbound_doorbell, ®->outbound_doorbell_clear); | 
					
						
							|  |  |  | 		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (acb->adapter_type) { | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_A: | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	case ACB_ADAPTER_TYPE_B: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			struct MessageUnit_B *reg = acb->pmuB; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			if (!arcmsr_hbb_wait_msgint_ready(acb)) { | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 				printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case ACB_ADAPTER_TYPE_C: | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint8_t value[64]; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	int i, count = 0; | 
					
						
							|  |  |  | 	struct MessageUnit_A __iomem *pmuA = acb->pmuA; | 
					
						
							|  |  |  | 	struct MessageUnit_C __iomem *pmuC = acb->pmuC; | 
					
						
							|  |  |  | 	u32 temp = 0; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	/* backup pci config data */ | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  | 		pci_read_config_byte(acb->pdev, i, &value[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* hardware reset signal */ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	if ((acb->dev_id == 0x1680)) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]); | 
					
						
							|  |  |  | 	} else if ((acb->dev_id == 0x1880)) { | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			count++; | 
					
						
							|  |  |  | 			writel(0xF, &pmuC->write_sequence); | 
					
						
							|  |  |  | 			writel(0x4, &pmuC->write_sequence); | 
					
						
							|  |  |  | 			writel(0xB, &pmuC->write_sequence); | 
					
						
							|  |  |  | 			writel(0x2, &pmuC->write_sequence); | 
					
						
							|  |  |  | 			writel(0x7, &pmuC->write_sequence); | 
					
						
							|  |  |  | 			writel(0xD, &pmuC->write_sequence); | 
					
						
							|  |  |  | 		} while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5)); | 
					
						
							|  |  |  | 		writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 		pci_write_config_byte(acb->pdev, 0x84, 0x20); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	msleep(2000); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	/* write back pci config data */ | 
					
						
							|  |  |  | 	for (i = 0; i < 64; i++) { | 
					
						
							|  |  |  | 		pci_write_config_byte(acb->pdev, i, value[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	msleep(1000); | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | static void arcmsr_iop_init(struct AdapterControlBlock *acb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	uint32_t intmask_org; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 	intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 	arcmsr_wait_firmware_ready(acb); | 
					
						
							|  |  |  | 	arcmsr_iop_confirm(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/*start background rebuild*/ | 
					
						
							|  |  |  | 	arcmsr_start_adapter_bgrb(acb); | 
					
						
							|  |  |  | 	/* empty doorbell Qbuffer if door bell ringed */ | 
					
						
							|  |  |  | 	arcmsr_clear_doorbell_queue_buffer(acb); | 
					
						
							| 
									
										
										
										
											2008-02-04 23:53:24 -08:00
										 |  |  | 	arcmsr_enable_eoi_mode(acb); | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	/* enable outbound Post Queue,outbound doorbell Interrupt */ | 
					
						
							|  |  |  | 	arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->acb_flags |= ACB_F_IOP_INITED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct CommandControlBlock *ccb; | 
					
						
							|  |  |  | 	uint32_t intmask_org; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	uint8_t rtnval = 0x00; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	if (atomic_read(&acb->ccboutstandingcount) != 0) { | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 		intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		/* talk to iop 331 outstanding command aborted */ | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		rtnval = arcmsr_abort_allcmd(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		/* clear all outbound posted Q */ | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 		arcmsr_done4abort_postqueue(acb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | 
					
						
							|  |  |  | 			ccb = acb->pccb_pool[i]; | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 			if (ccb->startdone == ARCMSR_CCB_START) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				arcmsr_ccb_complete(ccb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		atomic_set(&acb->ccboutstandingcount, 0); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		/* enable all outbound interrupt */ | 
					
						
							|  |  |  | 		arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		return rtnval; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	return rtnval; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_bus_reset(struct scsi_cmnd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = | 
					
						
							|  |  |  | 		(struct AdapterControlBlock *)cmd->device->host->hostdata; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	uint32_t intmask_org, outbound_doorbell; | 
					
						
							|  |  |  | 	int retry_count = 0; | 
					
						
							|  |  |  | 	int rtn = FAILED; | 
					
						
							|  |  |  | 	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts); | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 	acb->num_resets++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	switch(acb->adapter_type){ | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_A:{ | 
					
						
							|  |  |  | 			if (acb->acb_flags & ACB_F_BUS_RESET){ | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				long timeout; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				printk(KERN_ERR "arcmsr: there is an  bus reset eh proceeding.......\n"); | 
					
						
							|  |  |  | 				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				if (timeout) { | 
					
						
							|  |  |  | 					return SUCCESS; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			acb->acb_flags |= ACB_F_BUS_RESET; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			if (!arcmsr_iop_reset(acb)) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				struct MessageUnit_A __iomem *reg; | 
					
						
							|  |  |  | 				reg = acb->pmuA; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				arcmsr_hardware_reset(acb); | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_IOP_INITED; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | sleep_again: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				arcmsr_sleep_for_bus_reset(cmd); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); | 
					
						
							|  |  |  | 					if (retry_count > retrycount) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 						acb->fw_flag = FW_DEADLOCK; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 						return FAILED; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					retry_count++; | 
					
						
							|  |  |  | 					goto sleep_again; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				acb->acb_flags |= ACB_F_IOP_INITED; | 
					
						
							|  |  |  | 				/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 				intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				arcmsr_get_firmware_spec(acb); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				arcmsr_start_adapter_bgrb(acb); | 
					
						
							|  |  |  | 				/* clear Qbuffer if door bell ringed */ | 
					
						
							|  |  |  | 				outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 				writel(outbound_doorbell, ®->outbound_doorbell); /*clear interrupt */ | 
					
						
							|  |  |  |    				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 				/* enable outbound Post Queue,outbound doorbell Interrupt */ | 
					
						
							|  |  |  | 				arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							|  |  |  | 				atomic_set(&acb->rq_map_token, 16); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 				acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 				init_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); | 
					
						
							|  |  |  | 				acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 				acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 				add_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 				rtn = SUCCESS; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				printk(KERN_ERR "arcmsr: scsi  bus reset eh returns with success\n"); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 				if (atomic_read(&acb->rq_map_token) == 0) { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					init_timer(&acb->eternal_timer); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 					acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 					acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 					add_timer(&acb->eternal_timer); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				rtn = SUCCESS; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2010-05-17 11:22:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		case ACB_ADAPTER_TYPE_B:{ | 
					
						
							|  |  |  | 			acb->acb_flags |= ACB_F_BUS_RESET; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			if (!arcmsr_iop_reset(acb)) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 				rtn = FAILED; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 				if (atomic_read(&acb->rq_map_token) == 0) { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 					init_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); | 
					
						
							|  |  |  | 					acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 					acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 					add_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				rtn = SUCCESS; | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case ACB_ADAPTER_TYPE_C:{ | 
					
						
							|  |  |  | 			if (acb->acb_flags & ACB_F_BUS_RESET) { | 
					
						
							|  |  |  | 				long timeout; | 
					
						
							|  |  |  | 				printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); | 
					
						
							|  |  |  | 				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); | 
					
						
							|  |  |  | 				if (timeout) { | 
					
						
							|  |  |  | 					return SUCCESS; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			acb->acb_flags |= ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 			if (!arcmsr_iop_reset(acb)) { | 
					
						
							|  |  |  | 				struct MessageUnit_C __iomem *reg; | 
					
						
							|  |  |  | 				reg = acb->pmuC; | 
					
						
							|  |  |  | 				arcmsr_hardware_reset(acb); | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_IOP_INITED; | 
					
						
							|  |  |  | sleep: | 
					
						
							|  |  |  | 				arcmsr_sleep_for_bus_reset(cmd); | 
					
						
							|  |  |  | 				if ((readl(®->host_diagnostic) & 0x04) != 0) { | 
					
						
							|  |  |  | 					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); | 
					
						
							|  |  |  | 					if (retry_count > retrycount) { | 
					
						
							|  |  |  | 						acb->fw_flag = FW_DEADLOCK; | 
					
						
							|  |  |  | 						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); | 
					
						
							|  |  |  | 						return FAILED; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					retry_count++; | 
					
						
							|  |  |  | 					goto sleep; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				acb->acb_flags |= ACB_F_IOP_INITED; | 
					
						
							|  |  |  | 				/* disable all outbound interrupt */ | 
					
						
							|  |  |  | 				intmask_org = arcmsr_disable_outbound_ints(acb); | 
					
						
							|  |  |  | 				arcmsr_get_firmware_spec(acb); | 
					
						
							|  |  |  | 				arcmsr_start_adapter_bgrb(acb); | 
					
						
							|  |  |  | 				/* clear Qbuffer if door bell ringed */ | 
					
						
							|  |  |  | 				outbound_doorbell = readl(®->outbound_doorbell); | 
					
						
							|  |  |  | 				writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */ | 
					
						
							|  |  |  | 				writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); | 
					
						
							|  |  |  | 				/* enable outbound Post Queue,outbound doorbell Interrupt */ | 
					
						
							|  |  |  | 				arcmsr_enable_outbound_ints(acb, intmask_org); | 
					
						
							|  |  |  | 				atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 				atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 				acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 				init_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); | 
					
						
							|  |  |  | 				acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 				acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 				add_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 				rtn = SUCCESS; | 
					
						
							|  |  |  | 				printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				acb->acb_flags &= ~ACB_F_BUS_RESET; | 
					
						
							|  |  |  | 				if (atomic_read(&acb->rq_map_token) == 0) { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 					init_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 						acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); | 
					
						
							|  |  |  | 					acb->eternal_timer.data = (unsigned long) acb; | 
					
						
							|  |  |  | 					acb->eternal_timer.function = &arcmsr_request_device_map; | 
					
						
							|  |  |  | 					add_timer(&acb->eternal_timer); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					atomic_set(&acb->rq_map_token, 16); | 
					
						
							|  |  |  | 					atomic_set(&acb->ante_token_value, 16); | 
					
						
							|  |  |  | 					acb->fw_flag = FW_NORMAL; | 
					
						
							|  |  |  | 					mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				rtn = SUCCESS; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return rtn; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		struct CommandControlBlock *ccb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int rtn; | 
					
						
							|  |  |  | 	rtn = arcmsr_polling_ccbdone(acb, ccb); | 
					
						
							|  |  |  | 	return rtn; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arcmsr_abort(struct scsi_cmnd *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = | 
					
						
							|  |  |  | 		(struct AdapterControlBlock *)cmd->device->host->hostdata; | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	int rtn = FAILED; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	printk(KERN_NOTICE | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 		"arcmsr%d: abort device command of scsi id = %d lun = %d \n", | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		acb->host->host_no, cmd->device->id, cmd->device->lun); | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->acb_flags |= ACB_F_ABORT; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	acb->num_aborts++; | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	************************************************ | 
					
						
							|  |  |  | 	** the all interrupt service routine is locked | 
					
						
							|  |  |  | 	** we need to handle it as soon as possible and exit | 
					
						
							|  |  |  | 	************************************************ | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	if (!atomic_read(&acb->ccboutstandingcount)) | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 		return rtn; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { | 
					
						
							|  |  |  | 		struct CommandControlBlock *ccb = acb->pccb_pool[i]; | 
					
						
							|  |  |  | 		if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 			ccb->startdone = ARCMSR_CCB_ABORTED; | 
					
						
							|  |  |  | 			rtn = arcmsr_abort_one_cmd(acb, ccb); | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-06-18 15:39:12 +08:00
										 |  |  | 	acb->acb_flags &= ~ACB_F_ABORT; | 
					
						
							|  |  |  | 	return rtn; | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *arcmsr_info(struct Scsi_Host *host) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct AdapterControlBlock *acb = | 
					
						
							|  |  |  | 		(struct AdapterControlBlock *) host->hostdata; | 
					
						
							|  |  |  | 	static char buf[256]; | 
					
						
							|  |  |  | 	char *type; | 
					
						
							|  |  |  | 	int raid6 = 1; | 
					
						
							|  |  |  | 	switch (acb->pdev->device) { | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1110: | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case PCI_DEVICE_ID_ARECA_1200: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1202: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case PCI_DEVICE_ID_ARECA_1210: | 
					
						
							|  |  |  | 		raid6 = 0; | 
					
						
							|  |  |  | 		/*FALLTHRU*/ | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1120: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1130: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1160: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1170: | 
					
						
							| 
									
										
										
										
											2007-09-13 17:26:40 +08:00
										 |  |  | 	case PCI_DEVICE_ID_ARECA_1201: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 	case PCI_DEVICE_ID_ARECA_1220: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1230: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1260: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1270: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1280: | 
					
						
							|  |  |  | 		type = "SATA"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1380: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1381: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1680: | 
					
						
							|  |  |  | 	case PCI_DEVICE_ID_ARECA_1681: | 
					
						
							| 
									
										
										
										
											2010-07-13 20:03:04 +08:00
										 |  |  | 	case PCI_DEVICE_ID_ARECA_1880: | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 		type = "SAS"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		type = "X-TYPE"; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-06-15 11:43:32 +08:00
										 |  |  | 	sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", | 
					
						
							| 
									
										
										
										
											2006-07-12 08:59:32 -07:00
										 |  |  | 			type, raid6 ? "( RAID6 capable)" : "", | 
					
						
							|  |  |  | 			ARCMSR_DRIVER_VERSION); | 
					
						
							|  |  |  | 	return buf; | 
					
						
							|  |  |  | } |