diff options
Diffstat (limited to 'drivers/scsi/pm8001')
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.c | 144 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.h | 6 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_defs.h | 8 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 239 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.h | 7 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 176 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 16 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 95 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 602 | ||||
| -rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.h | 17 | 
10 files changed, 1069 insertions, 241 deletions
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index d99f41c2ca1..a368d77b8d4 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -309,6 +309,106 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,  }  static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);  /** + * pm8001_ctl_ib_queue_log_show - Out bound Queue log + * @cdev:pointer to embedded class device + * @buf: the buffer returned + * A sysfs 'read-only' shost attribute. + */ +static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); +	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; +	int offset; +	char *str = buf; +	int start = 0; +#define IB_MEMMAP(c)	\ +		(*(u32 *)((u8 *)pm8001_ha->	\ +		memoryMap.region[IB].virt_ptr +	\ +		pm8001_ha->evtlog_ib_offset + (c))) + +	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { +		str += sprintf(str, "0x%08x\n", IB_MEMMAP(start)); +		start = start + 4; +	} +	pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET; +	if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) +		pm8001_ha->evtlog_ib_offset = 0; + +	return str - buf; +} + +static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL); +/** + * pm8001_ctl_ob_queue_log_show - Out bound Queue log + * @cdev:pointer to embedded class device + * @buf: the buffer returned + * A sysfs 'read-only' shost attribute. + */ + +static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); +	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; +	int offset; +	char *str = buf; +	int start = 0; +#define OB_MEMMAP(c)	\ +		(*(u32 *)((u8 *)pm8001_ha->	\ +		memoryMap.region[OB].virt_ptr +	\ +		pm8001_ha->evtlog_ob_offset + (c))) + +	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { +		str += sprintf(str, "0x%08x\n", OB_MEMMAP(start)); +		start = start + 4; +	} +	pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET; +	if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) +		pm8001_ha->evtlog_ob_offset = 0; + +	return str - buf; +} +static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL); +/** + * pm8001_ctl_bios_version_show - Bios version Display + * @cdev:pointer to embedded class device + * @buf:the buffer returned + * A sysfs 'read-only' shost attribute. + */ +static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); +	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; +	char *str = buf; +	void *virt_addr; +	int bios_index; +	DECLARE_COMPLETION_ONSTACK(completion); +	struct pm8001_ioctl_payload payload; + +	pm8001_ha->nvmd_completion = &completion; +	payload.minor_function = 7; +	payload.offset = 0; +	payload.length = 4096; +	payload.func_specific = kzalloc(4096, GFP_KERNEL); +	if (!payload.func_specific) +		return -ENOMEM; +	PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); +	wait_for_completion(&completion); +	virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr; +	for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT; +		bios_index++) +		str += sprintf(str, "%c", +			*((u8 *)((u8 *)virt_addr+bios_index))); +	kfree(payload.func_specific); +	return str - buf; +} +static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL); +/**   * pm8001_ctl_aap_log_show - IOP event log   * @cdev: pointer to embedded class device   * @buf: the buffer returned @@ -344,6 +444,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,  }  static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); +/** + ** pm8001_ctl_fatal_log_show - fatal error logging + ** @cdev:pointer to embedded class device + ** @buf: the buffer returned + ** + ** A sysfs 'read-only' shost attribute. + **/ + +static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	ssize_t count; + +	count = pm80xx_get_fatal_dump(cdev, attr, buf); +	return count; +} + +static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); + + +/** + ** pm8001_ctl_gsm_log_show - gsm dump collection + ** @cdev:pointer to embedded class device + ** @buf: the buffer returned + **A sysfs 'read-only' shost attribute. + **/ +static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	ssize_t count; + +	count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf); +	return count; +} + +static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); +  #define FLASH_CMD_NONE      0x00  #define FLASH_CMD_UPDATE    0x01  #define FLASH_CMD_SET_NVMD    0x02 @@ -595,7 +732,7 @@ static ssize_t pm8001_show_update_fw(struct device *cdev,  			flash_error_table[i].reason);  } -static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUGO, +static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,  	pm8001_show_update_fw, pm8001_store_update_fw);  struct device_attribute *pm8001_host_attrs[] = {  	&dev_attr_interface_rev, @@ -603,12 +740,17 @@ struct device_attribute *pm8001_host_attrs[] = {  	&dev_attr_update_fw,  	&dev_attr_aap_log,  	&dev_attr_iop_log, +	&dev_attr_fatal_log, +	&dev_attr_gsm_log,  	&dev_attr_max_out_io,  	&dev_attr_max_devices,  	&dev_attr_max_sg_list,  	&dev_attr_sas_spec_support,  	&dev_attr_logging_level,  	&dev_attr_host_sas_address, +	&dev_attr_bios_version, +	&dev_attr_ib_log, +	&dev_attr_ob_log,  	NULL,  }; diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h index 63ad4aa0c42..d0d43a250b9 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.h +++ b/drivers/scsi/pm8001/pm8001_ctl.h @@ -45,6 +45,8 @@  #define HEADER_LEN			28  #define SIZE_OFFSET			16 +#define BIOSOFFSET			56 +#define BIOS_OFFSET_LIMIT		61  #define FLASH_OK                        0x000000  #define FAIL_OPEN_BIOS_FILE             0x000100 @@ -53,5 +55,9 @@  #define FAIL_OUT_MEMORY                 0x000c00  #define FLASH_IN_PROGRESS               0x001000 +#define IB_OB_READ_TIMES                256 +#define SYSFS_OFFSET                    1024 +#define PM80XX_IB_OB_QUEUE_SIZE         (32 * 1024) +#define PM8001_IB_OB_QUEUE_SIZE         (16 * 1024)  #endif /* PM8001_CTL_H_INCLUDED */ diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 479c5a7a863..74a4bb9af07 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -46,7 +46,10 @@ enum chip_flavors {  	chip_8008,  	chip_8009,  	chip_8018, -	chip_8019 +	chip_8019, +	chip_8074, +	chip_8076, +	chip_8077  };  enum phy_speed { @@ -99,7 +102,8 @@ enum memory_region_num {  	NVMD,	    /* NVM device */  	DEV_MEM,    /* memory for devices */  	CCB_MEM,    /* memory for command control block */ -	FW_FLASH    /* memory for fw flash update */ +	FW_FLASH,    /* memory for fw flash update */ +	FORENSIC_MEM  /* memory for fw forensic data */  };  #define	PM8001_EVENT_LOG_SIZE	 (128 * 1024) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 4a219575219..a97be015e52 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -644,7 +644,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)  	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);  	/* 8081 controllers need BAR shift to access MPI space  	* as this is shared with BIOS data */ -	if (deviceid == 0x8081) { +	if (deviceid == 0x8081 || deviceid == 0x0042) {  		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {  			PM8001_FAIL_DBG(pm8001_ha,  				pm8001_printk("Shift Bar4 to 0x%x failed\n", @@ -673,7 +673,7 @@ static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)  	for (i = 0; i < PM8001_MAX_OUTB_NUM; i++)  		update_outbnd_queue_table(pm8001_ha, i);  	/* 8081 controller donot require these operations */ -	if (deviceid != 0x8081) { +	if (deviceid != 0x8081 && deviceid != 0x0042) {  		mpi_set_phys_g3_with_ssc(pm8001_ha, 0);  		/* 7->130ms, 34->500ms, 119->1.5s */  		mpi_set_open_retry_interval_reg(pm8001_ha, 119); @@ -701,7 +701,7 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)  	u32 gst_len_mpistate;  	u16 deviceid;  	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid); -	if (deviceid == 0x8081) { +	if (deviceid == 0x8081 || deviceid == 0x0042) {  		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {  			PM8001_FAIL_DBG(pm8001_ha,  				pm8001_printk("Shift Bar4 to 0x%x failed\n", @@ -1868,6 +1868,13 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)  	if (unlikely(!t || !t->lldd_task || !t->dev))  		return;  	ts = &t->task_status; +	/* Print sas address of IO failed device */ +	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && +		(status != IO_UNDERFLOW)) +		PM8001_FAIL_DBG(pm8001_ha, +			pm8001_printk("SAS Address of IO Failure Drive:" +			"%016llx", SAS_ADDR(t->dev->sas_addr))); +  	switch (status) {  	case IO_SUCCESS:  		PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS" @@ -2276,6 +2283,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  	u32 param;  	u32 status;  	u32 tag; +	int i, j; +	u8 sata_addr_low[4]; +	u32 temp_sata_addr_low; +	u8 sata_addr_hi[4]; +	u32 temp_sata_addr_hi;  	struct sata_completion_resp *psataPayload;  	struct task_status_struct *ts;  	struct ata_task_resp *resp ; @@ -2325,7 +2337,46 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  			pm8001_printk("ts null\n"));  		return;  	} - +	/* Print sas address of IO failed device */ +	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && +		(status != IO_UNDERFLOW)) { +		if (!((t->dev->parent) && +			(DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { +			for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++) +				sata_addr_low[i] = pm8001_ha->sas_addr[j]; +			for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++) +				sata_addr_hi[i] = pm8001_ha->sas_addr[j]; +			memcpy(&temp_sata_addr_low, sata_addr_low, +				sizeof(sata_addr_low)); +			memcpy(&temp_sata_addr_hi, sata_addr_hi, +				sizeof(sata_addr_hi)); +			temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff) +						|((temp_sata_addr_hi << 8) & +						0xff0000) | +						((temp_sata_addr_hi >> 8) +						& 0xff00) | +						((temp_sata_addr_hi << 24) & +						0xff000000)); +			temp_sata_addr_low = ((((temp_sata_addr_low >> 24) +						& 0xff) | +						((temp_sata_addr_low << 8) +						& 0xff0000) | +						((temp_sata_addr_low >> 8) +						& 0xff00) | +						((temp_sata_addr_low << 24) +						& 0xff000000)) + +						pm8001_dev->attached_phy + +						0x10); +			PM8001_FAIL_DBG(pm8001_ha, +				pm8001_printk("SAS Address of IO Failure Drive:" +				"%08x%08x", temp_sata_addr_hi, +					temp_sata_addr_low)); +		} else { +			PM8001_FAIL_DBG(pm8001_ha, +				pm8001_printk("SAS Address of IO Failure Drive:" +				"%016llx", SAS_ADDR(t->dev->sas_addr))); +		} +	}  	switch (status) {  	case IO_SUCCESS:  		PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); @@ -2451,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*in order to force CPU ordering*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2471,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2499,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/* ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2566,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				    IO_DS_NON_OPERATIONAL);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2590,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				    IO_DS_IN_ERROR);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2623,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  			" resp 0x%x stat 0x%x but aborted by upper layer!\n",  			t, status, ts->resp, ts->stat));  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -	} else if (t->uldd_task) { -		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/* ditto */ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); -	} else if (!t->uldd_task) { +	} else {  		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/*ditto*/ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); +		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  	}  } @@ -2745,11 +2765,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_COMPLETE;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2858,20 +2874,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)  			" resp 0x%x stat 0x%x but aborted by upper layer!\n",  			t, event, ts->resp, ts->stat));  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -	} else if (t->uldd_task) { -		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/* ditto */ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); -	} else if (!t->uldd_task) { +	} else {  		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/*ditto*/ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); +		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  	}  } @@ -3087,8 +3092,8 @@ void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha,  	struct pm8001_device *pm8001_dev = ccb->device;  	u32 status = le32_to_cpu(pPayload->status);  	u32 device_id = le32_to_cpu(pPayload->device_id); -	u8 pds = le32_to_cpu(pPayload->pds_nds) | PDS_BITS; -	u8 nds = le32_to_cpu(pPayload->pds_nds) | NDS_BITS; +	u8 pds = le32_to_cpu(pPayload->pds_nds) & PDS_BITS; +	u8 nds = le32_to_cpu(pPayload->pds_nds) & NDS_BITS;  	PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set device id = 0x%x state "  		"from 0x%x to 0x%x status = 0x%x!\n",  		device_id, pds, nds, status)); @@ -3352,6 +3357,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)  	unsigned long flags;  	u8 deviceType = pPayload->sas_identify.dev_type;  	port->port_state =  portstate; +	phy->phy_state = PHY_STATE_LINK_UP_SPC;  	PM8001_MSG_DBG(pm8001_ha,  		pm8001_printk("HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n",  		port_id, phy_id)); @@ -3432,6 +3438,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)  		pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d,"  		" phy id = %d\n", port_id, phy_id));  	port->port_state =  portstate; +	phy->phy_state = PHY_STATE_LINK_UP_SPC;  	port->port_attached = 1;  	pm8001_get_lrate_mode(phy, link_rate);  	phy->phy_type |= PORT_TYPE_SATA; @@ -4414,23 +4421,11 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  					" stat 0x%x but aborted by upper layer "  					"\n", task, ts->resp, ts->stat));  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); -			} else if (task->uldd_task) { -				spin_unlock_irqrestore(&task->task_state_lock, -							flags); -				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); -				mb();/* ditto */ -				spin_unlock_irq(&pm8001_ha->lock); -				task->task_done(task); -				spin_lock_irq(&pm8001_ha->lock); -				return 0; -			} else if (!task->uldd_task) { +			} else {  				spin_unlock_irqrestore(&task->task_state_lock,  							flags); -				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); -				mb();/*ditto*/ -				spin_unlock_irq(&pm8001_ha->lock); -				task->task_done(task); -				spin_lock_irq(&pm8001_ha->lock); +				pm8001_ccb_task_free_done(pm8001_ha, task, +								ccb, tag);  				return 0;  			}  		} @@ -4700,6 +4695,8 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha,  	sspTMCmd.tmf = cpu_to_le32(tmf->tmf);  	memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8);  	sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag); +	if (pm8001_ha->chip_id != chip_8001) +		sspTMCmd.ds_ads_m = 0x08;  	circularQ = &pm8001_ha->inbnd_q_tbl[0];  	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, 0);  	return ret; @@ -4778,6 +4775,16 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,  		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);  		break;  	} +	case IOP_RDUMP: { +		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | IOP_RDUMP); +		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); +		nvmd_req.vpd_offset = cpu_to_le32(ioctl_payload->offset); +		nvmd_req.resp_addr_hi = +		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); +		nvmd_req.resp_addr_lo = +		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); +		break; +	}  	default:  		break;  	} @@ -4938,6 +4945,84 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,  	return rc;  } +ssize_t +pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf) +{ +	u32 value, rem, offset = 0, bar = 0; +	u32 index, work_offset, dw_length; +	u32 shift_value, gsm_base, gsm_dump_offset; +	char *direct_data; +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); +	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + +	direct_data = buf; +	gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset; + +	/* check max is 1 Mbytes */ +	if ((length > 0x100000) || (gsm_dump_offset & 3) || +		((gsm_dump_offset + length) > 0x1000000)) +			return -EINVAL; + +	if (pm8001_ha->chip_id == chip_8001) +		bar = 2; +	else +		bar = 1; + +	work_offset = gsm_dump_offset & 0xFFFF0000; +	offset = gsm_dump_offset & 0x0000FFFF; +	gsm_dump_offset = work_offset; +	/* adjust length to dword boundary */ +	rem = length & 3; +	dw_length = length >> 2; + +	for (index = 0; index < dw_length; index++) { +		if ((work_offset + offset) & 0xFFFF0000) { +			if (pm8001_ha->chip_id == chip_8001) +				shift_value = ((gsm_dump_offset + offset) & +						SHIFT_REG_64K_MASK); +			else +				shift_value = (((gsm_dump_offset + offset) & +						SHIFT_REG_64K_MASK) >> +						SHIFT_REG_BIT_SHIFT); + +			if (pm8001_ha->chip_id == chip_8001) { +				gsm_base = GSM_BASE; +				if (-1 == pm8001_bar4_shift(pm8001_ha, +						(gsm_base + shift_value))) +					return -EIO; +			} else { +				gsm_base = 0; +				if (-1 == pm80xx_bar4_shift(pm8001_ha, +						(gsm_base + shift_value))) +					return -EIO; +			} +			gsm_dump_offset = (gsm_dump_offset + offset) & +						0xFFFF0000; +			work_offset = 0; +			offset = offset & 0x0000FFFF; +		} +		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) & +						0x0000FFFF); +		direct_data += sprintf(direct_data, "%08x ", value); +		offset += 4; +	} +	if (rem != 0) { +		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) & +						0x0000FFFF); +		/* xfr for non_dw */ +		direct_data += sprintf(direct_data, "%08x ", value); +	} +	/* Shift back to BAR4 original address */ +	if (-1 == pm8001_bar4_shift(pm8001_ha, 0)) +			return -EIO; +	pm8001_ha->fatal_forensic_shift_offset += 1024; + +	if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000) +		pm8001_ha->fatal_forensic_shift_offset = 0; +	return direct_data - buf; +} +  int  pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,  	struct pm8001_device *pm8001_dev, u32 state) diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index d7c1e203422..e4867e690c8 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h @@ -131,6 +131,10 @@  #define LINKRATE_30			(0x02 << 8)  #define LINKRATE_60			(0x04 << 8) +/* for phy state */ + +#define PHY_STATE_LINK_UP_SPC		0x1 +  /* for new SPC controllers MEMBASE III is shared between BIOS and DATA */  #define GSM_SM_BASE			0x4F0000  struct mpi_msg_hdr{ @@ -1027,5 +1031,8 @@ struct set_dev_state_resp {  #define DEVREG_FAILURE_PORT_NOT_VALID_STATE		0x06  #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID		0x07 +#define GSM_BASE					0x4F0000 +#define SHIFT_REG_64K_MASK				0xffff0000 +#define SHIFT_REG_BIT_SHIFT				8  #endif diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index f7c189606b8..e90c89f1d48 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -54,6 +54,9 @@ static const struct pm8001_chip_info pm8001_chips[] = {  	[chip_8009] = {1,  8, &pm8001_80xx_dispatch,},  	[chip_8018] = {0,  16, &pm8001_80xx_dispatch,},  	[chip_8019] = {1,  16, &pm8001_80xx_dispatch,}, +	[chip_8074] = {0,  8, &pm8001_80xx_dispatch,}, +	[chip_8076] = {0,  16, &pm8001_80xx_dispatch,}, +	[chip_8077] = {0,  16, &pm8001_80xx_dispatch,},  };  static int pm8001_id; @@ -172,20 +175,16 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)  static void pm8001_tasklet(unsigned long opaque)  {  	struct pm8001_hba_info *pm8001_ha; -	u32 vec; -	pm8001_ha = (struct pm8001_hba_info *)opaque; +	struct isr_param *irq_vector; + +	irq_vector = (struct isr_param *)opaque; +	pm8001_ha = irq_vector->drv_inst;  	if (unlikely(!pm8001_ha))  		BUG_ON(1); -	vec = pm8001_ha->int_vector; -	PM8001_CHIP_DISP->isr(pm8001_ha, vec); +	PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id);  }  #endif -static struct  pm8001_hba_info *outq_to_hba(u8 *outq) -{ -	return container_of((outq - *outq), struct pm8001_hba_info, outq[0]); -} -  /**   * pm8001_interrupt_handler_msix - main MSIX interrupt handler.   * It obtains the vector number and calls the equivalent bottom @@ -195,18 +194,20 @@ static struct  pm8001_hba_info *outq_to_hba(u8 *outq)   */  static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)  { -	struct pm8001_hba_info *pm8001_ha = outq_to_hba(opaque); -	u8 outq = *(u8 *)opaque; +	struct isr_param *irq_vector; +	struct pm8001_hba_info *pm8001_ha;  	irqreturn_t ret = IRQ_HANDLED; +	irq_vector = (struct isr_param *)opaque; +	pm8001_ha = irq_vector->drv_inst; +  	if (unlikely(!pm8001_ha))  		return IRQ_NONE;  	if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))  		return IRQ_NONE; -	pm8001_ha->int_vector = outq;  #ifdef PM8001_USE_TASKLET -	tasklet_schedule(&pm8001_ha->tasklet); +	tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]);  #else -	ret = PM8001_CHIP_DISP->isr(pm8001_ha, outq); +	ret = PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id);  #endif  	return ret;  } @@ -227,9 +228,8 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)  	if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))  		return IRQ_NONE; -	pm8001_ha->int_vector = 0;  #ifdef PM8001_USE_TASKLET -	tasklet_schedule(&pm8001_ha->tasklet); +	tasklet_schedule(&pm8001_ha->tasklet[0]);  #else  	ret = PM8001_CHIP_DISP->isr(pm8001_ha, 0);  #endif @@ -344,6 +344,10 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha,  	/* Memory region for fw flash */  	pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096; +	pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1; +	pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000; +	pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000; +	pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;  	for (i = 0; i < USI_MAX_MEMCNT; i++) {  		if (pm8001_mem_alloc(pm8001_ha->pdev,  			&pm8001_ha->memoryMap.region[i].virt_ptr, @@ -450,7 +454,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,  {  	struct pm8001_hba_info *pm8001_ha;  	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - +	int j;  	pm8001_ha = sha->lldd_ha;  	if (!pm8001_ha) @@ -473,12 +477,14 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,  		pm8001_ha->iomb_size = IOMB_SIZE_SPC;  #ifdef PM8001_USE_TASKLET -	/** -	* default tasklet for non msi-x interrupt handler/first msi-x -	* interrupt handler -	**/ -	tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, -			(unsigned long)pm8001_ha); +	/* Tasklet for non msi-x interrupt handler */ +	if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) +		tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, +			(unsigned long)&(pm8001_ha->irq_vector[0])); +	else +		for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) +			tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, +				(unsigned long)&(pm8001_ha->irq_vector[j]));  #endif  	pm8001_ioremap(pm8001_ha);  	if (!pm8001_alloc(pm8001_ha, ent)) @@ -619,7 +625,7 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)  	pm8001_ha->nvmd_completion = &completion;  	if (pm8001_ha->chip_id == chip_8001) { -		if (deviceid == 0x8081) { +		if (deviceid == 0x8081 || deviceid == 0x0042) {  			payload.minor_function = 4;  			payload.length = 4096;  		} else { @@ -640,6 +646,9 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)  			if (deviceid == 0x8081)  				pm8001_ha->sas_addr[j] =  					payload.func_specific[0x704 + i]; +			else if (deviceid == 0x0042) +				pm8001_ha->sas_addr[j] = +					payload.func_specific[0x010 + i];  		} else  			pm8001_ha->sas_addr[j] =  					payload.func_specific[0x804 + i]; @@ -664,6 +673,35 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)  #endif  } +/* + * pm8001_get_phy_settings_info : Read phy setting values. + * @pm8001_ha : our hba. + */ +static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) +{ + +#ifdef PM8001_READ_VPD +	/*OPTION ROM FLASH read for the SPC cards */ +	DECLARE_COMPLETION_ONSTACK(completion); +	struct pm8001_ioctl_payload payload; + +	pm8001_ha->nvmd_completion = &completion; +	/* SAS ADDRESS read from flash / EEPROM */ +	payload.minor_function = 6; +	payload.offset = 0; +	payload.length = 4096; +	payload.func_specific = kzalloc(4096, GFP_KERNEL); +	if (!payload.func_specific) +		return -ENOMEM; +	/* Read phy setting values from flash */ +	PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); +	wait_for_completion(&completion); +	pm8001_set_phy_profile(pm8001_ha, sizeof(u8), payload.func_specific); +	kfree(payload.func_specific); +#endif +	return 0; +} +  #ifdef PM8001_USE_MSIX  /**   * pm8001_setup_msix - enable MSI-X interrupt @@ -682,11 +720,9 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)  	/* SPCv controllers supports 64 msi-x */  	if (pm8001_ha->chip_id == chip_8001) {  		number_of_intr = 1; -		flag |= IRQF_DISABLED;  	} else {  		number_of_intr = PM8001_MAX_MSIX_VEC;  		flag &= ~IRQF_SHARED; -		flag |= IRQF_DISABLED;  	}  	max_entry = sizeof(pm8001_ha->msix_entries) / @@ -701,19 +737,20 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)  			"pci_enable_msix request ret:%d no of intr %d\n",  					rc, pm8001_ha->number_of_intr)); -		for (i = 0; i < number_of_intr; i++) -			pm8001_ha->outq[i] = i;  		for (i = 0; i < number_of_intr; i++) {  			snprintf(intr_drvname[i], sizeof(intr_drvname[0]),  					DRV_NAME"%d", i); +			pm8001_ha->irq_vector[i].irq_id = i; +			pm8001_ha->irq_vector[i].drv_inst = pm8001_ha; +  			if (request_irq(pm8001_ha->msix_entries[i].vector,  				pm8001_interrupt_handler_msix, flag, -				intr_drvname[i], &pm8001_ha->outq[i])) { +				intr_drvname[i], &(pm8001_ha->irq_vector[i]))) {  				for (j = 0; j < i; j++)  					free_irq(  					pm8001_ha->msix_entries[j].vector, -					&pm8001_ha->outq[j]); +					&(pm8001_ha->irq_vector[i]));  				pci_disable_msix(pm8001_ha->pdev);  				break;  			} @@ -844,6 +881,13 @@ static int pm8001_pci_probe(struct pci_dev *pdev,  	}  	pm8001_init_sas_add(pm8001_ha); +	/* phy setting support for motherboard controller */ +	if (pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && +		pdev->subsystem_vendor != 0) { +		rc = pm8001_get_phy_settings_info(pm8001_ha); +		if (rc) +			goto err_out_shost; +	}  	pm8001_post_sas_ha_init(shost, chip);  	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));  	if (rc) @@ -871,9 +915,8 @@ static void pm8001_pci_remove(struct pci_dev *pdev)  {  	struct sas_ha_struct *sha = pci_get_drvdata(pdev);  	struct pm8001_hba_info *pm8001_ha; -	int i; +	int i, j;  	pm8001_ha = sha->lldd_ha; -	pci_set_drvdata(pdev, NULL);  	sas_unregister_ha(sha);  	sas_remove_host(pm8001_ha->shost);  	list_del(&pm8001_ha->list); @@ -886,13 +929,18 @@ static void pm8001_pci_remove(struct pci_dev *pdev)  		synchronize_irq(pm8001_ha->msix_entries[i].vector);  	for (i = 0; i < pm8001_ha->number_of_intr; i++)  		free_irq(pm8001_ha->msix_entries[i].vector, -				&pm8001_ha->outq[i]); +				&(pm8001_ha->irq_vector[i]));  	pci_disable_msix(pdev);  #else  	free_irq(pm8001_ha->irq, sha);  #endif  #ifdef PM8001_USE_TASKLET -	tasklet_kill(&pm8001_ha->tasklet); +	/* For non-msix and msix interrupts */ +	if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) +		tasklet_kill(&pm8001_ha->tasklet[0]); +	else +		for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) +			tasklet_kill(&pm8001_ha->tasklet[j]);  #endif  	pm8001_free(pm8001_ha);  	kfree(sha->sas_phy); @@ -913,7 +961,7 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)  {  	struct sas_ha_struct *sha = pci_get_drvdata(pdev);  	struct pm8001_hba_info *pm8001_ha; -	int i; +	int  i, j;  	u32 device_state;  	pm8001_ha = sha->lldd_ha;  	flush_workqueue(pm8001_wq); @@ -929,13 +977,18 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)  		synchronize_irq(pm8001_ha->msix_entries[i].vector);  	for (i = 0; i < pm8001_ha->number_of_intr; i++)  		free_irq(pm8001_ha->msix_entries[i].vector, -				&pm8001_ha->outq[i]); +				&(pm8001_ha->irq_vector[i]));  	pci_disable_msix(pdev);  #else  	free_irq(pm8001_ha->irq, sha);  #endif  #ifdef PM8001_USE_TASKLET -	tasklet_kill(&pm8001_ha->tasklet); +	/* For non-msix and msix interrupts */ +	if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) +		tasklet_kill(&pm8001_ha->tasklet[0]); +	else +		for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) +			tasklet_kill(&pm8001_ha->tasklet[j]);  #endif  	device_state = pci_choose_state(pdev, state);  	pm8001_printk("pdev=0x%p, slot=%s, entering " @@ -958,7 +1011,7 @@ static int pm8001_pci_resume(struct pci_dev *pdev)  	struct sas_ha_struct *sha = pci_get_drvdata(pdev);  	struct pm8001_hba_info *pm8001_ha;  	int rc; -	u8 i = 0; +	u8 i = 0, j;  	u32 device_state;  	pm8001_ha = sha->lldd_ha;  	device_state = pdev->current_state; @@ -998,10 +1051,14 @@ static int pm8001_pci_resume(struct pci_dev *pdev)  	if (rc)  		goto err_out_disable;  #ifdef PM8001_USE_TASKLET -	/* default tasklet for non msi-x interrupt handler/first msi-x -	* interrupt handler */ -	tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, -			(unsigned long)pm8001_ha); +	/*  Tasklet for non msi-x interrupt handler */ +	if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) +		tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, +			(unsigned long)&(pm8001_ha->irq_vector[0])); +	else +		for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) +			tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, +				(unsigned long)&(pm8001_ha->irq_vector[j]));  #endif  	PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0);  	if (pm8001_ha->chip_id != chip_8001) { @@ -1023,10 +1080,7 @@ err_out_enable:   */  static struct pci_device_id pm8001_pci_table[] = {  	{ PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 }, -	{ -		PCI_DEVICE(0x117c, 0x0042), -		.driver_data = chip_8001 -	}, +	{ PCI_VDEVICE(ATTO, 0x0042), chip_8001 },  	/* Support for SPC/SPCv/SPCve controllers */  	{ PCI_VDEVICE(ADAPTEC2, 0x8001), chip_8001 },  	{ PCI_VDEVICE(PMC_Sierra, 0x8008), chip_8008 }, @@ -1037,6 +1091,12 @@ static struct pci_device_id pm8001_pci_table[] = {  	{ PCI_VDEVICE(ADAPTEC2, 0x8009), chip_8009 },  	{ PCI_VDEVICE(PMC_Sierra, 0x8019), chip_8019 },  	{ PCI_VDEVICE(ADAPTEC2, 0x8019), chip_8019 }, +	{ PCI_VDEVICE(PMC_Sierra, 0x8074), chip_8074 }, +	{ PCI_VDEVICE(ADAPTEC2, 0x8074), chip_8074 }, +	{ PCI_VDEVICE(PMC_Sierra, 0x8076), chip_8076 }, +	{ PCI_VDEVICE(ADAPTEC2, 0x8076), chip_8076 }, +	{ PCI_VDEVICE(PMC_Sierra, 0x8077), chip_8077 }, +	{ PCI_VDEVICE(ADAPTEC2, 0x8077), chip_8077 },  	{ PCI_VENDOR_ID_ADAPTEC2, 0x8081,  		PCI_VENDOR_ID_ADAPTEC2, 0x0400, 0, 0, chip_8001 },  	{ PCI_VENDOR_ID_ADAPTEC2, 0x8081, @@ -1057,6 +1117,24 @@ static struct pci_device_id pm8001_pci_table[] = {  		PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8019 },  	{ PCI_VENDOR_ID_ADAPTEC2, 0x8089,  		PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8019 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8074, +		PCI_VENDOR_ID_ADAPTEC2, 0x0800, 0, 0, chip_8074 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8076, +		PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8076 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8077, +		PCI_VENDOR_ID_ADAPTEC2, 0x1600, 0, 0, chip_8077 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8074, +		PCI_VENDOR_ID_ADAPTEC2, 0x0008, 0, 0, chip_8074 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8076, +		PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8076 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8077, +		PCI_VENDOR_ID_ADAPTEC2, 0x0016, 0, 0, chip_8077 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8076, +		PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8076 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8077, +		PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 }, +	{ PCI_VENDOR_ID_ADAPTEC2, 0x8074, +		PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 },  	{} /* terminate list */  }; @@ -1108,8 +1186,12 @@ module_init(pm8001_init);  module_exit(pm8001_exit);  MODULE_AUTHOR("Jack Wang <jack_wang@usish.com>"); +MODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>"); +MODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>"); +MODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>");  MODULE_DESCRIPTION( -		"PMC-Sierra PM8001/8081/8088/8089 SAS/SATA controller driver"); +		"PMC-Sierra PM8001/8081/8088/8089/8074/8076/8077 " +		"SAS/SATA controller driver");  MODULE_VERSION(DRV_VERSION);  MODULE_LICENSE("GPL");  MODULE_DEVICE_TABLE(pci, pm8001_pci_table); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index a85d73de7c8..8a44bc92bc7 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -434,6 +434,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,  		ccb->n_elem = n_elem;  		ccb->ccb_tag = tag;  		ccb->task = t; +		ccb->device = pm8001_dev;  		switch (t->task_proto) {  		case SAS_PROTOCOL_SMP:  			rc = pm8001_task_prep_smp(pm8001_ha, ccb); @@ -447,7 +448,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,  			break;  		case SAS_PROTOCOL_SATA:  		case SAS_PROTOCOL_STP: -		case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:  			rc = pm8001_task_prep_ata(pm8001_ha, ccb);  			break;  		default: @@ -704,6 +704,8 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,  	int res, retry;  	struct sas_task *task = NULL;  	struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); +	struct pm8001_device *pm8001_dev = dev->lldd_dev; +	DECLARE_COMPLETION_ONSTACK(completion_setstate);  	for (retry = 0; retry < 3; retry++) {  		task = sas_alloc_slow_task(GFP_KERNEL); @@ -729,6 +731,12 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,  			goto ex_err;  		}  		wait_for_completion(&task->slow_task->completion); +		if (pm8001_ha->chip_id != chip_8001) { +			pm8001_dev->setds_completion = &completion_setstate; +				PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, +					pm8001_dev, 0x01); +			wait_for_completion(&completion_setstate); +		}  		res = -TMF_RESP_FUNC_FAILED;  		/* Even TMF timed out, return direct. */  		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { @@ -858,13 +866,11 @@ ex_err:  static void pm8001_dev_gone_notify(struct domain_device *dev)  {  	unsigned long flags = 0; -	u32 tag;  	struct pm8001_hba_info *pm8001_ha;  	struct pm8001_device *pm8001_dev = dev->lldd_dev;  	pm8001_ha = pm8001_find_ha_by_dev(dev);  	spin_lock_irqsave(&pm8001_ha->lock, flags); -	pm8001_tag_alloc(pm8001_ha, &tag);  	if (pm8001_dev) {  		u32 device_id = pm8001_dev->device_id; @@ -1091,15 +1097,17 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun)  	struct pm8001_tmf_task tmf_task;  	struct pm8001_device *pm8001_dev = dev->lldd_dev;  	struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); +	DECLARE_COMPLETION_ONSTACK(completion_setstate);  	if (dev_is_sata(dev)) {  		struct sas_phy *phy = sas_get_local_phy(dev);  		rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,  			dev, 1, 0);  		rc = sas_phy_reset(phy, 1);  		sas_put_local_phy(phy); +		pm8001_dev->setds_completion = &completion_setstate;  		rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,  			pm8001_dev, 0x01); -		msleep(2000); +		wait_for_completion(&completion_setstate);  	} else {  		tmf_task.tmf = TMF_LU_RESET;  		rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 570819464d9..1ee06f21803 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -104,6 +104,9 @@ do {						\  #define DEV_IS_EXPANDER(type)	((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) +#define IS_SPCV_12G(dev)	((dev->device == 0X8074)		\ +				|| (dev->device == 0X8076)		\ +				|| (dev->device == 0X8077))  #define PM8001_NAME_LENGTH		32/* generic length of strings */  extern struct list_head hba_list; @@ -129,6 +132,61 @@ struct pm8001_ioctl_payload {  	u8	*func_specific;  }; +#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF +#define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24) +#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET            0x00     /* HNFBUFL */ +#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET            0x04     /* HNFBUFH */ +#define MPI_FATAL_EDUMP_TABLE_LENGTH               0x08     /* HNFBLEN */ +#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE            0x0C     /* FDDHSHK */ +#define MPI_FATAL_EDUMP_TABLE_STATUS               0x10     /* FDDTSTAT */ +#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN            0x14     /* ACCDDLEN */ +#define MPI_FATAL_EDUMP_HANDSHAKE_RDY              0x1 +#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY             0x0 +#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD                 0x0 +#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED           0x1 +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2 +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE      0x3 +#define TYPE_GSM_SPACE        1 +#define TYPE_QUEUE            2 +#define TYPE_FATAL            3 +#define TYPE_NON_FATAL        4 +#define TYPE_INBOUND          1 +#define TYPE_OUTBOUND         2 +struct forensic_data { +	u32  data_type; +	union { +		struct { +			u32  direct_len; +			u32  direct_offset; +			void  *direct_data; +		} gsm_buf; +		struct { +			u16  queue_type; +			u16  queue_index; +			u32  direct_len; +			void  *direct_data; +		} queue_buf; +		struct { +			u32  direct_len; +			u32  direct_offset; +			u32  read_len; +			void  *direct_data; +		} data_buf; +	}; +}; + +/* bit31-26 - mask bar */ +#define SCRATCH_PAD0_BAR_MASK                    0xFC000000 +/* bit25-0  - offset mask */ +#define SCRATCH_PAD0_OFFSET_MASK                 0x03FFFFFF +/* if AAP error state */ +#define SCRATCH_PAD0_AAPERR_MASK                 0xFFFFFFFF +/* Inbound doorbell bit7 */ +#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP	 0x80 +/* Inbound doorbell bit7 SPCV */ +#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO  0x80 +#define MAIN_MERRDCTO_MERRDCES		         0xA0/* DWORD 0x28) */ +  struct pm8001_dispatch {  	char *name;  	int (*chip_init)(struct pm8001_hba_info *pm8001_ha); @@ -343,6 +401,7 @@ union main_cfg_table {  	u32			phy_attr_table_offset;  	u32			port_recovery_timer;  	u32			interrupt_reassertion_delay; +	u32			fatal_n_non_fatal_dump;	        /* 0x28 */  	} pm80xx_tbl;  }; @@ -407,6 +466,10 @@ struct pm8001_hba_memspace {  	u64			membase;  	u32			memsize;  }; +struct isr_param { +	struct pm8001_hba_info *drv_inst; +	u32 irq_id; +};  struct pm8001_hba_info {  	char			name[PM8001_NAME_LENGTH];  	struct list_head	list; @@ -417,6 +480,13 @@ struct pm8001_hba_info {  	struct pm8001_hba_memspace io_mem[6];  	struct mpi_mem_req	memoryMap;  	struct encrypt		encrypt_info; /* support encryption */ +	struct forensic_data	forensic_info; +	u32			fatal_bar_loc; +	u32			forensic_last_offset; +	u32			fatal_forensic_shift_offset; +	u32			forensic_fatal_step; +	u32			evtlog_ib_offset; +	u32			evtlog_ob_offset;  	void __iomem	*msg_unit_tbl_addr;/*Message Unit Table Addr*/  	void __iomem	*main_cfg_tbl_addr;/*Main Config Table Addr*/  	void __iomem	*general_stat_tbl_addr;/*General Status Table Addr*/ @@ -425,6 +495,7 @@ struct pm8001_hba_info {  	void __iomem	*pspa_q_tbl_addr;  			/*MPI SAS PHY attributes Queue Config Table Addr*/  	void __iomem	*ivt_tbl_addr; /*MPI IVT Table Addr */ +	void __iomem	*fatal_tbl_addr; /*MPI IVT Table Addr */  	union main_cfg_table	main_cfg_tbl;  	union general_status_table	gs_tbl;  	struct inbound_queue_table	inbnd_q_tbl[PM8001_MAX_SPCV_INB_NUM]; @@ -452,14 +523,13 @@ struct pm8001_hba_info {  	int			number_of_intr;/*will be used in remove()*/  #endif  #ifdef PM8001_USE_TASKLET -	struct tasklet_struct	tasklet; +	struct tasklet_struct	tasklet[PM8001_MAX_MSIX_VEC];  #endif  	u32			logging_level;  	u32			fw_status;  	u32			smp_exp_mode; -	u32			int_vector;  	const struct firmware 	*fw_image; -	u8			outq[PM8001_MAX_MSIX_VEC]; +	struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];  };  struct pm8001_work { @@ -629,9 +699,26 @@ struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha,  int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);  int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); - +void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, +	u32 length, u8 *buf); +int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); +ssize_t pm80xx_get_fatal_dump(struct device *cdev, +		struct device_attribute *attr, char *buf); +ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);  /* ctl shared API */  extern struct device_attribute *pm8001_host_attrs[]; +static inline void +pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha, +			struct sas_task *task, struct pm8001_ccb_info *ccb, +			u32 ccb_idx) +{ +	pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx); +	smp_mb(); /*in order to force CPU ordering*/ +	spin_unlock(&pm8001_ha->lock); +	task->task_done(task); +	spin_lock(&pm8001_ha->lock); +} +  #endif diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 9f91030211e..d70587f9618 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -45,6 +45,221 @@  #define SMP_DIRECT 1  #define SMP_INDIRECT 2 + + +int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) +{ +	u32 reg_val; +	unsigned long start; +	pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value); +	/* confirm the setting is written */ +	start = jiffies + HZ; /* 1 sec */ +	do { +		reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER); +	} while ((reg_val != shift_value) && time_before(jiffies, start)); +	if (reg_val != shift_value) { +		PM8001_FAIL_DBG(pm8001_ha, +			pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" +			" = 0x%x\n", reg_val)); +		return -1; +	} +	return 0; +} + +void pm80xx_pci_mem_copy(struct pm8001_hba_info  *pm8001_ha, u32 soffset, +				const void *destination, +				u32 dw_count, u32 bus_base_number) +{ +	u32 index, value, offset; +	u32 *destination1; +	destination1 = (u32 *)destination; + +	for (index = 0; index < dw_count; index += 4, destination1++) { +		offset = (soffset + index / 4); +		if (offset < (64 * 1024)) { +			value = pm8001_cr32(pm8001_ha, bus_base_number, offset); +			*destination1 =  cpu_to_le32(value); +		} +	} +	return; +} + +ssize_t pm80xx_get_fatal_dump(struct device *cdev, +	struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); +	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; +	void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; +	u32 accum_len , reg_val, index, *temp; +	unsigned long start; +	u8 *direct_data; +	char *fatal_error_data = buf; + +	pm8001_ha->forensic_info.data_buf.direct_data = buf; +	if (pm8001_ha->chip_id == chip_8001) { +		pm8001_ha->forensic_info.data_buf.direct_data += +			sprintf(pm8001_ha->forensic_info.data_buf.direct_data, +			"Not supported for SPC controller"); +		return (char *)pm8001_ha->forensic_info.data_buf.direct_data - +			(char *)buf; +	} +	if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { +		PM8001_IO_DBG(pm8001_ha, +		pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); +		direct_data = (u8 *)fatal_error_data; +		pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; +		pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; +		pm8001_ha->forensic_info.data_buf.read_len = 0; + +		pm8001_ha->forensic_info.data_buf.direct_data = direct_data; + +		/* start to get data */ +		/* Program the MEMBASE II Shifting Register with 0x00.*/ +		pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, +				pm8001_ha->fatal_forensic_shift_offset); +		pm8001_ha->forensic_last_offset = 0; +		pm8001_ha->forensic_fatal_step = 0; +		pm8001_ha->fatal_bar_loc = 0; +	} + +	/* Read until accum_len is retrived */ +	accum_len = pm8001_mr32(fatal_table_address, +				MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); +	PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n", +						accum_len)); +	if (accum_len == 0xFFFFFFFF) { +		PM8001_IO_DBG(pm8001_ha, +			pm8001_printk("Possible PCI issue 0x%x not expected\n", +				accum_len)); +		return -EIO; +	} +	if (accum_len == 0 || accum_len >= 0x100000) { +		pm8001_ha->forensic_info.data_buf.direct_data += +			sprintf(pm8001_ha->forensic_info.data_buf.direct_data, +				"%08x ", 0xFFFFFFFF); +		return (char *)pm8001_ha->forensic_info.data_buf.direct_data - +			(char *)buf; +	} +	temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; +	if (pm8001_ha->forensic_fatal_step == 0) { +moreData: +		if (pm8001_ha->forensic_info.data_buf.direct_data) { +			/* Data is in bar, copy to host memory */ +			pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc, +			 pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, +				pm8001_ha->forensic_info.data_buf.direct_len , +					1); +		} +		pm8001_ha->fatal_bar_loc += +			pm8001_ha->forensic_info.data_buf.direct_len; +		pm8001_ha->forensic_info.data_buf.direct_offset += +			pm8001_ha->forensic_info.data_buf.direct_len; +		pm8001_ha->forensic_last_offset	+= +			pm8001_ha->forensic_info.data_buf.direct_len; +		pm8001_ha->forensic_info.data_buf.read_len = +			pm8001_ha->forensic_info.data_buf.direct_len; + +		if (pm8001_ha->forensic_last_offset  >= accum_len) { +			pm8001_ha->forensic_info.data_buf.direct_data += +			sprintf(pm8001_ha->forensic_info.data_buf.direct_data, +				"%08x ", 3); +			for (index = 0; index < (SYSFS_OFFSET / 4); index++) { +				pm8001_ha->forensic_info.data_buf.direct_data += +					sprintf(pm8001_ha-> +					 forensic_info.data_buf.direct_data, +						"%08x ", *(temp + index)); +			} + +			pm8001_ha->fatal_bar_loc = 0; +			pm8001_ha->forensic_fatal_step = 1; +			pm8001_ha->fatal_forensic_shift_offset = 0; +			pm8001_ha->forensic_last_offset	= 0; +			return (char *)pm8001_ha-> +				forensic_info.data_buf.direct_data - +				(char *)buf; +		} +		if (pm8001_ha->fatal_bar_loc < (64 * 1024)) { +			pm8001_ha->forensic_info.data_buf.direct_data += +				sprintf(pm8001_ha-> +					forensic_info.data_buf.direct_data, +					"%08x ", 2); +			for (index = 0; index < (SYSFS_OFFSET / 4); index++) { +				pm8001_ha->forensic_info.data_buf.direct_data += +					sprintf(pm8001_ha-> +					forensic_info.data_buf.direct_data, +					"%08x ", *(temp + index)); +			} +			return (char *)pm8001_ha-> +				forensic_info.data_buf.direct_data - +				(char *)buf; +		} + +		/* Increment the MEMBASE II Shifting Register value by 0x100.*/ +		pm8001_ha->forensic_info.data_buf.direct_data += +			sprintf(pm8001_ha->forensic_info.data_buf.direct_data, +				"%08x ", 2); +		for (index = 0; index < 256; index++) { +			pm8001_ha->forensic_info.data_buf.direct_data += +				sprintf(pm8001_ha-> +					forensic_info.data_buf.direct_data, +						"%08x ", *(temp + index)); +		} +		pm8001_ha->fatal_forensic_shift_offset += 0x100; +		pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, +			pm8001_ha->fatal_forensic_shift_offset); +		pm8001_ha->fatal_bar_loc = 0; +		return (char *)pm8001_ha->forensic_info.data_buf.direct_data - +			(char *)buf; +	} +	if (pm8001_ha->forensic_fatal_step == 1) { +		pm8001_ha->fatal_forensic_shift_offset = 0; +		/* Read 64K of the debug data. */ +		pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, +			pm8001_ha->fatal_forensic_shift_offset); +		pm8001_mw32(fatal_table_address, +			MPI_FATAL_EDUMP_TABLE_HANDSHAKE, +				MPI_FATAL_EDUMP_HANDSHAKE_RDY); + +		/* Poll FDDHSHK  until clear  */ +		start = jiffies + (2 * HZ); /* 2 sec */ + +		do { +			reg_val = pm8001_mr32(fatal_table_address, +					MPI_FATAL_EDUMP_TABLE_HANDSHAKE); +		} while ((reg_val) && time_before(jiffies, start)); + +		if (reg_val != 0) { +			PM8001_FAIL_DBG(pm8001_ha, +			pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" +			" = 0x%x\n", reg_val)); +			return -EIO; +		} + +		/* Read the next 64K of the debug data. */ +		pm8001_ha->forensic_fatal_step = 0; +		if (pm8001_mr32(fatal_table_address, +			MPI_FATAL_EDUMP_TABLE_STATUS) != +				MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { +			pm8001_mw32(fatal_table_address, +				MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0); +			goto moreData; +		} else { +			pm8001_ha->forensic_info.data_buf.direct_data += +				sprintf(pm8001_ha-> +					forensic_info.data_buf.direct_data, +						"%08x ", 4); +			pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; +			pm8001_ha->forensic_info.data_buf.direct_len =  0; +			pm8001_ha->forensic_info.data_buf.direct_offset = 0; +			pm8001_ha->forensic_info.data_buf.read_len = 0; +		} +	} + +	return (char *)pm8001_ha->forensic_info.data_buf.direct_data - +		(char *)buf; +} +  /**   * read_main_config_table - read the configure table and save it.   * @pm8001_ha: our hba card information @@ -430,7 +645,11 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)  	table is updated */  	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_UPDATE);  	/* wait until Inbound DoorBell Clear Register toggled */ -	max_wait_count = 2 * 1000 * 1000;/* 2 sec for spcv/ve */ +	if (IS_SPCV_12G(pm8001_ha->pdev)) { +		max_wait_count = 4 * 1000 * 1000;/* 4 sec */ +	} else { +		max_wait_count = 2 * 1000 * 1000;/* 2 sec */ +	}  	do {  		udelay(1);  		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); @@ -579,6 +798,9 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)  	pm8001_ha->pspa_q_tbl_addr =  		base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) &  					0xFFFFFF); +	pm8001_ha->fatal_tbl_addr = +		base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) & +					0xFFFFFF);  	PM8001_INIT_DBG(pm8001_ha,  			pm8001_printk("GST OFFSET 0x%x\n", @@ -913,7 +1135,11 @@ static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)  	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_RESET);  	/* wait until Inbound DoorBell Clear Register toggled */ -	max_wait_count = 2 * 1000 * 1000;	/* 2 sec for spcv/ve */ +	if (IS_SPCV_12G(pm8001_ha->pdev)) { +		max_wait_count = 4 * 1000 * 1000;/* 4 sec */ +	} else { +		max_wait_count = 2 * 1000 * 1000;/* 2 sec */ +	}  	do {  		udelay(1);  		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); @@ -959,6 +1185,7 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)  {  	u32 regval;  	u32 bootloader_state; +	u32 ibutton0, ibutton1;  	/* Check if MPI is in ready state to reset */  	if (mpi_uninit_check(pm8001_ha) != 0) { @@ -1017,7 +1244,27 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)  	if (-1 == check_fw_ready(pm8001_ha)) {  		PM8001_FAIL_DBG(pm8001_ha,  			pm8001_printk("Firmware is not ready!\n")); -		return -EBUSY; +		/* check iButton feature support for motherboard controller */ +		if (pm8001_ha->pdev->subsystem_vendor != +			PCI_VENDOR_ID_ADAPTEC2 && +			pm8001_ha->pdev->subsystem_vendor != 0) { +			ibutton0 = pm8001_cr32(pm8001_ha, 0, +					MSGU_HOST_SCRATCH_PAD_6); +			ibutton1 = pm8001_cr32(pm8001_ha, 0, +					MSGU_HOST_SCRATCH_PAD_7); +			if (!ibutton0 && !ibutton1) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("iButton Feature is" +					" not Available!!!\n")); +				return -EBUSY; +			} +			if (ibutton0 == 0xdeadbeef && ibutton1 == 0xdeadbeef) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("CRC Check for iButton" +					" Feature Failed!!!\n")); +				return -EBUSY; +			} +		}  	}  	PM8001_INIT_DBG(pm8001_ha,  		pm8001_printk("SPCv soft reset Complete\n")); @@ -1268,6 +1515,13 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)  	if (unlikely(!t || !t->lldd_task || !t->dev))  		return;  	ts = &t->task_status; +	/* Print sas address of IO failed device */ +	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && +		(status != IO_UNDERFLOW)) +		PM8001_FAIL_DBG(pm8001_ha, +			pm8001_printk("SAS Address of IO Failure Drive" +			":%016llx", SAS_ADDR(t->dev->sas_addr))); +  	switch (status) {  	case IO_SUCCESS:  		PM8001_IO_DBG(pm8001_ha, @@ -1691,6 +1945,10 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  	u32 param;  	u32 status;  	u32 tag; +	int i, j; +	u8 sata_addr_low[4]; +	u32 temp_sata_addr_low, temp_sata_addr_hi; +	u8 sata_addr_hi[4];  	struct sata_completion_resp *psataPayload;  	struct task_status_struct *ts;  	struct ata_task_resp *resp ; @@ -1740,7 +1998,47 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  			pm8001_printk("ts null\n"));  		return;  	} +	/* Print sas address of IO failed device */ +	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && +		(status != IO_UNDERFLOW)) { +		if (!((t->dev->parent) && +			(DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { +			for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++) +				sata_addr_low[i] = pm8001_ha->sas_addr[j]; +			for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++) +				sata_addr_hi[i] = pm8001_ha->sas_addr[j]; +			memcpy(&temp_sata_addr_low, sata_addr_low, +				sizeof(sata_addr_low)); +			memcpy(&temp_sata_addr_hi, sata_addr_hi, +				sizeof(sata_addr_hi)); +			temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff) +						|((temp_sata_addr_hi << 8) & +						0xff0000) | +						((temp_sata_addr_hi >> 8) +						& 0xff00) | +						((temp_sata_addr_hi << 24) & +						0xff000000)); +			temp_sata_addr_low = ((((temp_sata_addr_low >> 24) +						& 0xff) | +						((temp_sata_addr_low << 8) +						& 0xff0000) | +						((temp_sata_addr_low >> 8) +						& 0xff00) | +						((temp_sata_addr_low << 24) +						& 0xff000000)) + +						pm8001_dev->attached_phy + +						0x10); +			PM8001_FAIL_DBG(pm8001_ha, +				pm8001_printk("SAS Address of IO Failure Drive:" +				"%08x%08x", temp_sata_addr_hi, +					temp_sata_addr_low)); +		} else { +			PM8001_FAIL_DBG(pm8001_ha, +				pm8001_printk("SAS Address of IO Failure Drive:" +				"%016llx", SAS_ADDR(t->dev->sas_addr))); +		} +	}  	switch (status) {  	case IO_SUCCESS:  		PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); @@ -1870,11 +2168,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*in order to force CPU ordering*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -1890,11 +2184,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -1916,11 +2206,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/* ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -1983,11 +2269,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  					IO_DS_NON_OPERATIONAL);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2007,11 +2289,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  					IO_DS_IN_ERROR);  			ts->resp = SAS_TASK_UNDELIVERED;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2040,20 +2318,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)  			" resp 0x%x stat 0x%x but aborted by upper layer!\n",  			t, status, ts->resp, ts->stat));  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -	} else if (t->uldd_task) { -		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/* ditto */ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); -	} else if (!t->uldd_task) { +	} else {  		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/*ditto*/ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); +		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  	}  } @@ -2165,11 +2432,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)  				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);  			ts->resp = SAS_TASK_COMPLETE;  			ts->stat = SAS_QUEUE_FULL; -			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -			mb();/*ditto*/ -			spin_unlock_irq(&pm8001_ha->lock); -			t->task_done(t); -			spin_lock_irq(&pm8001_ha->lock); +			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  			return;  		}  		break; @@ -2291,20 +2554,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)  			" resp 0x%x stat 0x%x but aborted by upper layer!\n",  			t, event, ts->resp, ts->stat));  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -	} else if (t->uldd_task) { -		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/* ditto */ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); -	} else if (!t->uldd_task) { +	} else {  		spin_unlock_irqrestore(&t->task_state_lock, flags); -		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); -		mb();/*ditto*/ -		spin_unlock_irq(&pm8001_ha->lock); -		t->task_done(t); -		spin_lock_irq(&pm8001_ha->lock); +		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);  	}  } @@ -2589,6 +2841,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)  	unsigned long flags;  	u8 deviceType = pPayload->sas_identify.dev_type;  	port->port_state = portstate; +	phy->phy_state = PHY_STATE_LINK_UP_SPCV;  	PM8001_MSG_DBG(pm8001_ha, pm8001_printk(  		"portid:%d; phyid:%d; linkrate:%d; "  		"portstate:%x; devicetype:%x\n", @@ -2673,6 +2926,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)  				port_id, phy_id, link_rate, portstate));  	port->port_state = portstate; +	phy->phy_state = PHY_STATE_LINK_UP_SPCV;  	port->port_attached = 1;  	pm8001_get_lrate_mode(phy, link_rate);  	phy->phy_type |= PORT_TYPE_SATA; @@ -3103,9 +3357,27 @@ static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)  static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,  			void *piomb)  { -	PM8001_MSG_DBG(pm8001_ha, -			pm8001_printk(" pm80xx_addition_functionality\n")); +	u8 page_code; +	struct set_phy_profile_resp *pPayload = +		(struct set_phy_profile_resp *)(piomb + 4); +	u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid); +	u32 status = le32_to_cpu(pPayload->status); +	page_code = (u8)((ppc_phyid & 0xFF00) >> 8); +	if (status) { +		/* status is FAILED */ +		PM8001_FAIL_DBG(pm8001_ha, +			pm8001_printk("PhyProfile command failed  with status " +			"0x%08X \n", status)); +		return -1; +	} else { +		if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) { +			PM8001_FAIL_DBG(pm8001_ha, +				pm8001_printk("Invalid page code 0x%X\n", +					page_code)); +			return -1; +		} +	}  	return 0;  } @@ -3484,8 +3756,6 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,  	else  		pm8001_ha->smp_exp_mode = SMP_INDIRECT; -	/* DIRECT MODE support only in spcv/ve */ -	pm8001_ha->smp_exp_mode = SMP_DIRECT;  	tmp_addr = cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));  	preq_dma_addr = (char *)phys_to_virt(tmp_addr); @@ -3501,7 +3771,7 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,  		/* exclude top 4 bytes for SMP req header */  		smp_cmd.long_smp_req.long_req_addr =  			cpu_to_le64((u64)sg_dma_address -				(&task->smp_task.smp_req) - 4); +				(&task->smp_task.smp_req) + 4);  		/* exclude 4 bytes for SMP req header and CRC */  		smp_cmd.long_smp_req.long_req_size =  			cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-8); @@ -3604,10 +3874,10 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  	struct ssp_ini_io_start_req ssp_cmd;  	u32 tag = ccb->ccb_tag;  	int ret; -	u64 phys_addr; +	u64 phys_addr, start_addr, end_addr; +	u32 end_addr_high, end_addr_low;  	struct inbound_queue_table *circularQ; -	static u32 inb; -	static u32 outb; +	u32 q_index;  	u32 opc = OPC_INB_SSPINIIOSTART;  	memset(&ssp_cmd, 0, sizeof(ssp_cmd));  	memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); @@ -3626,7 +3896,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  	ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7);  	memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd,  		       task->ssp_task.cmd->cmd_len); -	circularQ = &pm8001_ha->inbnd_q_tbl[0]; +	q_index = (u32) (pm8001_dev->id & 0x00ffffff) % PM8001_MAX_INB_NUM; +	circularQ = &pm8001_ha->inbnd_q_tbl[q_index];  	/* Check if encryption is set */  	if (pm8001_ha->chip->encrypt && @@ -3658,6 +3929,30 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  				cpu_to_le32(upper_32_bits(dma_addr));  			ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len);  			ssp_cmd.enc_esgl = 0; +			/* Check 4G Boundary */ +			start_addr = cpu_to_le64(dma_addr); +			end_addr = (start_addr + ssp_cmd.enc_len) - 1; +			end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); +			end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); +			if (end_addr_high != ssp_cmd.enc_addr_high) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("The sg list address " +					"start_addr=0x%016llx data_len=0x%x " +					"end_addr_high=0x%08x end_addr_low=" +					"0x%08x has crossed 4G boundary\n", +						start_addr, ssp_cmd.enc_len, +						end_addr_high, end_addr_low)); +				pm8001_chip_make_sg(task->scatter, 1, +					ccb->buf_prd); +				phys_addr = ccb->ccb_dma_handle + +					offsetof(struct pm8001_ccb_info, +						buf_prd[0]); +				ssp_cmd.enc_addr_low = +					cpu_to_le32(lower_32_bits(phys_addr)); +				ssp_cmd.enc_addr_high = +					cpu_to_le32(upper_32_bits(phys_addr)); +				ssp_cmd.enc_esgl = cpu_to_le32(1<<31); +			}  		} else if (task->num_scatter == 0) {  			ssp_cmd.enc_addr_low = 0;  			ssp_cmd.enc_addr_high = 0; @@ -3674,7 +3969,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  	} else {  		PM8001_IO_DBG(pm8001_ha, pm8001_printk(  			"Sending Normal SAS command 0x%x inb q %x\n", -			task->ssp_task.cmd->cmnd[0], inb)); +			task->ssp_task.cmd->cmnd[0], q_index));  		/* fill in PRD (scatter/gather) table, if any */  		if (task->num_scatter > 1) {  			pm8001_chip_make_sg(task->scatter, ccb->n_elem, @@ -3693,6 +3988,30 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  				cpu_to_le32(upper_32_bits(dma_addr));  			ssp_cmd.len = cpu_to_le32(task->total_xfer_len);  			ssp_cmd.esgl = 0; +			/* Check 4G Boundary */ +			start_addr = cpu_to_le64(dma_addr); +			end_addr = (start_addr + ssp_cmd.len) - 1; +			end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); +			end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); +			if (end_addr_high != ssp_cmd.addr_high) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("The sg list address " +					"start_addr=0x%016llx data_len=0x%x " +					"end_addr_high=0x%08x end_addr_low=" +					"0x%08x has crossed 4G boundary\n", +						 start_addr, ssp_cmd.len, +						 end_addr_high, end_addr_low)); +				pm8001_chip_make_sg(task->scatter, 1, +					ccb->buf_prd); +				phys_addr = ccb->ccb_dma_handle + +					offsetof(struct pm8001_ccb_info, +						 buf_prd[0]); +				ssp_cmd.addr_low = +					cpu_to_le32(lower_32_bits(phys_addr)); +				ssp_cmd.addr_high = +					cpu_to_le32(upper_32_bits(phys_addr)); +				ssp_cmd.esgl = cpu_to_le32(1<<31); +			}  		} else if (task->num_scatter == 0) {  			ssp_cmd.addr_low = 0;  			ssp_cmd.addr_high = 0; @@ -3700,11 +4019,9 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,  			ssp_cmd.esgl = 0;  		}  	} -	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd, outb++); - -	/* rotate the outb queue */ -	outb = outb%PM8001_MAX_SPCV_OUTB_NUM; - +	q_index = (u32) (pm8001_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM; +	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, +						&ssp_cmd, q_index);  	return ret;  } @@ -3716,18 +4033,19 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  	struct pm8001_device *pm8001_ha_dev = dev->lldd_dev;  	u32 tag = ccb->ccb_tag;  	int ret; -	static u32 inb; -	static u32 outb; +	u32 q_index;  	struct sata_start_req sata_cmd;  	u32 hdr_tag, ncg_tag = 0; -	u64 phys_addr; +	u64 phys_addr, start_addr, end_addr; +	u32 end_addr_high, end_addr_low;  	u32 ATAP = 0x0;  	u32 dir;  	struct inbound_queue_table *circularQ;  	unsigned long flags;  	u32 opc = OPC_INB_SATA_HOST_OPSTART;  	memset(&sata_cmd, 0, sizeof(sata_cmd)); -	circularQ = &pm8001_ha->inbnd_q_tbl[0]; +	q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_INB_NUM; +	circularQ = &pm8001_ha->inbnd_q_tbl[q_index];  	if (task->data_dir == PCI_DMA_NONE) {  		ATAP = 0x04; /* no data*/ @@ -3788,6 +4106,31 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  			sata_cmd.enc_addr_high = upper_32_bits(dma_addr);  			sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);  			sata_cmd.enc_esgl = 0; +			/* Check 4G Boundary */ +			start_addr = cpu_to_le64(dma_addr); +			end_addr = (start_addr + sata_cmd.enc_len) - 1; +			end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); +			end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); +			if (end_addr_high != sata_cmd.enc_addr_high) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("The sg list address " +					"start_addr=0x%016llx data_len=0x%x " +					"end_addr_high=0x%08x end_addr_low" +					"=0x%08x has crossed 4G boundary\n", +						start_addr, sata_cmd.enc_len, +						end_addr_high, end_addr_low)); +				pm8001_chip_make_sg(task->scatter, 1, +					ccb->buf_prd); +				phys_addr = ccb->ccb_dma_handle + +						offsetof(struct pm8001_ccb_info, +						buf_prd[0]); +				sata_cmd.enc_addr_low = +					lower_32_bits(phys_addr); +				sata_cmd.enc_addr_high = +					upper_32_bits(phys_addr); +				sata_cmd.enc_esgl = +					cpu_to_le32(1 << 31); +			}  		} else if (task->num_scatter == 0) {  			sata_cmd.enc_addr_low = 0;  			sata_cmd.enc_addr_high = 0; @@ -3808,7 +4151,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  	} else {  		PM8001_IO_DBG(pm8001_ha, pm8001_printk(  			"Sending Normal SATA command 0x%x inb %x\n", -			sata_cmd.sata_fis.command, inb)); +			sata_cmd.sata_fis.command, q_index));  		/* dad (bit 0-1) is 0 */  		sata_cmd.ncqtag_atap_dir_m_dad =  			cpu_to_le32(((ncg_tag & 0xff)<<16) | @@ -3829,6 +4172,30 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  			sata_cmd.addr_high = upper_32_bits(dma_addr);  			sata_cmd.len = cpu_to_le32(task->total_xfer_len);  			sata_cmd.esgl = 0; +			/* Check 4G Boundary */ +			start_addr = cpu_to_le64(dma_addr); +			end_addr = (start_addr + sata_cmd.len) - 1; +			end_addr_low = cpu_to_le32(lower_32_bits(end_addr)); +			end_addr_high = cpu_to_le32(upper_32_bits(end_addr)); +			if (end_addr_high != sata_cmd.addr_high) { +				PM8001_FAIL_DBG(pm8001_ha, +					pm8001_printk("The sg list address " +					"start_addr=0x%016llx data_len=0x%x" +					"end_addr_high=0x%08x end_addr_low=" +					"0x%08x has crossed 4G boundary\n", +						start_addr, sata_cmd.len, +						end_addr_high, end_addr_low)); +				pm8001_chip_make_sg(task->scatter, 1, +					ccb->buf_prd); +				phys_addr = ccb->ccb_dma_handle + +					offsetof(struct pm8001_ccb_info, +					buf_prd[0]); +				sata_cmd.addr_low = +					lower_32_bits(phys_addr); +				sata_cmd.addr_high = +					upper_32_bits(phys_addr); +				sata_cmd.esgl = cpu_to_le32(1 << 31); +			}  		} else if (task->num_scatter == 0) {  			sata_cmd.addr_low = 0;  			sata_cmd.addr_high = 0; @@ -3884,33 +4251,18 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,  					"\n", task, ts->resp, ts->stat));  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);  				return 0; -			} else if (task->uldd_task) { -				spin_unlock_irqrestore(&task->task_state_lock, -							flags); -				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); -				mb();/* ditto */ -				spin_unlock_irq(&pm8001_ha->lock); -				task->task_done(task); -				spin_lock_irq(&pm8001_ha->lock); -				return 0; -			} else if (!task->uldd_task) { +			} else {  				spin_unlock_irqrestore(&task->task_state_lock,  							flags); -				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); -				mb();/*ditto*/ -				spin_unlock_irq(&pm8001_ha->lock); -				task->task_done(task); -				spin_lock_irq(&pm8001_ha->lock); +				pm8001_ccb_task_free_done(pm8001_ha, task, +								ccb, tag);  				return 0;  			}  		}  	} - +	q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM;  	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, -						&sata_cmd, outb++); - -	/* rotate the outb queue */ -	outb = outb%PM8001_MAX_SPCV_OUTB_NUM; +						&sata_cmd, q_index);  	return ret;  } @@ -3941,9 +4293,16 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)  	 ** [14]	0b disable spin up hold; 1b enable spin up hold  	 ** [15] ob no change in current PHY analig setup 1b enable using SPAST  	 */ -	payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | -			LINKMODE_AUTO | LINKRATE_15 | -			LINKRATE_30 | LINKRATE_60 | phy_id); +	if (!IS_SPCV_12G(pm8001_ha->pdev)) +		payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | +				LINKMODE_AUTO | LINKRATE_15 | +				LINKRATE_30 | LINKRATE_60 | phy_id); +	else +		payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | +				LINKMODE_AUTO | LINKRATE_15 | +				LINKRATE_30 | LINKRATE_60 | LINKRATE_120 | +				phy_id); +  	/* SSC Disable and SAS Analog ST configuration */  	/**  	payload.ase_sh_lm_slr_phyid = @@ -4102,6 +4461,45 @@ pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)  	return IRQ_HANDLED;  } +void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, +	u32 operation, u32 phyid, u32 length, u32 *buf) +{ +	u32 tag , i, j = 0; +	int rc; +	struct set_phy_profile_req payload; +	struct inbound_queue_table *circularQ; +	u32 opc = OPC_INB_SET_PHY_PROFILE; + +	memset(&payload, 0, sizeof(payload)); +	rc = pm8001_tag_alloc(pm8001_ha, &tag); +	if (rc) +		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Invalid tag\n")); +	circularQ = &pm8001_ha->inbnd_q_tbl[0]; +	payload.tag = cpu_to_le32(tag); +	payload.ppc_phyid = (((operation & 0xF) << 8) | (phyid  & 0xFF)); +	PM8001_INIT_DBG(pm8001_ha, +		pm8001_printk(" phy profile command for phy %x ,length is %d\n", +			payload.ppc_phyid, length)); +	for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) { +		payload.reserved[j] =  cpu_to_le32(*((u32 *)buf + i)); +		j++; +	} +	pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); +} + +void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, +	u32 length, u8 *buf) +{ +	u32 page_code, i; + +	page_code = SAS_PHY_ANALOG_SETTINGS_PAGE; +	for (i = 0; i < pm8001_ha->chip->n_phy; i++) { +		mpi_set_phy_profile_req(pm8001_ha, +			SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf); +		length = length + PHY_DWORD_LENGTH; +	} +	PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n")); +}  const struct pm8001_dispatch pm8001_80xx_dispatch = {  	.name			= "pmc80xx",  	.chip_init		= pm80xx_chip_init, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 2b760ba75d7..9970a385795 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -168,6 +168,11 @@  #define LINKRATE_15			(0x01 << 8)  #define LINKRATE_30			(0x02 << 8)  #define LINKRATE_60			(0x06 << 8) +#define LINKRATE_120			(0x08 << 8) + +/* phy_profile */ +#define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04 +#define PHY_DWORD_LENGTH		0xC  /* Thermal related */  #define	THERMAL_ENABLE			0x1 @@ -210,6 +215,8 @@  #define SAS_DOPNRJT_RTRY_TMO            128  #define SAS_COPNRJT_RTRY_TMO            128 +/* for phy state */ +#define PHY_STATE_LINK_UP_SPCV		0x2  /*    Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second.    Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128 @@ -1223,10 +1230,10 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;  /* MSGU CONFIGURATION TABLE*/ -#define SPCv_MSGU_CFG_TABLE_UPDATE		0x01 -#define SPCv_MSGU_CFG_TABLE_RESET		0x02 -#define SPCv_MSGU_CFG_TABLE_FREEZE		0x04 -#define SPCv_MSGU_CFG_TABLE_UNFREEZE		0x08 +#define SPCv_MSGU_CFG_TABLE_UPDATE		0x001 +#define SPCv_MSGU_CFG_TABLE_RESET		0x002 +#define SPCv_MSGU_CFG_TABLE_FREEZE		0x004 +#define SPCv_MSGU_CFG_TABLE_UNFREEZE		0x008  #define MSGU_IBDB_SET				0x00  #define MSGU_HOST_INT_STATUS			0x08  #define MSGU_HOST_INT_MASK			0x0C @@ -1520,4 +1527,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;  #define DEVREG_FAILURE_PORT_NOT_VALID_STATE		0x06  #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID		0x07 + +#define MEMBASE_II_SHIFT_REGISTER       0x1010  #endif  | 
