diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_ctl.c')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 411 | 
1 files changed, 353 insertions, 58 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index d88e9756d8f..b774973f076 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -80,6 +80,32 @@ enum block_state {  	BLOCKING,  }; +/** + * _ctl_sas_device_find_by_handle - sas device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for sas_device based on sas_address, then return sas_device + * object. + */ +static struct _sas_device * +_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	struct _sas_device *sas_device, *r; + +	r = NULL; +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) { +		if (sas_device->handle != handle) +			continue; +		r = sas_device; +		goto out; +	} + + out: +	return r; +} +  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  /**   * _ctl_display_some_debug - debug routine @@ -188,14 +214,14 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,  	if (!desc)  		return; -	printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n", +	printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n",  	    ioc->name, calling_function_name, desc, smid);  	if (!mpi_reply)  		return;  	if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) -		printk(MPT2SAS_DEBUG_FMT +		printk(MPT2SAS_INFO_FMT  		    "\tiocstatus(0x%04x), loginfo(0x%08x)\n",  		    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),  		    le32_to_cpu(mpi_reply->IOCLogInfo)); @@ -205,8 +231,24 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,  	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {  		Mpi2SCSIIOReply_t *scsi_reply =  		    (Mpi2SCSIIOReply_t *)mpi_reply; +		struct _sas_device *sas_device = NULL; +		unsigned long flags; + +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _ctl_sas_device_find_by_handle(ioc, +		    le16_to_cpu(scsi_reply->DevHandle)); +		if (sas_device) { +			printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " +			    "phy(%d)\n", ioc->name, (unsigned long long) +			    sas_device->sas_address, sas_device->phy); +			printk(MPT2SAS_WARN_FMT +			    "\tenclosure_logical_id(0x%016llx), slot(%d)\n", +			    ioc->name, sas_device->enclosure_logical_id, +			    sas_device->slot); +		} +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) -			printk(MPT2SAS_DEBUG_FMT +			printk(MPT2SAS_INFO_FMT  			    "\tscsi_state(0x%02x), scsi_status"  			    "(0x%02x)\n", ioc->name,  			    scsi_reply->SCSIState, @@ -233,6 +275,9 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  	u32 reply)  {  	MPI2DefaultReply_t *mpi_reply; +	Mpi2SCSIIOReply_t *scsiio_reply; +	const void *sense_data; +	u32 sz;  	if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)  		return 1; @@ -243,6 +288,20 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  	if (mpi_reply) {  		memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);  		ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; +		/* get sense data */ +		if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || +		    mpi_reply->Function == +		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { +			scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; +			if (scsiio_reply->SCSIState & +			    MPI2_SCSI_STATE_AUTOSENSE_VALID) { +				sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, +				    le32_to_cpu(scsiio_reply->SenseCount)); +				sense_data = mpt2sas_base_get_sense_buffer(ioc, +				    smid); +				memcpy(ioc->ctl_cmds.sense, sense_data, sz); +			} +		}  	}  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); @@ -392,7 +451,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  	switch (reset_phase) {  	case MPT2_IOC_PRE_RESET: -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));  		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {  			if (!(ioc->diag_buffer_status[i] & @@ -405,7 +464,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		}  		break;  	case MPT2_IOC_AFTER_RESET: -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));  		if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {  			ioc->ctl_cmds.status |= MPT2_CMD_RESET; @@ -414,7 +473,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		}  		break;  	case MPT2_IOC_DONE_RESET: -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));  		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { @@ -531,7 +590,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);  	if (!found) { -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,  		    desc, le16_to_cpu(tm_request->DevHandle), lun));  		tm_reply = ioc->ctl_cmds.reply; @@ -549,7 +608,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  		return 1;  	} -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,  	    desc, le16_to_cpu(tm_request->DevHandle), lun,  	     le16_to_cpu(tm_request->TaskMID))); @@ -567,7 +626,7 @@ static long  _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,      struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)  { -	MPI2RequestHeader_t *mpi_request; +	MPI2RequestHeader_t *mpi_request = NULL, *request;  	MPI2DefaultReply_t *mpi_reply;  	u32 ioc_state;  	u16 ioc_status; @@ -576,7 +635,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	u8 issue_reset;  	u32 sz;  	void *psge; -	void *priv_sense = NULL;  	void *data_out = NULL;  	dma_addr_t data_out_dma;  	size_t data_out_sz = 0; @@ -621,31 +679,50 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",  		    ioc->name, __func__); -	smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); -	if (!smid) { -		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", -		    ioc->name, __func__); -		ret = -EAGAIN; +	mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); +	if (!mpi_request) { +		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " +		    "mpi_request\n", ioc->name, __func__); +		ret = -ENOMEM;  		goto out;  	} -	ret = 0; -	ioc->ctl_cmds.status = MPT2_CMD_PENDING; -	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -	ioc->ctl_cmds.smid = smid; -	data_out_sz = karg.data_out_size; -	data_in_sz = karg.data_in_size; -  	/* copy in request message frame from user */  	if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {  		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,  		    __func__);  		ret = -EFAULT; -		mpt2sas_base_free_smid(ioc, smid);  		goto out;  	} +	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { +		smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); +		if (!smid) { +			printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", +			    ioc->name, __func__); +			ret = -EAGAIN; +			goto out; +		} +	} else { + +		smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); +		if (!smid) { +			printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", +			    ioc->name, __func__); +			ret = -EAGAIN; +			goto out; +		} +	} + +	ret = 0; +	ioc->ctl_cmds.status = MPT2_CMD_PENDING; +	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); +	request = mpt2sas_base_get_msg_frame(ioc, smid); +	memcpy(request, mpi_request, karg.data_sge_offset*4); +	ioc->ctl_cmds.smid = smid; +	data_out_sz = karg.data_out_size; +	data_in_sz = karg.data_in_size; +  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||  	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {  		if (!le16_to_cpu(mpi_request->FunctionDependent1) || @@ -691,7 +768,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	}  	/* add scatter gather elements */ -	psge = (void *)mpi_request + (karg.data_sge_offset*4); +	psge = (void *)request + (karg.data_sge_offset*4);  	if (!data_out_sz && !data_in_sz) {  		mpt2sas_base_build_zero_len_sge(ioc, psge); @@ -739,11 +816,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:  	{  		Mpi2SCSIIORequest_t *scsiio_request = -		    (Mpi2SCSIIORequest_t *)mpi_request; +		    (Mpi2SCSIIORequest_t *)request; +		scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;  		scsiio_request->SenseBufferLowAddress =  		    mpt2sas_base_get_sense_buffer_dma(ioc, smid); -		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); -		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); +		memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);  		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)  			mpt2sas_base_put_smid_scsi_io(ioc, smid,  			    le16_to_cpu(mpi_request->FunctionDependent1)); @@ -754,9 +831,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	case MPI2_FUNCTION_SCSI_TASK_MGMT:  	{  		Mpi2SCSITaskManagementRequest_t *tm_request = -		    (Mpi2SCSITaskManagementRequest_t *)mpi_request; +		    (Mpi2SCSITaskManagementRequest_t *)request; -		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " +		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: "  		    "handle(0x%04x), task_type(0x%02x)\n", ioc->name,  		    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); @@ -851,7 +928,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		Mpi2SCSITaskManagementReply_t *tm_reply =  		    (Mpi2SCSITaskManagementReply_t *)mpi_reply; -		printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " +		printk(MPT2SAS_INFO_FMT "TASK_MGMT: "  		    "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "  		    "TerminationCount(0x%08x)\n", ioc->name,  		    le16_to_cpu(tm_reply->IOCStatus), @@ -887,7 +964,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	    MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==  	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {  		sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); -		if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) { +		if (copy_to_user(karg.sense_data_ptr, +			ioc->ctl_cmds.sense, sz)) {  			printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,  			    __LINE__, __func__);  			ret = -ENODATA; @@ -926,6 +1004,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		pci_free_consistent(ioc->pdev, data_out_sz, data_out,  		    data_out_dma); +	kfree(mpi_request);  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;  	mutex_unlock(&ioc->ctl_cmds.mutex);  	return ret; @@ -950,7 +1029,7 @@ _ctl_getiocinfo(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	memset(&karg, 0 , sizeof(karg)); @@ -998,7 +1077,7 @@ _ctl_eventquery(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; @@ -1031,7 +1110,7 @@ _ctl_eventenable(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	if (ioc->event_log) @@ -1073,7 +1152,7 @@ _ctl_eventreport(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	number_bytes = karg.hdr.max_data_size - @@ -1118,7 +1197,7 @@ _ctl_do_reset(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -1219,7 +1298,7 @@ _ctl_btdh_mapping(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	rc = _ctl_btdh_search_sas_device(ioc, &karg); @@ -1288,7 +1367,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  	u16 ioc_status;  	u8 issue_reset = 0; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { @@ -1376,7 +1455,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  	mpi_request->VF_ID = 0; /* TODO */  	mpi_request->VP_ID = 0; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), "  	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,  	    (unsigned long long)request_data_dma,  	    le32_to_cpu(mpi_request->BufferLength))); @@ -1414,10 +1493,10 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {  		ioc->diag_buffer_status[buffer_type] |=  			MPT2_DIAG_BUFFER_IS_REGISTERED; -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",  		    ioc->name, __func__));  	} else { -		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " +		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "  		    "log_info(0x%08x)\n", ioc->name, __func__,  		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));  		rc = -EFAULT; @@ -1541,7 +1620,7 @@ _ctl_diag_unregister(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	buffer_type = karg.unique_id & 0x000000ff; @@ -1611,7 +1690,7 @@ _ctl_diag_query(void __user *arg)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	karg.application_flags = 0; @@ -1689,7 +1768,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  	int rc;  	unsigned long timeleft; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	rc = 0; @@ -1697,7 +1776,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);  	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "skipping due to FAULT state\n", ioc->name,  		    __func__));  		rc = -EAGAIN; @@ -1759,10 +1838,10 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {  		ioc->diag_buffer_status[buffer_type] |=  		    MPT2_DIAG_BUFFER_IS_RELEASED; -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",  		    ioc->name, __func__));  	} else { -		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " +		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "  		    "log_info(0x%08x)\n", ioc->name, __func__,  		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));  		rc = -EFAULT; @@ -1800,7 +1879,7 @@ _ctl_diag_release(void __user *arg, enum block_state state)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	buffer_type = karg.unique_id & 0x000000ff; @@ -1896,7 +1975,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__));  	buffer_type = karg.unique_id & 0x000000ff; @@ -1927,7 +2006,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	}  	diag_data = (void *)(request_data + karg.starting_offset); -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), " +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "  	    "offset(%d), sz(%d)\n", ioc->name, __func__,  	    diag_data, karg.starting_offset, karg.bytes_to_read)); @@ -1942,11 +2021,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)  		return 0; -	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister " +	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister "  		"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));  	if ((ioc->diag_buffer_status[buffer_type] &  	    MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "  		    "buffer_type(0x%02x) is still registered\n", ioc->name,  		     __func__, buffer_type));  		return 0; @@ -2020,10 +2099,10 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {  		ioc->diag_buffer_status[buffer_type] |=  		    MPT2_DIAG_BUFFER_IS_REGISTERED; -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",  		    ioc->name, __func__));  	} else { -		printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " +		printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "  		    "log_info(0x%08x)\n", ioc->name, __func__,  		    ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));  		rc = -EFAULT; @@ -2077,7 +2156,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)  		    !ioc)  			return -ENODEV; -		if (ioc->shost_recovery) +		if (ioc->shost_recovery || ioc->pci_error_recovery)  			return -EAGAIN;  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { @@ -2140,7 +2219,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)  		    !ioc)  			return -ENODEV; -		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT +		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT  		    "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));  		break;  	} @@ -2196,7 +2275,7 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)  	if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)  		return -ENODEV; -	if (ioc->shost_recovery) +	if (ioc->shost_recovery || ioc->pci_error_recovery)  		return -EAGAIN;  	memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); @@ -2581,6 +2660,218 @@ _ctl_fwfault_debug_store(struct device *cdev,  static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,      _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); + +/** + * _ctl_ioc_reset_count_show - ioc reset count + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is firmware queue depth limit + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, +    char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); +} +static DEVICE_ATTR(ioc_reset_count, S_IRUGO, +    _ctl_ioc_reset_count_show, NULL); + +struct DIAG_BUFFER_START { +	u32 Size; +	u32 DiagVersion; +	u8 BufferType; +	u8 Reserved[3]; +	u32 Reserved1; +	u32 Reserved2; +	u32 Reserved3; +}; +/** + * _ctl_host_trace_buffer_size_show - host buffer size (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_host_trace_buffer_size_show(struct device *cdev, +    struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	u32 size = 0; +	struct DIAG_BUFFER_START *request_data; + +	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { +		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " +		    "registered\n", ioc->name, __func__); +		return 0; +	} + +	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { +		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " +		    "registered\n", ioc->name, __func__); +		return 0; +	} + +	request_data = (struct DIAG_BUFFER_START *) +	    ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; +	if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || +	    le32_to_cpu(request_data->DiagVersion) == 0x01000000) && +	    le32_to_cpu(request_data->Reserved3) == 0x4742444c) +		size = le32_to_cpu(request_data->Size); + +	ioc->ring_buffer_sz = size; +	return snprintf(buf, PAGE_SIZE, "%d\n", size); +} +static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, +	 _ctl_host_trace_buffer_size_show, NULL); + +/** + * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * You will only be able to read 4k bytes of ring buffer at a time. + * In order to read beyond 4k bytes, you will have to write out the + * offset to the same attribute, it will move the pointer. + */ +static ssize_t +_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, +     char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	void *request_data; +	u32 size; + +	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { +		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " +		    "registered\n", ioc->name, __func__); +		return 0; +	} + +	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { +		printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " +		    "registered\n", ioc->name, __func__); +		return 0; +	} + +	if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) +		return 0; + +	size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; +	size = (size > PAGE_SIZE) ? PAGE_SIZE : size; +	request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; +	memcpy(buf, request_data, size); +	return size; +} + +static ssize_t +_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, +    const char *buf, size_t count) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	int val = 0; + +	if (sscanf(buf, "%d", &val) != 1) +		return -EINVAL; + +	ioc->ring_buffer_offset = val; +	return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, +    _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); + +/*****************************************/ + +/** + * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * This is a mechnism to post/release host_trace_buffers + */ +static ssize_t +_ctl_host_trace_buffer_enable_show(struct device *cdev, +    struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || +	   ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +	    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) +		return snprintf(buf, PAGE_SIZE, "off\n"); +	else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +	    MPT2_DIAG_BUFFER_IS_RELEASED)) +		return snprintf(buf, PAGE_SIZE, "release\n"); +	else +		return snprintf(buf, PAGE_SIZE, "post\n"); +} + +static ssize_t +_ctl_host_trace_buffer_enable_store(struct device *cdev, +    struct device_attribute *attr, const char *buf, size_t count) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	char str[10] = ""; +	struct mpt2_diag_register diag_register; +	u8 issue_reset = 0; + +	if (sscanf(buf, "%s", str) != 1) +		return -EINVAL; + +	if (!strcmp(str, "post")) { +		/* exit out if host buffers are already posted */ +		if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && +		    (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +		    MPT2_DIAG_BUFFER_IS_REGISTERED) && +		    ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +		    MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) +			goto out; +		memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); +		printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", +		    ioc->name); +		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; +		diag_register.requested_buffer_size = (1024 * 1024); +		diag_register.unique_id = 0x7075900; +		ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; +		_ctl_diag_register_2(ioc,  &diag_register); +	} else if (!strcmp(str, "release")) { +		/* exit out if host buffers are already released */ +		if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) +			goto out; +		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +		    MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) +			goto out; +		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & +		    MPT2_DIAG_BUFFER_IS_RELEASED)) +			goto out; +		printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", +		    ioc->name); +		_ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); +	} + + out: +	return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, +    _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); +  struct device_attribute *mpt2sas_host_attrs[] = {  	&dev_attr_version_fw,  	&dev_attr_version_bios, @@ -2597,6 +2888,10 @@ struct device_attribute *mpt2sas_host_attrs[] = {  	&dev_attr_fwfault_debug,  	&dev_attr_fw_queue_depth,  	&dev_attr_host_sas_address, +	&dev_attr_ioc_reset_count, +	&dev_attr_host_trace_buffer_size, +	&dev_attr_host_trace_buffer, +	&dev_attr_host_trace_buffer_enable,  	NULL,  };  |