Re: [PATCH 2/6] mpt fusion: Firmware Event implementation using seperate WorkQueue

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2009-04-03 at 17:20 +0530, Kashyap, Desai wrote:
> 1) 	Now Firmware events are handled by firmware event queue.
> 	Previously it was handled in interrupt context/WorkQueue of Linux.
> 	Firmware Event handling is restructured and optimized.
> 2.)	Test Unit Ready will be used by driver to make sure device is
> 	already come up before indicating Device Add to Scsi subsystem.
> ---
> 
> Signed-off-by: Kashyap Desai <kashyap.desai@xxxxxxx>
> ---
> diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
> index 3418e83..14a9d4f 100644
> --- a/drivers/message/fusion/mptbase.c
> +++ b/drivers/message/fusion/mptbase.c
> @@ -1928,6 +1928,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
>  	 */
>  	mpt_detect_bound_ports(ioc, pdev);
>  
> +	INIT_LIST_HEAD(&ioc->fw_event_list);
> +	spin_lock_init(&ioc->fw_event_lock);
> +	snprintf(ioc->fw_event_q_name, 20, "mpt/%d", ioc->id);
> +	ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
> +
>  	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
>  	    CAN_SLEEP)) != 0){
>  		printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
> @@ -2007,6 +2012,11 @@ mpt_detach(struct pci_dev *pdev)
>  	cancel_delayed_work(&ioc->fault_reset_work);
>  	destroy_workqueue(wq);
>  
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	wq = ioc->fw_event_q;
> +	ioc->fw_event_q = NULL;
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +	destroy_workqueue(wq);
>  
>  	sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
>  	remove_proc_entry(pname, NULL);
> diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
> index 24d6012..a2e948b 100644
> --- a/drivers/message/fusion/mptbase.h
> +++ b/drivers/message/fusion/mptbase.h
> @@ -694,9 +694,19 @@ typedef struct _MPT_ADAPTER
>  	struct net_device	*netdev;
>  	struct list_head	 sas_topology;
>  	struct mutex		 sas_topology_mutex;
> +	u8			 disable_hotplug_remove;
> +
> +	struct workqueue_struct	*fw_event_q;
> +	struct list_head	 fw_event_list;
> +	spinlock_t		 fw_event_lock;
> +	u8			 fw_events_off; /* if '1', then ignore events */
> +	char 			 fw_event_q_name[20];
> +
>  	struct mutex		 sas_discovery_mutex;
>  	u8			 sas_discovery_runtime;
>  	u8			 sas_discovery_ignore_events;
> +	struct list_head	 sas_device_info_list;
> +	struct semaphore	 sas_device_info_mutex;

As you say, this is a mutex ... it should use mutex primitives, not
semaphore ones.

>  	u8			 sas_discovery_quiesce_io;
>  	int			 sas_index; /* index refrencing */
>  	MPT_MGMT		 sas_mgmt;
> diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
> index 4e90870..5b357ce 100644
> --- a/drivers/message/fusion/mptsas.c
> +++ b/drivers/message/fusion/mptsas.c
> @@ -95,7 +95,25 @@ static u8	mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for interna
>  static u8	mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
>  static u8	mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
>  
> -static void mptsas_hotplug_work(struct work_struct *work);
> +static void mptsas_firmware_event_work(struct work_struct *work);
> +static int mptsas_get_lun_number(MPT_ADAPTER *ioc, u8 channel, u8 id, int *lun);
> +static void mptsas_send_sas_event(struct fw_event_work *fw_event);
> +static void mptsas_send_raid_event(struct fw_event_work *fw_event);
> +static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
> +static void mptsas_parse_device_info(struct sas_identify *identify,
> +		struct mptsas_devinfo *device_info);
> +static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
> +    		struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
> +static struct mptsas_phyinfo	*mptsas_find_phyinfo_by_sas_address
> +		(MPT_ADAPTER *ioc, u64 sas_address);
> +static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
> +	struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
> +static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
> +	struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
> +static int mptsas_add_end_device(MPT_ADAPTER *ioc,
> +	struct mptsas_phyinfo *phy_info);
> +static void mptsas_del_end_device(MPT_ADAPTER *ioc,
> +	struct mptsas_phyinfo *phy_info);
>  
>  static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
>  					MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
> @@ -219,6 +237,116 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
>  	    le16_to_cpu(pg1->AttachedDevHandle)));
>  }
>  
> +/* inhibit sas firmware event handling */
> +static void
> +mptsas_fw_event_off(MPT_ADAPTER *ioc)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	ioc->fw_events_off = 1;
> +	ioc->sas_discovery_quiesce_io = 0;
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +
> +}
> +
> +/* enable sas firmware event handling */
> +static void
> +mptsas_fw_event_on(MPT_ADAPTER *ioc)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	ioc->fw_events_off = 0;
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +}
> +
> +/* queue a sas firmware event */
> +static void
> +mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
> +    unsigned long delay)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	list_add_tail(&fw_event->list, &ioc->fw_event_list);
> +	INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
> +	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
> +	    ioc->name, __func__, fw_event));
> +	queue_delayed_work(ioc->fw_event_q, &fw_event->work,
> +	    delay);
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +}
> +
> +/* requeue a sas firmware event */
> +static void
> +mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
> +    unsigned long delay)
> +{
> +	unsigned long flags;
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
> +	    "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
> +	fw_event->retries++;
> +	queue_delayed_work(ioc->fw_event_q, &fw_event->work,
> +	    msecs_to_jiffies(delay));
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +}
> +
> +
> +/* free memory assoicated to a sas firmware event */
> +static void
> +mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ioc->fw_event_lock, flags);
> +	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
> +	    ioc->name, __func__, fw_event));
> +	list_del(&fw_event->list);
> +	kfree(fw_event);
> +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
> +}
> +
> +/* walk the firmware event queue, and either stop or wait for
> + * outstanding events to complete */
> +static void
> +mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
> +{
> +	struct fw_event_work *fw_event, *next;
> +	struct mptsas_target_reset_event *target_reset_list, *n;
> +	u8	flush_q;
> +	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
> +
> +	/* flush the target_reset_list */
> +	if (!list_empty(&hd->target_reset_list)) {
> +		list_for_each_entry_safe(target_reset_list, n,
> +		    &hd->target_reset_list, list) {

What protects this list while you're traversing it?

> +			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
> +			    "%s: removing target reset for id=%d\n",
> +			    ioc->name, __func__,
> +			   target_reset_list->sas_event_data.TargetID));
> +			list_del(&target_reset_list->list);
> +			kfree(target_reset_list);
> +		}
> +	}
> +
> +	if (list_empty(&ioc->fw_event_list) ||
> +	     !ioc->fw_event_q || in_interrupt())
> +		return;
> +
> +	flush_q = 0;
> +	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {

You go to a lot of trouble protecting the fw_event_list with the
fw_event_lock, shouldn't you be using it here to protect the list
iterator?

> +		if (cancel_delayed_work(&fw_event->work))
> +			mptsas_free_fw_event(ioc, fw_event);
> +		else
> +			flush_q = 1;
> +	}
> +	if (flush_q)
> +		flush_workqueue(ioc->fw_event_q);
> +}
> +
> +
>  static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
>  {
>  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
> @@ -309,6 +437,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
>  		if(phy_info->port_details != port_details)
>  			continue;
>  		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
> +		mptsas_set_rphy(ioc, phy_info, NULL);
>  		phy_info->port_details = NULL;
>  	}
>  	kfree(port_details);
> @@ -380,6 +509,158 @@ starget)
>  		phy_info->port_details->starget = starget;
>  }
>  
> +/**
> + *	mptsas_add_device_component -
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@channel: fw mapped id's
> + *	@id:
> + *	@sas_address:
> + *	@device_info:
> + *
> + **/
> +static void
> +mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
> +	u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
> +{
> +	struct sas_device_info	*sas_info, *next;
> +	struct scsi_device	*sdev;
> +	struct scsi_target	*starget;
> +	struct sas_rphy		*rphy;
> +
> +	/*
> +	 * Delete all matching devices out of the list
> +	 */
> +	down(&ioc->sas_device_info_mutex);

Obviously, when this becomes a mutex, these all become mutex_lock and
mutex_unlock.

> +	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
> +	    list) {
> +		if (!sas_info->is_logical_volume &&
> +			(sas_info->sas_address == sas_address ||
> +			(sas_info->fw.channel == channel &&
> +			sas_info->fw.id == id))) {
> +			list_del(&sas_info->list);
> +			kfree(sas_info);
> +		}
> +	}
> +
> +	sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL);
> +	if (!sas_info)
> +		goto out;
> +
> +	/*
> +	 * Set Firmware mapping
> +	 */
> +	sas_info->fw.id = id;
> +	sas_info->fw.channel = channel;
> +
> +	sas_info->sas_address = sas_address;
> +	sas_info->device_info = device_info;
> +	sas_info->slot = slot;
> +	sas_info->enclosure_logical_id = enclosure_logical_id;
> +	INIT_LIST_HEAD(&sas_info->list);
> +	list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
> +
> +	/*
> +	 * Set OS mapping
> +	 */
> +	shost_for_each_device(sdev, ioc->sh) {
> +		starget = scsi_target(sdev);
> +		rphy = dev_to_rphy(starget->dev.parent);
> +		if (rphy->identify.sas_address == sas_address) {
> +			sas_info->os.id = starget->id;
> +			sas_info->os.channel = starget->channel;
> +		}
> +	}
> +
> + out:
> +	up(&ioc->sas_device_info_mutex);
> +	return;
> +}
> +
> +/**
> + *	mptsas_add_device_component_by_fw -
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@channel:  fw mapped id's
> + *	@id:
> + *
> + **/
> +static void
> +mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
> +{
> +	struct mptsas_devinfo sas_device;
> +	struct mptsas_enclosure enclosure_info;
> +	int rc;
> +
> +	rc = mptsas_sas_device_pg0(ioc, &sas_device,
> +	    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
> +	     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
> +	    (channel << 8) + id);
> +	if (rc)
> +		return;
> +
> +	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
> +	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
> +	    (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
> +	     MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
> +	     sas_device.handle_enclosure);
> +
> +	mptsas_add_device_component(ioc, sas_device.channel,
> +	    sas_device.id, sas_device.sas_address, sas_device.device_info,
> +	    sas_device.slot, enclosure_info.enclosure_logical_id);
> +}
> +
> +/**
> + *	mptsas_add_device_component_starget -
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@starget:
> + *
> + **/
> +static void
> +mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
> +	struct scsi_target *starget)
> +{
> +	VirtTarget	*vtarget;
> +	struct sas_rphy	*rphy;
> +	struct mptsas_phyinfo	*phy_info = NULL;
> +	struct mptsas_enclosure	enclosure_info;
> +
> +	rphy = dev_to_rphy(starget->dev.parent);
> +	vtarget = starget->hostdata;
> +	phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
> +			rphy->identify.sas_address);
> +	if (!phy_info)
> +		return;
> +
> +	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
> +	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
> +		(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
> +		MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
> +		phy_info->attached.handle_enclosure);
> +
> +	mptsas_add_device_component(ioc, phy_info->attached.channel,
> +		phy_info->attached.id, phy_info->attached.sas_address,
> +		phy_info->attached.device_info,
> +		phy_info->attached.slot, enclosure_info.enclosure_logical_id);
> +}
> +
> +/**
> + *	mptsas_del_device_components - Cleaning the list
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *
> + **/
> +static void
> +mptsas_del_device_components(MPT_ADAPTER *ioc)
> +{
> +	struct sas_device_info	*sas_info, *next;
> +
> +	down(&ioc->sas_device_info_mutex);
> +	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
> +		list) {
> +		list_del(&sas_info->list);
> +		kfree(sas_info);
> +	}
> +	up(&ioc->sas_device_info_mutex);
> +}
> +
>  
>  /*
>   * mptsas_setup_wide_ports
> @@ -535,6 +816,29 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
>  	return vtarget;
>  }
>  
> +static void
> +mptsas_queue_device_delete(MPT_ADAPTER *ioc,
> +	MpiEventDataSasDeviceStatusChange_t *sas_event_data)
> +{
> +	struct fw_event_work *fw_event;
> +	int sz;
> +
> +	sz = offsetof(struct fw_event_work, event_data) +
> +	    sizeof(MpiEventDataSasDeviceStatusChange_t);
> +	fw_event = kzalloc(sz, GFP_ATOMIC);
> +	if (!fw_event) {
> +		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
> +		    ioc->name, __func__, __LINE__);
> +		return;
> +	}
> +	memcpy(fw_event->event_data, sas_event_data,
> +	    sizeof(MpiEventDataSasDeviceStatusChange_t));
> +	fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
> +	fw_event->ioc = ioc;
> +	mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
> +}
> +
> +
>  /**
>   * mptsas_target_reset
>   *
> @@ -653,10 +957,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
>  {
>  	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
>          struct list_head *head = &hd->target_reset_list;
> -	struct mptsas_hotplug_event *ev;
>  	EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
>  	u8		id, channel;
> -	__le64		sas_address;
>  	struct mptsas_target_reset_event	*target_reset_list;
>  	SCSITaskMgmtReply_t *pScsiTmReply;
>  
> @@ -728,41 +1030,9 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
>  	 * enable work queue to remove device from upper layers
>  	 */
>  	list_del(&target_reset_list->list);
> -
> -	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
> -	if (!ev) {
> -		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
> -		    ioc->name,__func__, __LINE__));
> -		goto out_fail;
> -	}
> -
> -	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
> -		ioc->name, mf));
> -
> -	INIT_WORK(&ev->work, mptsas_hotplug_work);
> -	ev->ioc = ioc;
> -	ev->handle = le16_to_cpu(sas_event_data->DevHandle);
> -	ev->parent_handle =
> -	    le16_to_cpu(sas_event_data->ParentDevHandle);
> -	ev->channel = channel;
> -	ev->id =id;
> -	ev->phy_id = sas_event_data->PhyNum;
> -	memcpy(&sas_address, &sas_event_data->SASAddress,
> -	    sizeof(__le64));
> -	ev->sas_address = le64_to_cpu(sas_address);
> -	ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
> -	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
> -	   "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
> -	   ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
> -
> -	ev->event_type = MPTSAS_DEL_DEVICE;
> -	schedule_work(&ev->work);
> -	kfree(target_reset_list);
> -
> - out_fail:
> -
> -	mpt_clear_taskmgmt_in_progress_flag(ioc);
> -	return 0;
> +	if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
> +		mptsas_queue_device_delete(ioc,
> +			&target_reset_list->sas_event_data);
>  
> 
>  	/*
> @@ -797,37 +1067,191 @@ static int
>  mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
>  {
>  	MPT_SCSI_HOST	*hd;
> -	struct mptsas_target_reset_event *target_reset_list, *n;
>  	int rc;
>  
>  	rc = mptscsih_ioc_reset(ioc, reset_phase);
> +	if ((ioc->bus_type != SAS) || (!rc))

This is well over braced.

> +		return rc;
> -	if (ioc->bus_type != SAS)
> -		goto out;
> -
> -	if (reset_phase != MPT_IOC_POST_RESET)
> -		goto out;
> -
> -	if (!ioc->sh || !ioc->sh->hostdata)
> -		goto out;
>  	hd = shost_priv(ioc->sh);
>  	if (!hd->ioc)
>  		goto out;
>  
> -	if (list_empty(&hd->target_reset_list))
> -		goto out;
> -
> -	/* flush the target_reset_list */
> -	list_for_each_entry_safe(target_reset_list, n,
> -	    &hd->target_reset_list, list) {
> -		list_del(&target_reset_list->list);
> -		kfree(target_reset_list);
> +	switch (reset_phase) {
> +	case MPT_IOC_SETUP_RESET:
> +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
> +		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
> +		mptsas_fw_event_off(ioc);
> +		break;
> +	case MPT_IOC_PRE_RESET:
> +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
> +		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
> +		break;
> +	case MPT_IOC_POST_RESET:
> +		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
> +		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
> +		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
> +			ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
> +			complete(&ioc->sas_mgmt.done);
> +		}
> +		mptsas_cleanup_fw_event_q(ioc);
> +		mptsas_fw_event_on(ioc);
> +		break;
> +	default:
> +		break;
>  	}
>  
>   out:
>  	return rc;
>  }
>  
> +
> +/**
> + * enum device_state -
> + * @DEVICE_RETRY: need to retry the TUR
> + * @DEVICE_ERROR: TUR return error, don't add device
> + * @DEVICE_READY: device can be added
> + *
> + */
> +enum device_state{
> +	DEVICE_RETRY,
> +	DEVICE_ERROR,
> +	DEVICE_READY,
> +};
> +
> +/**
> + * mptsas_test_unit_ready -
> + * @ioc: Pointer to MPT_ADAPTER structure
> + * @channel:
> + * @id:
> + * @count: retry count
> + *
> + */
> +enum device_state
> +mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id, u16 count)
> +{
> +	INTERNAL_CMD	*iocmd;
> +	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
> +	enum device_state	state;
> +	int			rc;
> +	u8		skey, asc, ascq;
> +	u8		retry_ua;
> +
> +	retry_ua = 0;
> +	iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
> +	if (!iocmd) {
> +		printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
> +			__func__, ioc->name, sizeof(INTERNAL_CMD));
> +		return DEVICE_ERROR;
> +	}
> +
> +	state = DEVICE_ERROR;
> +	iocmd->cmd = TEST_UNIT_READY;
> +	iocmd->data_dma = -1;
> +	iocmd->data = NULL;
> +
> +	if (mptscsih_is_phys_disk(ioc, channel, id)) {
> +		iocmd->flags |= MPT_ICFLAG_PHYS_DISK;
> +		iocmd->physDiskNum = mptscsih_raid_id_to_num(ioc, channel, id);
> +		iocmd->id = id;
> +	}
> +	iocmd->channel = channel;
> +	iocmd->id = id;
> +
> + retry:
> +	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d "
> +	    "fw_id=%d retry=%d\n", ioc->name, __func__, channel, id, count));
> +	rc = mptscsih_do_cmd(hd, iocmd);
> +	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n",
> +	    ioc->name, __func__, rc));
> +	if (rc < 0) {
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
> +		    "tur failed due to timeout\n", ioc->name,
> +			__func__, channel, id);
> +		goto tur_done;
> +	}
> +
> +	switch (rc) {
> +	case MPT_SCANDV_GOOD:
> +		state = DEVICE_READY;
> +		goto tur_done;
> +	case MPT_SCANDV_BUSY:
> +		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
> +		    "fw_channel=%d fw_id=%d : device busy\n",
> +		    ioc->name, __func__, channel, id));
> +		state = DEVICE_RETRY;
> +		break;
> +	case MPT_SCANDV_DID_RESET:
> +		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
> +		    "fw_channel=%d fw_id=%d : did reset\n",
> +		    ioc->name, __func__, channel, id));
> +		state = DEVICE_RETRY;
> +		break;
> +	case MPT_SCANDV_SENSE:
> +		skey = ioc->internal_cmds.sense[2] & 0x0F;
> +		asc = ioc->internal_cmds.sense[12];
> +		ascq = ioc->internal_cmds.sense[13];
> +
> +		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: "
> +		    "fw_channel=%d fw_id=%d : [sense_key,asc,"
> +		    "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name,
> +		    __func__, channel, id, skey, asc, ascq));
> +
> +		if (skey == UNIT_ATTENTION) {
> +			state = DEVICE_RETRY;
> +			break;
> +		} else if (skey == NOT_READY) {
> +			/*
> +			 * medium isn't present
> +			 */
> +			if (asc == 0x3a) {
> +				state = DEVICE_READY;
> +				goto tur_done;
> +			}
> +			/*
> +			 * LU becoming ready, or
> +			 * LU hasn't self-configured yet
> +			 */
> +			if ((asc == 0x04 && ascq == 0x01) ||
> +			    (asc == 0x04 && ascq == 0x11) ||
> +			    asc == 0x3e) {
> +				state = DEVICE_RETRY;
> +				break;
> +			}
> +		} else if (skey == ILLEGAL_REQUEST) {
> +			/* try sending a tur to a non-zero lun number */
> +			if (!iocmd->lun && !mptsas_get_lun_number(ioc,
> +				channel, id, &iocmd->lun) && iocmd->lun)
> +				goto retry;
> +		}
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : "
> +			"tur failed due to [sense_key,asc,ascq]: "
> +			"[0x%02x,0x%02x,0x%02x]\n", ioc->name,
> +			__func__, channel, id, skey, asc, ascq);
> +		goto tur_done;
> +	case MPT_SCANDV_SELECTION_TIMEOUT:
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
> +			"tur failed due to no device\n", ioc->name,
> +			__func__, channel,
> +			id);
> +		goto tur_done;
> +	case MPT_SCANDV_SOME_ERROR:
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
> +			"tur failed due to some error\n", ioc->name,
> +			__func__, channel, id);
> +		goto tur_done;
> +	default:
> +		printk(MYIOC_s_ERR_FMT
> +			"%s: fw_channel=%d fw_id=%d: tur failed due to "
> +			"unknown rc=0x%02x\n", ioc->name, __func__,
> +			channel, id, rc);
> +		goto tur_done;
> +	}
> + tur_done:
> +	kfree(iocmd);
> +	return state;
> +}

This routine looks like a recoding of scsi_test_unit_ready().  Firstly,
why not just use it, but secondly, why is it necessary ... the use case
is when you spot a device added and the mid layer does inquiry and
settle checking anyway.

>  static int
>  mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
>  		u32 form, u32 form_specific)
> @@ -893,15 +1317,361 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
>  	return error;
>  }
>  
> +/**
> + *	mptsas_get_lun_number - returns the first entry in report_luns table
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@channel:
> + *	@id:
> + *	@lun:
> + *
> + */
> +static int
> +mptsas_get_lun_number(MPT_ADAPTER *ioc, u8 channel, u8 id, int *lun)
> +{
> +	INTERNAL_CMD	*iocmd;
> +	struct scsi_lun *lun_data;
> +	dma_addr_t	lun_data_dma;
> +	u32		lun_data_len;
> +	u8	*data;
> +	MPT_SCSI_HOST	*hd;
> +	int		rc;
> +	u32		length, num_luns;
> +
> +	iocmd = NULL;
> +	hd = shost_priv(ioc->sh);
> +	lun_data_len = (255 * sizeof(struct scsi_lun));
> +	lun_data = pci_alloc_consistent(ioc->pcidev, lun_data_len,
> +	    &lun_data_dma);
> +	if (!lun_data) {
> +		printk(MYIOC_s_ERR_FMT "%s: pci_alloc_consistent(%d) FAILED!\n",
> +		    ioc->name, __func__, lun_data_len);
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL);
> +	if (!iocmd) {
> +		printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n",
> +		    ioc->name, __func__, sizeof(INTERNAL_CMD));
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/*
> +	 * Report Luns
> +	 */
> +	iocmd->cmd = REPORT_LUNS;
> +	iocmd->data_dma = lun_data_dma;
> +	iocmd->data = (u8 *)lun_data;
> +	iocmd->size = lun_data_len;
> +	iocmd->channel = channel;
> +	iocmd->id = id;
> +
> +	rc = mptscsih_do_cmd(hd, iocmd);
> +	if (rc < 0) {
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
> +		    "report_luns failed due to rc=0x%x\n", ioc->name,
> +		 __func__, channel, id, rc);
> +		goto out;
> +	}
> +
> +	if (rc != MPT_SCANDV_GOOD) {
> +		printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: "
> +		    "report_luns failed due to rc=0x%x\n", ioc->name,
> +		 __func__, channel, id, rc);
> +		rc = -rc;
> +		goto out;
> +	}
> +
> +	data = (u8 *)lun_data;
> +	length = ((data[0] << 24) | (data[1] << 16) |
> +	    (data[2] << 8) | (data[3] << 0));
> +
> +	num_luns = (length / sizeof(struct scsi_lun));
> +	if (!num_luns)
> +		goto out;
> +	/* return 1st lun in the list */
> +	*lun = mpt_scsilun_to_int(&lun_data[1]);
> +
> +#if 0
> +	/* some debugging, left commented out */
> +	{
> +		struct scsi_lun *lunp;
> +		for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++)
> +			printk("%x\n", scsilun_to_int(lunp));
> +	}
> +#endif
> +
> + out:
> +	if (lun_data)
> +		pci_free_consistent(ioc->pcidev, lun_data_len, lun_data,
> +		    lun_data_dma);
> +	kfree(iocmd);
> +	return rc;
> +}

OK, this is getting sillier.  You send a TUR to a device, but the device
may not have a LUN 0, so now we're going to send a report luns and fish
for an actual lun to test?  Again, the mid layer does all of this when
the device appears, why not just let it?

> +/**
> + *	mptsas_add_end_device - report a new end device to sas transport layer
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@phy_info: decribes attached device
> + *
> + *	return (0) success (1) failure
> + *
> + **/
> +static int
> +mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
> +{
> +	struct sas_rphy *rphy;
> +	struct sas_port *port;
> +	struct sas_identify identify;
> +	char *ds = NULL;
> +	u8 fw_id;
> +
> +	if (!phy_info) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: exit at line=%d\n", ioc->name,
> +			 __func__, __LINE__));
> +		return 1;
> +	}
> +
> +	fw_id = phy_info->attached.id;
> +
> +	if (mptsas_get_rphy(phy_info)) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		return 2;
> +	}
> +
> +	port = mptsas_get_port(phy_info);
> +	if (!port) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		return 3;
> +	}
> +
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
> +		ds = "ssp";
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_STP_TARGET)
> +		ds = "stp";
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
> +		ds = "sata";
> +
> +	printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
> +	    " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
> +	    phy_info->attached.channel, phy_info->attached.id,
> +	    phy_info->attached.phy_id, (unsigned long long)
> +	    phy_info->attached.sas_address);
> +
> +	mptsas_parse_device_info(&identify, &phy_info->attached);
> +	rphy = sas_end_device_alloc(port);
> +	if (!rphy) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		return 5; /* non-fatal: an rphy can be added later */
> +	}
> +
> +	rphy->identify = identify;
> +	if (sas_rphy_add(rphy)) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		sas_rphy_free(rphy);
> +		return 6;
> +	}
> +	mptsas_set_rphy(ioc, phy_info, rphy);
> +	return 0;
> +}
> +
> +/**
> + *	mptsas_del_end_device - report a deleted end device to sas transport
> + *	layer
> + *	@ioc: Pointer to MPT_ADAPTER structure
> + *	@phy_info: decribes attached device
> + *
> + **/
> +static void
> +mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
> +{
> +	struct sas_rphy *rphy;
> +	struct sas_port *port;
> +	struct mptsas_portinfo *port_info;
> +	struct mptsas_phyinfo *phy_info_parent;
> +	int i;
> +	char *ds = NULL;
> +	u8 fw_id;
> +	u64 sas_address;
> +
> +	if (!phy_info)
> +		return;
> +
> +	fw_id = phy_info->attached.id;
> +	sas_address = phy_info->attached.sas_address;
> +
> +	if (!phy_info->port_details) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		return;
> +	}
> +	rphy = mptsas_get_rphy(phy_info);
> +	if (!rphy) {
> +		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
> +			"%s: fw_id=%d exit at line=%d\n", ioc->name,
> +			 __func__, fw_id, __LINE__));
> +		return;
> +	}
> +
> +	if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
> +		|| phy_info->attached.device_info
> +			& MPI_SAS_DEVICE_INFO_SMP_INITIATOR
> +		|| phy_info->attached.device_info
> +			& MPI_SAS_DEVICE_INFO_STP_INITIATOR)
> +		ds = "initiator";
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
> +		ds = "ssp";
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_STP_TARGET)
> +		ds = "stp";
> +	if (phy_info->attached.device_info &
> +	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
> +		ds = "sata";
> +
> +	printk(MYIOC_s_INFO_FMT "removing %s device: fw_channel %d,"
> +	    " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds,
> +	    phy_info->attached.channel, phy_info->attached.id,
> +	    phy_info->attached.phy_id, (unsigned long long)
> +	    sas_address);

If you just did a dev_printk on &rphy->dev, you'll get a lot of the
above.  The remaining information might be a useful addition to the sas
transport class as a printing primitive.

James


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux