From 4f14faaab4ee46a046b6baff85644be199de718c Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 28 Nov 2011 11:49:03 -0500 Subject: xen/blkback: use grant-table.c hypercall wrappers Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 0088bf60f3689d..31743534d1e5f0 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -321,6 +321,7 @@ struct seg_buf { static void xen_blkbk_unmap(struct pending_req *req) { struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; unsigned int i, invcount = 0; grant_handle_t handle; int ret; @@ -332,25 +333,12 @@ static void xen_blkbk_unmap(struct pending_req *req) gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), GNTMAP_host_map, handle); pending_handle(req, i) = BLKBACK_INVALID_HANDLE; + pages[invcount] = virt_to_page(vaddr(req, i)); invcount++; } - ret = HYPERVISOR_grant_table_op( - GNTTABOP_unmap_grant_ref, unmap, invcount); + ret = gnttab_unmap_refs(unmap, pages, invcount, false); BUG_ON(ret); - /* - * Note, we use invcount, so nr->pages, so we can't index - * using vaddr(req, i). - */ - for (i = 0; i < invcount; i++) { - ret = m2p_remove_override( - virt_to_page(unmap[i].host_addr), false); - if (ret) { - pr_alert(DRV_PFX "Failed to remove M2P override for %lx\n", - (unsigned long)unmap[i].host_addr); - continue; - } - } } static int xen_blkbk_map(struct blkif_request *req, @@ -378,7 +366,7 @@ static int xen_blkbk_map(struct blkif_request *req, pending_req->blkif->domid); } - ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg); + ret = gnttab_map_refs(map, NULL, &blkbk->pending_page(pending_req, 0), nseg); BUG_ON(ret); /* @@ -398,15 +386,6 @@ static int xen_blkbk_map(struct blkif_request *req, if (ret) continue; - ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), - blkbk->pending_page(pending_req, i), NULL); - if (ret) { - pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n", - (unsigned long)map[i].dev_bus_addr, ret); - /* We could switch over to GNTTABOP_copy */ - continue; - } - seg[i].buf = map[i].dev_bus_addr | (req->u.rw.seg[i].first_sect << 9); } -- cgit 1.2.3-korg From b2167ba6dd89d55ced26a867fad8f0fe388fd595 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 28 Nov 2011 11:49:05 -0500 Subject: xen/blkback: Enable blkback on HVM guests Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 31743534d1e5f0..70caa896997203 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -809,7 +809,7 @@ static int __init xen_blkif_init(void) int i, mmap_pages; int rc = 0; - if (!xen_pv_domain()) + if (!xen_domain()) return -ENODEV; blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL); -- cgit 1.2.3-korg From 34ae2e47d97216d8c66a1c5dff5b530c29b746b8 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 21 Jan 2012 00:15:26 +0900 Subject: xen-blkfront: use bitmap_set() and bitmap_clear() Use bitmap_set and bitmap_clear rather than modifying individual bits in a memory region. Signed-off-by: Akinobu Mita Cc: Jeremy Fitzhardinge Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xensource.com Cc: virtualization@lists.linux-foundation.org Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 2f22874c0a374d..619868d91ca872 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -177,8 +178,7 @@ static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) spin_lock(&minor_lock); if (find_next_bit(minors, end, minor) >= end) { - for (; minor < end; ++minor) - __set_bit(minor, minors); + bitmap_set(minors, minor, nr); rc = 0; } else rc = -EBUSY; @@ -193,8 +193,7 @@ static void xlbd_release_minors(unsigned int minor, unsigned int nr) BUG_ON(end > nr_minors); spin_lock(&minor_lock); - for (; minor < end; ++minor) - __clear_bit(minor, minors); + bitmap_clear(minors, minor, nr); spin_unlock(&minor_lock); } -- cgit 1.2.3-korg From dad5cf659b202b5070c8616b5c515f6ca4db0c42 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 16 Feb 2012 13:16:25 +0100 Subject: xen/blkfront: don't put bdev right after getting it We should hang onto bdev until we're done with it. Signed-off-by: Andrew Jones [v1: Fixed up git commit description] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 619868d91ca872..537cb722a211cf 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1409,7 +1409,6 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) mutex_lock(&blkfront_mutex); bdev = bdget_disk(disk, 0); - bdput(bdev); if (bdev->bd_openers) goto out; @@ -1440,6 +1439,7 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) } out: + bdput(bdev); mutex_unlock(&blkfront_mutex); return 0; } -- cgit 1.2.3-korg From 3467811e26660eb46bc655234573d22d6876d5f9 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Fri, 17 Feb 2012 12:04:44 -0800 Subject: xen-blkfront: make blkif_io_lock spinlock per-device This patch moves the global blkif_io_lock to the per-device structure. The spinlock seems to exists for two reasons: to disable IRQs when in the interrupt handlers for blkfront, and to protect the blkfront VBDs when a detachment is requested. Having a global blkif_io_lock doesn't make sense given the use case, and it drastically hinders performance due to contention. All VBDs with pending IOs have to take the lock in order to get work done, which serializes everything pretty badly. Signed-off-by: Steven Noonan Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 537cb722a211cf..5d9c559f18778f 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -82,6 +82,7 @@ static const struct block_device_operations xlvbd_block_fops; */ struct blkfront_info { + spinlock_t io_lock; struct mutex mutex; struct xenbus_device *xbdev; struct gendisk *gd; @@ -106,8 +107,6 @@ struct blkfront_info int is_ready; }; -static DEFINE_SPINLOCK(blkif_io_lock); - static unsigned int nr_minors; static unsigned long *minors; static DEFINE_SPINLOCK(minor_lock); @@ -418,7 +417,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) struct request_queue *rq; struct blkfront_info *info = gd->private_data; - rq = blk_init_queue(do_blkif_request, &blkif_io_lock); + rq = blk_init_queue(do_blkif_request, &info->io_lock); if (rq == NULL) return -1; @@ -635,14 +634,14 @@ static void xlvbd_release_gendisk(struct blkfront_info *info) if (info->rq == NULL) return; - spin_lock_irqsave(&blkif_io_lock, flags); + spin_lock_irqsave(&info->io_lock, flags); /* No more blkif_request(). */ blk_stop_queue(info->rq); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); /* Flush gnttab callback work. Must be done with no locks held. */ flush_work_sync(&info->work); @@ -674,16 +673,16 @@ static void blkif_restart_queue(struct work_struct *work) { struct blkfront_info *info = container_of(work, struct blkfront_info, work); - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); if (info->connected == BLKIF_STATE_CONNECTED) kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); } static void blkif_free(struct blkfront_info *info, int suspend) { /* Prevent new requests being issued until we fix things up. */ - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); info->connected = suspend ? BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; /* No more blkif_request(). */ @@ -691,7 +690,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) blk_stop_queue(info->rq); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); /* Flush gnttab callback work. Must be done with no locks held. */ flush_work_sync(&info->work); @@ -727,10 +726,10 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) struct blkfront_info *info = (struct blkfront_info *)dev_id; int error; - spin_lock_irqsave(&blkif_io_lock, flags); + spin_lock_irqsave(&info->io_lock, flags); if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); return IRQ_HANDLED; } @@ -815,7 +814,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) kick_pending_request_queues(info); - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); return IRQ_HANDLED; } @@ -990,6 +989,7 @@ static int blkfront_probe(struct xenbus_device *dev, } mutex_init(&info->mutex); + spin_lock_init(&info->io_lock); info->xbdev = dev; info->vdevice = vdevice; info->connected = BLKIF_STATE_DISCONNECTED; @@ -1067,7 +1067,7 @@ static int blkif_recover(struct blkfront_info *info) xenbus_switch_state(info->xbdev, XenbusStateConnected); - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); /* Now safe for us to use the shared ring */ info->connected = BLKIF_STATE_CONNECTED; @@ -1078,7 +1078,7 @@ static int blkif_recover(struct blkfront_info *info) /* Kick any other new requests queued since we resumed */ kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); return 0; } @@ -1276,10 +1276,10 @@ static void blkfront_connect(struct blkfront_info *info) xenbus_switch_state(info->xbdev, XenbusStateConnected); /* Kick pending requests. */ - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); info->connected = BLKIF_STATE_CONNECTED; kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); add_disk(info->gd); -- cgit 1.2.3-korg From 395d287526bb60411ff37b19ad9dd38b58ba8732 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 22 Mar 2012 21:40:08 +0100 Subject: cciss: Initialize scsi host max_sectors for tape drive support The default is too small (1024 blocks), use h->cciss_max_sectors (8192 blocks) Without this change, if you try to set the block size of a tape drive above 512*1024, via "mt -f /dev/st0 setblk nnn" where nnn is greater than 524288, it won't work right. Signed-off-by: Stephen M. Cameron Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe --- drivers/block/cciss_scsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e820b68d2f6cd4..f510a9c9a6fd3c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -866,6 +866,7 @@ cciss_scsi_detect(ctlr_info_t *h) sh->can_queue = cciss_tape_cmds; sh->sg_tablesize = h->maxsgentries; sh->max_cmd_len = MAX_COMMAND_SIZE; + sh->max_sectors = h->cciss_max_sectors; ((struct cciss_scsi_adapter_data_t *) h->scsi_ctlr)->scsi_host = sh; -- cgit 1.2.3-korg From bc67f63650fad6b3478d9ddfd5406d45a95987c9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 22 Mar 2012 21:40:09 +0100 Subject: cciss: Fix scsi tape io with more than 255 scatter gather elements The total number of scatter gather elements in the CISS command used by the scsi tape code was being cast to a u8, which can hold at most 255 scatter gather elements. It should have been cast to a u16. Without this patch the command gets rejected by the controller since the total scatter gather count did not add up to the right value resulting in an i/o error. Signed-off-by: Stephen M. Cameron Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe --- drivers/block/cciss_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index f510a9c9a6fd3c..acda773b372087 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1411,7 +1411,7 @@ static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *c, /* track how many SG entries we are using */ if (request_nsgs > h->maxSG) h->maxSG = request_nsgs; - c->Header.SGTotal = (__u8) request_nsgs + chained; + c->Header.SGTotal = (u16) request_nsgs + chained; if (request_nsgs > h->max_cmd_sgentries) c->Header.SGList = h->max_cmd_sgentries; else -- cgit 1.2.3-korg From 22be2e6e13ac09b20000582ac34d47fb0029a6da Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Fri, 23 Mar 2012 12:33:03 +0100 Subject: mtip32xx: fix incorrect value set for drv_cleanup_done, and re-initialize and start port in mtip_restart_port() This patch includes two changes: * fix incorrect value set for drv_cleanup_done * re-initialize and start port in mtip_restart_port() Signed-off-by: Asai Thambi S P Signed-off-by: Sam Bradshaw Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 8eb81c96608fbc..04f69e6da1fef6 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -422,6 +422,10 @@ static void mtip_init_port(struct mtip_port *port) /* Clear any pending interrupts for this port */ writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + /* Clear any pending interrupts on the HBA. */ + writel(readl(port->dd->mmio + HOST_IRQ_STAT), + port->dd->mmio + HOST_IRQ_STAT); + /* Enable port interrupts */ writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK); } @@ -490,11 +494,9 @@ static void mtip_restart_port(struct mtip_port *port) dev_warn(&port->dd->pdev->dev, "COM reset failed\n"); - /* Clear SError, the PxSERR.DIAG.x should be set so clear it */ - writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + mtip_init_port(port); + mtip_start_port(port); - /* Enable the DMA engine */ - mtip_enable_engine(port, 1); } /* @@ -3359,9 +3361,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - /* Set the atomic variable as 1 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); - atomic_set(&dd->resumeflag, false); /* Attach the private data to this PCI device. */ @@ -3434,8 +3433,8 @@ iomap_err: pci_set_drvdata(pdev, NULL); return rv; done: - /* Set the atomic variable as 0 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); + /* Set the atomic variable as 0 */ + atomic_set(&dd->drv_cleanup_done, false); return rv; } @@ -3463,8 +3462,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) } } } - /* Set the atomic variable as 1 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); /* Clean up the block layer. */ mtip_block_remove(dd); -- cgit 1.2.3-korg From 4dae76705fc8f9854bb732f9944e7ff9ba7a8e9f Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 13 Mar 2012 18:43:23 -0400 Subject: xen/blkback: Squash the discard support for 'file' and 'phy' type. The only reason for the distinction was for the special case of 'file' (which is assumed to be loopback device), was to reach inside the loopback device, find the underlaying file, and call fallocate on it. Fortunately "xen-blkback: convert hole punching to discard request on loop devices" removes that use-case and we now based the discard support based on blk_queue_discard(q) and extract all appropriate parameters from the 'struct request_queue'. CC: Li Dongyang Acked-by: Jan Beulich [v1: Dropping pointless initializer and keeping blank line] [v2: Remove the kfree as it is not used anymore] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/blkback.c | 19 +++++----- drivers/block/xen-blkback/common.h | 6 ---- drivers/block/xen-blkback/xenbus.c | 70 ++++++++++++++----------------------- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 70caa896997203..73f196ca713f20 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -398,21 +398,18 @@ static int dispatch_discard_io(struct xen_blkif *blkif, int err = 0; int status = BLKIF_RSP_OKAY; struct block_device *bdev = blkif->vbd.bdev; + unsigned long secure; blkif->st_ds_req++; xen_blkif_get(blkif); - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY || - blkif->blk_backend_type == BLKIF_BACKEND_FILE) { - unsigned long secure = (blkif->vbd.discard_secure && - (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? - BLKDEV_DISCARD_SECURE : 0; - err = blkdev_issue_discard(bdev, - req->u.discard.sector_number, - req->u.discard.nr_sectors, - GFP_KERNEL, secure); - } else - err = -EOPNOTSUPP; + secure = (blkif->vbd.discard_secure && + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + BLKDEV_DISCARD_SECURE : 0; + + err = blkdev_issue_discard(bdev, req->u.discard.sector_number, + req->u.discard.nr_sectors, + GFP_KERNEL, secure); if (err == -EOPNOTSUPP) { pr_debug(DRV_PFX "discard op failed, not supported\n"); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index d0ee7edc9be8ad..773cf27dc23fc5 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -146,11 +146,6 @@ enum blkif_protocol { BLKIF_PROTOCOL_X86_64 = 3, }; -enum blkif_backend_type { - BLKIF_BACKEND_PHY = 1, - BLKIF_BACKEND_FILE = 2, -}; - struct xen_vbd { /* What the domain refers to this vbd as. */ blkif_vdev_t handle; @@ -177,7 +172,6 @@ struct xen_blkif { unsigned int irq; /* Comms information. */ enum blkif_protocol blk_protocol; - enum blkif_backend_type blk_backend_type; union blkif_back_rings blk_rings; void *blk_ring; /* The VBD attached to this interface. */ diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 24a2fb57e5d012..d417c13e027e2a 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -390,61 +390,43 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) { struct xenbus_device *dev = be->dev; struct xen_blkif *blkif = be->blkif; - char *type; int err; int state = 0; + struct block_device *bdev = be->blkif->vbd.bdev; + struct request_queue *q = bdev_get_queue(bdev); - type = xenbus_read(XBT_NIL, dev->nodename, "type", NULL); - if (!IS_ERR(type)) { - if (strncmp(type, "file", 4) == 0) { - state = 1; - blkif->blk_backend_type = BLKIF_BACKEND_FILE; + if (blk_queue_discard(q)) { + err = xenbus_printf(xbt, dev->nodename, + "discard-granularity", "%u", + q->limits.discard_granularity); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-granularity"); + goto out; + } + err = xenbus_printf(xbt, dev->nodename, + "discard-alignment", "%u", + q->limits.discard_alignment); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-alignment"); + goto out; } - if (strncmp(type, "phy", 3) == 0) { - struct block_device *bdev = be->blkif->vbd.bdev; - struct request_queue *q = bdev_get_queue(bdev); - if (blk_queue_discard(q)) { - err = xenbus_printf(xbt, dev->nodename, - "discard-granularity", "%u", - q->limits.discard_granularity); - if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-granularity"); - goto kfree; - } - err = xenbus_printf(xbt, dev->nodename, - "discard-alignment", "%u", - q->limits.discard_alignment); - if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-alignment"); - goto kfree; - } - state = 1; - blkif->blk_backend_type = BLKIF_BACKEND_PHY; - } - /* Optional. */ - err = xenbus_printf(xbt, dev->nodename, - "discard-secure", "%d", - blkif->vbd.discard_secure); - if (err) { - xenbus_dev_fatal(dev, err, + state = 1; + /* Optional. */ + err = xenbus_printf(xbt, dev->nodename, + "discard-secure", "%d", + blkif->vbd.discard_secure); + if (err) { + xenbus_dev_fatal(dev, err, "writting discard-secure"); - goto kfree; - } + goto out; } - } else { - err = PTR_ERR(type); - xenbus_dev_fatal(dev, err, "reading type"); - goto out; } - err = xenbus_printf(xbt, dev->nodename, "feature-discard", "%d", state); if (err) xenbus_dev_fatal(dev, err, "writing feature-discard"); -kfree: - kfree(type); out: return err; } -- cgit 1.2.3-korg From 3389bb8bf76180eecaffdfa7dd5b35fa4a2ce9b5 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 14 Mar 2012 13:04:00 -0400 Subject: xen/blkback: Make optional features be really optional. They were using the xenbus_dev_fatal() function which would change the state of the connection immediately. Which is not what we want when we advertise optional features. So make 'feature-discard','feature-barrier','feature-flush-cache' optional. Suggested-by: Jan Beulich [v1: Made the discard function void and static] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/xenbus.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index d417c13e027e2a..89860f34a7ece7 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -381,12 +381,12 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, err = xenbus_printf(xbt, dev->nodename, "feature-flush-cache", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-flush-cache"); + dev_warn(&dev->dev, "writing feature-flush-cache (%d)", err); return err; } -int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) +static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) { struct xenbus_device *dev = be->dev; struct xen_blkif *blkif = be->blkif; @@ -400,17 +400,15 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) "discard-granularity", "%u", q->limits.discard_granularity); if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-granularity"); - goto out; + dev_warn(&dev->dev, "writing discard-granularity (%d)", err); + return; } err = xenbus_printf(xbt, dev->nodename, "discard-alignment", "%u", q->limits.discard_alignment); if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-alignment"); - goto out; + dev_warn(&dev->dev, "writing discard-alignment (%d)", err); + return; } state = 1; /* Optional. */ @@ -418,17 +416,14 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) "discard-secure", "%d", blkif->vbd.discard_secure); if (err) { - xenbus_dev_fatal(dev, err, - "writting discard-secure"); - goto out; + dev_warn(dev-dev, "writing discard-secure (%d)", err); + return; } } err = xenbus_printf(xbt, dev->nodename, "feature-discard", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-discard"); -out: - return err; + dev_warn(&dev->dev, "writing feature-discard (%d)", err); } int xen_blkbk_barrier(struct xenbus_transaction xbt, struct backend_info *be, int state) @@ -439,7 +434,7 @@ int xen_blkbk_barrier(struct xenbus_transaction xbt, err = xenbus_printf(xbt, dev->nodename, "feature-barrier", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-barrier"); + dev_warn(&dev->dev, "writing feature-barrier (%d)", err); return err; } @@ -671,14 +666,12 @@ again: return; } - err = xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support); - if (err) - goto abort; + /* If we can't advertise it is OK. */ + xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support); - err = xen_blkbk_discard(xbt, be); + xen_blkbk_discard(xbt, be); - /* If we can't advertise it is OK. */ - err = xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); + xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", (unsigned long long)vbd_sz(&be->blkif->vbd)); -- cgit 1.2.3-korg From e9986f303dc0f285401de28cf96f42f4dd23a4a1 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Thu, 29 Mar 2012 10:09:44 +0200 Subject: virtio-blk: Call revalidate_disk() upon online disk resize If a virtio disk is open in guest and a disk resize operation is done, (virsh blockresize), new size is not visible to tools like "fdisk -l". This seems to be happening as we update only part->nr_sects and not bdev->bd_inode size. Call revalidate_disk() which should take care of it. I tested growing disk size of already open disk and it works for me. Signed-off-by: Vivek Goyal Signed-off-by: Jens Axboe --- drivers/block/virtio_blk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index c4a60badf252ca..0e4ef3de9d5deb 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -351,6 +351,7 @@ static void virtblk_config_changed_work(struct work_struct *work) cap_str_10, cap_str_2); set_capacity(vblk->disk, capacity); + revalidate_disk(vblk->disk); done: mutex_unlock(&vblk->config_lock); } -- cgit 1.2.3-korg From 6d27f09a6398ee086b11804aa3a16609876f0c7c Mon Sep 17 00:00:00 2001 From: Ryosuke Saito Date: Thu, 5 Apr 2012 08:09:34 -0600 Subject: mtip32xx: fix error handling in mtip_init() Ensure that block device is properly unregistered, if pci_register_driver() fails. Signed-off-by: Ryosuke Saito Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 04f69e6da1fef6..c37073ddf7d466 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3605,18 +3605,25 @@ MODULE_DEVICE_TABLE(pci, mtip_pci_tbl); */ static int __init mtip_init(void) { + int error; + printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); /* Allocate a major block device number to use with this driver. */ - mtip_major = register_blkdev(0, MTIP_DRV_NAME); - if (mtip_major < 0) { + error = register_blkdev(0, MTIP_DRV_NAME); + if (error <= 0) { printk(KERN_ERR "Unable to register block device (%d)\n", - mtip_major); + error); return -EBUSY; } + mtip_major = error; /* Register our PCI operations. */ - return pci_register_driver(&mtip_pci_driver); + error = pci_register_driver(&mtip_pci_driver); + if (error) + unregister_blkdev(mtip_major, MTIP_DRV_NAME); + + return error; } /* -- cgit 1.2.3-korg From 45038367c271f83b649b16551bf2d8174b203cb9 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Add new bitwise flag 'dd_flag' * Merged the following flags into one variable 'dd_flag': * drv_cleanup_done * resumeflag * Added the following flags into 'dd_flag' * remove pending * init done * Removed 'ftlrebuildflag' (similar flag is already part of mti_port->flags) Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 211 +++++++++++++++++++++++++++++--------- drivers/block/mtip32xx/mtip32xx.h | 12 ++- 2 files changed, 168 insertions(+), 55 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index c37073ddf7d466..34b395d2d98de3 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -36,6 +36,7 @@ #include #include #include <../drivers/ata/ahci.h> +#include #include "mtip32xx.h" #define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) @@ -44,6 +45,7 @@ #define HW_PORT_PRIV_DMA_SZ \ (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ) +#define HOST_CAP_NZDMA (1 << 19) #define HOST_HSORG 0xFC #define HSORG_DISABLE_SLOTGRP_INTR (1<<24) #define HSORG_DISABLE_SLOTGRP_PXIS (1<<16) @@ -139,6 +141,12 @@ 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++) { @@ -165,7 +173,8 @@ static void mtip_command_cleanup(struct driver_data *dd) up(&port->cmd_slot); - atomic_set(&dd->drv_cleanup_done, true); + set_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag); + in_progress = 0; } /* @@ -262,6 +271,9 @@ static int hba_reset_nosleep(struct driver_data *dd) && time_before(jiffies, timeout)) mdelay(1); + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) + return -1; + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) return -1; @@ -451,6 +463,9 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + /* * Chip quirk: escalate to hba reset if * PxCMD.CR not clear after 500 ms @@ -479,6 +494,9 @@ static void mtip_restart_port(struct mtip_port *port) while (time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + /* Clear PxSCTL.DET */ writel(readl(port->mmio + PORT_SCR_CTL) & ~1, port->mmio + PORT_SCR_CTL); @@ -490,6 +508,9 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) dev_warn(&port->dd->pdev->dev, "COM reset failed\n"); @@ -520,7 +541,7 @@ static void mtip_timeout_function(unsigned long int data) if (unlikely(!port)) return; - if (atomic_read(&port->dd->resumeflag) == true) { + if (test_bit(MTIP_DD_FLAG_RESUME_BIT, &port->dd->dd_flag)) { mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(30000)); return; @@ -970,6 +991,9 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) /* don't proceed further */ return IRQ_HANDLED; } + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag)) + return rv; mtip_process_errors(dd, port_stat & PORT_IRQ_ERR); } @@ -1040,6 +1064,9 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) msleep(20); continue; /* svc thd is actively issuing commands */ } + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) + return -EFAULT; /* * Ignore s_active bit 0 of array element 0. * This bit will always be set @@ -1161,6 +1188,12 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command did not complete [%d] " "within timeout of %lu ms\n", atomic, timeout); + if (mtip_check_surprise_removal(port->dd->pdev) || + test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + rv = -ENXIO; + goto exec_ic_exit; + } rv = -EAGAIN; } @@ -1168,6 +1201,15 @@ static int mtip_exec_internal_command(struct mtip_port *port, & (1 << MTIP_TAG_INTERNAL)) { dev_warn(&port->dd->pdev->dev, "Retiring internal command but CI is 1.\n"); + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } + goto exec_ic_exit; } } else { @@ -1177,8 +1219,14 @@ static int mtip_exec_internal_command(struct mtip_port *port, while ((readl( port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) - && time_before(jiffies, timeout)) - ; + && time_before(jiffies, timeout)) { + if (mtip_check_surprise_removal(port->dd->pdev) || + test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + rv = -ENXIO; + goto exec_ic_exit; + } + } if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) { @@ -1186,9 +1234,17 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command did not complete [%d]\n", atomic); rv = -EAGAIN; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } } } - +exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); @@ -1242,6 +1298,9 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) int rv = 0; struct host_to_dev_fis fis; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return -EFAULT; + /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); fis.type = 0x27; @@ -1507,9 +1566,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) fis.device = command[6] & ~0x10; /* Clear the dev bit*/ - dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, " - "nsect %x, sect %x, lcyl %x, " - "hcyl %x, sel %x\n", + dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", __func__, command[0], command[1], @@ -1536,8 +1593,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) command[4] = reply->cyl_low; command[5] = reply->cyl_hi; - dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, " - "err %x , cyl_lo %x cyl_hi %x\n", + dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", __func__, command[0], command[1], @@ -2082,14 +2138,10 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, struct host_to_dev_fis *fis; struct mtip_port *port = dd->port; struct mtip_cmd *command = &port->commands[tag]; + int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; /* Map the scatter list for DMA access */ - if (dir == READ) - nents = dma_map_sg(&dd->pdev->dev, command->sg, - nents, DMA_FROM_DEVICE); - else - nents = dma_map_sg(&dd->pdev->dev, command->sg, - nents, DMA_TO_DEVICE); + nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); command->scatter_ents = nents; @@ -2129,7 +2181,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, */ command->comp_data = dd; command->comp_func = mtip_async_complete; - command->direction = (dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + command->direction = dma_dir; /* * Set the completion function and data for the command passed @@ -2193,6 +2245,10 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, down(&dd->port->cmd_slot); *tag = get_slot(dd->port); + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + up(&dd->port->cmd_slot); + return NULL; + } if (unlikely(*tag < 0)) return NULL; @@ -2209,7 +2265,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, * return value * The size, in bytes, of the data copied into buf. */ -static ssize_t hw_show_registers(struct device *dev, +static ssize_t mtip_hw_show_registers(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2255,7 +2311,7 @@ static ssize_t hw_show_registers(struct device *dev, return size; } -static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL); +static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); /* * Create the sysfs related attributes. @@ -2386,10 +2442,12 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) "FTL rebuild in progress. Polling for completion.\n"); start = jiffies; - dd->ftlrebuildflag = 1; timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); do { + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag))) + return -EFAULT; if (mtip_check_surprise_removal(dd->pdev)) return -EFAULT; @@ -2410,22 +2468,17 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) dev_warn(&dd->pdev->dev, "FTL rebuild complete (%d secs).\n", jiffies_to_msecs(jiffies - start) / 1000); - dd->ftlrebuildflag = 0; mtip_block_initialize(dd); - break; + return 0; } ssleep(10); } while (time_before(jiffies, timeout)); /* Check for timeout */ - if (dd->ftlrebuildflag) { - dev_err(&dd->pdev->dev, + dev_err(&dd->pdev->dev, "Timed out waiting for FTL rebuild to complete (%d secs).\n", jiffies_to_msecs(jiffies - start) / 1000); - return -EFAULT; - } - - return 0; + return -EFAULT; } /* @@ -2456,6 +2509,9 @@ static int mtip_service_thread(void *data) if (kthread_should_stop()) break; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag))) + break; set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; @@ -2515,6 +2571,7 @@ static int mtip_hw_init(struct driver_data *dd) int i; int rv; unsigned int num_command_slots; + unsigned long timeout, timetaken; dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; @@ -2625,14 +2682,43 @@ static int mtip_hw_init(struct driver_data *dd) dd->port->mmio + i*0x80 + PORT_SDBV; } - /* Reset the HBA. */ - if (mtip_hba_reset(dd) < 0) { - dev_err(&dd->pdev->dev, - "Card did not reset within timeout\n"); - rv = -EIO; + timetaken = jiffies; + timeout = jiffies + msecs_to_jiffies(30000); + while (((readl(dd->port->mmio + PORT_SCR_STAT) & 0x0F) != 0x03) && + time_before(jiffies, timeout)) { + mdelay(100); + } + if (unlikely(mtip_check_surprise_removal(dd->pdev))) { + timetaken = jiffies - timetaken; + dev_warn(&dd->pdev->dev, + "Surprise removal detected at %u ms\n", + jiffies_to_msecs(timetaken)); + rv = -ENODEV; + goto out2 ; + } + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + timetaken = jiffies - timetaken; + dev_warn(&dd->pdev->dev, + "Removal detected at %u ms\n", + jiffies_to_msecs(timetaken)); + rv = -EFAULT; goto out2; } + /* Conditionally reset the HBA. */ + if (!(readl(dd->mmio + HOST_CAP) & HOST_CAP_NZDMA)) { + if (mtip_hba_reset(dd) < 0) { + dev_err(&dd->pdev->dev, + "Card did not reset within timeout\n"); + rv = -EIO; + goto out2; + } + } else { + /* Clear any pending interrupts on the HBA */ + writel(readl(dd->mmio + HOST_IRQ_STAT), + dd->mmio + HOST_IRQ_STAT); + } + mtip_init_port(dd->port); mtip_start_port(dd->port); @@ -2662,6 +2748,12 @@ static int mtip_hw_init(struct driver_data *dd) mod_timer(&dd->port->cmd_timer, jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); + + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + rv = -EFAULT; + goto out3; + } + if (mtip_get_identify(dd->port, NULL) < 0) { rv = -EFAULT; goto out3; @@ -2714,9 +2806,12 @@ static int mtip_hw_exit(struct driver_data *dd) * Send standby immediate (E0h) to the drive so that it * saves its state. */ - if (atomic_read(&dd->drv_cleanup_done) != true) { + if (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { - mtip_standby_immediate(dd->port); + if (test_bit(MTIP_FLAG_REBUILD_BIT, &dd->dd_flag)) + if (mtip_standby_immediate(dd->port)) + dev_warn(&dd->pdev->dev, + "STANDBY IMMEDIATE failed\n"); /* de-initialize the port. */ mtip_deinit_port(dd->port); @@ -2894,6 +2989,9 @@ static int mtip_block_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + return -ENOTTY; + switch (cmd) { case BLKFLSBUF: return -ENOTTY; @@ -2929,6 +3027,9 @@ static int mtip_block_compat_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + return -ENOTTY; + switch (cmd) { case BLKFLSBUF: return -ENOTTY; @@ -3051,6 +3152,11 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + bio_endio(bio, -ENXIO); + return; + } + if (unlikely(!bio_has_data(bio))) { blk_queue_flush(queue, 0); bio_endio(bio, 0); @@ -3063,7 +3169,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) { dev_warn(&dd->pdev->dev, - "Maximum number of SGL entries exceeded"); + "Maximum number of SGL entries exceeded\n"); bio_io_error(bio); mtip_hw_release_scatterlist(dd, tag); return; @@ -3212,8 +3318,10 @@ skip_create_disk: kobject_put(kobj); } - if (dd->mtip_svc_handler) + if (dd->mtip_svc_handler) { + set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); return rv; /* service thread created for handling rebuild */ + } start_service_thread: sprintf(thd_name, "mtip_svc_thd_%02d", index); @@ -3228,6 +3336,9 @@ start_service_thread: goto kthread_run_error; } + if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) + rv = wait_for_rebuild; + return rv; kthread_run_error: @@ -3274,10 +3385,12 @@ static int mtip_block_remove(struct driver_data *dd) } /* Clean up the sysfs attributes managed by the protocol layer. */ - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); - if (kobj) { - mtip_hw_sysfs_exit(dd, kobj); - kobject_put(kobj); + if (test_bit(MTIP_DD_FLAG_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); + } } /* @@ -3361,8 +3474,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - atomic_set(&dd->resumeflag, false); - /* Attach the private data to this PCI device. */ pci_set_drvdata(pdev, dd); @@ -3419,7 +3530,8 @@ static int mtip_pci_probe(struct pci_dev *pdev, * instance number. */ instance++; - + if (rv != MTIP_FTL_REBUILD_MAGIC) + set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); goto done; block_initialize_err: @@ -3433,9 +3545,6 @@ iomap_err: pci_set_drvdata(pdev, NULL); return rv; done: - /* Set the atomic variable as 0 */ - atomic_set(&dd->drv_cleanup_done, false); - return rv; } @@ -3451,8 +3560,10 @@ static void mtip_pci_remove(struct pci_dev *pdev) struct driver_data *dd = pci_get_drvdata(pdev); int counter = 0; + set_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag); + if (mtip_check_surprise_removal(pdev)) { - while (atomic_read(&dd->drv_cleanup_done) == false) { + while (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { counter++; msleep(20); if (counter == 10) { @@ -3490,7 +3601,7 @@ static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) return -EFAULT; } - atomic_set(&dd->resumeflag, true); + set_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); /* Disable ports & interrupts then send standby immediate */ rv = mtip_block_suspend(dd); @@ -3556,7 +3667,7 @@ static int mtip_pci_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "Unable to resume\n"); err: - atomic_set(&dd->resumeflag, false); + clear_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); return rv; } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index e0554a8f2233fa..f4e46cc81d55fc 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -121,6 +121,12 @@ #define MTIP_FLAG_REBUILD_BIT 5 #define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 +/* below are bit numbers in 'dd_flag' defined in driver_data */ +#define MTIP_DD_FLAG_REMOVE_PENDING_BIT 1 +#define MTIP_DD_FLAG_RESUME_BIT 2 +#define MTIP_DD_FLAG_CLEANUP_BIT 3 +#define MTIP_DD_FLAG_INIT_DONE_BIT 4 + /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { /* @@ -404,13 +410,9 @@ struct driver_data { unsigned slot_groups; /* number of slot groups the product supports */ - atomic_t drv_cleanup_done; /* Atomic variable for SRSI */ - unsigned long index; /* Index to determine the disk name */ - unsigned int ftlrebuildflag; /* FTL rebuild flag */ - - atomic_t resumeflag; /* Atomic variable to track suspend/resume */ + unsigned long dd_flag; /* NOTE: use atomic bit operations on this */ struct task_struct *mtip_svc_handler; /* task_struct of svc thd */ }; -- cgit 1.2.3-korg From dad40f16ff683a10f4f2bea55a0b9fd86d3db58e Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: make setting comp_time as common Moved setting completion time into mtip_issue_ncq_command() Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 34b395d2d98de3..aaa82453ae741d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -306,6 +306,10 @@ static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) port->cmd_issue[MTIP_TAG_INDEX(tag)]); spin_unlock_irqrestore(&port->cmd_issue_lock, flags); + + /* Set the command's timeout value.*/ + port->commands[tag].comp_time = jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); } /* @@ -824,10 +828,6 @@ static void mtip_handle_tfe(struct driver_data *dd) set_bit(tag, tagaccum); - /* Update the timeout value. */ - port->commands[tag].comp_time = - jiffies + msecs_to_jiffies( - MTIP_NCQ_COMMAND_TIMEOUT_MS); /* Re-issue the command. */ mtip_issue_ncq_command(port, tag); @@ -2204,9 +2204,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, /* Issue the command to the hardware */ mtip_issue_ncq_command(port, tag); - /* Set the command's timeout value.*/ - port->commands[tag].comp_time = jiffies + msecs_to_jiffies( - MTIP_NCQ_COMMAND_TIMEOUT_MS); + return; } /* @@ -2538,10 +2536,6 @@ static int mtip_service_thread(void *data) /* Issue the command to the hardware */ mtip_issue_ncq_command(port, slot); - /* Set the command's timeout value.*/ - port->commands[slot].comp_time = jiffies + - msecs_to_jiffies(MTIP_NCQ_COMMAND_TIMEOUT_MS); - clear_bit(slot, port->cmds_to_issue); } -- cgit 1.2.3-korg From f65872177d838a33e90cbae25625b9bec05134ca Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Add new sysfs entry 'status' * Add support for detecting the following device status - write protect - over temp (thermal shutdown) * Add new sysfs entry 'status', possible values - online, write_protect, thermal_shutdown * Add new file 'sysfs-block-rssd' to document ABI (Reported-by: Greg Kroah-Hartman) Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block-rssd | 18 ++ drivers/block/mtip32xx/mtip32xx.c | 323 ++++++++++++++++++++++++++--- drivers/block/mtip32xx/mtip32xx.h | 19 ++ 3 files changed, 331 insertions(+), 29 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-block-rssd diff --git a/Documentation/ABI/testing/sysfs-block-rssd b/Documentation/ABI/testing/sysfs-block-rssd new file mode 100644 index 00000000000000..d535757799feda --- /dev/null +++ b/Documentation/ABI/testing/sysfs-block-rssd @@ -0,0 +1,18 @@ +What: /sys/block/rssd*/registers +Date: March 2012 +KernelVersion: 3.3 +Contact: Asai Thambi S P +Description: This is a read-only file. Dumps below driver information and + hardware registers. + - S ACTive + - Command Issue + - Allocated + - Completed + - PORT IRQ STAT + - HOST IRQ STAT + +What: /sys/block/rssd*/status +Date: April 2012 +KernelVersion: 3.4 +Contact: Asai Thambi S P +Description: This is a read-only file. Indicates the status of the device. diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index aaa82453ae741d..79fdb063f9c05d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -725,6 +725,10 @@ static void print_tags(struct driver_data *dd, dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); } +static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, + dma_addr_t buffer_dma, unsigned int sectors); +static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, + struct smart_attr *attrib); /* * Handle an error. * @@ -735,12 +739,15 @@ static void print_tags(struct driver_data *dd, */ static void mtip_handle_tfe(struct driver_data *dd) { - int group, tag, bit, reissue; + int group, tag, bit, reissue, rv; struct mtip_port *port; - struct mtip_cmd *command; + struct mtip_cmd *cmd; u32 completed; struct host_to_dev_fis *fis; unsigned long tagaccum[SLOTBITS_IN_LONGS]; + unsigned char *buf; + char *fail_reason = NULL; + int fail_all_ncq_write = 0, fail_all_ncq_cmds = 0; dev_warn(&dd->pdev->dev, "Taskfile error\n"); @@ -772,13 +779,13 @@ static void mtip_handle_tfe(struct driver_data *dd) if (tag == MTIP_TAG_INTERNAL) continue; - command = &port->commands[tag]; - if (likely(command->comp_func)) { + cmd = &port->commands[tag]; + if (likely(cmd->comp_func)) { set_bit(tag, tagaccum); - atomic_set(&port->commands[tag].active, 0); - command->comp_func(port, + atomic_set(&cmd->active, 0); + cmd->comp_func(port, tag, - command->comp_data, + cmd->comp_data, 0); } else { dev_err(&port->dd->pdev->dev, @@ -798,6 +805,38 @@ static void mtip_handle_tfe(struct driver_data *dd) mdelay(20); mtip_restart_port(port); + /* Trying to determine the cause of the error */ + rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, + dd->port->log_buf, + dd->port->log_buf_dma, 1); + if (rv) { + dev_warn(&dd->pdev->dev, + "Error in READ LOG EXT (10h) command\n"); + /* non-critical error, don't fail the load */ + } else { + buf = (unsigned char *)dd->port->log_buf; + if (buf[259] & 0x1) { + dev_info(&dd->pdev->dev, + "Write protect bit is set.\n"); + set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + fail_all_ncq_write = 1; + fail_reason = "write protect"; + } + if (buf[288] == 0xF7) { + dev_info(&dd->pdev->dev, + "Exceeded Tmax, drive in thermal shutdown.\n"); + set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + fail_all_ncq_cmds = 1; + fail_reason = "thermal shutdown"; + } + if (buf[288] == 0xBF) { + dev_info(&dd->pdev->dev, + "Drive indicates rebuild has failed.\n"); + fail_all_ncq_cmds = 1; + fail_reason = "rebuild failed"; + } + } + /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); @@ -806,25 +845,44 @@ static void mtip_handle_tfe(struct driver_data *dd) for (bit = 0; bit < 32; bit++) { reissue = 1; tag = (group << 5) + bit; + cmd = &port->commands[tag]; /* If the active bit is set re-issue the command */ - if (atomic_read(&port->commands[tag].active) == 0) + if (atomic_read(&cmd->active) == 0) continue; - fis = (struct host_to_dev_fis *) - port->commands[tag].command; + fis = (struct host_to_dev_fis *)cmd->command; /* Should re-issue? */ if (tag == MTIP_TAG_INTERNAL || fis->command == ATA_CMD_SET_FEATURES) reissue = 0; + else { + if (fail_all_ncq_cmds || + (fail_all_ncq_write && + fis->command == ATA_CMD_FPDMA_WRITE)) { + dev_warn(&dd->pdev->dev, + " Fail: %s w/tag %d [%s].\n", + fis->command == ATA_CMD_FPDMA_WRITE ? + "write" : "read", + tag, + fail_reason != NULL ? + fail_reason : "unknown"); + atomic_set(&cmd->active, 0); + if (cmd->comp_func) { + cmd->comp_func(port, tag, + cmd->comp_data, + -ENODATA); + } + continue; + } + } /* * First check if this command has * exceeded its retries. */ - if (reissue && - (port->commands[tag].retries-- > 0)) { + if (reissue && (cmd->retries-- > 0)) { set_bit(tag, tagaccum); @@ -837,13 +895,13 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Retire a command that will not be reissued */ dev_warn(&port->dd->pdev->dev, "retiring tag %d\n", tag); - atomic_set(&port->commands[tag].active, 0); + atomic_set(&cmd->active, 0); - if (port->commands[tag].comp_func) - port->commands[tag].comp_func( + if (cmd->comp_func) + cmd->comp_func( port, tag, - port->commands[tag].comp_data, + cmd->comp_data, PORT_IRQ_TF_ERR); else dev_warn(&port->dd->pdev->dev, @@ -1374,6 +1432,7 @@ static int mtip_standby_immediate(struct mtip_port *port) { int rv; struct host_to_dev_fis fis; + unsigned long start; /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); @@ -1381,15 +1440,150 @@ static int mtip_standby_immediate(struct mtip_port *port) fis.opts = 1 << 7; fis.command = ATA_CMD_STANDBYNOW1; - /* Execute the command. Use a 15-second timeout for large drives. */ + start = jiffies; rv = mtip_exec_internal_command(port, &fis, 5, 0, 0, 0, - GFP_KERNEL, + GFP_ATOMIC, 15000); + dbg_printk(MTIP_DRV_NAME "Time taken to complete standby cmd: %d ms\n", + jiffies_to_msecs(jiffies - start)); + if (rv) + dev_warn(&port->dd->pdev->dev, + "STANDBY IMMEDIATE command failed.\n"); + + return rv; +} + +/* + * Issue a READ LOG EXT command to the device. + * + * @port pointer to the port structure. + * @page page number to fetch + * @buffer pointer to buffer + * @buffer_dma dma address corresponding to @buffer + * @sectors page length to fetch, in sectors + * + * return value + * @rv return value from mtip_exec_internal_command() + */ +static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, + dma_addr_t buffer_dma, unsigned int sectors) +{ + struct host_to_dev_fis fis; + + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_READ_LOG_EXT; + fis.sect_count = sectors & 0xFF; + fis.sect_cnt_ex = (sectors >> 8) & 0xFF; + fis.lba_low = page; + fis.lba_mid = 0; + fis.device = ATA_DEVICE_OBS; + + memset(buffer, 0, sectors * ATA_SECT_SIZE); + + return mtip_exec_internal_command(port, + &fis, + 5, + buffer_dma, + sectors * ATA_SECT_SIZE, + 0, + GFP_ATOMIC, + MTIP_INTERNAL_COMMAND_TIMEOUT_MS); +} + +/* + * Issue a SMART READ DATA command to the device. + * + * @port pointer to the port structure. + * @buffer pointer to buffer + * @buffer_dma dma address corresponding to @buffer + * + * return value + * @rv return value from mtip_exec_internal_command() + */ +static int mtip_get_smart_data(struct mtip_port *port, u8 *buffer, + dma_addr_t buffer_dma) +{ + struct host_to_dev_fis fis; + + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_SMART; + fis.features = 0xD0; + fis.sect_count = 1; + fis.lba_mid = 0x4F; + fis.lba_hi = 0xC2; + fis.device = ATA_DEVICE_OBS; + + return mtip_exec_internal_command(port, + &fis, + 5, + buffer_dma, + ATA_SECT_SIZE, + 0, + GFP_ATOMIC, + 15000); +} + +/* + * Get the value of a smart attribute + * + * @port pointer to the port structure + * @id attribute number + * @attrib pointer to return attrib information corresponding to @id + * + * return value + * -EINVAL NULL buffer passed or unsupported attribute @id. + * -EPERM Identify data not valid, SMART not supported or not enabled + */ +static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, + struct smart_attr *attrib) +{ + int rv, i; + struct smart_attr *pattr; + + if (!attrib) + return -EINVAL; + + if (!port->identify_valid) { + dev_warn(&port->dd->pdev->dev, "IDENTIFY DATA not valid\n"); + return -EPERM; + } + if (!(port->identify[82] & 0x1)) { + dev_warn(&port->dd->pdev->dev, "SMART not supported\n"); + return -EPERM; + } + if (!(port->identify[85] & 0x1)) { + dev_warn(&port->dd->pdev->dev, "SMART not enabled\n"); + return -EPERM; + } + + memset(port->smart_buf, 0, ATA_SECT_SIZE); + rv = mtip_get_smart_data(port, port->smart_buf, port->smart_buf_dma); + if (rv) { + dev_warn(&port->dd->pdev->dev, "Failed to ge SMART data\n"); + return rv; + } + + pattr = (struct smart_attr *)(port->smart_buf + 2); + for (i = 0; i < 29; i++, pattr++) + if (pattr->attr_id == id) { + memcpy(attrib, pattr, sizeof(struct smart_attr)); + break; + } + + if (i == 29) { + dev_warn(&port->dd->pdev->dev, + "Query for invalid SMART attribute ID\n"); + rv = -EINVAL; + } return rv; } @@ -2272,7 +2466,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev, int size = 0; int n; - size += sprintf(&buf[size], "%s:\ns_active:\n", __func__); + size += sprintf(&buf[size], "S ACTive:\n"); for (n = 0; n < dd->slot_groups; n++) size += sprintf(&buf[size], "0x%08x\n", @@ -2296,20 +2490,39 @@ static ssize_t mtip_hw_show_registers(struct device *dev, group_allocated); } - size += sprintf(&buf[size], "completed:\n"); + size += sprintf(&buf[size], "Completed:\n"); for (n = 0; n < dd->slot_groups; n++) size += sprintf(&buf[size], "0x%08x\n", readl(dd->port->completed[n])); - size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n", + size += sprintf(&buf[size], "PORT IRQ STAT : 0x%08x\n", readl(dd->port->mmio + PORT_IRQ_STAT)); - size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n", + size += sprintf(&buf[size], "HOST IRQ STAT : 0x%08x\n", readl(dd->mmio + HOST_IRQ_STAT)); return size; } + +static ssize_t mtip_hw_show_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct driver_data *dd = dev_to_disk(dev)->private_data; + int size = 0; + + if (test_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag)) + size += sprintf(buf, "%s", "thermal_shutdown\n"); + else if (test_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag)) + size += sprintf(buf, "%s", "write_protect\n"); + else + size += sprintf(buf, "%s", "online\n"); + + return size; +} + static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); +static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); /* * Create the sysfs related attributes. @@ -2328,7 +2541,10 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) if (sysfs_create_file(kobj, &dev_attr_registers.attr)) dev_warn(&dd->pdev->dev, - "Error creating registers sysfs entry\n"); + "Error creating 'registers' sysfs entry\n"); + if (sysfs_create_file(kobj, &dev_attr_status.attr)) + dev_warn(&dd->pdev->dev, + "Error creating 'status' sysfs entry\n"); return 0; } @@ -2348,6 +2564,7 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) return -EINVAL; sysfs_remove_file(kobj, &dev_attr_registers.attr); + sysfs_remove_file(kobj, &dev_attr_status.attr); return 0; } @@ -2566,6 +2783,8 @@ static int mtip_hw_init(struct driver_data *dd) int rv; unsigned int num_command_slots; unsigned long timeout, timetaken; + unsigned char *buf; + struct smart_attr attr242; dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; @@ -2600,7 +2819,7 @@ static int mtip_hw_init(struct driver_data *dd) /* Allocate memory for the command list. */ dd->port->command_list = dmam_alloc_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), &dd->port->command_list_dma, GFP_KERNEL); if (!dd->port->command_list) { @@ -2613,7 +2832,7 @@ static int mtip_hw_init(struct driver_data *dd) /* Clear the memory we have allocated. */ memset(dd->port->command_list, 0, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2)); + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4)); /* Setup the addresse of the RX FIS. */ dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; @@ -2629,10 +2848,19 @@ static int mtip_hw_init(struct driver_data *dd) dd->port->identify_dma = dd->port->command_tbl_dma + HW_CMD_TBL_AR_SZ; - /* Setup the address of the sector buffer. */ + /* Setup the address of the sector buffer - for some non-ncq cmds */ dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; + /* Setup the address of the log buf - for read log command */ + dd->port->log_buf = (void *)dd->port->sector_buffer + ATA_SECT_SIZE; + dd->port->log_buf_dma = dd->port->sector_buffer_dma + ATA_SECT_SIZE; + + /* Setup the address of the smart buf - for smart read data command */ + dd->port->smart_buf = (void *)dd->port->log_buf + ATA_SECT_SIZE; + dd->port->smart_buf_dma = dd->port->log_buf_dma + ATA_SECT_SIZE; + + /* Point the command headers at the command tables. */ for (i = 0; i < num_command_slots; i++) { dd->port->commands[i].command_header = @@ -2759,6 +2987,43 @@ static int mtip_hw_init(struct driver_data *dd) 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, + dd->port->log_buf, + dd->port->log_buf_dma, 1); + if (rv) { + dev_warn(&dd->pdev->dev, + "Error in READ LOG EXT (10h) command\n"); + /* non-critical error, don't fail the load */ + } else { + buf = (unsigned char *)dd->port->log_buf; + if (buf[259] & 0x1) { + dev_info(&dd->pdev->dev, + "Write protect bit is set.\n"); + set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + } + if (buf[288] == 0xF7) { + dev_info(&dd->pdev->dev, + "Exceeded Tmax, drive in thermal shutdown.\n"); + set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + } + if (buf[288] == 0xBF) { + dev_info(&dd->pdev->dev, + "Drive indicates rebuild has failed.\n"); + /* TODO */ + } + } + + /* get write protect progess */ + memset(&attr242, 0, sizeof(struct smart_attr)); + if (mtip_get_smart_attr(dd->port, 242, &attr242)) + dev_warn(&dd->pdev->dev, + "Unable to check write protect progress\n"); + else + dev_info(&dd->pdev->dev, + "Write protect progress: %d%% (%d blocks)\n", + attr242.cur, attr242.data); return rv; out3: @@ -2776,7 +3041,7 @@ out2: /* Free the command/command header memory. */ dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), dd->port->command_list, dd->port->command_list_dma); out1: @@ -2825,7 +3090,7 @@ static int mtip_hw_exit(struct driver_data *dd) /* Free the command/command header memory. */ dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), dd->port->command_list, dd->port->command_list_dma); /* Free the memory allocated for the for structure. */ @@ -3378,7 +3643,7 @@ static int mtip_block_remove(struct driver_data *dd) kthread_stop(dd->mtip_svc_handler); } - /* Clean up the sysfs attributes managed by the protocol layer. */ + /* Clean up the sysfs attributes, if created */ if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); if (kobj) { diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index f4e46cc81d55fc..ea5c7e7cb50d2d 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -127,6 +127,19 @@ #define MTIP_DD_FLAG_CLEANUP_BIT 3 #define MTIP_DD_FLAG_INIT_DONE_BIT 4 +#define MTIP_DD_FLAG_WRITE_PROTECT_BIT 5 +#define MTIP_DD_FLAG_OVER_TEMP_BIT 6 +#define MTIP_DD_FLAG_REBUILD_FAILED_BIT 7 + +__packed struct smart_attr{ + u8 attr_id; + u16 flags; + u8 cur; + u8 worst; + u32 data; + u8 res[3]; +}; + /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { /* @@ -351,6 +364,12 @@ struct mtip_port { * when the command slot and all associated data structures * are no longer needed. */ + u16 *log_buf; + dma_addr_t log_buf_dma; + + u8 *smart_buf; + dma_addr_t smart_buf_dma; + unsigned long allocated[SLOTBITS_IN_LONGS]; /* * used to queue commands when an internal command is in progress -- cgit 1.2.3-korg From 8182b495281764ca518781e876c91900e75088d2 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: misc changes * Handle the interrupt completion of polled internal commands * Do not check remove pending flag for standby command * On rebuild failure, - set corresponding bit dd_flag - do not send standby command * Free ida index in remove path Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 66 ++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 79fdb063f9c05d..be96626accec85 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -708,6 +708,14 @@ static void mtip_completion(struct mtip_port *port, complete(waiting); } +static void mtip_null_completion(struct mtip_port *port, + int tag, + void *data, + int status) +{ + return; +} + /* * Helper function for tag logging */ @@ -992,8 +1000,6 @@ static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) } } - dev_warn(&dd->pdev->dev, "IRQ status 0x%x ignored.\n", port_stat); - return; } @@ -1161,7 +1167,7 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) * -EAGAIN Time out waiting for command to complete. */ static int mtip_exec_internal_command(struct mtip_port *port, - void *fis, + struct host_to_dev_fis *fis, int fis_len, dma_addr_t buffer, int buf_len, @@ -1190,14 +1196,17 @@ static int mtip_exec_internal_command(struct mtip_port *port, set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); if (atomic == GFP_KERNEL) { - /* wait for io to complete if non atomic */ - if (mtip_quiesce_io(port, 5000) < 0) { - dev_warn(&port->dd->pdev->dev, - "Failed to quiesce IO\n"); - release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); - wake_up_interruptible(&port->svc_wait); - return -EBUSY; + if (fis->command != ATA_CMD_STANDBYNOW1) { + /* wait for io to complete if non atomic */ + if (mtip_quiesce_io(port, 5000) < 0) { + dev_warn(&port->dd->pdev->dev, + "Failed to quiesce IO\n"); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, + &port->flags); + wake_up_interruptible(&port->svc_wait); + return -EBUSY; + } } /* Set the completion function and data for the command. */ @@ -1207,7 +1216,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, } else { /* Clear completion - we're going to poll */ int_cmd->comp_data = NULL; - int_cmd->comp_func = NULL; + int_cmd->comp_func = mtip_null_completion; } /* Copy the command to the command table */ @@ -1273,12 +1282,14 @@ static int mtip_exec_internal_command(struct mtip_port *port, } else { /* Spin for checking if command still outstanding */ timeout = jiffies + msecs_to_jiffies(timeout); - - while ((readl( - port->cmd_issue[MTIP_TAG_INTERNAL]) - & (1 << MTIP_TAG_INTERNAL)) - && time_before(jiffies, timeout)) { - if (mtip_check_surprise_removal(port->dd->pdev) || + while ((readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) + && time_before(jiffies, timeout)) { + if (mtip_check_surprise_removal(port->dd->pdev)) { + rv = -ENXIO; + goto exec_ic_exit; + } + if ((fis->command != ATA_CMD_STANDBYNOW1) && test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; @@ -1289,8 +1300,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) { dev_err(&port->dd->pdev->dev, - "Internal command did not complete [%d]\n", - atomic); + "Internal command did not complete [atomic]\n"); rv = -EAGAIN; if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { @@ -2758,7 +2768,9 @@ static int mtip_service_thread(void *data) clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { - mtip_ftl_rebuild_poll(dd); + if (!mtip_ftl_rebuild_poll(dd)) + set_bit(MTIP_DD_FLAG_REBUILD_FAILED_BIT, + &dd->dd_flag); clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); } clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); @@ -3067,7 +3079,7 @@ static int mtip_hw_exit(struct driver_data *dd) */ if (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { - if (test_bit(MTIP_FLAG_REBUILD_BIT, &dd->dd_flag)) + if (!test_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3657,6 +3669,11 @@ static int mtip_block_remove(struct driver_data *dd) * from /dev */ del_gendisk(dd->disk); + + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + blk_cleanup_queue(dd->queue); dd->disk = NULL; dd->queue = NULL; @@ -3686,6 +3703,11 @@ static int mtip_block_shutdown(struct driver_data *dd) /* Delete our gendisk structure, and cleanup the blk queue. */ del_gendisk(dd->disk); + + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + blk_cleanup_queue(dd->queue); dd->disk = NULL; dd->queue = NULL; -- cgit 1.2.3-korg From 8a857a880bd83ba4f217d55dd4a623a7e4b5cb47 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Shorten macro names Shortened macros used to represent mtip_port->flags and dd->dd_flag Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 124 +++++++++++++++++++------------------- drivers/block/mtip32xx/mtip32xx.h | 28 ++++----- 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index be96626accec85..e57864a7912e67 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -173,7 +173,7 @@ static void mtip_command_cleanup(struct driver_data *dd) up(&port->cmd_slot); - set_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); in_progress = 0; } @@ -271,7 +271,7 @@ static int hba_reset_nosleep(struct driver_data *dd) && time_before(jiffies, timeout)) mdelay(1); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) return -1; if (readl(dd->mmio + HOST_CTL) & HOST_RESET) @@ -467,7 +467,7 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; /* @@ -498,7 +498,7 @@ static void mtip_restart_port(struct mtip_port *port) while (time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; /* Clear PxSCTL.DET */ @@ -512,7 +512,7 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) @@ -545,7 +545,7 @@ static void mtip_timeout_function(unsigned long int data) if (unlikely(!port)) return; - if (test_bit(MTIP_DD_FLAG_RESUME_BIT, &port->dd->dd_flag)) { + if (test_bit(MTIP_DDF_RESUME_BIT, &port->dd->dd_flag)) { mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(30000)); return; @@ -572,7 +572,7 @@ static void mtip_timeout_function(unsigned long int data) cmdto_cnt++; if (cmdto_cnt == 1) - set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); /* * Clear the completed bit. This should prevent @@ -610,7 +610,7 @@ static void mtip_timeout_function(unsigned long int data) "%d commands timed out: restarting port", cmdto_cnt); mtip_restart_port(port); - clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); } @@ -765,7 +765,7 @@ static void mtip_handle_tfe(struct driver_data *dd) del_timer(&port->cmd_timer); /* Set eh_active */ - set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); /* Loop through all the groups */ for (group = 0; group < dd->slot_groups; group++) { @@ -826,14 +826,14 @@ static void mtip_handle_tfe(struct driver_data *dd) if (buf[259] & 0x1) { dev_info(&dd->pdev->dev, "Write protect bit is set.\n"); - set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); fail_all_ncq_write = 1; fail_reason = "write protect"; } if (buf[288] == 0xF7) { dev_info(&dd->pdev->dev, "Exceeded Tmax, drive in thermal shutdown.\n"); - set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); fail_all_ncq_cmds = 1; fail_reason = "thermal shutdown"; } @@ -920,7 +920,7 @@ static void mtip_handle_tfe(struct driver_data *dd) print_tags(dd, "TFE tags reissued:", tagaccum); /* clear eh_active */ - clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); mod_timer(&port->cmd_timer, @@ -988,7 +988,7 @@ static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) struct mtip_port *port = dd->port; struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL]; - if (test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL))) { if (cmd->comp_func) { @@ -1055,7 +1055,7 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) /* don't proceed further */ return IRQ_HANDLED; } - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) return rv; @@ -1123,13 +1123,12 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) to = jiffies + msecs_to_jiffies(timeout); do { - if (test_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags) && - test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) && + test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { msleep(20); continue; /* svc thd is actively issuing commands */ } - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, - &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return -EFAULT; /* * Ignore s_active bit 0 of array element 0. @@ -1193,7 +1192,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command already active\n"); return -EBUSY; } - set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); if (atomic == GFP_KERNEL) { if (fis->command != ATA_CMD_STANDBYNOW1) { @@ -1202,8 +1201,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, dev_warn(&port->dd->pdev->dev, "Failed to quiesce IO\n"); release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, - &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); return -EBUSY; } @@ -1256,7 +1254,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, "within timeout of %lu ms\n", atomic, timeout); if (mtip_check_surprise_removal(port->dd->pdev) || - test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; goto exec_ic_exit; @@ -1268,7 +1266,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, & (1 << MTIP_TAG_INTERNAL)) { dev_warn(&port->dd->pdev->dev, "Retiring internal command but CI is 1.\n"); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { hba_reset_nosleep(port->dd); rv = -ENXIO; @@ -1290,7 +1288,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, goto exec_ic_exit; } if ((fis->command != ATA_CMD_STANDBYNOW1) && - test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; goto exec_ic_exit; @@ -1302,7 +1300,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, dev_err(&port->dd->pdev->dev, "Internal command did not complete [atomic]\n"); rv = -EAGAIN; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { hba_reset_nosleep(port->dd); rv = -ENXIO; @@ -1316,7 +1314,7 @@ exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); return rv; @@ -1366,7 +1364,7 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) int rv = 0; struct host_to_dev_fis fis; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return -EFAULT; /* Build the FIS. */ @@ -2398,10 +2396,10 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, * To prevent this command from being issued * if an internal command is in progress or error handling is active. */ - if (unlikely(test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) || - test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags))) { + if (unlikely(test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) || + test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))) { set_bit(tag, port->cmds_to_issue); - set_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); return; } @@ -2447,7 +2445,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, down(&dd->port->cmd_slot); *tag = get_slot(dd->port); - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { up(&dd->port->cmd_slot); return NULL; } @@ -2521,9 +2519,9 @@ static ssize_t mtip_hw_show_status(struct device *dev, struct driver_data *dd = dev_to_disk(dev)->private_data; int size = 0; - if (test_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag)) + if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag)) size += sprintf(buf, "%s", "thermal_shutdown\n"); - else if (test_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag)) + else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag)) size += sprintf(buf, "%s", "write_protect\n"); else size += sprintf(buf, "%s", "online\n"); @@ -2670,7 +2668,7 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); do { - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -EFAULT; if (mtip_check_surprise_removal(dd->pdev)) @@ -2728,17 +2726,17 @@ static int mtip_service_thread(void *data) * is in progress nor error handling is active */ wait_event_interruptible(port->svc_wait, (port->flags) && - !test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && - !test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags)); + !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && + !test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)); if (kthread_should_stop()) break; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) break; - set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + 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 */ slot_start = num_cmd_slots; @@ -2766,16 +2764,16 @@ static int mtip_service_thread(void *data) clear_bit(slot, port->cmds_to_issue); } - clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); - } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { + 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)) - set_bit(MTIP_DD_FLAG_REBUILD_FAILED_BIT, + set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag); - clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); + clear_bit(MTIP_PF_REBUILD_BIT, &port->flags); } - clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + if (test_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &port->flags)) break; } return 0; @@ -2930,7 +2928,7 @@ static int mtip_hw_init(struct driver_data *dd) rv = -ENODEV; goto out2 ; } - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { timetaken = jiffies - timetaken; dev_warn(&dd->pdev->dev, "Removal detected at %u ms\n", @@ -2983,7 +2981,7 @@ static int mtip_hw_init(struct driver_data *dd) jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { rv = -EFAULT; goto out3; } @@ -2995,7 +2993,7 @@ static int mtip_hw_init(struct driver_data *dd) if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == MTIP_FTL_REBUILD_MAGIC) { - set_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags); + set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); return MTIP_FTL_REBUILD_MAGIC; } mtip_dump_identify(dd->port); @@ -3013,12 +3011,12 @@ static int mtip_hw_init(struct driver_data *dd) if (buf[259] & 0x1) { dev_info(&dd->pdev->dev, "Write protect bit is set.\n"); - set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); } if (buf[288] == 0xF7) { dev_info(&dd->pdev->dev, "Exceeded Tmax, drive in thermal shutdown.\n"); - set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); } if (buf[288] == 0xBF) { dev_info(&dd->pdev->dev, @@ -3077,9 +3075,9 @@ 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_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { + if (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { - if (!test_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags)) + if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3260,7 +3258,7 @@ static int mtip_block_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -ENOTTY; switch (cmd) { @@ -3298,7 +3296,7 @@ static int mtip_block_compat_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -ENOTTY; switch (cmd) { @@ -3423,7 +3421,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { bio_endio(bio, -ENXIO); return; } @@ -3590,7 +3588,7 @@ skip_create_disk: } if (dd->mtip_svc_handler) { - set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); return rv; /* service thread created for handling rebuild */ } @@ -3650,13 +3648,13 @@ static int mtip_block_remove(struct driver_data *dd) struct kobject *kobj; if (dd->mtip_svc_handler) { - set_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + set_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); wake_up_interruptible(&dd->port->svc_wait); kthread_stop(dd->mtip_svc_handler); } /* Clean up the sysfs attributes, if created */ - if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { + 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); @@ -3812,7 +3810,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, */ instance++; if (rv != MTIP_FTL_REBUILD_MAGIC) - set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); goto done; block_initialize_err: @@ -3841,10 +3839,10 @@ static void mtip_pci_remove(struct pci_dev *pdev) struct driver_data *dd = pci_get_drvdata(pdev); int counter = 0; - set_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag); if (mtip_check_surprise_removal(pdev)) { - while (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { + while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { counter++; msleep(20); if (counter == 10) { @@ -3882,7 +3880,7 @@ static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) return -EFAULT; } - set_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_RESUME_BIT, &dd->dd_flag); /* Disable ports & interrupts then send standby immediate */ rv = mtip_block_suspend(dd); @@ -3948,7 +3946,7 @@ static int mtip_pci_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "Unable to resume\n"); err: - clear_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); + clear_bit(MTIP_DDF_RESUME_BIT, &dd->dd_flag); return rv; } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index ea5c7e7cb50d2d..5ad2d79f7c4bb6 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -114,22 +114,22 @@ #define __force_bit2int (unsigned int __force) /* below are bit numbers in 'flags' defined in mtip_port */ -#define MTIP_FLAG_IC_ACTIVE_BIT 0 -#define MTIP_FLAG_EH_ACTIVE_BIT 1 -#define MTIP_FLAG_SVC_THD_ACTIVE_BIT 2 -#define MTIP_FLAG_ISSUE_CMDS_BIT 4 -#define MTIP_FLAG_REBUILD_BIT 5 -#define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 +#define MTIP_PF_IC_ACTIVE_BIT 0 +#define MTIP_PF_EH_ACTIVE_BIT 1 +#define MTIP_PF_SVC_THD_ACTIVE_BIT 2 +#define MTIP_PF_ISSUE_CMDS_BIT 4 +#define MTIP_PF_REBUILD_BIT 5 +#define MTIP_PF_SVC_THD_SHOULD_STOP_BIT 8 /* below are bit numbers in 'dd_flag' defined in driver_data */ -#define MTIP_DD_FLAG_REMOVE_PENDING_BIT 1 -#define MTIP_DD_FLAG_RESUME_BIT 2 -#define MTIP_DD_FLAG_CLEANUP_BIT 3 -#define MTIP_DD_FLAG_INIT_DONE_BIT 4 - -#define MTIP_DD_FLAG_WRITE_PROTECT_BIT 5 -#define MTIP_DD_FLAG_OVER_TEMP_BIT 6 -#define MTIP_DD_FLAG_REBUILD_FAILED_BIT 7 +#define MTIP_DDF_REMOVE_PENDING_BIT 1 +#define MTIP_DDF_RESUME_BIT 2 +#define MTIP_DDF_CLEANUP_BIT 3 +#define MTIP_DDF_INIT_DONE_BIT 4 + +#define MTIP_DDF_WRITE_PROTECT_BIT 5 +#define MTIP_DDF_OVER_TEMP_BIT 6 +#define MTIP_DDF_REBUILD_FAILED_BIT 7 __packed struct smart_attr{ u8 attr_id; -- cgit 1.2.3-korg From c74b0f586fa3cbc92ca451836fd75ae7a3fa85ac Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:39 +0200 Subject: mtip32xx: fix handling of commands in various scenarios * If a ncq command time out and a non-ncq command is active, skip restart port * Queue(pause) ncq commands during operations spanning more than one non-ncq commands - secure erase, download microcode * When a non-ncq command is active, allow incoming non-ncq commands to wait instead of failing back * Changed timeout for download microcode and smart commands * If the device in write protect mode, fail all writes (do not send to device) * Set maximum retries to 2 Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 144 ++++++++++++++++++++++++++++---------- drivers/block/mtip32xx/mtip32xx.h | 39 +++++++---- 2 files changed, 132 insertions(+), 51 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index e57864a7912e67..47404ef5749fc7 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -436,7 +436,8 @@ static void mtip_init_port(struct mtip_port *port) writel(0xFFFFFFFF, port->completed[i]); /* Clear any pending interrupts for this port */ - writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + writel(readl(port->dd->mmio + PORT_IRQ_STAT), + port->dd->mmio + PORT_IRQ_STAT); /* Clear any pending interrupts on the HBA. */ writel(readl(port->dd->mmio + HOST_IRQ_STAT), @@ -541,6 +542,7 @@ static void mtip_timeout_function(unsigned long int data) int tag, cmdto_cnt = 0; unsigned int bit, group; unsigned int num_command_slots = port->dd->slot_groups * 32; + unsigned long to; if (unlikely(!port)) return; @@ -605,7 +607,7 @@ static void mtip_timeout_function(unsigned long int data) } } - if (cmdto_cnt) { + if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { dev_warn(&port->dd->pdev->dev, "%d commands timed out: restarting port", cmdto_cnt); @@ -614,6 +616,21 @@ static void mtip_timeout_function(unsigned long int data) wake_up_interruptible(&port->svc_wait); } + if (port->ic_pause_timer) { + to = port->ic_pause_timer + msecs_to_jiffies(1000); + if (time_after(jiffies, to)) { + if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { + port->ic_pause_timer = 0; + clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + } + + + } + } + /* Restart the timer */ mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); @@ -1105,6 +1122,39 @@ static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag) port->cmd_issue[MTIP_TAG_INDEX(tag)]); } +static bool mtip_pause_ncq(struct mtip_port *port, + struct host_to_dev_fis *fis) +{ + struct host_to_dev_fis *reply; + unsigned long task_file_data; + + reply = port->rxfis + RX_FIS_D2H_REG; + task_file_data = readl(port->mmio+PORT_TFDATA); + + if ((task_file_data & 1) || (fis->command == ATA_CMD_SEC_ERASE_UNIT)) + return false; + + if (fis->command == ATA_CMD_SEC_ERASE_PREP) { + set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = jiffies; + return true; + } else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) && + (fis->features == 0x03)) { + set_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = jiffies; + return true; + } else if ((fis->command == ATA_CMD_SEC_ERASE_UNIT) || + ((fis->command == 0xFC) && + (fis->features == 0x27 || fis->features == 0x72 || + fis->features == 0x62 || fis->features == 0x26))) { + /* Com reset after secure erase or lowlevel format */ + mtip_restart_port(port); + return false; + } + + return false; +} + /* * Wait for port to quiesce * @@ -1176,8 +1226,9 @@ static int mtip_exec_internal_command(struct mtip_port *port, { struct mtip_cmd_sg *command_sg; DECLARE_COMPLETION_ONSTACK(wait); - int rv = 0; + int rv = 0, ready2go = 1; struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL]; + unsigned long to; /* Make sure the buffer is 8 byte aligned. This is asic specific. */ if (buffer & 0x00000007) { @@ -1186,13 +1237,26 @@ static int mtip_exec_internal_command(struct mtip_port *port, return -EFAULT; } - /* Only one internal command should be running at a time */ - if (test_and_set_bit(MTIP_TAG_INTERNAL, port->allocated)) { + to = jiffies + msecs_to_jiffies(timeout); + do { + ready2go = !test_and_set_bit(MTIP_TAG_INTERNAL, + port->allocated); + if (ready2go) + break; + mdelay(100); + } while (time_before(jiffies, to)); + if (!ready2go) { dev_warn(&port->dd->pdev->dev, - "Internal command already active\n"); + "Internal cmd active. new cmd [%02X]\n", fis->command); return -EBUSY; } set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = 0; + + if (fis->command == ATA_CMD_SEC_ERASE_UNIT) + 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); if (atomic == GFP_KERNEL) { if (fis->command != ATA_CMD_STANDBYNOW1) { @@ -1314,6 +1378,10 @@ exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); + if (rv >= 0 && mtip_pause_ncq(port, fis)) { + /* NCQ paused */ + return rv; + } clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); @@ -1767,8 +1835,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) fis.cyl_hi = command[5]; fis.device = command[6] & ~0x10; /* Clear the dev bit*/ - - dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", + dbg_printk(MTIP_DRV_NAME " %s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", __func__, command[0], command[1], @@ -1795,7 +1862,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) command[4] = reply->cyl_low; command[5] = reply->cyl_hi; - dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", + dbg_printk(MTIP_DRV_NAME " %s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", __func__, command[0], command[1], @@ -1838,7 +1905,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, } dbg_printk(MTIP_DRV_NAME - "%s: User Command: cmd %x, sect %x, " + " %s: User Command: cmd %x, sect %x, " "feat %x, sectcnt %x\n", __func__, command[0], @@ -1867,7 +1934,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, command[2] = command[3]; dbg_printk(MTIP_DRV_NAME - "%s: Completion Status: stat %x, " + " %s: Completion Status: stat %x, " "err %x, cmd %x\n", __func__, command[0], @@ -2070,9 +2137,10 @@ static int exec_drive_taskfile(struct driver_data *dd, } dbg_printk(MTIP_DRV_NAME - "taskfile: cmd %x, feat %x, nsect %x," + " %s: cmd %x, feat %x, nsect %x," " sect/lbal %x, lcyl/lbam %x, hcyl/lbah %x," " head/dev %x\n", + __func__, fis.command, fis.features, fis.sect_count, @@ -2083,8 +2151,8 @@ static int exec_drive_taskfile(struct driver_data *dd, switch (fis.command) { case ATA_CMD_DOWNLOAD_MICRO: - /* Change timeout for Download Microcode to 60 seconds.*/ - timeout = 60000; + /* Change timeout for Download Microcode to 2 minutes */ + timeout = 120000; break; case ATA_CMD_SEC_ERASE_UNIT: /* Change timeout for Security Erase Unit to 4 minutes.*/ @@ -2100,8 +2168,8 @@ static int exec_drive_taskfile(struct driver_data *dd, timeout = 10000; break; case ATA_CMD_SMART: - /* Change timeout for vendor unique command to 10 secs */ - timeout = 10000; + /* Change timeout for vendor unique command to 15 secs */ + timeout = 15000; break; default: timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; @@ -2163,18 +2231,8 @@ static int exec_drive_taskfile(struct driver_data *dd, req_task->hob_ports[1] = reply->features_ex; req_task->hob_ports[2] = reply->sect_cnt_ex; } - - /* Com rest after secure erase or lowlevel format */ - if (((fis.command == ATA_CMD_SEC_ERASE_UNIT) || - ((fis.command == 0xFC) && - (fis.features == 0x27 || fis.features == 0x72 || - fis.features == 0x62 || fis.features == 0x26))) && - !(reply->command & 1)) { - mtip_restart_port(dd->port); - } - dbg_printk(MTIP_DRV_NAME - "%s: Completion: stat %x," + " %s: Completion: stat %x," "err %x, sect_cnt %x, lbalo %x," "lbamid %x, lbahi %x, dev %x\n", __func__, @@ -2396,8 +2454,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, * To prevent this command from being issued * if an internal command is in progress or error handling is active. */ - if (unlikely(test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) || - test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))) { + if (port->flags & MTIP_PF_PAUSE_IO) { set_bit(tag, port->cmds_to_issue); set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); return; @@ -2726,8 +2783,7 @@ static int mtip_service_thread(void *data) * is in progress nor error handling is active */ wait_event_interruptible(port->svc_wait, (port->flags) && - !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && - !test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)); + !(port->flags & MTIP_PF_PAUSE_IO)); if (kthread_should_stop()) break; @@ -2735,6 +2791,7 @@ static int mtip_service_thread(void *data) if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) break; + set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; @@ -2773,7 +2830,7 @@ static int mtip_service_thread(void *data) } clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + if (test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags)) break; } return 0; @@ -3421,9 +3478,22 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; - if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { - bio_endio(bio, -ENXIO); - return; + if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, + &dd->dd_flag))) { + bio_endio(bio, -ENXIO); + return; + } + if (unlikely(test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))) { + bio_endio(bio, -ENODATA); + return; + } + if (unlikely(test_bit(MTIP_DDF_WRITE_PROTECT_BIT, + &dd->dd_flag) && + bio_data_dir(bio))) { + bio_endio(bio, -ENODATA); + return; + } } if (unlikely(!bio_has_data(bio))) { @@ -3599,7 +3669,7 @@ start_service_thread: dd, thd_name); if (IS_ERR(dd->mtip_svc_handler)) { - printk(KERN_ERR "mtip32xx: service thread failed to start\n"); + dev_err(&dd->pdev->dev, "service thread failed to start\n"); dd->mtip_svc_handler = NULL; rv = -EFAULT; goto kthread_run_error; @@ -3648,7 +3718,7 @@ static int mtip_block_remove(struct driver_data *dd) struct kobject *kobj; if (dd->mtip_svc_handler) { - set_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); wake_up_interruptible(&dd->port->svc_wait); kthread_stop(dd->mtip_svc_handler); } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 5ad2d79f7c4bb6..4ef58336310a12 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -34,8 +34,8 @@ /* offset of Device Control register in PCIe extended capabilites space */ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 -/* # of times to retry timed out IOs */ -#define MTIP_MAX_RETRIES 5 +/* # of times to retry timed out/failed IOs */ +#define MTIP_MAX_RETRIES 2 /* Various timeout values in ms */ #define MTIP_NCQ_COMMAND_TIMEOUT_MS 5000 @@ -114,22 +114,32 @@ #define __force_bit2int (unsigned int __force) /* below are bit numbers in 'flags' defined in mtip_port */ -#define MTIP_PF_IC_ACTIVE_BIT 0 -#define MTIP_PF_EH_ACTIVE_BIT 1 -#define MTIP_PF_SVC_THD_ACTIVE_BIT 2 -#define MTIP_PF_ISSUE_CMDS_BIT 4 -#define MTIP_PF_REBUILD_BIT 5 -#define MTIP_PF_SVC_THD_SHOULD_STOP_BIT 8 +#define MTIP_PF_IC_ACTIVE_BIT 0 /* pio/ioctl */ +#define MTIP_PF_EH_ACTIVE_BIT 1 /* error handling */ +#define MTIP_PF_SE_ACTIVE_BIT 2 /* secure erase */ +#define MTIP_PF_DM_ACTIVE_BIT 3 /* download microcde */ +#define MTIP_PF_PAUSE_IO ((1 << MTIP_PF_IC_ACTIVE_BIT) | \ + (1 << MTIP_PF_EH_ACTIVE_BIT) | \ + (1 << MTIP_PF_SE_ACTIVE_BIT) | \ + (1 << MTIP_PF_DM_ACTIVE_BIT)) + +#define MTIP_PF_SVC_THD_ACTIVE_BIT 4 +#define MTIP_PF_ISSUE_CMDS_BIT 5 +#define MTIP_PF_REBUILD_BIT 6 +#define MTIP_PF_SVC_THD_STOP_BIT 8 /* below are bit numbers in 'dd_flag' defined in driver_data */ #define MTIP_DDF_REMOVE_PENDING_BIT 1 -#define MTIP_DDF_RESUME_BIT 2 -#define MTIP_DDF_CLEANUP_BIT 3 -#define MTIP_DDF_INIT_DONE_BIT 4 +#define MTIP_DDF_OVER_TEMP_BIT 2 +#define MTIP_DDF_WRITE_PROTECT_BIT 3 +#define MTIP_DDF_STOP_IO ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ + (1 << MTIP_DDF_OVER_TEMP_BIT) | \ + (1 << MTIP_DDF_WRITE_PROTECT_BIT)) -#define MTIP_DDF_WRITE_PROTECT_BIT 5 -#define MTIP_DDF_OVER_TEMP_BIT 6 -#define MTIP_DDF_REBUILD_FAILED_BIT 7 +#define MTIP_DDF_CLEANUP_BIT 5 +#define MTIP_DDF_RESUME_BIT 6 +#define MTIP_DDF_INIT_DONE_BIT 7 +#define MTIP_DDF_REBUILD_FAILED_BIT 8 __packed struct smart_attr{ u8 attr_id; @@ -393,6 +403,7 @@ struct mtip_port { * Timer used to complete commands that have been active for too long. */ struct timer_list cmd_timer; + unsigned long ic_pause_timer; /* * Semaphore used to block threads if there are no * command slots available. -- cgit 1.2.3-korg From 95fea2f1d90626498e2495a81fe5aab7fba9fb3f Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:39 +0200 Subject: mtip32xx: dump tagmap on failure Dump tagmap on failure, instead of individual tags. Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 62 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 47404ef5749fc7..00f9fc99209009 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -525,6 +525,25 @@ static void mtip_restart_port(struct mtip_port *port) } +/* + * Helper function for tag logging + */ +static void print_tags(struct driver_data *dd, + char *msg, + unsigned long *tagbits, + int cnt) +{ + unsigned char tagmap[128]; + int group, tagmap_len = 0; + + memset(tagmap, 0, sizeof(tagmap)); + for (group = SLOTBITS_IN_LONGS; group > 0; group--) + tagmap_len = sprintf(tagmap + tagmap_len, "%016lX ", + tagbits[group-1]); + dev_warn(&dd->pdev->dev, + "%d command(s) %s: tagmap [%s]", cnt, msg, tagmap); +} + /* * Called periodically to see if any read/write commands are * taking too long to complete. @@ -542,7 +561,7 @@ static void mtip_timeout_function(unsigned long int data) int tag, cmdto_cnt = 0; unsigned int bit, group; unsigned int num_command_slots = port->dd->slot_groups * 32; - unsigned long to; + unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; if (unlikely(!port)) return; @@ -552,6 +571,8 @@ static void mtip_timeout_function(unsigned long int data) jiffies + msecs_to_jiffies(30000)); return; } + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); for (tag = 0; tag < num_command_slots; tag++) { /* @@ -569,9 +590,7 @@ static void mtip_timeout_function(unsigned long int data) command = &port->commands[tag]; fis = (struct host_to_dev_fis *) command->command; - dev_warn(&port->dd->pdev->dev, - "Timeout for command tag %d\n", tag); - + set_bit(tag, tagaccum); cmdto_cnt++; if (cmdto_cnt == 1) set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); @@ -608,9 +627,8 @@ static void mtip_timeout_function(unsigned long int data) } if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { - dev_warn(&port->dd->pdev->dev, - "%d commands timed out: restarting port", - cmdto_cnt); + print_tags(port->dd, "timed out", tagaccum, cmdto_cnt); + mtip_restart_port(port); clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); @@ -733,23 +751,6 @@ static void mtip_null_completion(struct mtip_port *port, return; } -/* - * Helper function for tag logging - */ -static void print_tags(struct driver_data *dd, - char *msg, - unsigned long *tagbits) -{ - unsigned int tag, count = 0; - - for (tag = 0; tag < (dd->slot_groups) * 32; tag++) { - if (test_bit(tag, tagbits)) - count++; - } - if (count) - dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); -} - static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, dma_addr_t buffer_dma, unsigned int sectors); static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, @@ -770,6 +771,7 @@ static void mtip_handle_tfe(struct driver_data *dd) u32 completed; struct host_to_dev_fis *fis; unsigned long tagaccum[SLOTBITS_IN_LONGS]; + unsigned int cmd_cnt = 0; unsigned char *buf; char *fail_reason = NULL; int fail_all_ncq_write = 0, fail_all_ncq_cmds = 0; @@ -781,6 +783,9 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Stop the timer to prevent command timeouts. */ del_timer(&port->cmd_timer); + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + /* Set eh_active */ set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); @@ -791,9 +796,6 @@ static void mtip_handle_tfe(struct driver_data *dd) /* clear completed status register in the hardware.*/ writel(completed, port->completed[group]); - /* clear the tag accumulator */ - memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); - /* Process successfully completed commands */ for (bit = 0; bit < 32 && completed; bit++) { if (!(completed & (1<commands[tag]; if (likely(cmd->comp_func)) { set_bit(tag, tagaccum); + cmd_cnt++; atomic_set(&cmd->active, 0); cmd->comp_func(port, tag, @@ -824,7 +827,8 @@ static void mtip_handle_tfe(struct driver_data *dd) } } } - print_tags(dd, "TFE tags completed:", tagaccum); + + print_tags(dd, "completed (TFE)", tagaccum, cmd_cnt); /* Restart the port */ mdelay(20); @@ -934,7 +938,7 @@ static void mtip_handle_tfe(struct driver_data *dd) tag); } } - print_tags(dd, "TFE tags reissued:", tagaccum); + print_tags(dd, "reissued (TFE)", tagaccum, cmd_cnt); /* clear eh_active */ clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); -- cgit 1.2.3-korg From 63634806519b49bb43f37e53a1e8366eb3e846a4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Apr 2012 08:47:05 +0200 Subject: block: mtip32xx: remove HOTPLUG_PCI_PCIE dependancy This removes the HOTPLUG_PCI_PCIE dependency on the driver and makes it depend on PCI. Cc: Sam Bradshaw Signed-off-by: Greg Kroah-Hartman Acked-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig index b5dd14e072f285..0ba837fc62a874 100644 --- a/drivers/block/mtip32xx/Kconfig +++ b/drivers/block/mtip32xx/Kconfig @@ -4,6 +4,6 @@ config BLK_DEV_PCIESSD_MTIP32XX tristate "Block Device Driver for Micron PCIe SSDs" - depends on HOTPLUG_PCI_PCIE + depends on PCI help This enables the block driver for Micron PCIe SSDs. -- cgit 1.2.3-korg