diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_base.c')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 247 | 
1 files changed, 203 insertions, 44 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 81209ca8727..beda04a8404 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -81,6 +81,15 @@ static int missing_delay[2] = {-1, -1};  module_param_array(missing_delay, int, NULL, 0);  MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); +static int mpt2sas_fwfault_debug; +MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " +	"and halt firmware - (default=0)"); + +static int disable_discovery = -1; +module_param(disable_discovery, int, 0); +MODULE_PARM_DESC(disable_discovery, " disable discovery "); + +  /* diag_buffer_enable is bitwise   * bit 0 set = TRACE   * bit 1 set = SNAPSHOT @@ -93,14 +102,6 @@ module_param(diag_buffer_enable, int, 0);  MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "      "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -static int mpt2sas_fwfault_debug; -MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " -    "and halt firmware - (default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); -  /**   * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.   * @@ -691,6 +692,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  		memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);  	}  	ioc->base_cmds.status &= ~MPT2_CMD_PENDING; +  	complete(&ioc->base_cmds.done);  	return 1;  } @@ -3470,6 +3472,58 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  }  /** + * mpt2sas_port_enable_done - command completion routine for port enable + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function. + */ +u8 +mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply) +{ +	MPI2DefaultReply_t *mpi_reply; +	u16 ioc_status; + +	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); +	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) +		return 1; + +	if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) +		return 1; + +	ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; +	if (mpi_reply) { +		ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; +		memcpy(ioc->port_enable_cmds.reply, mpi_reply, +		    mpi_reply->MsgLength*4); +	} +	ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; + +	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) +		ioc->port_enable_failed = 1; + +	if (ioc->is_driver_loading) { +		if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { +			mpt2sas_port_enable_complete(ioc); +			return 1; +		} else { +			ioc->start_scan_failed = ioc_status; +			ioc->start_scan = 0; +			return 1; +		} +	} +	complete(&ioc->port_enable_cmds.done); +	return 1; +} + + +/**   * _base_send_port_enable - send port_enable(discovery stuff) to firmware   * @ioc: per adapter object   * @sleep_flag: CAN_SLEEP or NO_SLEEP @@ -3480,67 +3534,151 @@ static int  _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2PortEnableRequest_t *mpi_request; -	u32 ioc_state; +	Mpi2PortEnableReply_t *mpi_reply;  	unsigned long timeleft;  	int r = 0;  	u16 smid; +	u16 ioc_status;  	printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); -	if (ioc->base_cmds.status & MPT2_CMD_PENDING) { +	if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {  		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",  		    ioc->name, __func__);  		return -EAGAIN;  	} -	smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); +	smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__);  		return -EAGAIN;  	} -	ioc->base_cmds.status = MPT2_CMD_PENDING; +	ioc->port_enable_cmds.status = MPT2_CMD_PENDING;  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -	ioc->base_cmds.smid = smid; +	ioc->port_enable_cmds.smid = smid;  	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));  	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -	mpi_request->VF_ID = 0; /* TODO */ -	mpi_request->VP_ID = 0; +	init_completion(&ioc->port_enable_cmds.done);  	mpt2sas_base_put_smid_default(ioc, smid); -	init_completion(&ioc->base_cmds.done); -	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, +	timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done,  	    300*HZ); -	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { +	if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n",  		    ioc->name, __func__);  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2PortEnableRequest_t)/4); -		if (ioc->base_cmds.status & MPT2_CMD_RESET) +		if (ioc->port_enable_cmds.status & MPT2_CMD_RESET)  			r = -EFAULT;  		else  			r = -ETIME;  		goto out; -	} else -		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", -		    ioc->name, __func__)); +	} +	mpi_reply = ioc->port_enable_cmds.reply; -	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, -	    60, sleep_flag); -	if (ioc_state) { -		printk(MPT2SAS_ERR_FMT "%s: failed going to operational state " -		    " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); +	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +		printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", +		    ioc->name, __func__, ioc_status);  		r = -EFAULT; +		goto out;  	}   out: -	ioc->base_cmds.status = MPT2_CMD_NOT_USED; -	printk(MPT2SAS_INFO_FMT "port enable: %s\n", -	    ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); +	ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; +	printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? +	    "SUCCESS" : "FAILED"));  	return r;  }  /** + * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) +{ +	Mpi2PortEnableRequest_t *mpi_request; +	u16 smid; + +	printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); + +	if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { +		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", +		    ioc->name, __func__); +		return -EAGAIN; +	} + +	smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); +	if (!smid) { +		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", +		    ioc->name, __func__); +		return -EAGAIN; +	} + +	ioc->port_enable_cmds.status = MPT2_CMD_PENDING; +	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); +	ioc->port_enable_cmds.smid = smid; +	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); +	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; + +	mpt2sas_base_put_smid_default(ioc, smid); +	return 0; +} + +/** + * _base_determine_wait_on_discovery - desposition + * @ioc: per adapter object + * + * Decide whether to wait on discovery to complete. Used to either + * locate boot device, or report volumes ahead of physical devices. + * + * Returns 1 for wait, 0 for don't wait + */ +static int +_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) +{ +	/* We wait for discovery to complete if IR firmware is loaded. +	 * The sas topology events arrive before PD events, so we need time to +	 * turn on the bit in ioc->pd_handles to indicate PD +	 * Also, it maybe required to report Volumes ahead of physical +	 * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. +	 */ +	if (ioc->ir_firmware) +		return 1; + +	/* if no Bios, then we don't need to wait */ +	if (!ioc->bios_pg3.BiosVersion) +		return 0; + +	/* Bios is present, then we drop down here. +	 * +	 * If there any entries in the Bios Page 2, then we wait +	 * for discovery to complete. +	 */ + +	/* Current Boot Device */ +	if ((ioc->bios_pg2.CurrentBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && +	/* Request Boot Device */ +	   (ioc->bios_pg2.ReqBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && +	/* Alternate Request Boot Device */ +	   (ioc->bios_pg2.ReqAltBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) +		return 0; + +	return 1; +} + + +/**   * _base_unmask_events - turn on notification for this event   * @ioc: per adapter object   * @event: firmware event @@ -3962,6 +4100,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)   skip_init_reply_post_host_index:  	_base_unmask_interrupts(ioc); +  	r = _base_event_notification(ioc, sleep_flag);  	if (r)  		return r; @@ -3969,7 +4108,18 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	if (sleep_flag == CAN_SLEEP)  		_base_static_config_pages(ioc); -	if (ioc->wait_for_port_enable_to_complete && ioc->is_warpdrive) { + +	if (ioc->is_driver_loading) { + + + +		ioc->wait_for_discovery_to_complete = +		    _base_determine_wait_on_discovery(ioc); +		return r; /* scan_start and scan_finished support */ +	} + + +	if (ioc->wait_for_discovery_to_complete && ioc->is_warpdrive) {  		if (ioc->manu_pg10.OEMIdentifier  == 0x80) {  			hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 &  			    MFG_PAGE10_HIDE_SSDS_MASK); @@ -3978,13 +4128,6 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  		}  	} -	if (ioc->wait_for_port_enable_to_complete) { -		if (diag_buffer_enable != 0) -			mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); -		if (disable_discovery > 0) -			return r; -	} -  	r = _base_send_port_enable(ioc, sleep_flag);  	if (r)  		return r; @@ -4121,6 +4264,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->base_cmds.status = MPT2_CMD_NOT_USED; +	/* port_enable command bits */ +	ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); +	ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; +  	/* transport internal command bits */  	ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->transport_cmds.status = MPT2_CMD_NOT_USED; @@ -4162,8 +4309,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		goto out_free_resources;  	} -	init_completion(&ioc->shost_recovery_done); -  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		ioc->event_masks[i] = -1; @@ -4186,7 +4331,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		_base_update_missing_delay(ioc, missing_delay[0],  		    missing_delay[1]); -	mpt2sas_base_start_watchdog(ioc);  	return 0;   out_free_resources: @@ -4204,6 +4348,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  	kfree(ioc->base_cmds.reply); +	kfree(ioc->port_enable_cmds.reply);  	kfree(ioc->ctl_cmds.reply);  	kfree(ioc->ctl_cmds.sense);  	kfree(ioc->pfacts); @@ -4243,6 +4388,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)  	kfree(ioc->ctl_cmds.reply);  	kfree(ioc->ctl_cmds.sense);  	kfree(ioc->base_cmds.reply); +	kfree(ioc->port_enable_cmds.reply);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply);  	kfree(ioc->scsih_cmds.reply); @@ -4284,6 +4430,20 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  			mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid);  			complete(&ioc->base_cmds.done);  		} +		if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { +			ioc->port_enable_failed = 1; +			ioc->port_enable_cmds.status |= MPT2_CMD_RESET; +			mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); +			if (ioc->is_driver_loading) { +				ioc->start_scan_failed = +				    MPI2_IOCSTATUS_INTERNAL_ERROR; +				ioc->start_scan = 0; +				ioc->port_enable_cmds.status = +						MPT2_CMD_NOT_USED; +			} else +				complete(&ioc->port_enable_cmds.done); + +		}  		if (ioc->config_cmds.status & MPT2_CMD_PENDING) {  			ioc->config_cmds.status |= MPT2_CMD_RESET;  			mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); @@ -4349,7 +4509,6 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  {  	int r;  	unsigned long flags; -	u8 pe_complete = ioc->wait_for_port_enable_to_complete;  	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -4396,7 +4555,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	/* If this hard reset is called while port enable is active, then  	 * there is no reason to call make_ioc_operational  	 */ -	if (pe_complete) { +	if (ioc->is_driver_loading && ioc->port_enable_failed) { +		ioc->remove_host = 1;  		r = -EFAULT;  		goto out;  	} @@ -4410,7 +4570,6 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);  	ioc->ioc_reset_in_progress_status = r;  	ioc->shost_recovery = 0; -	complete(&ioc->shost_recovery_done);  	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);  	mutex_unlock(&ioc->reset_in_progress_mutex);  |