for-linus-20130409
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABCAAGBQJRZCnRAAoJEPfTWPspceCmQD0QAMS6a7kYln9n7ByzMa1rfm7x Mhu3NkT3I34a5+hgdiIwWTjqJ2Uu78S5pD522eAP4m9yGcG7m1c3aqdTEewDck7K xcIjgzS1j1J/XRlrtgPxJhsiA23Kzhliwztrr1YhczWLMijvIrNu2KYZ4EK4/YPB KkdGJJitunrOw4nhmnB1AYCRJoZJ5KXOpigqVr7vxTh0Ye7ue2k9mDD3x6tOp/Q0 TxKxXyEZF9yHgUkpARMcy4OEcr63APfAeiAnZOPpdK5rbCc8pVXpoadLE8UipnlI 0FcGBzuEezQE3FZrT9PL58FFNEPUmx3NWz2SwYV7Te5Gw5Zw/ffMxk8geE12ALmb YuULHGOxz97rxjFImYYGqIOQl7F6V59bYgbXegmKnWjorKEn6LxHyNI1Q76oH5V3 UgvkmTK91yNa6DvB24Vrt1yKb3GvKQApHAwEn82y+LqcZFkWq1iKqlPVNNGGjCbR j47Qu4G/6Bif0vTFC34ciI79ga/di4S4FUOCthsjskm7waDUNvrlbP4Mvwq1VPAc VZaYGrQcWCDxuAY/S3XTR+2ci/B0n4Fhyn/iFg/6S+nQawJDeiM+C3yVDbH8caq4 wV2PXEQ/r+SII4PVGFAmATewUKF3dkUpT2TKhc9KRHZh9+mFBXFj13MZ3+WpBPHl NTvEyi5nUL+MdyZGuJUi =CB+W -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
27387dd8c6
@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
/* 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,40 +248,31 @@ 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 {
|
||||||
*/
|
mdelay(10);
|
||||||
timeout = jiffies + msecs_to_jiffies(1000);
|
if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
|
||||||
mdelay(10);
|
return -1;
|
||||||
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))
|
} while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
|
||||||
return -1;
|
&& 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);
|
clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
|
||||||
else if (fis->command == ATA_CMD_DOWNLOAD_MICRO)
|
|
||||||
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,11 +4652,18 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
@ -180,7 +180,7 @@ struct mtip_work {
|
|||||||
|
|
||||||
#define MTIP_TRIM_TIMEOUT_MS 240000
|
#define MTIP_TRIM_TIMEOUT_MS 240000
|
||||||
#define MTIP_MAX_TRIM_ENTRIES 8
|
#define MTIP_MAX_TRIM_ENTRIES 8
|
||||||
#define MTIP_MAX_TRIM_ENTRY_LEN 0xfff8
|
#define MTIP_MAX_TRIM_ENTRY_LEN 0xfff8
|
||||||
|
|
||||||
struct mtip_trim_entry {
|
struct mtip_trim_entry {
|
||||||
u32 lba; /* starting lba of region */
|
u32 lba; /* starting lba of region */
|
||||||
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user