diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
| -rw-r--r-- | drivers/scsi/mpt2sas/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_init.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 92 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 36 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_config.c | 10 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 46 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_debug.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1055 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 89 | 
15 files changed, 854 insertions, 492 deletions
| diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index ba8e128de23..bbb7e4bf30a 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -2,7 +2,7 @@  # Kernel configuration file for the MPT2SAS  #  # This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2009  LSI Corporation +# Copyright (C) 2007-2010  LSI Corporation  #  (mailto:DL-MPTFusionLinux@lsi.com)  # This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 9958d847a88..dada0a13223 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index cf0ac9f40c9..d4e9d6f8452 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_cnfg.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt index c4adf76b49d..bd6c92b5fae 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -2,7 +2,7 @@   Fusion-MPT MPI 2.0 Header File Change History   ============================== - Copyright (c) 2000-2009 LSI Corporation. + Copyright (c) 2000-2010 LSI Corporation.   ---------------------------------------   Header Set Release Version:    02.00.14 diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 6541945e97c..220bf65a921 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_init.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 754938422f6..f18f114922b 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_ioc.h diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 73fcdbf9263..686b09b8121 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2009 LSI Corporation. + *  Copyright (c) 2000-2010 LSI Corporation.   *   *   *           Name:  mpi2_tool.h diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 88e6eebc315..0ec1ed389c2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -58,6 +58,7 @@  #include <linux/sort.h>  #include <linux/io.h>  #include <linux/time.h> +#include <linux/aer.h>  #include "mpt2sas_base.h" @@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,  	    request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)  		return; +	if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		return; +  	switch (ioc_status) {  /**************************************************************************** @@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,  		desc = "IR Operation Status";  		break;  	case MPI2_EVENT_SAS_DISCOVERY: -		desc =  "Discovery"; -		break; +	{ +		Mpi2EventDataSasDiscovery_t *event_data = +		    (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; +		printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, +		    (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? +		    "start" : "stop"); +		if (event_data->DiscoveryStatus) +			printk("discovery_status(0x%08x)", +			    le32_to_cpu(event_data->DiscoveryStatus)); +			printk("\n"); +		return; +	}  	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:  		desc = "SAS Broadcast Primitive";  		break; @@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  		goto out_fail;  	} +	/* AER (Advanced Error Reporting) hooks */ +	pci_enable_pcie_error_reporting(pdev); +  	pci_set_master(pdev);  	if (_base_config_dma_addressing(ioc, pdev) != 0) { @@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	}  	for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { -		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { +		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {  			if (pio_sz)  				continue;  			pio_chip = (u64)pci_resource_start(pdev, i); @@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  		} else {  			if (memap_sz)  				continue; -			ioc->chip_phys = pci_resource_start(pdev, i); -			chip_phys = (u64)ioc->chip_phys; -			memap_sz = pci_resource_len(pdev, i); -			ioc->chip = ioremap(ioc->chip_phys, memap_sz); -			if (ioc->chip == NULL) { -				printk(MPT2SAS_ERR_FMT "unable to map adapter " -				    "memory!\n", ioc->name); -				r = -EINVAL; -				goto out_fail; +			/* verify memory resource is valid before using */ +			if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { +				ioc->chip_phys = pci_resource_start(pdev, i); +				chip_phys = (u64)ioc->chip_phys; +				memap_sz = pci_resource_len(pdev, i); +				ioc->chip = ioremap(ioc->chip_phys, memap_sz); +				if (ioc->chip == NULL) { +					printk(MPT2SAS_ERR_FMT "unable to map " +					    "adapter memory!\n", ioc->name); +					r = -EINVAL; +					goto out_fail; +				}  			}  		}  	} @@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	ioc->chip_phys = 0;  	ioc->pci_irq = -1;  	pci_release_selected_regions(ioc->pdev, ioc->bars); +	pci_disable_pcie_error_reporting(pdev);  	pci_disable_device(pdev);  	return r;  } @@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  		    ioc->config_page, ioc->config_page_dma);  	} -	kfree(ioc->scsi_lookup); +	if (ioc->scsi_lookup) { +		free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); +		ioc->scsi_lookup = NULL; +	}  	kfree(ioc->hpr_lookup);  	kfree(ioc->internal_lookup);  } @@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	    ioc->name, (unsigned long long) ioc->request_dma));  	total_sz += sz; -	ioc->scsi_lookup = kcalloc(ioc->scsiio_depth, -	    sizeof(struct request_tracker), GFP_KERNEL); +	sz = ioc->scsiio_depth * sizeof(struct request_tracker); +	ioc->scsi_lookup_pages = get_order(sz); +	ioc->scsi_lookup = (struct request_tracker *)__get_free_pages( +	    GFP_KERNEL, ioc->scsi_lookup_pages);  	if (!ioc->scsi_lookup) { -		printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", -		    ioc->name); +		printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " +		    "sz(%d)\n", ioc->name, (int)sz);  		goto out;  	} @@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	 * since epoch ~ midnight January 1, 1970.  	 */  	do_gettimeofday(¤t_time); -	mpi_request.TimeStamp = (current_time.tv_sec * 1000) + -	    (current_time.tv_usec >> 3); +	mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + +	    (current_time.tv_usec / 1000));  	if (ioc->logging_level & MPT_DEBUG_INIT) {  		u32 *mfp; @@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	mpi_request->VP_ID = 0;  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		mpi_request->EventMasks[i] = -		    le32_to_cpu(ioc->event_masks[i]); +		    cpu_to_le32(ioc->event_masks[i]);  	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); @@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)  	    __func__));  	_base_mask_interrupts(ioc); +	ioc->shost_recovery = 1;  	_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); +	ioc->shost_recovery = 0;  	if (ioc->pci_irq) {  		synchronize_irq(pdev->irq);  		free_irq(ioc->pci_irq, ioc); @@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)  	ioc->pci_irq = -1;  	ioc->chip_phys = 0;  	pci_release_selected_regions(ioc->pdev, ioc->bars); +	pci_disable_pcie_error_reporting(pdev);  	pci_disable_device(pdev);  	return;  } @@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,  	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); -	if (!ioc->pfacts) +	if (!ioc->pfacts) { +		r = -ENOMEM;  		goto out_free_resources; +	}  	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {  		r = _base_get_port_facts(ioc, i, CAN_SLEEP); @@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;  	mutex_init(&ioc->ctl_cmds.mutex); +	if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || +	    !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || +	    !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { +		r = -ENOMEM; +		goto out_free_resources; +	} + +	init_completion(&ioc->shost_recovery_done); +  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		ioc->event_masks[i] = -1; @@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	pci_set_drvdata(ioc->pdev, NULL);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply); +	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  	kfree(ioc->base_cmds.reply);  	kfree(ioc->ctl_cmds.reply); @@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->ctl_cmds.reply = NULL;  	ioc->base_cmds.reply = NULL;  	ioc->tm_cmds.reply = NULL; +	ioc->scsih_cmds.reply = NULL;  	ioc->transport_cmds.reply = NULL;  	ioc->config_cmds.reply = NULL;  	ioc->pfacts = NULL; @@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)  	kfree(ioc->base_cmds.reply);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply); +	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  } @@ -3714,7 +3757,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		if (ioc->config_cmds.status & MPT2_CMD_PENDING) {  			ioc->config_cmds.status |= MPT2_CMD_RESET;  			mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); -			ioc->config_cmds.smid = USHORT_MAX; +			ioc->config_cmds.smid = USHRT_MAX;  			complete(&ioc->config_cmds.done);  		}  		break; @@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);  	ioc->shost_recovery = 0; +	complete(&ioc->shost_recovery_done);  	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -	if (!r) -		_base_reset_handler(ioc, MPT2_IOC_RUNNING);  	return r;  } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index e18b0544c38..b4afe431ac1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.h - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -69,11 +69,11 @@  #define MPT2SAS_DRIVER_NAME		"mpt2sas"  #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"  #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION		"04.100.01.00" -#define MPT2SAS_MAJOR_VERSION		04 +#define MPT2SAS_DRIVER_VERSION		"05.100.00.02" +#define MPT2SAS_MAJOR_VERSION		05  #define MPT2SAS_MINOR_VERSION		100 -#define MPT2SAS_BUILD_VERSION		01 -#define MPT2SAS_RELEASE_VERSION		00 +#define MPT2SAS_BUILD_VERSION		00 +#define MPT2SAS_RELEASE_VERSION		02  /*   * Set MPT2SAS_SG_DEPTH value based on user input. @@ -119,7 +119,6 @@  #define MPT2_IOC_PRE_RESET		1 /* prior to host reset */  #define MPT2_IOC_AFTER_RESET		2 /* just after host reset */  #define MPT2_IOC_DONE_RESET		3 /* links re-initialized */ -#define MPT2_IOC_RUNNING		4 /* shost running */  /*   * logging format @@ -260,16 +259,6 @@ struct _internal_cmd {  	u16	smid;  }; -/* - * SAS Topology Structures - */ - -#define MPTSAS_STATE_TR_SEND		0x0001 -#define MPTSAS_STATE_TR_COMPLETE	0x0002 -#define MPTSAS_STATE_CNTRL_SEND		0x0004 -#define MPTSAS_STATE_CNTRL_COMPLETE	0x0008 - -#define MPT2SAS_REQ_SAS_CNTRL		0x0010  /**   * struct _sas_device - attached device information @@ -307,7 +296,6 @@ struct _sas_device {  	u16	slot;  	u8	hidden_raid_component;  	u8	responding; -	u16	state;  };  /** @@ -378,6 +366,7 @@ struct _sas_port {   * @phy_id: unique phy id   * @handle: device handle for this phy   * @attached_handle: device handle for attached device + * @phy_belongs_to_port: port has been created for this phy   */  struct _sas_phy {  	struct list_head port_siblings; @@ -387,6 +376,7 @@ struct _sas_phy {  	u8	phy_id;  	u16	handle;  	u16	attached_handle; +	u8	phy_belongs_to_port;  };  /** @@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER {  	/* fw event handler */  	char		firmware_event_name[20];  	struct workqueue_struct	*firmware_event_thread; -	u8		fw_events_off;  	spinlock_t	fw_event_lock;  	struct list_head fw_event_list; @@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER {  	int		aen_event_read_flag;  	u8		broadcast_aen_busy;  	u8		shost_recovery; +	struct completion	shost_recovery_done;  	spinlock_t 	ioc_reset_in_progress_lock;  	u8		ioc_link_reset_in_progress;  	u8		ignore_loginfos; @@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER {  	dma_addr_t	request_dma;  	u32		request_dma_sz;  	struct request_tracker *scsi_lookup; -	spinlock_t scsi_lookup_lock; +	ulong		scsi_lookup_pages; +	spinlock_t 	scsi_lookup_lock;  	struct list_head free_list;  	int		pending_io_count;  	wait_queue_head_t reset_wq; @@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER {  	u16		max_sges_in_chain_message;  	u16		chains_needed_per_io;  	u16		chain_offset_value_for_main_message; -	u16		chain_depth; +	u32		chain_depth;  	/* hi-priority queue */  	u16		hi_priority_smid; @@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);  /* scsih shared API */  u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,      u32 reply); -void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, -    u8 type, u16 smid_task, ulong timeout); +int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, +    uint channel, uint id, uint lun, u8 type, u16 smid_task, +    ulong timeout, struct scsi_cmnd *scmd);  void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);  void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);  struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index cf44b355bc9..c65442982d7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -2,7 +2,7 @@   * This module provides common API for accessing firmware configuration pages   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -258,7 +258,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	_config_display_some_debug(ioc, smid, "config_done", mpi_reply);  #endif -	ioc->config_cmds.smid = USHORT_MAX; +	ioc->config_cmds.smid = USHRT_MAX;  	complete(&ioc->config_cmds.done);  	return 1;  } @@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,  	if (ioc_status != MPI2_IOCSTATUS_SUCCESS)  		goto out;  	for (i = 0; i < config_page->NumElements; i++) { -		if ((config_page->ConfigElement[i].ElementFlags & +		if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) &  		    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=  		    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)  			continue; -		if (config_page->ConfigElement[i].PhysDiskDevHandle == -		    pd_handle) { +		if (le16_to_cpu(config_page->ConfigElement[i]. +		    PhysDiskDevHandle) == pd_handle) {  			*volume_handle = le16_to_cpu(config_page->  			    ConfigElement[i].VolDevHandle);  			r = 0; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index fa9bf83819d..d88e9756d8f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	if (!found) {  		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, -		    desc, tm_request->DevHandle, lun)); +		    desc, le16_to_cpu(tm_request->DevHandle), lun));  		tm_reply = ioc->ctl_cmds.reply;  		tm_reply->DevHandle = tm_request->DevHandle;  		tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, -	    desc, tm_request->DevHandle, lun, tm_request->TaskMID)); +	    desc, le16_to_cpu(tm_request->DevHandle), lun, +	     le16_to_cpu(tm_request->TaskMID)));  	return 0;  } @@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||  	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -		if (!mpi_request->FunctionDependent1 || -		    mpi_request->FunctionDependent1 > -		    cpu_to_le16(ioc->facts.MaxDevHandle)) { +		if (!le16_to_cpu(mpi_request->FunctionDependent1) || +		    le16_to_cpu(mpi_request->FunctionDependent1) > +		    ioc->facts.MaxDevHandle) {  			ret = -EINVAL;  			mpt2sas_base_free_smid(ioc, smid);  			goto out; @@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		    mpt2sas_base_get_sense_buffer_dma(ioc, smid);  		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);  		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); -		mpt2sas_base_put_smid_scsi_io(ioc, smid, -		    le16_to_cpu(mpi_request->FunctionDependent1)); +		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) +			mpt2sas_base_put_smid_scsi_io(ioc, smid, +			    le16_to_cpu(mpi_request->FunctionDependent1)); +		else +			mpt2sas_base_put_smid_default(ioc, smid);  		break;  	}  	case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		Mpi2SCSITaskManagementRequest_t *tm_request =  		    (Mpi2SCSITaskManagementRequest_t *)mpi_request; +		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " +		    "handle(0x%04x), task_type(0x%02x)\n", ioc->name, +		    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); +  		if (tm_request->TaskType ==  		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||  		    tm_request->TaskType == @@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  			}  		} -		mutex_lock(&ioc->tm_cmds.mutex);  		mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(  		    tm_request->DevHandle));  		mpt2sas_base_put_smid_hi_priority(ioc, smid); @@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {  		Mpi2SCSITaskManagementRequest_t *tm_request =  		    (Mpi2SCSITaskManagementRequest_t *)mpi_request; -		mutex_unlock(&ioc->tm_cmds.mutex);  		mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(  		    tm_request->DevHandle));  	} else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || @@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {  			printk(MPT2SAS_INFO_FMT "issue target reset: handle "  			    "= (0x%04x)\n", ioc->name, -			    mpi_request->FunctionDependent1); +			    le16_to_cpu(mpi_request->FunctionDependent1));  			mpt2sas_halt_firmware(ioc); -			mutex_lock(&ioc->tm_cmds.mutex);  			mpt2sas_scsih_issue_tm(ioc, -			    mpi_request->FunctionDependent1, 0, -			    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); +			    le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, +			    0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, +			    NULL);  			ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -			mutex_unlock(&ioc->tm_cmds.mutex);  		} else  			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  			    FORCE_BIG_HAMMER); @@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "  	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, -	    (unsigned long long)request_data_dma, mpi_request->BufferLength)); +	    (unsigned long long)request_data_dma, +	    le32_to_cpu(mpi_request->BufferLength)));  	for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)  		mpi_request->ProductSpecific[i] = @@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,  	struct Scsi_Host *shost = class_to_shost(cdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	return snprintf(buf, PAGE_SIZE, "%02xh\n", -	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); +	return snprintf(buf, PAGE_SIZE, "%08xh\n", +	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));  }  static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,      _ctl_version_nvdata_persistent_show, NULL); @@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev,  	struct Scsi_Host *shost = class_to_shost(cdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	return snprintf(buf, PAGE_SIZE, "%02xh\n", -	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); +	return snprintf(buf, PAGE_SIZE, "%08xh\n", +	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));  }  static DEVICE_ATTR(version_nvdata_default, S_IRUGO,      _ctl_version_nvdata_default_show, NULL); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 8a5eeb1a5c8..69916e46e04 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index 5308a25cb30..3dcddfeb6f4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -2,7 +2,7 @@   * Logging Support for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index be171ed682e..c5ff26a2a51 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2,7 +2,7 @@   * Scsi Host Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -52,6 +52,7 @@  #include <linux/delay.h>  #include <linux/pci.h>  #include <linux/interrupt.h> +#include <linux/aer.h>  #include <linux/raid_class.h>  #include <linux/slab.h> @@ -109,14 +110,16 @@ struct sense_info {  }; +#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) +  /**   * struct fw_event_work - firmware event struct   * @list: link list framework   * @work: work object (ioc->fault_reset_work_q) + * @cancel_pending_work: flag set during reset handling   * @ioc: per adapter object   * @VF_ID: virtual function id   * @VP_ID: virtual port id - * @host_reset_handling: handling events during host reset   * @ignore: flag meaning this event has been marked to ignore   * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h   * @event_data: reply event data payload follows @@ -125,11 +128,11 @@ struct sense_info {   */  struct fw_event_work {  	struct list_head 	list; -	struct work_struct	work; +	u8			cancel_pending_work; +	struct delayed_work	delayed_work;  	struct MPT2SAS_ADAPTER *ioc;  	u8			VF_ID;  	u8			VP_ID; -	u8			host_reset_handling;  	u8			ignore;  	u16			event;  	void			*event_data; @@ -482,27 +485,17 @@ struct _sas_device *  mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,      u64 sas_address)  { -	struct _sas_device *sas_device, *r; +	struct _sas_device *sas_device; -	r = NULL; -	/* check the sas_device_init_list */ -	list_for_each_entry(sas_device, &ioc->sas_device_init_list, -	    list) { -		if (sas_device->sas_address != sas_address) -			continue; -		r = sas_device; -		goto out; -	} +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; -	/* then check the sas_device_list */ -	list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -		if (sas_device->sas_address != sas_address) -			continue; -		r = sas_device; -		goto out; -	} - out: -	return r; +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; + +	return NULL;  }  /** @@ -517,28 +510,17 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,  static struct _sas_device *  _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)  { -	struct _sas_device *sas_device, *r; +	struct _sas_device *sas_device; -	r = NULL; -	if (ioc->wait_for_port_enable_to_complete) { -		list_for_each_entry(sas_device, &ioc->sas_device_init_list, -		    list) { -			if (sas_device->handle != handle) -				continue; -			r = sas_device; -			goto out; -		} -	} else { -		list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -			if (sas_device->handle != handle) -				continue; -			r = sas_device; -			goto out; -		} -	} +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->handle == handle) +			return sas_device; - out: -	return r; +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->handle == handle) +			return sas_device; + +	return NULL;  }  /** @@ -555,10 +537,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,  {  	unsigned long flags; +	if (!sas_device) +		return; +  	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	list_del(&sas_device->list); -	memset(sas_device, 0, sizeof(struct _sas_device)); -	kfree(sas_device); +	if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_device->sas_address)) { +		list_del(&sas_device->list); +		kfree(sas_device); +	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  } @@ -988,7 +975,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,  	u32 chain_offset;  	u32 chain_length;  	u32 chain_flags; -	u32 sges_left; +	int sges_left;  	u32 sges_in_segment;  	u32 sgl_flags;  	u32 sgl_flags_last_element; @@ -1009,7 +996,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,  	sg_scmd = scsi_sglist(scmd);  	sges_left = scsi_dma_map(scmd); -	if (!sges_left) { +	if (sges_left < 0) {  		sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"  		" failed: request for %d bytes!\n", scsi_bufflen(scmd));  		return -ENOMEM; @@ -1395,7 +1382,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,  	}  	flags = le16_to_cpu(sas_device_pg0.Flags); -	device_info = le16_to_cpu(sas_device_pg0.DeviceInfo); +	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);  	sdev_printk(KERN_INFO, sdev,  	    "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " @@ -1963,65 +1950,78 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	}  } +  /**   * mpt2sas_scsih_issue_tm - main routine for sending tm requests   * @ioc: per adapter struct   * @device_handle: device handle + * @channel: the channel assigned by the OS + * @id: the id assigned by the OS   * @lun: lun number   * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)   * @smid_task: smid assigned to the task   * @timeout: timeout in seconds - * Context: The calling function needs to acquire the tm_cmds.mutex + * Context: user   *   * A generic API for sending task management requests to firmware.   * - * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling - * this API. - *   * The callback index is set inside `ioc->tm_cb_idx`.   * - * Return nothing. + * Return SUCCESS or FAILED.   */ -void -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, -    u8 type, u16 smid_task, ulong timeout) +int +mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, +    uint id, uint lun, u8 type, u16 smid_task, ulong timeout, +    struct scsi_cmnd *scmd)  {  	Mpi2SCSITaskManagementRequest_t *mpi_request;  	Mpi2SCSITaskManagementReply_t *mpi_reply;  	u16 smid = 0;  	u32 ioc_state;  	unsigned long timeleft; +	struct scsi_cmnd *scmd_lookup; +	int rc; +	mutex_lock(&ioc->tm_cmds.mutex);  	if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",  		    __func__, ioc->name); -		return; +		rc = FAILED; +		goto err_out;  	} -	if (ioc->shost_recovery) { +	if (ioc->shost_recovery || ioc->remove_host) {  		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",  		    __func__, ioc->name); -		return; +		rc = FAILED; +		goto err_out;  	}  	ioc_state = mpt2sas_base_get_iocstate(ioc, 0);  	if (ioc_state & MPI2_DOORBELL_USED) {  		dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "  		    "active!\n", ioc->name)); -		goto issue_host_reset; +		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +		rc = SUCCESS; +		goto err_out;  	}  	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {  		mpt2sas_base_fault_info(ioc, ioc_state &  		    MPI2_DOORBELL_DATA_MASK); -		goto issue_host_reset; +		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +		rc = SUCCESS; +		goto err_out;  	}  	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); -		return; +		rc = FAILED; +		goto err_out;  	}  	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," @@ -2035,21 +2035,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  	mpi_request->DevHandle = cpu_to_le16(handle);  	mpi_request->TaskType = type;  	mpi_request->TaskMID = cpu_to_le16(smid_task); -	mpi_request->VP_ID = 0;  /* TODO */ -	mpi_request->VF_ID = 0;  	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);  	mpt2sas_scsih_set_tm_flag(ioc, handle);  	init_completion(&ioc->tm_cmds.done);  	mpt2sas_base_put_smid_hi_priority(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); -	mpt2sas_scsih_clear_tm_flag(ioc, handle);  	if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n",  		    ioc->name, __func__);  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2SCSITaskManagementRequest_t)/4); -		if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) -			goto issue_host_reset; +		if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { +			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +			    FORCE_BIG_HAMMER); +			rc = SUCCESS; +			ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +			mpt2sas_scsih_clear_tm_flag(ioc, handle); +			goto err_out; +		}  	}  	if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { @@ -2059,12 +2062,57 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),  		    le32_to_cpu(mpi_reply->IOCLogInfo),  		    le32_to_cpu(mpi_reply->TerminationCount))); -		if (ioc->logging_level & MPT_DEBUG_TM) +		if (ioc->logging_level & MPT_DEBUG_TM) {  			_scsih_response_code(ioc, mpi_reply->ResponseCode); +			if (mpi_reply->IOCStatus) +				_debug_dump_mf(mpi_request, +				    sizeof(Mpi2SCSITaskManagementRequest_t)/4); +		}  	} -	return; - issue_host_reset: -	mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); + +	/* sanity check: +	 * Check to see the commands were terminated. +	 * This is only needed for eh callbacks, hence the scmd check. +	 */ +	rc = FAILED; +	if (scmd == NULL) +		goto bypass_sanity_checks; +	switch (type) { +	case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: +		scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); +		if (scmd_lookup && (scmd_lookup->serial_number == +		    scmd->serial_number)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; + +	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: +		if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; + +	case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: +		if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) +			rc = FAILED; +		else +			rc = SUCCESS; +		break; +	} + + bypass_sanity_checks: + +	mpt2sas_scsih_clear_tm_flag(ioc, handle); +	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +	mutex_unlock(&ioc->tm_cmds.mutex); + +	return rc; + + err_out: +	mutex_unlock(&ioc->tm_cmds.mutex); +	return rc;  }  /** @@ -2081,7 +2129,6 @@ _scsih_abort(struct scsi_cmnd *scmd)  	u16 smid;  	u16 handle;  	int r; -	struct scsi_cmnd *scmd_lookup;  	printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",  	    ioc->name, scmd); @@ -2116,19 +2163,10 @@ _scsih_abort(struct scsi_cmnd *scmd)  	mpt2sas_halt_firmware(ioc); -	mutex_lock(&ioc->tm_cmds.mutex);  	handle = sas_device_priv_data->sas_target->handle; -	mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, -	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30); - -	/* sanity check - see whether command actually completed */ -	scmd_lookup = _scsih_scsi_lookup_get(ioc, smid); -	if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, scmd->device->lun, +	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", @@ -2185,22 +2223,9 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)  		goto out;  	} -	mutex_lock(&ioc->tm_cmds.mutex); -	mpt2sas_scsih_issue_tm(ioc, handle, 0, -	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun, -	    30); - -	/* -	 *  sanity check see whether all commands to this device been -	 *  completed -	 */ -	if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id, -	    scmd->device->lun, scmd->device->channel)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, scmd->device->lun, +	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", @@ -2257,21 +2282,9 @@ _scsih_target_reset(struct scsi_cmnd *scmd)  		goto out;  	} -	mutex_lock(&ioc->tm_cmds.mutex); -	mpt2sas_scsih_issue_tm(ioc, handle, 0, -	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30); - -	/* -	 *  sanity check see whether all commands to this target been -	 *  completed -	 */ -	if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id, -	    scmd->device->channel)) -		r = FAILED; -	else -		r = SUCCESS; -	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, +	    scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, +	    30, scmd);   out:  	printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", @@ -2325,8 +2338,9 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)  	spin_lock_irqsave(&ioc->fw_event_lock, flags);  	list_add_tail(&fw_event->list, &ioc->fw_event_list); -	INIT_WORK(&fw_event->work, _firmware_event_work); -	queue_work(ioc->firmware_event_thread, &fw_event->work); +	INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); +	queue_delayed_work(ioc->firmware_event_thread, +	    &fw_event->delayed_work, 0);  	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  } @@ -2353,61 +2367,53 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work  	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  } +  /** - * _scsih_fw_event_add - requeue an event + * _scsih_queue_rescan - queue a topology rescan from user context   * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock.   *   * Return nothing.   */  static void -_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work -    *fw_event, unsigned long delay) +_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)  { -	unsigned long flags; -	if (ioc->firmware_event_thread == NULL) -		return; +	struct fw_event_work *fw_event; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	queue_work(ioc->firmware_event_thread, &fw_event->work); -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->wait_for_port_enable_to_complete) +		return; +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, fw_event);  }  /** - * _scsih_fw_event_off - turn flag off preventing event handling + * _scsih_fw_event_cleanup_queue - cleanup event queue   * @ioc: per adapter object   * - * Used to prevent handling of firmware events during adapter reset - * driver unload. + * Walk the firmware event queue, either killing timers, or waiting + * for outstanding events to complete   *   * Return nothing.   */  static void -_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc) +_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)  { -	unsigned long flags; +	struct fw_event_work *fw_event, *next; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	ioc->fw_events_off = 1; -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - -} - -/** - * _scsih_fw_event_on - turn flag on allowing firmware event handling - * @ioc: per adapter object - * - * Returns nothing. - */ -static void -_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc) -{ -	unsigned long flags; +	if (list_empty(&ioc->fw_event_list) || +	     !ioc->firmware_event_thread || in_interrupt()) +		return; -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	ioc->fw_events_off = 0; -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { +		if (cancel_delayed_work(&fw_event->delayed_work)) { +			_scsih_fw_event_free(ioc, fw_event); +			continue; +		} +		fw_event->cancel_pending_work = 1; +	}  }  /** @@ -2571,25 +2577,24 @@ static void  _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)  {  	Mpi2SCSITaskManagementRequest_t *mpi_request; -	struct MPT2SAS_TARGET *sas_target_priv_data;  	u16 smid;  	struct _sas_device *sas_device;  	unsigned long flags;  	struct _tr_list *delayed_tr; -	if (ioc->shost_recovery) { -		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", -		    __func__, ioc->name); +	if (ioc->shost_recovery || ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " +		   "progress!\n", __func__, ioc->name));  		return;  	}  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	/* skip is hidden raid component */ -	if (sas_device && sas_device->hidden_raid_component) +	if (sas_device && sas_device->hidden_raid_component) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return; +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);  	if (!smid) { @@ -2598,36 +2603,16 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)  			return;  		INIT_LIST_HEAD(&delayed_tr->list);  		delayed_tr->handle = handle; -		delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL; -		list_add_tail(&delayed_tr->list, -		    &ioc->delayed_tr_list); -		if (sas_device && sas_device->starget) { -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "DELAYED:tr:handle(0x%04x), " -			    "(open)\n", handle)); -		} else { -			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -			    "DELAYED:tr:handle(0x%04x), (open)\n", -			    ioc->name, handle)); -		} -		return; -	} - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_TR_SEND; -		sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; -		if (sas_device->starget && sas_device->starget->hostdata) { -			sas_target_priv_data = sas_device->starget->hostdata; -			sas_target_priv_data->tm_busy = 1; -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "tr:handle(0x%04x), (open)\n", -			    handle)); -		} -	} else { +		list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);  		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "tr:handle(0x%04x), (open)\n", ioc->name, handle)); +		    "DELAYED:tr:handle(0x%04x), (open)\n", +		    ioc->name, handle)); +		return;  	} +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " +	    "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, +	    ioc->tm_tr_cb_idx));  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);  	memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -2657,35 +2642,15 @@ static u8  _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,      u8 msix_index, u32 reply)  { -	unsigned long flags; -	u16 handle; -	struct _sas_device *sas_device;  	Mpi2SasIoUnitControlReply_t *mpi_reply =  	    mpt2sas_base_get_reply_virt_addr(ioc, reply); -	handle = le16_to_cpu(mpi_reply->DevHandle); - -	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; -		if (sas_device->starget) -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, -			    "sc_complete:handle(0x%04x), " -			    "ioc_status(0x%04x), loginfo(0x%08x)\n", -			    handle, le16_to_cpu(mpi_reply->IOCStatus), -			    le32_to_cpu(mpi_reply->IOCLogInfo))); -	} else { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "sc_complete:handle(0x%04x), " -		    "ioc_status(0x%04x), loginfo(0x%08x)\n", -		    ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus), -		    le32_to_cpu(mpi_reply->IOCLogInfo))); -	} - +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT +	    "sc_complete:handle(0x%04x), (open) " +	    "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", +	    ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, +	    le16_to_cpu(mpi_reply->IOCStatus), +	    le32_to_cpu(mpi_reply->IOCLogInfo)));  	return 1;  } @@ -2709,87 +2674,63 @@ static u8  _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply)  { -	unsigned long flags;  	u16 handle; -	struct _sas_device *sas_device; +	Mpi2SCSITaskManagementRequest_t *mpi_request_tm;  	Mpi2SCSITaskManagementReply_t *mpi_reply =  	    mpt2sas_base_get_reply_virt_addr(ioc, reply);  	Mpi2SasIoUnitControlRequest_t *mpi_request;  	u16 smid_sas_ctrl; -	struct MPT2SAS_TARGET *sas_target_priv_data;  	struct _tr_list *delayed_tr; -	u8 rc; -	handle = le16_to_cpu(mpi_reply->DevHandle); -	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (sas_device) { -		sas_device->state |= MPTSAS_STATE_TR_COMPLETE; -		if (sas_device->starget) { -			dewtprintk(ioc, starget_printk(KERN_INFO, -			    sas_device->starget, "tr_complete:handle(0x%04x), " -			    "(%s) ioc_status(0x%04x), loginfo(0x%08x), " -			    "completed(%d)\n", sas_device->handle, -			    (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ? -			    "open" : "active", -			    le16_to_cpu(mpi_reply->IOCStatus), -			    le32_to_cpu(mpi_reply->IOCLogInfo), -			    le32_to_cpu(mpi_reply->TerminationCount))); -			if (sas_device->starget->hostdata) { -				sas_target_priv_data = -				    sas_device->starget->hostdata; -				sas_target_priv_data->tm_busy = 0; -			} -		} -	} else { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -		    "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), " -		    "loginfo(0x%08x), completed(%d)\n", ioc->name, -		    handle, le16_to_cpu(mpi_reply->IOCStatus), -		    le32_to_cpu(mpi_reply->IOCLogInfo), -		    le32_to_cpu(mpi_reply->TerminationCount))); +	if (ioc->shost_recovery || ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " +		   "progress!\n", __func__, ioc->name)); +		return 1;  	} -	if (!list_empty(&ioc->delayed_tr_list)) { -		delayed_tr = list_entry(ioc->delayed_tr_list.next, -		    struct _tr_list, list); -		mpt2sas_base_free_smid(ioc, smid); -		if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL) -			_scsih_tm_tr_send(ioc, delayed_tr->handle); -		list_del(&delayed_tr->list); -		kfree(delayed_tr); -		rc = 0; /* tells base_interrupt not to free mf */ -	} else -		rc = 1; - -	if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) -		return rc; - -	if (ioc->shost_recovery) { -		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", -		    __func__, ioc->name); -		return rc; +	mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); +	handle = le16_to_cpu(mpi_request_tm->DevHandle); +	if (handle != le16_to_cpu(mpi_reply->DevHandle)) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " +		    "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, +		    le16_to_cpu(mpi_reply->DevHandle), smid)); +		return 0;  	} +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT +	    "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " +	    "loginfo(0x%08x), completed(%d)\n", ioc->name, +	    handle, smid, le16_to_cpu(mpi_reply->IOCStatus), +	    le32_to_cpu(mpi_reply->IOCLogInfo), +	    le32_to_cpu(mpi_reply->TerminationCount))); +  	smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);  	if (!smid_sas_ctrl) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); -		return rc; +		return 1;  	} -	if (sas_device) -		sas_device->state |= MPTSAS_STATE_CNTRL_SEND; - +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " +	    "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, +	    ioc->tm_sas_control_cb_idx));  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);  	memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;  	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -	mpi_request->DevHandle = mpi_reply->DevHandle; +	mpi_request->DevHandle = mpi_request_tm->DevHandle;  	mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); -	return rc; + +	if (!list_empty(&ioc->delayed_tr_list)) { +		delayed_tr = list_entry(ioc->delayed_tr_list.next, +		    struct _tr_list, list); +		mpt2sas_base_free_smid(ioc, smid); +		_scsih_tm_tr_send(ioc, delayed_tr->handle); +		list_del(&delayed_tr->list); +		kfree(delayed_tr); +		return 0; /* tells base_interrupt not to free mf */ +	} +	return 1;  }  /** @@ -3021,25 +2962,32 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  	scmd->scsi_done = done;  	sas_device_priv_data = scmd->device->hostdata; -	if (!sas_device_priv_data) { +	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd);  		return 0;  	}  	sas_target_priv_data = sas_device_priv_data->sas_target; -	if (!sas_target_priv_data || sas_target_priv_data->handle == -	    MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) { +	/* invalid device handle */ +	if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd);  		return 0;  	} -	/* see if we are busy with task managment stuff */ -	if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) -		return SCSI_MLQUEUE_DEVICE_BUSY; -	else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) +	/* host recovery or link resets sent via IOCTLs */ +	if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)  		return SCSI_MLQUEUE_HOST_BUSY; +	/* device busy with task managment */ +	else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) +		return SCSI_MLQUEUE_DEVICE_BUSY; +	/* device has been deleted */ +	else if (sas_target_priv_data->deleted) { +		scmd->result = DID_NO_CONNECT << 16; +		scmd->scsi_done(scmd); +		return 0; +	}  	if (scmd->sc_data_direction == DMA_FROM_DEVICE)  		mpi_control = MPI2_SCSIIO_CONTROL_READ; @@ -3110,8 +3058,11 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  		}  	} -	mpt2sas_base_put_smid_scsi_io(ioc, smid, -	    sas_device_priv_data->sas_target->handle); +	if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) +		mpt2sas_base_put_smid_scsi_io(ioc, smid, +		    sas_device_priv_data->sas_target->handle); +	else +		mpt2sas_base_put_smid_default(ioc, smid);  	return 0;   out: @@ -3301,8 +3252,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  		struct sense_info data;  		_scsih_normalize_sense(scmd->sense_buffer, &data);  		printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " -		    "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey, -		    data.asc, data.ascq); +		    "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, +		    data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));  	}  	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { @@ -3356,7 +3307,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)  		mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;  		mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;  		mpi_request.SlotStatus = -		    MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; +		    cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);  		mpi_request.DevHandle = cpu_to_le16(handle);  		mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;  		if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, @@ -4008,6 +3959,134 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)  }  /** + * _scsih_check_access_status - check access flags + * @ioc: per adapter object + * @sas_address: sas address + * @handle: sas device handle + * @access_flags: errors returned during discovery of the device + * + * Return 0 for success, else failure + */ +static u8 +_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, +   u16 handle, u8 access_status) +{ +	u8 rc = 1; +	char *desc = NULL; + +	switch (access_status) { +	case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: +		rc = 0; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: +		desc = "sata capability failed"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: +		desc = "sata affiliation conflict"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: +		desc = "route not addressable"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: +		desc = "smp error not addressable"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: +		desc = "device blocked"; +		break; +	case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: +	case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: +		desc = "sata initialization failed"; +		break; +	default: +		desc = "unknown"; +		break; +	} + +	if (!rc) +		return 0; + +	printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " +	    "handle(0x%04x)\n", ioc->name, desc, +	    (unsigned long long)sas_address, handle); +	return rc; +} + +static void +_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	Mpi2ConfigReply_t mpi_reply; +	Mpi2SasDevicePage0_t sas_device_pg0; +	struct _sas_device *sas_device; +	u32 ioc_status; +	unsigned long flags; +	u64 sas_address; +	struct scsi_target *starget; +	struct MPT2SAS_TARGET *sas_target_priv_data; +	u32 device_info; + +	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, +	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) +		return; + +	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) +		return; + +	/* check if this is end device */ +	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); +	if (!(_scsih_is_end_device(device_info))) +		return; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); + +	if (!sas_device) { +		printk(MPT2SAS_ERR_FMT "device is not present " +		    "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	if (unlikely(sas_device->handle != handle)) { +		starget = sas_device->starget; +		sas_target_priv_data = starget->hostdata; +		starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" +		   " to (0x%04x)!!!\n", sas_device->handle, handle); +		sas_target_priv_data->handle = handle; +		sas_device->handle = handle; +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	/* check if device is present */ +	if (!(le16_to_cpu(sas_device_pg0.Flags) & +	    MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { +		printk(MPT2SAS_ERR_FMT "device is not present " +		    "handle(0x%04x), flags!!!\n", ioc->name, handle); +		return; +	} + +	/* check if there were any issues with discovery */ +	if (_scsih_check_access_status(ioc, sas_address, handle, +	    sas_device_pg0.AccessStatus)) +		return; +	_scsih_ublock_io_device(ioc, handle); + +} + +/**   * _scsih_add_device -  creating sas device object   * @ioc: per adapter object   * @handle: sas device handle @@ -4045,6 +4124,8 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} +	sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +  	/* check if device is present */  	if (!(le16_to_cpu(sas_device_pg0.Flags) &  	    MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { @@ -4055,15 +4136,10 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} -	/* check if there were any issus with discovery */ -	if (sas_device_pg0.AccessStatus == -	    MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) { -		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -		    ioc->name, __FILE__, __LINE__, __func__); -		printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n", -		    ioc->name, sas_device_pg0.AccessStatus); +	/* check if there were any issues with discovery */ +	if (_scsih_check_access_status(ioc, sas_address, handle, +	    sas_device_pg0.AccessStatus))  		return -1; -	}  	/* check if this is end device */  	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); @@ -4073,17 +4149,14 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  		return -1;  	} -	sas_address = le64_to_cpu(sas_device_pg0.SASAddress);  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,  	    sas_address);  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -	if (sas_device) { -		_scsih_ublock_io_device(ioc, handle); +	if (sas_device)  		return 0; -	}  	sas_device = kzalloc(sizeof(struct _sas_device),  	    GFP_KERNEL); @@ -4126,67 +4199,38 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  }  /** - * _scsih_remove_device -  removing sas device object + * _scsih_remove_pd_device -  removing sas device pd object   * @ioc: per adapter object - * @sas_device: the sas_device object + * @sas_device_delete: the sas_device object   * + * For hidden raid components, we do driver-fw handshake from + * hotplug work threads.   * Return nothing.   */  static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device -    *sas_device) +_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device +    sas_device)  { -	struct MPT2SAS_TARGET *sas_target_priv_data;  	Mpi2SasIoUnitControlReply_t mpi_reply;  	Mpi2SasIoUnitControlRequest_t mpi_request; -	u16 device_handle, handle; - -	if (!sas_device) -		return; +	u16 vol_handle, handle; -	handle = sas_device->handle; +	handle = sas_device.handle;  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"  	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, -	    (unsigned long long) sas_device->sas_address)); - -	if (sas_device->starget && sas_device->starget->hostdata) { -		sas_target_priv_data = sas_device->starget->hostdata; -		sas_target_priv_data->deleted = 1; -	} - -	if (ioc->remove_host || ioc->shost_recovery || !handle) -		goto out; +	    (unsigned long long) sas_device.sas_address)); -	if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " -		   "target_reset handle(0x%04x)\n", ioc->name, -		   handle)); -		goto skip_tr; -	} - -	/* Target Reset to flush out all the outstanding IO */ -	device_handle = (sas_device->hidden_raid_component) ? -	    sas_device->volume_handle : handle; -	if (device_handle) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " -		    "handle(0x%04x)\n", ioc->name, device_handle)); -		mutex_lock(&ioc->tm_cmds.mutex); -		mpt2sas_scsih_issue_tm(ioc, device_handle, 0, -		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); -		ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -		mutex_unlock(&ioc->tm_cmds.mutex); -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " -		    "done: handle(0x%04x)\n", ioc->name, device_handle)); -		if (ioc->shost_recovery) -			goto out; -	} - skip_tr: - -	if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) { -		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " -		   "sas_cntrl handle(0x%04x)\n", ioc->name, handle)); -		goto out; -	} +	vol_handle = sas_device.volume_handle; +	if (!vol_handle) +		return; +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " +	    "handle(0x%04x)\n", ioc->name, vol_handle)); +	mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0, +	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL); +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " +	    "done: handle(0x%04x)\n", ioc->name, vol_handle)); +	if (ioc->shost_recovery) +		return;  	/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" @@ -4194,34 +4238,68 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device  	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));  	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;  	mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; -	mpi_request.DevHandle = handle; -	mpi_request.VF_ID = 0; /* TODO */ -	mpi_request.VP_ID = 0; +	mpi_request.DevHandle = cpu_to_le16(handle);  	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, -	    &mpi_request)) != 0) { +	    &mpi_request)) != 0)  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); -	}  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"  	    "(0x%04x), loginfo(0x%08x)\n", ioc->name,  	    le16_to_cpu(mpi_reply.IOCStatus),  	    le32_to_cpu(mpi_reply.IOCLogInfo))); - out: +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x)," +	    " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, +	    (unsigned long long) sas_device.sas_address)); +} -	_scsih_ublock_io_device(ioc, handle); +/** + * _scsih_remove_device -  removing sas device object + * @ioc: per adapter object + * @sas_device_delete: the sas_device object + * + * Return nothing. + */ +static void +_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, +    struct _sas_device *sas_device) +{ +	struct _sas_device sas_device_backup; +	struct MPT2SAS_TARGET *sas_target_priv_data; -	mpt2sas_transport_port_remove(ioc, sas_device->sas_address, -	    sas_device->sas_address_parent); +	if (!sas_device) +		return; -	printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" -	    "(0x%016llx)\n", ioc->name, handle, -	    (unsigned long long) sas_device->sas_address); +	memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));  	_scsih_sas_device_remove(ioc, sas_device); -	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle" -	    "(0x%04x)\n", ioc->name, __func__, handle)); +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " +	    "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, +	    sas_device_backup.handle, (unsigned long long) +	    sas_device_backup.sas_address)); + +	if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { +		sas_target_priv_data = sas_device_backup.starget->hostdata; +		sas_target_priv_data->deleted = 1; +	} + +	if (sas_device_backup.hidden_raid_component) +		_scsih_remove_pd_device(ioc, sas_device_backup); + +	_scsih_ublock_io_device(ioc, sas_device_backup.handle); + +	mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, +	    sas_device_backup.sas_address_parent); + +	printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" +	    "(0x%016llx)\n", ioc->name, sas_device_backup.handle, +	    (unsigned long long) sas_device_backup.sas_address); + +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " +	    "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, +	    sas_device_backup.handle, (unsigned long long) +	    sas_device_backup.sas_address));  }  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4331,7 +4409,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  		_scsih_sas_topology_change_event_debug(ioc, event_data);  #endif -	if (ioc->shost_recovery) +	if (ioc->shost_recovery || ioc->remove_host)  		return;  	if (!ioc->sas_hba.num_phys) @@ -4370,7 +4448,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			    "expander event\n", ioc->name));  			return;  		} -		if (ioc->shost_recovery) +		if (ioc->shost_recovery || ioc->remove_host)  			return;  		phy_number = event_data->StartPhyNum + i;  		reason_code = event_data->PHY[i].PhyStatus & @@ -4393,8 +4471,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			mpt2sas_transport_update_links(ioc, sas_address,  			    handle, phy_number, link_rate); -			if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5) -				_scsih_ublock_io_device(ioc, handle); +			if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) +				break; + +			_scsih_check_device(ioc, handle);  			break;  		case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: @@ -4520,10 +4600,10 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,  		     event_data);  #endif -	if (!(event_data->ReasonCode == +	if (event_data->ReasonCode !=  	    MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && -	   event_data->ReasonCode == -	    MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)) +	   event_data->ReasonCode != +	    MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)  		return;  	spin_lock_irqsave(&ioc->sas_device_lock, flags); @@ -4630,7 +4710,6 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,  	    __func__)); -	mutex_lock(&ioc->tm_cmds.mutex);  	termination_count = 0;  	query_count = 0;  	mpi_reply = ioc->tm_cmds.reply; @@ -4654,8 +4733,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  		lun = sas_device_priv_data->lun;  		query_count++; -		mpt2sas_scsih_issue_tm(ioc, handle, lun, -		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); +		mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, +		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);  		ioc->tm_cmds.status = MPT2_CMD_NOT_USED;  		ioc_status = le16_to_cpu(mpi_reply->IOCStatus)  		    & MPI2_IOCSTATUS_MASK; @@ -4666,13 +4745,11 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  		     MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))  			continue; -		mpt2sas_scsih_issue_tm(ioc, handle, lun, -		    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30); -		ioc->tm_cmds.status = MPT2_CMD_NOT_USED; +		mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, +		    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);  		termination_count += le32_to_cpu(mpi_reply->TerminationCount);  	}  	ioc->broadcast_aen_busy = 0; -	mutex_unlock(&ioc->tm_cmds.mutex);  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT  	    "%s - exit, query_count = %d termination_count = %d\n", @@ -5442,6 +5519,26 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work  }  /** + * _scsih_prep_device_scan - initialize parameters prior to device scan + * @ioc: per adapter object + * + * Set the deleted flag prior to device scan.  If the device is found during + * the scan, then we clear the deleted flag. + */ +static void +_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) +{ +	struct MPT2SAS_DEVICE *sas_device_priv_data; +	struct scsi_device *sdev; + +	shost_for_each_device(sdev, ioc->shost) { +		sas_device_priv_data = sdev->hostdata; +		if (sas_device_priv_data && sas_device_priv_data->sas_target) +			sas_device_priv_data->sas_target->deleted = 1; +	} +} + +/**   * _scsih_mark_responding_sas_device - mark a sas_devices as responding   * @ioc: per adapter object   * @sas_address: sas address @@ -5467,10 +5564,13 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  		if (sas_device->sas_address == sas_address &&  		    sas_device->slot == slot && sas_device->starget) {  			sas_device->responding = 1; -			sas_device->state = 0;  			starget = sas_device->starget; -			sas_target_priv_data = starget->hostdata; -			sas_target_priv_data->tm_busy = 0; +			if (starget && starget->hostdata) { +				sas_target_priv_data = starget->hostdata; +				sas_target_priv_data->tm_busy = 0; +				sas_target_priv_data->deleted = 0; +			} else +				sas_target_priv_data = NULL;  			starget_printk(KERN_INFO, sas_device->starget,  			    "handle(0x%04x), sas_addr(0x%016llx), enclosure "  			    "logical id(0x%016llx), slot(%d)\n", handle, @@ -5483,7 +5583,8 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    sas_device->handle);  			sas_device->handle = handle; -			sas_target_priv_data->handle = handle; +			if (sas_target_priv_data) +				sas_target_priv_data->handle = handle;  			goto out;  		}  	} @@ -5558,6 +5659,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	list_for_each_entry(raid_device, &ioc->raid_device_list, list) {  		if (raid_device->wwid == wwid && raid_device->starget) { +			starget = raid_device->starget; +			if (starget && starget->hostdata) { +				sas_target_priv_data = starget->hostdata; +				sas_target_priv_data->deleted = 0; +			} else +				sas_target_priv_data = NULL;  			raid_device->responding = 1;  			starget_printk(KERN_INFO, raid_device->starget,  			    "handle(0x%04x), wwid(0x%016llx)\n", handle, @@ -5567,9 +5674,8 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    raid_device->handle);  			raid_device->handle = handle; -			starget = raid_device->starget; -			sas_target_priv_data = starget->hostdata; -			sas_target_priv_data->handle = handle; +			if (sas_target_priv_data) +				sas_target_priv_data->handle = handle;  			goto out;  		}  	} @@ -5694,13 +5800,13 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)  }  /** - * _scsih_remove_unresponding_devices - removing unresponding devices + * _scsih_remove_unresponding_sas_devices - removing unresponding devices   * @ioc: per adapter object   *   * Return nothing.   */  static void -_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) +_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  {  	struct _sas_device *sas_device, *sas_device_next;  	struct _sas_node *sas_expander; @@ -5722,8 +5828,6 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)  			    (unsigned long long)  			    sas_device->enclosure_logical_id,  			    sas_device->slot); -		/* invalidate the device handle */ -		sas_device->handle = 0;  		_scsih_remove_device(ioc, sas_device);  	} @@ -5774,32 +5878,33 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  	case MPT2_IOC_PRE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); -		_scsih_fw_event_off(ioc);  		break;  	case MPT2_IOC_AFTER_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); +		if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { +			ioc->scsih_cmds.status |= MPT2_CMD_RESET; +			mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); +			complete(&ioc->scsih_cmds.done); +		}  		if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {  			ioc->tm_cmds.status |= MPT2_CMD_RESET;  			mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);  			complete(&ioc->tm_cmds.done);  		} -		_scsih_fw_event_on(ioc); +		_scsih_fw_event_cleanup_queue(ioc);  		_scsih_flush_running_cmds(ioc); +		_scsih_queue_rescan(ioc);  		break;  	case MPT2_IOC_DONE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "  		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));  		_scsih_sas_host_refresh(ioc); +		_scsih_prep_device_scan(ioc);  		_scsih_search_responding_sas_devices(ioc);  		_scsih_search_responding_raid_devices(ioc);  		_scsih_search_responding_expanders(ioc);  		break; -	case MPT2_IOC_RUNNING: -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " -		    "MPT2_IOC_RUNNING\n", ioc->name, __func__)); -		_scsih_remove_unresponding_devices(ioc); -		break;  	}  } @@ -5815,21 +5920,28 @@ static void  _firmware_event_work(struct work_struct *work)  {  	struct fw_event_work *fw_event = container_of(work, -	    struct fw_event_work, work); +	    struct fw_event_work, delayed_work.work);  	unsigned long flags;  	struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;  	/* the queue is being flushed so ignore this event */ -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	if (ioc->fw_events_off || ioc->remove_host) { -		spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->remove_host || fw_event->cancel_pending_work) {  		_scsih_fw_event_free(ioc, fw_event);  		return;  	} -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -	if (ioc->shost_recovery) { -		_scsih_fw_event_requeue(ioc, fw_event, 1000); +	if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { +		_scsih_fw_event_free(ioc, fw_event); +		spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); +		if (ioc->shost_recovery) { +			init_completion(&ioc->shost_recovery_done); +			spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, +			    flags); +			wait_for_completion(&ioc->shost_recovery_done); +		} else +			spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, +			    flags); +		_scsih_remove_unresponding_sas_devices(ioc);  		return;  	} @@ -5891,16 +6003,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  {  	struct fw_event_work *fw_event;  	Mpi2EventNotificationReply_t *mpi_reply; -	unsigned long flags;  	u16 event; +	u16 sz;  	/* events turned off due to host reset or driver unloading */ -	spin_lock_irqsave(&ioc->fw_event_lock, flags); -	if (ioc->fw_events_off || ioc->remove_host) { -		spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (ioc->remove_host)  		return 1; -	} -	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	event = le16_to_cpu(mpi_reply->Event); @@ -5947,8 +6055,8 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  		    ioc->name, __FILE__, __LINE__, __func__);  		return 1;  	} -	fw_event->event_data = -	    kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); +	sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; +	fw_event->event_data = kzalloc(sz, GFP_ATOMIC);  	if (!fw_event->event_data) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); @@ -5957,7 +6065,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  	}  	memcpy(fw_event->event_data, mpi_reply->EventData, -	    mpi_reply->EventDataLength*4); +	    sz);  	fw_event->ioc = ioc;  	fw_event->VF_ID = mpi_reply->VF_ID;  	fw_event->VP_ID = mpi_reply->VP_ID; @@ -6158,6 +6266,18 @@ _scsih_shutdown(struct pci_dev *pdev)  {  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	struct workqueue_struct	*wq; +	unsigned long flags; + +	ioc->remove_host = 1; +	_scsih_fw_event_cleanup_queue(ioc); + +	spin_lock_irqsave(&ioc->fw_event_lock, flags); +	wq = ioc->firmware_event_thread; +	ioc->firmware_event_thread = NULL; +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +	if (wq) +		destroy_workqueue(wq);  	_scsih_ir_shutdown(ioc);  	mpt2sas_base_detach(ioc); @@ -6184,7 +6304,7 @@ _scsih_remove(struct pci_dev *pdev)  	unsigned long flags;  	ioc->remove_host = 1; -	_scsih_fw_event_off(ioc); +	_scsih_fw_event_cleanup_queue(ioc);  	spin_lock_irqsave(&ioc->fw_event_lock, flags);  	wq = ioc->firmware_event_thread; @@ -6557,6 +6677,122 @@ _scsih_resume(struct pci_dev *pdev)  }  #endif /* CONFIG_PM */ +/** + * _scsih_pci_error_detected - Called when a PCI error is detected. + * @pdev: PCI device struct + * @state: PCI channel state + * + * Description: Called when a PCI error is detected. + * + * Return value: + *      PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t +_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", +	    ioc->name, state); + +	switch (state) { +	case pci_channel_io_normal: +		return PCI_ERS_RESULT_CAN_RECOVER; +	case pci_channel_io_frozen: +		scsi_block_requests(ioc->shost); +		mpt2sas_base_stop_watchdog(ioc); +		mpt2sas_base_free_resources(ioc); +		return PCI_ERS_RESULT_NEED_RESET; +	case pci_channel_io_perm_failure: +		_scsih_remove(pdev); +		return PCI_ERS_RESULT_DISCONNECT; +	} +	return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * _scsih_pci_slot_reset - Called when PCI slot has been reset. + * @pdev: PCI device struct + * + * Description: This routine is called by the pci error recovery + * code after the PCI slot has been reset, just before we + * should resume normal operations. + */ +static pci_ers_result_t +_scsih_pci_slot_reset(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	int rc; + +	printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", +		ioc->name); + +	ioc->pdev = pdev; +	rc = mpt2sas_base_map_resources(ioc); +	if (rc) +		return PCI_ERS_RESULT_DISCONNECT; + + +	rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +	    FORCE_BIG_HAMMER); + +	printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, +	    (rc == 0) ? "success" : "failed"); + +	if (!rc) +		return PCI_ERS_RESULT_RECOVERED; +	else +		return PCI_ERS_RESULT_DISCONNECT; +} + +/** + * _scsih_pci_resume() - resume normal ops after PCI reset + * @pdev: pointer to PCI device + * + * Called when the error recovery driver tells us that its + * OK to resume normal operation. Use completion to allow + * halted scsi ops to resume. + */ +static void +_scsih_pci_resume(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); + +	pci_cleanup_aer_uncorrect_error_status(pdev); +	mpt2sas_base_start_watchdog(ioc); +	scsi_unblock_requests(ioc->shost); +} + +/** + * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * @pdev: pointer to PCI device + */ +static pci_ers_result_t +_scsih_pci_mmio_enabled(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", +	    ioc->name); + +	/* TODO - dump whatever for debugging purposes */ + +	/* Request a slot reset. */ +	return PCI_ERS_RESULT_NEED_RESET; +} + +static struct pci_error_handlers _scsih_err_handler = { +	.error_detected = _scsih_pci_error_detected, +	.mmio_enabled = _scsih_pci_mmio_enabled, +	.slot_reset =	_scsih_pci_slot_reset, +	.resume =	_scsih_pci_resume, +};  static struct pci_driver scsih_driver = {  	.name		= MPT2SAS_DRIVER_NAME, @@ -6564,6 +6800,7 @@ static struct pci_driver scsih_driver = {  	.probe		= _scsih_probe,  	.remove		= __devexit_p(_scsih_remove),  	.shutdown	= _scsih_shutdown, +	.err_handler	= &_scsih_err_handler,  #ifdef CONFIG_PM  	.suspend	= _scsih_suspend,  	.resume		= _scsih_resume, diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index bd7ca2b49f8..2727c3b6510 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -2,7 +2,7 @@   * SAS Transport Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2009  LSI Corporation + * Copyright (C) 2007-2010  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -465,6 +465,85 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	return rc;  } + +/** + * _transport_delete_duplicate_port - (see below description) + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @sas_address: sas address of device being added + * @phy_num: phy number + * + * This function is called when attempting to add a new port that is claiming + * the same phy resources already in use by another port.  If we don't release + * the claimed phy resources, the sas transport layer will hang from the BUG + * in sas_port_add_phy. + * + * The reason we would hit this issue is becuase someone is changing the + * sas address of a device on the fly, meanwhile controller firmware sends + * EVENTs out of order when removing the previous instance of the device. + */ +static void +_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, +    struct _sas_node *sas_node, u64 sas_address, int phy_num) +{ +	struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; +	struct _sas_phy *mpt2sas_phy; + +	printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " +	    "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, +	    phy_num); + +	mpt2sas_port_duplicate = NULL; +	list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { +		dev_printk(KERN_ERR, &mpt2sas_port->port->dev, +		    "existing device at sas_addr(0x%016llx), num_phys(%d)\n", +		    (unsigned long long) +		    mpt2sas_port->remote_identify.sas_address, +		    mpt2sas_port->num_phys); +		list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, +		    port_siblings) { +			dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, +			    "phy_number(%d)\n", mpt2sas_phy->phy_id); +			if (mpt2sas_phy->phy_id == phy_num) +				mpt2sas_port_duplicate = mpt2sas_port; +		} +	} + +	if (!mpt2sas_port_duplicate) +		return; + +	dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, +	    "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", +	    (unsigned long long) +	    mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); +	ioc->logging_level |= MPT_DEBUG_TRANSPORT; +	mpt2sas_transport_port_remove(ioc, +	    mpt2sas_port_duplicate->remote_identify.sas_address, +	    sas_node->sas_address); +	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; +} + +/** + * _transport_sanity_check - sanity check when adding a new port + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @sas_address: sas address of device being added + * + * See the explanation above from _transport_delete_duplicate_port + */ +static void +_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, +     u64 sas_address) +{ +	int i; + +	for (i = 0; i < sas_node->num_phys; i++) +		if (sas_node->phy[i].remote_identify.sas_address == sas_address) +			if (sas_node->phy[i].phy_belongs_to_port) +				_transport_delete_duplicate_port(ioc, sas_node, +					sas_address, i); +} +  /**   * mpt2sas_transport_port_add - insert port to the list   * @ioc: per adapter object @@ -522,6 +601,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,  		goto out_fail;  	} +	_transport_sanity_check(ioc, sas_node, +	    mpt2sas_port->remote_identify.sas_address); +  	for (i = 0; i < sas_node->num_phys; i++) {  		if (sas_node->phy[i].remote_identify.sas_address !=  		    mpt2sas_port->remote_identify.sas_address) @@ -553,6 +635,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,  			    mpt2sas_port->remote_identify.sas_address,  			    mpt2sas_phy->phy_id);  		sas_port_add_phy(port, mpt2sas_phy->phy); +		mpt2sas_phy->phy_belongs_to_port = 1;  	}  	mpt2sas_port->port = port; @@ -651,6 +734,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			    (unsigned long long)  			    mpt2sas_port->remote_identify.sas_address,  			    mpt2sas_phy->phy_id); +		mpt2sas_phy->phy_belongs_to_port = 0;  		sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);  		list_del(&mpt2sas_phy->port_siblings);  	} @@ -1341,7 +1425,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  		memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));  		req->sense_len = sizeof(*mpi_reply);  		req->resid_len = 0; -		rsp->resid_len -= mpi_reply->ResponseDataLength; +		rsp->resid_len -= +		    le16_to_cpu(mpi_reply->ResponseDataLength);  	} else {  		dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT  		    "%s - no reply\n", ioc->name, __func__)); | 
