diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
| -rw-r--r-- | drivers/message/fusion/mptsas.c | 996 | 
1 files changed, 720 insertions, 276 deletions
| diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 85689ab46cbc..f7bd8b11ed3b 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -50,11 +50,14 @@  #include <linux/errno.h>  #include <linux/sched.h>  #include <linux/workqueue.h> +#include <linux/delay.h>	/* for mdelay */ +#include <scsi/scsi.h>  #include <scsi/scsi_cmnd.h>  #include <scsi/scsi_device.h>  #include <scsi/scsi_host.h>  #include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h>  #include "mptbase.h"  #include "mptscsih.h" @@ -137,23 +140,37 @@ struct mptsas_devinfo {  	u32	device_info;	/* bitfield detailed info about this device */  }; +/* + * Specific details on ports, wide/narrow + */ +struct mptsas_portinfo_details{ +	u8	port_id; 	/* port number provided to transport */ +	u16	num_phys;	/* number of phys belong to this port */ +	u64	phy_bitmask; 	/* TODO, extend support for 255 phys */ +	struct sas_rphy *rphy;	/* transport layer rphy object */ +	struct sas_port *port;	/* transport layer port object */ +	struct scsi_target *starget; +	struct mptsas_portinfo *port_info; +}; +  struct mptsas_phyinfo {  	u8	phy_id; 		/* phy index */ -	u8	port_id; 		/* port number this phy is part of */ +	u8	port_id; 		/* firmware port identifier */  	u8	negotiated_link_rate;	/* nego'd link rate for this phy */  	u8	hw_link_rate; 		/* hardware max/min phys link rate */  	u8	programmed_link_rate;	/* programmed max/min phy link rate */ +	u8	sas_port_add_phy;	/* flag to request sas_port_add_phy*/  	struct mptsas_devinfo identify;	/* point to phy device info */  	struct mptsas_devinfo attached;	/* point to attached device info */ -	struct sas_phy *phy; -	struct sas_rphy *rphy; -	struct scsi_target *starget; +	struct sas_phy *phy;		/* transport layer phy object */ +	struct mptsas_portinfo *portinfo; +	struct mptsas_portinfo_details * port_details;  };  struct mptsas_portinfo {  	struct list_head list;  	u16		handle;		/* unique id to address this */ -	u8		num_phys;	/* number of phys */ +	u16		num_phys;	/* number of phys */  	struct mptsas_phyinfo *phy_info;  }; @@ -169,7 +186,7 @@ struct mptsas_enclosure {  	u8	sep_channel;		/* SEP channel logical channel id */  }; -#ifdef SASDEBUG +#ifdef MPT_DEBUG_SAS  static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)  {  	printk("---- IO UNIT PAGE 0 ------------\n"); @@ -305,7 +322,7 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)  static inline int  mptsas_is_end_device(struct mptsas_devinfo * attached)  { -	if ((attached->handle) && +	if ((attached->sas_address) &&  	    (attached->device_info &  	    MPI_SAS_DEVICE_INFO_END_DEVICE) &&  	    ((attached->device_info & @@ -319,6 +336,253 @@ mptsas_is_end_device(struct mptsas_devinfo * attached)  		return 0;  } +/* no mutex */ +static void +mptsas_port_delete(struct mptsas_portinfo_details * port_details) +{ +	struct mptsas_portinfo *port_info; +	struct mptsas_phyinfo *phy_info; +	u8	i; + +	if (!port_details) +		return; + +	port_info = port_details->port_info; +	phy_info = port_info->phy_info; + +	dsaswideprintk((KERN_DEBUG "%s: [%p]: port=%02d num_phys=%02d " +	    	"bitmask=0x%016llX\n", +		__FUNCTION__, port_details, port_details->port_id, +		port_details->num_phys, port_details->phy_bitmask)); + +	for (i = 0; i < port_info->num_phys; i++, phy_info++) { +		if(phy_info->port_details != port_details) +			continue; +		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); +		phy_info->port_details = NULL; +	} +	kfree(port_details); +} + +static inline struct sas_rphy * +mptsas_get_rphy(struct mptsas_phyinfo *phy_info) +{ +	if (phy_info->port_details) +		return phy_info->port_details->rphy; +	else +		return NULL; +} + +static inline void +mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) +{ +	if (phy_info->port_details) { +		phy_info->port_details->rphy = rphy; +		dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy)); +	} + +#ifdef MPT_DEBUG_SAS_WIDE +	if (rphy) { +		dev_printk(KERN_DEBUG, &rphy->dev, "add:"); +		printk("rphy=%p release=%p\n", +			rphy, rphy->dev.release); +	} +#endif +} + +static inline struct sas_port * +mptsas_get_port(struct mptsas_phyinfo *phy_info) +{ +	if (phy_info->port_details) +		return phy_info->port_details->port; +	else +		return NULL; +} + +static inline void +mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port) +{ +	if (phy_info->port_details) +		phy_info->port_details->port = port; + +#ifdef MPT_DEBUG_SAS_WIDE +	if (port) { +		dev_printk(KERN_DEBUG, &port->dev, "add: "); +		printk("port=%p release=%p\n", +			port, port->dev.release); +	} +#endif +} + +static inline struct scsi_target * +mptsas_get_starget(struct mptsas_phyinfo *phy_info) +{ +	if (phy_info->port_details) +		return phy_info->port_details->starget; +	else +		return NULL; +} + +static inline void +mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * +starget) +{ +	if (phy_info->port_details) +		phy_info->port_details->starget = starget; +} + + +/* + * mptsas_setup_wide_ports + * + * Updates for new and existing narrow/wide port configuration + * in the sas_topology + */ +static void +mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ +	struct mptsas_portinfo_details * port_details; +	struct mptsas_phyinfo *phy_info, *phy_info_cmp; +	u64	sas_address; +	int	i, j; + +	mutex_lock(&ioc->sas_topology_mutex); + +	phy_info = port_info->phy_info; +	for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { +		if (phy_info->attached.handle) +			continue; +		port_details = phy_info->port_details; +		if (!port_details) +			continue; +		if (port_details->num_phys < 2) +			continue; +		/* +		 * Removing a phy from a port, letting the last +		 * phy be removed by firmware events. +		 */ +		dsaswideprintk((KERN_DEBUG +			"%s: [%p]: port=%d deleting phy = %d\n", +			__FUNCTION__, port_details, +			port_details->port_id, i)); +		port_details->num_phys--; +		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); +		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); +		sas_port_delete_phy(port_details->port, phy_info->phy); +		phy_info->port_details = NULL; +	} + +	/* +	 * Populate and refresh the tree +	 */ +	phy_info = port_info->phy_info; +	for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { +		sas_address = phy_info->attached.sas_address; +		dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", +			i, sas_address)); +		if (!sas_address) +			continue; +		port_details = phy_info->port_details; +		/* +		 * Forming a port +		 */ +		if (!port_details) { +			port_details = kzalloc(sizeof(*port_details), +				GFP_KERNEL); +			if (!port_details) +				goto out; +			port_details->num_phys = 1; +			port_details->port_info = port_info; +			port_details->port_id = ioc->port_serial_number++; +			if (phy_info->phy_id < 64 ) +				port_details->phy_bitmask |= +				    (1 << phy_info->phy_id); +			phy_info->sas_port_add_phy=1; +			dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t" +				"phy_id=%d sas_address=0x%018llX\n", +				i, sas_address)); +			phy_info->port_details = port_details; +		} + +		if (i == port_info->num_phys - 1) +			continue; +		phy_info_cmp = &port_info->phy_info[i + 1]; +		for (j = i + 1 ; j < port_info->num_phys ; j++, +		    phy_info_cmp++) { +			if (!phy_info_cmp->attached.sas_address) +				continue; +			if (sas_address != phy_info_cmp->attached.sas_address) +				continue; +			if (phy_info_cmp->port_details == port_details ) +				continue; +			dsaswideprintk((KERN_DEBUG +				"\t\tphy_id=%d sas_address=0x%018llX\n", +				j, phy_info_cmp->attached.sas_address)); +			if (phy_info_cmp->port_details) { +				port_details->rphy = +				    mptsas_get_rphy(phy_info_cmp); +				port_details->port = +				    mptsas_get_port(phy_info_cmp); +				port_details->starget = +				    mptsas_get_starget(phy_info_cmp); +				port_details->port_id = +					phy_info_cmp->port_details->port_id; +				port_details->num_phys = +					phy_info_cmp->port_details->num_phys; +//				port_info->port_serial_number--; +				ioc->port_serial_number--; +				if (!phy_info_cmp->port_details->num_phys) +					kfree(phy_info_cmp->port_details); +			} else +				phy_info_cmp->sas_port_add_phy=1; +			/* +			 * Adding a phy to a port +			 */ +			phy_info_cmp->port_details = port_details; +			if (phy_info_cmp->phy_id < 64 ) +				port_details->phy_bitmask |= +				(1 << phy_info_cmp->phy_id); +			port_details->num_phys++; +		} +	} + + out: + +#ifdef MPT_DEBUG_SAS_WIDE +	for (i = 0; i < port_info->num_phys; i++) { +		port_details = port_info->phy_info[i].port_details; +		if (!port_details) +			continue; +		dsaswideprintk((KERN_DEBUG +			"%s: [%p]: phy_id=%02d port_id=%02d num_phys=%02d " +		    	"bitmask=0x%016llX\n", +			__FUNCTION__, +			port_details, i, port_details->port_id, +			port_details->num_phys, port_details->phy_bitmask)); +		dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n", +			port_details->port, port_details->rphy)); +	} +	dsaswideprintk((KERN_DEBUG"\n")); +#endif +	mutex_unlock(&ioc->sas_topology_mutex); +} + +static void +mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget) +{ +	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + +	if (mptscsih_TMHandler(hd, +	     MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, +	     vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) { +		hd->tmPending = 0; +		hd->tmState = TM_STATE_NONE; +		printk(MYIOC_s_WARN_FMT +	       "Error processing TaskMgmt id=%d TARGET_RESET\n", +			ioc->name, vtarget->target_id); +	} +} +  static int  mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,  		u32 form, u32 form_specific) @@ -400,11 +664,105 @@ mptsas_slave_configure(struct scsi_device *sdev)  	return mptscsih_slave_configure(sdev);  } -/* - * This is pretty ugly.  We will be able to seriously clean it up - * once the DV code in mptscsih goes away and we can properly - * implement ->target_alloc. - */ +static int +mptsas_target_alloc(struct scsi_target *starget) +{ +	struct Scsi_Host *host = dev_to_shost(&starget->dev); +	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)host->hostdata; +	VirtTarget		*vtarget; +	u32			target_id; +	u32			channel; +	struct sas_rphy		*rphy; +	struct mptsas_portinfo	*p; +	int 			 i; + +	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); +	if (!vtarget) +		return -ENOMEM; + +	vtarget->starget = starget; +	vtarget->ioc_id = hd->ioc->id; +	vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; + +	target_id = starget->id; +	channel = 0; + +	hd->Targets[target_id] = vtarget; + +	/* +	 * RAID volumes placed beyond the last expected port. +	 */ +	if (starget->channel == hd->ioc->num_ports) +		goto out; + +	rphy = dev_to_rphy(starget->dev.parent); +	mutex_lock(&hd->ioc->sas_topology_mutex); +	list_for_each_entry(p, &hd->ioc->sas_topology, list) { +		for (i = 0; i < p->num_phys; i++) { +			if (p->phy_info[i].attached.sas_address != +					rphy->identify.sas_address) +				continue; +			target_id = p->phy_info[i].attached.id; +			channel = p->phy_info[i].attached.channel; +			mptsas_set_starget(&p->phy_info[i], starget); + +			/* +			 * Exposing hidden raid components +			 */ +			if (mptscsih_is_phys_disk(hd->ioc, target_id)) { +				target_id = mptscsih_raid_id_to_num(hd, +						target_id); +				vtarget->tflags |= +				    MPT_TARGET_FLAGS_RAID_COMPONENT; +			} +			mutex_unlock(&hd->ioc->sas_topology_mutex); +			goto out; +		} +	} +	mutex_unlock(&hd->ioc->sas_topology_mutex); + +	kfree(vtarget); +	return -ENXIO; + + out: +	vtarget->target_id = target_id; +	vtarget->bus_id = channel; +	starget->hostdata = vtarget; +	return 0; +} + +static void +mptsas_target_destroy(struct scsi_target *starget) +{ +	struct Scsi_Host *host = dev_to_shost(&starget->dev); +	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)host->hostdata; +	struct sas_rphy		*rphy; +	struct mptsas_portinfo	*p; +	int 			 i; + +	if (!starget->hostdata) +		return; + +	if (starget->channel == hd->ioc->num_ports) +		goto out; + +	rphy = dev_to_rphy(starget->dev.parent); +	list_for_each_entry(p, &hd->ioc->sas_topology, list) { +		for (i = 0; i < p->num_phys; i++) { +			if (p->phy_info[i].attached.sas_address != +					rphy->identify.sas_address) +				continue; +			mptsas_set_starget(&p->phy_info[i], NULL); +			goto out; +		} +	} + + out: +	kfree(starget->hostdata); +	starget->hostdata = NULL; +} + +  static int  mptsas_slave_alloc(struct scsi_device *sdev)  { @@ -412,61 +770,41 @@ mptsas_slave_alloc(struct scsi_device *sdev)  	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)host->hostdata;  	struct sas_rphy		*rphy;  	struct mptsas_portinfo	*p; -	VirtTarget		*vtarget;  	VirtDevice		*vdev;  	struct scsi_target 	*starget; -	u32			target_id; -	int i; +	int 			i;  	vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);  	if (!vdev) { -		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", +		printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",  				hd->ioc->name, sizeof(VirtDevice));  		return -ENOMEM;  	} -	sdev->hostdata = vdev;  	starget = scsi_target(sdev); -	vtarget = starget->hostdata; -	vtarget->ioc_id = hd->ioc->id; -	vdev->vtarget = vtarget; -	if (vtarget->num_luns == 0) { -		vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; -		hd->Targets[sdev->id] = vtarget; -	} +	vdev->vtarget = starget->hostdata;  	/* -	  RAID volumes placed beyond the last expected port. -	*/ -	if (sdev->channel == hd->ioc->num_ports) { -		target_id = sdev->id; -		vtarget->bus_id = 0; -		vdev->lun = 0; +	 * RAID volumes placed beyond the last expected port. +	 */ +	if (sdev->channel == hd->ioc->num_ports)  		goto out; -	}  	rphy = dev_to_rphy(sdev->sdev_target->dev.parent);  	mutex_lock(&hd->ioc->sas_topology_mutex);  	list_for_each_entry(p, &hd->ioc->sas_topology, list) {  		for (i = 0; i < p->num_phys; i++) { -			if (p->phy_info[i].attached.sas_address == -					rphy->identify.sas_address) { -				target_id = p->phy_info[i].attached.id; -				vtarget->bus_id = p->phy_info[i].attached.channel; -				vdev->lun = sdev->lun; -				p->phy_info[i].starget = sdev->sdev_target; -				/* -				 * Exposing hidden disk (RAID) -				 */ -				if (mptscsih_is_phys_disk(hd->ioc, target_id)) { -					target_id = mptscsih_raid_id_to_num(hd, -							target_id); -					vdev->vtarget->tflags |= -					    MPT_TARGET_FLAGS_RAID_COMPONENT; -					sdev->no_uld_attach = 1; -				} -				mutex_unlock(&hd->ioc->sas_topology_mutex); -				goto out; -			} +			if (p->phy_info[i].attached.sas_address != +					rphy->identify.sas_address) +				continue; +			vdev->lun = sdev->lun; +			/* +			 * Exposing hidden raid components +			 */ +			if (mptscsih_is_phys_disk(hd->ioc, +					p->phy_info[i].attached.id)) +				sdev->no_uld_attach = 1; +			mutex_unlock(&hd->ioc->sas_topology_mutex); +			goto out;  		}  	}  	mutex_unlock(&hd->ioc->sas_topology_mutex); @@ -475,57 +813,39 @@ mptsas_slave_alloc(struct scsi_device *sdev)  	return -ENXIO;   out: -	vtarget->target_id = target_id; -	vtarget->num_luns++; +	vdev->vtarget->num_luns++; +	sdev->hostdata = vdev;  	return 0;  } -static void -mptsas_slave_destroy(struct scsi_device *sdev) +static int +mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))  { -	struct Scsi_Host *host = sdev->host; -	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; -	VirtDevice *vdev; +	VirtDevice	*vdev = SCpnt->device->hostdata; -	/* -	 * Issue target reset to flush firmware outstanding commands. -	 */ -	vdev = sdev->hostdata; -	if (vdev->configured_lun){ -		if (mptscsih_TMHandler(hd, -		     MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, -		     vdev->vtarget->bus_id, -		     vdev->vtarget->target_id, -		     0, 0, 5 /* 5 second timeout */) -		     < 0){ - -			/* The TM request failed! -			 * Fatal error case. -			 */ -			printk(MYIOC_s_WARN_FMT -		       "Error processing TaskMgmt id=%d TARGET_RESET\n", -				hd->ioc->name, -				vdev->vtarget->target_id); - -			hd->tmPending = 0; -			hd->tmState = TM_STATE_NONE; -		} +//	scsi_print_command(SCpnt); +	if (vdev->vtarget->deleted) { +		SCpnt->result = DID_NO_CONNECT << 16; +		done(SCpnt); +		return 0;  	} -	mptscsih_slave_destroy(sdev); + +	return mptscsih_qcmd(SCpnt,done);  } +  static struct scsi_host_template mptsas_driver_template = {  	.module				= THIS_MODULE,  	.proc_name			= "mptsas",  	.proc_info			= mptscsih_proc_info,  	.name				= "MPT SPI Host",  	.info				= mptscsih_info, -	.queuecommand			= mptscsih_qcmd, -	.target_alloc			= mptscsih_target_alloc, +	.queuecommand			= mptsas_qcmd, +	.target_alloc			= mptsas_target_alloc,  	.slave_alloc			= mptsas_slave_alloc,  	.slave_configure		= mptsas_slave_configure, -	.target_destroy			= mptscsih_target_destroy, -	.slave_destroy			= mptsas_slave_destroy, +	.target_destroy			= mptsas_target_destroy, +	.slave_destroy			= mptscsih_slave_destroy,  	.change_queue_depth 		= mptscsih_change_queue_depth,  	.eh_abort_handler		= mptscsih_abort,  	.eh_device_reset_handler	= mptscsih_dev_reset, @@ -795,7 +1115,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)  	port_info->num_phys = buffer->NumPhys;  	port_info->phy_info = kcalloc(port_info->num_phys, -		sizeof(struct mptsas_phyinfo),GFP_KERNEL); +		sizeof(*port_info->phy_info),GFP_KERNEL);  	if (!port_info->phy_info) {  		error = -ENOMEM;  		goto out_free_consistent; @@ -811,6 +1131,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)  		    buffer->PhyData[i].Port;  		port_info->phy_info[i].negotiated_link_rate =  		    buffer->PhyData[i].NegotiatedLinkRate; +		port_info->phy_info[i].portinfo = port_info;  	}   out_free_consistent: @@ -968,7 +1289,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,  	CONFIGPARMS cfg;  	SasExpanderPage0_t *buffer;  	dma_addr_t dma_handle; -	int error; +	int i, error;  	hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;  	hdr.ExtPageLength = 0; @@ -1013,12 +1334,15 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,  	port_info->num_phys = buffer->NumPhys;  	port_info->handle = le16_to_cpu(buffer->DevHandle);  	port_info->phy_info = kcalloc(port_info->num_phys, -		sizeof(struct mptsas_phyinfo),GFP_KERNEL); +		sizeof(*port_info->phy_info),GFP_KERNEL);  	if (!port_info->phy_info) {  		error = -ENOMEM;  		goto out_free_consistent;  	} +	for (i = 0; i < port_info->num_phys; i++) +		port_info->phy_info[i].portinfo = port_info; +   out_free_consistent:  	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,  			    buffer, dma_handle); @@ -1161,19 +1485,23 @@ static int mptsas_probe_one_phy(struct device *dev,  {  	MPT_ADAPTER *ioc;  	struct sas_phy *phy; -	int error; +	struct sas_port *port; +	int error = 0; -	if (!dev) -		return -ENODEV; +	if (!dev) { +		error = -ENODEV; +		goto out; +	}  	if (!phy_info->phy) {  		phy = sas_phy_alloc(dev, index); -		if (!phy) -			return -ENOMEM; +		if (!phy) { +			error = -ENOMEM; +			goto out; +		}  	} else  		phy = phy_info->phy; -	phy->port_identifier = phy_info->port_id;  	mptsas_parse_device_info(&phy->identify, &phy_info->identify);  	/* @@ -1265,19 +1593,52 @@ static int mptsas_probe_one_phy(struct device *dev,  		error = sas_phy_add(phy);  		if (error) {  			sas_phy_free(phy); -			return error; +			goto out;  		}  		phy_info->phy = phy;  	} -	if ((phy_info->attached.handle) && -	    (!phy_info->rphy)) { +	if (!phy_info->attached.handle || +			!phy_info->port_details) +		goto out; + +	port = mptsas_get_port(phy_info); +	ioc = phy_to_ioc(phy_info->phy); + +	if (phy_info->sas_port_add_phy) { + +		if (!port) { +			port = sas_port_alloc(dev, +			    phy_info->port_details->port_id); +			dsaswideprintk((KERN_DEBUG +			    "sas_port_alloc: port=%p dev=%p port_id=%d\n", +			    port, dev, phy_info->port_details->port_id)); +			if (!port) { +				error = -ENOMEM; +				goto out; +			} +			error = sas_port_add(port); +			if (error) { +				dfailprintk((MYIOC_s_ERR_FMT +					"%s: exit at line=%d\n", ioc->name, +					__FUNCTION__, __LINE__)); +				goto out; +			} +			mptsas_set_port(phy_info, port); +		} +		dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n", +		    phy_info->phy_id)); +		sas_port_add_phy(port, phy_info->phy); +		phy_info->sas_port_add_phy = 0; +	} + +	if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {  		struct sas_rphy *rphy; +		struct device *parent;  		struct sas_identify identify; -		ioc = phy_to_ioc(phy_info->phy); - +		parent = dev->parent->parent;  		/*  		 * Let the hotplug_work thread handle processing  		 * the adding/removing of devices that occur @@ -1285,36 +1646,63 @@ static int mptsas_probe_one_phy(struct device *dev,  		 */  		if (ioc->sas_discovery_runtime &&  			mptsas_is_end_device(&phy_info->attached)) -			return 0; +				goto out;  		mptsas_parse_device_info(&identify, &phy_info->attached); +		if (scsi_is_host_device(parent)) { +			struct mptsas_portinfo *port_info; +			int i; + +			mutex_lock(&ioc->sas_topology_mutex); +			port_info = mptsas_find_portinfo_by_handle(ioc, +								   ioc->handle); +			mutex_unlock(&ioc->sas_topology_mutex); + +			for (i = 0; i < port_info->num_phys; i++) +				if (port_info->phy_info[i].identify.sas_address == +				    identify.sas_address) +					goto out; + +		} else if (scsi_is_sas_rphy(parent)) { +			struct sas_rphy *parent_rphy = dev_to_rphy(parent); +			if (identify.sas_address == +			    parent_rphy->identify.sas_address) +				goto out; +		} +  		switch (identify.device_type) {  		case SAS_END_DEVICE: -			rphy = sas_end_device_alloc(phy); +			rphy = sas_end_device_alloc(port);  			break;  		case SAS_EDGE_EXPANDER_DEVICE:  		case SAS_FANOUT_EXPANDER_DEVICE: -			rphy = sas_expander_alloc(phy, identify.device_type); +			rphy = sas_expander_alloc(port, identify.device_type);  			break;  		default:  			rphy = NULL;  			break;  		} -		if (!rphy) -			return 0; /* non-fatal: an rphy can be added later */ +		if (!rphy) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +				__FUNCTION__, __LINE__)); +			goto out; +		}  		rphy->identify = identify; -  		error = sas_rphy_add(rphy);  		if (error) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +				__FUNCTION__, __LINE__));  			sas_rphy_free(rphy); -			return error; +			goto out;  		} - -		phy_info->rphy = rphy; +		mptsas_set_rphy(phy_info, rphy);  	} -	return 0; + out: +	return error;  }  static int @@ -1333,6 +1721,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)  		goto out_free_port_info;  	mutex_lock(&ioc->sas_topology_mutex); +	ioc->handle = hba->handle;  	port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);  	if (!port_info) {  		port_info = hba; @@ -1342,8 +1731,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)  		for (i = 0; i < hba->num_phys; i++)  			port_info->phy_info[i].negotiated_link_rate =  				hba->phy_info[i].negotiated_link_rate; -		if (hba->phy_info) -			kfree(hba->phy_info); +		kfree(hba->phy_info);  		kfree(hba);  		hba = NULL;  	} @@ -1362,18 +1750,19 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)  		    port_info->phy_info[i].phy_id;  		handle = port_info->phy_info[i].identify.handle; -		if (port_info->phy_info[i].attached.handle) { +		if (port_info->phy_info[i].attached.handle)  			mptsas_sas_device_pg0(ioc,  				&port_info->phy_info[i].attached,  				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<  				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),  				port_info->phy_info[i].attached.handle); -		} +	} + +	mptsas_setup_wide_ports(ioc, port_info); +	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)  		mptsas_probe_one_phy(&ioc->sh->shost_gendev,  		    &port_info->phy_info[i], ioc->sas_index, 1); -		ioc->sas_index++; -	}  	return 0; @@ -1387,6 +1776,8 @@ static int  mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)  {  	struct mptsas_portinfo *port_info, *p, *ex; +	struct device *parent; +	struct sas_rphy *rphy;  	int error = -ENOMEM, i, j;  	ex = kzalloc(sizeof(*port_info), GFP_KERNEL); @@ -1408,16 +1799,13 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)  		list_add_tail(&port_info->list, &ioc->sas_topology);  	} else {  		port_info->handle = ex->handle; -		if (ex->phy_info) -			kfree(ex->phy_info); +		kfree(ex->phy_info);  		kfree(ex);  		ex = NULL;  	}  	mutex_unlock(&ioc->sas_topology_mutex);  	for (i = 0; i < port_info->num_phys; i++) { -		struct device *parent; -  		mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],  			(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<  			 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); @@ -1441,34 +1829,34 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)  			port_info->phy_info[i].attached.phy_id =  			    port_info->phy_info[i].phy_id;  		} +	} -		/* -		 * If we find a parent port handle this expander is -		 * attached to another expander, else it hangs of the -		 * HBA phys. -		 */ -		parent = &ioc->sh->shost_gendev; +	parent = &ioc->sh->shost_gendev; +	for (i = 0; i < port_info->num_phys; i++) {  		mutex_lock(&ioc->sas_topology_mutex);  		list_for_each_entry(p, &ioc->sas_topology, list) {  			for (j = 0; j < p->num_phys; j++) { -				if (port_info->phy_info[i].identify.handle == +				if (port_info->phy_info[i].identify.handle !=  						p->phy_info[j].attached.handle) -					parent = &p->phy_info[j].rphy->dev; +					continue; +				rphy = mptsas_get_rphy(&p->phy_info[j]); +				parent = &rphy->dev;  			}  		}  		mutex_unlock(&ioc->sas_topology_mutex); +	} + +	mptsas_setup_wide_ports(ioc, port_info); +	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)  		mptsas_probe_one_phy(parent, &port_info->phy_info[i],  		    ioc->sas_index, 0); -		ioc->sas_index++; -	}  	return 0;   out_free_port_info:  	if (ex) { -		if (ex->phy_info) -			kfree(ex->phy_info); +		kfree(ex->phy_info);  		kfree(ex);  	}   out: @@ -1487,7 +1875,12 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)  {  	struct mptsas_portinfo buffer;  	struct mptsas_portinfo *port_info, *n, *parent; +	struct mptsas_phyinfo *phy_info; +	struct scsi_target * starget; +	VirtTarget * vtarget; +	struct sas_port * port;  	int i; +	u64	expander_sas_address;  	mutex_lock(&ioc->sas_topology_mutex);  	list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { @@ -1502,6 +1895,25 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)  		     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {  			/* +			 * Issue target reset to all child end devices +			 * then mark them deleted to prevent further +			 * IO going to them. +			 */ +			phy_info = port_info->phy_info; +			for (i = 0; i < port_info->num_phys; i++, phy_info++) { +				starget = mptsas_get_starget(phy_info); +				if (!starget) +					continue; +				vtarget = starget->hostdata; +				if(vtarget->deleted) +					continue; +				vtarget->deleted = 1; +				mptsas_target_reset(ioc, vtarget); +				sas_port_delete(mptsas_get_port(phy_info)); +				mptsas_port_delete(phy_info->port_details); +			} + +			/*  			 * Obtain the port_info instance to the parent port  			 */  			parent = mptsas_find_portinfo_by_handle(ioc, @@ -1510,34 +1922,43 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)  			if (!parent)  				goto next_port; +			expander_sas_address = +				port_info->phy_info[0].identify.sas_address; +  			/*  			 * Delete rphys in the parent that point  			 * to this expander.  The transport layer will  			 * cleanup all the children.  			 */ -			for (i = 0; i < parent->num_phys; i++) { -				if ((!parent->phy_info[i].rphy) || -				    (parent->phy_info[i].attached.sas_address != -				   port_info->phy_info[i].identify.sas_address)) +			phy_info = parent->phy_info; +			for (i = 0; i < parent->num_phys; i++, phy_info++) { +				port = mptsas_get_port(phy_info); +				if (!port) +					continue; +				if (phy_info->attached.sas_address != +					expander_sas_address)  					continue; -				sas_rphy_delete(parent->phy_info[i].rphy); -				memset(&parent->phy_info[i].attached, 0, -				    sizeof(struct mptsas_devinfo)); -				parent->phy_info[i].rphy = NULL; -				parent->phy_info[i].starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE +				dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif +				sas_port_delete(port); +				mptsas_port_delete(phy_info->port_details);  			}   next_port: + +			phy_info = port_info->phy_info; +			for (i = 0; i < port_info->num_phys; i++, phy_info++) +				mptsas_port_delete(phy_info->port_details); +  			list_del(&port_info->list); -			if (port_info->phy_info) -				kfree(port_info->phy_info); +			kfree(port_info->phy_info);  			kfree(port_info);  		}  		/*  		* Free this memory allocated from inside  		* mptsas_sas_expander_pg0  		*/ -		if (buffer.phy_info) -			kfree(buffer.phy_info); +		kfree(buffer.phy_info);  	}  	mutex_unlock(&ioc->sas_topology_mutex);  } @@ -1573,60 +1994,59 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)  /*   * Work queue thread to handle Runtime discovery   * Mere purpose is the hot add/delete of expanders + *(Mutex UNLOCKED)   */  static void -mptscsih_discovery_work(void * arg) +__mptsas_discovery_work(MPT_ADAPTER *ioc)  { -	struct mptsas_discovery_event *ev = arg; -	MPT_ADAPTER *ioc = ev->ioc;  	u32 handle = 0xFFFF; -	mutex_lock(&ioc->sas_discovery_mutex);  	ioc->sas_discovery_runtime=1;  	mptsas_delete_expander_phys(ioc);  	mptsas_probe_hba_phys(ioc);  	while (!mptsas_probe_expander_phys(ioc, &handle))  		; -	kfree(ev);  	ioc->sas_discovery_runtime=0; +} + +/* + * Work queue thread to handle Runtime discovery + * Mere purpose is the hot add/delete of expanders + *(Mutex LOCKED) + */ +static void +mptsas_discovery_work(void * arg) +{ +	struct mptsas_discovery_event *ev = arg; +	MPT_ADAPTER *ioc = ev->ioc; + +	mutex_lock(&ioc->sas_discovery_mutex); +	__mptsas_discovery_work(ioc);  	mutex_unlock(&ioc->sas_discovery_mutex); +	kfree(ev);  }  static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) +mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)  {  	struct mptsas_portinfo *port_info; -	struct mptsas_devinfo device_info;  	struct mptsas_phyinfo *phy_info = NULL; -	int i, error; - -	/* -	 * Retrieve the parent sas_address -	 */ -	error = mptsas_sas_device_pg0(ioc, &device_info, -		(MPI_SAS_DEVICE_PGAD_FORM_HANDLE << -		 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), -		parent_handle); -	if (error) -		return NULL; +	int i; -	/* -	 * The phy_info structures are never deallocated during lifetime of -	 * a host, so the code below is safe without additional refcounting. -	 */  	mutex_lock(&ioc->sas_topology_mutex);  	list_for_each_entry(port_info, &ioc->sas_topology, list) {  		for (i = 0; i < port_info->num_phys; i++) { -			if (port_info->phy_info[i].identify.sas_address == -			    device_info.sas_address && -			    port_info->phy_info[i].phy_id == phy_id) { -				phy_info = &port_info->phy_info[i]; -				break; -			} +			if (port_info->phy_info[i].attached.sas_address +			    != sas_address) +				continue; +			if (!mptsas_is_end_device( +				&port_info->phy_info[i].attached)) +				continue; +			phy_info = &port_info->phy_info[i]; +			break;  		}  	}  	mutex_unlock(&ioc->sas_topology_mutex); -  	return phy_info;  } @@ -1637,21 +2057,19 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)  	struct mptsas_phyinfo *phy_info = NULL;  	int i; -	/* -	 * The phy_info structures are never deallocated during lifetime of -	 * a host, so the code below is safe without additional refcounting. -	 */  	mutex_lock(&ioc->sas_topology_mutex);  	list_for_each_entry(port_info, &ioc->sas_topology, list) { -		for (i = 0; i < port_info->num_phys; i++) -			if (mptsas_is_end_device(&port_info->phy_info[i].attached)) -				if (port_info->phy_info[i].attached.id == id) { -					phy_info = &port_info->phy_info[i]; -					break; -				} +		for (i = 0; i < port_info->num_phys; i++) { +			if (port_info->phy_info[i].attached.id != id) +				continue; +			if (!mptsas_is_end_device( +				&port_info->phy_info[i].attached)) +				continue; +			phy_info = &port_info->phy_info[i]; +			break; +		}  	}  	mutex_unlock(&ioc->sas_topology_mutex); -  	return phy_info;  } @@ -1659,7 +2077,7 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)   * Work queue thread to clear the persitency table   */  static void -mptscsih_sas_persist_clear_table(void * arg) +mptsas_persist_clear_table(void * arg)  {  	MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; @@ -1680,7 +2098,6 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)  			mptsas_reprobe_lun);  } -  /*   * Work queue thread to handle SAS hotplug events   */ @@ -1691,14 +2108,17 @@ mptsas_hotplug_work(void *arg)  	MPT_ADAPTER *ioc = ev->ioc;  	struct mptsas_phyinfo *phy_info;  	struct sas_rphy *rphy; +	struct sas_port *port;  	struct scsi_device *sdev; +	struct scsi_target * starget;  	struct sas_identify identify;  	char *ds = NULL;  	struct mptsas_devinfo sas_device;  	VirtTarget *vtarget; +	VirtDevice *vdevice; -	mutex_lock(&ioc->sas_discovery_mutex); +	mutex_lock(&ioc->sas_discovery_mutex);  	switch (ev->event_type) {  	case MPTSAS_DEL_DEVICE: @@ -1707,24 +2127,50 @@ mptsas_hotplug_work(void *arg)  		/*  		 * Sanity checks, for non-existing phys and remote rphys.  		 */ -		if (!phy_info) +		if (!phy_info || !phy_info->port_details) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__));  			break; -		if (!phy_info->rphy) +		} +		rphy = mptsas_get_rphy(phy_info); +		if (!rphy) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__));  			break; -		if (phy_info->starget) { -			vtarget = phy_info->starget->hostdata; +		} +		port = mptsas_get_port(phy_info); +		if (!port) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__)); +			break; +		} -			if (!vtarget) +		starget = mptsas_get_starget(phy_info); +		if (starget) { +			vtarget = starget->hostdata; + +			if (!vtarget) { +				dfailprintk((MYIOC_s_ERR_FMT +					"%s: exit at line=%d\n", ioc->name, +					__FUNCTION__, __LINE__));  				break; +			} +  			/*  			 * Handling  RAID components  			 */  			if (ev->phys_disk_num_valid) {  				vtarget->target_id = ev->phys_disk_num;  				vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; -				mptsas_reprobe_target(vtarget->starget, 1); +				mptsas_reprobe_target(starget, 1);  				break;  			} + +			vtarget->deleted = 1; +			mptsas_target_reset(ioc, vtarget);  		}  		if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) @@ -1738,10 +2184,11 @@ mptsas_hotplug_work(void *arg)  		       "removing %s device, channel %d, id %d, phy %d\n",  		       ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); -		sas_rphy_delete(phy_info->rphy); -		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); -		phy_info->rphy = NULL; -		phy_info->starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE +		dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif +		sas_port_delete(port); +		mptsas_port_delete(phy_info->port_details);  		break;  	case MPTSAS_ADD_DEVICE: @@ -1753,59 +2200,60 @@ mptsas_hotplug_work(void *arg)  		 */  		if (mptsas_sas_device_pg0(ioc, &sas_device,  		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << -		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) +		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) { +				dfailprintk((MYIOC_s_ERR_FMT +					"%s: exit at line=%d\n", ioc->name, +					__FUNCTION__, __LINE__));  			break; +		} -		phy_info = mptsas_find_phyinfo_by_parent(ioc, -				sas_device.handle_parent, sas_device.phy_id); +		ssleep(2); +		__mptsas_discovery_work(ioc); -		if (!phy_info) { -			u32 handle = 0xFFFF; +		phy_info = mptsas_find_phyinfo_by_sas_address(ioc, +				sas_device.sas_address); -			/* -			* Its possible when an expander has been hot added -			* containing attached devices, the sas firmware -			* may send a RC_ADDED event prior to the -			* DISCOVERY STOP event. If that occurs, our -			* view of the topology in the driver in respect to this -			* expander might of not been setup, and we hit this -			* condition. -			* Therefore, this code kicks off discovery to -			* refresh the data. -			* Then again, we check whether the parent phy has -			* been created. -			*/ -			ioc->sas_discovery_runtime=1; -			mptsas_delete_expander_phys(ioc); -			mptsas_probe_hba_phys(ioc); -			while (!mptsas_probe_expander_phys(ioc, &handle)) -				; -			ioc->sas_discovery_runtime=0; - -			phy_info = mptsas_find_phyinfo_by_parent(ioc, -				sas_device.handle_parent, sas_device.phy_id); -			if (!phy_info) -				break; +		if (!phy_info || !phy_info->port_details) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__)); +			break;  		} -		if (phy_info->starget) { -			vtarget = phy_info->starget->hostdata; +		starget = mptsas_get_starget(phy_info); +		if (starget) { +			vtarget = starget->hostdata; -			if (!vtarget) +			if (!vtarget) { +				dfailprintk((MYIOC_s_ERR_FMT +					"%s: exit at line=%d\n", ioc->name, +				       	__FUNCTION__, __LINE__));  				break; +			}  			/*  			 * Handling  RAID components  			 */  			if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {  				vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;  				vtarget->target_id = ev->id; -				mptsas_reprobe_target(phy_info->starget, 0); +				mptsas_reprobe_target(starget, 0);  			}  			break;  		} -		if (phy_info->rphy) +		if (mptsas_get_rphy(phy_info)) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__));  			break; +		} +		port = mptsas_get_port(phy_info); +		if (!port) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__)); +			break; +		}  		memcpy(&phy_info->attached, &sas_device,  		    sizeof(struct mptsas_devinfo)); @@ -1822,28 +2270,23 @@ mptsas_hotplug_work(void *arg)  		       ioc->name, ds, ev->channel, ev->id, ev->phy_id);  		mptsas_parse_device_info(&identify, &phy_info->attached); -		switch (identify.device_type) { -		case SAS_END_DEVICE: -			rphy = sas_end_device_alloc(phy_info->phy); -			break; -		case SAS_EDGE_EXPANDER_DEVICE: -		case SAS_FANOUT_EXPANDER_DEVICE: -			rphy = sas_expander_alloc(phy_info->phy, identify.device_type); -			break; -		default: -			rphy = NULL; -			break; -		} -		if (!rphy) +		rphy = sas_end_device_alloc(port); +		if (!rphy) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__));  			break; /* non-fatal: an rphy can be added later */ +		}  		rphy->identify = identify;  		if (sas_rphy_add(rphy)) { +			dfailprintk((MYIOC_s_ERR_FMT +				"%s: exit at line=%d\n", ioc->name, +			       	__FUNCTION__, __LINE__));  			sas_rphy_free(rphy);  			break;  		} - -		phy_info->rphy = rphy; +		mptsas_set_rphy(phy_info, rphy);  		break;  	case MPTSAS_ADD_RAID:  		sdev = scsi_device_lookup( @@ -1875,6 +2318,9 @@ mptsas_hotplug_work(void *arg)  		printk(MYIOC_s_INFO_FMT  		       "removing raid volume, channel %d, id %d\n",  		       ioc->name, ioc->num_ports, ev->id); +		vdevice = sdev->hostdata; +		vdevice->vtarget->deleted = 1; +		mptsas_target_reset(ioc, vdevice->vtarget);  		scsi_remove_device(sdev);  		scsi_device_put(sdev);  		mpt_findImVolumes(ioc); @@ -1884,12 +2330,13 @@ mptsas_hotplug_work(void *arg)  		break;  	} -	kfree(ev);  	mutex_unlock(&ioc->sas_discovery_mutex); +	kfree(ev); +  }  static void -mptscsih_send_sas_event(MPT_ADAPTER *ioc, +mptsas_send_sas_event(MPT_ADAPTER *ioc,  		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)  {  	struct mptsas_hotplug_event *ev; @@ -1905,7 +2352,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,  	switch (sas_event_data->ReasonCode) {  	case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:  	case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: -		ev = kmalloc(sizeof(*ev), GFP_ATOMIC); +		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);  		if (!ev) {  			printk(KERN_WARNING "mptsas: lost hotplug event\n");  			break; @@ -1935,10 +2382,9 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,  	/*  	 * Persistent table is full.  	 */ -		INIT_WORK(&ioc->mptscsih_persistTask, -		    mptscsih_sas_persist_clear_table, -		    (void *)ioc); -		schedule_work(&ioc->mptscsih_persistTask); +		INIT_WORK(&ioc->sas_persist_task, +		    mptsas_persist_clear_table, (void *)ioc); +		schedule_work(&ioc->sas_persist_task);  		break;  	case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:  	/* TODO */ @@ -1950,7 +2396,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,  }  static void -mptscsih_send_raid_event(MPT_ADAPTER *ioc, +mptsas_send_raid_event(MPT_ADAPTER *ioc,  		EVENT_DATA_RAID *raid_event_data)  {  	struct mptsas_hotplug_event *ev; @@ -1960,13 +2406,12 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,  	if (ioc->bus_type != SAS)  		return; -	ev = kmalloc(sizeof(*ev), GFP_ATOMIC); +	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);  	if (!ev) {  		printk(KERN_WARNING "mptsas: lost hotplug event\n");  		return;  	} -	memset(ev,0,sizeof(struct mptsas_hotplug_event));  	INIT_WORK(&ev->work, mptsas_hotplug_work, ev);  	ev->ioc = ioc;  	ev->id = raid_event_data->VolumeID; @@ -2028,7 +2473,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,  }  static void -mptscsih_send_discovery(MPT_ADAPTER *ioc, +mptsas_send_discovery_event(MPT_ADAPTER *ioc,  	EVENT_DATA_SAS_DISCOVERY *discovery_data)  {  	struct mptsas_discovery_event *ev; @@ -2043,11 +2488,10 @@ mptscsih_send_discovery(MPT_ADAPTER *ioc,  	if (discovery_data->DiscoveryStatus)  		return; -	ev = kmalloc(sizeof(*ev), GFP_ATOMIC); +	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);  	if (!ev)  		return; -	memset(ev,0,sizeof(struct mptsas_discovery_event)); -	INIT_WORK(&ev->work, mptscsih_discovery_work, ev); +	INIT_WORK(&ev->work, mptsas_discovery_work, ev);  	ev->ioc = ioc;  	schedule_work(&ev->work);  }; @@ -2075,21 +2519,21 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)  	switch (event) {  	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: -		mptscsih_send_sas_event(ioc, +		mptsas_send_sas_event(ioc,  			(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);  		break;  	case MPI_EVENT_INTEGRATED_RAID: -		mptscsih_send_raid_event(ioc, +		mptsas_send_raid_event(ioc,  			(EVENT_DATA_RAID *)reply->Data);  		break;  	case MPI_EVENT_PERSISTENT_TABLE_FULL: -		INIT_WORK(&ioc->mptscsih_persistTask, -		    mptscsih_sas_persist_clear_table, +		INIT_WORK(&ioc->sas_persist_task, +		    mptsas_persist_clear_table,  		    (void *)ioc); -		schedule_work(&ioc->mptscsih_persistTask); +		schedule_work(&ioc->sas_persist_task);  		break;  	 case MPI_EVENT_SAS_DISCOVERY: -		mptscsih_send_discovery(ioc, +		mptsas_send_discovery_event(ioc,  			(EVENT_DATA_SAS_DISCOVERY *)reply->Data);  		break;  	default: @@ -2308,7 +2752,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	return 0; -out_mptsas_probe: + out_mptsas_probe:  	mptscsih_remove(pdev);  	return error; @@ -2318,6 +2762,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)  {  	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);  	struct mptsas_portinfo *p, *n; +	int i;  	ioc->sas_discovery_ignore_events=1;  	sas_remove_host(ioc->sh); @@ -2325,8 +2770,9 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)  	mutex_lock(&ioc->sas_topology_mutex);  	list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {  		list_del(&p->list); -		if (p->phy_info) -			kfree(p->phy_info); +		for (i = 0 ; i < p->num_phys ; i++) +			mptsas_port_delete(p->phy_info[i].port_details); +		kfree(p->phy_info);  		kfree(p);  	}  	mutex_unlock(&ioc->sas_topology_mutex); @@ -2335,17 +2781,15 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)  }  static struct pci_device_id mptsas_pci_table[] = { -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064, -		PCI_ANY_ID, PCI_ANY_ID }, -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066, +	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,  		PCI_ANY_ID, PCI_ANY_ID }, -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068, +	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,  		PCI_ANY_ID, PCI_ANY_ID }, -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E, +	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,  		PCI_ANY_ID, PCI_ANY_ID }, -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E, +	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,  		PCI_ANY_ID, PCI_ANY_ID }, -	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E, +	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,  		PCI_ANY_ID, PCI_ANY_ID },  	{0}	/* Terminating entry */  }; | 
