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

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
...@@ -229,6 +229,8 @@ queue_store_##name(struct request_queue *q, const char *page, size_t count) \ ...@@ -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; \
\ \
......
...@@ -257,7 +257,6 @@ void delete_partition(struct gendisk *disk, int partno) ...@@ -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)
......
...@@ -1051,29 +1051,12 @@ static int loop_clr_fd(struct loop_device *lo) ...@@ -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
......
...@@ -81,12 +81,17 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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. */
......
...@@ -129,9 +129,9 @@ enum { ...@@ -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 { ...@@ -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 { ...@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment