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

Commit 6223a39f authored by Raghava Aditya Renukunta's avatar Raghava Aditya Renukunta Committed by Martin K. Petersen
Browse files

scsi: aacraid: Added support for hotplug



Added support for drive hotplug add and removal

Signed-off-by: default avatarRaghava Aditya Renukunta <RaghavaAditya.Renukunta@microsemi.com>
Signed-off-by: default avatarDave Carroll <David.Carroll@microsemi.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent a052865f
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -1595,7 +1595,7 @@ int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target)
 *	Update our hba map with the information gathered from the FW
 */
void aac_update_hba_map(struct aac_dev *dev,
		struct aac_ciss_phys_luns_resp *phys_luns)
		struct aac_ciss_phys_luns_resp *phys_luns, int rescan)
{
	/* ok and extended reporting */
	u32 lun_count, nexus;
@@ -1640,7 +1640,10 @@ void aac_update_hba_map(struct aac_dev *dev,
			dev->hba_map[bus][target].qd_limit = 32;

update_devtype:
		if (rescan == AAC_INIT)
			dev->hba_map[bus][target].devtype = devtype;
		else
			dev->hba_map[bus][target].new_devtype = devtype;
	}
}

@@ -1652,7 +1655,7 @@ void aac_update_hba_map(struct aac_dev *dev,
 *	Execute a CISS REPORT PHYS LUNS and process the results into
 *	the current hba_map.
 */
int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr)
int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan)
{
	int fibsize, datasize;
	struct aac_ciss_phys_luns_resp *phys_luns;
@@ -1712,7 +1715,7 @@ int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr)
	/* analyse data */
	if (rcode >= 0 && phys_luns->resp_flag == 2) {
		/* ok and extended reporting */
		aac_update_hba_map(dev, phys_luns);
		aac_update_hba_map(dev, phys_luns, rescan);
	}

	pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr);
@@ -1825,7 +1828,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
	if (!dev->sync_mode && dev->sa_firmware &&
			dev->supplement_adapter_info.VirtDeviceBus != 0xffff) {
		/* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
		rcode = aac_report_phys_luns(dev, fibptr);
		rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT);
	}

	if (!dev->in_reset) {
+15 −2
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ enum {
#define AAC_NUM_IO_FIB		(1024 - AAC_NUM_MGT_FIB)
#define AAC_NUM_FIB		(AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB)

#define AAC_MAX_LUN		(256)
#define AAC_MAX_LUN		256

#define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
#define AAC_MAX_32BIT_SGBCOUNT	((unsigned short)256)
@@ -87,6 +87,14 @@ enum {
#define AAC_MAX_TARGETS		256
#define AAC_MAX_NATIVE_SIZE		2048

/* Thor AIF events */
#define SA_AIF_HOTPLUG			(1<<1)
#define SA_AIF_HARDWARE		(1<<2)
#define SA_AIF_PDEV_CHANGE		(1<<4)
#define SA_AIF_LDEV_CHANGE		(1<<5)
#define SA_AIF_BPSTAT_CHANGE		(1<<30)
#define SA_AIF_BPCFG_CHANGE		(1<<31)

#define CISS_REPORT_PHYSICAL_LUNS	0xc3
#define WRITE_HOST_WELLNESS		0xa5
#define CISS_IDENTIFY_PHYSICAL_DEVICE	0x15
@@ -194,6 +202,7 @@ struct aac_ciss_identify_pd {
#define CONTAINER_TO_CHANNEL(cont)	(CONTAINER_CHANNEL)
#define CONTAINER_TO_ID(cont)		(cont)
#define CONTAINER_TO_LUN(cont)		(0)
#define ENCLOSURE_CHANNEL		(3)

#define PMC_DEVICE_S6	0x28b
#define PMC_DEVICE_S7	0x28c
@@ -1098,6 +1107,9 @@ struct fib {
	u32			hbacmd_size;	/* cmd size for native */
};

#define AAC_INIT			0
#define AAC_RESCAN			1

#define AAC_DEVTYPE_RAID_MEMBER	1
#define AAC_DEVTYPE_ARC_RAW		2
#define AAC_DEVTYPE_NATIVE_RAW		3
@@ -1107,6 +1119,7 @@ struct fib {
struct aac_hba_map_info {
	__le32	rmw_nexus;		/* nexus for native HBA devices */
	u8		devtype;	/* device type */
	u8		new_devtype;
	u8		reset_state;	/* 0 - no reset, 1..x - */
					/* after xth TM LUN reset */
	u16		qd_limit;
@@ -2317,7 +2330,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)

int aac_acquire_irq(struct aac_dev *dev);
void aac_free_irq(struct aac_dev *dev);
int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr);
int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan);
int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target);
const char *aac_driverinfo(struct Scsi_Host *);
void aac_fib_vector_assign(struct aac_dev *dev);
+137 −0
Original line number Diff line number Diff line
@@ -1730,6 +1730,137 @@ int aac_check_health(struct aac_dev * aac)
	return BlinkLED;
}


static void aac_resolve_luns(struct aac_dev *dev)
{
	int bus, target, channel;
	struct scsi_device *sdev;
	u8 devtype;
	u8 new_devtype;

	for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
		for (target = 0; target < AAC_MAX_TARGETS; target++) {

			if (aac_phys_to_logical(bus) == ENCLOSURE_CHANNEL)
				continue;

			if (bus == CONTAINER_CHANNEL)
				channel = CONTAINER_CHANNEL;
			else
				channel = aac_phys_to_logical(bus);

			devtype = dev->hba_map[bus][target].devtype;
			new_devtype = dev->hba_map[bus][target].new_devtype;

			sdev = scsi_device_lookup(dev->scsi_host_ptr, channel,
					target, 0);

			if (!sdev && devtype)
				scsi_add_device(dev->scsi_host_ptr, channel,
						target, 0);
			else if (sdev && new_devtype != devtype)
				scsi_remove_device(sdev);
			else if (sdev && new_devtype == devtype)
				scsi_rescan_device(&sdev->sdev_gendev);

			if (sdev)
				scsi_device_put(sdev);

			dev->hba_map[bus][target].devtype = new_devtype;
		}
	}
}

/**
 *	aac_handle_sa_aif	Handle a message from the firmware
 *	@dev: Which adapter this fib is from
 *	@fibptr: Pointer to fibptr from adapter
 *
 *	This routine handles a driver notify fib from the adapter and
 *	dispatches it to the appropriate routine for handling.
 */
static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr)
{
	int i, bus, target, container, rcode = 0;
	u32 events = 0;
	struct fib *fib;
	struct scsi_device *sdev;

	if (fibptr->hbacmd_size & SA_AIF_HOTPLUG)
		events = SA_AIF_HOTPLUG;
	else if (fibptr->hbacmd_size & SA_AIF_HARDWARE)
		events = SA_AIF_HARDWARE;
	else if (fibptr->hbacmd_size & SA_AIF_PDEV_CHANGE)
		events = SA_AIF_PDEV_CHANGE;
	else if (fibptr->hbacmd_size & SA_AIF_LDEV_CHANGE)
		events = SA_AIF_LDEV_CHANGE;
	else if (fibptr->hbacmd_size & SA_AIF_BPSTAT_CHANGE)
		events = SA_AIF_BPSTAT_CHANGE;
	else if (fibptr->hbacmd_size & SA_AIF_BPCFG_CHANGE)
		events = SA_AIF_BPCFG_CHANGE;

	switch (events) {
	case SA_AIF_HOTPLUG:
	case SA_AIF_HARDWARE:
	case SA_AIF_PDEV_CHANGE:
	case SA_AIF_LDEV_CHANGE:
	case SA_AIF_BPCFG_CHANGE:

		fib = aac_fib_alloc(dev);
		if (!fib) {
			pr_err("aac_handle_sa_aif: out of memory\n");
			return;
		}
		for (bus = 0; bus < AAC_MAX_BUSES; bus++)
			for (target = 0; target < AAC_MAX_TARGETS; target++)
				dev->hba_map[bus][target].new_devtype = 0;

		rcode = aac_report_phys_luns(dev, fib, AAC_RESCAN);

		if (rcode != -ERESTARTSYS)
			aac_fib_free(fib);

		aac_resolve_luns(dev);

		if (events == SA_AIF_LDEV_CHANGE ||
		    events == SA_AIF_BPCFG_CHANGE) {
			aac_get_containers(dev);
			for (container = 0; container <
			dev->maximum_num_containers; ++container) {
				sdev = scsi_device_lookup(dev->scsi_host_ptr,
						CONTAINER_CHANNEL,
						container, 0);
				if (dev->fsa_dev[container].valid && !sdev) {
					scsi_add_device(dev->scsi_host_ptr,
						CONTAINER_CHANNEL,
						container, 0);
				} else if (!dev->fsa_dev[container].valid &&
					sdev) {
					scsi_remove_device(sdev);
					scsi_device_put(sdev);
				} else if (sdev) {
					scsi_rescan_device(&sdev->sdev_gendev);
					scsi_device_put(sdev);
				}
			}
		}
		break;

	case SA_AIF_BPSTAT_CHANGE:
		/* currently do nothing */
		break;
	}

	for (i = 1; i <= 10; ++i) {
		events = src_readl(dev, MUnit.IDR);
		if (events & (1<<23)) {
			pr_warn(" AIF not cleared by firmware - %d/%d)\n",
				i, 10);
			ssleep(1);
		}
	}
}

static int get_fib_count(struct aac_dev *dev)
{
	unsigned int num = 0;
@@ -1913,6 +2044,12 @@ static void aac_process_events(struct aac_dev *dev)

		fib = list_entry(entry, struct fib, fiblink);
		hw_fib = fib->hw_fib_va;
		if (dev->sa_firmware) {
			/* Thor AIF */
			aac_handle_sa_aif(dev, fib);
			aac_fib_adapter_complete(fib, (u16)sizeof(u32));
			continue;
		}
		/*
		 *	We will process the FIB here or pass it to a
		 *	worker thread that is TBD. We Really can't