diff options
| -rw-r--r-- | drivers/scsi/hpsa.c | 266 | ||||
| -rw-r--r-- | drivers/scsi/hpsa.h | 42 | ||||
| -rw-r--r-- | drivers/scsi/hpsa_cmd.h | 49 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 23 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 6 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 5 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 258 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_mem.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 60 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 297 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 6 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 16 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 15 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_target.h | 16 | 
24 files changed, 715 insertions, 369 deletions
| diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5858600bfe59..31184b35370f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -48,6 +48,7 @@  #include <linux/bitmap.h>  #include <linux/atomic.h>  #include <linux/jiffies.h> +#include <linux/percpu.h>  #include <asm/div64.h>  #include "hpsa_cmd.h"  #include "hpsa.h" @@ -193,7 +194,8 @@ static int number_of_controllers;  static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);  static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);  static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); -static void start_io(struct ctlr_info *h); +static void lock_and_start_io(struct ctlr_info *h); +static void start_io(struct ctlr_info *h, unsigned long *flags);  #ifdef CONFIG_COMPAT  static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); @@ -695,7 +697,7 @@ static inline void addQ(struct list_head *list, struct CommandList *c)  static inline u32 next_command(struct ctlr_info *h, u8 q)  {  	u32 a; -	struct reply_pool *rq = &h->reply_queue[q]; +	struct reply_queue_buffer *rq = &h->reply_queue[q];  	unsigned long flags;  	if (h->transMethod & CFGTBL_Trans_io_accel1) @@ -844,8 +846,8 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,  	spin_lock_irqsave(&h->lock, flags);  	addQ(&h->reqQ, c);  	h->Qdepth++; +	start_io(h, &flags);  	spin_unlock_irqrestore(&h->lock, flags); -	start_io(h);  }  static inline void removeQ(struct CommandList *c) @@ -1554,9 +1556,13 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,  			dev_warn(&h->pdev->dev,  				"%s: task complete with check condition.\n",  				"HP SSD Smart Path"); +			cmd->result |= SAM_STAT_CHECK_CONDITION;  			if (c2->error_data.data_present != -					IOACCEL2_SENSE_DATA_PRESENT) +					IOACCEL2_SENSE_DATA_PRESENT) { +				memset(cmd->sense_buffer, 0, +					SCSI_SENSE_BUFFERSIZE);  				break; +			}  			/* copy the sense data */  			data_len = c2->error_data.sense_data_len;  			if (data_len > SCSI_SENSE_BUFFERSIZE) @@ -1566,7 +1572,6 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,  					sizeof(c2->error_data.sense_data_buff);  			memcpy(cmd->sense_buffer,  				c2->error_data.sense_data_buff, data_len); -			cmd->result |= SAM_STAT_CHECK_CONDITION;  			retry = 1;  			break;  		case IOACCEL2_STATUS_SR_TASK_COMP_BUSY: @@ -1651,16 +1656,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h,  	if (is_logical_dev_addr_mode(dev->scsi3addr) &&  		c2->error_data.serv_response ==  			IOACCEL2_SERV_RESPONSE_FAILURE) { -		if (c2->error_data.status == -			IOACCEL2_STATUS_SR_IOACCEL_DISABLED) -			dev_warn(&h->pdev->dev, -				"%s: Path is unavailable, retrying on standard path.\n", -				"HP SSD Smart Path"); -		else -			dev_warn(&h->pdev->dev, -				"%s: Error 0x%02x, retrying on standard path.\n", -				"HP SSD Smart Path", c2->error_data.status); -  		dev->offload_enabled = 0;  		h->drv_req_rescan = 1;	/* schedule controller for a rescan */  		cmd->result = DID_SOFT_ERROR << 16; @@ -1991,20 +1986,26 @@ static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h,  	wait_for_completion(&wait);  } +static u32 lockup_detected(struct ctlr_info *h) +{ +	int cpu; +	u32 rc, *lockup_detected; + +	cpu = get_cpu(); +	lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); +	rc = *lockup_detected; +	put_cpu(); +	return rc; +} +  static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h,  	struct CommandList *c)  { -	unsigned long flags; -  	/* If controller lockup detected, fake a hardware error. */ -	spin_lock_irqsave(&h->lock, flags); -	if (unlikely(h->lockup_detected)) { -		spin_unlock_irqrestore(&h->lock, flags); +	if (unlikely(lockup_detected(h)))  		c->err_info->CommandStatus = CMD_HARDWARE_ERR; -	} else { -		spin_unlock_irqrestore(&h->lock, flags); +	else  		hpsa_scsi_do_simple_cmd_core(h, c); -	}  }  #define MAX_DRIVER_CMD_RETRIES 25 @@ -2429,7 +2430,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,  		buflen = 16;  	buf = kzalloc(64, GFP_KERNEL);  	if (!buf) -		return -1; +		return -ENOMEM;  	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);  	if (rc == 0)  		memcpy(device_id, &buf[8], buflen); @@ -2515,27 +2516,21 @@ static int hpsa_get_volume_status(struct ctlr_info *h,  		return HPSA_VPD_LV_STATUS_UNSUPPORTED;  	/* Does controller have VPD for logical volume status? */ -	if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) { -		dev_warn(&h->pdev->dev, "Logical volume status VPD page is unsupported.\n"); +	if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS))  		goto exit_failed; -	}  	/* Get the size of the VPD return buffer */  	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,  					buf, HPSA_VPD_HEADER_SZ); -	if (rc != 0) { -		dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n"); +	if (rc != 0)  		goto exit_failed; -	}  	size = buf[3];  	/* Now get the whole VPD buffer */  	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,  					buf, size + HPSA_VPD_HEADER_SZ); -	if (rc != 0) { -		dev_warn(&h->pdev->dev, "Logical volume status VPD inquiry failed.\n"); +	if (rc != 0)  		goto exit_failed; -	}  	status = buf[4]; /* status byte */  	kfree(buf); @@ -2548,11 +2543,11 @@ exit_failed:  /* Determine offline status of a volume.   * Return either:   *  0 (not offline) - * -1 (offline for unknown reasons) + *  0xff (offline for unknown reasons)   *  # (integer code indicating one of several NOT READY states   *     describing why a volume is to be kept offline)   */ -static unsigned char hpsa_volume_offline(struct ctlr_info *h, +static int hpsa_volume_offline(struct ctlr_info *h,  					unsigned char scsi3addr[])  {  	struct CommandList *c; @@ -2651,11 +2646,15 @@ static int hpsa_update_device_info(struct ctlr_info *h,  	if (this_device->devtype == TYPE_DISK &&  		is_logical_dev_addr_mode(scsi3addr)) { +		int volume_offline; +  		hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);  		if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)  			hpsa_get_ioaccel_status(h, scsi3addr, this_device); -		this_device->volume_offline = -			hpsa_volume_offline(h, scsi3addr); +		volume_offline = hpsa_volume_offline(h, scsi3addr); +		if (volume_offline < 0 || volume_offline > 0xff) +			volume_offline = HPSA_VPD_LV_STATUS_UNSUPPORTED; +		this_device->volume_offline = volume_offline & 0xff;  	} else {  		this_device->raid_level = RAID_UNKNOWN;  		this_device->offload_config = 0; @@ -2861,26 +2860,20 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,  	nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) /  							responsesize; -  	/* find ioaccel2 handle in list of physicals: */  	for (i = 0; i < nphysicals; i++) { +		struct ext_report_lun_entry *entry = &physicals->LUN[i]; +  		/* handle is in bytes 28-31 of each lun */ -		if (memcmp(&((struct ReportExtendedLUNdata *) -				physicals)->LUN[i][20], &find, 4) != 0) { +		if (entry->ioaccel_handle != find)  			continue; /* didn't match */ -		}  		found = 1; -		memcpy(scsi3addr, &((struct ReportExtendedLUNdata *) -					physicals)->LUN[i][0], 8); +		memcpy(scsi3addr, entry->lunid, 8);  		if (h->raid_offload_debug > 0)  			dev_info(&h->pdev->dev, -				"%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", +				"%s: Searched h=0x%08x, Found h=0x%08x, scsiaddr 0x%8phN\n",  				__func__, find, -				((struct ReportExtendedLUNdata *) -					physicals)->LUN[i][20], -				scsi3addr[0], scsi3addr[1], scsi3addr[2], -				scsi3addr[3], scsi3addr[4], scsi3addr[5], -				scsi3addr[6], scsi3addr[7]); +				entry->ioaccel_handle, scsi3addr);  		break; /* found it */  	} @@ -2965,7 +2958,8 @@ u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,  		return RAID_CTLR_LUNID;  	if (i < logicals_start) -		return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0]; +		return &physdev_list->LUN[i - +				(raid_ctlr_position == 0)].lunid[0];  	if (i < last_device)  		return &logdev_list->LUN[i - nphysicals - @@ -3074,7 +3068,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)  		ndev_allocated++;  	} -	if (unlikely(is_scsi_rev_5(h))) +	if (is_scsi_rev_5(h))  		raid_ctlr_position = 0;  	else  		raid_ctlr_position = nphysicals + nlogicals; @@ -3971,7 +3965,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,  	struct hpsa_scsi_dev_t *dev;  	unsigned char scsi3addr[8];  	struct CommandList *c; -	unsigned long flags;  	int rc = 0;  	/* Get the ptr to our adapter structure out of cmd->host. */ @@ -3984,14 +3977,11 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,  	}  	memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); -	spin_lock_irqsave(&h->lock, flags); -	if (unlikely(h->lockup_detected)) { -		spin_unlock_irqrestore(&h->lock, flags); +	if (unlikely(lockup_detected(h))) {  		cmd->result = DID_ERROR << 16;  		done(cmd);  		return 0;  	} -	spin_unlock_irqrestore(&h->lock, flags);  	c = cmd_alloc(h);  	if (c == NULL) {			/* trouble... */  		dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); @@ -4103,16 +4093,13 @@ static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)  	 * we can prevent new rescan threads from piling up on a  	 * locked up controller.  	 */ -	spin_lock_irqsave(&h->lock, flags); -	if (unlikely(h->lockup_detected)) { -		spin_unlock_irqrestore(&h->lock, flags); +	if (unlikely(lockup_detected(h))) {  		spin_lock_irqsave(&h->scan_lock, flags);  		h->scan_finished = 1;  		wake_up_all(&h->scan_wait_queue);  		spin_unlock_irqrestore(&h->scan_lock, flags);  		return 1;  	} -	spin_unlock_irqrestore(&h->lock, flags);  	return 0;  } @@ -4963,7 +4950,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)  		buff = kmalloc(iocommand.buf_size, GFP_KERNEL);  		if (buff == NULL)  			return -EFAULT; -		if (iocommand.Request.Type.Direction == XFER_WRITE) { +		if (iocommand.Request.Type.Direction & XFER_WRITE) {  			/* Copy the data into the buffer we created */  			if (copy_from_user(buff, iocommand.buf,  				iocommand.buf_size)) { @@ -5026,7 +5013,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)  		rc = -EFAULT;  		goto out;  	} -	if (iocommand.Request.Type.Direction == XFER_READ && +	if ((iocommand.Request.Type.Direction & XFER_READ) &&  		iocommand.buf_size > 0) {  		/* Copy the data out of the buffer we created */  		if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { @@ -5103,7 +5090,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)  			status = -ENOMEM;  			goto cleanup1;  		} -		if (ioc->Request.Type.Direction == XFER_WRITE) { +		if (ioc->Request.Type.Direction & XFER_WRITE) {  			if (copy_from_user(buff[sg_used], data_ptr, sz)) {  				status = -ENOMEM;  				goto cleanup1; @@ -5155,7 +5142,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)  		status = -EFAULT;  		goto cleanup0;  	} -	if (ioc->Request.Type.Direction == XFER_READ && ioc->buf_size > 0) { +	if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) {  		/* Copy the data out of the buffer we created */  		BYTE __user *ptr = ioc->buf;  		for (i = 0; i < sg_used; i++) { @@ -5459,13 +5446,12 @@ static void __iomem *remap_pci_mem(ulong base, ulong size)  /* Takes cmds off the submission queue and sends them to the hardware,   * then puts them on the queue of cmds waiting for completion. + * Assumes h->lock is held   */ -static void start_io(struct ctlr_info *h) +static void start_io(struct ctlr_info *h, unsigned long *flags)  {  	struct CommandList *c; -	unsigned long flags; -	spin_lock_irqsave(&h->lock, flags);  	while (!list_empty(&h->reqQ)) {  		c = list_entry(h->reqQ.next, struct CommandList, list);  		/* can't do anything if fifo is full */ @@ -5488,14 +5474,20 @@ static void start_io(struct ctlr_info *h)  		 * condition.  		 */  		h->commands_outstanding++; -		if (h->commands_outstanding > h->max_outstanding) -			h->max_outstanding = h->commands_outstanding;  		/* Tell the controller execute command */ -		spin_unlock_irqrestore(&h->lock, flags); +		spin_unlock_irqrestore(&h->lock, *flags);  		h->access.submit_command(h, c); -		spin_lock_irqsave(&h->lock, flags); +		spin_lock_irqsave(&h->lock, *flags);  	} +} + +static void lock_and_start_io(struct ctlr_info *h) +{ +	unsigned long flags; + +	spin_lock_irqsave(&h->lock, flags); +	start_io(h, &flags);  	spin_unlock_irqrestore(&h->lock, flags);  } @@ -5563,7 +5555,7 @@ static inline void finish_cmd(struct CommandList *c)  	else if (c->cmd_type == CMD_IOCTL_PEND)  		complete(c->waiting);  	if (unlikely(io_may_be_stalled)) -		start_io(h); +		lock_and_start_io(h);  }  static inline u32 hpsa_tag_contains_index(u32 tag) @@ -5840,12 +5832,12 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,  		dev_info(&pdev->dev, "using doorbell to reset controller\n");  		writel(use_doorbell, vaddr + SA5_DOORBELL); -		/* PMC hardware guys tell us we need a 5 second delay after +		/* PMC hardware guys tell us we need a 10 second delay after  		 * doorbell reset and before any attempt to talk to the board  		 * at all to ensure that this actually works and doesn't fall  		 * over in some weird corner cases.  		 */ -		msleep(5000); +		msleep(10000);  	} else { /* Try to do it the PCI power state way */  		/* Quoting from the Open CISS Specification: "The Power @@ -6166,6 +6158,8 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)  	if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {  		dev_info(&h->pdev->dev, "MSIX\n");  		h->msix_vector = MAX_REPLY_QUEUES; +		if (h->msix_vector > num_online_cpus()) +			h->msix_vector = num_online_cpus();  		err = pci_enable_msix(h->pdev, hpsa_msix_entries,  				      h->msix_vector);  		if (err > 0) { @@ -6615,6 +6609,17 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)  			h->ioaccel_cmd_pool, h->ioaccel_cmd_pool_dhandle);  } +static void hpsa_irq_affinity_hints(struct ctlr_info *h) +{ +	int i, cpu, rc; + +	cpu = cpumask_first(cpu_online_mask); +	for (i = 0; i < h->msix_vector; i++) { +		rc = irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu)); +		cpu = cpumask_next(cpu, cpu_online_mask); +	} +} +  static int hpsa_request_irq(struct ctlr_info *h,  	irqreturn_t (*msixhandler)(int, void *),  	irqreturn_t (*intxhandler)(int, void *)) @@ -6634,6 +6639,7 @@ static int hpsa_request_irq(struct ctlr_info *h,  			rc = request_irq(h->intr[i], msixhandler,  					0, h->devname,  					&h->q[i]); +		hpsa_irq_affinity_hints(h);  	} else {  		/* Use single reply pool */  		if (h->msix_vector > 0 || h->msi_vector) { @@ -6685,12 +6691,15 @@ static void free_irqs(struct ctlr_info *h)  	if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) {  		/* Single reply queue, only one irq to free */  		i = h->intr_mode; +		irq_set_affinity_hint(h->intr[i], NULL);  		free_irq(h->intr[i], &h->q[i]);  		return;  	} -	for (i = 0; i < h->msix_vector; i++) +	for (i = 0; i < h->msix_vector; i++) { +		irq_set_affinity_hint(h->intr[i], NULL);  		free_irq(h->intr[i], &h->q[i]); +	}  }  static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h) @@ -6707,6 +6716,20 @@ static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h)  #endif /* CONFIG_PCI_MSI */  } +static void hpsa_free_reply_queues(struct ctlr_info *h) +{ +	int i; + +	for (i = 0; i < h->nreply_queues; i++) { +		if (!h->reply_queue[i].head) +			continue; +		pci_free_consistent(h->pdev, h->reply_queue_size, +			h->reply_queue[i].head, h->reply_queue[i].busaddr); +		h->reply_queue[i].head = NULL; +		h->reply_queue[i].busaddr = 0; +	} +} +  static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)  {  	hpsa_free_irqs_and_disable_msix(h); @@ -6714,8 +6737,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)  	hpsa_free_cmd_pool(h);  	kfree(h->ioaccel1_blockFetchTable);  	kfree(h->blockFetchTable); -	pci_free_consistent(h->pdev, h->reply_pool_size, -		h->reply_pool, h->reply_pool_dhandle); +	hpsa_free_reply_queues(h);  	if (h->vaddr)  		iounmap(h->vaddr);  	if (h->transtable) @@ -6740,16 +6762,38 @@ static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)  	}  } +static void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value) +{ +	int i, cpu; + +	cpu = cpumask_first(cpu_online_mask); +	for (i = 0; i < num_online_cpus(); i++) { +		u32 *lockup_detected; +		lockup_detected = per_cpu_ptr(h->lockup_detected, cpu); +		*lockup_detected = value; +		cpu = cpumask_next(cpu, cpu_online_mask); +	} +	wmb(); /* be sure the per-cpu variables are out to memory */ +} +  static void controller_lockup_detected(struct ctlr_info *h)  {  	unsigned long flags; +	u32 lockup_detected;  	h->access.set_intr_mask(h, HPSA_INTR_OFF);  	spin_lock_irqsave(&h->lock, flags); -	h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); +	lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); +	if (!lockup_detected) { +		/* no heartbeat, but controller gave us a zero. */ +		dev_warn(&h->pdev->dev, +			"lockup detected but scratchpad register is zero\n"); +		lockup_detected = 0xffffffff; +	} +	set_lockup_detected_for_all_cpus(h, lockup_detected);  	spin_unlock_irqrestore(&h->lock, flags);  	dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", -			h->lockup_detected); +			lockup_detected);  	pci_disable_device(h->pdev);  	spin_lock_irqsave(&h->lock, flags);  	fail_all_cmds_on_list(h, &h->cmpQ); @@ -6884,7 +6928,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)  	struct ctlr_info *h = container_of(to_delayed_work(work),  					struct ctlr_info, monitor_ctlr_work);  	detect_controller_lockup(h); -	if (h->lockup_detected) +	if (lockup_detected(h))  		return;  	if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) { @@ -6934,7 +6978,6 @@ reinit_after_soft_reset:  	 * the 5 lower bits of the address are used by the hardware. and by  	 * the driver.  See comments in hpsa.h for more info.  	 */ -#define COMMANDLIST_ALIGNMENT 128  	BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);  	h = kzalloc(sizeof(*h), GFP_KERNEL);  	if (!h) @@ -6949,6 +6992,13 @@ reinit_after_soft_reset:  	spin_lock_init(&h->offline_device_lock);  	spin_lock_init(&h->scan_lock);  	spin_lock_init(&h->passthru_count_lock); + +	/* Allocate and clear per-cpu variable lockup_detected */ +	h->lockup_detected = alloc_percpu(u32); +	if (!h->lockup_detected) +		goto clean1; +	set_lockup_detected_for_all_cpus(h, 0); +  	rc = hpsa_pci_init(h);  	if (rc != 0)  		goto clean1; @@ -7072,6 +7122,8 @@ clean4:  	free_irqs(h);  clean2:  clean1: +	if (h->lockup_detected) +		free_percpu(h->lockup_detected);  	kfree(h);  	return rc;  } @@ -7080,16 +7132,10 @@ static void hpsa_flush_cache(struct ctlr_info *h)  {  	char *flush_buf;  	struct CommandList *c; -	unsigned long flags;  	/* Don't bother trying to flush the cache if locked up */ -	spin_lock_irqsave(&h->lock, flags); -	if (unlikely(h->lockup_detected)) { -		spin_unlock_irqrestore(&h->lock, flags); +	if (unlikely(lockup_detected(h)))  		return; -	} -	spin_unlock_irqrestore(&h->lock, flags); -  	flush_buf = kzalloc(4, GFP_KERNEL);  	if (!flush_buf)  		return; @@ -7165,8 +7211,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)  	pci_free_consistent(h->pdev,  		h->nr_cmds * sizeof(struct ErrorInfo),  		h->errinfo_pool, h->errinfo_pool_dhandle); -	pci_free_consistent(h->pdev, h->reply_pool_size, -		h->reply_pool, h->reply_pool_dhandle); +	hpsa_free_reply_queues(h);  	kfree(h->cmd_pool_bits);  	kfree(h->blockFetchTable);  	kfree(h->ioaccel1_blockFetchTable); @@ -7174,6 +7219,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)  	kfree(h->hba_inquiry_data);  	pci_disable_device(pdev);  	pci_release_regions(pdev); +	free_percpu(h->lockup_detected);  	kfree(h);  } @@ -7278,8 +7324,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)  	 * 10 = 6 s/g entry or 24k  	 */ +	/* If the controller supports either ioaccel method then +	 * we can also use the RAID stack submit path that does not +	 * perform the superfluous readl() after each command submission. +	 */ +	if (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2)) +		access = SA5_performant_access_no_read; +  	/* Controller spec: zero out this buffer. */ -	memset(h->reply_pool, 0, h->reply_pool_size); +	for (i = 0; i < h->nreply_queues; i++) +		memset(h->reply_queue[i].head, 0, h->reply_queue_size);  	bft[7] = SG_ENTRIES_IN_CMD + 4;  	calc_bucket_map(bft, ARRAY_SIZE(bft), @@ -7295,8 +7349,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)  	for (i = 0; i < h->nreply_queues; i++) {  		writel(0, &h->transtable->RepQAddr[i].upper); -		writel(h->reply_pool_dhandle + -			(h->max_commands * sizeof(u64) * i), +		writel(h->reply_queue[i].busaddr,  			&h->transtable->RepQAddr[i].lower);  	} @@ -7344,8 +7397,10 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)  				h->ioaccel1_blockFetchTable);  		/* initialize all reply queue entries to unused */ -		memset(h->reply_pool, (u8) IOACCEL_MODE1_REPLY_UNUSED, -				h->reply_pool_size); +		for (i = 0; i < h->nreply_queues; i++) +			memset(h->reply_queue[i].head, +				(u8) IOACCEL_MODE1_REPLY_UNUSED, +				h->reply_queue_size);  		/* set all the constant fields in the accelerator command  		 * frames once at init time to save CPU cycles later. @@ -7407,7 +7462,6 @@ static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)  	 * because the 7 lower bits of the address are used by the  	 * hardware.  	 */ -#define IOACCEL1_COMMANDLIST_ALIGNMENT 128  	BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %  			IOACCEL1_COMMANDLIST_ALIGNMENT);  	h->ioaccel_cmd_pool = @@ -7445,7 +7499,6 @@ static int ioaccel2_alloc_cmds_and_bft(struct ctlr_info *h)  	if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES)  		h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES; -#define IOACCEL2_COMMANDLIST_ALIGNMENT 128  	BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %  			IOACCEL2_COMMANDLIST_ALIGNMENT);  	h->ioaccel2_cmd_pool = @@ -7503,16 +7556,17 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)  		}  	} -	/* TODO, check that this next line h->nreply_queues is correct */  	h->nreply_queues = h->msix_vector > 0 ? h->msix_vector : 1;  	hpsa_get_max_perf_mode_cmds(h);  	/* Performant mode ring buffer and supporting data structures */ -	h->reply_pool_size = h->max_commands * sizeof(u64) * h->nreply_queues; -	h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, -				&(h->reply_pool_dhandle)); +	h->reply_queue_size = h->max_commands * sizeof(u64);  	for (i = 0; i < h->nreply_queues; i++) { -		h->reply_queue[i].head = &h->reply_pool[h->max_commands * i]; +		h->reply_queue[i].head = pci_alloc_consistent(h->pdev, +						h->reply_queue_size, +						&(h->reply_queue[i].busaddr)); +		if (!h->reply_queue[i].head) +			goto clean_up;  		h->reply_queue[i].size = h->max_commands;  		h->reply_queue[i].wraparound = 1;  /* spec: init to 1 */  		h->reply_queue[i].current_entry = 0; @@ -7521,18 +7575,14 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)  	/* Need a block fetch table for performant mode */  	h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *  				sizeof(u32)), GFP_KERNEL); - -	if ((h->reply_pool == NULL) -		|| (h->blockFetchTable == NULL)) +	if (!h->blockFetchTable)  		goto clean_up;  	hpsa_enter_performant_mode(h, trans_support);  	return;  clean_up: -	if (h->reply_pool) -		pci_free_consistent(h->pdev, h->reply_pool_size, -			h->reply_pool, h->reply_pool_dhandle); +	hpsa_free_reply_queues(h);  	kfree(h->blockFetchTable);  } diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1e3cf33a82cf..24472cec7de3 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -57,11 +57,12 @@ struct hpsa_scsi_dev_t {  }; -struct reply_pool { +struct reply_queue_buffer {  	u64 *head;  	size_t size;  	u8 wraparound;  	u32 current_entry; +	dma_addr_t busaddr;  };  #pragma pack(1) @@ -116,11 +117,8 @@ struct ctlr_info {  	int 	nr_cmds; /* Number of commands allowed on this controller */  	struct CfgTable __iomem *cfgtable;  	int	interrupts_enabled; -	int	major;  	int 	max_commands;  	int	commands_outstanding; -	int 	max_outstanding; /* Debug */ -	int	usage_count;  /* number of opens all all minor devices */  #	define PERF_MODE_INT	0  #	define DOORBELL_INT	1  #	define SIMPLE_MODE_INT	2 @@ -177,11 +175,9 @@ struct ctlr_info {  	/*  	 * Performant mode completion buffers  	 */ -	u64 *reply_pool; -	size_t reply_pool_size; -	struct reply_pool reply_queue[MAX_REPLY_QUEUES]; +	size_t reply_queue_size; +	struct reply_queue_buffer reply_queue[MAX_REPLY_QUEUES];  	u8 nreply_queues; -	dma_addr_t reply_pool_dhandle;  	u32 *blockFetchTable;  	u32 *ioaccel1_blockFetchTable;  	u32 *ioaccel2_blockFetchTable; @@ -196,7 +192,7 @@ struct ctlr_info {  	u64 last_heartbeat_timestamp;  	u32 heartbeat_sample_interval;  	atomic_t firmware_flash_in_progress; -	u32 lockup_detected; +	u32 *lockup_detected;  	struct delayed_work monitor_ctlr_work;  	int remove_in_progress;  	u32 fifo_recently_full; @@ -233,11 +229,9 @@ struct ctlr_info {  #define CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE	(1 << 31)  #define RESCAN_REQUIRED_EVENT_BITS \ -		(CTLR_STATE_CHANGE_EVENT | \ -		CTLR_ENCLOSURE_HOT_PLUG_EVENT | \ +		(CTLR_ENCLOSURE_HOT_PLUG_EVENT | \  		CTLR_STATE_CHANGE_EVENT_PHYSICAL_DRV | \  		CTLR_STATE_CHANGE_EVENT_LOGICAL_DRV | \ -		CTLR_STATE_CHANGE_EVENT_REDUNDANT_CNTRL | \  		CTLR_STATE_CHANGE_EVENT_AIO_ENABLED_DISABLED | \  		CTLR_STATE_CHANGE_EVENT_AIO_CONFIG_CHANGE)  	spinlock_t offline_device_lock; @@ -346,22 +340,23 @@ struct offline_device_entry {  static void SA5_submit_command(struct ctlr_info *h,  	struct CommandList *c)  { -	dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, -		c->Header.Tag.lower);  	writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);  	(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);  } +static void SA5_submit_command_no_read(struct ctlr_info *h, +	struct CommandList *c) +{ +	writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); +} +  static void SA5_submit_command_ioaccel2(struct ctlr_info *h,  	struct CommandList *c)  { -	dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, -		c->Header.Tag.lower);  	if (c->cmd_type == CMD_IOACCEL2)  		writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);  	else  		writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); -	(void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);  }  /* @@ -399,7 +394,7 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)  static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)  { -	struct reply_pool *rq = &h->reply_queue[q]; +	struct reply_queue_buffer *rq = &h->reply_queue[q];  	unsigned long flags, register_value = FIFO_EMPTY;  	/* msi auto clears the interrupt pending bit. */ @@ -478,7 +473,6 @@ static bool SA5_intr_pending(struct ctlr_info *h)  {  	unsigned long register_value  =  		readl(h->vaddr + SA5_INTR_STATUS); -	dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value);  	return register_value & SA5_INTR_PENDING;  } @@ -515,7 +509,7 @@ static bool SA5_ioaccel_mode1_intr_pending(struct ctlr_info *h)  static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)  {  	u64 register_value; -	struct reply_pool *rq = &h->reply_queue[q]; +	struct reply_queue_buffer *rq = &h->reply_queue[q];  	unsigned long flags;  	BUG_ON(q >= h->nreply_queues); @@ -573,6 +567,14 @@ static struct access_method SA5_performant_access = {  	SA5_performant_completed,  }; +static struct access_method SA5_performant_access_no_read = { +	SA5_submit_command_no_read, +	SA5_performant_intr_mask, +	SA5_fifo_full, +	SA5_performant_intr_pending, +	SA5_performant_completed, +}; +  struct board_type {  	u32	board_id;  	char	*product_name; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index b5cc7052339f..b5125dc31439 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -151,7 +151,7 @@  #define HPSA_VPD_HEADER_SZ              4  /* Logical volume states */ -#define HPSA_VPD_LV_STATUS_UNSUPPORTED			-1 +#define HPSA_VPD_LV_STATUS_UNSUPPORTED			0xff  #define HPSA_LV_OK                                      0x0  #define HPSA_LV_UNDERGOING_ERASE			0x0F  #define HPSA_LV_UNDERGOING_RPI				0x12 @@ -238,11 +238,21 @@ struct ReportLUNdata {  	u8 LUN[HPSA_MAX_LUN][8];  }; +struct ext_report_lun_entry { +	u8 lunid[8]; +	u8 wwid[8]; +	u8 device_type; +	u8 device_flags; +	u8 lun_count; /* multi-lun device, how many luns */ +	u8 redundant_paths; +	u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ +}; +  struct ReportExtendedLUNdata {  	u8 LUNListLength[4];  	u8 extended_response_flag;  	u8 reserved[3]; -	u8 LUN[HPSA_MAX_LUN][24]; +	struct ext_report_lun_entry LUN[HPSA_MAX_LUN];  };  struct SenseSubsystem_info { @@ -375,6 +385,7 @@ struct ctlr_info; /* defined in hpsa.h */   *        or a bus address.   */ +#define COMMANDLIST_ALIGNMENT 128  struct CommandList {  	struct CommandListHeader Header;  	struct RequestBlock      Request; @@ -389,21 +400,7 @@ struct CommandList {  	struct list_head list;  	struct completion *waiting;  	void   *scsi_cmd; - -/* on 64 bit architectures, to get this to be 32-byte-aligned - * it so happens we need PAD_64 bytes of padding, on 32 bit systems, - * we need PAD_32 bytes of padding (see below).   This does that. - * If it happens that 64 bit and 32 bit systems need different - * padding, PAD_32 and PAD_64 can be set independently, and. - * the code below will do the right thing. - */ -#define IS_32_BIT ((8 - sizeof(long))/4) -#define IS_64_BIT (!IS_32_BIT) -#define PAD_32 (40) -#define PAD_64 (12) -#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64) -	u8 pad[COMMANDLIST_PAD]; -}; +} __aligned(COMMANDLIST_ALIGNMENT);  /* Max S/G elements in I/O accelerator command */  #define IOACCEL1_MAXSGENTRIES           24 @@ -413,6 +410,7 @@ struct CommandList {   * Structure for I/O accelerator (mode 1) commands.   * Note that this structure must be 128-byte aligned in size.   */ +#define IOACCEL1_COMMANDLIST_ALIGNMENT 128  struct io_accel1_cmd {  	u16 dev_handle;			/* 0x00 - 0x01 */  	u8  reserved1;			/* 0x02 */ @@ -440,12 +438,7 @@ struct io_accel1_cmd {  	struct vals32 host_addr;	/* 0x70 - 0x77 */  	u8  CISS_LUN[8];		/* 0x78 - 0x7F */  	struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES]; -#define IOACCEL1_PAD_64 0 -#define IOACCEL1_PAD_32 0 -#define IOACCEL1_PAD (IS_32_BIT * IOACCEL1_PAD_32 + \ -			IS_64_BIT * IOACCEL1_PAD_64) -	u8 pad[IOACCEL1_PAD]; -}; +} __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT);  #define IOACCEL1_FUNCTION_SCSIIO        0x00  #define IOACCEL1_SGLOFFSET              32 @@ -510,14 +503,11 @@ struct io_accel2_scsi_response {  	u8 sense_data_buff[32];		/* sense/response data buffer */  }; -#define IOACCEL2_64_PAD 76 -#define IOACCEL2_32_PAD 76 -#define IOACCEL2_PAD (IS_32_BIT * IOACCEL2_32_PAD + \ -			IS_64_BIT * IOACCEL2_64_PAD)  /*   * Structure for I/O accelerator (mode 2 or m2) commands.   * Note that this structure must be 128-byte aligned in size.   */ +#define IOACCEL2_COMMANDLIST_ALIGNMENT 128  struct io_accel2_cmd {  	u8  IU_type;			/* IU Type */  	u8  direction;			/* direction, memtype, and encryption */ @@ -544,8 +534,7 @@ struct io_accel2_cmd {  	u32 tweak_upper;		/* Encryption tweak, upper 4 bytes */  	struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];  	struct io_accel2_scsi_response error_data; -	u8 pad[IOACCEL2_PAD]; -}; +} __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT);  /*   * defines for Mode 2 command struct @@ -636,7 +625,7 @@ struct TransTable_struct {  	u32            RepQCount;  	u32            RepQCtrAddrLow32;  	u32            RepQCtrAddrHigh32; -#define MAX_REPLY_QUEUES 8 +#define MAX_REPLY_QUEUES 64  	struct vals32  RepQAddr[MAX_REPLY_QUEUES];  }; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 94a3cafe7197..434e9037908e 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -640,6 +640,7 @@ struct lpfc_hba {  #define HBA_DEVLOSS_TMO         0x2000 /* HBA in devloss timeout */  #define HBA_RRQ_ACTIVE		0x4000 /* process the rrq active list */  #define HBA_FCP_IOQ_FLUSH	0x8000 /* FCP I/O queues being flushed */ +#define HBA_FW_DUMP_OP		0x10000 /* Skips fn reset before FW dump */  	uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/  	struct lpfc_dmabuf slim2p; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 8d5b6ceec9c9..1d7a5c34ee8c 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -919,10 +919,15 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)  		phba->cfg_sriov_nr_virtfn = 0;  	} +	if (opcode == LPFC_FW_DUMP) +		phba->hba_flag |= HBA_FW_DUMP_OP; +  	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); -	if (status != 0) +	if (status != 0) { +		phba->hba_flag &= ~HBA_FW_DUMP_OP;  		return status; +	}  	/* wait for the device to be quiesced before firmware reset */  	msleep(100); @@ -2364,7 +2369,7 @@ lpfc_oas_tgt_store(struct device *dev, struct device_attribute *attr,  	uint8_t wwpn[WWN_SZ];  	int rc; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	/* count may include a LF at end of string */ @@ -2432,7 +2437,7 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr,  	uint8_t wwpn[WWN_SZ];  	int rc; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	/* count may include a LF at end of string */ @@ -2499,7 +2504,7 @@ lpfc_oas_lun_state_store(struct device *dev, struct device_attribute *attr,  	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;  	int val = 0; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	if (!isdigit(buf[0])) @@ -2565,7 +2570,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],  	int rc = 0; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	if (oas_state) { @@ -2670,7 +2675,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr,  	uint64_t oas_lun;  	int len = 0; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) @@ -2716,7 +2721,7 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,  	uint64_t scsi_lun;  	ssize_t rc; -	if (!phba->cfg_EnableXLane) +	if (!phba->cfg_fof)  		return -EPERM;  	if (wwn_to_u64(phba->cfg_oas_vpt_wwpn) == 0) @@ -4655,7 +4660,7 @@ LPFC_ATTR_R(EnableXLane, 0, 0, 1, "Enable Express Lane Feature.");  #       0x0 - 0x7f  = CS_CTL field in FC header (high 7 bits)  # Value range is [0x0,0x7f]. Default value is 0  */ -LPFC_ATTR_R(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature."); +LPFC_ATTR_RW(XLanePriority, 0, 0x0, 0x7f, "CS_CTL for Express Lane Feature.");  /*  # lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index ca2f4ea7cdef..5b5c825d9576 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2009-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2009-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index a94d4c9dfaa5..928ef609f363 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2010-2012 Emulex.  All rights reserved.                * + * Copyright (C) 2010-2014 Emulex.  All rights reserved.                *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index adda0bf7a244..db5604f01a1a 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * @@ -289,6 +289,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,  void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);  void lpfc_sli_bemem_bcopy(void *, void *, uint32_t);  void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); +void lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba);  void lpfc_sli_hba_iocb_abort(struct lpfc_hba *);  void lpfc_sli_flush_fcp_rings(struct lpfc_hba *);  int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, @@ -310,6 +311,9 @@ int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,  int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd);  int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,  			uint64_t, lpfc_ctx_cmd); +int +lpfc_sli_abort_taskmgmt(struct lpfc_vport *, struct lpfc_sli_ring *, +			uint16_t, uint64_t, lpfc_ctx_cmd);  void lpfc_mbox_timeout(unsigned long);  void lpfc_mbox_timeout_handler(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 828c08e9389e..b0aedce3f54b 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2007-2012 Emulex.  All rights reserved.           * + * Copyright (C) 2007-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * @@ -2314,7 +2314,7 @@ proc_cq:  			goto too_big;  	} -	if (phba->cfg_EnableXLane) { +	if (phba->cfg_fof) {  		/* OAS CQ */  		qp = phba->sli4_hba.oas_cq; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 624fe0b3cc0b..7a5d81a65be8 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 294c072e9083..2a17e31265b8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -5634,6 +5634,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  		ndlp->active_rrqs_xri_bitmap =  				mempool_alloc(vport->phba->active_rrq_pool,  					      GFP_KERNEL); +		if (ndlp->active_rrqs_xri_bitmap) +			memset(ndlp->active_rrqs_xri_bitmap, 0, +			       ndlp->phba->cfg_rrq_xri_bitmap_sz);  	} diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 3d9438ce59ab..236259252379 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index fd79f7de7666..f432ec180cf8 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2009-2013 Emulex.  All rights reserved.                * + * Copyright (C) 2009-2014 Emulex.  All rights reserved.                *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 635eeb3d6987..06f9a5b79e66 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -820,57 +820,153 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)  }  /** - * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset + * lpfc_sli4_free_sp_events - Cleanup sp_queue_events to free + * rspiocb which got deferred + *   * @phba: pointer to lpfc HBA data structure.   * - * This routine will do uninitialization after the HBA is reset when bring - * down the SLI Layer. + * This routine will cleanup completed slow path events after HBA is reset + * when bringing down the SLI Layer. + *   *   * Return codes - *   0 - success. - *   Any other value - error. + *   void.   **/ -static int -lpfc_hba_down_post_s3(struct lpfc_hba *phba) +static void +lpfc_sli4_free_sp_events(struct lpfc_hba *phba) +{ +	struct lpfc_iocbq *rspiocbq; +	struct hbq_dmabuf *dmabuf; +	struct lpfc_cq_event *cq_event; + +	spin_lock_irq(&phba->hbalock); +	phba->hba_flag &= ~HBA_SP_QUEUE_EVT; +	spin_unlock_irq(&phba->hbalock); + +	while (!list_empty(&phba->sli4_hba.sp_queue_event)) { +		/* Get the response iocb from the head of work queue */ +		spin_lock_irq(&phba->hbalock); +		list_remove_head(&phba->sli4_hba.sp_queue_event, +				 cq_event, struct lpfc_cq_event, list); +		spin_unlock_irq(&phba->hbalock); + +		switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { +		case CQE_CODE_COMPL_WQE: +			rspiocbq = container_of(cq_event, struct lpfc_iocbq, +						 cq_event); +			lpfc_sli_release_iocbq(phba, rspiocbq); +			break; +		case CQE_CODE_RECEIVE: +		case CQE_CODE_RECEIVE_V1: +			dmabuf = container_of(cq_event, struct hbq_dmabuf, +					      cq_event); +			lpfc_in_buf_free(phba, &dmabuf->dbuf); +		} +	} +} + +/** + * lpfc_hba_free_post_buf - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup posted ELS buffers after the HBA is reset + * when bringing down the SLI Layer. + * + * + * Return codes + *   void. + **/ +static void +lpfc_hba_free_post_buf(struct lpfc_hba *phba)  {  	struct lpfc_sli *psli = &phba->sli;  	struct lpfc_sli_ring *pring;  	struct lpfc_dmabuf *mp, *next_mp; -	LIST_HEAD(completions); -	int i; +	LIST_HEAD(buflist); +	int count;  	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)  		lpfc_sli_hbqbuf_free_all(phba);  	else {  		/* Cleanup preposted buffers on the ELS ring */  		pring = &psli->ring[LPFC_ELS_RING]; -		list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { +		spin_lock_irq(&phba->hbalock); +		list_splice_init(&pring->postbufq, &buflist); +		spin_unlock_irq(&phba->hbalock); + +		count = 0; +		list_for_each_entry_safe(mp, next_mp, &buflist, list) {  			list_del(&mp->list); -			pring->postbufq_cnt--; +			count++;  			lpfc_mbuf_free(phba, mp->virt, mp->phys);  			kfree(mp);  		} + +		spin_lock_irq(&phba->hbalock); +		pring->postbufq_cnt -= count; +		spin_unlock_irq(&phba->hbalock);  	} +} + +/** + * lpfc_hba_clean_txcmplq - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup the txcmplq after the HBA is reset when bringing + * down the SLI Layer. + * + * Return codes + *   void + **/ +static void +lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) +{ +	struct lpfc_sli *psli = &phba->sli; +	struct lpfc_sli_ring *pring; +	LIST_HEAD(completions); +	int i; -	spin_lock_irq(&phba->hbalock);  	for (i = 0; i < psli->num_rings; i++) {  		pring = &psli->ring[i]; - +		if (phba->sli_rev >= LPFC_SLI_REV4) +			spin_lock_irq(&pring->ring_lock); +		else +			spin_lock_irq(&phba->hbalock);  		/* At this point in time the HBA is either reset or DOA. Either  		 * way, nothing should be on txcmplq as it will NEVER complete.  		 */  		list_splice_init(&pring->txcmplq, &completions); -		spin_unlock_irq(&phba->hbalock); +		pring->txcmplq_cnt = 0; + +		if (phba->sli_rev >= LPFC_SLI_REV4) +			spin_unlock_irq(&pring->ring_lock); +		else +			spin_unlock_irq(&phba->hbalock);  		/* Cancel all the IOCBs from the completions list */  		lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,  				      IOERR_SLI_ABORTED); -  		lpfc_sli_abort_iocb_ring(phba, pring); -		spin_lock_irq(&phba->hbalock);  	} -	spin_unlock_irq(&phba->hbalock); +} +/** + * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset +	int i; + * @phba: pointer to lpfc HBA data structure. + * + * This routine will do uninitialization after the HBA is reset when bring + * down the SLI Layer. + * + * Return codes + *   0 - success. + *   Any other value - error. + **/ +static int +lpfc_hba_down_post_s3(struct lpfc_hba *phba) +{ +	lpfc_hba_free_post_buf(phba); +	lpfc_hba_clean_txcmplq(phba);  	return 0;  } @@ -890,13 +986,12 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)  {  	struct lpfc_scsi_buf *psb, *psb_next;  	LIST_HEAD(aborts); -	int ret;  	unsigned long iflag = 0;  	struct lpfc_sglq *sglq_entry = NULL; -	ret = lpfc_hba_down_post_s3(phba); -	if (ret) -		return ret; +	lpfc_hba_free_post_buf(phba); +	lpfc_hba_clean_txcmplq(phba); +  	/* At this point in time the HBA is either reset or DOA. Either  	 * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be  	 * on the lpfc_sgl_list so that it can either be freed if the @@ -932,6 +1027,8 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)  	spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag);  	list_splice(&aborts, &phba->lpfc_scsi_buf_list_put);  	spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag); + +	lpfc_sli4_free_sp_events(phba);  	return 0;  } @@ -1250,7 +1347,6 @@ static void  lpfc_handle_deferred_eratt(struct lpfc_hba *phba)  {  	uint32_t old_host_status = phba->work_hs; -	struct lpfc_sli_ring  *pring;  	struct lpfc_sli *psli = &phba->sli;  	/* If the pci channel is offline, ignore possible errors, @@ -1279,8 +1375,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)  	 * dropped by the firmware. Error iocb (I/O) on txcmplq and let the  	 * SCSI layer retry it after re-establishing link.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  	/*  	 * There was a firmware error. Take the hba offline and then @@ -1348,7 +1443,6 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)  {  	struct lpfc_vport *vport = phba->pport;  	struct lpfc_sli   *psli = &phba->sli; -	struct lpfc_sli_ring  *pring;  	uint32_t event_data;  	unsigned long temperature;  	struct temp_event temp_event_data; @@ -1400,8 +1494,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)  		* Error iocb (I/O) on txcmplq and let the SCSI layer  		* retry it after re-establishing link.  		*/ -		pring = &psli->ring[psli->fcp_ring]; -		lpfc_sli_abort_iocb_ring(phba, pring); +		lpfc_sli_abort_fcp_rings(phba);  		/*  		 * There was a firmware error.  Take the hba offline and then @@ -1940,78 +2033,81 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  	switch (dev_id) {  	case PCI_DEVICE_ID_FIREFLY: -		m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP6000", "PCI", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_SUPERFLY:  		if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) -			m = (typeof(m)){"LP7000", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP7000", "PCI", ""};  		else -			m = (typeof(m)){"LP7000E", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP7000E", "PCI", ""}; +		m.function = "Obsolete, Unsupported Fibre Channel Adapter";  		break;  	case PCI_DEVICE_ID_DRAGONFLY:  		m = (typeof(m)){"LP8000", "PCI", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_CENTAUR:  		if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) -			m = (typeof(m)){"LP9002", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP9002", "PCI", ""};  		else -			m = (typeof(m)){"LP9000", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP9000", "PCI", ""}; +		m.function = "Obsolete, Unsupported Fibre Channel Adapter";  		break;  	case PCI_DEVICE_ID_RFLY:  		m = (typeof(m)){"LP952", "PCI", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PEGASUS:  		m = (typeof(m)){"LP9802", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_THOR:  		m = (typeof(m)){"LP10000", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_VIPER:  		m = (typeof(m)){"LPX1000",  "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PFLY:  		m = (typeof(m)){"LP982", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_TFLY:  		m = (typeof(m)){"LP1050", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS:  		m = (typeof(m)){"LP11000", "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS_SCSP:  		m = (typeof(m)){"LP11000-SP", "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS_DCSP:  		m = (typeof(m)){"LP11002-SP",  "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE: -		m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1000", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE_SCSP: -		m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1000-SP", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE_DCSP: -		m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1002-SP", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_BMID:  		m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_BSMB: -		m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP111", "PCI-X2", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_ZEPHYR:  		m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; @@ -2030,16 +2126,20 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP101: -		m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP101", "PCI-X", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP10000S: -		m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP10000-S", "PCI", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP11000S: -		m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP11000-S", "PCI-X2", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LPE11000S: -		m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe11000-S", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_SAT:  		m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; @@ -2060,20 +2160,21 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HORNET: -		m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"}; +		m = (typeof(m)){"LP21000", "PCIe", +				"Obsolete, Unsupported FCoE Adapter"};  		GE = 1;  		break;  	case PCI_DEVICE_ID_PROTEUS_VF:  		m = (typeof(m)){"LPev12000", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PROTEUS_PF:  		m = (typeof(m)){"LPev12000", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PROTEUS_S:  		m = (typeof(m)){"LPemv12002-S", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_TIGERSHARK:  		oneConnect = 1; @@ -2089,17 +2190,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		break;  	case PCI_DEVICE_ID_BALIUS:  		m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LANCER_FC: -	case PCI_DEVICE_ID_LANCER_FC_VF:  		m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"};  		break; +	case PCI_DEVICE_ID_LANCER_FC_VF: +		m = (typeof(m)){"LPe16000", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"}; +		break;  	case PCI_DEVICE_ID_LANCER_FCOE: -	case PCI_DEVICE_ID_LANCER_FCOE_VF:  		oneConnect = 1;  		m = (typeof(m)){"OCe15100", "PCIe", "FCoE"};  		break; +	case PCI_DEVICE_ID_LANCER_FCOE_VF: +		oneConnect = 1; +		m = (typeof(m)){"OCe15100", "PCIe", +				"Obsolete, Unsupported FCoE"}; +		break;  	case PCI_DEVICE_ID_SKYHAWK:  	case PCI_DEVICE_ID_SKYHAWK_VF:  		oneConnect = 1; @@ -4614,7 +4722,10 @@ lpfc_reset_hba(struct lpfc_hba *phba)  		phba->link_state = LPFC_HBA_ERROR;  		return;  	} -	lpfc_offline_prep(phba, LPFC_MBX_WAIT); +	if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) +		lpfc_offline_prep(phba, LPFC_MBX_WAIT); +	else +		lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);  	lpfc_offline(phba);  	lpfc_sli_brdrestart(phba);  	lpfc_online(phba); @@ -9663,9 +9774,6 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)  static void  lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  { -	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring  *pring; -  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2723 PCI channel I/O abort preparing for recovery\n"); @@ -9673,8 +9781,7 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq  	 * and let the SCSI mid-layer to retry them to recover.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  }  /** @@ -10417,17 +10524,13 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)  static void  lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)  { -	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring  *pring; -  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2828 PCI channel I/O abort preparing for recovery\n");  	/*  	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq  	 * and let the SCSI mid-layer to retry them to recover.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  }  /** @@ -10898,7 +11001,7 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba)  	if (phba->sli4_hba.pc_sli4_params.oas_supported) {  		phba->cfg_fof = 1;  	} else { -		phba->cfg_EnableXLane = 0; +		phba->cfg_fof = 0;  		if (phba->device_data_mem_pool)  			mempool_destroy(phba->device_data_mem_pool);  		phba->device_data_mem_pool = NULL; @@ -10928,7 +11031,7 @@ lpfc_fof_queue_setup(struct lpfc_hba *phba)  	if (rc)  		return -ENOMEM; -	if (phba->cfg_EnableXLane) { +	if (phba->cfg_fof) {  		rc = lpfc_cq_create(phba, phba->sli4_hba.oas_cq,  				    phba->sli4_hba.fof_eq, LPFC_WCQ, LPFC_FCP); @@ -10947,8 +11050,7 @@ lpfc_fof_queue_setup(struct lpfc_hba *phba)  	return 0;  out_oas_wq: -	if (phba->cfg_EnableXLane) -		lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq); +	lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq);  out_oas_cq:  	lpfc_eq_destroy(phba, phba->sli4_hba.fof_eq);  	return rc; @@ -10982,7 +11084,7 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)  	phba->sli4_hba.fof_eq = qdesc; -	if (phba->cfg_EnableXLane) { +	if (phba->cfg_fof) {  		/* Create OAS CQ */  		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ed419aad2b1f..3fa65338d3f5 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2012 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 462453ee0bda..2df11daad85b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -73,7 +73,7 @@ lpfc_rport_data_from_scsi_device(struct scsi_device *sdev)  {  	struct lpfc_vport *vport = (struct lpfc_vport *)sdev->host->hostdata; -	if (vport->phba->cfg_EnableXLane) +	if (vport->phba->cfg_fof)  		return ((struct lpfc_device_data *)sdev->hostdata)->rport_data;  	else  		return (struct lpfc_rport_data *)sdev->hostdata; @@ -3462,7 +3462,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)  	 * If the OAS driver feature is enabled and the lun is enabled for  	 * OAS, set the oas iocb related flags.  	 */ -	if ((phba->cfg_EnableXLane) && ((struct lpfc_device_data *) +	if ((phba->cfg_fof) && ((struct lpfc_device_data *)  		scsi_cmnd->device->hostdata)->oas_enabled)  		lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS;  	return 0; @@ -4314,6 +4314,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,  		fcp_cmnd->fcpCntl1 = SIMPLE_Q;  	sli4 = (phba->sli_rev == LPFC_SLI_REV4); +	piocbq->iocb.un.fcpi.fcpi_XRdy = 0;  	/*  	 * There are three possibilities here - use scatter-gather segment, use @@ -4782,7 +4783,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	struct lpfc_scsi_buf *lpfc_cmd;  	IOCB_t *cmd, *icmd;  	int ret = SUCCESS, status = 0; -	unsigned long flags; +	struct lpfc_sli_ring *pring_s4; +	int ring_number, ret_val; +	unsigned long flags, iflags;  	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);  	status = fc_block_scsi_eh(cmnd); @@ -4833,6 +4836,14 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	BUG_ON(iocb->context1 != lpfc_cmd); +	/* abort issued in recovery is still in progress */ +	if (iocb->iocb_flag & LPFC_DRIVER_ABORTED) { +		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +			 "3389 SCSI Layer I/O Abort Request is pending\n"); +		spin_unlock_irqrestore(&phba->hbalock, flags); +		goto wait_for_cmpl; +	} +  	abtsiocb = __lpfc_sli_get_iocbq(phba);  	if (abtsiocb == NULL) {  		ret = FAILED; @@ -4871,11 +4882,23 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  	abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;  	abtsiocb->vport = vport; +	if (phba->sli_rev == LPFC_SLI_REV4) { +		ring_number = MAX_SLI3_CONFIGURED_RINGS + iocb->fcp_wqidx; +		pring_s4 = &phba->sli.ring[ring_number]; +		/* Note: both hbalock and ring_lock must be set here */ +		spin_lock_irqsave(&pring_s4->ring_lock, iflags); +		ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, +						abtsiocb, 0); +		spin_unlock_irqrestore(&pring_s4->ring_lock, iflags); +	} else { +		ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, +						abtsiocb, 0); +	}  	/* no longer need the lock after this point */  	spin_unlock_irqrestore(&phba->hbalock, flags); -	if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == -	    IOCB_ERROR) { + +	if (ret_val == IOCB_ERROR) {  		lpfc_sli_release_iocbq(phba, abtsiocb);  		ret = FAILED;  		goto out; @@ -4885,12 +4908,16 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)  		lpfc_sli_handle_fast_ring_event(phba,  			&phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); +wait_for_cmpl:  	lpfc_cmd->waitq = &waitq;  	/* Wait for abort to complete */  	wait_event_timeout(waitq,  			  (lpfc_cmd->pCmd != cmnd),  			   msecs_to_jiffies(2*vport->cfg_devloss_tmo*1000)); + +	spin_lock_irqsave(shost->host_lock, flags);  	lpfc_cmd->waitq = NULL; +	spin_unlock_irqrestore(shost->host_lock, flags);  	if (lpfc_cmd->pCmd == cmnd) {  		ret = FAILED; @@ -5172,8 +5199,9 @@ lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id,  	cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context);  	if (cnt) -		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], -				    tgt_id, lun_id, context); +		lpfc_sli_abort_taskmgmt(vport, +					&phba->sli.ring[phba->sli.fcp_ring], +					tgt_id, lun_id, context);  	later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;  	while (time_after(later, jiffies) && cnt) {  		schedule_timeout_uninterruptible(msecs_to_jiffies(20)); @@ -5491,7 +5519,7 @@ lpfc_slave_alloc(struct scsi_device *sdev)  	if (!rport || fc_remote_port_chkready(rport))  		return -ENXIO; -	if (phba->cfg_EnableXLane) { +	if (phba->cfg_fof) {  		/*  		 * Check to see if the device data structure for the lun @@ -5616,7 +5644,7 @@ lpfc_slave_destroy(struct scsi_device *sdev)  	struct lpfc_device_data *device_data = sdev->hostdata;  	atomic_dec(&phba->sdev_cnt); -	if ((phba->cfg_EnableXLane) && (device_data)) { +	if ((phba->cfg_fof) && (device_data)) {  		spin_lock_irqsave(&phba->devicelock, flags);  		device_data->available = false;  		if (!device_data->oas_enabled) @@ -5655,7 +5683,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,  	int memory_flags;  	if (unlikely(!phba) || !vport_wwpn || !target_wwpn  || -	    !(phba->cfg_EnableXLane)) +	    !(phba->cfg_fof))  		return NULL;  	/* Attempt to create the device data to contain lun info */ @@ -5693,7 +5721,7 @@ lpfc_delete_device_data(struct lpfc_hba *phba,  {  	if (unlikely(!phba) || !lun_info  || -	    !(phba->cfg_EnableXLane)) +	    !(phba->cfg_fof))  		return;  	if (!list_empty(&lun_info->listentry)) @@ -5727,7 +5755,7 @@ __lpfc_get_device_data(struct lpfc_hba *phba, struct list_head *list,  	struct lpfc_device_data *lun_info;  	if (unlikely(!phba) || !list || !vport_wwpn || !target_wwpn || -	    !phba->cfg_EnableXLane) +	    !phba->cfg_fof)  		return NULL;  	/* Check to see if the lun is already enabled for OAS. */ @@ -5789,7 +5817,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,  	    !starting_lun || !found_vport_wwpn ||  	    !found_target_wwpn || !found_lun || !found_lun_status ||  	    (*starting_lun == NO_MORE_OAS_LUN) || -	    !phba->cfg_EnableXLane) +	    !phba->cfg_fof)  		return false;  	lun = *starting_lun; @@ -5873,7 +5901,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,  	unsigned long flags;  	if (unlikely(!phba) || !vport_wwpn || !target_wwpn || -	    !phba->cfg_EnableXLane) +	    !phba->cfg_fof)  		return false;  	spin_lock_irqsave(&phba->devicelock, flags); @@ -5930,7 +5958,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,  	unsigned long flags;  	if (unlikely(!phba) || !vport_wwpn || !target_wwpn || -	    !phba->cfg_EnableXLane) +	    !phba->cfg_fof)  		return false;  	spin_lock_irqsave(&phba->devicelock, flags); diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 0120bfccf50b..0389ac1e7b83 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 393662c24df5..32ada0505576 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -3532,14 +3532,27 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)  	/* Error everything on txq and txcmplq  	 * First do the txq.  	 */ -	spin_lock_irq(&phba->hbalock); -	list_splice_init(&pring->txq, &completions); +	if (phba->sli_rev >= LPFC_SLI_REV4) { +		spin_lock_irq(&pring->ring_lock); +		list_splice_init(&pring->txq, &completions); +		pring->txq_cnt = 0; +		spin_unlock_irq(&pring->ring_lock); -	/* Next issue ABTS for everything on the txcmplq */ -	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) -		lpfc_sli_issue_abort_iotag(phba, pring, iocb); +		spin_lock_irq(&phba->hbalock); +		/* Next issue ABTS for everything on the txcmplq */ +		list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) +			lpfc_sli_issue_abort_iotag(phba, pring, iocb); +		spin_unlock_irq(&phba->hbalock); +	} else { +		spin_lock_irq(&phba->hbalock); +		list_splice_init(&pring->txq, &completions); +		pring->txq_cnt = 0; -	spin_unlock_irq(&phba->hbalock); +		/* Next issue ABTS for everything on the txcmplq */ +		list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) +			lpfc_sli_issue_abort_iotag(phba, pring, iocb); +		spin_unlock_irq(&phba->hbalock); +	}  	/* Cancel all the IOCBs from the completions list */  	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, @@ -3547,6 +3560,36 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)  }  /** + * lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. + * + * This function aborts all iocbs in FCP rings and frees all the iocb + * objects in txq. This function issues an abort iocb for all the iocb commands + * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before + * the return of this function. The caller is not required to hold any locks. + **/ +void +lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) +{ +	struct lpfc_sli *psli = &phba->sli; +	struct lpfc_sli_ring  *pring; +	uint32_t i; + +	/* Look on all the FCP Rings for the iotag */ +	if (phba->sli_rev >= LPFC_SLI_REV4) { +		for (i = 0; i < phba->cfg_fcp_io_channel; i++) { +			pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; +			lpfc_sli_abort_iocb_ring(phba, pring); +		} +	} else { +		pring = &psli->ring[psli->fcp_ring]; +		lpfc_sli_abort_iocb_ring(phba, pring); +	} +} + + +/**   * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring   * @phba: Pointer to HBA context object.   * @@ -3563,28 +3606,55 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)  	LIST_HEAD(txcmplq);  	struct lpfc_sli *psli = &phba->sli;  	struct lpfc_sli_ring  *pring; - -	/* Currently, only one fcp ring */ -	pring = &psli->ring[psli->fcp_ring]; +	uint32_t i;  	spin_lock_irq(&phba->hbalock); -	/* Retrieve everything on txq */ -	list_splice_init(&pring->txq, &txq); - -	/* Retrieve everything on the txcmplq */ -	list_splice_init(&pring->txcmplq, &txcmplq); -  	/* Indicate the I/O queues are flushed */  	phba->hba_flag |= HBA_FCP_IOQ_FLUSH;  	spin_unlock_irq(&phba->hbalock); -	/* Flush the txq */ -	lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, -			      IOERR_SLI_DOWN); +	/* Look on all the FCP Rings for the iotag */ +	if (phba->sli_rev >= LPFC_SLI_REV4) { +		for (i = 0; i < phba->cfg_fcp_io_channel; i++) { +			pring = &psli->ring[i + MAX_SLI3_CONFIGURED_RINGS]; + +			spin_lock_irq(&pring->ring_lock); +			/* Retrieve everything on txq */ +			list_splice_init(&pring->txq, &txq); +			/* Retrieve everything on the txcmplq */ +			list_splice_init(&pring->txcmplq, &txcmplq); +			pring->txq_cnt = 0; +			pring->txcmplq_cnt = 0; +			spin_unlock_irq(&pring->ring_lock); + +			/* Flush the txq */ +			lpfc_sli_cancel_iocbs(phba, &txq, +					      IOSTAT_LOCAL_REJECT, +					      IOERR_SLI_DOWN); +			/* Flush the txcmpq */ +			lpfc_sli_cancel_iocbs(phba, &txcmplq, +					      IOSTAT_LOCAL_REJECT, +					      IOERR_SLI_DOWN); +		} +	} else { +		pring = &psli->ring[psli->fcp_ring]; -	/* Flush the txcmpq */ -	lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, -			      IOERR_SLI_DOWN); +		spin_lock_irq(&phba->hbalock); +		/* Retrieve everything on txq */ +		list_splice_init(&pring->txq, &txq); +		/* Retrieve everything on the txcmplq */ +		list_splice_init(&pring->txcmplq, &txcmplq); +		pring->txq_cnt = 0; +		pring->txcmplq_cnt = 0; +		spin_unlock_irq(&phba->hbalock); + +		/* Flush the txq */ +		lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, +				      IOERR_SLI_DOWN); +		/* Flush the txcmpq */ +		lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, +				      IOERR_SLI_DOWN); +	}  }  /** @@ -3987,12 +4057,13 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)  {  	struct lpfc_sli *psli = &phba->sli;  	uint16_t cfg_value; -	int rc; +	int rc = 0;  	/* Reset HBA */  	lpfc_printf_log(phba, KERN_INFO, LOG_SLI, -			"0295 Reset HBA Data: x%x x%x\n", -			phba->pport->port_state, psli->sli_flag); +			"0295 Reset HBA Data: x%x x%x x%x\n", +			phba->pport->port_state, psli->sli_flag, +			phba->hba_flag);  	/* perform board reset */  	phba->fc_eventTag = 0; @@ -4005,6 +4076,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)  	phba->fcf.fcf_flag = 0;  	spin_unlock_irq(&phba->hbalock); +	/* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ +	if (phba->hba_flag & HBA_FW_DUMP_OP) { +		phba->hba_flag &= ~HBA_FW_DUMP_OP; +		return rc; +	} +  	/* Now physically reset the device */  	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,  			"0389 Performing PCI function reset!\n"); @@ -5002,7 +5079,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)  		} while (++fcp_eqidx < phba->cfg_fcp_io_channel);  	} -	if (phba->cfg_EnableXLane) +	if (phba->cfg_fof)  		lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM);  	if (phba->sli4_hba.hba_eq) { @@ -6722,7 +6799,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)  	LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;  	MAILBOX_t *mb = &pmbox->u.mb;  	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring *pring;  	/* If the mailbox completed, process the completion and return */  	if (lpfc_sli4_process_missed_mbox_completions(phba)) @@ -6764,8 +6840,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)  	psli->sli_flag &= ~LPFC_SLI_ACTIVE;  	spin_unlock_irq(&phba->hbalock); -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,  			"0345 Resetting board due to mailbox timeout\n"); @@ -8133,6 +8208,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  	abort_tag = (uint32_t) iocbq->iotag;  	xritag = iocbq->sli4_xritag;  	wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */ +	wqe->generic.wqe_com.word10 = 0;  	/* words0-2 bpl convert bde */  	if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {  		numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / @@ -8639,8 +8715,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,  	if ((piocb->iocb_flag & LPFC_IO_FCP) ||  	    (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { -		if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag & -			LPFC_IO_OAS))) { +		if (!phba->cfg_fof || (!(piocb->iocb_flag & LPFC_IO_OAS))) {  			wq = phba->sli4_hba.fcp_wq[piocb->fcp_wqidx];  		} else {  			wq = phba->sli4_hba.oas_wq; @@ -8735,7 +8810,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,  	if (phba->sli_rev == LPFC_SLI_REV4) {  		if (piocb->iocb_flag &  LPFC_IO_FCP) { -			if (!phba->cfg_EnableXLane || (!(piocb->iocb_flag & +			if (!phba->cfg_fof || (!(piocb->iocb_flag &  				LPFC_IO_OAS))) {  				if (unlikely(!phba->sli4_hba.fcp_wq))  					return IOCB_ERROR; @@ -9170,6 +9245,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)  		pring->sli.sli3.next_cmdidx  = 0;  		pring->sli.sli3.local_getidx = 0;  		pring->sli.sli3.cmdidx = 0; +		pring->flag = 0;  		INIT_LIST_HEAD(&pring->txq);  		INIT_LIST_HEAD(&pring->txcmplq);  		INIT_LIST_HEAD(&pring->iocb_continueq); @@ -9805,43 +9881,6 @@ abort_iotag_exit:  }  /** - * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues abort iocbs unconditionally for all - * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed - * to complete before the return of this function. The caller is not required - * to hold any locks. - **/ -static void -lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ -	LIST_HEAD(completions); -	struct lpfc_iocbq *iocb, *next_iocb; - -	if (pring->ringno == LPFC_ELS_RING) -		lpfc_fabric_abort_hba(phba); - -	spin_lock_irq(&phba->hbalock); - -	/* Take off all the iocbs on txq for cancelling */ -	list_splice_init(&pring->txq, &completions); -	pring->txq_cnt = 0; - -	/* Next issue ABTS for everything on the txcmplq */ -	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) -		lpfc_sli_abort_iotag_issue(phba, pring, iocb); - -	spin_unlock_irq(&phba->hbalock); - -	/* Cancel all the IOCBs from the completions list */ -	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, -			      IOERR_SLI_ABORTED); -} - -/**   * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.   * @phba: pointer to lpfc HBA data structure.   * @@ -9856,7 +9895,7 @@ lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)  	for (i = 0; i < psli->num_rings; i++) {  		pring = &psli->ring[i]; -		lpfc_sli_iocb_ring_abort(phba, pring); +		lpfc_sli_abort_iocb_ring(phba, pring);  	}  } @@ -10081,6 +10120,124 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,  }  /** + * lpfc_sli_abort_taskmgmt - issue abort for all commands on a host/target/LUN + * @vport: Pointer to virtual port. + * @pring: Pointer to driver SLI ring object. + * @tgt_id: SCSI ID of the target. + * @lun_id: LUN ID of the scsi device. + * @taskmgmt_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. + * + * This function sends an abort command for every SCSI command + * associated with the given virtual port pending on the ring + * filtered by lpfc_sli_validate_fcp_iocb function. + * When taskmgmt_cmd == LPFC_CTX_LUN, the function sends abort only to the + * FCP iocbs associated with lun specified by tgt_id and lun_id + * parameters + * When taskmgmt_cmd == LPFC_CTX_TGT, the function sends abort only to the + * FCP iocbs associated with SCSI target specified by tgt_id parameter. + * When taskmgmt_cmd == LPFC_CTX_HOST, the function sends abort to all + * FCP iocbs associated with virtual port. + * This function returns number of iocbs it aborted . + * This function is called with no locks held right after a taskmgmt + * command is sent. + **/ +int +lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, +			uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd cmd) +{ +	struct lpfc_hba *phba = vport->phba; +	struct lpfc_iocbq *abtsiocbq; +	struct lpfc_iocbq *iocbq; +	IOCB_t *icmd; +	int sum, i, ret_val; +	unsigned long iflags; +	struct lpfc_sli_ring *pring_s4; +	uint32_t ring_number; + +	spin_lock_irq(&phba->hbalock); + +	/* all I/Os are in process of being flushed */ +	if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { +		spin_unlock_irq(&phba->hbalock); +		return 0; +	} +	sum = 0; + +	for (i = 1; i <= phba->sli.last_iotag; i++) { +		iocbq = phba->sli.iocbq_lookup[i]; + +		if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, +					       cmd) != 0) +			continue; + +		/* +		 * If the iocbq is already being aborted, don't take a second +		 * action, but do count it. +		 */ +		if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED) +			continue; + +		/* issue ABTS for this IOCB based on iotag */ +		abtsiocbq = __lpfc_sli_get_iocbq(phba); +		if (abtsiocbq == NULL) +			continue; + +		icmd = &iocbq->iocb; +		abtsiocbq->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; +		abtsiocbq->iocb.un.acxri.abortContextTag = icmd->ulpContext; +		if (phba->sli_rev == LPFC_SLI_REV4) +			abtsiocbq->iocb.un.acxri.abortIoTag = +							 iocbq->sli4_xritag; +		else +			abtsiocbq->iocb.un.acxri.abortIoTag = icmd->ulpIoTag; +		abtsiocbq->iocb.ulpLe = 1; +		abtsiocbq->iocb.ulpClass = icmd->ulpClass; +		abtsiocbq->vport = vport; + +		/* ABTS WQE must go to the same WQ as the WQE to be aborted */ +		abtsiocbq->fcp_wqidx = iocbq->fcp_wqidx; +		if (iocbq->iocb_flag & LPFC_IO_FCP) +			abtsiocbq->iocb_flag |= LPFC_USE_FCPWQIDX; + +		if (lpfc_is_link_up(phba)) +			abtsiocbq->iocb.ulpCommand = CMD_ABORT_XRI_CN; +		else +			abtsiocbq->iocb.ulpCommand = CMD_CLOSE_XRI_CN; + +		/* Setup callback routine and issue the command. */ +		abtsiocbq->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; + +		/* +		 * Indicate the IO is being aborted by the driver and set +		 * the caller's flag into the aborted IO. +		 */ +		iocbq->iocb_flag |= LPFC_DRIVER_ABORTED; + +		if (phba->sli_rev == LPFC_SLI_REV4) { +			ring_number = MAX_SLI3_CONFIGURED_RINGS + +					 iocbq->fcp_wqidx; +			pring_s4 = &phba->sli.ring[ring_number]; +			/* Note: both hbalock and ring_lock must be set here */ +			spin_lock_irqsave(&pring_s4->ring_lock, iflags); +			ret_val = __lpfc_sli_issue_iocb(phba, pring_s4->ringno, +							abtsiocbq, 0); +			spin_unlock_irqrestore(&pring_s4->ring_lock, iflags); +		} else { +			ret_val = __lpfc_sli_issue_iocb(phba, pring->ringno, +							abtsiocbq, 0); +		} + + +		if (ret_val == IOCB_ERROR) +			__lpfc_sli_release_iocbq(phba, abtsiocbq); +		else +			sum++; +	} +	spin_unlock_irq(&phba->hbalock); +	return sum; +} + +/**   * lpfc_sli_wake_iocb_wait - lpfc_sli_issue_iocb_wait's completion handler   * @phba: Pointer to HBA context object.   * @cmdiocbq: Pointer to command iocb. diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 6f04080f4ea8..edb48832c39b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 9b8cda866176..7f50aa04d66a 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2009-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2009-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e32cbec70324..41675c1193e7 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   *                                                                 * @@ -18,7 +18,7 @@   * included with this package.                                     *   *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.45" +#define LPFC_DRIVER_VERSION "10.2.8001.0."  #define LPFC_DRIVER_NAME		"lpfc"  /* Used for SLI 2/3 */ @@ -30,4 +30,4 @@  #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \  		LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2013 Emulex.  All rights reserved." +#define LPFC_COPYRIGHT "Copyright(c) 2004-2014 Emulex.  All rights reserved." diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1fa010448666..de5d0ae19d83 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1648,16 +1648,16 @@ typedef struct {   */  struct crc_context {  	uint32_t handle;		/* System handle. */ -	uint32_t ref_tag; -	uint16_t app_tag; +	__le32 ref_tag; +	__le16 app_tag;  	uint8_t ref_tag_mask[4];	/* Validation/Replacement Mask*/  	uint8_t app_tag_mask[2];	/* Validation/Replacement Mask*/ -	uint16_t guard_seed;		/* Initial Guard Seed */ -	uint16_t prot_opts;		/* Requested Data Protection Mode */ -	uint16_t blk_size;		/* Data size in bytes */ +	__le16 guard_seed;		/* Initial Guard Seed */ +	__le16 prot_opts;		/* Requested Data Protection Mode */ +	__le16 blk_size;		/* Data size in bytes */  	uint16_t runt_blk_guard;	/* Guard value for runt block (tape  					 * only) */ -	uint32_t byte_count;		/* Total byte count/ total data +	__le32 byte_count;		/* Total byte count/ total data  					 * transfer count */  	union {  		struct { @@ -1671,10 +1671,10 @@ struct crc_context {  			uint32_t	reserved_6;  		} nobundling;  		struct { -			uint32_t	dif_byte_count;	/* Total DIF byte +			__le32	dif_byte_count;	/* Total DIF byte  							 * count */  			uint16_t	reserved_1; -			uint16_t	dseg_count;	/* Data segment count */ +			__le16	dseg_count;	/* Data segment count */  			uint32_t	reserved_2;  			uint32_t	data_address[2];  			uint32_t	data_length; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 8d85ed8d8917..4b188b0164e9 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1996,7 +1996,7 @@ qlt_set_t10dif_tags(struct se_cmd *se_cmd, struct crc_context *ctx)  	 * have been immplemented by TCM, before AppTag is avail.  	 * Look for modesense_handlers[]  	 */ -	ctx->app_tag = __constant_cpu_to_le16(0); +	ctx->app_tag = 0;  	ctx->app_tag_mask[0] = 0x0;  	ctx->app_tag_mask[1] = 0x0; @@ -2078,6 +2078,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha)  	struct se_cmd		*se_cmd = &cmd->se_cmd;  	uint32_t h;  	struct atio_from_isp *atio = &prm->cmd->atio; +	uint16_t t16;  	sgc = 0;  	ha = vha->hw; @@ -2174,8 +2175,13 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha)  	pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1];  	pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0];  	pkt->exchange_addr   = atio->u.isp24.exchange_addr; -	pkt->ox_id  = swab16(atio->u.isp24.fcp_hdr.ox_id); -	pkt->flags |= (atio->u.isp24.attr << 9); + +	/* silence compile warning */ +	t16 = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); +	pkt->ox_id  = cpu_to_le16(t16); + +	t16 = (atio->u.isp24.attr << 9); +	pkt->flags |= cpu_to_le16(t16);  	pkt->relative_offset = cpu_to_le32(prm->cmd->offset);  	/* Set transfer direction */ @@ -2250,8 +2256,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha)  	if (bundling && prm->prot_seg_cnt) {  		/* Walks dif segments */ -		pkt->add_flags |= -			__constant_cpu_to_le16(CTIO_CRC2_AF_DIF_DSD_ENA); +		pkt->add_flags |= CTIO_CRC2_AF_DIF_DSD_ENA;  		cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;  		if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 5c9f185a8ebd..e0a58fd13f66 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -316,7 +316,7 @@ struct fcp_hdr {  	uint8_t  seq_id;  	uint8_t  df_ctl;  	uint16_t seq_cnt; -	uint16_t ox_id; +	__be16   ox_id;  	uint16_t rx_id;  	uint32_t parameter;  } __packed; @@ -441,7 +441,7 @@ struct ctio7_to_24xx {  	union {  		struct {  			uint16_t reserved1; -			uint16_t flags; +			__le16 flags;  			uint32_t residual;  			uint16_t ox_id;  			uint16_t scsi_status; @@ -527,7 +527,7 @@ struct ctio_crc2_to_fw {  	uint32_t handle;		/* System handle. */  	uint16_t nport_handle;		/* N_PORT handle. */ -	uint16_t timeout;		/* Command timeout. */ +	__le16 timeout;		/* Command timeout. */  	uint16_t dseg_count;		/* Data segment count. */  	uint8_t  vp_index; @@ -538,15 +538,15 @@ struct ctio_crc2_to_fw {  	uint8_t  reserved1;  	uint32_t exchange_addr;		/* rcv exchange address */  	uint16_t reserved2; -	uint16_t flags;			/* refer to CTIO7 flags values */ +	__le16 flags;			/* refer to CTIO7 flags values */  	uint32_t residual; -	uint16_t ox_id; +	__le16 ox_id;  	uint16_t scsi_status; -	uint32_t relative_offset; +	__le32 relative_offset;  	uint32_t reserved5; -	uint32_t transfer_length;		/* total fc transfer length */ +	__le32 transfer_length;		/* total fc transfer length */  	uint32_t reserved6; -	uint32_t crc_context_address[2];/* Data segment address. */ +	__le32 crc_context_address[2];/* Data segment address. */  	uint16_t crc_context_len;	/* Data segment length. */  	uint16_t reserved_1;		/* MUST be set to 0. */  } __packed; | 
