Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7a014af authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6: (25 commits)
  [SCSI] mptfc: race between mptfc_register_dev and mptfc_target_alloc
  [SCSI] lpfc 8.1.6 : Fix Data Corruption in Bus Reset Path
  [SCSI] mptspi: revalidate negotiation parameters after host reset and resume
  [SCSI] srp.h: avoid padding of structs
  [SCSI] ibmvscsi: fix leak when failing to send srp event
  [SCSI] qla2xxx: Correct eh_abort recovery logic.
  [SCSI] megaraid_{mm,mbox}: fix a bug in reset handler
  [SCSI] fusion - bug fix stack overflow in mptbase
  [SCSI] scsi: Add IBM 2104-DU3 to blist
  [SCSI] Fix DVD burning issues.
  [SCSI] SCSI: aic7xxx_osm_pci resource leak fix.
  [SCSI] - fusion - mptfc bug fix's to prevent deadlock situations
  [SCSI] mptfusion: bug fix's for raid components adding/deleting
  [SCSI] aic7xxx: ahc_pci_write_config() fix
  [SCSI] megaraid: unused variable
  [SCSI] qla2xxx: only free_irq() after request_irq() succeeds
  [SCSI] Overrun in drivers/scsi/sim710.c
  [SCSI] lpfc 8.1.5 : Change version number to 8.1.5
  [SCSI] lpfc 8.1.5 : Misc small fixes
  [SCSI] lpfc 8.1.5 : Additional fixes to LOGO, PLOGI, and RSCN processing
  ...
parents dac07ec1 6dd727da
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
Release Date	: Mon Apr 11 12:27:22 EST 2006 - Seokmann Ju <sju@lsil.com>
Current Version : 2.20.4.8 (scsi module), 2.20.2.6 (cmm module)
Older Version	: 2.20.4.7 (scsi module), 2.20.2.6 (cmm module)

1.	Fixed a bug in megaraid_reset_handler().
	Customer reported "Unable to handle kernel NULL pointer dereference
	at virtual address 00000000" when system goes to reset condition
	for some reason. It happened randomly.
	Root Cause: in the megaraid_reset_handler(), there is possibility not
	returning pending packets in the pend_list if there are multiple
	pending packets.
	Fix: Made the change in the driver so that it will return all packets
	in the pend_list.

2.	Added change request.
	As found in the following URL, rmb() only didn't help the
	problem. I had to increase the loop counter to 0xFFFFFF. (6 F's)
	http://marc.theaimsgroup.com/?l=linux-scsi&m=110971060502497&w=2

	I attached a patch for your reference, too.
	Could you check and get this fix in your driver?

	Best Regards,
	Jun'ichi Nomura

Release Date	: Fri Nov 11 12:27:22 EST 2005 - Seokmann Ju <sju@lsil.com>
Current Version : 2.20.4.7 (scsi module), 2.20.2.6 (cmm module)
Older Version	: 2.20.4.6 (scsi module), 2.20.2.6 (cmm module)
+37 −26
Original line number Diff line number Diff line
@@ -1189,7 +1189,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
	ioc->diagPending = 0;
	spin_lock_init(&ioc->diagLock);
	spin_lock_init(&ioc->fc_rescan_work_lock);
	spin_lock_init(&ioc->fc_rport_lock);
	spin_lock_init(&ioc->initializing_hba_lock);

	/* Initialize the event logging.
@@ -5736,11 +5735,13 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
	return rc;
}

# define EVENT_DESCR_STR_SZ		100

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void
EventDescriptionStr(u8 event, u32 evData0, char *evStr)
{
	char *ds;
	char *ds = NULL;

	switch(event) {
	case MPI_EVENT_NONE:
@@ -5841,27 +5842,32 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
		break;
	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
	{
		char buf[50];
		u8 id = (u8)(evData0);
		u8 ReasonCode = (u8)(evData0 >> 16);
		switch (ReasonCode) {
		case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
			sprintf(buf,"SAS Device Status Change: Added: id=%d", id);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			    "SAS Device Status Change: Added: id=%d", id);
			break;
		case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
			sprintf(buf,"SAS Device Status Change: Deleted: id=%d", id);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			    "SAS Device Status Change: Deleted: id=%d", id);
			break;
		case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
			sprintf(buf,"SAS Device Status Change: SMART Data: id=%d", id);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			    "SAS Device Status Change: SMART Data: id=%d",
			    id);
			break;
		case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
			sprintf(buf,"SAS Device Status Change: No Persistancy Added: id=%d", id);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			    "SAS Device Status Change: No Persistancy "
			    "Added: id=%d", id);
			break;
		default:
			sprintf(buf,"SAS Device Status Change: Unknown: id=%d", id);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			    "SAS Device Status Change: Unknown: id=%d", id);
			break;
		}
		ds = buf;
		break;
	}
	case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
@@ -5878,41 +5884,46 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
		break;
	case MPI_EVENT_SAS_PHY_LINK_STATUS:
	{
		char buf[50];
		u8 LinkRates = (u8)(evData0 >> 8);
		u8 PhyNumber = (u8)(evData0);
		LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
			MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
		switch (LinkRates) {
		case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Rate Unknown",PhyNumber);
			break;
		case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Phy Disabled",PhyNumber);
			break;
		case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Failed Speed Nego",PhyNumber);
			break;
		case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Sata OOB Completed",PhyNumber);
			break;
		case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Rate 1.5 Gbps",PhyNumber);
			break;
		case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
			sprintf(buf,"SAS PHY Link Status: Phy=%d:"
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d:"
			   " Rate 3.0 Gpbs",PhyNumber);
			break;
		default:
			sprintf(buf,"SAS PHY Link Status: Phy=%d", PhyNumber);
			snprintf(evStr, EVENT_DESCR_STR_SZ,
			   "SAS PHY Link Status: Phy=%d", PhyNumber);
			break;
		}
		ds = buf;
		break;
	}
	case MPI_EVENT_SAS_DISCOVERY_ERROR:
@@ -5921,9 +5932,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
	case MPI_EVENT_IR_RESYNC_UPDATE:
	{
		u8 resync_complete = (u8)(evData0 >> 16);
		char buf[40];
		sprintf(buf,"IR Resync Update: Complete = %d:",resync_complete);
		ds = buf;
		snprintf(evStr, EVENT_DESCR_STR_SZ,
		    "IR Resync Update: Complete = %d:",resync_complete);
		break;
	}
	case MPI_EVENT_IR2:
@@ -5976,7 +5986,8 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
		ds = "Unknown";
		break;
	}
	strcpy(evStr,ds);
	if (ds)
		strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5998,7 +6009,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
	int ii;
	int r = 0;
	int handlers = 0;
	char evStr[100];
	char evStr[EVENT_DESCR_STR_SZ];
	u8 event;

	/*
+4 −6
Original line number Diff line number Diff line
@@ -76,8 +76,8 @@
#define COPYRIGHT	"Copyright (c) 1999-2005 " MODULEAUTHOR
#endif

#define MPT_LINUX_VERSION_COMMON	"3.03.08"
#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.08"
#define MPT_LINUX_VERSION_COMMON	"3.03.09"
#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.09"
#define WHAT_MAGIC_STRING		"@" "(" "#" ")"

#define show_mptmod_ver(s,ver)  \
@@ -489,7 +489,6 @@ typedef struct _RaidCfgData {

#define MPT_RPORT_INFO_FLAGS_REGISTERED	0x01	/* rport registered */
#define MPT_RPORT_INFO_FLAGS_MISSING	0x02	/* missing from DevPage0 scan */
#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04	/* target mapped in vdev */

/*
 * data allocated for each fc rport device
@@ -501,7 +500,6 @@ struct mptfc_rport_info
	struct scsi_target *starget;
	FCDevicePage0_t pg0;
	u8		flags;
	u8		remap_needed;
};

/*
@@ -628,11 +626,11 @@ typedef struct _MPT_ADAPTER
	struct work_struct	 mptscsih_persistTask;

	struct list_head	 fc_rports;
	spinlock_t		 fc_rport_lock; /* list and ri flags */
	spinlock_t		 fc_rescan_work_lock;
	int			 fc_rescan_work_count;
	struct work_struct	 fc_rescan_work;

	char			 fc_rescan_work_q_name[KOBJ_NAME_LEN];
	struct workqueue_struct *fc_rescan_work_q;
} MPT_ADAPTER;

/*
+83 −51
Original line number Diff line number Diff line
@@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
	rid->port_id =   pg0->PortIdentifier;
	rid->roles = FC_RPORT_ROLE_UNKNOWN;
	rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
		rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;

	return 0;
}
@@ -355,15 +352,18 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
	struct fc_rport		*rport;
	struct mptfc_rport_info	*ri;
	int			new_ri = 1;
	u64			pn;
	unsigned long		flags;
	u64			pn, nn;
	VirtTarget		*vtarget;
	u32			roles = FC_RPORT_ROLE_UNKNOWN;

	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
		return;

	roles |= FC_RPORT_ROLE_FCP_TARGET;
	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
		roles |= FC_RPORT_ROLE_FCP_INITIATOR;

	/* scan list looking for a match */
	spin_lock_irqsave(&ioc->fc_rport_lock, flags);
	list_for_each_entry(ri, &ioc->fc_rports, list) {
		pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
		if (pn == rport_ids.port_name) {	/* match */
@@ -373,11 +373,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
		}
	}
	if (new_ri) {	/* allocate one */
		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
		if (!ri)
			return;
		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
		list_add_tail(&ri->list, &ioc->fc_rports);
	}

@@ -387,14 +385,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
	/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
		rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
		if (rport) {
			ri->rport = rport;
			if (new_ri) /* may have been reset by user */
				rport->dev_loss_tmo = mptfc_dev_loss_tmo;
			*((struct mptfc_rport_info **)rport->dd_data) = ri;
			/*
			 * if already mapped, remap here.  If not mapped,
			 * target_alloc will allocate vtarget and map,
@@ -406,16 +401,21 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
					vtarget->target_id = pg0->CurrentTargetID;
					vtarget->bus_id = pg0->CurrentBus;
				}
				ri->remap_needed = 0;
			}
			*((struct mptfc_rport_info **)rport->dd_data) = ri;
			/* scan will be scheduled once rport becomes a target */
			fc_remote_port_rolechg(rport,roles);

			pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
			nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
			dfcprintk ((MYIOC_s_INFO_FMT
				"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
				"rport tid %d, tmo %d\n",
					ioc->name,
					ioc->sh->host_no,
					pg0->PortIdentifier,
					pg0->WWNN,
					pg0->WWPN,
					(unsigned long long)nn,
					(unsigned long long)pn,
					pg0->CurrentTargetID,
					ri->rport->scsi_target_id,
					ri->rport->dev_loss_tmo));
@@ -425,8 +425,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
			ri = NULL;
		}
	}
	spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);

}

/*
@@ -476,7 +474,6 @@ mptfc_target_alloc(struct scsi_target *starget)
			vtarget->target_id = ri->pg0.CurrentTargetID;
			vtarget->bus_id = ri->pg0.CurrentBus;
			ri->starget = starget;
			ri->remap_needed = 0;
			rc = 0;
		}
	}
@@ -502,10 +499,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
	VirtDevice		*vdev;
	struct scsi_target	*starget;
	struct fc_rport		*rport;
	unsigned long		flags;


	rport = starget_to_rport(scsi_target(sdev));
	starget = scsi_target(sdev);
	rport = starget_to_rport(starget);

	if (!rport || fc_remote_port_chkready(rport))
		return -ENXIO;
@@ -519,10 +516,8 @@ mptfc_slave_alloc(struct scsi_device *sdev)
		return -ENOMEM;
	}

	spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);

	sdev->hostdata = vdev;
	starget = scsi_target(sdev);
	vtarget = starget->hostdata;

	if (vtarget->num_luns == 0) {
@@ -535,14 +530,16 @@ mptfc_slave_alloc(struct scsi_device *sdev)
	vdev->vtarget = vtarget;
	vdev->lun = sdev->lun;

	spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);

	vtarget->num_luns++;


#ifdef DMPT_DEBUG_FC
	{
	u64 nn, pn;
	struct mptfc_rport_info *ri;
	ri = *((struct mptfc_rport_info **)rport->dd_data);
	pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
	nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
	dfcprintk ((MYIOC_s_INFO_FMT
		"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
	        "CurrentTargetID %d, %x %llx %llx\n",
@@ -550,7 +547,9 @@ mptfc_slave_alloc(struct scsi_device *sdev)
		sdev->host->host_no,
		vtarget->num_luns,
		sdev->id, ri->pg0.CurrentTargetID,
		ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
		ri->pg0.PortIdentifier,
		(unsigned long long)pn,
		(unsigned long long)nn));
	}
#endif

@@ -570,11 +569,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
		done(SCpnt);
		return 0;
	}

	/* dd_data is null until finished adding target */
	ri = *((struct mptfc_rport_info **)rport->dd_data);
	if (unlikely(ri->remap_needed))
		return SCSI_MLQUEUE_HOST_BUSY;
	if (unlikely(!ri)) {
		dfcprintk ((MYIOC_s_INFO_FMT
			"mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
			SCpnt->device->id,SCpnt->device->lun));
		SCpnt->result = DID_IMM_RETRY << 16;
		done(SCpnt);
		return 0;
	}

	return mptscsih_qcmd(SCpnt,done);
	err = mptscsih_qcmd(SCpnt,done);
#ifdef DMPT_DEBUG_FC
	if (unlikely(err)) {
		dfcprintk ((MYIOC_s_INFO_FMT
			"mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n",
			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
			SCpnt->device->id,SCpnt->device->lun));
	}
#endif
	return err;
}

static void
@@ -615,18 +634,17 @@ mptfc_rescan_devices(void *arg)
	MPT_ADAPTER		*ioc = (MPT_ADAPTER *)arg;
	int			ii;
	int			work_to_do;
	u64			pn;
	unsigned long		flags;
	struct mptfc_rport_info *ri;

	do {
		/* start by tagging all ports as missing */
		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
		list_for_each_entry(ri, &ioc->fc_rports, list) {
			if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
				ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
			}
		}
		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);

		/*
		 * now rescan devices known to adapter,
@@ -639,33 +657,24 @@ mptfc_rescan_devices(void *arg)
		}

		/* delete devices still missing */
		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
		list_for_each_entry(ri, &ioc->fc_rports, list) {
			/* if newly missing, delete it */
			if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
					  MPT_RPORT_INFO_FLAGS_MISSING))
			  == (MPT_RPORT_INFO_FLAGS_REGISTERED |
			      MPT_RPORT_INFO_FLAGS_MISSING)) {
			if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {

				ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
					       MPT_RPORT_INFO_FLAGS_MISSING);
				ri->remap_needed = 1;
				fc_remote_port_delete(ri->rport);
				/*
				 * remote port not really deleted 'cause
				 * binding is by WWPN and driver only
				 * registers FCP_TARGETs but cannot trust
				 * data structures.
				 */
				fc_remote_port_delete(ri->rport);	/* won't sleep */
				ri->rport = NULL;

				pn = (u64)ri->pg0.WWPN.High << 32 |
				     (u64)ri->pg0.WWPN.Low;
				dfcprintk ((MYIOC_s_INFO_FMT
					"mptfc_rescan.%d: %llx deleted\n",
					ioc->name,
					ioc->sh->host_no,
					ri->pg0.WWPN));
					(unsigned long long)pn));
			}
		}
		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);

		/*
		 * allow multiple passes as target state
@@ -870,10 +879,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		goto out_mptfc_probe;
	}

	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
		mptfc_init_host_attr(ioc,ii);
		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
	}
	/* initialize workqueue */

	snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
		sh->host_no);
	ioc->fc_rescan_work_q =
		create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
	if (!ioc->fc_rescan_work_q)
		goto out_mptfc_probe;

	/*
	 * scan for rports -
	 *	by doing it via the workqueue, some locking is eliminated
	 */

	ioc->fc_rescan_work_count = 1;
	queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
	flush_workqueue(ioc->fc_rescan_work_q);

	return 0;

@@ -951,6 +973,16 @@ mptfc_remove(struct pci_dev *pdev)
{
	MPT_ADAPTER		*ioc = pci_get_drvdata(pdev);
	struct mptfc_rport_info	*p, *n;
	struct workqueue_struct *work_q;
	unsigned long		flags;

	/* destroy workqueue */
	if ((work_q=ioc->fc_rescan_work_q)) {
		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
		ioc->fc_rescan_work_q = NULL;
		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
		destroy_workqueue(work_q);
	}

	fc_remove_host(ioc->sh);

+71 −28
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ enum mptsas_hotplug_action {
	MPTSAS_DEL_DEVICE,
	MPTSAS_ADD_RAID,
	MPTSAS_DEL_RAID,
	MPTSAS_IGNORE_EVENT,
};

struct mptsas_hotplug_event {
@@ -298,6 +299,26 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
	return rc;
}

/*
 * Returns true if there is a scsi end device
 */
static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)
{
	if ((attached->handle) &&
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_END_DEVICE) &&
	    ((attached->device_info &
	    MPI_SAS_DEVICE_INFO_SSP_TARGET) |
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_STP_TARGET) |
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
		return 1;
	else
		return 0;
}

static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
		u32 form, u32 form_specific)
@@ -872,7 +893,11 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
	SasDevicePage0_t *buffer;
	dma_addr_t dma_handle;
	__le64 sas_address;
	int error;
	int error=0;

	if (ioc->sas_discovery_runtime &&
		mptsas_is_end_device(device_info))
			goto out;

	hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
	hdr.ExtPageLength = 0;
@@ -1009,7 +1034,11 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
	CONFIGPARMS cfg;
	SasExpanderPage1_t *buffer;
	dma_addr_t dma_handle;
	int error;
	int error=0;

	if (ioc->sas_discovery_runtime &&
		mptsas_is_end_device(&phy_info->attached))
			goto out;

	hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
	hdr.ExtPageLength = 0;
@@ -1068,26 +1097,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
	return error;
}

/*
 * Returns true if there is a scsi end device
 */
static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)
{
	if ((attached->handle) &&
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_END_DEVICE) &&
	    ((attached->device_info &
	    MPI_SAS_DEVICE_INFO_SSP_TARGET) |
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_STP_TARGET) |
	    (attached->device_info &
	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
		return 1;
	else
		return 0;
}

static void
mptsas_parse_device_info(struct sas_identify *identify,
		struct mptsas_devinfo *device_info)
@@ -1737,6 +1746,9 @@ mptsas_hotplug_work(void *arg)
		break;
	case MPTSAS_ADD_DEVICE:

		if (ev->phys_disk_num_valid)
			mpt_findImVolumes(ioc);

		/*
		 * Refresh sas device pg0 data
		 */
@@ -1868,6 +1880,9 @@ mptsas_hotplug_work(void *arg)
		scsi_device_put(sdev);
		mpt_findImVolumes(ioc);
		break;
	case MPTSAS_IGNORE_EVENT:
	default:
		break;
	}

	kfree(ev);
@@ -1940,7 +1955,8 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
		EVENT_DATA_RAID *raid_event_data)
{
	struct mptsas_hotplug_event *ev;
	RAID_VOL0_STATUS * volumeStatus;
	int status = le32_to_cpu(raid_event_data->SettingsStatus);
	int state = (status >> 8) & 0xff;

	if (ioc->bus_type != SAS)
		return;
@@ -1955,6 +1971,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
	INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
	ev->ioc = ioc;
	ev->id = raid_event_data->VolumeID;
	ev->event_type = MPTSAS_IGNORE_EVENT;

	switch (raid_event_data->ReasonCode) {
	case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
@@ -1966,6 +1983,25 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
		ev->phys_disk_num = raid_event_data->PhysDiskNum;
		ev->event_type = MPTSAS_DEL_DEVICE;
		break;
	case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
		switch (state) {
		case MPI_PD_STATE_ONLINE:
			ioc->raid_data.isRaid = 1;
			ev->phys_disk_num_valid = 1;
			ev->phys_disk_num = raid_event_data->PhysDiskNum;
			ev->event_type = MPTSAS_ADD_DEVICE;
			break;
		case MPI_PD_STATE_MISSING:
		case MPI_PD_STATE_NOT_COMPATIBLE:
		case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
		case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
		case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
			ev->event_type = MPTSAS_DEL_DEVICE;
			break;
		default:
			break;
		}
		break;
	case MPI_EVENT_RAID_RC_VOLUME_DELETED:
		ev->event_type = MPTSAS_DEL_RAID;
		break;
@@ -1973,11 +2009,18 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
		ev->event_type = MPTSAS_ADD_RAID;
		break;
	case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
		volumeStatus = (RAID_VOL0_STATUS *) &
		    raid_event_data->SettingsStatus;
		ev->event_type = (volumeStatus->State ==
		    MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
		    MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
		switch (state) {
		case MPI_RAIDVOL0_STATUS_STATE_FAILED:
		case MPI_RAIDVOL0_STATUS_STATE_MISSING:
			ev->event_type = MPTSAS_DEL_RAID;
			break;
		case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
		case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
			ev->event_type = MPTSAS_ADD_RAID;
			break;
		default:
			break;
		}
		break;
	default:
		break;
Loading