Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753897Ab3EJTVl (ORCPT ); Fri, 10 May 2013 15:21:41 -0400 Received: from mailout.micron.com ([137.201.242.129]:37565 "EHLO mailout.micron.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753679Ab3EJTVj (ORCPT ); Fri, 10 May 2013 15:21:39 -0400 Message-ID: <518D48BA.6010507@micron.com> Date: Sat, 11 May 2013 00:51:30 +0530 From: Asai Thambi S P User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20120428 Thunderbird/12.0.1 MIME-Version: 1.0 To: Jens Axboe CC: "linux-kernel@vger.kernel.org" , "Sam Bradshaw" Subject: Re: [PATCH] mtip32xx: Add SRSI support References: <518BE87F.3080201@micron.com> In-Reply-To: <518BE87F.3080201@micron.com> Content-Type: text/plain; charset="ISO-8859-1" Content-Transfer-Encoding: 7bit X-TM-AS-Product-Ver: SMEX-10.0.0.4152-7.000.1014-19858.001 X-TM-AS-Result: No--30.158100-0.000000-31 X-TM-AS-User-Approved-Sender: Yes X-TM-AS-User-Blocked-Sender: No X-MT-CheckInternalSenderRule: True Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 22686 Lines: 774 On 5/9/2013 11:48 PM, Asai Thambi S P wrote: > > This patch add support for SRSI(Surprise Removal Surprise Insertion). Jens, Forgot to include. This patch is for 3.10 > > Approach: > --------- > Surprise Removal: > ----------------- > On surprise removal of the device, gendisk, request queue, device index, sysfs > entries, etc are retained as long as device is in use - mounted filesystem, > device opened by an application, etc. The service thread breaks out of the main > while loop, waits for pci remove to exit, and then waits for device to become > free. When there no holders of the device, service thread cleans up the block > and device related stuff and returns. > > Surprise Insertion: > ------------------- > No change, this scenario follows the normal pci probe() function flow. > > Signed-off-by: Asai Thambi S P > --- > drivers/block/mtip32xx/mtip32xx.c | 453 ++++++++++++++++++++++--------------- > drivers/block/mtip32xx/mtip32xx.h | 18 +- > 2 files changed, 289 insertions(+), 182 deletions(-) > > diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c > index 847107e..aab28a4 100644 > --- a/drivers/block/mtip32xx/mtip32xx.c > +++ b/drivers/block/mtip32xx/mtip32xx.c > @@ -126,64 +126,30 @@ struct mtip_compat_ide_task_request_s { > static bool mtip_check_surprise_removal(struct pci_dev *pdev) > { > u16 vendor_id = 0; > + struct driver_data *dd = pci_get_drvdata(pdev); > + > + if (dd->sr) > + return true; > > /* Read the vendorID from the configuration space */ > pci_read_config_word(pdev, 0x00, &vendor_id); > - if (vendor_id == 0xFFFF) > + if (vendor_id == 0xFFFF) { > + dd->sr = true; > + if (dd->queue) > + set_bit(QUEUE_FLAG_DEAD, &dd->queue->queue_flags); > + else > + dev_warn(&dd->pdev->dev, > + "%s: dd->queue is NULL\n", __func__); > + if (dd->port) { > + set_bit(MTIP_PF_SR_CLEANUP_BIT, &dd->port->flags); > + wake_up_interruptible(&dd->port->svc_wait); > + } else > + dev_warn(&dd->pdev->dev, > + "%s: dd->port is NULL\n", __func__); > return true; /* device removed */ > - > - return false; /* device present */ > -} > - > -/* > - * This function is called for clean the pending command in the > - * command slot during the surprise removal of device and return > - * error to the upper layer. > - * > - * @dd Pointer to the DRIVER_DATA structure. > - * > - * return value > - * None > - */ > -static void mtip_command_cleanup(struct driver_data *dd) > -{ > - int group = 0, commandslot = 0, commandindex = 0; > - struct mtip_cmd *command; > - struct mtip_port *port = dd->port; > - static int in_progress; > - > - if (in_progress) > - return; > - > - in_progress = 1; > - > - for (group = 0; group < 4; group++) { > - for (commandslot = 0; commandslot < 32; commandslot++) { > - if (!(port->allocated[group] & (1 << commandslot))) > - continue; > - > - commandindex = group << 5 | commandslot; > - command = &port->commands[commandindex]; > - > - if (atomic_read(&command->active) > - && (command->async_callback)) { > - command->async_callback(command->async_data, > - -ENODEV); > - command->async_callback = NULL; > - command->async_data = NULL; > - } > - > - dma_unmap_sg(&port->dd->pdev->dev, > - command->sg, > - command->scatter_ents, > - command->direction); > - } > } > > - up(&port->cmd_slot); > - > - set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); > - in_progress = 0; > + return false; /* device present */ > } > > /* > @@ -222,10 +188,7 @@ static int get_slot(struct mtip_port *port) > } > dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n"); > > - if (mtip_check_surprise_removal(port->dd->pdev)) { > - /* Device not present, clean outstanding commands */ > - mtip_command_cleanup(port->dd); > - } > + mtip_check_surprise_removal(port->dd->pdev); > return -1; > } > > @@ -246,6 +209,107 @@ static inline void release_slot(struct mtip_port *port, int tag) > } > > /* > + * IO completion function. > + * > + * This completion function is called by the driver ISR when a > + * command that was issued by the kernel completes. It first calls the > + * asynchronous completion function which normally calls back into the block > + * layer passing the asynchronous callback data, then unmaps the > + * scatter list associated with the completed command, and finally > + * clears the allocated bit associated with the completed command. > + * > + * @port Pointer to the port data structure. > + * @tag Tag of the command. > + * @data Pointer to driver_data. > + * @status Completion status. > + * > + * return value > + * None > + */ > +static void mtip_async_complete(struct mtip_port *port, > + int tag, > + void *data, > + int status) > +{ > + struct mtip_cmd *command; > + struct driver_data *dd = data; > + int cb_status = status ? -EIO : 0; > + > + if (unlikely(!dd) || unlikely(!port)) > + return; > + > + command = &port->commands[tag]; > + > + if (unlikely(status == PORT_IRQ_TF_ERR)) { > + dev_warn(&port->dd->pdev->dev, > + "Command tag %d failed due to TFE\n", tag); > + } > + > + /* Upper layer callback */ > + if (likely(command->async_callback)) > + command->async_callback(command->async_data, cb_status); > + > + command->async_callback = NULL; > + command->comp_func = NULL; > + > + /* Unmap the DMA scatter list entries */ > + dma_unmap_sg(&dd->pdev->dev, > + command->sg, > + command->scatter_ents, > + command->direction); > + > + /* Clear the allocated and active bits for the command */ > + atomic_set(&port->commands[tag].active, 0); > + release_slot(port, tag); > + > + up(&port->cmd_slot); > +} > + > +/* > + * This function is called for clean the pending command in the > + * command slot during the surprise removal of device and return > + * error to the upper layer. > + * > + * @dd Pointer to the DRIVER_DATA structure. > + * > + * return value > + * None > + */ > +static void mtip_command_cleanup(struct driver_data *dd) > +{ > + int tag = 0; > + struct mtip_cmd *cmd; > + struct mtip_port *port = dd->port; > + unsigned int num_cmd_slots = dd->slot_groups * 32; > + > + if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) > + return; > + > + if (!port) > + return; > + > + cmd = &port->commands[MTIP_TAG_INTERNAL]; > + if (atomic_read(&cmd->active)) > + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & > + (1 << MTIP_TAG_INTERNAL)) > + if (cmd->comp_func) > + cmd->comp_func(port, MTIP_TAG_INTERNAL, > + cmd->comp_data, -ENODEV); > + > + while (1) { > + tag = find_next_bit(port->allocated, num_cmd_slots, tag); > + if (tag >= num_cmd_slots) > + break; > + > + cmd = &port->commands[tag]; > + if (atomic_read(&cmd->active)) > + mtip_async_complete(port, tag, dd, -ENODEV); > + } > + > + set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); > +} > + > +/* > * Reset the HBA (without sleeping) > * > * @dd Pointer to the driver data structure. > @@ -584,6 +648,9 @@ static void mtip_timeout_function(unsigned long int data) > if (unlikely(!port)) > return; > > + if (unlikely(port->dd->sr)) > + return; > + > if (test_bit(MTIP_DDF_RESUME_BIT, &port->dd->dd_flag)) { > mod_timer(&port->cmd_timer, > jiffies + msecs_to_jiffies(30000)); > @@ -675,66 +742,6 @@ static void mtip_timeout_function(unsigned long int data) > } > > /* > - * IO completion function. > - * > - * This completion function is called by the driver ISR when a > - * command that was issued by the kernel completes. It first calls the > - * asynchronous completion function which normally calls back into the block > - * layer passing the asynchronous callback data, then unmaps the > - * scatter list associated with the completed command, and finally > - * clears the allocated bit associated with the completed command. > - * > - * @port Pointer to the port data structure. > - * @tag Tag of the command. > - * @data Pointer to driver_data. > - * @status Completion status. > - * > - * return value > - * None > - */ > -static void mtip_async_complete(struct mtip_port *port, > - int tag, > - void *data, > - int status) > -{ > - struct mtip_cmd *command; > - struct driver_data *dd = data; > - int cb_status = status ? -EIO : 0; > - > - if (unlikely(!dd) || unlikely(!port)) > - return; > - > - command = &port->commands[tag]; > - > - if (unlikely(status == PORT_IRQ_TF_ERR)) { > - dev_warn(&port->dd->pdev->dev, > - "Command tag %d failed due to TFE\n", tag); > - } > - > - /* Upper layer callback */ > - if (likely(command->async_callback)) > - command->async_callback(command->async_data, cb_status); > - > - command->async_callback = NULL; > - command->comp_func = NULL; > - > - /* Unmap the DMA scatter list entries */ > - dma_unmap_sg(&dd->pdev->dev, > - command->sg, > - command->scatter_ents, > - command->direction); > - > - /* Clear the allocated and active bits for the command */ > - atomic_set(&port->commands[tag].active, 0); > - release_slot(port, tag); > - > - if (unlikely(command->unaligned)) > - up(&port->cmd_slot_unal); > - else > - up(&port->cmd_slot); > -} > - > -/* > * Internal command completion callback function. > * > * This function is normally called by the driver ISR when an internal > @@ -854,7 +861,6 @@ static void mtip_handle_tfe(struct driver_data *dd) > "Missing completion func for tag %d", > tag); > if (mtip_check_surprise_removal(dd->pdev)) { > - mtip_command_cleanup(dd); > /* don't proceed further */ > return; > } > @@ -1018,14 +1024,12 @@ static inline void mtip_workq_sdbfx(struct mtip_port *port, int group, > command->comp_data, > 0); > } else { > - dev_warn(&dd->pdev->dev, > - "Null completion " > - "for tag %d", > + dev_dbg(&dd->pdev->dev, > + "Null completion for tag %d", > tag); > > if (mtip_check_surprise_removal( > dd->pdev)) { > - mtip_command_cleanup(dd); > return; > } > } > @@ -1145,7 +1149,6 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) > > if (unlikely(port_stat & PORT_IRQ_ERR)) { > if (unlikely(mtip_check_surprise_removal(dd->pdev))) { > - mtip_command_cleanup(dd); > /* don't proceed further */ > return IRQ_HANDLED; > } > @@ -3005,6 +3008,46 @@ static void mtip_hw_debugfs_exit(struct driver_data *dd) > debugfs_remove_recursive(dd->dfs_node); > } > > +static int mtip_free_orphan(struct driver_data *dd) > +{ > + struct kobject *kobj; > + > + if (dd->bdev) { > + if (dd->bdev->bd_holders >= 1) > + return -2; > + > + bdput(dd->bdev); > + dd->bdev = NULL; > + } > + > + mtip_hw_debugfs_exit(dd); > + > + spin_lock(&rssd_index_lock); > + ida_remove(&rssd_index_ida, dd->index); > + spin_unlock(&rssd_index_lock); > + > + if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag) && > + test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) { > + put_disk(dd->disk); > + } else { > + if (dd->disk) { > + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); > + if (kobj) { > + mtip_hw_sysfs_exit(dd, kobj); > + kobject_put(kobj); > + } > + del_gendisk(dd->disk); > + dd->disk = NULL; > + } > + if (dd->queue) { > + dd->queue->queuedata = NULL; > + blk_cleanup_queue(dd->queue); > + dd->queue = NULL; > + } > + } > + kfree(dd); > + return 0; > +} > > /* > * Perform any init/resume time hardware setup > @@ -3153,6 +3196,7 @@ static int mtip_service_thread(void *data) > unsigned long slot, slot_start, slot_wrap; > unsigned int num_cmd_slots = dd->slot_groups * 32; > struct mtip_port *port = dd->port; > + int ret; > > while (1) { > /* > @@ -3163,13 +3207,18 @@ static int mtip_service_thread(void *data) > !(port->flags & MTIP_PF_PAUSE_IO)); > > if (kthread_should_stop()) > + goto st_out; > + > + set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); > + > + /* If I am an orphan, start self cleanup */ > + if (test_bit(MTIP_PF_SR_CLEANUP_BIT, &port->flags)) > break; > > if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, > &dd->dd_flag))) > - break; > + goto st_out; > > - set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); > if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { > slot = 1; > /* used to restrict the loop to one iteration */ > @@ -3200,7 +3249,7 @@ static int mtip_service_thread(void *data) > > clear_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); > } else if (test_bit(MTIP_PF_REBUILD_BIT, &port->flags)) { > - if (!mtip_ftl_rebuild_poll(dd)) > + if (mtip_ftl_rebuild_poll(dd) < 0) > set_bit(MTIP_DDF_REBUILD_FAILED_BIT, > &dd->dd_flag); > clear_bit(MTIP_PF_REBUILD_BIT, &port->flags); > @@ -3208,8 +3257,30 @@ static int mtip_service_thread(void *data) > clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); > > if (test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags)) > + goto st_out; > + } > + > + /* wait for pci remove to exit */ > + while (1) { > + if (test_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag)) > break; > + msleep_interruptible(1000); > + if (kthread_should_stop()) > + goto st_out; > } > + > + while (1) { > + ret = mtip_free_orphan(dd); > + if (!ret) { > + /* NOTE: All data structures are invalid, do not > + * access any here */ > + return 0; > + } > + msleep_interruptible(1000); > + if (kthread_should_stop()) > + goto st_out; > + } > +st_out: > return 0; > } > > @@ -3436,13 +3507,13 @@ static int mtip_hw_init(struct driver_data *dd) > rv = -EFAULT; > goto out3; > } > + mtip_dump_identify(dd->port); > > if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == > MTIP_FTL_REBUILD_MAGIC) { > set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); > return MTIP_FTL_REBUILD_MAGIC; > } > - mtip_dump_identify(dd->port); > > /* check write protect, over temp and rebuild statuses */ > rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, > @@ -3466,8 +3537,8 @@ static int mtip_hw_init(struct driver_data *dd) > } > if (buf[288] == 0xBF) { > dev_info(&dd->pdev->dev, > - "Drive indicates rebuild has failed.\n"); > - /* TODO */ > + "Drive is in security locked state.\n"); > + set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag); > } > } > > @@ -3522,9 +3593,8 @@ static int mtip_hw_exit(struct driver_data *dd) > * Send standby immediate (E0h) to the drive so that it > * saves its state. > */ > - if (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { > - > - if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) > + if (!dd->sr) { > + if (!test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) > if (mtip_standby_immediate(dd->port)) > dev_warn(&dd->pdev->dev, > "STANDBY IMMEDIATE failed\n"); > @@ -3550,6 +3620,7 @@ static int mtip_hw_exit(struct driver_data *dd) > dd->port->command_list_dma); > /* Free the memory allocated for the for structure. */ > kfree(dd->port); > + dd->port = NULL; > > return 0; > } > @@ -3571,7 +3642,8 @@ static int mtip_hw_shutdown(struct driver_data *dd) > * Send standby immediate (E0h) to the drive so that it > * saves its state. > */ > - mtip_standby_immediate(dd->port); > + if (!dd->sr && dd->port) > + mtip_standby_immediate(dd->port); > > return 0; > } > @@ -3886,6 +3958,10 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) > bio_endio(bio, -ENODATA); > return; > } > + if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) { > + bio_endio(bio, -ENXIO); > + return; > + } > } > > if (unlikely(bio->bi_rw & REQ_DISCARD)) { > @@ -4008,6 +4084,8 @@ static int mtip_block_initialize(struct driver_data *dd) > dd->disk->private_data = dd; > dd->index = index; > > + mtip_hw_debugfs_init(dd); > + > /* > * if rebuild pending, start the service thread, and delay the block > * queue creation and add_disk() > @@ -4066,6 +4144,7 @@ skip_create_disk: > /* Enable the block device and add it to /dev */ > add_disk(dd->disk); > > + dd->bdev = bdget_disk(dd->disk, 0); > /* > * Now that the disk is active, initialize any sysfs attributes > * managed by the protocol layer. > @@ -4075,7 +4154,6 @@ skip_create_disk: > mtip_hw_sysfs_init(dd, kobj); > kobject_put(kobj); > } > - mtip_hw_debugfs_init(dd); > > if (dd->mtip_svc_handler) { > set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); > @@ -4100,7 +4178,8 @@ start_service_thread: > return rv; > > kthread_run_error: > - mtip_hw_debugfs_exit(dd); > + bdput(dd->bdev); > + dd->bdev = NULL; > > /* Delete our gendisk. This also removes the device from /dev */ > del_gendisk(dd->disk); > @@ -4109,6 +4188,7 @@ read_capacity_error: > blk_cleanup_queue(dd->queue); > > block_queue_alloc_init_error: > + mtip_hw_debugfs_exit(dd); > disk_index_error: > spin_lock(&rssd_index_lock); > ida_remove(&rssd_index_ida, index); > @@ -4138,40 +4218,48 @@ static int mtip_block_remove(struct driver_data *dd) > { > struct kobject *kobj; > > - if (dd->mtip_svc_handler) { > - set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); > - wake_up_interruptible(&dd->port->svc_wait); > - kthread_stop(dd->mtip_svc_handler); > - } > + if (!dd->sr) { > + mtip_hw_debugfs_exit(dd); > > - /* Clean up the sysfs attributes, if created */ > - if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { > - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); > - if (kobj) { > - mtip_hw_sysfs_exit(dd, kobj); > - kobject_put(kobj); > + if (dd->mtip_svc_handler) { > + set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); > + wake_up_interruptible(&dd->port->svc_wait); > + kthread_stop(dd->mtip_svc_handler); > } > - } > - mtip_hw_debugfs_exit(dd); > > - /* > - * Delete our gendisk structure. This also removes the device > - * from /dev > - */ > - if (dd->disk) { > - if (dd->disk->queue) > - del_gendisk(dd->disk); > - else > - put_disk(dd->disk); > - } > - > - spin_lock(&rssd_index_lock); > - ida_remove(&rssd_index_ida, dd->index); > - spin_unlock(&rssd_index_lock); > + /* Clean up the sysfs attributes, if created */ > + if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { > + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); > + if (kobj) { > + mtip_hw_sysfs_exit(dd, kobj); > + kobject_put(kobj); > + } > + } > + /* > + * Delete our gendisk structure. This also removes the device > + * from /dev > + */ > + if (dd->bdev) { > + bdput(dd->bdev); > + dd->bdev = NULL; > + } > + if (dd->disk) { > + if (dd->disk->queue) { > + del_gendisk(dd->disk); > + blk_cleanup_queue(dd->queue); > + dd->queue = NULL; > + } else > + put_disk(dd->disk); > + } > + dd->disk = NULL; > > - blk_cleanup_queue(dd->queue); > - dd->disk = NULL; > - dd->queue = NULL; > + spin_lock(&rssd_index_lock); > + ida_remove(&rssd_index_ida, dd->index); > + spin_unlock(&rssd_index_lock); > + } else { > + dev_info(&dd->pdev->dev, "device %s surprise removal\n", > + dd->disk->disk_name); > + } > > /* De-initialize the protocol layer. */ > mtip_hw_exit(dd); > @@ -4487,8 +4575,7 @@ done: > static void mtip_pci_remove(struct pci_dev *pdev) > { > struct driver_data *dd = pci_get_drvdata(pdev); > - int counter = 0; > - unsigned long flags; > + unsigned long flags, to; > > set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag); > > @@ -4497,17 +4584,22 @@ static void mtip_pci_remove(struct pci_dev *pdev) > list_add(&dd->remove_list, &removing_list); > spin_unlock_irqrestore(&dev_lock, flags); > > - if (mtip_check_surprise_removal(pdev)) { > - while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { > - counter++; > - msleep(20); > - if (counter == 10) { > - /* Cleanup the outstanding commands */ > - mtip_command_cleanup(dd); > - break; > - } > - } > + mtip_check_surprise_removal(pdev); > + synchronize_irq(dd->pdev->irq); > + > + /* Spin until workers are done */ > + to = jiffies + msecs_to_jiffies(4000); > + do { > + msleep(20); > + } while (atomic_read(&dd->irq_workers_active) != 0 && > + time_before(jiffies, to)); > + > + if (atomic_read(&dd->irq_workers_active) != 0) { > + dev_warn(&dd->pdev->dev, > + "Completion workers still active!\n"); > } > + /* Cleanup the outstanding commands */ > + mtip_command_cleanup(dd); > > /* Clean up the block layer. */ > mtip_block_remove(dd); > @@ -4526,8 +4618,15 @@ static void mtip_pci_remove(struct pci_dev *pdev) > list_del_init(&dd->remove_list); > spin_unlock_irqrestore(&dev_lock, flags); > > - kfree(dd); > + if (!dd->sr) > + kfree(dd); > + else > + set_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag); > + > pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); > + pci_set_drvdata(pdev, NULL); > + pci_dev_put(pdev); > + > } > > /* > diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h > index 3bb8a29..9be7a15 100644 > --- a/drivers/block/mtip32xx/mtip32xx.h > +++ b/drivers/block/mtip32xx/mtip32xx.h > @@ -140,6 +140,7 @@ enum { > MTIP_PF_SVC_THD_ACTIVE_BIT = 4, > MTIP_PF_ISSUE_CMDS_BIT = 5, > MTIP_PF_REBUILD_BIT = 6, > + MTIP_PF_SR_CLEANUP_BIT = 7, > MTIP_PF_SVC_THD_STOP_BIT = 8, > > /* below are bit numbers in 'dd_flag' defined in driver_data */ > @@ -147,15 +148,18 @@ enum { > MTIP_DDF_REMOVE_PENDING_BIT = 1, > MTIP_DDF_OVER_TEMP_BIT = 2, > MTIP_DDF_WRITE_PROTECT_BIT = 3, > - MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | > - (1 << MTIP_DDF_SEC_LOCK_BIT) | > - (1 << MTIP_DDF_OVER_TEMP_BIT) | > - (1 << MTIP_DDF_WRITE_PROTECT_BIT)), > - > + MTIP_DDF_REMOVE_DONE_BIT = 4, > MTIP_DDF_CLEANUP_BIT = 5, > MTIP_DDF_RESUME_BIT = 6, > MTIP_DDF_INIT_DONE_BIT = 7, > MTIP_DDF_REBUILD_FAILED_BIT = 8, > + > + MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | > + (1 << MTIP_DDF_SEC_LOCK_BIT) | > + (1 << MTIP_DDF_OVER_TEMP_BIT) | > + (1 << MTIP_DDF_WRITE_PROTECT_BIT) | > + (1 << MTIP_DDF_REBUILD_FAILED_BIT)), > + > }; > > struct smart_attr { > @@ -499,6 +503,8 @@ struct driver_data { > > bool trim_supp; /* flag indicating trim support */ > > + bool sr; > + > int numa_node; /* NUMA support */ > > char workq_name[32]; > @@ -511,6 +517,8 @@ struct driver_data { > > int isr_binding; > > + struct block_device *bdev; > + > int unal_qdepth; /* qdepth of unaligned IO queue */ > > struct list_head online_list; /* linkage for online list */ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/