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

Commit 27387dd8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-20130409' of git://git.kernel.dk/linux-block

Pull block fixes from Jens Axboe:
 "I've got a few smaller fixes queued up for 3.9 that should go in.  The
  major one is the loop regression, the others are nice fixes on their
  own though.  It contains:

   - Fix for unitialized var in the block sysfs code, courtesy of Arnd
     and gcc-4.8.

   - Two fixes for mtip32xx, fixing probe and command timeout.  Also a
     debug measure that could have waited for 3.10, but it's driver
     only, so I let it slip in.

   - Revert the loop partition cleanup fix, it could cause a deadlock on
     auto-teardown as part of umount.  The fix is clear, but at this
     point we just want to revert it and get a real fix in for 3.10."

* tag 'for-linus-20130409' of git://git.kernel.dk/linux-block:
  Revert "loop: cleanup partitions when detaching loop device"
  mtip32xx: fix two smatch warnings
  mtip32xx: Add debugfs entry device_status
  mtip32xx: return 0 from pci probe in case of rebuild
  mtip32xx: recovery from command timeout
  block: avoid using uninitialized value in from queue_var_store
parents 386afc91 c2fccc1c
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -229,6 +229,8 @@ queue_store_##name(struct request_queue *q, const char *page, size_t count) \
	unsigned long val;						\
	unsigned long val;						\
	ssize_t ret;							\
	ssize_t ret;							\
	ret = queue_var_store(&val, page, count);			\
	ret = queue_var_store(&val, page, count);			\
	if (ret < 0)							\
		 return ret;						\
	if (neg)							\
	if (neg)							\
		val = !val;						\
		val = !val;						\
									\
									\
+0 −1
Original line number Original line Diff line number Diff line
@@ -257,7 +257,6 @@ void delete_partition(struct gendisk *disk, int partno)


	hd_struct_put(part);
	hd_struct_put(part);
}
}
EXPORT_SYMBOL(delete_partition);


static ssize_t whole_disk_show(struct device *dev,
static ssize_t whole_disk_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
			       struct device_attribute *attr, char *buf)
+2 −19
Original line number Original line Diff line number Diff line
@@ -1051,29 +1051,12 @@ static int loop_clr_fd(struct loop_device *lo)
	lo->lo_state = Lo_unbound;
	lo->lo_state = Lo_unbound;
	/* This is safe: open() is still holding a reference. */
	/* This is safe: open() is still holding a reference. */
	module_put(THIS_MODULE);
	module_put(THIS_MODULE);
	if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev)
		ioctl_by_bdev(bdev, BLKRRPART, 0);
	lo->lo_flags = 0;
	lo->lo_flags = 0;
	if (!part_shift)
	if (!part_shift)
		lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
		lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
	mutex_unlock(&lo->lo_ctl_mutex);
	mutex_unlock(&lo->lo_ctl_mutex);

	/*
	 * Remove all partitions, since BLKRRPART won't remove user
	 * added partitions when max_part=0
	 */
	if (bdev) {
		struct disk_part_iter piter;
		struct hd_struct *part;

		mutex_lock_nested(&bdev->bd_mutex, 1);
		invalidate_partition(bdev->bd_disk, 0);
		disk_part_iter_init(&piter, bdev->bd_disk,
					DISK_PITER_INCL_EMPTY);
		while ((part = disk_part_iter_next(&piter)))
			delete_partition(bdev->bd_disk, part->partno);
		disk_part_iter_exit(&piter);
		mutex_unlock(&bdev->bd_mutex);
	}

	/*
	/*
	 * Need not hold lo_ctl_mutex to fput backing file.
	 * Need not hold lo_ctl_mutex to fput backing file.
	 * Calling fput holding lo_ctl_mutex triggers a circular
	 * Calling fput holding lo_ctl_mutex triggers a circular
+232 −95
Original line number Original line Diff line number Diff line
@@ -81,12 +81,17 @@
/* Device instance number, incremented each time a device is probed. */
/* Device instance number, incremented each time a device is probed. */
static int instance;
static int instance;


struct list_head online_list;
struct list_head removing_list;
spinlock_t dev_lock;

/*
/*
 * Global variable used to hold the major block device number
 * Global variable used to hold the major block device number
 * allocated in mtip_init().
 * allocated in mtip_init().
 */
 */
static int mtip_major;
static int mtip_major;
static struct dentry *dfs_parent;
static struct dentry *dfs_parent;
static struct dentry *dfs_device_status;


static u32 cpu_use[NR_CPUS];
static u32 cpu_use[NR_CPUS];


@@ -243,41 +248,32 @@ static inline void release_slot(struct mtip_port *port, int tag)
/*
/*
 * Reset the HBA (without sleeping)
 * Reset the HBA (without sleeping)
 *
 *
 * Just like hba_reset, except does not call sleep, so can be
 * run from interrupt/tasklet context.
 *
 * @dd Pointer to the driver data structure.
 * @dd Pointer to the driver data structure.
 *
 *
 * return value
 * return value
 *	0	The reset was successful.
 *	0	The reset was successful.
 *	-1	The HBA Reset bit did not clear.
 *	-1	The HBA Reset bit did not clear.
 */
 */
static int hba_reset_nosleep(struct driver_data *dd)
static int mtip_hba_reset(struct driver_data *dd)
{
{
	unsigned long timeout;
	unsigned long timeout;


	/* Chip quirk: quiesce any chip function */
	mdelay(10);

	/* Set the reset bit */
	/* Set the reset bit */
	writel(HOST_RESET, dd->mmio + HOST_CTL);
	writel(HOST_RESET, dd->mmio + HOST_CTL);


	/* Flush */
	/* Flush */
	readl(dd->mmio + HOST_CTL);
	readl(dd->mmio + HOST_CTL);


	/*
	/* Spin for up to 2 seconds, waiting for reset acknowledgement */
	 * Wait 10ms then spin for up to 1 second
	timeout = jiffies + msecs_to_jiffies(2000);
	 * waiting for reset acknowledgement
	do {
	 */
	timeout = jiffies + msecs_to_jiffies(1000);
		mdelay(10);
		mdelay(10);
	while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
		 && time_before(jiffies, timeout))
		mdelay(1);

		if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
		if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
			return -1;
			return -1;


	} while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
		 && time_before(jiffies, timeout));

	if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
	if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
		return -1;
		return -1;


@@ -481,7 +477,7 @@ static void mtip_restart_port(struct mtip_port *port)
		dev_warn(&port->dd->pdev->dev,
		dev_warn(&port->dd->pdev->dev,
			"PxCMD.CR not clear, escalating reset\n");
			"PxCMD.CR not clear, escalating reset\n");


		if (hba_reset_nosleep(port->dd))
		if (mtip_hba_reset(port->dd))
			dev_err(&port->dd->pdev->dev,
			dev_err(&port->dd->pdev->dev,
				"HBA reset escalation failed.\n");
				"HBA reset escalation failed.\n");


@@ -527,6 +523,26 @@ static void mtip_restart_port(struct mtip_port *port)


}
}


static int mtip_device_reset(struct driver_data *dd)
{
	int rv = 0;

	if (mtip_check_surprise_removal(dd->pdev))
		return 0;

	if (mtip_hba_reset(dd) < 0)
		rv = -EFAULT;

	mdelay(1);
	mtip_init_port(dd->port);
	mtip_start_port(dd->port);

	/* Enable interrupts on the HBA. */
	writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN,
					dd->mmio + HOST_CTL);
	return rv;
}

/*
/*
 * Helper function for tag logging
 * Helper function for tag logging
 */
 */
@@ -632,7 +648,7 @@ static void mtip_timeout_function(unsigned long int data)
	if (cmdto_cnt) {
	if (cmdto_cnt) {
		print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);
		print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);
		if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
		if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
			mtip_restart_port(port);
			mtip_device_reset(port->dd);
			wake_up_interruptible(&port->svc_wait);
			wake_up_interruptible(&port->svc_wait);
		}
		}
		clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
		clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
@@ -1283,11 +1299,11 @@ static int mtip_exec_internal_command(struct mtip_port *port,
	int rv = 0, ready2go = 1;
	int rv = 0, ready2go = 1;
	struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL];
	struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL];
	unsigned long to;
	unsigned long to;
	struct driver_data *dd = port->dd;


	/* Make sure the buffer is 8 byte aligned. This is asic specific. */
	/* Make sure the buffer is 8 byte aligned. This is asic specific. */
	if (buffer & 0x00000007) {
	if (buffer & 0x00000007) {
		dev_err(&port->dd->pdev->dev,
		dev_err(&dd->pdev->dev, "SG buffer is not 8 byte aligned\n");
			"SG buffer is not 8 byte aligned\n");
		return -EFAULT;
		return -EFAULT;
	}
	}


@@ -1300,23 +1316,21 @@ static int mtip_exec_internal_command(struct mtip_port *port,
		mdelay(100);
		mdelay(100);
	} while (time_before(jiffies, to));
	} while (time_before(jiffies, to));
	if (!ready2go) {
	if (!ready2go) {
		dev_warn(&port->dd->pdev->dev,
		dev_warn(&dd->pdev->dev,
			"Internal cmd active. new cmd [%02X]\n", fis->command);
			"Internal cmd active. new cmd [%02X]\n", fis->command);
		return -EBUSY;
		return -EBUSY;
	}
	}
	set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
	set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
	port->ic_pause_timer = 0;
	port->ic_pause_timer = 0;


	if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
	clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
	clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
	else if (fis->command == ATA_CMD_DOWNLOAD_MICRO)
	clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
	clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);


	if (atomic == GFP_KERNEL) {
	if (atomic == GFP_KERNEL) {
		if (fis->command != ATA_CMD_STANDBYNOW1) {
		if (fis->command != ATA_CMD_STANDBYNOW1) {
			/* wait for io to complete if non atomic */
			/* wait for io to complete if non atomic */
			if (mtip_quiesce_io(port, 5000) < 0) {
			if (mtip_quiesce_io(port, 5000) < 0) {
				dev_warn(&port->dd->pdev->dev,
				dev_warn(&dd->pdev->dev,
					"Failed to quiesce IO\n");
					"Failed to quiesce IO\n");
				release_slot(port, MTIP_TAG_INTERNAL);
				release_slot(port, MTIP_TAG_INTERNAL);
				clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
				clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
@@ -1361,58 +1375,84 @@ static int mtip_exec_internal_command(struct mtip_port *port,
	/* Issue the command to the hardware */
	/* Issue the command to the hardware */
	mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);
	mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);


	/* Poll if atomic, wait_for_completion otherwise */
	if (atomic == GFP_KERNEL) {
	if (atomic == GFP_KERNEL) {
		/* Wait for the command to complete or timeout. */
		/* Wait for the command to complete or timeout. */
		if (wait_for_completion_timeout(
		if (wait_for_completion_interruptible_timeout(
				&wait,
				&wait,
				msecs_to_jiffies(timeout)) == 0) {
				msecs_to_jiffies(timeout)) <= 0) {
			dev_err(&port->dd->pdev->dev,
			if (rv == -ERESTARTSYS) { /* interrupted */
				"Internal command did not complete [%d] "
				dev_err(&dd->pdev->dev,
				"within timeout of  %lu ms\n",
					"Internal command [%02X] was interrupted after %lu ms\n",
				atomic, timeout);
					fis->command, timeout);
			if (mtip_check_surprise_removal(port->dd->pdev) ||
				rv = -EINTR;
				goto exec_ic_exit;
			} else if (rv == 0) /* timeout */
				dev_err(&dd->pdev->dev,
					"Internal command did not complete [%02X] within timeout of  %lu ms\n",
					fis->command, timeout);
			else
				dev_err(&dd->pdev->dev,
					"Internal command [%02X] wait returned code [%d] after %lu ms - unhandled\n",
					fis->command, rv, timeout);

			if (mtip_check_surprise_removal(dd->pdev) ||
				test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
				test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
						&port->dd->dd_flag)) {
						&dd->dd_flag)) {
				dev_err(&dd->pdev->dev,
					"Internal command [%02X] wait returned due to SR\n",
					fis->command);
				rv = -ENXIO;
				rv = -ENXIO;
				goto exec_ic_exit;
				goto exec_ic_exit;
			}
			}
			mtip_device_reset(dd); /* recover from timeout issue */
			rv = -EAGAIN;
			rv = -EAGAIN;
			goto exec_ic_exit;
		}
		}
	} else {
	} else {
		u32 hba_stat, port_stat;

		/* Spin for <timeout> checking if command still outstanding */
		/* Spin for <timeout> checking if command still outstanding */
		timeout = jiffies + msecs_to_jiffies(timeout);
		timeout = jiffies + msecs_to_jiffies(timeout);
		while ((readl(port->cmd_issue[MTIP_TAG_INTERNAL])
		while ((readl(port->cmd_issue[MTIP_TAG_INTERNAL])
				& (1 << MTIP_TAG_INTERNAL))
				& (1 << MTIP_TAG_INTERNAL))
				&& time_before(jiffies, timeout)) {
				&& time_before(jiffies, timeout)) {
			if (mtip_check_surprise_removal(port->dd->pdev)) {
			if (mtip_check_surprise_removal(dd->pdev)) {
				rv = -ENXIO;
				rv = -ENXIO;
				goto exec_ic_exit;
				goto exec_ic_exit;
			}
			}
			if ((fis->command != ATA_CMD_STANDBYNOW1) &&
			if ((fis->command != ATA_CMD_STANDBYNOW1) &&
				test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
				test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
						&port->dd->dd_flag)) {
						&dd->dd_flag)) {
				rv = -ENXIO;
				rv = -ENXIO;
				goto exec_ic_exit;
				goto exec_ic_exit;
			}
			}
			if (readl(port->mmio + PORT_IRQ_STAT) & PORT_IRQ_ERR) {
			port_stat = readl(port->mmio + PORT_IRQ_STAT);
				atomic_inc(&int_cmd->active); /* error */
			if (!port_stat)
				break;
				continue;

			if (port_stat & PORT_IRQ_ERR) {
				dev_err(&dd->pdev->dev,
					"Internal command [%02X] failed\n",
					fis->command);
				mtip_device_reset(dd);
				rv = -EIO;
				goto exec_ic_exit;
			} else {
				writel(port_stat, port->mmio + PORT_IRQ_STAT);
				hba_stat = readl(dd->mmio + HOST_IRQ_STAT);
				if (hba_stat)
					writel(hba_stat,
						dd->mmio + HOST_IRQ_STAT);
			}
			}
			break;
		}
		}
	}
	}


	if (atomic_read(&int_cmd->active) > 1) {
		dev_err(&port->dd->pdev->dev,
			"Internal command [%02X] failed\n", fis->command);
		rv = -EIO;
	}
	if (readl(port->cmd_issue[MTIP_TAG_INTERNAL])
	if (readl(port->cmd_issue[MTIP_TAG_INTERNAL])
			& (1 << MTIP_TAG_INTERNAL)) {
			& (1 << MTIP_TAG_INTERNAL)) {
		rv = -ENXIO;
		rv = -ENXIO;
		if (!test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
		if (!test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) {
					&port->dd->dd_flag)) {
			mtip_device_reset(dd);
			mtip_restart_port(port);
			rv = -EAGAIN;
			rv = -EAGAIN;
		}
		}
	}
	}
@@ -1724,7 +1764,8 @@ static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id,
 *      -EINVAL		Invalid parameters passed in, trim not supported
 *      -EINVAL		Invalid parameters passed in, trim not supported
 *      -EIO		Error submitting trim request to hw
 *      -EIO		Error submitting trim request to hw
 */
 */
static int mtip_send_trim(struct driver_data *dd, unsigned int lba, unsigned int len)
static int mtip_send_trim(struct driver_data *dd, unsigned int lba,
				unsigned int len)
{
{
	int i, rv = 0;
	int i, rv = 0;
	u64 tlba, tlen, sect_left;
	u64 tlba, tlen, sect_left;
@@ -1810,45 +1851,6 @@ static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors)
	return (bool) !!port->identify_valid;
	return (bool) !!port->identify_valid;
}
}


/*
 * Reset the HBA.
 *
 * Resets the HBA by setting the HBA Reset bit in the Global
 * HBA Control register. After setting the HBA Reset bit the
 * function waits for 1 second before reading the HBA Reset
 * bit to make sure it has cleared. If HBA Reset is not clear
 * an error is returned. Cannot be used in non-blockable
 * context.
 *
 * @dd Pointer to the driver data structure.
 *
 * return value
 *	0  The reset was successful.
 *	-1 The HBA Reset bit did not clear.
 */
static int mtip_hba_reset(struct driver_data *dd)
{
	mtip_deinit_port(dd->port);

	/* Set the reset bit */
	writel(HOST_RESET, dd->mmio + HOST_CTL);

	/* Flush */
	readl(dd->mmio + HOST_CTL);

	/* Wait for reset to clear */
	ssleep(1);

	/* Check the bit has cleared */
	if (readl(dd->mmio + HOST_CTL) & HOST_RESET) {
		dev_err(&dd->pdev->dev,
			"Reset bit did not clear.\n");
		return -1;
	}

	return 0;
}

/*
/*
 * Display the identify command data.
 * Display the identify command data.
 *
 *
@@ -2710,6 +2712,100 @@ static ssize_t mtip_hw_show_status(struct device *dev,


static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);


/* debugsfs entries */

static ssize_t show_device_status(struct device_driver *drv, char *buf)
{
	int size = 0;
	struct driver_data *dd, *tmp;
	unsigned long flags;
	char id_buf[42];
	u16 status = 0;

	spin_lock_irqsave(&dev_lock, flags);
	size += sprintf(&buf[size], "Devices Present:\n");
	list_for_each_entry_safe(dd, tmp, &online_list, online_list) {
		if (dd->pdev) {
			if (dd->port &&
			    dd->port->identify &&
			    dd->port->identify_valid) {
				strlcpy(id_buf,
					(char *) (dd->port->identify + 10), 21);
				status = *(dd->port->identify + 141);
			} else {
				memset(id_buf, 0, 42);
				status = 0;
			}

			if (dd->port &&
			    test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
				size += sprintf(&buf[size],
					" device %s %s (ftl rebuild %d %%)\n",
					dev_name(&dd->pdev->dev),
					id_buf,
					status);
			} else {
				size += sprintf(&buf[size],
					" device %s %s\n",
					dev_name(&dd->pdev->dev),
					id_buf);
			}
		}
	}

	size += sprintf(&buf[size], "Devices Being Removed:\n");
	list_for_each_entry_safe(dd, tmp, &removing_list, remove_list) {
		if (dd->pdev) {
			if (dd->port &&
			    dd->port->identify &&
			    dd->port->identify_valid) {
				strlcpy(id_buf,
					(char *) (dd->port->identify+10), 21);
				status = *(dd->port->identify + 141);
			} else {
				memset(id_buf, 0, 42);
				status = 0;
			}

			if (dd->port &&
			    test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
				size += sprintf(&buf[size],
					" device %s %s (ftl rebuild %d %%)\n",
					dev_name(&dd->pdev->dev),
					id_buf,
					status);
			} else {
				size += sprintf(&buf[size],
					" device %s %s\n",
					dev_name(&dd->pdev->dev),
					id_buf);
			}
		}
	}
	spin_unlock_irqrestore(&dev_lock, flags);

	return size;
}

static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
						size_t len, loff_t *offset)
{
	int size = *offset;
	char buf[MTIP_DFS_MAX_BUF_SIZE];

	if (!len || *offset)
		return 0;

	size += show_device_status(NULL, buf);

	*offset = size <= len ? size : len;
	size = copy_to_user(ubuf, buf, *offset);
	if (size)
		return -EFAULT;

	return *offset;
}

static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
				  size_t len, loff_t *offset)
				  size_t len, loff_t *offset)
{
{
@@ -2804,6 +2900,13 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
	return *offset;
	return *offset;
}
}


static const struct file_operations mtip_device_status_fops = {
	.owner  = THIS_MODULE,
	.open   = simple_open,
	.read   = mtip_hw_read_device_status,
	.llseek = no_llseek,
};

static const struct file_operations mtip_regs_fops = {
static const struct file_operations mtip_regs_fops = {
	.owner  = THIS_MODULE,
	.owner  = THIS_MODULE,
	.open   = simple_open,
	.open   = simple_open,
@@ -4161,6 +4264,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
	const struct cpumask *node_mask;
	const struct cpumask *node_mask;
	int cpu, i = 0, j = 0;
	int cpu, i = 0, j = 0;
	int my_node = NUMA_NO_NODE;
	int my_node = NUMA_NO_NODE;
	unsigned long flags;


	/* Allocate memory for this devices private data. */
	/* Allocate memory for this devices private data. */
	my_node = pcibus_to_node(pdev->bus);
	my_node = pcibus_to_node(pdev->bus);
@@ -4218,6 +4322,9 @@ static int mtip_pci_probe(struct pci_dev *pdev,
	dd->pdev	= pdev;
	dd->pdev	= pdev;
	dd->numa_node	= my_node;
	dd->numa_node	= my_node;


	INIT_LIST_HEAD(&dd->online_list);
	INIT_LIST_HEAD(&dd->remove_list);

	memset(dd->workq_name, 0, 32);
	memset(dd->workq_name, 0, 32);
	snprintf(dd->workq_name, 31, "mtipq%d", dd->instance);
	snprintf(dd->workq_name, 31, "mtipq%d", dd->instance);


@@ -4305,6 +4412,14 @@ static int mtip_pci_probe(struct pci_dev *pdev,
	instance++;
	instance++;
	if (rv != MTIP_FTL_REBUILD_MAGIC)
	if (rv != MTIP_FTL_REBUILD_MAGIC)
		set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
		set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
	else
		rv = 0; /* device in rebuild state, return 0 from probe */

	/* Add to online list even if in ftl rebuild */
	spin_lock_irqsave(&dev_lock, flags);
	list_add(&dd->online_list, &online_list);
	spin_unlock_irqrestore(&dev_lock, flags);

	goto done;
	goto done;


block_initialize_err:
block_initialize_err:
@@ -4338,9 +4453,15 @@ static void mtip_pci_remove(struct pci_dev *pdev)
{
{
	struct driver_data *dd = pci_get_drvdata(pdev);
	struct driver_data *dd = pci_get_drvdata(pdev);
	int counter = 0;
	int counter = 0;
	unsigned long flags;


	set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
	set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);


	spin_lock_irqsave(&dev_lock, flags);
	list_del_init(&dd->online_list);
	list_add(&dd->remove_list, &removing_list);
	spin_unlock_irqrestore(&dev_lock, flags);

	if (mtip_check_surprise_removal(pdev)) {
	if (mtip_check_surprise_removal(pdev)) {
		while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) {
		while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) {
			counter++;
			counter++;
@@ -4366,6 +4487,10 @@ static void mtip_pci_remove(struct pci_dev *pdev)


	pci_disable_msi(pdev);
	pci_disable_msi(pdev);


	spin_lock_irqsave(&dev_lock, flags);
	list_del_init(&dd->remove_list);
	spin_unlock_irqrestore(&dev_lock, flags);

	kfree(dd);
	kfree(dd);
	pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
	pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
}
}
@@ -4513,6 +4638,11 @@ static int __init mtip_init(void)


	pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
	pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");


	spin_lock_init(&dev_lock);

	INIT_LIST_HEAD(&online_list);
	INIT_LIST_HEAD(&removing_list);

	/* Allocate a major block device number to use with this driver. */
	/* Allocate a major block device number to use with this driver. */
	error = register_blkdev(0, MTIP_DRV_NAME);
	error = register_blkdev(0, MTIP_DRV_NAME);
	if (error <= 0) {
	if (error <= 0) {
@@ -4522,12 +4652,19 @@ static int __init mtip_init(void)
	}
	}
	mtip_major = error;
	mtip_major = error;


	if (!dfs_parent) {
	dfs_parent = debugfs_create_dir("rssd", NULL);
	dfs_parent = debugfs_create_dir("rssd", NULL);
	if (IS_ERR_OR_NULL(dfs_parent)) {
	if (IS_ERR_OR_NULL(dfs_parent)) {
		pr_warn("Error creating debugfs parent\n");
		pr_warn("Error creating debugfs parent\n");
		dfs_parent = NULL;
		dfs_parent = NULL;
	}
	}
	if (dfs_parent) {
		dfs_device_status = debugfs_create_file("device_status",
					S_IRUGO, dfs_parent, NULL,
					&mtip_device_status_fops);
		if (IS_ERR_OR_NULL(dfs_device_status)) {
			pr_err("Error creating device_status node\n");
			dfs_device_status = NULL;
		}
	}
	}


	/* Register our PCI operations. */
	/* Register our PCI operations. */
+11 −7
Original line number Original line Diff line number Diff line
@@ -129,9 +129,9 @@ enum {
	MTIP_PF_EH_ACTIVE_BIT       = 1, /* error handling */
	MTIP_PF_EH_ACTIVE_BIT       = 1, /* error handling */
	MTIP_PF_SE_ACTIVE_BIT       = 2, /* secure erase */
	MTIP_PF_SE_ACTIVE_BIT       = 2, /* secure erase */
	MTIP_PF_DM_ACTIVE_BIT       = 3, /* download microcde */
	MTIP_PF_DM_ACTIVE_BIT       = 3, /* download microcde */
	MTIP_PF_PAUSE_IO      =	((1 << MTIP_PF_IC_ACTIVE_BIT) | \
	MTIP_PF_PAUSE_IO      =	((1 << MTIP_PF_IC_ACTIVE_BIT) |
				(1 << MTIP_PF_EH_ACTIVE_BIT) | \
				(1 << MTIP_PF_EH_ACTIVE_BIT) |
				(1 << MTIP_PF_SE_ACTIVE_BIT) | \
				(1 << MTIP_PF_SE_ACTIVE_BIT) |
				(1 << MTIP_PF_DM_ACTIVE_BIT)),
				(1 << MTIP_PF_DM_ACTIVE_BIT)),


	MTIP_PF_SVC_THD_ACTIVE_BIT  = 4,
	MTIP_PF_SVC_THD_ACTIVE_BIT  = 4,
@@ -144,9 +144,9 @@ enum {
	MTIP_DDF_REMOVE_PENDING_BIT = 1,
	MTIP_DDF_REMOVE_PENDING_BIT = 1,
	MTIP_DDF_OVER_TEMP_BIT      = 2,
	MTIP_DDF_OVER_TEMP_BIT      = 2,
	MTIP_DDF_WRITE_PROTECT_BIT  = 3,
	MTIP_DDF_WRITE_PROTECT_BIT  = 3,
	MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \
	MTIP_DDF_STOP_IO      = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) |
				(1 << MTIP_DDF_SEC_LOCK_BIT) | \
				(1 << MTIP_DDF_SEC_LOCK_BIT) |
				(1 << MTIP_DDF_OVER_TEMP_BIT) | \
				(1 << MTIP_DDF_OVER_TEMP_BIT) |
				(1 << MTIP_DDF_WRITE_PROTECT_BIT)),
				(1 << MTIP_DDF_WRITE_PROTECT_BIT)),


	MTIP_DDF_CLEANUP_BIT        = 5,
	MTIP_DDF_CLEANUP_BIT        = 5,
@@ -501,6 +501,10 @@ struct driver_data {
	atomic_t irq_workers_active;
	atomic_t irq_workers_active;


	int isr_binding;
	int isr_binding;

	struct list_head online_list; /* linkage for online list */

	struct list_head remove_list; /* linkage for removing list */
};
};


#endif
#endif