diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
| -rw-r--r-- | drivers/message/fusion/mptsas.c | 211 | 
1 files changed, 206 insertions, 5 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 83873e3d0ce..c20bbe45da8 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1075,6 +1075,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)  	return 0;  } +static void +mptsas_block_io_sdev(struct scsi_device *sdev, void *data) +{ +	scsi_device_set_state(sdev, SDEV_BLOCK); +} + +static void +mptsas_block_io_starget(struct scsi_target *starget) +{ +	if (starget) +		starget_for_each_device(starget, NULL, mptsas_block_io_sdev); +} +  /**   * mptsas_target_reset_queue   * @@ -1098,10 +1111,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,  	id = sas_event_data->TargetID;  	channel = sas_event_data->Bus; -	if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) -		return; - -	vtarget->deleted = 1; /* block IO */ +	vtarget = mptsas_find_vtarget(ioc, channel, id); +	if (vtarget) { +		mptsas_block_io_starget(vtarget->starget); +		vtarget->deleted = 1; /* block IO */ +	}  	target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),  	    GFP_ATOMIC); @@ -1868,7 +1882,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))  	if (ioc->sas_discovery_quiesce_io)  		return SCSI_MLQUEUE_HOST_BUSY; -//	scsi_print_command(SCpnt); +	if (ioc->debug_level & MPT_DEBUG_SCSI) +		scsi_print_command(SCpnt);  	return mptscsih_qcmd(SCpnt,done);  } @@ -2686,6 +2701,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,  	return error;  } +struct rep_manu_request{ +	u8 smp_frame_type; +	u8 function; +	u8 reserved; +	u8 request_length; +}; + +struct rep_manu_reply{ +	u8 smp_frame_type; /* 0x41 */ +	u8 function; /* 0x01 */ +	u8 function_result; +	u8 response_length; +	u16 expander_change_count; +	u8 reserved0[2]; +	u8 sas_format:1; +	u8 reserved1:7; +	u8 reserved2[3]; +	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; +	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; +	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; +	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; +	u16 component_id; +	u8 component_revision_id; +	u8 reserved3; +	u8 vendor_specific[8]; +}; + +/** +  * mptsas_exp_repmanufacture_info - +  * @ioc: per adapter object +  * @sas_address: expander sas address +  * @edev: the sas_expander_device object +  * +  * Fills in the sas_expander_device object when SMP port is created. +  * +  * Returns 0 for success, non-zero for failure. +  */ +static int +mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, +	u64 sas_address, struct sas_expander_device *edev) +{ +	MPT_FRAME_HDR *mf; +	SmpPassthroughRequest_t *smpreq; +	SmpPassthroughReply_t *smprep; +	struct rep_manu_reply *manufacture_reply; +	struct rep_manu_request *manufacture_request; +	int ret; +	int flagsLength; +	unsigned long timeleft; +	char *psge; +	unsigned long flags; +	void *data_out = NULL; +	dma_addr_t data_out_dma = 0; +	u32 sz; + +	spin_lock_irqsave(&ioc->taskmgmt_lock, flags); +	if (ioc->ioc_reset_in_progress) { +		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +		printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", +			__func__, ioc->name); +		return -EFAULT; +	} +	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +	ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); +	if (ret) +		goto out; + +	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); +	if (!mf) { +		ret = -ENOMEM; +		goto out_unlock; +	} + +	smpreq = (SmpPassthroughRequest_t *)mf; +	memset(smpreq, 0, sizeof(*smpreq)); + +	sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + +	data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); +	if (!data_out) { +		printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", +			__FILE__, __LINE__, __func__); +		ret = -ENOMEM; +		goto put_mf; +	} + +	manufacture_request = data_out; +	manufacture_request->smp_frame_type = 0x40; +	manufacture_request->function = 1; +	manufacture_request->reserved = 0; +	manufacture_request->request_length = 0; + +	smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; +	smpreq->PhysicalPort = 0xFF; +	*((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); +	smpreq->RequestDataLength = sizeof(struct rep_manu_request); + +	psge = (char *) +		(((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); + +	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | +		MPI_SGE_FLAGS_SYSTEM_ADDRESS | +		MPI_SGE_FLAGS_HOST_TO_IOC | +		MPI_SGE_FLAGS_END_OF_BUFFER; +	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; +	flagsLength |= sizeof(struct rep_manu_request); + +	ioc->add_sge(psge, flagsLength, data_out_dma); +	psge += ioc->SGE_size; + +	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | +		MPI_SGE_FLAGS_SYSTEM_ADDRESS | +		MPI_SGE_FLAGS_IOC_TO_HOST | +		MPI_SGE_FLAGS_END_OF_BUFFER; +	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; +	flagsLength |= sizeof(struct rep_manu_reply); +	ioc->add_sge(psge, flagsLength, data_out_dma + +	sizeof(struct rep_manu_request)); + +	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) +	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); + +	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); +	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { +		ret = -ETIME; +		mpt_free_msg_frame(ioc, mf); +		mf = NULL; +		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) +			goto out_free; +		if (!timeleft) +			mpt_HardResetHandler(ioc, CAN_SLEEP); +		goto out_free; +	} + +	mf = NULL; + +	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { +		u8 *tmp; + +	smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; +	if (le16_to_cpu(smprep->ResponseDataLength) != +		sizeof(struct rep_manu_reply)) +			goto out_free; + +	manufacture_reply = data_out + sizeof(struct rep_manu_request); +	strncpy(edev->vendor_id, manufacture_reply->vendor_id, +		SAS_EXPANDER_VENDOR_ID_LEN); +	strncpy(edev->product_id, manufacture_reply->product_id, +		SAS_EXPANDER_PRODUCT_ID_LEN); +	strncpy(edev->product_rev, manufacture_reply->product_rev, +		SAS_EXPANDER_PRODUCT_REV_LEN); +	edev->level = manufacture_reply->sas_format; +	if (manufacture_reply->sas_format) { +		strncpy(edev->component_vendor_id, +			manufacture_reply->component_vendor_id, +				SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); +		tmp = (u8 *)&manufacture_reply->component_id; +		edev->component_id = tmp[0] << 8 | tmp[1]; +		edev->component_revision_id = +			manufacture_reply->component_revision_id; +		} +	} else { +		printk(MYIOC_s_ERR_FMT +			"%s: smp passthru reply failed to be returned\n", +			ioc->name, __func__); +		ret = -ENXIO; +	} +out_free: +	if (data_out_dma) +		pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); +put_mf: +	if (mf) +		mpt_free_msg_frame(ioc, mf); +out_unlock: +	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) +	mutex_unlock(&ioc->sas_mgmt.mutex); +out: +	return ret; + } +  static void  mptsas_parse_device_info(struct sas_identify *identify,  		struct mptsas_devinfo *device_info) @@ -2967,6 +3163,11 @@ static int mptsas_probe_one_phy(struct device *dev,  			goto out;  		}  		mptsas_set_rphy(ioc, phy_info, rphy); +		if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || +			identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) +				mptsas_exp_repmanufacture_info(ioc, +					identify.sas_address, +					rphy_to_expander_device(rphy));  	}   out:  | 
