From 03ea83e9a37e41d436f8348e6eee3d8281bfff3a Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 10 Jun 2013 10:20:55 +0530 Subject: NVMe: Use kzalloc instead of kmalloc+memset Use kzalloc instead of kmalloc and a susbsequent memset. Signed-off-by: Tushar Behera Signed-off-by: Vishal Verma Signed-off-by: Matthew Wilcox --- drivers/block/nvme-scsi.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index 102de2f52b5c..4a4ff4eb8e23 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -933,13 +933,12 @@ static int nvme_trans_bdev_char_page(struct nvme_ns *ns, struct sg_io_hdr *hdr, int res = SNTI_TRANSLATION_SUCCESS; int xfer_len; - inq_response = kmalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL); + inq_response = kzalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL); if (inq_response == NULL) { res = -ENOMEM; goto out_mem; } - memset(inq_response, 0, EXTENDED_INQUIRY_DATA_PAGE_LENGTH); inq_response[1] = INQ_BDEV_CHARACTERISTICS_PAGE; /* Page Code */ inq_response[2] = 0x00; /* Page Length MSB */ inq_response[3] = 0x3C; /* Page Length LSB */ @@ -964,12 +963,11 @@ static int nvme_trans_log_supp_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr, int xfer_len; u8 *log_response; - log_response = kmalloc(LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH, GFP_KERNEL); + log_response = kzalloc(LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH, GFP_KERNEL); if (log_response == NULL) { res = -ENOMEM; goto out_mem; } - memset(log_response, 0, LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH); log_response[0] = LOG_PAGE_SUPPORTED_LOG_PAGES_PAGE; /* Subpage=0x00, Page Length MSB=0 */ @@ -1000,12 +998,11 @@ static int nvme_trans_log_info_exceptions(struct nvme_ns *ns, u8 temp_c; u16 temp_k; - log_response = kmalloc(LOG_INFO_EXCP_PAGE_LENGTH, GFP_KERNEL); + log_response = kzalloc(LOG_INFO_EXCP_PAGE_LENGTH, GFP_KERNEL); if (log_response == NULL) { res = -ENOMEM; goto out_mem; } - memset(log_response, 0, LOG_INFO_EXCP_PAGE_LENGTH); mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_smart_log), @@ -1069,12 +1066,11 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 temp_c_cur, temp_c_thresh; u16 temp_k; - log_response = kmalloc(LOG_TEMP_PAGE_LENGTH, GFP_KERNEL); + log_response = kzalloc(LOG_TEMP_PAGE_LENGTH, GFP_KERNEL); if (log_response == NULL) { res = -ENOMEM; goto out_mem; } - memset(log_response, 0, LOG_TEMP_PAGE_LENGTH); mem = dma_alloc_coherent(&dev->pci_dev->dev, sizeof(struct nvme_smart_log), @@ -1380,12 +1376,11 @@ static int nvme_trans_mode_page_create(struct nvme_ns *ns, blk_desc_offset = mph_size; mode_pages_offset_1 = blk_desc_offset + blk_desc_len; - response = kmalloc(resp_size, GFP_KERNEL); + response = kzalloc(resp_size, GFP_KERNEL); if (response == NULL) { res = -ENOMEM; goto out_mem; } - memset(response, 0, resp_size); res = nvme_trans_fill_mode_parm_hdr(&response[0], mph_size, cdb10, llbaa, mode_data_length, blk_desc_len); @@ -2480,12 +2475,11 @@ static int nvme_trans_read_capacity(struct nvme_ns *ns, struct sg_io_hdr *hdr, } id_ns = mem; - response = kmalloc(resp_size, GFP_KERNEL); + response = kzalloc(resp_size, GFP_KERNEL); if (response == NULL) { res = -ENOMEM; goto out_dma; } - memset(response, 0, resp_size); nvme_trans_fill_read_cap(response, id_ns, cdb16); xfer_len = min(alloc_len, resp_size); @@ -2554,12 +2548,11 @@ static int nvme_trans_report_luns(struct nvme_ns *ns, struct sg_io_hdr *hdr, goto out_dma; } - response = kmalloc(resp_size, GFP_KERNEL); + response = kzalloc(resp_size, GFP_KERNEL); if (response == NULL) { res = -ENOMEM; goto out_dma; } - memset(response, 0, resp_size); /* The first LUN ID will always be 0 per the SAM spec */ for (lun_id = 0; lun_id < le32_to_cpu(id_ctrl->nn); lun_id++) { @@ -2600,12 +2593,11 @@ static int nvme_trans_request_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr, resp_size = ((desc_format) ? (DESC_FMT_SENSE_DATA_SIZE) : (FIXED_FMT_SENSE_DATA_SIZE)); - response = kmalloc(resp_size, GFP_KERNEL); + response = kzalloc(resp_size, GFP_KERNEL); if (response == NULL) { res = -ENOMEM; goto out; } - memset(response, 0, resp_size); if (desc_format == DESCRIPTOR_FORMAT_SENSE_DATA_TYPE) { /* Descriptor Format Sense Data */ -- cgit v1.2.3 From 063a8096f3dbca7521d5918b3aea7ab46c5d2fe9 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Thu, 20 Jun 2013 10:53:48 -0400 Subject: NVMe: Restructure MSI / MSI-X setup The current code copies 'nr_io_queues' into 'q_count', modifies 'nr_io_queues' during MSI-X setup, then resets 'nr_io_queues' for MSI setup. Instead, copy 'nr_io_queues' into 'vecs' and modify 'vecs' during both MSI-X and MSI setup. This lets us simplify the for-loops that set up MSI-X and MSI, and opens the possibility of using more I/O queues than we have interrupt vectors, should future benchmarking prove that to be a useful feature. Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index ce79a590b45b..de3a75978c56 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1638,7 +1638,7 @@ static int set_queue_count(struct nvme_dev *dev, int count) static int nvme_setup_io_queues(struct nvme_dev *dev) { struct pci_dev *pdev = dev->pci_dev; - int result, cpu, i, nr_io_queues, db_bar_size, q_depth, q_count; + int result, cpu, i, vecs, nr_io_queues, db_bar_size, q_depth; nr_io_queues = num_online_cpus(); result = set_queue_count(dev, nr_io_queues); @@ -1647,7 +1647,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; - q_count = nr_io_queues; /* Deregister the admin queue's interrupt */ free_irq(dev->entry[0].vector, dev->queues[0]); @@ -1659,39 +1658,42 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) dev->queues[0]->q_db = dev->dbs; } - for (i = 0; i < nr_io_queues; i++) + vecs = nr_io_queues; + for (i = 0; i < vecs; i++) dev->entry[i].entry = i; for (;;) { - result = pci_enable_msix(pdev, dev->entry, nr_io_queues); - if (result == 0) { + result = pci_enable_msix(pdev, dev->entry, vecs); + if (result <= 0) break; - } else if (result > 0) { - nr_io_queues = result; - continue; - } else { - nr_io_queues = 0; - break; - } + vecs = result; } - if (nr_io_queues == 0) { - nr_io_queues = q_count; + if (result < 0) { + vecs = nr_io_queues; + if (vecs > 32) + vecs = 32; for (;;) { - result = pci_enable_msi_block(pdev, nr_io_queues); + result = pci_enable_msi_block(pdev, vecs); if (result == 0) { - for (i = 0; i < nr_io_queues; i++) + for (i = 0; i < vecs; i++) dev->entry[i].vector = i + pdev->irq; break; - } else if (result > 0) { - nr_io_queues = result; - continue; - } else { - nr_io_queues = 1; + } else if (result < 0) { + vecs = 1; break; } + vecs = result; } } + /* + * Should investigate if there's a performance win from allocating + * more queues than interrupt vectors; it might allow the submission + * path to scale better, even if the receive path is limited by the + * number of interrupts. + */ + nr_io_queues = vecs; + result = queue_request_irq(dev, dev->queues[0], "nvme admin"); /* XXX: handle failure here */ -- cgit v1.2.3 From 6198221fa0df0298513b35796f63f242ea97134e Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 29 May 2013 15:59:39 -0600 Subject: NVMe: Disk IO statistics Add io stats accounting for bio requests so nvme block devices show useful disk stats. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 28 ++++++++++++++++++++++++++++ include/linux/nvme.h | 1 + 2 files changed, 29 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index de3a75978c56..4e71b075d3b4 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -285,6 +285,7 @@ nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp) iod->npages = -1; iod->length = nbytes; iod->nents = 0; + iod->start_time = jiffies; } return iod; @@ -308,6 +309,30 @@ void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod) kfree(iod); } +static void nvme_start_io_acct(struct bio *bio) +{ + struct gendisk *disk = bio->bi_bdev->bd_disk; + const int rw = bio_data_dir(bio); + int cpu = part_stat_lock(); + part_round_stats(cpu, &disk->part0); + part_stat_inc(cpu, &disk->part0, ios[rw]); + part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio)); + part_inc_in_flight(&disk->part0, rw); + part_stat_unlock(); +} + +static void nvme_end_io_acct(struct bio *bio, unsigned long start_time) +{ + struct gendisk *disk = bio->bi_bdev->bd_disk; + const int rw = bio_data_dir(bio); + unsigned long duration = jiffies - start_time; + int cpu = part_stat_lock(); + part_stat_add(cpu, &disk->part0, ticks[rw], duration); + part_round_stats(cpu, &disk->part0); + part_dec_in_flight(&disk->part0, rw); + part_stat_unlock(); +} + static void bio_completion(struct nvme_dev *dev, void *ctx, struct nvme_completion *cqe) { @@ -318,6 +343,8 @@ static void bio_completion(struct nvme_dev *dev, void *ctx, if (iod->nents) dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents, bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + nvme_end_io_acct(bio, iod->start_time); nvme_free_iod(dev, iod); if (status) bio_endio(bio, -EIO); @@ -695,6 +722,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, cmnd->rw.control = cpu_to_le16(control); cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); + nvme_start_io_acct(bio); if (++nvmeq->sq_tail == nvmeq->q_depth) nvmeq->sq_tail = 0; writel(nvmeq->sq_tail, nvmeq->q_db); diff --git a/include/linux/nvme.h b/include/linux/nvme.h index f451c8d6e231..5d7c07946fbe 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -572,6 +572,7 @@ struct nvme_iod { int offset; /* Of PRP list */ int nents; /* Used in scatterlist */ int length; /* Of data, in bytes */ + unsigned long start_time; dma_addr_t first_dma; struct scatterlist sg[0]; }; -- cgit v1.2.3 From e9539f47525ecee05c9f22c3565885f3e9492c52 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 24 Jun 2013 11:47:34 -0400 Subject: NVMe: Return correct value from interrupt handler The interrupt handler currently reports whether it found any new completion queue entries. If the completion queue is primarily being processed by a method other than the interrupt handler, it may return IRQ_NONE so often that Linux thinks that the interrupt is being falsely triggered. To solve this problem, report whether any completion queue entries have been seen since the last interrupt was received for this queue. Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 4e71b075d3b4..88a95747494c 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -79,7 +79,8 @@ struct nvme_queue { u16 sq_head; u16 sq_tail; u16 cq_head; - u16 cq_phase; + u8 cq_phase; + u8 cqe_seen; unsigned long cmdid_data[]; }; @@ -756,7 +757,7 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio) put_nvmeq(nvmeq); } -static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq) +static int nvme_process_cq(struct nvme_queue *nvmeq) { u16 head, phase; @@ -786,13 +787,14 @@ static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq) * a big problem. */ if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) - return IRQ_NONE; + return 0; writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride)); nvmeq->cq_head = head; nvmeq->cq_phase = phase; - return IRQ_HANDLED; + nvmeq->cqe_seen = 1; + return 1; } static irqreturn_t nvme_irq(int irq, void *data) @@ -800,7 +802,9 @@ static irqreturn_t nvme_irq(int irq, void *data) irqreturn_t result; struct nvme_queue *nvmeq = data; spin_lock(&nvmeq->q_lock); - result = nvme_process_cq(nvmeq); + nvme_process_cq(nvmeq); + result = nvmeq->cqe_seen ? IRQ_HANDLED : IRQ_NONE; + nvmeq->cqe_seen = 0; spin_unlock(&nvmeq->q_lock); return result; } -- cgit v1.2.3 From bc57a0f7a44cfcf3e9873f6c6b8dcecdca486b1f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 24 Jun 2013 11:56:42 -0400 Subject: NVMe: Remove "process_cq did something" message I was originally intending to log the fact that the kthread had done some work since it might help us find interrupt handling problems, but that hasn't been done yet, and spamming the logs with this message is just rude. Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 88a95747494c..eb4a91f3bf41 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1538,8 +1538,7 @@ static int nvme_kthread(void *data) if (!nvmeq) continue; spin_lock_irq(&nvmeq->q_lock); - if (nvme_process_cq(nvmeq)) - printk("process_cq did something\n"); + nvme_process_cq(nvmeq); nvme_cancel_ios(nvmeq, true); nvme_resubmit_bios(nvmeq); spin_unlock_irq(&nvmeq->q_lock); -- cgit v1.2.3 From 7d8224574cbd2326a6be00f319f5f7597abec3f6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 24 Jun 2013 12:03:57 -0400 Subject: NVMe: Call nvme_process_cq from submission path Since we have the queue locked, it makes sense to check if there are any completion queue entries on the queue before we release the lock. If there are, it may save an interrupt and reduce latency for the I/Os that happened to complete. This happens fairly often for some workloads. Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index eb4a91f3bf41..07d527c66eb4 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -738,25 +738,6 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, return result; } -static void nvme_make_request(struct request_queue *q, struct bio *bio) -{ - struct nvme_ns *ns = q->queuedata; - struct nvme_queue *nvmeq = get_nvmeq(ns->dev); - int result = -EBUSY; - - spin_lock_irq(&nvmeq->q_lock); - if (bio_list_empty(&nvmeq->sq_cong)) - result = nvme_submit_bio_queue(nvmeq, ns, bio); - if (unlikely(result)) { - if (bio_list_empty(&nvmeq->sq_cong)) - add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); - bio_list_add(&nvmeq->sq_cong, bio); - } - - spin_unlock_irq(&nvmeq->q_lock); - put_nvmeq(nvmeq); -} - static int nvme_process_cq(struct nvme_queue *nvmeq) { u16 head, phase; @@ -797,6 +778,26 @@ static int nvme_process_cq(struct nvme_queue *nvmeq) return 1; } +static void nvme_make_request(struct request_queue *q, struct bio *bio) +{ + struct nvme_ns *ns = q->queuedata; + struct nvme_queue *nvmeq = get_nvmeq(ns->dev); + int result = -EBUSY; + + spin_lock_irq(&nvmeq->q_lock); + if (bio_list_empty(&nvmeq->sq_cong)) + result = nvme_submit_bio_queue(nvmeq, ns, bio); + if (unlikely(result)) { + if (bio_list_empty(&nvmeq->sq_cong)) + add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); + bio_list_add(&nvmeq->sq_cong, bio); + } + + nvme_process_cq(nvmeq); + spin_unlock_irq(&nvmeq->q_lock); + put_nvmeq(nvmeq); +} + static irqreturn_t nvme_irq(int irq, void *data) { irqreturn_t result; -- cgit v1.2.3 From a158073c43b3aa26407b4c7987c909d21a12b5e5 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 9 Aug 2013 13:04:35 +0900 Subject: block: rbd: use NULL instead of 0 The local variables such as 'bio_list', and 'pages' are pointers; thus, use NULL instead of 0 to fix the following sparse warnings. drivers/block/rbd.c:2166:32: warning: Using plain integer as NULL pointer drivers/block/rbd.c:2168:31: warning: Using plain integer as NULL pointer Signed-off-by: Jingoo Han Reviewed-by: Sage Weil --- drivers/block/rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 4ad2ad9a5bb0..0d669ae80d61 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2163,9 +2163,9 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, struct rbd_obj_request *obj_request = NULL; struct rbd_obj_request *next_obj_request; bool write_request = img_request_write_test(img_request); - struct bio *bio_list = 0; + struct bio *bio_list = NULL; unsigned int bio_offset = 0; - struct page **pages = 0; + struct page **pages = NULL; u64 img_offset; u64 resid; u16 opcode; -- cgit v1.2.3 From c3bfe7176c035a0a2c70bc79180fb13a6c57142a Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 8 Jul 2013 17:26:25 -0400 Subject: NVMe: Namespace IDs are unsigned The 'Number of Namespaces' read from the device was being treated as signed, which would cause us to not scan any namespaces for a device with more than 2 billion namespaces. That led to noticing that the namespace ID was also being treated as signed, which could lead to the result from NVME_IOCTL_ID being treated as an error code. Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 7 +++++-- include/linux/nvme.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 07d527c66eb4..56d1fa472d06 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1486,6 +1487,7 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, switch (cmd) { case NVME_IOCTL_ID: + force_successful_syscall_return(); return ns->ns_id; case NVME_IOCTL_ADMIN_CMD: return nvme_user_admin_cmd(ns->dev, (void __user *)arg); @@ -1588,7 +1590,7 @@ static void nvme_config_discard(struct nvme_ns *ns) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); } -static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid, +static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid, struct nvme_id_ns *id, struct nvme_lba_range_type *rt) { struct nvme_ns *ns; @@ -1768,7 +1770,8 @@ static void nvme_free_queues(struct nvme_dev *dev) */ static int nvme_dev_add(struct nvme_dev *dev) { - int res, nn, i; + int res; + unsigned nn, i; struct nvme_ns *ns; struct nvme_id_ctrl *ctrl; struct nvme_id_ns *id_ns; diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 8d0041513e1a..3403c8f06fa0 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -104,7 +104,7 @@ struct nvme_ns { struct request_queue *queue; struct gendisk *disk; - int ns_id; + unsigned ns_id; int lba_shift; int ms; u64 mode_select_num_blocks; -- cgit v1.2.3 From 1b56749e541ad59068582f2a28297843e243b856 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 18 Jul 2013 12:13:51 -0600 Subject: NVMe: Fix checkpatch issues Signed-off-by: Keith Busch --- drivers/block/nvme-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 56d1fa472d06..f9244131b88a 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -451,10 +451,8 @@ static void nvme_bio_pair_endio(struct bio *bio, int err) if (atomic_dec_and_test(&bp->cnt)) { bio_endio(bp->parent, bp->err); - if (bp->bv1) - kfree(bp->bv1); - if (bp->bv2) - kfree(bp->bv2); + kfree(bp->bv1); + kfree(bp->bv2); kfree(bp); } } @@ -1348,7 +1346,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) c.rw.appmask = cpu_to_le16(io.appmask); if (meta_len) { - meta_iod = nvme_map_user_pages(dev, io.opcode & 1, io.metadata, meta_len); + meta_iod = nvme_map_user_pages(dev, io.opcode & 1, io.metadata, + meta_len); if (IS_ERR(meta_iod)) { status = PTR_ERR(meta_iod); meta_iod = NULL; -- cgit v1.2.3 From 7e03b124065507e72008ef294c30001eca74a031 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 29 Jul 2013 16:20:56 -0600 Subject: NVMe: Bring up cdev on set feature failure This patch creates the character device as long as a device's admin queues are usable so a user has an opprotunity to perform administration tasks. A device may be in a state that does not allow IO and setting the queue count feature in such a state returns an error. Previously the driver would bail and the controller would be unusable. Signed-off-by: Keith Busch --- drivers/block/nvme-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index f9244131b88a..8cfa4576d424 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1664,7 +1664,7 @@ static int set_queue_count(struct nvme_dev *dev, int count) status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0, &result); if (status) - return -EIO; + return status < 0 ? -EIO : -EBUSY; return min(result & 0xffff, result >> 16) + 1; } @@ -2018,7 +2018,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_unlock(&dev_list_lock); result = nvme_dev_add(dev); - if (result) + if (result && result != -EBUSY) goto delete; scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance); -- cgit v1.2.3 From 9e59d091b0eb04f223ed037348e3d9e36f30e72b Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 8 Aug 2013 10:25:38 -0600 Subject: NVMe: Disk stats for read/write commands only Flush and discard requests would previously mess up the accounting. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 8cfa4576d424..360ac5d32d26 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -342,11 +342,11 @@ static void bio_completion(struct nvme_dev *dev, void *ctx, struct bio *bio = iod->private; u16 status = le16_to_cpup(&cqe->status) >> 1; - if (iod->nents) + if (iod->nents) { dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents, bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - nvme_end_io_acct(bio, iod->start_time); + nvme_end_io_acct(bio, iod->start_time); + } nvme_free_iod(dev, iod); if (status) bio_endio(bio, -EIO); -- cgit v1.2.3 From 0877cb0d285c7f1d53d0b84b360bdea4be4f3f59 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:19 -0600 Subject: NVMe: Group pci related actions in functions This will make it easier to reuse these outside probe/remove. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 112 +++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 46 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 360ac5d32d26..a93f52c48036 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1191,9 +1191,6 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) u64 cap = readq(&dev->bar->cap); struct nvme_queue *nvmeq; - dev->dbs = ((void __iomem *)dev->bar) + 4096; - dev->db_stride = NVME_CAP_STRIDE(cap); - result = nvme_disable_ctrl(dev, cap); if (result < 0) return result; @@ -1832,6 +1829,61 @@ static int nvme_dev_add(struct nvme_dev *dev) return res; } +static int nvme_dev_map(struct nvme_dev *dev) +{ + int bars, result = -ENOMEM; + struct pci_dev *pdev = dev->pci_dev; + + if (pci_enable_device_mem(pdev)) + return result; + + dev->entry[0].vector = pdev->irq; + pci_set_master(pdev); + bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_request_selected_regions(pdev, bars, "nvme")) + goto disable_pci; + + if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + else + goto disable_pci; + + pci_set_drvdata(pdev, dev); + dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); + if (!dev->bar) + goto disable; + + dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap)); + dev->dbs = ((void __iomem *)dev->bar) + 4096; + + return 0; + + disable: + pci_release_regions(pdev); + disable_pci: + pci_disable_device(pdev); + return result; +} + +static void nvme_dev_unmap(struct nvme_dev *dev) +{ + if (dev->pci_dev->msi_enabled) + pci_disable_msi(dev->pci_dev); + else if (dev->pci_dev->msix_enabled) + pci_disable_msix(dev->pci_dev); + + if (dev->bar) { + iounmap(dev->bar); + dev->bar = NULL; + } + + pci_release_regions(dev->pci_dev); + if (pci_is_enabled(dev->pci_dev)) + pci_disable_device(dev->pci_dev); +} + static int nvme_dev_remove(struct nvme_dev *dev) { struct nvme_ns *ns, *next; @@ -1908,15 +1960,9 @@ static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); nvme_dev_remove(dev); - if (dev->pci_dev->msi_enabled) - pci_disable_msi(dev->pci_dev); - else if (dev->pci_dev->msix_enabled) - pci_disable_msix(dev->pci_dev); - iounmap(dev->bar); + nvme_dev_unmap(dev); nvme_release_instance(dev); nvme_release_prp_pools(dev); - pci_disable_device(dev->pci_dev); - pci_release_regions(dev->pci_dev); kfree(dev->queues); kfree(dev->entry); kfree(dev); @@ -1959,7 +2005,7 @@ static const struct file_operations nvme_dev_fops = { static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int bars, result = -ENOMEM; + int result = -ENOMEM; struct nvme_dev *dev; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1974,39 +2020,19 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!dev->queues) goto free; - if (pci_enable_device_mem(pdev)) - goto free; - pci_set_master(pdev); - bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_request_selected_regions(pdev, bars, "nvme")) - goto disable; - INIT_LIST_HEAD(&dev->namespaces); dev->pci_dev = pdev; - pci_set_drvdata(pdev, dev); - - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - else - goto disable; - result = nvme_set_instance(dev); if (result) - goto disable; - - dev->entry[0].vector = pdev->irq; + goto free; result = nvme_setup_prp_pools(dev); if (result) - goto disable_msix; + goto release; - dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); - if (!dev->bar) { - result = -ENOMEM; - goto disable_msix; - } + result = nvme_dev_map(dev); + if (result) + goto release_pools; result = nvme_configure_admin_queue(dev); if (result) @@ -2042,17 +2068,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) nvme_free_queues(dev); unmap: - iounmap(dev->bar); - disable_msix: - if (dev->pci_dev->msi_enabled) - pci_disable_msi(dev->pci_dev); - else if (dev->pci_dev->msix_enabled) - pci_disable_msix(dev->pci_dev); - nvme_release_instance(dev); + nvme_dev_unmap(dev); + release_pools: nvme_release_prp_pools(dev); - disable: - pci_disable_device(pdev); - pci_release_regions(pdev); + release: + nvme_release_instance(dev); free: kfree(dev->queues); kfree(dev->entry); -- cgit v1.2.3 From 224042742582c9938788b81165180c876e997a07 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:20 -0600 Subject: NVMe: Separate queue alloc/free from create/delete This separates nvme queue allocation from creation, and queue deletion from freeing. This is so that we may in the future temporarily disable queues and reuse the same memory when bringing them back online, like coming back from suspend state. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 133 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 39 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index a93f52c48036..95e28b6bcd09 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -82,6 +82,7 @@ struct nvme_queue { u16 cq_head; u8 cq_phase; u8 cqe_seen; + u8 q_suspended; unsigned long cmdid_data[]; }; @@ -117,6 +118,11 @@ static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) return (void *)&nvmeq->cmdid_data[BITS_TO_LONGS(nvmeq->q_depth)]; } +static unsigned nvme_queue_extra(int depth) +{ + return DIV_ROUND_UP(depth, 8) + (depth * sizeof(struct nvme_cmd_info)); +} + /** * alloc_cmdid() - Allocate a Command ID * @nvmeq: The queue that will be used for this command @@ -784,7 +790,7 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio) int result = -EBUSY; spin_lock_irq(&nvmeq->q_lock); - if (bio_list_empty(&nvmeq->sq_cong)) + if (!nvmeq->q_suspended && bio_list_empty(&nvmeq->sq_cong)) result = nvme_submit_bio_queue(nvmeq, ns, bio); if (unlikely(result)) { if (bio_list_empty(&nvmeq->sq_cong)) @@ -1018,8 +1024,15 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout) } } -static void nvme_free_queue_mem(struct nvme_queue *nvmeq) +static void nvme_free_queue(struct nvme_queue *nvmeq) { + spin_lock_irq(&nvmeq->q_lock); + while (bio_list_peek(&nvmeq->sq_cong)) { + struct bio *bio = bio_list_pop(&nvmeq->sq_cong); + bio_endio(bio, -EIO); + } + spin_unlock_irq(&nvmeq->q_lock); + dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), @@ -1027,17 +1040,28 @@ static void nvme_free_queue_mem(struct nvme_queue *nvmeq) kfree(nvmeq); } -static void nvme_free_queue(struct nvme_dev *dev, int qid) +static void nvme_free_queues(struct nvme_dev *dev) +{ + int i; + + for (i = dev->queue_count - 1; i >= 0; i--) { + nvme_free_queue(dev->queues[i]); + dev->queue_count--; + dev->queues[i] = NULL; + } +} + +static void nvme_disable_queue(struct nvme_dev *dev, int qid) { struct nvme_queue *nvmeq = dev->queues[qid]; int vector = dev->entry[nvmeq->cq_vector].vector; spin_lock_irq(&nvmeq->q_lock); - nvme_cancel_ios(nvmeq, false); - while (bio_list_peek(&nvmeq->sq_cong)) { - struct bio *bio = bio_list_pop(&nvmeq->sq_cong); - bio_endio(bio, -EIO); + if (nvmeq->q_suspended) { + spin_unlock_irq(&nvmeq->q_lock); + return; } + nvmeq->q_suspended = 1; spin_unlock_irq(&nvmeq->q_lock); irq_set_affinity_hint(vector, NULL); @@ -1049,15 +1073,17 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid) adapter_delete_cq(dev, qid); } - nvme_free_queue_mem(nvmeq); + spin_lock_irq(&nvmeq->q_lock); + nvme_process_cq(nvmeq); + nvme_cancel_ios(nvmeq, false); + spin_unlock_irq(&nvmeq->q_lock); } static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth, int vector) { struct device *dmadev = &dev->pci_dev->dev; - unsigned extra = DIV_ROUND_UP(depth, 8) + (depth * - sizeof(struct nvme_cmd_info)); + unsigned extra = nvme_queue_extra(depth); struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL); if (!nvmeq) return NULL; @@ -1084,6 +1110,8 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; nvmeq->q_depth = depth; nvmeq->cq_vector = vector; + nvmeq->q_suspended = 1; + dev->queue_count++; return nvmeq; @@ -1107,18 +1135,29 @@ static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq, IRQF_DISABLED | IRQF_SHARED, name, nvmeq); } -static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid, - int cq_size, int vector) +static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) { - int result; - struct nvme_queue *nvmeq = nvme_alloc_queue(dev, qid, cq_size, vector); + struct nvme_dev *dev = nvmeq->dev; + unsigned extra = nvme_queue_extra(nvmeq->q_depth); - if (!nvmeq) - return ERR_PTR(-ENOMEM); + nvmeq->sq_tail = 0; + nvmeq->cq_head = 0; + nvmeq->cq_phase = 1; + nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + memset(nvmeq->cmdid_data, 0, extra); + memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth)); + nvme_cancel_ios(nvmeq, false); + nvmeq->q_suspended = 0; +} + +static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) +{ + struct nvme_dev *dev = nvmeq->dev; + int result; result = adapter_alloc_cq(dev, qid, nvmeq); if (result < 0) - goto free_nvmeq; + return result; result = adapter_alloc_sq(dev, qid, nvmeq); if (result < 0) @@ -1128,19 +1167,17 @@ static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid, if (result < 0) goto release_sq; - return nvmeq; + spin_lock(&nvmeq->q_lock); + nvme_init_queue(nvmeq, qid); + spin_unlock(&nvmeq->q_lock); + + return result; release_sq: adapter_delete_sq(dev, qid); release_cq: adapter_delete_cq(dev, qid); - free_nvmeq: - dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), - (void *)nvmeq->cqes, nvmeq->cq_dma_addr); - dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), - nvmeq->sq_cmds, nvmeq->sq_dma_addr); - kfree(nvmeq); - return ERR_PTR(result); + return result; } static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled) @@ -1221,10 +1258,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) goto free_q; dev->queues[0] = nvmeq; + spin_lock(&nvmeq->q_lock); + nvme_init_queue(nvmeq, 0); + spin_unlock(&nvmeq->q_lock); return result; free_q: - nvme_free_queue_mem(nvmeq); + nvme_free_queue(nvmeq); return result; } @@ -1386,6 +1426,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) put_nvmeq(nvmeq); if (length != (io.nblocks + 1) << ns->lba_shift) status = -ENOMEM; + else if (!nvmeq || nvmeq->q_suspended) + status = -EBUSY; else status = nvme_submit_sync_cmd(nvmeq, &c, NULL, NVME_IO_TIMEOUT); @@ -1537,9 +1579,12 @@ static int nvme_kthread(void *data) if (!nvmeq) continue; spin_lock_irq(&nvmeq->q_lock); + if (nvmeq->q_suspended) + goto unlock; nvme_process_cq(nvmeq); nvme_cancel_ios(nvmeq, true); nvme_resubmit_bios(nvmeq); + unlock: spin_unlock_irq(&nvmeq->q_lock); } } @@ -1725,7 +1770,8 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) nr_io_queues = vecs; result = queue_request_irq(dev, dev->queues[0], "nvme admin"); - /* XXX: handle failure here */ + if (result) + goto free_queues; cpu = cpumask_first(cpu_online_mask); for (i = 0; i < nr_io_queues; i++) { @@ -1736,10 +1782,11 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1, NVME_Q_DEPTH); for (i = 0; i < nr_io_queues; i++) { - dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i); - if (IS_ERR(dev->queues[i + 1])) - return PTR_ERR(dev->queues[i + 1]); - dev->queue_count++; + dev->queues[i + 1] = nvme_alloc_queue(dev, i + 1, q_depth, i); + if (!dev->queues[i + 1]) { + result = -ENOMEM; + goto free_queues; + } } for (; i < num_possible_cpus(); i++) { @@ -1747,15 +1794,20 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) dev->queues[i + 1] = dev->queues[target + 1]; } - return 0; -} + for (i = 1; i < dev->queue_count; i++) { + result = nvme_create_queue(dev->queues[i], i); + if (result) { + for (--i; i > 0; i--) + nvme_disable_queue(dev, i); + goto free_queues; + } + } -static void nvme_free_queues(struct nvme_dev *dev) -{ - int i; + return 0; - for (i = dev->queue_count - 1; i >= 0; i--) - nvme_free_queue(dev, i); + free_queues: + nvme_free_queues(dev); + return result; } /* @@ -1887,6 +1939,10 @@ static void nvme_dev_unmap(struct nvme_dev *dev) static int nvme_dev_remove(struct nvme_dev *dev) { struct nvme_ns *ns, *next; + int i; + + for (i = dev->queue_count - 1; i >= 0; i--) + nvme_disable_queue(dev, i); spin_lock(&dev_list_lock); list_del(&dev->node); @@ -2037,7 +2093,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) result = nvme_configure_admin_queue(dev); if (result) goto unmap; - dev->queue_count++; spin_lock(&dev_list_lock); list_add(&dev->node, &dev_list); -- cgit v1.2.3 From f0b50732a979c55c2d15fe8ec4503fa5b3260c53 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:21 -0600 Subject: NVMe: Separate controller init from disk discovery This combines the controller initialization into one function, removing IO queue setup from namespace discovery, and creates symetric functions for device removal. The controller start and shutdown functions can now be called from resume/suspend context as well as probe/remove. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 77 +++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 30 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 95e28b6bcd09..1595ffba8a66 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1827,10 +1827,6 @@ static int nvme_dev_add(struct nvme_dev *dev) dma_addr_t dma_addr; int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12; - res = nvme_setup_io_queues(dev); - if (res) - return res; - mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr, GFP_KERNEL); if (!mem) @@ -1936,27 +1932,29 @@ static void nvme_dev_unmap(struct nvme_dev *dev) pci_disable_device(dev->pci_dev); } -static int nvme_dev_remove(struct nvme_dev *dev) +static void nvme_dev_shutdown(struct nvme_dev *dev) { - struct nvme_ns *ns, *next; int i; for (i = dev->queue_count - 1; i >= 0; i--) nvme_disable_queue(dev, i); spin_lock(&dev_list_lock); - list_del(&dev->node); + list_del_init(&dev->node); spin_unlock(&dev_list_lock); + nvme_dev_unmap(dev); +} + +static void nvme_dev_remove(struct nvme_dev *dev) +{ + struct nvme_ns *ns, *next; + list_for_each_entry_safe(ns, next, &dev->namespaces, list) { list_del(&ns->list); del_gendisk(ns->disk); nvme_ns_free(ns); } - - nvme_free_queues(dev); - - return 0; } static int nvme_setup_prp_pools(struct nvme_dev *dev) @@ -2016,7 +2014,8 @@ static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); nvme_dev_remove(dev); - nvme_dev_unmap(dev); + nvme_dev_shutdown(dev); + nvme_free_queues(dev); nvme_release_instance(dev); nvme_release_prp_pools(dev); kfree(dev->queues); @@ -2059,6 +2058,37 @@ static const struct file_operations nvme_dev_fops = { .compat_ioctl = nvme_dev_ioctl, }; +static int nvme_dev_start(struct nvme_dev *dev) +{ + int result; + + result = nvme_dev_map(dev); + if (result) + return result; + + result = nvme_configure_admin_queue(dev); + if (result) + goto unmap; + + spin_lock(&dev_list_lock); + list_add(&dev->node, &dev_list); + spin_unlock(&dev_list_lock); + + result = nvme_setup_io_queues(dev); + if (result) + goto disable; + + return 0; + + disable: + spin_lock(&dev_list_lock); + list_del_init(&dev->node); + spin_unlock(&dev_list_lock); + unmap: + nvme_dev_unmap(dev); + return result; +} + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int result = -ENOMEM; @@ -2086,21 +2116,13 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (result) goto release; - result = nvme_dev_map(dev); + result = nvme_dev_start(dev); if (result) goto release_pools; - result = nvme_configure_admin_queue(dev); - if (result) - goto unmap; - - spin_lock(&dev_list_lock); - list_add(&dev->node, &dev_list); - spin_unlock(&dev_list_lock); - result = nvme_dev_add(dev); if (result && result != -EBUSY) - goto delete; + goto shutdown; scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance); dev->miscdev.minor = MISC_DYNAMIC_MINOR; @@ -2116,15 +2138,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) remove: nvme_dev_remove(dev); - delete: - spin_lock(&dev_list_lock); - list_del(&dev->node); - spin_unlock(&dev_list_lock); - - nvme_free_queues(dev); - unmap: - nvme_dev_unmap(dev); + shutdown: + nvme_dev_shutdown(dev); release_pools: + nvme_free_queues(dev); nvme_release_prp_pools(dev); release: nvme_release_instance(dev); -- cgit v1.2.3 From 1894d8f16afe5ad54b732f0fa6c4e80bd4d40b91 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:22 -0600 Subject: NVMe: Use normal shutdown The NVMe spec recommends using the shutdown normal sequence when safely taking the controller offline instead of hitting CC.EN on the next start-up to reset the controller. The spec recommends a minimum of 1 second for the shutdown complete. This patch waits 2 seconds to be on the safe side. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 26 ++++++++++++++++++++++++++ include/linux/nvme.h | 2 ++ 2 files changed, 28 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 1595ffba8a66..23bb5a70d810 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1221,6 +1221,30 @@ static int nvme_enable_ctrl(struct nvme_dev *dev, u64 cap) return nvme_wait_ready(dev, cap, true); } +static int nvme_shutdown_ctrl(struct nvme_dev *dev) +{ + unsigned long timeout; + u32 cc; + + cc = (readl(&dev->bar->cc) & ~NVME_CC_SHN_MASK) | NVME_CC_SHN_NORMAL; + writel(cc, &dev->bar->cc); + + timeout = 2 * HZ + jiffies; + while ((readl(&dev->bar->csts) & NVME_CSTS_SHST_MASK) != + NVME_CSTS_SHST_CMPLT) { + msleep(100); + if (fatal_signal_pending(current)) + return -EINTR; + if (time_after(jiffies, timeout)) { + dev_err(&dev->pci_dev->dev, + "Device shutdown incomplete; abort shutdown\n"); + return -ENODEV; + } + } + + return 0; +} + static int nvme_configure_admin_queue(struct nvme_dev *dev) { int result; @@ -1943,6 +1967,8 @@ static void nvme_dev_shutdown(struct nvme_dev *dev) list_del_init(&dev->node); spin_unlock(&dev_list_lock); + if (dev->bar) + nvme_shutdown_ctrl(dev); nvme_dev_unmap(dev); } diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 3403c8f06fa0..26ebcf41c213 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -53,6 +53,7 @@ enum { NVME_CC_SHN_NONE = 0 << 14, NVME_CC_SHN_NORMAL = 1 << 14, NVME_CC_SHN_ABRUPT = 2 << 14, + NVME_CC_SHN_MASK = 3 << 14, NVME_CC_IOSQES = 6 << 16, NVME_CC_IOCQES = 4 << 20, NVME_CSTS_RDY = 1 << 0, @@ -60,6 +61,7 @@ enum { NVME_CSTS_SHST_NORMAL = 0 << 2, NVME_CSTS_SHST_OCCUR = 1 << 2, NVME_CSTS_SHST_CMPLT = 2 << 2, + NVME_CSTS_SHST_MASK = 3 << 2, }; #define NVME_VS(major, minor) (major << 16 | minor) -- cgit v1.2.3 From cd63894630ab17a192bf97427d16dbec10710a6a Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:23 -0600 Subject: NVMe: Add pci suspend/resume driver callbacks Used for going in and out of low power states. Resuming reuses the IO queues from the previous initialization, freeing any allocated queues that are no longer usable. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 73 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 23bb5a70d810..8efa728f1eac 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -789,6 +789,12 @@ static void nvme_make_request(struct request_queue *q, struct bio *bio) struct nvme_queue *nvmeq = get_nvmeq(ns->dev); int result = -EBUSY; + if (!nvmeq) { + put_nvmeq(NULL); + bio_endio(bio, -EIO); + return; + } + spin_lock_irq(&nvmeq->q_lock); if (!nvmeq->q_suspended && bio_list_empty(&nvmeq->sq_cong)) result = nvme_submit_bio_queue(nvmeq, ns, bio); @@ -1256,9 +1262,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) if (result < 0) return result; - nvmeq = nvme_alloc_queue(dev, 0, 64, 0); - if (!nvmeq) - return -ENOMEM; + nvmeq = dev->queues[0]; + if (!nvmeq) { + nvmeq = nvme_alloc_queue(dev, 0, 64, 0); + if (!nvmeq) + return -ENOMEM; + dev->queues[0] = nvmeq; + } aqa = nvmeq->q_depth - 1; aqa |= aqa << 16; @@ -1275,21 +1285,16 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) result = nvme_enable_ctrl(dev, cap); if (result) - goto free_q; + return result; result = queue_request_irq(dev, nvmeq, "nvme admin"); if (result) - goto free_q; + return result; - dev->queues[0] = nvmeq; spin_lock(&nvmeq->q_lock); nvme_init_queue(nvmeq, 0); spin_unlock(&nvmeq->q_lock); return result; - - free_q: - nvme_free_queue(nvmeq); - return result; } struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, @@ -1797,6 +1802,21 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result) goto free_queues; + /* Free previously allocated queues that are no longer usable */ + spin_lock(&dev_list_lock); + for (i = dev->queue_count - 1; i > nr_io_queues; i--) { + struct nvme_queue *nvmeq = dev->queues[i]; + + spin_lock(&nvmeq->q_lock); + nvme_cancel_ios(nvmeq, false); + spin_unlock(&nvmeq->q_lock); + + nvme_free_queue(nvmeq); + dev->queue_count--; + dev->queues[i] = NULL; + } + spin_unlock(&dev_list_lock); + cpu = cpumask_first(cpu_online_mask); for (i = 0; i < nr_io_queues; i++) { irq_set_affinity_hint(dev->entry[i].vector, get_cpu_mask(cpu)); @@ -1805,7 +1825,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1, NVME_Q_DEPTH); - for (i = 0; i < nr_io_queues; i++) { + for (i = dev->queue_count - 1; i < nr_io_queues; i++) { dev->queues[i + 1] = nvme_alloc_queue(dev, i + 1, q_depth, i); if (!dev->queues[i + 1]) { result = -ENOMEM; @@ -2191,8 +2211,30 @@ static void nvme_remove(struct pci_dev *pdev) #define nvme_link_reset NULL #define nvme_slot_reset NULL #define nvme_error_resume NULL -#define nvme_suspend NULL -#define nvme_resume NULL + +static int nvme_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct nvme_dev *ndev = pci_get_drvdata(pdev); + + nvme_dev_shutdown(ndev); + return 0; +} + +static int nvme_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct nvme_dev *ndev = pci_get_drvdata(pdev); + int ret; + + ret = nvme_dev_start(ndev); + /* XXX: should remove gendisks if resume fails */ + if (ret) + nvme_free_queues(ndev); + return ret; +} + +static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume); static const struct pci_error_handlers nvme_err_handler = { .error_detected = nvme_error_detected, @@ -2216,8 +2258,9 @@ static struct pci_driver nvme_driver = { .id_table = nvme_id_table, .probe = nvme_probe, .remove = nvme_remove, - .suspend = nvme_suspend, - .resume = nvme_resume, + .driver = { + .pm = &nvme_dev_pm_ops, + }, .err_handler = &nvme_err_handler, }; -- cgit v1.2.3 From 9d713c2bfb5e1d6abb18a8b12293631f9fcdc708 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 15 Jul 2013 15:02:24 -0600 Subject: NVMe: Handle ioremap failure Decrement the number of queues required for doorbell remapping until the memory is successfully mapped for that size. Additional checks are done so that we don't call free_irq if it has already been freed. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 8efa728f1eac..9f2b424c445e 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1739,10 +1739,15 @@ static int set_queue_count(struct nvme_dev *dev, int count) return min(result & 0xffff, result >> 16) + 1; } +static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) +{ + return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); +} + static int nvme_setup_io_queues(struct nvme_dev *dev) { struct pci_dev *pdev = dev->pci_dev; - int result, cpu, i, vecs, nr_io_queues, db_bar_size, q_depth; + int result, cpu, i, vecs, nr_io_queues, size, q_depth; nr_io_queues = num_online_cpus(); result = set_queue_count(dev, nr_io_queues); @@ -1751,17 +1756,24 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; - /* Deregister the admin queue's interrupt */ - free_irq(dev->entry[0].vector, dev->queues[0]); - - db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); - if (db_bar_size > 8192) { + size = db_bar_size(dev, nr_io_queues); + if (size > 8192) { iounmap(dev->bar); - dev->bar = ioremap(pci_resource_start(pdev, 0), db_bar_size); + do { + dev->bar = ioremap(pci_resource_start(pdev, 0), size); + if (dev->bar) + break; + if (!--nr_io_queues) + return -ENOMEM; + size = db_bar_size(dev, nr_io_queues); + } while (1); dev->dbs = ((void __iomem *)dev->bar) + 4096; dev->queues[0]->q_db = dev->dbs; } + /* Deregister the admin queue's interrupt */ + free_irq(dev->entry[0].vector, dev->queues[0]); + vecs = nr_io_queues; for (i = 0; i < vecs; i++) dev->entry[i].entry = i; @@ -1799,8 +1811,10 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) nr_io_queues = vecs; result = queue_request_irq(dev, dev->queues[0], "nvme admin"); - if (result) + if (result) { + dev->queues[0]->q_suspended = 1; goto free_queues; + } /* Free previously allocated queues that are no longer usable */ spin_lock(&dev_list_lock); -- cgit v1.2.3 From 17c1cc1d9293a568a00545469078e29555cc7f39 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 26 Aug 2013 17:55:38 -0700 Subject: rbd: fix I/O error propagation for reads When a request returns an error, the driver needs to report the entire extent of the request as completed. Writes already did this, since they always set xferred = length, but reads were skipping that step if an error other than -ENOENT occurred. Instead, rbd would end up passing 0 xferred to blk_end_request(), which would always report needing more data. This resulted in an assert failing when more data was required by the block layer, but all the object requests were done: [ 1868.719077] rbd: obj_request read result -108 xferred 0 [ 1868.719077] [ 1868.719518] end_request: I/O error, dev rbd1, sector 0 [ 1868.719739] [ 1868.719739] Assertion failure in rbd_img_obj_callback() at line 1736: [ 1868.719739] [ 1868.719739] rbd_assert(more ^ (which == img_request->obj_request_count)); Without this assert, reads that hit errors would hang forever, since the block layer considered them incomplete. Fixes: http://tracker.ceph.com/issues/5647 CC: stable@vger.kernel.org # v3.10 Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 0d669ae80d61..f8fd7d3c13ba 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1557,11 +1557,12 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) obj_request, obj_request->img_request, obj_request->result, xferred, length); /* - * ENOENT means a hole in the image. We zero-fill the - * entire length of the request. A short read also implies - * zero-fill to the end of the request. Either way we - * update the xferred count to indicate the whole request - * was satisfied. + * ENOENT means a hole in the image. We zero-fill the entire + * length of the request. A short read also implies zero-fill + * to the end of the request. An error requires the whole + * length of the request to be reported finished with an error + * to the block layer. In each case we update the xferred + * count to indicate the whole request was satisfied. */ rbd_assert(obj_request->type != OBJ_REQUEST_NODATA); if (obj_request->result == -ENOENT) { @@ -1570,14 +1571,13 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request) else zero_pages(obj_request->pages, 0, length); obj_request->result = 0; - obj_request->xferred = length; } else if (xferred < length && !obj_request->result) { if (obj_request->type == OBJ_REQUEST_BIO) zero_bio_chain(obj_request->bio_list, xferred); else zero_pages(obj_request->pages, xferred, length); - obj_request->xferred = length; } + obj_request->xferred = length; obj_request_done_set(obj_request); } -- cgit v1.2.3 From 03507db631c94a48e316c7f638ffb2991544d617 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Tue, 27 Aug 2013 14:45:46 -0700 Subject: rbd: fix buffer size for writes to images with snapshots rbd_osd_req_create() needs to know the snapshot context size to create a buffer large enough to send it with the message front. It gets this from the img_request, which was not set for the obj_request yet. This resulted in trying to write past the end of the front payload, hitting this BUG: libceph: BUG_ON(p > msg->front.iov_base + msg->front.iov_len); Fix this by associating the obj_request with its img_request immediately after it's created, before the osd request is created. Fixes: http://tracker.ceph.com/issues/5760 Suggested-by: Alex Elder Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index f8fd7d3c13ba..80f787b6226e 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2203,6 +2203,11 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, rbd_segment_name_free(object_name); if (!obj_request) goto out_unwind; + /* + * set obj_request->img_request before creating the + * osd_request so that it gets the right snapc + */ + rbd_img_obj_request_add(img_request, obj_request); if (type == OBJ_REQUEST_BIO) { unsigned int clone_size; @@ -2244,11 +2249,6 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, obj_request->pages, length, offset & ~PAGE_MASK, false, false); - /* - * set obj_request->img_request before formatting - * the osd_request so that it gets the right snapc - */ - rbd_img_obj_request_add(img_request, obj_request); if (write_request) rbd_osd_req_format_write(obj_request); else -- cgit v1.2.3 From c35455791c1131e7ccbf56ea6fbdd562401c2ce2 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Wed, 28 Aug 2013 17:08:10 -0700 Subject: rbd: fix null dereference in dout The order parameter is sometimes NULL in _rbd_dev_v2_snap_size(), but the dout() always derefences it. Move this to another dout() protected by a check that order is non-NULL. Signed-off-by: Josh Durgin Reviewed-by: Sage Weil Reviewed-by: Alex Elder --- drivers/block/rbd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 80f787b6226e..fef3687c1527 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3702,12 +3702,14 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id, if (ret < sizeof (size_buf)) return -ERANGE; - if (order) + if (order) { *order = size_buf.order; + dout(" order %u", (unsigned int)*order); + } *snap_size = le64_to_cpu(size_buf.size); - dout(" snap_id 0x%016llx order = %u, snap_size = %llu\n", - (unsigned long long)snap_id, (unsigned int)*order, + dout(" snap_id 0x%016llx snap_size = %llu\n", + (unsigned long long)snap_id, (unsigned long long)*snap_size); return 0; -- cgit v1.2.3 From d82e8bfdef9afae83b894be49af4644d9ac3c359 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 5 Sep 2013 14:45:07 -0600 Subject: NVMe: Merge issue on character device bring-up A recent patch made it possible to bring up the character handle when the device is responsive but not accepting a set-features command. Another recent patch moved the initialization that requires we move where the checks for this condition occur. This patch merges these two ideas so it works much as before. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 9f2b424c445e..da52092980e2 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -2135,10 +2135,10 @@ static int nvme_dev_start(struct nvme_dev *dev) spin_unlock(&dev_list_lock); result = nvme_setup_io_queues(dev); - if (result) + if (result && result != -EBUSY) goto disable; - return 0; + return result; disable: spin_lock(&dev_list_lock); @@ -2177,13 +2177,17 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto release; result = nvme_dev_start(dev); - if (result) + if (result) { + if (result == -EBUSY) + goto create_cdev; goto release_pools; + } result = nvme_dev_add(dev); - if (result && result != -EBUSY) + if (result) goto shutdown; + create_cdev: scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance); dev->miscdev.minor = MISC_DYNAMIC_MINOR; dev->miscdev.parent = &pdev->dev; -- cgit v1.2.3 From 9abc59908e0c5f983aaa91150da32d5b62cf60b7 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 29 Aug 2013 17:31:03 -0700 Subject: rbd: complete notifies before cleaning up osd_client and rbd_dev To ensure rbd_dev is not used after it's released, flush all pending notify callbacks before calling rbd_dev_image_release(). No new notifies can be added to the queue at this point because the watch has already be unregistered with the osd_client. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index fef3687c1527..bf89e348d11b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -5163,6 +5163,13 @@ static ssize_t rbd_remove(struct bus_type *bus, ret = rbd_dev_header_watch_sync(rbd_dev, false); if (ret) rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret); + + /* + * flush remaining watch callbacks - these must be complete + * before the osd_client is shutdown + */ + dout("%s: flushing notifies", __func__); + ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); rbd_dev_image_release(rbd_dev); module_put(THIS_MODULE); -- cgit v1.2.3 From 20e0af67ce88c657d0601977b9941a2256afbdaa Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 29 Aug 2013 17:36:03 -0700 Subject: rbd: make rbd_obj_notify_ack() synchronous The only user of rbd_obj_notify_ack() is rbd_watch_cb(). It used asynchronously with no tracking of when the notify ack completes, so it may still be in progress when the osd_client is shut down. This results in a BUG() since the osd client assumes no requests are in flight when it stops. Since all notifies are flushed before the osd_client is stopped, waiting for the notify ack to complete before returning from the watch callback ensures there are no notify acks in flight during shutdown. Rename rbd_obj_notify_ack() to rbd_obj_notify_ack_sync() to reflect its new synchronous nature. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bf89e348d11b..9e5f07f936dd 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2808,7 +2808,7 @@ out_err: obj_request_done_set(obj_request); } -static int rbd_obj_notify_ack(struct rbd_device *rbd_dev, u64 notify_id) +static int rbd_obj_notify_ack_sync(struct rbd_device *rbd_dev, u64 notify_id) { struct rbd_obj_request *obj_request; struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; @@ -2823,16 +2823,17 @@ static int rbd_obj_notify_ack(struct rbd_device *rbd_dev, u64 notify_id) obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, obj_request); if (!obj_request->osd_req) goto out; - obj_request->callback = rbd_obj_request_put; osd_req_op_watch_init(obj_request->osd_req, 0, CEPH_OSD_OP_NOTIFY_ACK, notify_id, 0, 0); rbd_osd_req_format_read(obj_request); ret = rbd_obj_request_submit(osdc, obj_request); -out: if (ret) - rbd_obj_request_put(obj_request); + goto out; + ret = rbd_obj_request_wait(obj_request); +out: + rbd_obj_request_put(obj_request); return ret; } @@ -2852,7 +2853,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) if (ret) rbd_warn(rbd_dev, "header refresh error (%d)\n", ret); - rbd_obj_notify_ack(rbd_dev, notify_id); + rbd_obj_notify_ack_sync(rbd_dev, notify_id); } /* -- cgit v1.2.3 From 9875201e10496612080e7d164acc8f625c18725c Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 29 Aug 2013 17:26:31 -0700 Subject: rbd: fix use-after free of rbd_dev->disk Removing a device deallocates the disk, unschedules the watch, and finally cleans up the rbd_dev structure. rbd_dev_refresh(), called from the watch callback, updates the disk size and rbd_dev structure. With no locking between them, rbd_dev_refresh() may use the device or rbd_dev after they've been freed. To fix this, check whether RBD_DEV_FLAG_REMOVING is set before updating the disk size in rbd_dev_refresh(). In order to prevent a race where rbd_dev_refresh() is already revalidating the disk when rbd_remove() is called, move the call to rbd_bus_del_dev() after the watch is unregistered and all notifies are complete. It's safe to defer deleting this structure because no new requests can be submitted once the RBD_DEV_FLAG_REMOVING is set, since the device cannot be opened. Fixes: http://tracker.ceph.com/issues/5636 Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 9e5f07f936dd..47c6f9cf9dba 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3325,6 +3325,31 @@ static void rbd_exists_validate(struct rbd_device *rbd_dev) clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags); } +static void rbd_dev_update_size(struct rbd_device *rbd_dev) +{ + sector_t size; + bool removing; + + /* + * Don't hold the lock while doing disk operations, + * or lock ordering will conflict with the bdev mutex via: + * rbd_add() -> blkdev_get() -> rbd_open() + */ + spin_lock_irq(&rbd_dev->lock); + removing = test_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags); + spin_unlock_irq(&rbd_dev->lock); + /* + * If the device is being removed, rbd_dev->disk has + * been destroyed, so don't try to update its size + */ + if (!removing) { + size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE; + dout("setting size to %llu sectors", (unsigned long long)size); + set_capacity(rbd_dev->disk, size); + revalidate_disk(rbd_dev->disk); + } +} + static int rbd_dev_refresh(struct rbd_device *rbd_dev) { u64 mapping_size; @@ -3344,12 +3369,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev) up_write(&rbd_dev->header_rwsem); if (mapping_size != rbd_dev->mapping.size) { - sector_t size; - - size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE; - dout("setting size to %llu sectors", (unsigned long long)size); - set_capacity(rbd_dev->disk, size); - revalidate_disk(rbd_dev->disk); + rbd_dev_update_size(rbd_dev); } return ret; @@ -5160,7 +5180,6 @@ static ssize_t rbd_remove(struct bus_type *bus, if (ret < 0 || already) return ret; - rbd_bus_del_dev(rbd_dev); ret = rbd_dev_header_watch_sync(rbd_dev, false); if (ret) rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret); @@ -5171,6 +5190,13 @@ static ssize_t rbd_remove(struct bus_type *bus, */ dout("%s: flushing notifies", __func__); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); + /* + * Don't free anything from rbd_dev->disk until after all + * notifies are completely processed. Otherwise + * rbd_bus_del_dev() will race with rbd_watch_cb(), resulting + * in a potential use after free of rbd_dev->disk or rbd_dev. + */ + rbd_bus_del_dev(rbd_dev); rbd_dev_image_release(rbd_dev); module_put(THIS_MODULE); -- cgit v1.2.3 From efadc98aab674153709cc357ba565f04e3164fcd Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 29 Aug 2013 19:16:42 -0700 Subject: rbd: ignore unmapped snapshots that no longer exist This prevents erroring out while adding a device when a snapshot unrelated to the current mapping is deleted between reading the snapshot context and reading the snapshot names. If the mapped snapshot name is not found an error still occurs as usual. Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 47c6f9cf9dba..626a7136fb2f 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4078,8 +4078,13 @@ static u64 rbd_v2_snap_id_by_name(struct rbd_device *rbd_dev, const char *name) snap_id = snapc->snaps[which]; snap_name = rbd_dev_v2_snap_name(rbd_dev, snap_id); - if (IS_ERR(snap_name)) - break; + if (IS_ERR(snap_name)) { + /* ignore no-longer existing snapshots */ + if (PTR_ERR(snap_name) == -ENOENT) + continue; + else + break; + } found = !strcmp(name, snap_name); kfree(snap_name); } -- cgit v1.2.3 From da6a6b63978d45f9ae582d1f362f182012da3a22 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Wed, 4 Sep 2013 17:57:31 -0700 Subject: rbd: fix error handling from rbd_snap_name() rbd_snap_name() calls rbd_dev_v{1,2}_snap_name() depending on the format of the image. The format 1 version returns NULL on error, which is handled by the caller. The format 2 version returns an ERR_PTR, which the caller of rbd_snap_name() does not expect. Fortunately this is unlikely to occur in practice because rbd_snap_id_by_name() is called before rbd_snap_name(). This would hit similar errors to rbd_snap_name() (like the snapshot not existing) and return early, so rbd_snap_name() would not hit an error unless the snapshot was removed between the two calls or memory was exhausted. Use an ERR_PTR in rbd_dev_v1_snap_name() so that the specific error can be propagated, and it is consistent with rbd_dev_v2_snap_name(). Handle the ERR_PTR in the only rbd_snap_name() caller. Suggested-by: Alex Elder Signed-off-by: Josh Durgin Reviewed-by: Alex Elder --- drivers/block/rbd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 626a7136fb2f..2f00778e1024 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -927,12 +927,14 @@ static const char *rbd_dev_v1_snap_name(struct rbd_device *rbd_dev, u64 snap_id) { u32 which; + const char *snap_name; which = rbd_dev_snap_index(rbd_dev, snap_id); if (which == BAD_SNAP_INDEX) - return NULL; + return ERR_PTR(-ENOENT); - return _rbd_dev_v1_snap_name(rbd_dev, which); + snap_name = _rbd_dev_v1_snap_name(rbd_dev, which); + return snap_name ? snap_name : ERR_PTR(-ENOMEM); } static const char *rbd_snap_name(struct rbd_device *rbd_dev, u64 snap_id) @@ -4163,8 +4165,8 @@ static int rbd_dev_spec_update(struct rbd_device *rbd_dev) /* Look up the snapshot name, and make a copy */ snap_name = rbd_snap_name(rbd_dev, spec->snap_id); - if (!snap_name) { - ret = -ENOMEM; + if (IS_ERR(snap_name)) { + ret = PTR_ERR(snap_name); goto out_err; } -- cgit v1.2.3 From bb8e0e84b30afc9827931c9773d75d5c99fcddff Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 11 Sep 2013 14:20:07 -0700 Subject: block: replace strict_strtoul() with kstrtoul() The use of strict_strtoul() is not preferred, because strict_strtoul() is obsolete. Thus, kstrtoul() should be used. Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/osdblk.c | 2 +- drivers/block/rbd.c | 2 +- drivers/block/xen-blkback/xenbus.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c index 1bbc681688e4..79aa179305b5 100644 --- a/drivers/block/osdblk.c +++ b/drivers/block/osdblk.c @@ -598,7 +598,7 @@ static ssize_t class_osdblk_remove(struct class *c, unsigned long ul; struct list_head *tmp; - rc = strict_strtoul(buf, 10, &ul); + rc = kstrtoul(buf, 10, &ul); if (rc) return rc; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 39c51cc7fabc..b22a7d0fe5b7 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -5132,7 +5132,7 @@ static ssize_t rbd_remove(struct bus_type *bus, bool already = false; int ret; - ret = strict_strtoul(buf, 10, &ul); + ret = kstrtoul(buf, 10, &ul); if (ret) return ret; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index fe5c3cd10c34..c2014a0aa206 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -620,7 +620,7 @@ static void backend_changed(struct xenbus_watch *watch, } /* Front end dir is a number, which is used as the handle. */ - err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle); + err = kstrtoul(strrchr(dev->otherend, '/') + 1, 0, &handle); if (err) return; -- cgit v1.2.3 From c86db975c87976a234f13a0c2d7f931d8ede493b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 11 Sep 2013 14:20:10 -0700 Subject: drivers/block/mg_disk.c: make mg_times_out() static mg_times_out() is used only in this file. Fix the following sparse warning: drivers/block/mg_disk.c:639:6: warning: symbol 'mg_times_out' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/mg_disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index a56cfcd5d648..77a60bedd7a3 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -636,7 +636,7 @@ ok_to_write: mg_request(host->breq); } -void mg_times_out(unsigned long data) +static void mg_times_out(unsigned long data) { struct mg_host *host = (struct mg_host *)data; char *name; -- cgit v1.2.3 From e7b18ede4443c0207b9fd849cf604e67c6f38fc9 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Wed, 11 Sep 2013 14:20:11 -0700 Subject: cciss: set max scatter gather entries to 32 on P600 At one time we used to set the maximum number of scatter gather elements on all Smart Array controllers to 32. At some point in time the firmware began to write the "appropriate" value for each controller into the config table. The cciss driver would then read that and set h->maxsgentries. h->maxsgentries = readl(&(h->cfgtable->MaxSGElements); On the P600 that value is 544. Under some workloads a significant performance reduction may result. This patch forces the P600 to use only 32 scatter gather elements. Other controllers are not affected. Signed-off-by: Mike Miller Signed-off-by: Dwight (Bud) Brown Signed-off-by: Tomas Henzl Acked-by: Stephen M. Cameron Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 62b6c2cc80b5..d2d95ff5353b 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4257,6 +4257,13 @@ static void cciss_find_board_params(ctlr_info_t *h) cciss_get_max_perf_mode_cmds(h); h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds; h->maxsgentries = readl(&(h->cfgtable->MaxSGElements)); + /* + * The P600 may exhibit poor performnace under some workloads + * if we use the value in the configuration table. Limit this + * controller to MAXSGENTRIES (32) instead. + */ + if (h->board_id == 0x3225103C) + h->maxsgentries = MAXSGENTRIES; /* * Limit in-command s/g elements to 32 save dma'able memory. * Howvever spec says if 0, use 31 -- cgit v1.2.3 From c07303c0af38ffb1e5fd9b5ff37d0798298a7acf Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 11 Sep 2013 14:20:13 -0700 Subject: drivers/block/swim.c: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Cc: Jean Delvare Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/swim.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 8ed6ccb748cf..b02d53a399f3 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -924,7 +924,6 @@ static int swim_probe(struct platform_device *dev) return 0; out_kfree: - platform_set_drvdata(dev, NULL); kfree(swd); out_iounmap: iounmap(swim_base); @@ -962,7 +961,6 @@ static int swim_remove(struct platform_device *dev) if (res) release_mem_region(res->start, resource_size(res)); - platform_set_drvdata(dev, NULL); kfree(swd); return 0; -- cgit v1.2.3 From 190519cd30884215a63ed875ac074dc97a602522 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:39 -0700 Subject: aoe: create and destroy debugfs directory for aoe This series adds the debugging information that the coraid.com-distributed aoe driver exports via sysfs, but instead of sysfs, it uses debugfs. With these patches applied, even without AoE targets on the network, KEDR reports new possible memory leaks, but these are from callers outside the aoe driver that have used aoe_devnode to get the name of the character devices through the aoe_class->devnode callback, and I believe they're responsible for freeing that memory. This patch: Create and destroy the debugfs directory. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoeblk.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 916d9ed5c8aa..cb508b754377 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -17,11 +17,13 @@ #include #include #include +#include #include #include "aoe.h" static DEFINE_MUTEX(aoeblk_mutex); static struct kmem_cache *buf_pool_cache; +static struct dentry *aoe_debugfs_dir; /* GPFS needs a larger value than the default. */ static int aoe_maxsectors; @@ -351,6 +353,8 @@ err: void aoeblk_exit(void) { + debugfs_remove_recursive(aoe_debugfs_dir); + aoe_debugfs_dir = NULL; kmem_cache_destroy(buf_pool_cache); } @@ -362,7 +366,11 @@ aoeblk_init(void) 0, 0, NULL); if (buf_pool_cache == NULL) return -ENOMEM; - + aoe_debugfs_dir = debugfs_create_dir("aoe", NULL); + if (IS_ERR_OR_NULL(aoe_debugfs_dir)) { + pr_info("aoe: cannot create debugfs directory\n"); + aoe_debugfs_dir = NULL; + } return 0; } -- cgit v1.2.3 From e8866cf2b90f3a29859d2113c0fd23daf189c282 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:40 -0700 Subject: aoe: add AoE-target files to debugfs Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoe.h | 2 ++ drivers/block/aoe/aoeblk.c | 35 +++++++++++++++++++++++++++++++++++ drivers/block/aoe/aoedev.c | 1 + 3 files changed, 38 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 025c41d3cb33..b1f24c5a6bd1 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -169,6 +169,7 @@ struct aoedev { ulong ref; struct work_struct work;/* disk create work struct */ struct gendisk *gd; + struct dentry *debugfs; struct request_queue *blkq; struct hd_geometry geo; sector_t ssize; @@ -206,6 +207,7 @@ struct ktstate { int aoeblk_init(void); void aoeblk_exit(void); void aoeblk_gdalloc(void *); +void aoedisk_rm_debugfs(struct aoedev *d); void aoedisk_rm_sysfs(struct aoedev *d); int aoechr_init(void); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index cb508b754377..d76c5cb3c708 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -132,6 +132,40 @@ static const struct attribute_group attr_group = { .attrs = aoe_attrs, }; +static const struct file_operations aoe_debugfs_fops; + +static void +aoedisk_add_debugfs(struct aoedev *d) +{ + struct dentry *entry; + char *p; + + if (aoe_debugfs_dir == NULL) + return; + p = strchr(d->gd->disk_name, '/'); + if (p == NULL) + p = d->gd->disk_name; + else + p++; + BUG_ON(*p == '\0'); + entry = debugfs_create_file(p, 0444, aoe_debugfs_dir, d, + &aoe_debugfs_fops); + if (IS_ERR_OR_NULL(entry)) { + pr_info("aoe: cannot create debugfs file for %s\n", + d->gd->disk_name); + return; + } + BUG_ON(d->debugfs); + d->debugfs = entry; +} +void +aoedisk_rm_debugfs(struct aoedev *d) +{ + BUG_ON(d->debugfs == NULL); + debugfs_remove(d->debugfs); + d->debugfs = NULL; +} + static int aoedisk_add_sysfs(struct aoedev *d) { @@ -332,6 +366,7 @@ aoeblk_gdalloc(void *vp) add_disk(gd); aoedisk_add_sysfs(d); + aoedisk_add_debugfs(d); spin_lock_irqsave(&d->lock, flags); WARN_ON(!(d->flags & DEVFL_GD_NOW)); diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 784c92e038d1..c9047675dfc9 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -278,6 +278,7 @@ freedev(struct aoedev *d) del_timer_sync(&d->timer); if (d->gd) { + aoedisk_rm_debugfs(d); aoedisk_rm_sysfs(d); del_gendisk(d->gd); put_disk(d->gd); -- cgit v1.2.3 From 1cf94797c2bbc514c2bd0892e1774a0a8ca9afdb Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:41 -0700 Subject: aoe: provide file operations for debugfs files The place holder in the file contents is filled out in the following patch. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoeblk.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index d76c5cb3c708..0511d38e412d 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -110,6 +110,24 @@ static ssize_t aoedisk_show_payload(struct device *dev, return snprintf(page, PAGE_SIZE, "%lu\n", d->maxbcnt); } +static int aoedisk_debugfs_show(struct seq_file *s, void *ignored) +{ + struct aoedev *d; + unsigned long flags; + + d = s->private; + spin_lock_irqsave(&d->lock, flags); + seq_printf(s, "%s\n", d->gd->disk_name); /* place holder */ + spin_unlock_irqrestore(&d->lock, flags); + + return 0; +} + +static int aoe_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, aoedisk_debugfs_show, inode->i_private); +} + static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL); static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL); static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL); @@ -132,7 +150,12 @@ static const struct attribute_group attr_group = { .attrs = aoe_attrs, }; -static const struct file_operations aoe_debugfs_fops; +static const struct file_operations aoe_debugfs_fops = { + .open = aoe_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; static void aoedisk_add_debugfs(struct aoedev *d) -- cgit v1.2.3 From 2256c1c51e98d4eb2063a7f84f9ea783fda95f7f Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:42 -0700 Subject: aoe: fill in per-AoE-target information for debugfs file This information is presented in a compact format that has evolved for easy routine scanning by expert humans, mostly developers and support technicians helping to troubleshoot or test AoE-based systems. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoeblk.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 0511d38e412d..b58cbeb43e05 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -113,11 +113,42 @@ static ssize_t aoedisk_show_payload(struct device *dev, static int aoedisk_debugfs_show(struct seq_file *s, void *ignored) { struct aoedev *d; + struct aoetgt **t, **te; + struct aoeif *ifp, *ife; unsigned long flags; + char c; d = s->private; + seq_printf(s, "rttavg: %d rttdev: %d\n", + d->rttavg >> RTTSCALE, + d->rttdev >> RTTDSCALE); + seq_printf(s, "nskbpool: %d\n", skb_queue_len(&d->skbpool)); + seq_printf(s, "kicked: %ld\n", d->kicked); + seq_printf(s, "maxbcnt: %ld\n", d->maxbcnt); + seq_printf(s, "ref: %ld\n", d->ref); + spin_lock_irqsave(&d->lock, flags); - seq_printf(s, "%s\n", d->gd->disk_name); /* place holder */ + t = d->targets; + te = t + d->ntargets; + for (; t < te && *t; t++) { + c = '\t'; + seq_printf(s, "falloc: %ld\n", (*t)->falloc); + seq_printf(s, "ffree: %p\n", + list_empty(&(*t)->ffree) ? NULL : (*t)->ffree.next); + seq_printf(s, "%pm:%d:%d:%d\n", (*t)->addr, (*t)->nout, + (*t)->maxout, (*t)->nframes); + seq_printf(s, "\tssthresh:%d\n", (*t)->ssthresh); + seq_printf(s, "\ttaint:%d\n", (*t)->taint); + seq_printf(s, "\tr:%d\n", (*t)->rpkts); + seq_printf(s, "\tw:%d\n", (*t)->wpkts); + ifp = (*t)->ifs; + ife = ifp + ARRAY_SIZE((*t)->ifs); + for (; ifp->nd && ifp < ife; ifp++) { + seq_printf(s, "%c%s", c, ifp->nd->name); + c = ','; + } + seq_puts(s, "\n"); + } spin_unlock_irqrestore(&d->lock, flags); return 0; -- cgit v1.2.3 From ec345120c571847dea3d3bef76dd9b7978fa794e Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:43 -0700 Subject: aoe: update copyright date Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoeblk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index b58cbeb43e05..d63dcf0f2266 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */ /* * aoeblk.c * block device routines -- cgit v1.2.3 From 896dcd9a64a86d8792302615ee8ab118dc8afd9c Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:44 -0700 Subject: aoe: update internal version number to 85 Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index b1f24c5a6bd1..14a9d1912318 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ /* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "83" +#define VERSION "85" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" -- cgit v1.2.3 From a88c1f0caccaa335690d53ea03b12de31c357263 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Sep 2013 14:25:44 -0700 Subject: aoe: remove custom implementation of kbasename() In the kernel we have a nice helper that may be used here. This patch substitutes the custom implementation by the native function call. Signed-off-by: Andy Shevchenko Cc: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoedev.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index c9047675dfc9..e774c50b6842 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "aoe.h" static void dummy_timer(ulong); @@ -241,16 +242,12 @@ aoedev_downdev(struct aoedev *d) static int user_req(char *s, size_t slen, struct aoedev *d) { - char *p; + const char *p; size_t lim; if (!d->gd) return 0; - p = strrchr(d->gd->disk_name, '/'); - if (!p) - p = d->gd->disk_name; - else - p += 1; + p = kbasename(d->gd->disk_name); lim = sizeof(d->gd->disk_name); lim -= p - d->gd->disk_name; if (slen < lim) -- cgit v1.2.3 From e0ec36059774ff51812b40509d28ca6c9a2a6a62 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Sep 2013 14:25:45 -0700 Subject: aoe: suppress compiler warnings This patch fixes following compiler warnings: drivers/block/aoe/aoecmd.c: In function `aoecmd_ata_rw': drivers/block/aoe/aoecmd.c:383:17: warning: variable `t' set but not used [-Wunused-but-set-variable] struct aoetgt *t; ^ drivers/block/aoe/aoecmd.c: In function `resend': drivers/block/aoe/aoecmd.c:488:21: warning: variable `ah' set but not used [-Wunused-but-set-variable] struct aoe_atahdr *ah; ^ Signed-off-by: Andy Shevchenko Cc: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoecmd.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 4d45dba7fb8f..d2515435e23f 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -380,7 +380,6 @@ aoecmd_ata_rw(struct aoedev *d) { struct frame *f; struct buf *buf; - struct aoetgt *t; struct sk_buff *skb; struct sk_buff_head queue; ulong bcnt, fbcnt; @@ -391,7 +390,6 @@ aoecmd_ata_rw(struct aoedev *d) f = newframe(d); if (f == NULL) return 0; - t = *d->tgt; bcnt = d->maxbcnt; if (bcnt == 0) bcnt = DEFAULTBCNT; @@ -485,7 +483,6 @@ resend(struct aoedev *d, struct frame *f) struct sk_buff *skb; struct sk_buff_head queue; struct aoe_hdr *h; - struct aoe_atahdr *ah; struct aoetgt *t; char buf[128]; u32 n; @@ -500,7 +497,6 @@ resend(struct aoedev *d, struct frame *f) return; } h = (struct aoe_hdr *) skb_mac_header(skb); - ah = (struct aoe_atahdr *) (h+1); if (!(f->flags & FFL_PROBE)) { snprintf(buf, sizeof(buf), -- cgit v1.2.3 From fea1b139735355fe17a66f63811c58698ff03ec5 Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 11 Sep 2013 14:25:46 -0700 Subject: aoe: do not BUG if memory pressure prevented debugfs file creation If the system has trouble allocating memory for the creation of the aoe debugfs directory or of a file inside it, the debugfs member of an aoedev can be NULL. Do not treat a NULL debugfs pointer as a BUG on aoedev shutdown, avoiding the user impact of an unecessary panic. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoeblk.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index d63dcf0f2266..dd73e1ff1759 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -215,7 +215,6 @@ aoedisk_add_debugfs(struct aoedev *d) void aoedisk_rm_debugfs(struct aoedev *d) { - BUG_ON(d->debugfs == NULL); debugfs_remove(d->debugfs); d->debugfs = NULL; } -- cgit v1.2.3 From 5323fb770b6254a4c218a2dfb0ef9aa007b7725a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:51 -0700 Subject: pktcdvd: convert ZONE macro to static function get_zone() Macros should be converted to functions where feasible to verify arguments and the like. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index f5d0ea11d9fd..aa18a2584249 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -83,9 +83,6 @@ #define MAX_SPEED 0xffff -#define ZONE(sector, pd) (((sector) + (pd)->offset) & \ - ~(sector_t)((pd)->settings.size - 1)) - static DEFINE_MUTEX(pktcdvd_mutex); static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; @@ -103,7 +100,10 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev); static int pkt_remove_dev(dev_t pkt_dev); static int pkt_seq_show(struct seq_file *m, void *p); - +static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd) +{ + return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1); +} /* * create and register a pktcdvd kernel object. @@ -1224,7 +1224,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) node = first_node; while (node) { bio = node->bio; - zone = ZONE(bio->bi_sector, pd); + zone = get_zone(bio->bi_sector, pd); list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { if (p->sector == zone) { bio = NULL; @@ -1264,8 +1264,8 @@ try_next_bio: while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; VPRINTK("pkt_handle_queue: found zone=%llx\n", - (unsigned long long)ZONE(bio->bi_sector, pd)); - if (ZONE(bio->bi_sector, pd) != zone) + (unsigned long long)get_zone(bio->bi_sector, pd)); + if (get_zone(bio->bi_sector, pd) != zone) break; pkt_rbtree_erase(pd, node); spin_lock(&pkt->lock); @@ -2394,7 +2394,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); - zone = ZONE(bio->bi_sector, pd); + zone = get_zone(bio->bi_sector, pd); VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n", (unsigned long long)bio->bi_sector, (unsigned long long)bio_end_sector(bio)); @@ -2405,7 +2405,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) sector_t last_zone; int first_sectors; - last_zone = ZONE(bio_end_sector(bio) - 1, pd); + last_zone = get_zone(bio_end_sector(bio) - 1, pd); if (last_zone != zone) { BUG_ON(last_zone != zone + pd->settings.size); first_sectors = last_zone - bio->bi_sector; @@ -2500,7 +2500,7 @@ static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, struct bio_vec *bvec) { struct pktcdvd_device *pd = q->queuedata; - sector_t zone = ZONE(bmd->bi_sector, pd); + sector_t zone = get_zone(bmd->bi_sector, pd); int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size; int remaining = (pd->settings.size << 9) - used; int remaining2; -- cgit v1.2.3 From 99481334bcab1330fce0c590b845b4a95b101a69 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:52 -0700 Subject: pktcdvd: convert printk to pr_ Use a more current logging style and add messages levels to the logging messages. Simplify pkt_dump_sense by using %*ph and adding a simple function to emit the sense string. Includes improvements from Andy Shevchenko and Dan Carpenter. Signed-off-by: Joe Perches Cc: Andy Shevchenko Cc: Dan Carpenter Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 122 ++++++++++++++++++++++++------------------------ 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index aa18a2584249..eb71522c20ab 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -44,6 +44,8 @@ * *************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -424,7 +426,7 @@ static int pkt_sysfs_init(void) if (ret) { kfree(class_pktcdvd); class_pktcdvd = NULL; - printk(DRIVER_NAME": failed to create class pktcdvd\n"); + pr_err("failed to create class pktcdvd\n"); return ret; } return 0; @@ -734,36 +736,32 @@ out: return ret; } +static const char *sense_key_string(__u8 index) +{ + static const char * const info[] = { + "No sense", "Recovered error", "Not ready", + "Medium error", "Hardware error", "Illegal request", + "Unit attention", "Data protect", "Blank check", + }; + + return index < ARRAY_SIZE(info) ? info[index] : "INVALID"; +} + /* * A generic sense dump / resolve mechanism should be implemented across * all ATAPI + SCSI devices. */ static void pkt_dump_sense(struct packet_command *cgc) { - static char *info[9] = { "No sense", "Recovered error", "Not ready", - "Medium error", "Hardware error", "Illegal request", - "Unit attention", "Data protect", "Blank check" }; - int i; struct request_sense *sense = cgc->sense; - printk(DRIVER_NAME":"); - for (i = 0; i < CDROM_PACKET_SIZE; i++) - printk(" %02x", cgc->cmd[i]); - printk(" - "); - - if (sense == NULL) { - printk("no sense\n"); - return; - } - - printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq); - - if (sense->sense_key > 8) { - printk(" (INVALID)\n"); - return; - } - - printk(" (%s)\n", info[sense->sense_key]); + if (sense) + pr_err("%*ph - sense %02x.%02x.%02x (%s)\n", + CDROM_PACKET_SIZE, cgc->cmd, + sense->sense_key, sense->asc, sense->ascq, + sense_key_string(sense->sense_key)); + else + pr_err("%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd); } /* @@ -943,7 +941,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_que set_bit(PACKET_MERGE_SEGS, &pd->flags); return 0; } else { - printk(DRIVER_NAME": cdrom max_phys_segments too small\n"); + pr_err("cdrom max_phys_segments too small\n"); return -EIO; } } @@ -1563,9 +1561,10 @@ work_to_do: static void pkt_print_settings(struct pktcdvd_device *pd) { - printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); - printk("%u blocks, ", pd->settings.size >> 2); - printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2'); + pr_info("%s packets, %u blocks, Mode-%c disc\n", + pd->settings.fp ? "Fixed" : "Variable", + pd->settings.size >> 2, + pd->settings.block_mode == 8 ? '1' : '2'); } static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control) @@ -1749,7 +1748,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) /* * paranoia */ - printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type); + pr_err("write mode wrong %d\n", wp->data_block_type); return 1; } wp->packet_size = cpu_to_be32(pd->settings.size >> 2); @@ -1793,7 +1792,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti) if (ti->rt == 1 && ti->blank == 0) return 1; - printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + pr_err("bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); return 0; } @@ -1820,22 +1819,22 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) * but i'm not sure, should we leave this to user apps? probably. */ if (di->disc_type == 0xff) { - printk(DRIVER_NAME": Unknown disc. No track?\n"); + pr_notice("unknown disc - no track?\n"); return 0; } if (di->disc_type != 0x20 && di->disc_type != 0) { - printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type); + pr_err("wrong disc type (%x)\n", di->disc_type); return 0; } if (di->erasable == 0) { - printk(DRIVER_NAME": Disc not erasable\n"); + pr_notice("disc not erasable\n"); return 0; } if (di->border_status == PACKET_SESSION_RESERVED) { - printk(DRIVER_NAME": Can't write to last track (reserved)\n"); + pr_err("can't write to last track (reserved)\n"); return 0; } @@ -1860,7 +1859,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) memset(&ti, 0, sizeof(track_information)); if ((ret = pkt_get_disc_info(pd, &di))) { - printk("failed get_disc\n"); + pr_err("failed get_disc\n"); return ret; } @@ -1871,12 +1870,12 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ if ((ret = pkt_get_track_info(pd, track, 1, &ti))) { - printk(DRIVER_NAME": failed get_track\n"); + pr_err("failed get_track\n"); return ret; } if (!pkt_writable_track(pd, &ti)) { - printk(DRIVER_NAME": can't write to this track\n"); + pr_err("can't write to this track\n"); return -EROFS; } @@ -1886,11 +1885,11 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) */ pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; if (pd->settings.size == 0) { - printk(DRIVER_NAME": detected zero packet size!\n"); + pr_notice("detected zero packet size!\n"); return -ENXIO; } if (pd->settings.size > PACKET_MAX_SECTORS) { - printk(DRIVER_NAME": packet size is too big\n"); + pr_err("packet size is too big\n"); return -EROFS; } pd->settings.fp = ti.fp; @@ -1932,7 +1931,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) pd->settings.block_mode = PACKET_BLOCK_MODE2; break; default: - printk(DRIVER_NAME": unknown data mode\n"); + pr_err("unknown data mode\n"); return -EROFS; } return 0; @@ -1966,10 +1965,10 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); ret = pkt_mode_select(pd, &cgc); if (ret) { - printk(DRIVER_NAME": write caching control failed\n"); + pr_err("write caching control failed\n"); pkt_dump_sense(&cgc); } else if (!ret && set) - printk(DRIVER_NAME": enabled write caching on %s\n", pd->name); + pr_notice("enabled write caching on %s\n", pd->name); return ret; } @@ -2084,11 +2083,11 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, } if (!(buf[6] & 0x40)) { - printk(DRIVER_NAME": Disc type is not CD-RW\n"); + pr_notice("disc type is not CD-RW\n"); return 1; } if (!(buf[6] & 0x4)) { - printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n"); + pr_notice("A1 values on media are not valid, maybe not CDRW?\n"); return 1; } @@ -2108,14 +2107,14 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, *speed = us_clv_to_speed[sp]; break; default: - printk(DRIVER_NAME": Unknown disc sub-type %d\n",st); + pr_notice("unknown disc sub-type %d\n", st); return 1; } if (*speed) { - printk(DRIVER_NAME": Max. media speed: %d\n",*speed); + pr_info("maximum media speed: %d\n", *speed); return 0; } else { - printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st); + pr_notice("unknown speed %d for sub-type %d\n", sp, st); return 1; } } @@ -2205,7 +2204,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) goto out; if ((ret = pkt_get_last_written(pd, &lba))) { - printk(DRIVER_NAME": pkt_get_last_written failed\n"); + pr_err("pkt_get_last_written failed\n"); goto out_putdev; } @@ -2235,11 +2234,11 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) if (write) { if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { - printk(DRIVER_NAME": not enough memory for buffers\n"); + pr_err("not enough memory for buffers\n"); ret = -ENOMEM; goto out_putdev; } - printk(DRIVER_NAME": %lukB available on disc\n", lba << 1); + pr_info("%lukB available on disc\n", lba << 1); } return 0; @@ -2360,7 +2359,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) pd = q->queuedata; if (!pd) { - printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b)); + pr_err("%s incorrect request queue\n", + bdevname(bio->bi_bdev, b)); goto end_io; } @@ -2382,13 +2382,13 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { - printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n", - pd->name, (unsigned long long)bio->bi_sector); + pr_notice("WRITE for ro device %s (%llu)\n", + pd->name, (unsigned long long)bio->bi_sector); goto end_io; } if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { - printk(DRIVER_NAME": wrong bio size\n"); + pr_err("wrong bio size\n"); goto end_io; } @@ -2609,7 +2609,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) struct block_device *bdev; if (pd->pkt_dev == dev) { - printk(DRIVER_NAME": Recursive setup not allowed\n"); + pr_err("recursive setup not allowed\n"); return -EBUSY; } for (i = 0; i < MAX_WRITERS; i++) { @@ -2617,11 +2617,11 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) if (!pd2) continue; if (pd2->bdev->bd_dev == dev) { - printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b)); + pr_err("%s already setup\n", bdevname(pd2->bdev, b)); return -EBUSY; } if (pd2->pkt_dev == dev) { - printk(DRIVER_NAME": Can't chain pktcdvd devices\n"); + pr_err("can't chain pktcdvd devices\n"); return -EBUSY; } } @@ -2644,7 +2644,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) atomic_set(&pd->cdrw.pending_bios, 0); pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); if (IS_ERR(pd->cdrw.thread)) { - printk(DRIVER_NAME": can't start kernel thread\n"); + pr_err("can't start kernel thread\n"); ret = -ENOMEM; goto out_mem; } @@ -2743,7 +2743,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) if (!pkt_devs[idx]) break; if (idx == MAX_WRITERS) { - printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS); + pr_err("max %d writers supported\n", MAX_WRITERS); ret = -EBUSY; goto out_mutex; } @@ -2818,7 +2818,7 @@ out_mem: kfree(pd); out_mutex: mutex_unlock(&ctl_mutex); - printk(DRIVER_NAME": setup of pktcdvd device failed\n"); + pr_err("setup of pktcdvd device failed\n"); return ret; } @@ -2969,7 +2969,7 @@ static int __init pkt_init(void) ret = register_blkdev(pktdev_major, DRIVER_NAME); if (ret < 0) { - printk(DRIVER_NAME": Unable to register block device\n"); + pr_err("unable to register block device\n"); goto out2; } if (!pktdev_major) @@ -2983,7 +2983,7 @@ static int __init pkt_init(void) ret = misc_register(&pkt_misc); if (ret) { - printk(DRIVER_NAME": Unable to register misc device\n"); + pr_err("unable to register misc device\n"); goto out_misc; } -- cgit v1.2.3 From cd3f2cd05cf1066f3975ed3223f12c799bc553c6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:53 -0700 Subject: pktcdvd: consolidate DPRINTK and VPRINTK macros Use the more common pkt_dbg(level, fmt, ...) form. These messages are emitted at KERN_NOTICE. Always emit function name with pkt_dbg(2, ...) uses and remove the sometimes abbreviated embedded function name. This form always verifies the format and arguments. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 107 ++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 54 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index eb71522c20ab..aaa5da2b3d66 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -71,17 +71,13 @@ #define DRIVER_NAME "pktcdvd" -#if PACKET_DEBUG -#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) -#else -#define DPRINTK(fmt, args...) -#endif - -#if PACKET_DEBUG > 1 -#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) -#else -#define VPRINTK(fmt, args...) -#endif +#define pkt_dbg(level, fmt, ...) \ +do { \ + if (level == 2 && PACKET_DEBUG >= 2) \ + pr_notice("%s: " fmt, __func__, ##__VA_ARGS__); \ + else if (level == 1 && PACKET_DEBUG >= 1) \ + pr_notice(fmt, ##__VA_ARGS__); \ +} while (0) #define MAX_SPEED 0xffff @@ -519,7 +515,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd) { BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0); if (atomic_dec_and_test(&pd->cdrw.pending_bios)) { - VPRINTK(DRIVER_NAME": queue empty\n"); + pkt_dbg(2, "queue empty\n"); atomic_set(&pd->iosched.attention, 1); wake_up(&pd->wqueue); } @@ -870,7 +866,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - VPRINTK(DRIVER_NAME": write, waiting\n"); + pkt_dbg(2, "write, waiting\n"); break; } pkt_flush_cache(pd); @@ -879,7 +875,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) } else { if (!reads_queued && writes_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - VPRINTK(DRIVER_NAME": read, waiting\n"); + pkt_dbg(2, "read, waiting\n"); break; } pd->iosched.writing = 1; @@ -985,8 +981,9 @@ static void pkt_end_io_read(struct bio *bio, int err) struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, - (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); + pkt_dbg(2, "bio=%p sec0=%llx sec=%llx err=%d\n", + bio, (unsigned long long)pkt->sector, + (unsigned long long)bio->bi_sector, err); if (err) atomic_inc(&pkt->io_errors); @@ -1003,7 +1000,7 @@ static void pkt_end_io_packet_write(struct bio *bio, int err) struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err); + pkt_dbg(2, "id=%d, err=%d\n", pkt->id, err); pd->stats.pkt_ended++; @@ -1045,7 +1042,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) spin_unlock(&pkt->lock); if (pkt->cache_valid) { - VPRINTK("pkt_gather_data: zone %llx cached\n", + pkt_dbg(2, "zone %llx cached\n", (unsigned long long)pkt->sector); goto out_account; } @@ -1068,7 +1065,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) p = (f * CD_FRAMESIZE) / PAGE_SIZE; offset = (f * CD_FRAMESIZE) % PAGE_SIZE; - VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d\n", + pkt_dbg(2, "Adding frame %d, page:%p offs:%d\n", f, pkt->pages[p], offset); if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset)) BUG(); @@ -1080,7 +1077,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) } out_account: - VPRINTK("pkt_gather_data: need %d frames for zone %llx\n", + pkt_dbg(2, "need %d frames for zone %llx\n", frames_read, (unsigned long long)pkt->sector); pd->stats.pkt_started++; pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); @@ -1181,7 +1178,8 @@ static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED" }; enum packet_data_state old_state = pkt->state; - VPRINTK("pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector, + pkt_dbg(2, "pkt %2d : s=%6llx %s -> %s\n", + pkt->id, (unsigned long long)pkt->sector, state_name[old_state], state_name[state]); #endif pkt->state = state; @@ -1200,12 +1198,12 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) struct rb_node *n; int wakeup; - VPRINTK("handle_queue\n"); + pkt_dbg(2, "\n"); atomic_set(&pd->scan_queue, 0); if (list_empty(&pd->cdrw.pkt_free_list)) { - VPRINTK("handle_queue: no pkt\n"); + pkt_dbg(2, "no pkt\n"); return 0; } @@ -1242,7 +1240,7 @@ try_next_bio: } spin_unlock(&pd->lock); if (!bio) { - VPRINTK("handle_queue: no bio\n"); + pkt_dbg(2, "no bio\n"); return 0; } @@ -1258,10 +1256,10 @@ try_next_bio: * to this packet. */ spin_lock(&pd->lock); - VPRINTK("pkt_handle_queue: looking for zone %llx\n", (unsigned long long)zone); + pkt_dbg(2, "looking for zone %llx\n", (unsigned long long)zone); while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; - VPRINTK("pkt_handle_queue: found zone=%llx\n", + pkt_dbg(2, "found zone=%llx\n", (unsigned long long)get_zone(bio->bi_sector, pd)); if (get_zone(bio->bi_sector, pd) != zone) break; @@ -1314,7 +1312,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset)) BUG(); } - VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt); + pkt_dbg(2, "vcnt=%d\n", pkt->w_bio->bi_vcnt); /* * Fill-in bvec with data from orig_bios. @@ -1325,7 +1323,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); spin_unlock(&pkt->lock); - VPRINTK("pkt_start_write: Writing %d frames for zone %llx\n", + pkt_dbg(2, "Writing %d frames for zone %llx\n", pkt->write_size, (unsigned long long)pkt->sector); if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) { @@ -1357,7 +1355,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data { int uptodate; - VPRINTK("run_state_machine: pkt %d\n", pkt->id); + pkt_dbg(2, "pkt %d\n", pkt->id); for (;;) { switch (pkt->state) { @@ -1396,7 +1394,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data if (pkt_start_recovery(pkt)) { pkt_start_write(pd, pkt); } else { - VPRINTK("No recovery possible\n"); + pkt_dbg(2, "No recovery possible\n"); pkt_set_state(pkt, PACKET_FINISHED_STATE); } break; @@ -1417,7 +1415,7 @@ static void pkt_handle_packets(struct pktcdvd_device *pd) { struct packet_data *pkt, *next; - VPRINTK("pkt_handle_packets\n"); + pkt_dbg(2, "\n"); /* * Run state machine for active packets @@ -1500,9 +1498,9 @@ static int kcdrwd(void *foobar) if (PACKET_DEBUG > 1) { int states[PACKET_NUM_STATES]; pkt_count_states(pd, states); - VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", - states[0], states[1], states[2], states[3], - states[4], states[5]); + pkt_dbg(2, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + states[0], states[1], states[2], + states[3], states[4], states[5]); } min_sleep_time = MAX_SCHEDULE_TIMEOUT; @@ -1511,9 +1509,9 @@ static int kcdrwd(void *foobar) min_sleep_time = pkt->sleep_time; } - VPRINTK("kcdrwd: sleeping\n"); + pkt_dbg(2, "sleeping\n"); residue = schedule_timeout(min_sleep_time); - VPRINTK("kcdrwd: wake up\n"); + pkt_dbg(2, "wake up\n"); /* make swsusp happy with our thread */ try_to_freeze(); @@ -1810,7 +1808,8 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) case 0x12: /* DVD-RAM */ return 1; default: - VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile); + pkt_dbg(2, "Wrong disc profile (%x)\n", + pd->mmc3_profile); return 0; } @@ -2125,7 +2124,7 @@ static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd) struct request_sense sense; int ret; - VPRINTK(DRIVER_NAME": Performing OPC\n"); + pkt_dbg(2, "Performing OPC\n"); init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.sense = &sense; @@ -2143,12 +2142,12 @@ static int pkt_open_write(struct pktcdvd_device *pd) unsigned int write_speed, media_write_speed, read_speed; if ((ret = pkt_probe_settings(pd))) { - VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name); + pkt_dbg(2, "%s failed probe\n", pd->name); return ret; } if ((ret = pkt_set_write_settings(pd))) { - DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name); + pkt_dbg(1, "%s failed saving write settings\n", pd->name); return -EIO; } @@ -2160,26 +2159,26 @@ static int pkt_open_write(struct pktcdvd_device *pd) case 0x13: /* DVD-RW */ case 0x1a: /* DVD+RW */ case 0x12: /* DVD-RAM */ - DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed); + pkt_dbg(1, "write speed %ukB/s\n", write_speed); break; default: if ((ret = pkt_media_speed(pd, &media_write_speed))) media_write_speed = 16; write_speed = min(write_speed, media_write_speed * 177); - DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176); + pkt_dbg(1, "write speed %ux\n", write_speed / 176); break; } read_speed = write_speed; if ((ret = pkt_set_speed(pd, write_speed, read_speed))) { - DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name); + pkt_dbg(1, "%s couldn't set write speed\n", pd->name); return -EIO; } pd->write_speed = write_speed; pd->read_speed = read_speed; if ((ret = pkt_perform_opc(pd))) { - DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name); + pkt_dbg(1, "%s Optimum Power Calibration failed\n", pd->name); } return 0; @@ -2256,7 +2255,7 @@ out: static void pkt_release_dev(struct pktcdvd_device *pd, int flush) { if (flush && pkt_flush_cache(pd)) - DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name); + pkt_dbg(1, "%s not flushing cache\n", pd->name); pkt_lock_door(pd, 0); @@ -2278,7 +2277,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) struct pktcdvd_device *pd = NULL; int ret; - VPRINTK(DRIVER_NAME": entering open\n"); + pkt_dbg(2, "entering\n"); mutex_lock(&pktcdvd_mutex); mutex_lock(&ctl_mutex); @@ -2314,7 +2313,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) out_dec: pd->refcnt--; out: - VPRINTK(DRIVER_NAME": failed open (%d)\n", ret); + pkt_dbg(2, "failed (%d)\n", ret); mutex_unlock(&ctl_mutex); mutex_unlock(&pktcdvd_mutex); return ret; @@ -2395,7 +2394,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); zone = get_zone(bio->bi_sector, pd); - VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n", + pkt_dbg(2, "start = %6llx stop = %6llx\n", (unsigned long long)bio->bi_sector, (unsigned long long)bio_end_sector(bio)); @@ -2650,7 +2649,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) } proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); - DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); + pkt_dbg(1, "writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); return 0; out_mem: @@ -2665,8 +2664,8 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, struct pktcdvd_device *pd = bdev->bd_disk->private_data; int ret; - VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, - MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); + pkt_dbg(2, "cmd %x, dev %d:%d\n", + cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); mutex_lock(&pktcdvd_mutex); switch (cmd) { @@ -2690,7 +2689,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, break; default: - VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); + pkt_dbg(2, "Unknown ioctl for %s (%x)\n", pd->name, cmd); ret = -ENOTTY; } mutex_unlock(&pktcdvd_mutex); @@ -2839,7 +2838,7 @@ static int pkt_remove_dev(dev_t pkt_dev) break; } if (idx == MAX_WRITERS) { - DPRINTK(DRIVER_NAME": dev not setup\n"); + pkt_dbg(1, "dev not setup\n"); ret = -ENXIO; goto out; } @@ -2859,7 +2858,7 @@ static int pkt_remove_dev(dev_t pkt_dev) blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY); remove_proc_entry(pd->name, pkt_proc); - DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name); + pkt_dbg(1, "writer %s unmapped\n", pd->name); del_gendisk(pd->disk); blk_cleanup_queue(pd->disk->queue); -- cgit v1.2.3 From 844aa7974395df1f0c7a866007e900e5f979fc7b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:54 -0700 Subject: pktcdvd: add struct pktcdvd_device * to pkt_dbg Add pd->name to output for these debugging messages. Remove normally compiled out pkt_dbg(2, ...) function entry tracing equivalents as it's better done via the function tracer. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 90 +++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 48 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index aaa5da2b3d66..5050c7abb6ee 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -71,12 +71,13 @@ #define DRIVER_NAME "pktcdvd" -#define pkt_dbg(level, fmt, ...) \ -do { \ - if (level == 2 && PACKET_DEBUG >= 2) \ - pr_notice("%s: " fmt, __func__, ##__VA_ARGS__); \ - else if (level == 1 && PACKET_DEBUG >= 1) \ - pr_notice(fmt, ##__VA_ARGS__); \ +#define pkt_dbg(level, pd, fmt, ...) \ +do { \ + if (level == 2 && PACKET_DEBUG >= 2) \ + pr_notice("%s: %s():" fmt, \ + pd->name, __func__, ##__VA_ARGS__); \ + else if (level == 1 && PACKET_DEBUG >= 1) \ + pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__); \ } while (0) #define MAX_SPEED 0xffff @@ -515,7 +516,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd) { BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0); if (atomic_dec_and_test(&pd->cdrw.pending_bios)) { - pkt_dbg(2, "queue empty\n"); + pkt_dbg(2, pd, "queue empty\n"); atomic_set(&pd->iosched.attention, 1); wake_up(&pd->wqueue); } @@ -866,7 +867,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - pkt_dbg(2, "write, waiting\n"); + pkt_dbg(2, pd, "write, waiting\n"); break; } pkt_flush_cache(pd); @@ -875,7 +876,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) } else { if (!reads_queued && writes_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { - pkt_dbg(2, "read, waiting\n"); + pkt_dbg(2, pd, "read, waiting\n"); break; } pd->iosched.writing = 1; @@ -981,7 +982,7 @@ static void pkt_end_io_read(struct bio *bio, int err) struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - pkt_dbg(2, "bio=%p sec0=%llx sec=%llx err=%d\n", + pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); @@ -1000,7 +1001,7 @@ static void pkt_end_io_packet_write(struct bio *bio, int err) struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - pkt_dbg(2, "id=%d, err=%d\n", pkt->id, err); + pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, err); pd->stats.pkt_ended++; @@ -1042,7 +1043,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) spin_unlock(&pkt->lock); if (pkt->cache_valid) { - pkt_dbg(2, "zone %llx cached\n", + pkt_dbg(2, pd, "zone %llx cached\n", (unsigned long long)pkt->sector); goto out_account; } @@ -1065,7 +1066,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) p = (f * CD_FRAMESIZE) / PAGE_SIZE; offset = (f * CD_FRAMESIZE) % PAGE_SIZE; - pkt_dbg(2, "Adding frame %d, page:%p offs:%d\n", + pkt_dbg(2, pd, "Adding frame %d, page:%p offs:%d\n", f, pkt->pages[p], offset); if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset)) BUG(); @@ -1077,7 +1078,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) } out_account: - pkt_dbg(2, "need %d frames for zone %llx\n", + pkt_dbg(2, pd, "need %d frames for zone %llx\n", frames_read, (unsigned long long)pkt->sector); pd->stats.pkt_started++; pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); @@ -1178,7 +1179,7 @@ static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED" }; enum packet_data_state old_state = pkt->state; - pkt_dbg(2, "pkt %2d : s=%6llx %s -> %s\n", + pkt_dbg(2, pd, "pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector, state_name[old_state], state_name[state]); #endif @@ -1198,12 +1199,10 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) struct rb_node *n; int wakeup; - pkt_dbg(2, "\n"); - atomic_set(&pd->scan_queue, 0); if (list_empty(&pd->cdrw.pkt_free_list)) { - pkt_dbg(2, "no pkt\n"); + pkt_dbg(2, pd, "no pkt\n"); return 0; } @@ -1240,7 +1239,7 @@ try_next_bio: } spin_unlock(&pd->lock); if (!bio) { - pkt_dbg(2, "no bio\n"); + pkt_dbg(2, pd, "no bio\n"); return 0; } @@ -1256,10 +1255,10 @@ try_next_bio: * to this packet. */ spin_lock(&pd->lock); - pkt_dbg(2, "looking for zone %llx\n", (unsigned long long)zone); + pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone); while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; - pkt_dbg(2, "found zone=%llx\n", + pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long)get_zone(bio->bi_sector, pd)); if (get_zone(bio->bi_sector, pd) != zone) break; @@ -1312,7 +1311,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset)) BUG(); } - pkt_dbg(2, "vcnt=%d\n", pkt->w_bio->bi_vcnt); + pkt_dbg(2, pd, "vcnt=%d\n", pkt->w_bio->bi_vcnt); /* * Fill-in bvec with data from orig_bios. @@ -1323,7 +1322,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); spin_unlock(&pkt->lock); - pkt_dbg(2, "Writing %d frames for zone %llx\n", + pkt_dbg(2, pd, "Writing %d frames for zone %llx\n", pkt->write_size, (unsigned long long)pkt->sector); if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) { @@ -1355,7 +1354,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data { int uptodate; - pkt_dbg(2, "pkt %d\n", pkt->id); + pkt_dbg(2, pd, "pkt %d\n", pkt->id); for (;;) { switch (pkt->state) { @@ -1394,7 +1393,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data if (pkt_start_recovery(pkt)) { pkt_start_write(pd, pkt); } else { - pkt_dbg(2, "No recovery possible\n"); + pkt_dbg(2, pd, "No recovery possible\n"); pkt_set_state(pkt, PACKET_FINISHED_STATE); } break; @@ -1415,8 +1414,6 @@ static void pkt_handle_packets(struct pktcdvd_device *pd) { struct packet_data *pkt, *next; - pkt_dbg(2, "\n"); - /* * Run state machine for active packets */ @@ -1498,7 +1495,7 @@ static int kcdrwd(void *foobar) if (PACKET_DEBUG > 1) { int states[PACKET_NUM_STATES]; pkt_count_states(pd, states); - pkt_dbg(2, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + pkt_dbg(2, pd, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", states[0], states[1], states[2], states[3], states[4], states[5]); } @@ -1509,9 +1506,9 @@ static int kcdrwd(void *foobar) min_sleep_time = pkt->sleep_time; } - pkt_dbg(2, "sleeping\n"); + pkt_dbg(2, pd, "sleeping\n"); residue = schedule_timeout(min_sleep_time); - pkt_dbg(2, "wake up\n"); + pkt_dbg(2, pd, "wake up\n"); /* make swsusp happy with our thread */ try_to_freeze(); @@ -1808,7 +1805,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) case 0x12: /* DVD-RAM */ return 1; default: - pkt_dbg(2, "Wrong disc profile (%x)\n", + pkt_dbg(2, pd, "Wrong disc profile (%x)\n", pd->mmc3_profile); return 0; } @@ -2124,7 +2121,7 @@ static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd) struct request_sense sense; int ret; - pkt_dbg(2, "Performing OPC\n"); + pkt_dbg(2, pd, "Performing OPC\n"); init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.sense = &sense; @@ -2142,12 +2139,12 @@ static int pkt_open_write(struct pktcdvd_device *pd) unsigned int write_speed, media_write_speed, read_speed; if ((ret = pkt_probe_settings(pd))) { - pkt_dbg(2, "%s failed probe\n", pd->name); + pkt_dbg(2, pd, "failed probe\n"); return ret; } if ((ret = pkt_set_write_settings(pd))) { - pkt_dbg(1, "%s failed saving write settings\n", pd->name); + pkt_dbg(1, pd, "failed saving write settings\n"); return -EIO; } @@ -2159,26 +2156,26 @@ static int pkt_open_write(struct pktcdvd_device *pd) case 0x13: /* DVD-RW */ case 0x1a: /* DVD+RW */ case 0x12: /* DVD-RAM */ - pkt_dbg(1, "write speed %ukB/s\n", write_speed); + pkt_dbg(1, pd, "write speed %ukB/s\n", write_speed); break; default: if ((ret = pkt_media_speed(pd, &media_write_speed))) media_write_speed = 16; write_speed = min(write_speed, media_write_speed * 177); - pkt_dbg(1, "write speed %ux\n", write_speed / 176); + pkt_dbg(1, pd, "write speed %ux\n", write_speed / 176); break; } read_speed = write_speed; if ((ret = pkt_set_speed(pd, write_speed, read_speed))) { - pkt_dbg(1, "%s couldn't set write speed\n", pd->name); + pkt_dbg(1, pd, "couldn't set write speed\n"); return -EIO; } pd->write_speed = write_speed; pd->read_speed = read_speed; if ((ret = pkt_perform_opc(pd))) { - pkt_dbg(1, "%s Optimum Power Calibration failed\n", pd->name); + pkt_dbg(1, pd, "Optimum Power Calibration failed\n"); } return 0; @@ -2255,7 +2252,7 @@ out: static void pkt_release_dev(struct pktcdvd_device *pd, int flush) { if (flush && pkt_flush_cache(pd)) - pkt_dbg(1, "%s not flushing cache\n", pd->name); + pkt_dbg(1, pd, "not flushing cache\n"); pkt_lock_door(pd, 0); @@ -2277,8 +2274,6 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) struct pktcdvd_device *pd = NULL; int ret; - pkt_dbg(2, "entering\n"); - mutex_lock(&pktcdvd_mutex); mutex_lock(&ctl_mutex); pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev)); @@ -2313,7 +2308,6 @@ static int pkt_open(struct block_device *bdev, fmode_t mode) out_dec: pd->refcnt--; out: - pkt_dbg(2, "failed (%d)\n", ret); mutex_unlock(&ctl_mutex); mutex_unlock(&pktcdvd_mutex); return ret; @@ -2394,7 +2388,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); zone = get_zone(bio->bi_sector, pd); - pkt_dbg(2, "start = %6llx stop = %6llx\n", + pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", (unsigned long long)bio->bi_sector, (unsigned long long)bio_end_sector(bio)); @@ -2649,7 +2643,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) } proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); - pkt_dbg(1, "writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); + pkt_dbg(1, pd, "writer mapped to %s\n", bdevname(bdev, b)); return 0; out_mem: @@ -2664,7 +2658,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, struct pktcdvd_device *pd = bdev->bd_disk->private_data; int ret; - pkt_dbg(2, "cmd %x, dev %d:%d\n", + pkt_dbg(2, pd, "cmd %x, dev %d:%d\n", cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); mutex_lock(&pktcdvd_mutex); @@ -2689,7 +2683,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, break; default: - pkt_dbg(2, "Unknown ioctl for %s (%x)\n", pd->name, cmd); + pkt_dbg(2, pd, "Unknown ioctl (%x)\n", cmd); ret = -ENOTTY; } mutex_unlock(&pktcdvd_mutex); @@ -2838,7 +2832,7 @@ static int pkt_remove_dev(dev_t pkt_dev) break; } if (idx == MAX_WRITERS) { - pkt_dbg(1, "dev not setup\n"); + pkt_dbg(1, pd, "dev not setup\n"); ret = -ENXIO; goto out; } @@ -2858,7 +2852,7 @@ static int pkt_remove_dev(dev_t pkt_dev) blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY); remove_proc_entry(pd->name, pkt_proc); - pkt_dbg(1, "writer %s unmapped\n", pd->name); + pkt_dbg(1, pd, "writer unmapped\n"); del_gendisk(pd->disk); blk_cleanup_queue(pd->disk->queue); -- cgit v1.2.3 From fa63c0ab81f55eb5a016c1bcea04fe39c14afbaa Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:55 -0700 Subject: pktcdvd: add struct pktcdvd_device.name to pr_err logging where possible Add a new pkt_err macro to prefix the name to the logging output. Convert pr_err where there is a non-null struct pktcdvd_device. Includes improvements from Andy Shevchenko. Signed-off-by: Joe Perches Cc: Andy Shevchenko Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 5050c7abb6ee..3dbe42fe1bdd 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -71,6 +71,9 @@ #define DRIVER_NAME "pktcdvd" +#define pkt_err(pd, fmt, ...) \ + pr_err("%s: " fmt, pd->name, ##__VA_ARGS__) + #define pkt_dbg(level, pd, fmt, ...) \ do { \ if (level == 2 && PACKET_DEBUG >= 2) \ @@ -938,7 +941,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_que set_bit(PACKET_MERGE_SEGS, &pd->flags); return 0; } else { - pr_err("cdrom max_phys_segments too small\n"); + pkt_err(pd, "cdrom max_phys_segments too small\n"); return -EIO; } } @@ -1743,7 +1746,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) /* * paranoia */ - pr_err("write mode wrong %d\n", wp->data_block_type); + pkt_err(pd, "write mode wrong %d\n", wp->data_block_type); return 1; } wp->packet_size = cpu_to_be32(pd->settings.size >> 2); @@ -1787,7 +1790,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti) if (ti->rt == 1 && ti->blank == 0) return 1; - pr_err("bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + pkt_err(pd, "bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); return 0; } @@ -1820,7 +1823,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) } if (di->disc_type != 0x20 && di->disc_type != 0) { - pr_err("wrong disc type (%x)\n", di->disc_type); + pkt_err(pd, "wrong disc type (%x)\n", di->disc_type); return 0; } @@ -1830,7 +1833,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) } if (di->border_status == PACKET_SESSION_RESERVED) { - pr_err("can't write to last track (reserved)\n"); + pkt_err(pd, "can't write to last track (reserved)\n"); return 0; } @@ -1855,7 +1858,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) memset(&ti, 0, sizeof(track_information)); if ((ret = pkt_get_disc_info(pd, &di))) { - pr_err("failed get_disc\n"); + pkt_err(pd, "failed get_disc\n"); return ret; } @@ -1866,12 +1869,12 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ if ((ret = pkt_get_track_info(pd, track, 1, &ti))) { - pr_err("failed get_track\n"); + pkt_err(pd, "failed get_track\n"); return ret; } if (!pkt_writable_track(pd, &ti)) { - pr_err("can't write to this track\n"); + pkt_err(pd, "can't write to this track\n"); return -EROFS; } @@ -1885,7 +1888,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) return -ENXIO; } if (pd->settings.size > PACKET_MAX_SECTORS) { - pr_err("packet size is too big\n"); + pkt_err(pd, "packet size is too big\n"); return -EROFS; } pd->settings.fp = ti.fp; @@ -1927,7 +1930,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) pd->settings.block_mode = PACKET_BLOCK_MODE2; break; default: - pr_err("unknown data mode\n"); + pkt_err(pd, "unknown data mode\n"); return -EROFS; } return 0; @@ -1961,7 +1964,7 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); ret = pkt_mode_select(pd, &cgc); if (ret) { - pr_err("write caching control failed\n"); + pkt_err(pd, "write caching control failed\n"); pkt_dump_sense(&cgc); } else if (!ret && set) pr_notice("enabled write caching on %s\n", pd->name); @@ -2200,7 +2203,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) goto out; if ((ret = pkt_get_last_written(pd, &lba))) { - pr_err("pkt_get_last_written failed\n"); + pkt_err(pd, "pkt_get_last_written failed\n"); goto out_putdev; } @@ -2230,7 +2233,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) if (write) { if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { - pr_err("not enough memory for buffers\n"); + pkt_err(pd, "not enough memory for buffers\n"); ret = -ENOMEM; goto out_putdev; } @@ -2352,8 +2355,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) pd = q->queuedata; if (!pd) { - pr_err("%s incorrect request queue\n", - bdevname(bio->bi_bdev, b)); + pkt_err(pd, "%s incorrect request queue\n", + bdevname(bio->bi_bdev, b)); goto end_io; } @@ -2381,7 +2384,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) } if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { - pr_err("wrong bio size\n"); + pkt_err(pd, "wrong bio size\n"); goto end_io; } @@ -2602,7 +2605,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) struct block_device *bdev; if (pd->pkt_dev == dev) { - pr_err("recursive setup not allowed\n"); + pkt_err(pd, "recursive setup not allowed\n"); return -EBUSY; } for (i = 0; i < MAX_WRITERS; i++) { @@ -2610,11 +2613,12 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) if (!pd2) continue; if (pd2->bdev->bd_dev == dev) { - pr_err("%s already setup\n", bdevname(pd2->bdev, b)); + pkt_err(pd, "%s already setup\n", + bdevname(pd2->bdev, b)); return -EBUSY; } if (pd2->pkt_dev == dev) { - pr_err("can't chain pktcdvd devices\n"); + pkt_err(pd, "can't chain pktcdvd devices\n"); return -EBUSY; } } @@ -2637,7 +2641,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) atomic_set(&pd->cdrw.pending_bios, 0); pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); if (IS_ERR(pd->cdrw.thread)) { - pr_err("can't start kernel thread\n"); + pkt_err(pd, "can't start kernel thread\n"); ret = -ENOMEM; goto out_mem; } -- cgit v1.2.3 From ca73dabc3d1df4aaacb242b6d4e39cd36618444f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:56 -0700 Subject: pktcdvd: convert pr_notice to pkt_notice Add a new pkt_notice macro to prefix the name to the logging output. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 3dbe42fe1bdd..136a04c3a07a 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -73,6 +73,8 @@ #define pkt_err(pd, fmt, ...) \ pr_err("%s: " fmt, pd->name, ##__VA_ARGS__) +#define pkt_notice(pd, fmt, ...) \ + pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__) #define pkt_dbg(level, pd, fmt, ...) \ do { \ @@ -1818,7 +1820,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) * but i'm not sure, should we leave this to user apps? probably. */ if (di->disc_type == 0xff) { - pr_notice("unknown disc - no track?\n"); + pkt_notice(pd, "unknown disc - no track?\n"); return 0; } @@ -1828,7 +1830,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di) } if (di->erasable == 0) { - pr_notice("disc not erasable\n"); + pkt_notice(pd, "disc not erasable\n"); return 0; } @@ -1884,7 +1886,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) */ pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; if (pd->settings.size == 0) { - pr_notice("detected zero packet size!\n"); + pkt_notice(pd, "detected zero packet size!\n"); return -ENXIO; } if (pd->settings.size > PACKET_MAX_SECTORS) { @@ -1967,7 +1969,7 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, pkt_err(pd, "write caching control failed\n"); pkt_dump_sense(&cgc); } else if (!ret && set) - pr_notice("enabled write caching on %s\n", pd->name); + pkt_notice(pd, "enabled write caching\n"); return ret; } @@ -2082,11 +2084,11 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, } if (!(buf[6] & 0x40)) { - pr_notice("disc type is not CD-RW\n"); + pkt_notice(pd, "disc type is not CD-RW\n"); return 1; } if (!(buf[6] & 0x4)) { - pr_notice("A1 values on media are not valid, maybe not CDRW?\n"); + pkt_notice(pd, "A1 values on media are not valid, maybe not CDRW?\n"); return 1; } @@ -2106,14 +2108,14 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, *speed = us_clv_to_speed[sp]; break; default: - pr_notice("unknown disc sub-type %d\n", st); + pkt_notice(pd, "unknown disc sub-type %d\n", st); return 1; } if (*speed) { pr_info("maximum media speed: %d\n", *speed); return 0; } else { - pr_notice("unknown speed %d for sub-type %d\n", sp, st); + pkt_notice(pd, "unknown speed %d for sub-type %d\n", sp, st); return 1; } } @@ -2378,8 +2380,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) } if (!test_bit(PACKET_WRITABLE, &pd->flags)) { - pr_notice("WRITE for ro device %s (%llu)\n", - pd->name, (unsigned long long)bio->bi_sector); + pkt_notice(pd, "WRITE for ro device (%llu)\n", + (unsigned long long)bio->bi_sector); goto end_io; } -- cgit v1.2.3 From 0c075d64df3aa9636a8700a710a2f2ada5e453a2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:57 -0700 Subject: pktcdvd: convert pr_info to pkt_info Add a new pkt_info macro to prefix the name to the logging output. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 136a04c3a07a..1ceafb70fc16 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -75,6 +75,8 @@ pr_err("%s: " fmt, pd->name, ##__VA_ARGS__) #define pkt_notice(pd, fmt, ...) \ pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__) +#define pkt_info(pd, fmt, ...) \ + pr_info("%s: " fmt, pd->name, ##__VA_ARGS__) #define pkt_dbg(level, pd, fmt, ...) \ do { \ @@ -1561,10 +1563,10 @@ work_to_do: static void pkt_print_settings(struct pktcdvd_device *pd) { - pr_info("%s packets, %u blocks, Mode-%c disc\n", - pd->settings.fp ? "Fixed" : "Variable", - pd->settings.size >> 2, - pd->settings.block_mode == 8 ? '1' : '2'); + pkt_info(pd, "%s packets, %u blocks, Mode-%c disc\n", + pd->settings.fp ? "Fixed" : "Variable", + pd->settings.size >> 2, + pd->settings.block_mode == 8 ? '1' : '2'); } static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control) @@ -2112,7 +2114,7 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, return 1; } if (*speed) { - pr_info("maximum media speed: %d\n", *speed); + pkt_info(pd, "maximum media speed: %d\n", *speed); return 0; } else { pkt_notice(pd, "unknown speed %d for sub-type %d\n", sp, st); @@ -2239,7 +2241,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write) ret = -ENOMEM; goto out_putdev; } - pr_info("%lukB available on disc\n", lba << 1); + pkt_info(pd, "%lukB available on disc\n", lba << 1); } return 0; -- cgit v1.2.3 From f3ded788bbd95af344a34ae40d1ab578cb76c7fb Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:58 -0700 Subject: pktcdvd: add struct pktcdvd_device * to pkt_dump_sense() Allow the device name to be emitted with pkt_err when logging the sense data. Signed-off-by: Joe Perches Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 1ceafb70fc16..29a5194ab147 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -755,17 +755,18 @@ static const char *sense_key_string(__u8 index) * A generic sense dump / resolve mechanism should be implemented across * all ATAPI + SCSI devices. */ -static void pkt_dump_sense(struct packet_command *cgc) +static void pkt_dump_sense(struct pktcdvd_device *pd, + struct packet_command *cgc) { struct request_sense *sense = cgc->sense; if (sense) - pr_err("%*ph - sense %02x.%02x.%02x (%s)\n", - CDROM_PACKET_SIZE, cgc->cmd, - sense->sense_key, sense->asc, sense->ascq, - sense_key_string(sense->sense_key)); + pkt_err(pd, "%*ph - sense %02x.%02x.%02x (%s)\n", + CDROM_PACKET_SIZE, cgc->cmd, + sense->sense_key, sense->asc, sense->ascq, + sense_key_string(sense->sense_key)); else - pr_err("%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd); + pkt_err(pd, "%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd); } /* @@ -808,7 +809,7 @@ static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd, cgc.cmd[5] = write_speed & 0xff; if ((ret = pkt_generic_packet(pd, &cgc))) - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } @@ -1700,7 +1701,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ); cgc.sense = &sense; if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } @@ -1715,7 +1716,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ); cgc.sense = &sense; if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } @@ -1757,7 +1758,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd) cgc.buflen = cgc.cmd[8] = size; if ((ret = pkt_mode_select(pd, &cgc))) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } @@ -1969,7 +1970,7 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, ret = pkt_mode_select(pd, &cgc); if (ret) { pkt_err(pd, "write caching control failed\n"); - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); } else if (!ret && set) pkt_notice(pd, "enabled write caching\n"); return ret; @@ -2007,7 +2008,7 @@ static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd, sizeof(struct mode_page_header); ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); if (ret) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } } @@ -2066,7 +2067,7 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, cgc.cmd[8] = 2; ret = pkt_generic_packet(pd, &cgc); if (ret) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } size = ((unsigned int) buf[0]<<8) + buf[1] + 2; @@ -2081,7 +2082,7 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd, cgc.cmd[8] = size; ret = pkt_generic_packet(pd, &cgc); if (ret) { - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } @@ -2136,7 +2137,7 @@ static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd) cgc.cmd[0] = GPCMD_SEND_OPC; cgc.cmd[1] = 1; if ((ret = pkt_generic_packet(pd, &cgc))) - pkt_dump_sense(&cgc); + pkt_dump_sense(pd, &cgc); return ret; } -- cgit v1.2.3 From 666dc7c90ab2531f7f0f13ef21afab8cd61478a9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Sep 2013 14:25:59 -0700 Subject: pktcdvd: fix defective misuses of pkt_ Fix thinkos where pkt_ needs a valid pktcdvd_device * and the pointer is known to be NULL. Signed-off-by: Joe Perches Reported-by: Dan Carpenter (go smatch!) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/pktcdvd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 29a5194ab147..56188475cfd3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2360,8 +2360,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) pd = q->queuedata; if (!pd) { - pkt_err(pd, "%s incorrect request queue\n", - bdevname(bio->bi_bdev, b)); + pr_err("%s incorrect request queue\n", + bdevname(bio->bi_bdev, b)); goto end_io; } @@ -2841,7 +2841,7 @@ static int pkt_remove_dev(dev_t pkt_dev) break; } if (idx == MAX_WRITERS) { - pkt_dbg(1, pd, "dev not setup\n"); + pr_debug("dev not setup\n"); ret = -ENXIO; goto out; } -- cgit v1.2.3 From 0244ad004a54e39308d495fee0a2e637f8b5c317 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 30 Aug 2013 09:39:53 +0200 Subject: Remove GENERIC_HARDIRQ config option After the last architecture switched to generic hard irqs the config options HAVE_GENERIC_HARDIRQS & GENERIC_HARDIRQS and the related code for !CONFIG_GENERIC_HARDIRQS can be removed. Signed-off-by: Martin Schwidefsky --- arch/alpha/Kconfig | 1 - arch/arc/Kconfig | 1 - arch/arm/Kconfig | 1 - arch/arm64/Kconfig | 1 - arch/avr32/Kconfig | 1 - arch/blackfin/Kconfig | 1 - arch/c6x/Kconfig | 1 - arch/cris/Kconfig | 1 - arch/frv/Kconfig | 1 - arch/h8300/Kconfig | 1 - arch/hexagon/Kconfig | 1 - arch/ia64/Kconfig | 1 - arch/m32r/Kconfig | 1 - arch/m68k/Kconfig | 1 - arch/metag/Kconfig | 1 - arch/microblaze/Kconfig | 1 - arch/mips/Kconfig | 1 - arch/mn10300/Kconfig | 1 - arch/openrisc/Kconfig | 1 - arch/parisc/Kconfig | 1 - arch/powerpc/Kconfig | 1 - arch/s390/Kconfig | 1 - arch/score/Kconfig | 1 - arch/sh/Kconfig | 1 - arch/sparc/Kconfig | 1 - arch/tile/Kconfig | 1 - arch/um/Kconfig.common | 1 - arch/um/defconfig | 2 - arch/unicore32/Kconfig | 1 - arch/x86/Kconfig | 1 - arch/xtensa/Kconfig | 1 - arch/xtensa/configs/common_defconfig | 1 - arch/xtensa/configs/iss_defconfig | 1 - arch/xtensa/configs/s6105_defconfig | 1 - drivers/block/mtip32xx/Kconfig | 2 +- drivers/char/random.c | 5 +- drivers/dma/dw/Kconfig | 1 - drivers/gpio/Kconfig | 6 +- drivers/hid/Kconfig | 2 +- drivers/i2c/Kconfig | 1 - drivers/i2c/busses/Kconfig | 6 +- drivers/iio/Kconfig | 1 - drivers/infiniband/hw/qib/Kconfig | 2 +- drivers/input/keyboard/Kconfig | 4 +- drivers/input/serio/Kconfig | 1 - drivers/input/touchscreen/Kconfig | 4 +- drivers/media/platform/Kconfig | 2 +- drivers/media/radio/Kconfig | 2 +- drivers/mfd/Kconfig | 126 ++++++++++++++++----------------- drivers/misc/cb710/Kconfig | 2 +- drivers/mmc/host/Kconfig | 2 +- drivers/net/ethernet/cadence/Kconfig | 2 +- drivers/net/wireless/p54/Kconfig | 2 +- drivers/net/wireless/ti/wl1251/Kconfig | 2 +- drivers/net/wireless/ti/wlcore/Kconfig | 2 +- drivers/pci/msi.c | 22 ------ drivers/power/Kconfig | 3 +- drivers/pps/clients/Kconfig | 2 +- drivers/spi/Kconfig | 3 +- drivers/tty/serial/Kconfig | 2 +- drivers/usb/dwc3/Kconfig | 2 +- drivers/usb/gadget/Kconfig | 4 +- drivers/usb/host/Kconfig | 1 - drivers/usb/musb/Kconfig | 1 - drivers/usb/renesas_usbhs/Kconfig | 2 +- drivers/w1/masters/Kconfig | 2 +- include/linux/cpu_rmap.h | 3 - include/linux/hardirq.h | 4 -- include/linux/interrupt.h | 75 +------------------- include/linux/irq.h | 9 --- include/linux/irqdesc.h | 3 - include/linux/irqnr.h | 19 ----- include/linux/kernel_stat.h | 34 --------- kernel/Makefile | 2 +- kernel/irq/Kconfig | 12 ---- kernel/softirq.c | 2 - lib/Kconfig.debug | 2 +- lib/cpu_rmap.c | 6 -- net/Kconfig | 2 +- sound/soc/codecs/Kconfig | 2 +- sound/soc/samsung/Kconfig | 6 +- 81 files changed, 100 insertions(+), 337 deletions(-) (limited to 'drivers/block') diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 082d9b4b5472..35a300d4a9fb 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -7,7 +7,6 @@ config ALPHA select HAVE_PCSPKR_PLATFORM select HAVE_PERF_EVENTS select HAVE_DMA_ATTRS - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_PROBE select AUTO_IRQ_AFFINITY if SMP diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 68fcbb2d59e2..91dbb2757afd 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -20,7 +20,6 @@ config ARC select GENERIC_SMP_IDLE_THREAD select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK - select HAVE_GENERIC_HARDIRQS select HAVE_IOREMAP_PROT select HAVE_KPROBES select HAVE_KRETPROBES diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d13f6743df4b..3f7714d8d2d2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -37,7 +37,6 @@ config ARM select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) select HAVE_GENERIC_DMA_COHERENT - select HAVE_GENERIC_HARDIRQS select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_IRQ_TIME_ACCOUNTING diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ae323a45c28c..c04454876bcb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -23,7 +23,6 @@ config ARM64 select HAVE_DMA_API_DEBUG select HAVE_DMA_ATTRS select HAVE_GENERIC_DMA_COHERENT - select HAVE_GENERIC_HARDIRQS select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_MEMBLOCK select HAVE_PERF_EVENTS diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 549903cfc2cb..b6878eb64884 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -6,7 +6,6 @@ config AVR32 select HAVE_CLK select HAVE_OPROFILE select HAVE_KPROBES - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_PROBE select GENERIC_ATOMIC64 diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 3b6abc54b015..f78c9a2c7e28 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -32,7 +32,6 @@ config BLACKFIN select HAVE_UNDERSCORE_SYMBOL_PREFIX select VIRT_TO_BUS select ARCH_WANT_IPC_PARSE_VERSION - select HAVE_GENERIC_HARDIRQS select GENERIC_ATOMIC64 select GENERIC_IRQ_PROBE select USE_GENERIC_SMP_HELPERS if SMP diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index f6a3648f5ec3..957dd00ea561 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -10,7 +10,6 @@ config C6X select GENERIC_IRQ_SHOW select HAVE_ARCH_TRACEHOOK select HAVE_DMA_API_DEBUG - select HAVE_GENERIC_HARDIRQS select HAVE_MEMBLOCK select SPARSE_IRQ select IRQ_DOMAIN diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index c699d3259872..02380bed189c 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -41,7 +41,6 @@ config CRIS default y select HAVE_IDE select GENERIC_ATOMIC64 - select HAVE_GENERIC_HARDIRQS select HAVE_UID16 select VIRT_TO_BUS select ARCH_WANT_IPC_PARSE_VERSION diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 4b6628ea381e..34aa19352dc1 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -5,7 +5,6 @@ config FRV select HAVE_ARCH_TRACEHOOK select HAVE_PERF_EVENTS select HAVE_UID16 - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_SHOW select HAVE_DEBUG_BUGVERBOSE diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 3d6759ee382f..24b1dc2564f1 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -2,7 +2,6 @@ config H8300 bool default y select HAVE_IDE - select HAVE_GENERIC_HARDIRQS select GENERIC_ATOMIC64 select HAVE_UID16 select VIRT_TO_BUS diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index 77d442ab28c8..99041b07e610 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig @@ -15,7 +15,6 @@ config HEXAGON # select GENERIC_PENDING_IRQ if SMP select GENERIC_ATOMIC64 select HAVE_PERF_EVENTS - select HAVE_GENERIC_HARDIRQS # GENERIC_ALLOCATOR is used by dma_alloc_coherent() select GENERIC_ALLOCATOR select GENERIC_IRQ_SHOW diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index a86a56d9e73f..7740ab10a171 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -21,7 +21,6 @@ config IA64 select HAVE_KVM select HAVE_ARCH_TRACEHOOK select HAVE_DMA_API_DEBUG - select HAVE_GENERIC_HARDIRQS select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP select HAVE_VIRT_CPU_ACCOUNTING diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 29a7ef4e448b..75661fbf4529 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -9,7 +9,6 @@ config M32R select HAVE_KERNEL_LZMA select ARCH_WANT_IPC_PARSE_VERSION select HAVE_DEBUG_BUGVERBOSE - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index c3cda41af801..311a300d48cc 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -4,7 +4,6 @@ config M68K select HAVE_IDE select HAVE_AOUT if MMU select HAVE_DEBUG_BUGVERBOSE - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW select GENERIC_ATOMIC64 select HAVE_UID16 diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig index cfd831c29824..36368eb07e13 100644 --- a/arch/metag/Kconfig +++ b/arch/metag/Kconfig @@ -13,7 +13,6 @@ config METAG select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST - select HAVE_GENERIC_HARDIRQS select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 3f6659cbc969..b82f82b74319 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -18,7 +18,6 @@ config MICROBLAZE select ARCH_WANT_IPC_PARSE_VERSION select HAVE_DEBUG_KMEMLEAK select IRQ_DOMAIN - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a9668d4653c2..f75ab4a2f246 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -25,7 +25,6 @@ config MIPS select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_PCI_IOMAP diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 70e4f663ebd2..6aaa1607001a 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig @@ -1,7 +1,6 @@ config MN10300 def_bool y select HAVE_OPROFILE - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select HAVE_ARCH_TRACEHOOK diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index d60bf98fa5cf..9488209a5253 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -11,7 +11,6 @@ config OPENRISC select HAVE_MEMBLOCK select ARCH_REQUIRE_GPIOLIB select HAVE_ARCH_TRACEHOOK - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_CHIP select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index aa399a5259b6..ad2ce8dab996 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -14,7 +14,6 @@ config PARISC select HAVE_PERF_EVENTS select GENERIC_ATOMIC64 if !64BIT select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE - select HAVE_GENERIC_HARDIRQS select BROKEN_RODATA select GENERIC_IRQ_PROBE select GENERIC_PCI_IOMAP diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 6b7530f8183c..38f3b7e47ec5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -114,7 +114,6 @@ config PPC select HAVE_PERF_EVENTS select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 - select HAVE_GENERIC_HARDIRQS select ARCH_WANT_IPC_PARSE_VERSION select SPARSE_IRQ select IRQ_DOMAIN diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 3ec272859e1e..dcc6ac2d8026 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -116,7 +116,6 @@ config S390 select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST - select HAVE_GENERIC_HARDIRQS select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZ4 diff --git a/arch/score/Kconfig b/arch/score/Kconfig index 5fc237581caf..a1be70db75fe 100644 --- a/arch/score/Kconfig +++ b/arch/score/Kconfig @@ -2,7 +2,6 @@ menu "Machine selection" config SCORE def_bool y - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW select GENERIC_IOMAP select GENERIC_ATOMIC64 diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 1018ed3a3ca5..224f4bc9925e 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -26,7 +26,6 @@ config SUPERH select ARCH_WANT_IPC_PARSE_VERSION select HAVE_SYSCALL_TRACEPOINTS select HAVE_REGS_AND_STACK_ACCESS_API - select HAVE_GENERIC_HARDIRQS select MAY_HAVE_SPARSE_IRQ select IRQ_FORCED_THREADING select RTC_LIB diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 1570ad2802b3..2137ad667438 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -26,7 +26,6 @@ config SPARC select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select HAVE_ARCH_JUMP_LABEL - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW select ARCH_WANT_IPC_PARSE_VERSION select USE_GENERIC_SMP_HELPERS if SMP diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 932fa14de5fe..8a7cc663b3f8 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -11,7 +11,6 @@ config TILE select USE_GENERIC_SMP_HELPERS select CC_OPTIMIZE_FOR_SIZE select HAVE_DEBUG_KMEMLEAK - select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE select GENERIC_PENDING_IRQ if SMP select GENERIC_IRQ_SHOW diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common index bceee6623b00..8ddea1f8006a 100644 --- a/arch/um/Kconfig.common +++ b/arch/um/Kconfig.common @@ -6,7 +6,6 @@ config DEFCONFIG_LIST config UML bool default y - select HAVE_GENERIC_HARDIRQS select HAVE_UID16 select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES diff --git a/arch/um/defconfig b/arch/um/defconfig index 08107a795062..2665e6b683f5 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -129,12 +129,10 @@ CONFIG_BSD_PROCESS_ACCT=y # CONFIG_FHANDLE is not set # CONFIG_TASKSTATS is not set # CONFIG_AUDIT is not set -CONFIG_HAVE_GENERIC_HARDIRQS=y # # IRQ subsystem # -CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_SHOW=y # diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig index 41bcc0013442..82cdd8906f3d 100644 --- a/arch/unicore32/Kconfig +++ b/arch/unicore32/Kconfig @@ -2,7 +2,6 @@ config UNICORE32 def_bool y select HAVE_MEMBLOCK select HAVE_GENERIC_DMA_COHERENT - select HAVE_GENERIC_HARDIRQS select HAVE_DMA_ATTRS select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 30c40f08a3d4..e241a1930c98 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -82,7 +82,6 @@ config X86 select HAVE_USER_RETURN_NOTIFIER select ARCH_BINFMT_ELF_RANDOMIZE_PIE select HAVE_ARCH_JUMP_LABEL - select HAVE_GENERIC_HARDIRQS select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select SPARSE_IRQ select GENERIC_FIND_FIRST_BIT diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 7ea6451a3a33..8d24dcb7cdac 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -7,7 +7,6 @@ config XTENSA select HAVE_IDE select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS - select HAVE_GENERIC_HARDIRQS select VIRT_TO_BUS select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig index a182a4e6d688..f6000fe05119 100644 --- a/arch/xtensa/configs/common_defconfig +++ b/arch/xtensa/configs/common_defconfig @@ -8,7 +8,6 @@ CONFIG_XTENSA=y # CONFIG_UID16 is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_HAVE_DEC_LOCK=y -CONFIG_GENERIC_HARDIRQS=y # # Code maturity level options diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig index 77c52f80187a..4f233204faf9 100644 --- a/arch/xtensa/configs/iss_defconfig +++ b/arch/xtensa/configs/iss_defconfig @@ -9,7 +9,6 @@ CONFIG_XTENSA=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_HARDIRQS=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_NO_IOPORT=y diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig index 4799c6a526b5..d929f77a0360 100644 --- a/arch/xtensa/configs/s6105_defconfig +++ b/arch/xtensa/configs/s6105_defconfig @@ -9,7 +9,6 @@ CONFIG_XTENSA=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_HARDIRQS=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_NO_IOPORT=y diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig index 1fca1f996b45..0ba837fc62a8 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 PCI && GENERIC_HARDIRQS + depends on PCI help This enables the block driver for Micron PCIe SSDs. diff --git a/drivers/char/random.c b/drivers/char/random.c index 0d91fe52f3f5..7737b5bd26af 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -255,10 +255,7 @@ #include #include #include - -#ifdef CONFIG_GENERIC_HARDIRQS -# include -#endif +#include #include #include diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig index dde13248b681..dcfe964cc8dc 100644 --- a/drivers/dma/dw/Kconfig +++ b/drivers/dma/dw/Kconfig @@ -4,7 +4,6 @@ config DW_DMAC_CORE tristate "Synopsys DesignWare AHB DMA support" - depends on GENERIC_HARDIRQS select DMA_ENGINE config DW_DMAC diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cb218151c9c..b6ed304863eb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -322,7 +322,7 @@ config GPIO_ICH config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE select MFD_VX855 help @@ -396,7 +396,7 @@ config GPIO_MAX732X config GPIO_MAX732X_IRQ bool "Interrupt controller support for MAX732x" - depends on GPIO_MAX732X=y && GENERIC_HARDIRQS + depends on GPIO_MAX732X=y help Say yes here to enable the max732x to be used as an interrupt controller. It requires the driver to be built in the kernel. @@ -661,7 +661,7 @@ config GPIO_TIMBERDALE config GPIO_RDC321X tristate "RDC R-321x GPIO support" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE select MFD_RDC321X help diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3d7c9f67b6d7..71b70e3a7a71 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -773,7 +773,7 @@ config HID_ZYDACRON config HID_SENSOR_HUB tristate "HID Sensors framework support" - depends on HID && GENERIC_HARDIRQS + depends on HID select MFD_CORE default n ---help--- diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index e380c6eef3af..7b7ea320a258 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -75,7 +75,6 @@ config I2C_HELPER_AUTO config I2C_SMBUS tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO - depends on GENERIC_HARDIRQS help Say Y here if you want support for SMBus extensions to the I2C specification. At the moment, the only supported extension is diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index fcdd321f709e..cdcbd8368ed3 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -115,7 +115,7 @@ config I2C_I801 config I2C_ISCH tristate "Intel SCH SMBus 1.0" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select LPC_SCH help Say Y here if you want to use SMBus controller on the Intel SCH @@ -546,7 +546,6 @@ config I2C_NUC900 config I2C_OCORES tristate "OpenCores I2C Controller" - depends on GENERIC_HARDIRQS help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see @@ -791,7 +790,7 @@ config I2C_DIOLAN_U2C config I2C_PARPORT tristate "Parallel port adapter" - depends on PARPORT && GENERIC_HARDIRQS + depends on PARPORT select I2C_ALGOBIT select I2C_SMBUS help @@ -816,7 +815,6 @@ config I2C_PARPORT config I2C_PARPORT_LIGHT tristate "Parallel port adapter (light)" - depends on GENERIC_HARDIRQS select I2C_ALGOBIT select I2C_SMBUS help diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index cbea3271c1b1..90cf0cda50c4 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -4,7 +4,6 @@ menuconfig IIO tristate "Industrial I/O support" - depends on GENERIC_HARDIRQS help The industrial I/O subsystem provides a unified framework for drivers for many different types of embedded sensors using a diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig index d03ca4c1ff25..495be09781b1 100644 --- a/drivers/infiniband/hw/qib/Kconfig +++ b/drivers/infiniband/hw/qib/Kconfig @@ -8,7 +8,7 @@ config INFINIBAND_QIB config INFINIBAND_QIB_DCA bool "QIB DCA support" - depends on INFINIBAND_QIB && DCA && SMP && GENERIC_HARDIRQS && !(INFINIBAND_QIB=y && DCA=m) + depends on INFINIBAND_QIB && DCA && SMP && !(INFINIBAND_QIB=y && DCA=m) default y ---help--- Setting this enables DCA support on some Intel chip sets diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 269d4c3658cb..c1edd39bc5ba 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -224,7 +224,7 @@ config KEYBOARD_TCA6416 config KEYBOARD_TCA8418 tristate "TCA8418 Keypad Support" - depends on I2C && GENERIC_HARDIRQS + depends on I2C select INPUT_MATRIXKMAP help This driver implements basic keypad functionality @@ -303,7 +303,7 @@ config KEYBOARD_HP7XX config KEYBOARD_LM8323 tristate "LM8323 keypad chip" - depends on I2C && GENERIC_HARDIRQS + depends on I2C depends on LEDS_CLASS help If you say yes here you get support for the National Semiconductor diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 1e691a3a79cb..33b3e88fe4a2 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -239,7 +239,6 @@ config SERIO_PS2MULT config SERIO_ARC_PS2 tristate "ARC PS/2 support" - depends on GENERIC_HARDIRQS help Say Y here if you have an ARC FPGA platform with a PS/2 controller in it. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 3b9758b5f4d7..e09ec67957a3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -389,7 +389,7 @@ config TOUCHSCREEN_MCS5000 config TOUCHSCREEN_MMS114 tristate "MELFAS MMS114 touchscreen" - depends on I2C && GENERIC_HARDIRQS + depends on I2C help Say Y here if you have the MELFAS MMS114 touchscreen controller chip in your system. @@ -845,7 +845,7 @@ config TOUCHSCREEN_TSC_SERIO config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" - depends on SPI_MASTER && GENERIC_HARDIRQS + depends on SPI_MASTER help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 8068d7b64155..c7caf94621b4 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -203,7 +203,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" - depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS && HAS_DMA + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 39882ddd2594..6ecdc39bb366 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -214,7 +214,7 @@ config RADIO_TIMBERDALE config RADIO_WL1273 tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 && GENERIC_HARDIRQS + depends on I2C && VIDEO_V4L2 select MFD_CORE select MFD_WL1273_CORE select FW_LOADER diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e0e46f50f95d..914c3d142f78 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -23,7 +23,7 @@ config MFD_AS3711 select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help Support for the AS3711 PMIC from AMS @@ -40,7 +40,7 @@ config PMIC_ADP5520 config MFD_AAT2870_CORE bool "AnalogicTech AAT2870" select MFD_CORE - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + depends on I2C=y && GPIOLIB help If you say yes here you get support for the AAT2870. This driver provides common support for accessing the device, @@ -78,7 +78,7 @@ config MFD_CROS_EC_SPI config MFD_ASIC3 bool "Compaq ASIC3" - depends on GENERIC_HARDIRQS && GPIOLIB && ARM + depends on GPIOLIB && ARM select MFD_CORE ---help--- This driver supports the ASIC3 multifunction chip found on many @@ -104,7 +104,7 @@ config MFD_DA9052_SPI select REGMAP_SPI select REGMAP_IRQ select PMIC_DA9052 - depends on SPI_MASTER=y && GENERIC_HARDIRQS + depends on SPI_MASTER=y help Support for the Dialog Semiconductor DA9052 PMIC when controlled using SPI. This driver provides common support @@ -116,7 +116,7 @@ config MFD_DA9052_I2C select REGMAP_I2C select REGMAP_IRQ select PMIC_DA9052 - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help Support for the Dialog Semiconductor DA9052 PMIC when controlled using I2C. This driver provides common support @@ -128,7 +128,7 @@ config MFD_DA9055 select REGMAP_I2C select REGMAP_IRQ select MFD_CORE - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help Say yes here for support of Dialog Semiconductor DA9055. This is a Power Management IC. This driver provides common support for @@ -144,7 +144,7 @@ config MFD_DA9063 select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help Say yes here for support for the Dialog Semiconductor DA9063 PMIC. This includes the I2C driver and core APIs. @@ -156,7 +156,7 @@ config MFD_MC13783 config MFD_MC13XXX tristate - depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS + depends on (SPI_MASTER || I2C) select MFD_CORE select MFD_MC13783 help @@ -167,7 +167,7 @@ config MFD_MC13XXX config MFD_MC13XXX_SPI tristate "Freescale MC13783 and MC13892 SPI interface" - depends on SPI_MASTER && GENERIC_HARDIRQS + depends on SPI_MASTER select REGMAP_SPI select MFD_MC13XXX help @@ -175,7 +175,7 @@ config MFD_MC13XXX_SPI config MFD_MC13XXX_I2C tristate "Freescale MC13892 I2C interface" - depends on I2C && GENERIC_HARDIRQS + depends on I2C select REGMAP_I2C select MFD_MC13XXX help @@ -183,7 +183,7 @@ config MFD_MC13XXX_I2C config HTC_EGPIO bool "HTC EGPIO support" - depends on GENERIC_HARDIRQS && GPIOLIB && ARM + depends on GPIOLIB && ARM help This driver supports the CPLD egpio chip present on several HTC phones. It provides basic support for input @@ -192,7 +192,6 @@ config HTC_EGPIO config HTC_PASIC3 tristate "HTC PASIC3 LED/DS1WM chip support" select MFD_CORE - depends on GENERIC_HARDIRQS help This core driver provides register access for the LED/DS1WM chips labeled "AIC2" and "AIC3", found on HTC Blueangel and @@ -210,7 +209,7 @@ config HTC_I2CPLD config LPC_ICH tristate "Intel ICH LPC" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE help The LPC bridge function of the Intel ICH provides support for @@ -220,7 +219,7 @@ config LPC_ICH config LPC_SCH tristate "Intel SCH LPC" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE help LPC bridge function of the Intel SCH provides support for @@ -238,7 +237,7 @@ config MFD_INTEL_MSIC config MFD_JANZ_CMODIO tristate "Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE - depends on PCI && GENERIC_HARDIRQS + depends on PCI help This is the core driver for the Janz CMOD-IO PCI MODULbus carrier board. This device is a PCI to MODULbus bridge which may @@ -277,7 +276,7 @@ config MFD_KEMPLD config MFD_88PM800 tristate "Marvell 88PM800" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select REGMAP_I2C select REGMAP_IRQ select MFD_CORE @@ -289,7 +288,7 @@ config MFD_88PM800 config MFD_88PM805 tristate "Marvell 88PM805" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select REGMAP_I2C select REGMAP_IRQ select MFD_CORE @@ -301,7 +300,7 @@ config MFD_88PM805 config MFD_88PM860X bool "Marvell 88PM8606/88PM8607" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select REGMAP_I2C select MFD_CORE help @@ -312,7 +311,7 @@ config MFD_88PM860X config MFD_MAX77686 bool "Maxim Semiconductor MAX77686 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select IRQ_DOMAIN @@ -325,7 +324,7 @@ config MFD_MAX77686 config MFD_MAX77693 bool "Maxim Semiconductor MAX77693 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C help @@ -339,7 +338,7 @@ config MFD_MAX77693 config MFD_MAX8907 tristate "Maxim Semiconductor MAX8907 PMIC Support" select MFD_CORE - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select REGMAP_I2C select REGMAP_IRQ help @@ -350,7 +349,7 @@ config MFD_MAX8907 config MFD_MAX8925 bool "Maxim Semiconductor MAX8925 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE help Say yes here to support for Maxim Semiconductor MAX8925. This is @@ -360,7 +359,7 @@ config MFD_MAX8925 config MFD_MAX8997 bool "Maxim Semiconductor MAX8997/8966 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select IRQ_DOMAIN help @@ -373,7 +372,7 @@ config MFD_MAX8997 config MFD_MAX8998 bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select IRQ_DOMAIN help @@ -385,7 +384,7 @@ config MFD_MAX8998 config EZX_PCAP bool "Motorola EZXPCAP Support" - depends on GENERIC_HARDIRQS && SPI_MASTER + depends on SPI_MASTER help This enables the PCAP ASIC present on EZX Phones. This is needed for MMC, TouchScreen, Sound, USB, etc.. @@ -393,7 +392,7 @@ config EZX_PCAP config MFD_VIPERBOARD tristate "Nano River Technologies Viperboard" select MFD_CORE - depends on USB && GENERIC_HARDIRQS + depends on USB default n help Say yes here if you want support for Nano River Technologies @@ -407,7 +406,7 @@ config MFD_VIPERBOARD config MFD_RETU tristate "Nokia Retu and Tahvo multi-function device" select MFD_CORE - depends on I2C && GENERIC_HARDIRQS + depends on I2C select REGMAP_IRQ help Retu and Tahvo are a multi-function devices found on Nokia @@ -480,7 +479,7 @@ config MFD_PM8XXX_IRQ config MFD_RDC321X tristate "RDC R-321x southbridge" select MFD_CORE - depends on PCI && GENERIC_HARDIRQS + depends on PCI help Say yes here if you want to have support for the RDC R-321x SoC southbridge which provides access to GPIOs and Watchdog using the @@ -488,7 +487,7 @@ config MFD_RDC321X config MFD_RTSX_PCI tristate "Realtek PCI-E card reader" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE help This supports for Realtek PCI-Express card reader including rts5209, @@ -498,7 +497,7 @@ config MFD_RTSX_PCI config MFD_RC5T583 bool "Ricoh RC5T583 Power Management system device" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C help @@ -512,7 +511,7 @@ config MFD_RC5T583 config MFD_SEC_CORE bool "SAMSUNG Electronics PMIC Series Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -555,7 +554,7 @@ config MFD_SM501_GPIO config MFD_SMSC bool "SMSC ECE1099 series chips" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C help @@ -577,7 +576,7 @@ config ABX500_CORE config AB3100_CORE bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS + depends on I2C=y && ABX500_CORE select MFD_CORE default y if ARCH_U300 help @@ -601,7 +600,7 @@ config AB3100_OTP config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU + depends on ABX500_CORE && MFD_DB8500_PRCMU select POWER_SUPPLY select MFD_CORE select IRQ_DOMAIN @@ -639,7 +638,7 @@ config MFD_DB8500_PRCMU config MFD_STMPE bool "STMicroelectronics STMPE" - depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS + depends on (I2C=y || SPI_MASTER=y) select MFD_CORE help Support for the STMPE family of I/O Expanders from @@ -680,7 +679,7 @@ endmenu config MFD_STA2X11 bool "STMicroelectronics STA2X11" - depends on STA2X11 && GENERIC_HARDIRQS + depends on STA2X11 select MFD_CORE select REGMAP_MMIO @@ -700,7 +699,6 @@ config MFD_TI_AM335X_TSCADC select MFD_CORE select REGMAP select REGMAP_MMIO - depends on GENERIC_HARDIRQS help If you say yes here you get support for Texas Instruments series of Touch Screen /ADC chips. @@ -717,7 +715,7 @@ config MFD_DM355EVM_MSP config MFD_LP8788 bool "TI LP8788 Power Management Unit Driver" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select IRQ_DOMAIN @@ -739,14 +737,14 @@ config MFD_PALMAS select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help If you say yes here you get support for the Palmas series of PMIC chips from Texas Instruments. config MFD_TI_SSP tristate "TI Sequencer Serial Port support" - depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS + depends on ARCH_DAVINCI_TNETV107X select MFD_CORE ---help--- Say Y here if you want support for the Sequencer Serial Port @@ -761,7 +759,6 @@ config TPS6105X select REGULATOR select MFD_CORE select REGULATOR_FIXED_VOLTAGE - depends on GENERIC_HARDIRQS help This option enables a driver for the TP61050/TPS61052 high-power "white LED driver". This boost converter is @@ -784,7 +781,7 @@ config TPS65010 config TPS6507X tristate "TI TPS6507x Power Management / Touch Screen chips" select MFD_CORE - depends on I2C && GENERIC_HARDIRQS + depends on I2C help If you say yes here you get support for the TPS6507x series of Power Management / Touch Screen chips. These include voltage @@ -798,7 +795,7 @@ config TPS65911_COMPARATOR config MFD_TPS65090 bool "TI TPS65090 Power Management chips" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -811,7 +808,7 @@ config MFD_TPS65090 config MFD_TPS65217 tristate "TI TPS65217 Power Management / White LED chips" - depends on I2C && GENERIC_HARDIRQS + depends on I2C select MFD_CORE select REGMAP_I2C help @@ -826,7 +823,7 @@ config MFD_TPS65217 config MFD_TPS6586X bool "TI TPS6586x Power Management chips" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C help @@ -841,7 +838,7 @@ config MFD_TPS6586X config MFD_TPS65910 bool "TI TPS65910 Power Management chip" - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + depends on I2C=y && GPIOLIB select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -862,7 +859,7 @@ config MFD_TPS65912_I2C bool "TI TPS65912 Power Management chip with I2C" select MFD_CORE select MFD_TPS65912 - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + depends on I2C=y && GPIOLIB help If you say yes here you get support for the TPS65912 series of PM chips with I2C interface. @@ -871,14 +868,14 @@ config MFD_TPS65912_SPI bool "TI TPS65912 Power Management chip with SPI" select MFD_CORE select MFD_TPS65912 - depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS + depends on SPI_MASTER && GPIOLIB help If you say yes here you get support for the TPS65912 series of PM chips with SPI interface. config MFD_TPS80031 bool "TI TPS80031/TPS80032 Power Management chips" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -892,7 +889,7 @@ config MFD_TPS80031 config TWL4030_CORE bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select IRQ_DOMAIN select REGMAP_I2C help @@ -931,13 +928,13 @@ config TWL4030_POWER config MFD_TWL4030_AUDIO bool "TI TWL4030 Audio" - depends on TWL4030_CORE && GENERIC_HARDIRQS + depends on TWL4030_CORE select MFD_CORE default n config TWL6040_CORE bool "TI TWL6040 audio codec" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -961,7 +958,7 @@ config MENELAUS config MFD_WL1273_CORE tristate "TI WL1273 FM radio" - depends on I2C && GENERIC_HARDIRQS + depends on I2C select MFD_CORE default n help @@ -974,7 +971,6 @@ config MFD_LM3533 depends on I2C select MFD_CORE select REGMAP_I2C - depends on GENERIC_HARDIRQS help Say yes here to enable support for National Semiconductor / TI LM3533 Lighting Power chips. @@ -996,7 +992,7 @@ config MFD_TIMBERDALE config MFD_TC3589X bool "Toshiba TC35892 and variants" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_CORE help Support for the Toshiba TC35892 and variants I/O Expander. @@ -1011,7 +1007,7 @@ config MFD_TMIO config MFD_T7L66XB bool "Toshiba T7L66XB" - depends on ARM && HAVE_CLK && GENERIC_HARDIRQS + depends on ARM && HAVE_CLK select MFD_CORE select MFD_TMIO help @@ -1036,7 +1032,7 @@ config MFD_TC6393XB config MFD_VX855 tristate "VIA VX855/VX875 integrated south bridge" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select MFD_CORE help Say yes here to enable support for various functions of the @@ -1054,7 +1050,7 @@ config MFD_ARIZONA_I2C select MFD_ARIZONA select MFD_CORE select REGMAP_I2C - depends on I2C && GENERIC_HARDIRQS + depends on I2C help Support for the Wolfson Microelectronics Arizona platform audio SoC core functionality controlled via I2C. @@ -1064,7 +1060,7 @@ config MFD_ARIZONA_SPI select MFD_ARIZONA select MFD_CORE select REGMAP_SPI - depends on SPI_MASTER && GENERIC_HARDIRQS + depends on SPI_MASTER help Support for the Wolfson Microelectronics Arizona platform audio SoC core functionality controlled via I2C. @@ -1090,7 +1086,7 @@ config MFD_WM8997 config MFD_WM8400 bool "Wolfson Microelectronics WM8400" select MFD_CORE - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select REGMAP_I2C help Support for the Wolfson Microelecronics WM8400 PMIC and audio @@ -1100,7 +1096,6 @@ config MFD_WM8400 config MFD_WM831X bool - depends on GENERIC_HARDIRQS config MFD_WM831X_I2C bool "Wolfson Microelectronics WM831x/2x PMICs with I2C" @@ -1108,7 +1103,7 @@ config MFD_WM831X_I2C select MFD_WM831X select REGMAP_I2C select IRQ_DOMAIN - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help Support for the Wolfson Microelecronics WM831x and WM832x PMICs when controlled using I2C. This driver provides common support @@ -1121,7 +1116,7 @@ config MFD_WM831X_SPI select MFD_WM831X select REGMAP_SPI select IRQ_DOMAIN - depends on SPI_MASTER && GENERIC_HARDIRQS + depends on SPI_MASTER help Support for the Wolfson Microelecronics WM831x and WM832x PMICs when controlled using SPI. This driver provides common support @@ -1130,12 +1125,11 @@ config MFD_WM831X_SPI config MFD_WM8350 bool - depends on GENERIC_HARDIRQS config MFD_WM8350_I2C bool "Wolfson Microelectronics WM8350 with I2C" select MFD_WM8350 - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help The WM8350 is an integrated audio and power management subsystem with watchdog and RTC functionality for embedded @@ -1148,7 +1142,7 @@ config MFD_WM8994 select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y help The WM8994 is a highly integrated hi-fi CODEC designed for smartphone applicatiosn. As well as audio functionality it diff --git a/drivers/misc/cb710/Kconfig b/drivers/misc/cb710/Kconfig index 5acb9c5b49c4..22429b8b1068 100644 --- a/drivers/misc/cb710/Kconfig +++ b/drivers/misc/cb710/Kconfig @@ -1,6 +1,6 @@ config CB710_CORE tristate "ENE CB710/720 Flash memory card reader support" - depends on PCI && GENERIC_HARDIRQS + depends on PCI help This option enables support for PCI ENE CB710/720 Flash memory card reader found in some laptops (ie. some versions of HP Compaq nx9500). diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index b7fd5ab80a48..7fc5099e44b2 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -487,7 +487,7 @@ config MMC_SDHI config MMC_CB710 tristate "ENE CB710 MMC/SD Interface support" - depends on PCI && GENERIC_HARDIRQS + depends on PCI select CB710_CORE help This option enables support for MMC/SD part of ENE CB710/720 Flash diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 8030cc0396fd..751d5c7b312d 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -22,7 +22,7 @@ if NET_CADENCE config ARM_AT91_ETHER tristate "AT91RM9200 Ethernet support" - depends on GENERIC_HARDIRQS && HAS_DMA + depends on HAS_DMA select MACB ---help--- If you wish to compile a kernel for the AT91RM9200 and enable diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig index 15ea36b51a66..cdafb8c73e82 100644 --- a/drivers/net/wireless/p54/Kconfig +++ b/drivers/net/wireless/p54/Kconfig @@ -41,7 +41,7 @@ config P54_PCI config P54_SPI tristate "Prism54 SPI (stlc45xx) support" - depends on P54_COMMON && SPI_MASTER && GENERIC_HARDIRQS + depends on P54_COMMON && SPI_MASTER ---help--- This driver is for stlc4550 or stlc4560 based wireless chips such as Nokia's N800/N810 Portable Internet Tablet. diff --git a/drivers/net/wireless/ti/wl1251/Kconfig b/drivers/net/wireless/ti/wl1251/Kconfig index 8fec4ed36ac2..477a206c098e 100644 --- a/drivers/net/wireless/ti/wl1251/Kconfig +++ b/drivers/net/wireless/ti/wl1251/Kconfig @@ -1,6 +1,6 @@ menuconfig WL1251 tristate "TI wl1251 driver support" - depends on MAC80211 && GENERIC_HARDIRQS + depends on MAC80211 select FW_LOADER select CRC7 ---help--- diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index 2b832825c3d4..7c099542b214 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig @@ -1,6 +1,6 @@ config WLCORE tristate "TI wlcore support" - depends on WL_TI && GENERIC_HARDIRQS && MAC80211 + depends on WL_TI && MAC80211 select FW_LOADER ---help--- This module contains the main code for TI WLAN chips. It abstracts diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index b35f93c232cf..d5f90d6383bc 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -30,7 +30,6 @@ static int pci_msi_enable = 1; /* Arch hooks */ -#if defined(CONFIG_GENERIC_HARDIRQS) int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_chip *chip = dev->bus->msi; @@ -67,21 +66,6 @@ int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) return chip->check_device(chip, dev, nvec, type); } -#else -int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) -{ - return -ENOSYS; -} - -void __weak arch_teardown_msi_irq(unsigned int irq) -{ -} - -int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - return 0; -} -#endif /* CONFIG_GENERIC_HARDIRQS */ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { @@ -245,8 +229,6 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag) desc->masked = __msix_mask_irq(desc, flag); } -#ifdef CONFIG_GENERIC_HARDIRQS - static void msi_set_mask_bit(struct irq_data *data, u32 flag) { struct msi_desc *desc = irq_data_get_msi(data); @@ -270,8 +252,6 @@ void unmask_msi_irq(struct irq_data *data) msi_set_mask_bit(data, 0); } -#endif /* CONFIG_GENERIC_HARDIRQS */ - void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { BUG_ON(entry->dev->current_state != PCI_D0); @@ -382,10 +362,8 @@ static void free_msi_irqs(struct pci_dev *dev) nvec = entry->nvec_used; else nvec = 1 << entry->msi_attrib.multiple; -#ifdef CONFIG_GENERIC_HARDIRQS for (i = 0; i < nvec; i++) BUG_ON(irq_has_action(entry->irq + i)); -#endif } arch_teardown_msi_irqs(dev); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index bb49ab684f9a..e6f92b450913 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -269,7 +269,6 @@ config CHARGER_ISP1704 config CHARGER_MAX8903 tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power" - depends on GENERIC_HARDIRQS help Say Y to enable support for the MAX8903 DC-DC charger and sysfs. The driver supports controlling charger-enable and current-limit @@ -370,7 +369,7 @@ config AB8500_BM config BATTERY_GOLDFISH tristate "Goldfish battery driver" - depends on GENERIC_HARDIRQS && (GOLDFISH || COMPILE_TEST) + depends on GOLDFISH || COMPILE_TEST help Say Y to enable support for the battery and AC power in the Goldfish emulator. diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig index 6efd9b60d8ff..0c9f2805d076 100644 --- a/drivers/pps/clients/Kconfig +++ b/drivers/pps/clients/Kconfig @@ -31,7 +31,7 @@ config PPS_CLIENT_PARPORT config PPS_CLIENT_GPIO tristate "PPS client using GPIO" - depends on PPS && GENERIC_HARDIRQS + depends on PPS help If you say yes here you get support for a PPS source using GPIO. To be useful you must also register a platform device diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0170d4c4a8a3..b9c53cc40e1f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -55,7 +55,6 @@ comment "SPI Master Controller Drivers" config SPI_ALTERA tristate "Altera SPI Controller" - depends on GENERIC_HARDIRQS select SPI_BITBANG help This is the driver for the Altera SPI Controller. @@ -358,7 +357,7 @@ config SPI_PXA2XX_DMA config SPI_PXA2XX tristate "PXA2xx SSP SPI master" - depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS + depends on (ARCH_PXA || PCI || ACPI) select PXA_SSP if ARCH_PXA help This enables using a PXA2xx or Sodaville SSP port as a SPI master diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 47c6e7b9e150..febd45cd5027 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -5,7 +5,7 @@ if TTY menu "Serial drivers" - depends on HAS_IOMEM && GENERIC_HARDIRQS + depends on HAS_IOMEM source "drivers/tty/serial/8250/Kconfig" diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index f969ea266acb..b870872e020f 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,6 +1,6 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" - depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA + depends on (USB || USB_GADGET) && HAS_DMA depends on EXTCON select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD help diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 30e2dd8a1f2c..48cddf3cd6b8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -313,7 +313,7 @@ config USB_S3C_HSUDC config USB_MV_UDC tristate "Marvell USB2.0 Device Controller" - depends on GENERIC_HARDIRQS && HAS_DMA + depends on HAS_DMA help Marvell Socs (including PXA and MMP series) include a high speed USB2.0 OTG controller, which can be configured as high speed or @@ -425,7 +425,7 @@ config USB_GOKU config USB_EG20T tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" - depends on PCI && GENERIC_HARDIRQS + depends on PCI help This is a USB device driver for EG20T PCH. EG20T PCH is the platform controller hub that is used in Intel's diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5be0326aae38..b3f20d7f15de 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -278,7 +278,6 @@ endif # USB_EHCI_HCD config USB_OXU210HP_HCD tristate "OXU210HP HCD support" - depends on GENERIC_HARDIRQS ---help--- The OXU210HP is an USB host/OTG/device controller. Enable this option if your board has this chip. If unsure, say N. diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index c64ee09a7c0e..c258a97ef1b0 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -71,7 +71,6 @@ config USB_MUSB_DA8XX config USB_MUSB_TUSB6010 tristate "TUSB6010" - depends on GENERIC_HARDIRQS config USB_MUSB_OMAP2PLUS tristate "OMAP2430 and onwards" diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig index 019bf7e49ee6..1c4195abc108 100644 --- a/drivers/usb/renesas_usbhs/Kconfig +++ b/drivers/usb/renesas_usbhs/Kconfig @@ -4,7 +4,7 @@ config USB_RENESAS_USBHS tristate 'Renesas USBHS controller' - depends on USB_GADGET && GENERIC_HARDIRQS + depends on USB_GADGET default n help Renesas USBHS is a discrete USB host and peripheral controller chip diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 2bd1257dcc1c..efc7f075fcbe 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -42,7 +42,7 @@ config W1_MASTER_MXC config W1_MASTER_DS1WM tristate "Maxim DS1WM 1-wire busmaster" - depends on W1 && GENERIC_HARDIRQS + depends on W1 help Say Y here to enable the DS1WM 1-wire driver, such as that in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like diff --git a/include/linux/cpu_rmap.h b/include/linux/cpu_rmap.h index 1739510d8994..bdd18caa6c94 100644 --- a/include/linux/cpu_rmap.h +++ b/include/linux/cpu_rmap.h @@ -52,8 +52,6 @@ static inline void *cpu_rmap_lookup_obj(struct cpu_rmap *rmap, unsigned int cpu) return rmap->obj[rmap->near[cpu].index]; } -#ifdef CONFIG_GENERIC_HARDIRQS - /** * alloc_irq_cpu_rmap - allocate CPU affinity reverse-map for IRQs * @size: Number of objects to be mapped @@ -68,5 +66,4 @@ extern void free_irq_cpu_rmap(struct cpu_rmap *rmap); extern int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq); -#endif #endif /* __LINUX_CPU_RMAP_H */ diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index ccfe17c5c8da..1e041063b226 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -7,11 +7,7 @@ #include -#if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS) extern void synchronize_irq(unsigned int irq); -#else -# define synchronize_irq(irq) barrier() -#endif #if defined(CONFIG_TINY_RCU) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5fa5afeeb759..5e865b554940 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -120,7 +120,6 @@ struct irqaction { extern irqreturn_t no_action(int cpl, void *dev_id); -#ifdef CONFIG_GENERIC_HARDIRQS extern int __must_check request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, @@ -140,40 +139,6 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler, extern int __must_check request_percpu_irq(unsigned int irq, irq_handler_t handler, const char *devname, void __percpu *percpu_dev_id); -#else - -extern int __must_check -request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, - const char *name, void *dev); - -/* - * Special function to avoid ifdeffery in kernel/irq/devres.c which - * gets magically built by GENERIC_HARDIRQS=n architectures (sparc, - * m68k). I really love these $@%#!* obvious Makefile references: - * ../../../kernel/irq/devres.o - */ -static inline int __must_check -request_threaded_irq(unsigned int irq, irq_handler_t handler, - irq_handler_t thread_fn, - unsigned long flags, const char *name, void *dev) -{ - return request_irq(irq, handler, flags, name, dev); -} - -static inline int __must_check -request_any_context_irq(unsigned int irq, irq_handler_t handler, - unsigned long flags, const char *name, void *dev_id) -{ - return request_irq(irq, handler, flags, name, dev_id); -} - -static inline int __must_check -request_percpu_irq(unsigned int irq, irq_handler_t handler, - const char *devname, void __percpu *percpu_dev_id) -{ - return request_irq(irq, handler, 0, devname, percpu_dev_id); -} -#endif extern void free_irq(unsigned int, void *); extern void free_percpu_irq(unsigned int, void __percpu *); @@ -221,7 +186,6 @@ extern void enable_irq(unsigned int irq); extern void enable_percpu_irq(unsigned int irq, unsigned int type); /* The following three functions are for the core kernel use only. */ -#ifdef CONFIG_GENERIC_HARDIRQS extern void suspend_device_irqs(void); extern void resume_device_irqs(void); #ifdef CONFIG_PM_SLEEP @@ -229,13 +193,8 @@ extern int check_wakeup_irqs(void); #else static inline int check_wakeup_irqs(void) { return 0; } #endif -#else -static inline void suspend_device_irqs(void) { }; -static inline void resume_device_irqs(void) { }; -static inline int check_wakeup_irqs(void) { return 0; } -#endif -#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) +#if defined(CONFIG_SMP) extern cpumask_var_t irq_default_affinity; @@ -287,9 +246,8 @@ static inline int irq_set_affinity_hint(unsigned int irq, { return -EINVAL; } -#endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */ +#endif /* CONFIG_SMP */ -#ifdef CONFIG_GENERIC_HARDIRQS /* * Special lockdep variants of irq disabling/enabling. * These should be used for locking constructs that @@ -354,33 +312,6 @@ static inline int disable_irq_wake(unsigned int irq) return irq_set_irq_wake(irq, 0); } -#else /* !CONFIG_GENERIC_HARDIRQS */ -/* - * NOTE: non-genirq architectures, if they want to support the lock - * validator need to define the methods below in their asm/irq.h - * files, under an #ifdef CONFIG_LOCKDEP section. - */ -#ifndef CONFIG_LOCKDEP -# define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq) -# define disable_irq_nosync_lockdep_irqsave(irq, flags) \ - disable_irq_nosync(irq) -# define disable_irq_lockdep(irq) disable_irq(irq) -# define enable_irq_lockdep(irq) enable_irq(irq) -# define enable_irq_lockdep_irqrestore(irq, flags) \ - enable_irq(irq) -# endif - -static inline int enable_irq_wake(unsigned int irq) -{ - return 0; -} - -static inline int disable_irq_wake(unsigned int irq) -{ - return 0; -} -#endif /* CONFIG_GENERIC_HARDIRQS */ - #ifdef CONFIG_IRQ_FORCED_THREADING extern bool force_irqthreads; @@ -655,7 +586,7 @@ void tasklet_hrtimer_cancel(struct tasklet_hrtimer *ttimer) * if more than one irq occurred. */ -#if defined(CONFIG_GENERIC_HARDIRQS) && !defined(CONFIG_GENERIC_IRQ_PROBE) +#if !defined(CONFIG_GENERIC_IRQ_PROBE) static inline unsigned long probe_irq_on(void) { return 0; diff --git a/include/linux/irq.h b/include/linux/irq.h index f04d3ba335cb..56bb0dc8b7d4 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -382,8 +382,6 @@ extern void irq_cpu_online(void); extern void irq_cpu_offline(void); extern int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *cpumask); -#ifdef CONFIG_GENERIC_HARDIRQS - #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) void irq_move_irq(struct irq_data *data); void irq_move_masked_irq(struct irq_data *data); @@ -802,11 +800,4 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { } static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } #endif -#else /* !CONFIG_GENERIC_HARDIRQS */ - -extern struct msi_desc *irq_get_msi_desc(unsigned int irq); -extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry); - -#endif /* CONFIG_GENERIC_HARDIRQS */ - #endif /* _LINUX_IRQ_H */ diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 623325e2ff97..56fb646909dc 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -76,8 +76,6 @@ struct irq_desc { extern struct irq_desc irq_desc[NR_IRQS]; #endif -#ifdef CONFIG_GENERIC_HARDIRQS - static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc) { return &desc->irq_data; @@ -173,6 +171,5 @@ __irq_set_preflow_handler(unsigned int irq, irq_preflow_handler_t handler) desc->preflow_handler = handler; } #endif -#endif #endif diff --git a/include/linux/irqnr.h b/include/linux/irqnr.h index 0a2dc46cdaf6..fdd5cc16c9c4 100644 --- a/include/linux/irqnr.h +++ b/include/linux/irqnr.h @@ -4,23 +4,6 @@ #include -#ifndef CONFIG_GENERIC_HARDIRQS -#include - -/* - * Wrappers for non-genirq architectures: - */ -#define nr_irqs NR_IRQS -#define irq_to_desc(irq) (&irq_desc[irq]) - -# define for_each_irq_desc(irq, desc) \ - for (irq = 0; irq < nr_irqs; irq++) - -# define for_each_irq_desc_reverse(irq, desc) \ - for (irq = nr_irqs - 1; irq >= 0; irq--) - -#else /* CONFIG_GENERIC_HARDIRQS */ - extern int nr_irqs; extern struct irq_desc *irq_to_desc(unsigned int irq); unsigned int irq_get_next_irq(unsigned int offset); @@ -50,8 +33,6 @@ unsigned int irq_get_next_irq(unsigned int offset); for (irq = irq_get_next_irq(0); irq < nr_irqs; \ irq = irq_get_next_irq(irq + 1)) -#endif /* CONFIG_GENERIC_HARDIRQS */ - #define for_each_irq_nr(irq) \ for (irq = 0; irq < nr_irqs; irq++) diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index ed5f6ed6eb77..51c72be4a7c3 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -36,9 +36,6 @@ struct kernel_cpustat { }; struct kernel_stat { -#ifndef CONFIG_GENERIC_HARDIRQS - unsigned int irqs[NR_IRQS]; -#endif unsigned long irqs_sum; unsigned int softirqs[NR_SOFTIRQS]; }; @@ -54,22 +51,6 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat); extern unsigned long long nr_context_switches(void); -#ifndef CONFIG_GENERIC_HARDIRQS - -struct irq_desc; - -static inline void kstat_incr_irqs_this_cpu(unsigned int irq, - struct irq_desc *desc) -{ - __this_cpu_inc(kstat.irqs[irq]); - __this_cpu_inc(kstat.irqs_sum); -} - -static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) -{ - return kstat_cpu(cpu).irqs[irq]; -} -#else #include extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu); @@ -79,8 +60,6 @@ do { \ __this_cpu_inc(kstat.irqs_sum); \ } while (0) -#endif - static inline void kstat_incr_softirqs_this_cpu(unsigned int irq) { __this_cpu_inc(kstat.softirqs[irq]); @@ -94,20 +73,7 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu) /* * Number of interrupts per specific IRQ source, since bootup */ -#ifndef CONFIG_GENERIC_HARDIRQS -static inline unsigned int kstat_irqs(unsigned int irq) -{ - unsigned int sum = 0; - int cpu; - - for_each_possible_cpu(cpu) - sum += kstat_irqs_cpu(irq, cpu); - - return sum; -} -#else extern unsigned int kstat_irqs(unsigned int irq); -#endif /* * Number of interrupts per cpu, since bootup diff --git a/kernel/Makefile b/kernel/Makefile index 35ef1185e359..1ce47553fb02 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -26,6 +26,7 @@ obj-y += sched/ obj-y += power/ obj-y += printk/ obj-y += cpu/ +obj-y += irq/ obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o obj-$(CONFIG_FREEZER) += freezer.o @@ -79,7 +80,6 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KGDB) += debug/ obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o -obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += rcutree.o diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index d1a758bc972a..4a1fef09f658 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -1,15 +1,4 @@ -# Select this to activate the generic irq options below -config HAVE_GENERIC_HARDIRQS - bool - -if HAVE_GENERIC_HARDIRQS menu "IRQ subsystem" -# -# Interrupt subsystem related configuration options -# -config GENERIC_HARDIRQS - def_bool y - # Options selectable by the architecture code # Make sparse irq Kconfig switch below available @@ -84,4 +73,3 @@ config SPARSE_IRQ If you don't know what to do here, say N. endmenu -endif diff --git a/kernel/softirq.c b/kernel/softirq.c index be3d3514c325..53cc09ceb0b8 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -876,7 +876,6 @@ int __init __weak early_irq_init(void) return 0; } -#ifdef CONFIG_GENERIC_HARDIRQS int __init __weak arch_probe_nr_irqs(void) { return NR_IRQS_LEGACY; @@ -886,4 +885,3 @@ int __init __weak arch_early_irq_init(void) { return 0; } -#endif diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c9eef36739a9..06344d986eb9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -597,7 +597,7 @@ endmenu # "Memory Debugging" config DEBUG_SHIRQ bool "Debug shared IRQ handlers" - depends on DEBUG_KERNEL && GENERIC_HARDIRQS + depends on DEBUG_KERNEL help Enable this to generate a spurious interrupt as soon as a shared interrupt handler is registered, and just before one is deregistered. diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c index 5fbed5caba6e..4f134d8907a7 100644 --- a/lib/cpu_rmap.c +++ b/lib/cpu_rmap.c @@ -8,9 +8,7 @@ */ #include -#ifdef CONFIG_GENERIC_HARDIRQS #include -#endif #include /* @@ -213,8 +211,6 @@ int cpu_rmap_update(struct cpu_rmap *rmap, u16 index, } EXPORT_SYMBOL(cpu_rmap_update); -#ifdef CONFIG_GENERIC_HARDIRQS - /* Glue between IRQ affinity notifiers and CPU rmaps */ struct irq_glue { @@ -309,5 +305,3 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq) return rc; } EXPORT_SYMBOL(irq_cpu_rmap_add); - -#endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/net/Kconfig b/net/Kconfig index ee0213667272..b50dacc072f0 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -228,7 +228,7 @@ config RPS config RFS_ACCEL boolean - depends on RPS && GENERIC_HARDIRQS + depends on RPS select CPU_RMAP default y diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 15106c045478..b33b45dfceec 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -107,7 +107,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8782 select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C - select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS + select SND_SOC_WM8903 if I2C select SND_SOC_WM8904 if I2C select SND_SOC_WM8940 if I2C select SND_SOC_WM8955 if I2C diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 9855dfc3e3ec..2eea1840315d 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -63,7 +63,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580 config SND_SOC_SAMSUNG_SMDK_WM8994 tristate "SoC I2S Audio support for WM8994 on SMDK" depends on SND_SOC_SAMSUNG - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_I2S @@ -151,7 +151,7 @@ config SND_SOC_SMARTQ config SND_SOC_GONI_AQUILA_WM8994 tristate "SoC I2S Audio support for AQUILA/GONI - WM8994" depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA) - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select SND_SAMSUNG_I2S select MFD_WM8994 select SND_SOC_WM8994 @@ -177,7 +177,7 @@ config SND_SOC_SMDK_WM8580_PCM config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" depends on SND_SOC_SAMSUNG - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y select MFD_WM8994 select SND_SOC_WM8994 select SND_SAMSUNG_PCM -- cgit v1.2.3 From 052d0efada8ccfccd924059b75f5fb119cd10f9a Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 26 Jun 2013 23:49:11 +0100 Subject: DMA-API: block: nvme-core: replace dma_set_mask()+dma_set_coherent_mask() with new helper Replace the following sequence: dma_set_mask(dev, mask); dma_set_coherent_mask(dev, mask); with a call to the new helper dma_set_mask_and_coherent(). Signed-off-by: Russell King --- drivers/block/nvme-core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index da52092980e2..26d03fa0bf26 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1949,12 +1949,9 @@ static int nvme_dev_map(struct nvme_dev *dev) if (pci_request_selected_regions(pdev, bars, "nvme")) goto disable_pci; - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); - else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - else - goto disable_pci; + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)) && + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) + goto disable; pci_set_drvdata(pdev, dev); dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); @@ -2168,6 +2165,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&dev->namespaces); dev->pci_dev = pdev; + result = nvme_set_instance(dev); if (result) goto free; -- cgit v1.2.3 From 891070003999e7ac8881bba6f8242615382742eb Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Tue, 17 Sep 2013 09:25:23 +0930 Subject: virtio: pm: use CONFIG_PM_SLEEP instead of CONFIG_PM The freeze and restore functions defined in virtio drivers are used for suspend and hibernate, so CONFIG_PM_SLEEP is more appropriate than CONFIG_PM. This patch replace all CONFIG_PM with CONFIG_PM_SLEEP for virtio drivers that implement freeze and restore callbacks. Signed-off-by: Aaron Lu Reviewed-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/block/virtio_blk.c | 4 ++-- drivers/char/hw_random/virtio-rng.c | 4 ++-- drivers/char/virtio_console.c | 4 ++-- drivers/net/virtio_net.c | 4 ++-- drivers/scsi/virtio_scsi.c | 4 ++-- drivers/virtio/virtio_balloon.c | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 5cdf88b7ad9e..89245b5adca1 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -899,7 +899,7 @@ static void virtblk_remove(struct virtio_device *vdev) ida_simple_remove(&vd_index_ida, index); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtblk_freeze(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; @@ -959,7 +959,7 @@ static struct virtio_driver virtio_blk = { .probe = virtblk_probe, .remove = virtblk_remove, .config_changed = virtblk_config_changed, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtblk_freeze, .restore = virtblk_restore, #endif diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index ef46a9cfd832..c12398d1517c 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -133,7 +133,7 @@ static void virtrng_remove(struct virtio_device *vdev) remove_common(vdev); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtrng_freeze(struct virtio_device *vdev) { remove_common(vdev); @@ -157,7 +157,7 @@ static struct virtio_driver virtio_rng_driver = { .id_table = id_table, .probe = virtrng_probe, .remove = virtrng_remove, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtrng_freeze, .restore = virtrng_restore, #endif diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index b79cf3e1b793..862fd54a0ffb 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2142,7 +2142,7 @@ static struct virtio_device_id rproc_serial_id_table[] = { static unsigned int rproc_serial_features[] = { }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtcons_freeze(struct virtio_device *vdev) { struct ports_device *portdev; @@ -2220,7 +2220,7 @@ static struct virtio_driver virtio_console = { .probe = virtcons_probe, .remove = virtcons_remove, .config_changed = config_intr, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtcons_freeze, .restore = virtcons_restore, #endif diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index defec2b3c5a4..2ad3d96d4a7c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1683,7 +1683,7 @@ static void virtnet_remove(struct virtio_device *vdev) free_netdev(vi->dev); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtnet_freeze(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; @@ -1766,7 +1766,7 @@ static struct virtio_driver virtio_net_driver = { .probe = virtnet_probe, .remove = virtnet_remove, .config_changed = virtnet_config_changed, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtnet_freeze, .restore = virtnet_restore, #endif diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 74b88efde6ad..2a110391f8ce 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -954,7 +954,7 @@ static void virtscsi_remove(struct virtio_device *vdev) scsi_host_put(shost); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtscsi_freeze(struct virtio_device *vdev) { virtscsi_remove_vqs(vdev); @@ -988,7 +988,7 @@ static struct virtio_driver virtio_scsi_driver = { .id_table = id_table, .probe = virtscsi_probe, .scan = virtscsi_scan, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtscsi_freeze, .restore = virtscsi_restore, #endif diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 1f572c00a1be..d6f681641606 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -513,7 +513,7 @@ static void virtballoon_remove(struct virtio_device *vdev) kfree(vb); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int virtballoon_freeze(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; @@ -556,7 +556,7 @@ static struct virtio_driver virtio_balloon_driver = { .probe = virtballoon_probe, .remove = virtballoon_remove, .config_changed = virtballoon_changed, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .freeze = virtballoon_freeze, .restore = virtballoon_restore, #endif -- cgit v1.2.3 From 627aad1c01da6f881e7f98d71fd928ca0c316b1a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Sep 2013 15:27:44 -0700 Subject: cpqarray: fix info leak in ida_locked_ioctl() The pciinfo struct has a two byte hole after ->dev_fn so stack information could be leaked to the user. This was assigned CVE-2013-2147. Signed-off-by: Dan Carpenter Acked-by: Mike Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cpqarray.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/block') diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 639d26b90b91..2b9440384536 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1193,6 +1193,7 @@ out_passthru: ida_pci_info_struct pciinfo; if (!arg) return -EINVAL; + memset(&pciinfo, 0, sizeof(pciinfo)); pciinfo.bus = host->pci_dev->bus->number; pciinfo.dev_fn = host->pci_dev->devfn; pciinfo.board_id = host->board_id; -- cgit v1.2.3 From 58f09e00ae095e46ef9edfcf3a5fd9ccdfad065e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Sep 2013 15:27:45 -0700 Subject: cciss: fix info leak in cciss_ioctl32_passthru() The arg64 struct has a hole after ->buf_size which isn't cleared. Or if any of the calls to copy_from_user() fail then that would cause an information leak as well. This was assigned CVE-2013-2147. Signed-off-by: Dan Carpenter Acked-by: Mike Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/cciss.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/block') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d2d95ff5353b..edfa2515bc86 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1189,6 +1189,7 @@ static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode, int err; u32 cp; + memset(&arg64, 0, sizeof(arg64)); err = 0; err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, -- cgit v1.2.3 From 3c5710f6a229504d1e6b15cb4170b64ab420b43a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 3 Sep 2013 11:43:10 +0200 Subject: block: drop dependency on ARCH_SHARK With this machine deleted, there is no need to maintain the MFM block driver for its hard disk either. Cc: Jens Axboe Signed-off-by: Linus Walleij --- drivers/block/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index e07a5fd58ad7..e67fa16e1938 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -505,7 +505,7 @@ config VIRTIO_BLK config BLK_DEV_HD bool "Very old hard disk (MFM/RLL/IDE) driver" depends on HAVE_IDE - depends on !ARM || ARCH_RPC || ARCH_SHARK || BROKEN + depends on !ARM || ARCH_RPC || BROKEN help This is a very old hard disk driver that lacks the enhanced functionality of the newer ones. -- cgit v1.2.3 From 855e0c5288177bcb193f6f6316952d2490478e1c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 14 Oct 2013 18:11:51 +1030 Subject: virtio: use size-based config accessors. This lets the transport do endian conversion if necessary, and insulates the drivers from the difference. Most drivers can use the simple helpers virtio_cread() and virtio_cwrite(). Signed-off-by: Rusty Russell --- drivers/block/virtio_blk.c | 77 ++++++++++++++++++----------------------- drivers/char/virtio_console.c | 15 +++----- drivers/net/caif/caif_virtio.c | 23 ++++++------ drivers/net/virtio_net.c | 28 +++++++++------ drivers/scsi/virtio_scsi.c | 12 +++---- drivers/virtio/virtio_balloon.c | 10 +++--- net/9p/trans_virtio.c | 9 +++-- 7 files changed, 79 insertions(+), 95 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 89245b5adca1..6b66252fc4e6 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -456,18 +456,15 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { struct virtio_blk *vblk = bd->bd_disk->private_data; - struct virtio_blk_geometry vgeo; - int err; /* see if the host passed in geometry config */ - err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY, - offsetof(struct virtio_blk_config, geometry), - &vgeo); - - if (!err) { - geo->heads = vgeo.heads; - geo->sectors = vgeo.sectors; - geo->cylinders = vgeo.cylinders; + if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) { + virtio_cread(vblk->vdev, struct virtio_blk_config, + geometry.cylinders, &geo->cylinders); + virtio_cread(vblk->vdev, struct virtio_blk_config, + geometry.heads, &geo->heads); + virtio_cread(vblk->vdev, struct virtio_blk_config, + geometry.sectors, &geo->sectors); } else { /* some standard values, similar to sd */ geo->heads = 1 << 6; @@ -529,8 +526,7 @@ static void virtblk_config_changed_work(struct work_struct *work) goto done; /* Host must always specify the capacity. */ - vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), - &capacity, sizeof(capacity)); + virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity); /* If capacity is too big, truncate with warning. */ if ((sector_t)capacity != capacity) { @@ -608,9 +604,9 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev) u8 writeback; int err; - err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE, - offsetof(struct virtio_blk_config, wce), - &writeback); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE, + struct virtio_blk_config, wce, + &writeback); if (err) writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE); @@ -642,7 +638,6 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, struct virtio_blk *vblk = disk->private_data; struct virtio_device *vdev = vblk->vdev; int i; - u8 writeback; BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE)); for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; ) @@ -652,11 +647,7 @@ virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, if (i < 0) return -EINVAL; - writeback = i; - vdev->config->set(vdev, - offsetof(struct virtio_blk_config, wce), - &writeback, sizeof(writeback)); - + virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i); virtblk_update_cache_mode(vdev); return count; } @@ -699,9 +690,9 @@ static int virtblk_probe(struct virtio_device *vdev) index = err; /* We need to know how many segments before we allocate. */ - err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX, - offsetof(struct virtio_blk_config, seg_max), - &sg_elems); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX, + struct virtio_blk_config, seg_max, + &sg_elems); /* We need at least one SG element, whatever they say. */ if (err || !sg_elems) @@ -772,8 +763,7 @@ static int virtblk_probe(struct virtio_device *vdev) set_disk_ro(vblk->disk, 1); /* Host must always specify the capacity. */ - vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity), - &cap, sizeof(cap)); + virtio_cread(vdev, struct virtio_blk_config, capacity, &cap); /* If capacity is too big, truncate with warning. */ if ((sector_t)cap != cap) { @@ -794,46 +784,45 @@ static int virtblk_probe(struct virtio_device *vdev) /* Host can optionally specify maximum segment size and number of * segments. */ - err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX, - offsetof(struct virtio_blk_config, size_max), - &v); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX, + struct virtio_blk_config, size_max, &v); if (!err) blk_queue_max_segment_size(q, v); else blk_queue_max_segment_size(q, -1U); /* Host can optionally specify the block size of the device */ - err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, - offsetof(struct virtio_blk_config, blk_size), - &blk_size); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, + struct virtio_blk_config, blk_size, + &blk_size); if (!err) blk_queue_logical_block_size(q, blk_size); else blk_size = queue_logical_block_size(q); /* Use topology information if available */ - err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, - offsetof(struct virtio_blk_config, physical_block_exp), - &physical_block_exp); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, + struct virtio_blk_config, physical_block_exp, + &physical_block_exp); if (!err && physical_block_exp) blk_queue_physical_block_size(q, blk_size * (1 << physical_block_exp)); - err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, - offsetof(struct virtio_blk_config, alignment_offset), - &alignment_offset); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, + struct virtio_blk_config, alignment_offset, + &alignment_offset); if (!err && alignment_offset) blk_queue_alignment_offset(q, blk_size * alignment_offset); - err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, - offsetof(struct virtio_blk_config, min_io_size), - &min_io_size); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, + struct virtio_blk_config, min_io_size, + &min_io_size); if (!err && min_io_size) blk_queue_io_min(q, blk_size * min_io_size); - err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY, - offsetof(struct virtio_blk_config, opt_io_size), - &opt_io_size); + err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, + struct virtio_blk_config, opt_io_size, + &opt_io_size); if (!err && opt_io_size) blk_queue_io_opt(q, blk_size * opt_io_size); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 862fd54a0ffb..2a8d9a7a1834 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1837,12 +1837,8 @@ static void config_intr(struct virtio_device *vdev) struct port *port; u16 rows, cols; - vdev->config->get(vdev, - offsetof(struct virtio_console_config, cols), - &cols, sizeof(u16)); - vdev->config->get(vdev, - offsetof(struct virtio_console_config, rows), - &rows, sizeof(u16)); + virtio_cread(vdev, struct virtio_console_config, cols, &cols); + virtio_cread(vdev, struct virtio_console_config, rows, &rows); port = find_port_by_id(portdev, 0); set_console_size(port, rows, cols); @@ -2014,10 +2010,9 @@ static int virtcons_probe(struct virtio_device *vdev) /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ if (!is_rproc_serial(vdev) && - virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT, - offsetof(struct virtio_console_config, - max_nr_ports), - &portdev->config.max_nr_ports) == 0) { + virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, + struct virtio_console_config, max_nr_ports, + &portdev->config.max_nr_ports) == 0) { multiport = true; } diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index b9ed1288ce2d..985608634f8c 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -686,18 +686,19 @@ static int cfv_probe(struct virtio_device *vdev) goto err; /* Get the CAIF configuration from virtio config space, if available */ -#define GET_VIRTIO_CONFIG_OPS(_v, _var, _f) \ - ((_v)->config->get(_v, offsetof(struct virtio_caif_transf_config, _f), \ - &_var, \ - FIELD_SIZEOF(struct virtio_caif_transf_config, _f))) - if (vdev->config->get) { - GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_hr, headroom); - GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_hr, headroom); - GET_VIRTIO_CONFIG_OPS(vdev, cfv->tx_tr, tailroom); - GET_VIRTIO_CONFIG_OPS(vdev, cfv->rx_tr, tailroom); - GET_VIRTIO_CONFIG_OPS(vdev, cfv->mtu, mtu); - GET_VIRTIO_CONFIG_OPS(vdev, cfv->mru, mtu); + virtio_cread(vdev, struct virtio_caif_transf_config, headroom, + &cfv->tx_hr); + virtio_cread(vdev, struct virtio_caif_transf_config, headroom, + &cfv->rx_hr); + virtio_cread(vdev, struct virtio_caif_transf_config, tailroom, + &cfv->tx_tr); + virtio_cread(vdev, struct virtio_caif_transf_config, tailroom, + &cfv->rx_tr); + virtio_cread(vdev, struct virtio_caif_transf_config, mtu, + &cfv->mtu); + virtio_cread(vdev, struct virtio_caif_transf_config, mtu, + &cfv->mru); } else { cfv->tx_hr = CFV_DEF_HEADROOM; cfv->rx_hr = CFV_DEF_HEADROOM; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2ad3d96d4a7c..ee022714eadb 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -852,8 +852,13 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p) return -EINVAL; } } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) { - vdev->config->set(vdev, offsetof(struct virtio_net_config, mac), - addr->sa_data, dev->addr_len); + unsigned int i; + + /* Naturally, this has an atomicity problem. */ + for (i = 0; i < dev->addr_len; i++) + virtio_cwrite8(vdev, + offsetof(struct virtio_net_config, mac) + + i, addr->sa_data[i]); } eth_commit_mac_addr_change(dev, p); @@ -1266,9 +1271,8 @@ static void virtnet_config_changed_work(struct work_struct *work) if (!vi->config_enable) goto done; - if (virtio_config_val(vi->vdev, VIRTIO_NET_F_STATUS, - offsetof(struct virtio_net_config, status), - &v) < 0) + if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS, + struct virtio_net_config, status, &v) < 0) goto done; if (v & VIRTIO_NET_S_ANNOUNCE) { @@ -1490,9 +1494,9 @@ static int virtnet_probe(struct virtio_device *vdev) u16 max_queue_pairs; /* Find if host supports multiqueue virtio_net device */ - err = virtio_config_val(vdev, VIRTIO_NET_F_MQ, - offsetof(struct virtio_net_config, - max_virtqueue_pairs), &max_queue_pairs); + err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ, + struct virtio_net_config, + max_virtqueue_pairs, &max_queue_pairs); /* We need at least 2 queue's */ if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || @@ -1544,9 +1548,11 @@ static int virtnet_probe(struct virtio_device *vdev) dev->vlan_features = dev->features; /* Configuration may specify what MAC to use. Otherwise random. */ - if (virtio_config_val_len(vdev, VIRTIO_NET_F_MAC, - offsetof(struct virtio_net_config, mac), - dev->dev_addr, dev->addr_len) < 0) + if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) + virtio_cread_bytes(vdev, + offsetof(struct virtio_net_config, mac), + dev->dev_addr, dev->addr_len); + else eth_hw_addr_random(dev); /* Set up our device-specific information */ diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 2a110391f8ce..e6bb2352df40 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -710,19 +710,15 @@ static struct scsi_host_template virtscsi_host_template_multi = { #define virtscsi_config_get(vdev, fld) \ ({ \ typeof(((struct virtio_scsi_config *)0)->fld) __val; \ - vdev->config->get(vdev, \ - offsetof(struct virtio_scsi_config, fld), \ - &__val, sizeof(__val)); \ + virtio_cread(vdev, struct virtio_scsi_config, fld, &__val); \ __val; \ }) #define virtscsi_config_set(vdev, fld, val) \ - (void)({ \ + do { \ typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \ - vdev->config->set(vdev, \ - offsetof(struct virtio_scsi_config, fld), \ - &__val, sizeof(__val)); \ - }) + virtio_cwrite(vdev, struct virtio_scsi_config, fld, &__val); \ + } while(0) static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity) { diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index d6f681641606..c444654fc33f 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -275,9 +275,8 @@ static inline s64 towards_target(struct virtio_balloon *vb) __le32 v; s64 target; - vb->vdev->config->get(vb->vdev, - offsetof(struct virtio_balloon_config, num_pages), - &v, sizeof(v)); + virtio_cread(vb->vdev, struct virtio_balloon_config, num_pages, &v); + target = le32_to_cpu(v); return target - vb->num_pages; } @@ -286,9 +285,8 @@ static void update_balloon_size(struct virtio_balloon *vb) { __le32 actual = cpu_to_le32(vb->num_pages); - vb->vdev->config->set(vb->vdev, - offsetof(struct virtio_balloon_config, actual), - &actual, sizeof(actual)); + virtio_cwrite(vb->vdev, struct virtio_balloon_config, num_pages, + &actual); } static int balloon(void *_vballoon) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 990afab2be1b..9c5a1aa34d12 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -544,9 +544,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->inuse = false; if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) { - vdev->config->get(vdev, - offsetof(struct virtio_9p_config, tag_len), - &tag_len, sizeof(tag_len)); + virtio_cread(vdev, struct virtio_9p_config, tag_len, &tag_len); } else { err = -EINVAL; goto out_free_vq; @@ -556,8 +554,9 @@ static int p9_virtio_probe(struct virtio_device *vdev) err = -ENOMEM; goto out_free_vq; } - vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag), - tag, tag_len); + + virtio_cread_bytes(vdev, offsetof(struct virtio_9p_config, tag), + tag, tag_len); chan->tag = tag; chan->tag_len = tag_len; err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); -- cgit v1.2.3 From 5953316dbf90067ebdeca626c34488bc166b73a8 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 23 May 2013 12:25:08 +0200 Subject: block: make rq->cmd_flags be 64-bit We have officially run out of flags in a 32-bit space. Extend it to 64-bit even on 32-bit archs. Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- block/blk-core.c | 4 +-- drivers/block/floppy.c | 4 +-- drivers/scsi/sd.c | 2 +- include/linux/blk_types.h | 66 +++++++++++++++++++++++------------------------ include/linux/blkdev.h | 4 +-- 5 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers/block') diff --git a/block/blk-core.c b/block/blk-core.c index 0a00e4ecf87c..213e9f01c627 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -174,9 +174,9 @@ void blk_dump_rq_flags(struct request *rq, char *msg) { int bit; - printk(KERN_INFO "%s: dev %s: type=%x, flags=%x\n", msg, + printk(KERN_INFO "%s: dev %s: type=%x, flags=%llx\n", msg, rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type, - rq->cmd_flags); + (unsigned long long) rq->cmd_flags); printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n", (unsigned long long)blk_rq_pos(rq), diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 04ceb7e2fadd..000abe2f105c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2886,9 +2886,9 @@ static void do_fd_request(struct request_queue *q) return; if (WARN(atomic_read(&usage_count) == 0, - "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n", + "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n", current_req, (long)blk_rq_pos(current_req), current_req->cmd_type, - current_req->cmd_flags)) + (unsigned long long) current_req->cmd_flags)) return; if (test_and_set_bit(0, &fdc_busy)) { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e62d17d41d4e..dae6133a538d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1002,7 +1002,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); + scmd_printk(KERN_ERR, SCpnt, "Unknown command %llx\n", (unsigned long long) rq->cmd_flags); goto out; } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index fa1abeb45b76..c26801e14788 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -181,16 +181,16 @@ enum rq_flag_bits { __REQ_NR_BITS, /* stops here */ }; -#define REQ_WRITE (1 << __REQ_WRITE) -#define REQ_FAILFAST_DEV (1 << __REQ_FAILFAST_DEV) -#define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT) -#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER) -#define REQ_SYNC (1 << __REQ_SYNC) -#define REQ_META (1 << __REQ_META) -#define REQ_PRIO (1 << __REQ_PRIO) -#define REQ_DISCARD (1 << __REQ_DISCARD) -#define REQ_WRITE_SAME (1 << __REQ_WRITE_SAME) -#define REQ_NOIDLE (1 << __REQ_NOIDLE) +#define REQ_WRITE (1ULL << __REQ_WRITE) +#define REQ_FAILFAST_DEV (1ULL << __REQ_FAILFAST_DEV) +#define REQ_FAILFAST_TRANSPORT (1ULL << __REQ_FAILFAST_TRANSPORT) +#define REQ_FAILFAST_DRIVER (1ULL << __REQ_FAILFAST_DRIVER) +#define REQ_SYNC (1ULL << __REQ_SYNC) +#define REQ_META (1ULL << __REQ_META) +#define REQ_PRIO (1ULL << __REQ_PRIO) +#define REQ_DISCARD (1ULL << __REQ_DISCARD) +#define REQ_WRITE_SAME (1ULL << __REQ_WRITE_SAME) +#define REQ_NOIDLE (1ULL << __REQ_NOIDLE) #define REQ_FAILFAST_MASK \ (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) @@ -206,28 +206,28 @@ enum rq_flag_bits { #define REQ_NOMERGE_FLAGS \ (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA) -#define REQ_RAHEAD (1 << __REQ_RAHEAD) -#define REQ_THROTTLED (1 << __REQ_THROTTLED) - -#define REQ_SORTED (1 << __REQ_SORTED) -#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) -#define REQ_FUA (1 << __REQ_FUA) -#define REQ_NOMERGE (1 << __REQ_NOMERGE) -#define REQ_STARTED (1 << __REQ_STARTED) -#define REQ_DONTPREP (1 << __REQ_DONTPREP) -#define REQ_QUEUED (1 << __REQ_QUEUED) -#define REQ_ELVPRIV (1 << __REQ_ELVPRIV) -#define REQ_FAILED (1 << __REQ_FAILED) -#define REQ_QUIET (1 << __REQ_QUIET) -#define REQ_PREEMPT (1 << __REQ_PREEMPT) -#define REQ_ALLOCED (1 << __REQ_ALLOCED) -#define REQ_COPY_USER (1 << __REQ_COPY_USER) -#define REQ_FLUSH (1 << __REQ_FLUSH) -#define REQ_FLUSH_SEQ (1 << __REQ_FLUSH_SEQ) -#define REQ_IO_STAT (1 << __REQ_IO_STAT) -#define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE) -#define REQ_SECURE (1 << __REQ_SECURE) -#define REQ_KERNEL (1 << __REQ_KERNEL) -#define REQ_PM (1 << __REQ_PM) +#define REQ_RAHEAD (1ULL << __REQ_RAHEAD) +#define REQ_THROTTLED (1ULL << __REQ_THROTTLED) + +#define REQ_SORTED (1ULL << __REQ_SORTED) +#define REQ_SOFTBARRIER (1ULL << __REQ_SOFTBARRIER) +#define REQ_FUA (1ULL << __REQ_FUA) +#define REQ_NOMERGE (1ULL << __REQ_NOMERGE) +#define REQ_STARTED (1ULL << __REQ_STARTED) +#define REQ_DONTPREP (1ULL << __REQ_DONTPREP) +#define REQ_QUEUED (1ULL << __REQ_QUEUED) +#define REQ_ELVPRIV (1ULL << __REQ_ELVPRIV) +#define REQ_FAILED (1ULL << __REQ_FAILED) +#define REQ_QUIET (1ULL << __REQ_QUIET) +#define REQ_PREEMPT (1ULL << __REQ_PREEMPT) +#define REQ_ALLOCED (1ULL << __REQ_ALLOCED) +#define REQ_COPY_USER (1ULL << __REQ_COPY_USER) +#define REQ_FLUSH (1ULL << __REQ_FLUSH) +#define REQ_FLUSH_SEQ (1ULL << __REQ_FLUSH_SEQ) +#define REQ_IO_STAT (1ULL << __REQ_IO_STAT) +#define REQ_MIXED_MERGE (1ULL << __REQ_MIXED_MERGE) +#define REQ_SECURE (1ULL << __REQ_SECURE) +#define REQ_KERNEL (1ULL << __REQ_KERNEL) +#define REQ_PM (1ULL << __REQ_PM) #endif /* __LINUX_BLK_TYPES_H */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0e6f765aa1f5..f5c7596c93dd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -99,7 +99,7 @@ struct request { struct request_queue *q; - unsigned int cmd_flags; + u64 cmd_flags; enum rq_cmd_type_bits cmd_type; unsigned long atomic_flags; @@ -570,7 +570,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -#define rq_data_dir(rq) ((rq)->cmd_flags & 1) +#define rq_data_dir(rq) (((rq)->cmd_flags & 1) != 0) static inline unsigned int blk_queue_cluster(struct request_queue *q) { -- cgit v1.2.3 From f2298c0403b0dfcaef637eba0c02c4a06d7a25ab Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 25 Oct 2013 11:52:25 +0100 Subject: null_blk: multi queue aware block test driver A driver that simply completes IO it receives, it does no transfers. Written to fascilitate testing of the blk-mq code. It supports various module options to use either bio queueing, rq queueing, or mq mode. Signed-off-by: Jens Axboe --- drivers/block/Kconfig | 3 + drivers/block/Makefile | 1 + drivers/block/null_blk.c | 635 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 639 insertions(+) create mode 100644 drivers/block/null_blk.c (limited to 'drivers/block') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index e07a5fd58ad7..4682546c5da7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -15,6 +15,9 @@ menuconfig BLK_DEV if BLK_DEV +config BLK_DEV_NULL_BLK + tristate "Null test block driver" + config BLK_DEV_FD tristate "Normal floppy disk support" depends on ARCH_MAY_HAVE_PC_FDC diff --git a/drivers/block/Makefile b/drivers/block/Makefile index ca07399a8d99..03b3b4a2bd8a 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/ +obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk.o nvme-y := nvme-core.o nvme-scsi.o swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c new file mode 100644 index 000000000000..b5d842370cc9 --- /dev/null +++ b/drivers/block/null_blk.c @@ -0,0 +1,635 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nullb_cmd { + struct list_head list; + struct llist_node ll_list; + struct call_single_data csd; + struct request *rq; + struct bio *bio; + unsigned int tag; + struct nullb_queue *nq; +}; + +struct nullb_queue { + unsigned long *tag_map; + wait_queue_head_t wait; + unsigned int queue_depth; + + struct nullb_cmd *cmds; +}; + +struct nullb { + struct list_head list; + unsigned int index; + struct request_queue *q; + struct gendisk *disk; + struct hrtimer timer; + unsigned int queue_depth; + spinlock_t lock; + + struct nullb_queue *queues; + unsigned int nr_queues; +}; + +static LIST_HEAD(nullb_list); +static struct mutex lock; +static int null_major; +static int nullb_indexes; + +struct completion_queue { + struct llist_head list; + struct hrtimer timer; +}; + +/* + * These are per-cpu for now, they will need to be configured by the + * complete_queues parameter and appropriately mapped. + */ +static DEFINE_PER_CPU(struct completion_queue, completion_queues); + +enum { + NULL_IRQ_NONE = 0, + NULL_IRQ_SOFTIRQ = 1, + NULL_IRQ_TIMER = 2, + + NULL_Q_BIO = 0, + NULL_Q_RQ = 1, + NULL_Q_MQ = 2, +}; + +static int submit_queues = 1; +module_param(submit_queues, int, S_IRUGO); +MODULE_PARM_DESC(submit_queues, "Number of submission queues"); + +static int home_node = NUMA_NO_NODE; +module_param(home_node, int, S_IRUGO); +MODULE_PARM_DESC(home_node, "Home node for the device"); + +static int queue_mode = NULL_Q_MQ; +module_param(queue_mode, int, S_IRUGO); +MODULE_PARM_DESC(use_mq, "Use blk-mq interface (0=bio,1=rq,2=multiqueue)"); + +static int gb = 250; +module_param(gb, int, S_IRUGO); +MODULE_PARM_DESC(gb, "Size in GB"); + +static int bs = 512; +module_param(bs, int, S_IRUGO); +MODULE_PARM_DESC(bs, "Block size (in bytes)"); + +static int nr_devices = 2; +module_param(nr_devices, int, S_IRUGO); +MODULE_PARM_DESC(nr_devices, "Number of devices to register"); + +static int irqmode = NULL_IRQ_SOFTIRQ; +module_param(irqmode, int, S_IRUGO); +MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer"); + +static int completion_nsec = 10000; +module_param(completion_nsec, int, S_IRUGO); +MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns"); + +static int hw_queue_depth = 64; +module_param(hw_queue_depth, int, S_IRUGO); +MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: 64"); + +static bool use_per_node_hctx = true; +module_param(use_per_node_hctx, bool, S_IRUGO); +MODULE_PARM_DESC(use_per_node_hctx, "Use per-node allocation for hardware context queues. Default: true"); + +static void put_tag(struct nullb_queue *nq, unsigned int tag) +{ + clear_bit_unlock(tag, nq->tag_map); + + if (waitqueue_active(&nq->wait)) + wake_up(&nq->wait); +} + +static unsigned int get_tag(struct nullb_queue *nq) +{ + unsigned int tag; + + do { + tag = find_first_zero_bit(nq->tag_map, nq->queue_depth); + if (tag >= nq->queue_depth) + return -1U; + } while (test_and_set_bit_lock(tag, nq->tag_map)); + + return tag; +} + +static void free_cmd(struct nullb_cmd *cmd) +{ + put_tag(cmd->nq, cmd->tag); +} + +static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq) +{ + struct nullb_cmd *cmd; + unsigned int tag; + + tag = get_tag(nq); + if (tag != -1U) { + cmd = &nq->cmds[tag]; + cmd->tag = tag; + cmd->nq = nq; + return cmd; + } + + return NULL; +} + +static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) +{ + struct nullb_cmd *cmd; + DEFINE_WAIT(wait); + + cmd = __alloc_cmd(nq); + if (cmd || !can_wait) + return cmd; + + do { + prepare_to_wait(&nq->wait, &wait, TASK_UNINTERRUPTIBLE); + cmd = __alloc_cmd(nq); + if (cmd) + break; + + io_schedule(); + } while (1); + + finish_wait(&nq->wait, &wait); + return cmd; +} + +static void end_cmd(struct nullb_cmd *cmd) +{ + if (cmd->rq) { + if (queue_mode == NULL_Q_MQ) + blk_mq_end_io(cmd->rq, 0); + else { + INIT_LIST_HEAD(&cmd->rq->queuelist); + blk_end_request_all(cmd->rq, 0); + } + } else if (cmd->bio) + bio_endio(cmd->bio, 0); + + if (queue_mode != NULL_Q_MQ) + free_cmd(cmd); +} + +static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) +{ + struct completion_queue *cq; + struct llist_node *entry; + struct nullb_cmd *cmd; + + cq = &per_cpu(completion_queues, smp_processor_id()); + + while ((entry = llist_del_all(&cq->list)) != NULL) { + do { + cmd = container_of(entry, struct nullb_cmd, ll_list); + end_cmd(cmd); + entry = entry->next; + } while (entry); + } + + return HRTIMER_NORESTART; +} + +static void null_cmd_end_timer(struct nullb_cmd *cmd) +{ + struct completion_queue *cq = &per_cpu(completion_queues, get_cpu()); + + cmd->ll_list.next = NULL; + if (llist_add(&cmd->ll_list, &cq->list)) { + ktime_t kt = ktime_set(0, completion_nsec); + + hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL); + } + + put_cpu(); +} + +static void null_softirq_done_fn(struct request *rq) +{ + blk_end_request_all(rq, 0); +} + +#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS) + +static void null_ipi_cmd_end_io(void *data) +{ + struct completion_queue *cq; + struct llist_node *entry, *next; + struct nullb_cmd *cmd; + + cq = &per_cpu(completion_queues, smp_processor_id()); + + entry = llist_del_all(&cq->list); + + while (entry) { + next = entry->next; + cmd = llist_entry(entry, struct nullb_cmd, ll_list); + end_cmd(cmd); + entry = next; + } +} + +static void null_cmd_end_ipi(struct nullb_cmd *cmd) +{ + struct call_single_data *data = &cmd->csd; + int cpu = get_cpu(); + struct completion_queue *cq = &per_cpu(completion_queues, cpu); + + cmd->ll_list.next = NULL; + + if (llist_add(&cmd->ll_list, &cq->list)) { + data->func = null_ipi_cmd_end_io; + data->flags = 0; + __smp_call_function_single(cpu, data, 0); + } + + put_cpu(); +} + +#endif /* CONFIG_SMP && CONFIG_USE_GENERIC_SMP_HELPERS */ + +static inline void null_handle_cmd(struct nullb_cmd *cmd) +{ + /* Complete IO by inline, softirq or timer */ + switch (irqmode) { + case NULL_IRQ_NONE: + end_cmd(cmd); + break; + case NULL_IRQ_SOFTIRQ: +#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS) + null_cmd_end_ipi(cmd); +#else + end_cmd(cmd); +#endif + break; + case NULL_IRQ_TIMER: + null_cmd_end_timer(cmd); + break; + } +} + +static struct nullb_queue *nullb_to_queue(struct nullb *nullb) +{ + int index = 0; + + if (nullb->nr_queues != 1) + index = raw_smp_processor_id() / ((nr_cpu_ids + nullb->nr_queues - 1) / nullb->nr_queues); + + return &nullb->queues[index]; +} + +static void null_queue_bio(struct request_queue *q, struct bio *bio) +{ + struct nullb *nullb = q->queuedata; + struct nullb_queue *nq = nullb_to_queue(nullb); + struct nullb_cmd *cmd; + + cmd = alloc_cmd(nq, 1); + cmd->bio = bio; + + null_handle_cmd(cmd); +} + +static int null_rq_prep_fn(struct request_queue *q, struct request *req) +{ + struct nullb *nullb = q->queuedata; + struct nullb_queue *nq = nullb_to_queue(nullb); + struct nullb_cmd *cmd; + + cmd = alloc_cmd(nq, 0); + if (cmd) { + cmd->rq = req; + req->special = cmd; + return BLKPREP_OK; + } + + return BLKPREP_DEFER; +} + +static void null_request_fn(struct request_queue *q) +{ + struct request *rq; + + while ((rq = blk_fetch_request(q)) != NULL) { + struct nullb_cmd *cmd = rq->special; + + spin_unlock_irq(q->queue_lock); + null_handle_cmd(cmd); + spin_lock_irq(q->queue_lock); + } +} + +static int null_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq) +{ + struct nullb_cmd *cmd = rq->special; + + cmd->rq = rq; + cmd->nq = hctx->driver_data; + + null_handle_cmd(cmd); + return BLK_MQ_RQ_QUEUE_OK; +} + +static struct blk_mq_hw_ctx *null_alloc_hctx(struct blk_mq_reg *reg, unsigned int hctx_index) +{ + return kzalloc_node(sizeof(struct blk_mq_hw_ctx), GFP_KERNEL, + hctx_index); +} + +static void null_free_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_index) +{ + kfree(hctx); +} + +static int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, + unsigned int index) +{ + struct nullb *nullb = data; + struct nullb_queue *nq = &nullb->queues[index]; + + init_waitqueue_head(&nq->wait); + nq->queue_depth = nullb->queue_depth; + nullb->nr_queues++; + hctx->driver_data = nq; + + return 0; +} + +static struct blk_mq_ops null_mq_ops = { + .queue_rq = null_queue_rq, + .map_queue = blk_mq_map_queue, + .init_hctx = null_init_hctx, +}; + +static struct blk_mq_reg null_mq_reg = { + .ops = &null_mq_ops, + .queue_depth = 64, + .cmd_size = sizeof(struct nullb_cmd), + .flags = BLK_MQ_F_SHOULD_MERGE, +}; + +static void null_del_dev(struct nullb *nullb) +{ + list_del_init(&nullb->list); + + del_gendisk(nullb->disk); + if (queue_mode == NULL_Q_MQ) + blk_mq_free_queue(nullb->q); + else + blk_cleanup_queue(nullb->q); + put_disk(nullb->disk); + kfree(nullb); +} + +static int null_open(struct block_device *bdev, fmode_t mode) +{ + return 0; +} + +static void null_release(struct gendisk *disk, fmode_t mode) +{ +} + +static const struct block_device_operations null_fops = { + .owner = THIS_MODULE, + .open = null_open, + .release = null_release, +}; + +static int setup_commands(struct nullb_queue *nq) +{ + struct nullb_cmd *cmd; + int i, tag_size; + + nq->cmds = kzalloc(nq->queue_depth * sizeof(*cmd), GFP_KERNEL); + if (!nq->cmds) + return 1; + + tag_size = ALIGN(nq->queue_depth, BITS_PER_LONG) / BITS_PER_LONG; + nq->tag_map = kzalloc(tag_size * sizeof(unsigned long), GFP_KERNEL); + if (!nq->tag_map) { + kfree(nq->cmds); + return 1; + } + + for (i = 0; i < nq->queue_depth; i++) { + cmd = &nq->cmds[i]; + INIT_LIST_HEAD(&cmd->list); + cmd->ll_list.next = NULL; + cmd->tag = -1U; + } + + return 0; +} + +static void cleanup_queue(struct nullb_queue *nq) +{ + kfree(nq->tag_map); + kfree(nq->cmds); +} + +static void cleanup_queues(struct nullb *nullb) +{ + int i; + + for (i = 0; i < nullb->nr_queues; i++) + cleanup_queue(&nullb->queues[i]); + + kfree(nullb->queues); +} + +static int setup_queues(struct nullb *nullb) +{ + struct nullb_queue *nq; + int i; + + nullb->queues = kzalloc(submit_queues * sizeof(*nq), GFP_KERNEL); + if (!nullb->queues) + return 1; + + nullb->nr_queues = 0; + nullb->queue_depth = hw_queue_depth; + + if (queue_mode == NULL_Q_MQ) + return 0; + + for (i = 0; i < submit_queues; i++) { + nq = &nullb->queues[i]; + init_waitqueue_head(&nq->wait); + nq->queue_depth = hw_queue_depth; + if (setup_commands(nq)) + break; + nullb->nr_queues++; + } + + if (i == submit_queues) + return 0; + + cleanup_queues(nullb); + return 1; +} + +static int null_add_dev(void) +{ + struct gendisk *disk; + struct nullb *nullb; + sector_t size; + + nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, home_node); + if (!nullb) + return -ENOMEM; + + spin_lock_init(&nullb->lock); + + if (setup_queues(nullb)) + goto err; + + if (queue_mode == NULL_Q_MQ) { + null_mq_reg.numa_node = home_node; + null_mq_reg.queue_depth = hw_queue_depth; + + if (use_per_node_hctx) { + null_mq_reg.ops->alloc_hctx = null_alloc_hctx; + null_mq_reg.ops->free_hctx = null_free_hctx; + + null_mq_reg.nr_hw_queues = nr_online_nodes; + } else { + null_mq_reg.ops->alloc_hctx = blk_mq_alloc_single_hw_queue; + null_mq_reg.ops->free_hctx = blk_mq_free_single_hw_queue; + + null_mq_reg.nr_hw_queues = submit_queues; + } + + nullb->q = blk_mq_init_queue(&null_mq_reg, nullb); + } else if (queue_mode == NULL_Q_BIO) { + nullb->q = blk_alloc_queue_node(GFP_KERNEL, home_node); + blk_queue_make_request(nullb->q, null_queue_bio); + } else { + nullb->q = blk_init_queue_node(null_request_fn, &nullb->lock, home_node); + blk_queue_prep_rq(nullb->q, null_rq_prep_fn); + if (nullb->q) + blk_queue_softirq_done(nullb->q, null_softirq_done_fn); + } + + if (!nullb->q) + goto queue_fail; + + nullb->q->queuedata = nullb; + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q); + + disk = nullb->disk = alloc_disk_node(1, home_node); + if (!disk) { +queue_fail: + if (queue_mode == NULL_Q_MQ) + blk_mq_free_queue(nullb->q); + else + blk_cleanup_queue(nullb->q); + cleanup_queues(nullb); +err: + kfree(nullb); + return -ENOMEM; + } + + mutex_lock(&lock); + list_add_tail(&nullb->list, &nullb_list); + nullb->index = nullb_indexes++; + mutex_unlock(&lock); + + blk_queue_logical_block_size(nullb->q, bs); + blk_queue_physical_block_size(nullb->q, bs); + + size = gb * 1024 * 1024 * 1024ULL; + sector_div(size, bs); + set_capacity(disk, size); + + disk->flags |= GENHD_FL_EXT_DEVT; + disk->major = null_major; + disk->first_minor = nullb->index; + disk->fops = &null_fops; + disk->private_data = nullb; + disk->queue = nullb->q; + sprintf(disk->disk_name, "nullb%d", nullb->index); + add_disk(disk); + return 0; +} + +static int __init null_init(void) +{ + unsigned int i; + +#if !defined(CONFIG_SMP) || !defined(CONFIG_USE_GENERIC_SMP_HELPERS) + if (irqmode == NULL_IRQ_SOFTIRQ) { + pr_warn("null_blk: softirq completions not available.\n"); + pr_warn("null_blk: using direct completions.\n"); + irqmode = NULL_IRQ_NONE; + } +#endif + + if (submit_queues > nr_cpu_ids) + submit_queues = nr_cpu_ids; + else if (!submit_queues) + submit_queues = 1; + + mutex_init(&lock); + + /* Initialize a separate list for each CPU for issuing softirqs */ + for_each_possible_cpu(i) { + struct completion_queue *cq = &per_cpu(completion_queues, i); + + init_llist_head(&cq->list); + + if (irqmode != NULL_IRQ_TIMER) + continue; + + hrtimer_init(&cq->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + cq->timer.function = null_cmd_timer_expired; + } + + null_major = register_blkdev(0, "nullb"); + if (null_major < 0) + return null_major; + + for (i = 0; i < nr_devices; i++) { + if (null_add_dev()) { + unregister_blkdev(null_major, "nullb"); + return -EINVAL; + } + } + + pr_info("null: module loaded\n"); + return 0; +} + +static void __exit null_exit(void) +{ + struct nullb *nullb; + + unregister_blkdev(null_major, "nullb"); + + mutex_lock(&lock); + while (!list_empty(&nullb_list)) { + nullb = list_entry(nullb_list.next, struct nullb, list); + null_del_dev(nullb); + } + mutex_unlock(&lock); +} + +module_init(null_init); +module_exit(null_exit); + +MODULE_AUTHOR("Jens Axboe "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7f03b17d5c3f3b63dcacf0e481cf94c9d07267ab Mon Sep 17 00:00:00 2001 From: Heinz Graalfs Date: Tue, 29 Oct 2013 09:40:30 +1030 Subject: virtio_blk: verify if queue is broken after virtqueue_get_buf() In case virtqueue_get_buf() returned with a NULL pointer verify if the virtqueue is broken in order to leave while loop. Signed-off-by: Heinz Graalfs Signed-off-by: Rusty Russell --- drivers/block/virtio_blk.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6b66252fc4e6..f3be496ac8fa 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -292,6 +292,8 @@ static void virtblk_done(struct virtqueue *vq) req_done = true; } } + if (unlikely(virtqueue_is_broken(vq))) + break; } while (!virtqueue_enable_cb(vq)); /* In case queue is stopped waiting for more buffers. */ if (req_done) -- cgit v1.2.3 From 3ec981e30fae1f3c8728a05c730acaa1f627bcfb Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 14 Oct 2013 12:12:24 -0400 Subject: loop: fix crash if blk_alloc_queue fails loop: fix crash if blk_alloc_queue fails If blk_alloc_queue fails, loop_add cleans up, but it doesn't clean up the identifier allocated with idr_alloc. That causes crash on module unload in idr_for_each(&loop_index_idr, &loop_exit_cb, NULL); where we attempt to remove non-existed device with that id. BUG: unable to handle kernel NULL pointer dereference at 0000000000000380 IP: [] del_gendisk+0x19/0x2d0 PGD 43d399067 PUD 43d0ad067 PMD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: loop(-) dm_snapshot dm_zero dm_mirror dm_region_hash dm_log dm_loop dm_mod ip6table_filter ip6_tables uvesafb cfbcopyarea cfbimgblt cfbfillrect fbcon font bitblit fbcon_rotate fbcon_cw fbcon_ud fbcon_ccw softcursor fb fbdev msr ipt_MASQUERADE iptable_nat nf_nat_ipv4 nf_conntrack_ipv4 nf_defrag_ipv4 xt_state ipt_REJECT xt_tcpudp iptable_filter ip_tables x_tables bridge stp llc tun ipv6 cpufreq_userspace cpufreq_stats cpufreq_ondemand cpufreq_conservative cpufreq_powersave spadfs fuse hid_generic usbhid hid raid0 md_mod dmi_sysfs nf_nat_ftp nf_nat nf_conntrack_ftp nf_conntrack snd_usb_audio snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc lm85 hwmon_vid snd_hwdep snd_usbmidi_lib snd_rawmidi snd soundcore acpi_cpufreq ohci_hcd freq_table tg3 ehci_pci mperf ehci_hcd kvm_amd kvm sata_svw serverworks libphy libata ide_core k10temp usbcore hwmon microcode ptp pcspkr pps_core e100 skge mii usb_common i2c_piix4 floppy evdev rtc_cmos i2c_core processor but! ton unix CPU: 7 PID: 2735 Comm: rmmod Tainted: G W 3.10.15-devel #15 Hardware name: empty empty/S3992-E, BIOS 'V1.06 ' 06/09/2009 task: ffff88043d38e780 ti: ffff88043d21e000 task.ti: ffff88043d21e000 RIP: 0010:[] [] del_gendisk+0x19/0x2d0 RSP: 0018:ffff88043d21fe10 EFLAGS: 00010282 RAX: ffffffffa05102e0 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff88043ea82800 RDI: 0000000000000000 RBP: ffff88043d21fe48 R08: 0000000000000000 R09: 0000000000000001 R10: 0000000000000001 R11: 0000000000000000 R12: 00000000000000ff R13: 0000000000000080 R14: 0000000000000000 R15: ffff88043ea82800 FS: 00007ff646534700(0000) GS:ffff880447000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000380 CR3: 000000043e9bf000 CR4: 00000000000007e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffffffff8100aba4 0000000000000092 ffff88043d21fe48 ffff88043ea82800 00000000000000ff ffff88043d21fe98 0000000000000000 ffff88043d21fe60 ffffffffa05102b4 0000000000000000 ffff88043d21fe70 ffffffffa05102ec Call Trace: [] ? native_sched_clock+0x24/0x80 [] loop_remove+0x14/0x40 [loop] [] loop_exit_cb+0xc/0x10 [loop] [] idr_for_each+0x104/0x190 [] ? loop_remove+0x40/0x40 [loop] [] ? trace_hardirqs_on_caller+0x105/0x1d0 [] loop_exit+0x34/0xa58 [loop] [] SyS_delete_module+0x13a/0x260 [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x1a/0x1f Code: f0 4c 8b 6d f8 c9 c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 41 56 41 55 4c 8d af 80 00 00 00 41 54 53 48 89 fb 48 83 ec 18 <48> 83 bf 80 03 00 00 00 74 4d e8 98 fe ff ff 31 f6 48 c7 c7 20 RIP [] del_gendisk+0x19/0x2d0 RSP CR2: 0000000000000380 ---[ end trace 64ec069ec70f1309 ]--- Signed-off-by: Mikulas Patocka Acked-by: Tejun Heo Cc: stable@kernel.org # 3.1+ Signed-off-by: Jens Axboe --- drivers/block/loop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 40e715531aa6..de7f4563d1e1 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1633,7 +1633,7 @@ static int loop_add(struct loop_device **l, int i) err = -ENOMEM; lo->lo_queue = blk_alloc_queue(GFP_KERNEL); if (!lo->lo_queue) - goto out_free_dev; + goto out_free_idr; disk = lo->lo_disk = alloc_disk(1 << part_shift); if (!disk) @@ -1678,6 +1678,8 @@ static int loop_add(struct loop_device **l, int i) out_free_queue: blk_cleanup_queue(lo->lo_queue); +out_free_idr: + idr_remove(&loop_index_idr, i); out_free_dev: kfree(lo); out: -- cgit v1.2.3 From a207f5937630dd35bd2550620bef416937a1365e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 14 Oct 2013 12:13:24 -0400 Subject: block: fix a probe argument to blk_register_region The probe function is supposed to return NULL on failure (as we can see in kobj_lookup: kobj = probe(dev, index, data); ... if (kobj) return kobj; However, in loop and brd, it returns negative error from ERR_PTR. This causes a crash if we simulate disk allocation failure and run less -f /dev/loop0 because the negative number is interpreted as a pointer: BUG: unable to handle kernel NULL pointer dereference at 00000000000002b4 IP: [] __blkdev_get+0x28/0x450 PGD 23c677067 PUD 23d6d1067 PMD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: loop hpfs nvidia(PO) ip6table_filter ip6_tables uvesafb cfbcopyarea cfbimgblt cfbfillrect fbcon font bitblit fbcon_rotate fbcon_cw fbcon_ud fbcon_ccw softcursor fb fbdev msr ipt_MASQUERADE iptable_nat nf_nat_ipv4 nf_conntrack_ipv4 nf_defrag_ipv4 xt_state ipt_REJECT xt_tcpudp iptable_filter ip_tables x_tables bridge stp llc tun ipv6 cpufreq_stats cpufreq_ondemand cpufreq_userspace cpufreq_powersave cpufreq_conservative hid_generic spadfs usbhid hid fuse raid0 snd_usb_audio snd_pcm_oss snd_mixer_oss md_mod snd_pcm snd_timer snd_page_alloc snd_hwdep snd_usbmidi_lib dmi_sysfs snd_rawmidi nf_nat_ftp nf_nat nf_conntrack_ftp nf_conntrack snd soundcore lm85 hwmon_vid ohci_hcd ehci_pci ehci_hcd serverworks sata_svw libata acpi_cpufreq freq_table mperf ide_core usbcore kvm_amd kvm tg3 i2c_piix4 libphy microcode e100 usb_common ptp skge i2c_core pcspkr k10temp evdev floppy hwmon pps_core mii rtc_cmos button processor unix [last unloaded: nvidia] CPU: 1 PID: 6831 Comm: less Tainted: P W O 3.10.15-devel #18 Hardware name: empty empty/S3992-E, BIOS 'V1.06 ' 06/09/2009 task: ffff880203cc6bc0 ti: ffff88023e47c000 task.ti: ffff88023e47c000 RIP: 0010:[] [] __blkdev_get+0x28/0x450 RSP: 0018:ffff88023e47dbd8 EFLAGS: 00010286 RAX: ffffffffffffff74 RBX: ffffffffffffff74 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000001 RBP: ffff88023e47dc18 R08: 0000000000000002 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff88023f519658 R13: ffffffff8118c300 R14: 0000000000000000 R15: ffff88023f519640 FS: 00007f2070bf7700(0000) GS:ffff880247400000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000000002b4 CR3: 000000023da1d000 CR4: 00000000000007e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: 0000000000000002 0000001d00000000 000000003e47dc50 ffff88023f519640 ffff88043d5bb668 ffffffff8118c300 ffff88023d683550 ffff88023e47de60 ffff88023e47dc98 ffffffff8118c10d 0000001d81605698 0000000000000292 Call Trace: [] ? blkdev_get_by_dev+0x60/0x60 [] blkdev_get+0x1dd/0x370 [] ? blkdev_get_by_dev+0x60/0x60 [] ? _raw_spin_unlock+0x2c/0x50 [] ? blkdev_get_by_dev+0x60/0x60 [] blkdev_open+0x65/0x80 [] do_dentry_open.isra.18+0x23e/0x2f0 [] finish_open+0x34/0x50 [] do_last.isra.62+0x2d2/0xc50 [] path_openat.isra.63+0xb8/0x4d0 [] ? might_fault+0x4e/0xa0 [] do_filp_open+0x40/0x90 [] ? _raw_spin_unlock+0x2c/0x50 [] ? __alloc_fd+0xa5/0x1f0 [] do_sys_open+0xef/0x1d0 [] SyS_open+0x19/0x20 [] system_call_fastpath+0x1a/0x1f Code: 44 00 00 55 48 89 e5 41 57 49 89 ff 41 56 41 89 d6 41 55 41 54 4c 8d 67 18 53 48 83 ec 18 89 75 cc e9 f2 00 00 00 0f 1f 44 00 00 <48> 8b 80 40 03 00 00 48 89 df 4c 8b 68 58 e8 d5 a4 07 00 44 89 RIP [] __blkdev_get+0x28/0x450 RSP CR2: 00000000000002b4 ---[ end trace bb7f32dbf02398dc ]--- The brd change should be backported to stable kernels starting with 2.6.25. The loop change should be backported to stable kernels starting with 2.6.22. Signed-off-by: Mikulas Patocka Acked-by: Tejun Heo Cc: stable@kernel.org # 2.6.22+ Signed-off-by: Jens Axboe --- drivers/block/brd.c | 2 +- drivers/block/loop.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 9bf4371755f2..d91f1a56e861 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -545,7 +545,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data) mutex_lock(&brd_devices_mutex); brd = brd_init_one(MINOR(dev) >> part_shift); - kobj = brd ? get_disk(brd->brd_disk) : ERR_PTR(-ENOMEM); + kobj = brd ? get_disk(brd->brd_disk) : NULL; mutex_unlock(&brd_devices_mutex); *part = 0; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index de7f4563d1e1..dbdb88a4976c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1743,7 +1743,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data) if (err < 0) err = loop_add(&lo, MINOR(dev) >> part_shift); if (err < 0) - kobj = ERR_PTR(err); + kobj = NULL; else kobj = get_disk(lo->lo_disk); mutex_unlock(&loop_index_mutex); -- cgit v1.2.3 From 6678d83f18386eb103f8345024e52c5abe61725c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 11:14:32 -0700 Subject: block: Consolidate duplicated bio_trim() implementations Someone cut and pasted md's md_trim_bio() into xen-blkfront.c. Come on, we should know better than this. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Neil Brown Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Signed-off-by: Jens Axboe --- drivers/block/xen-blkfront.c | 53 +------------------------------------------- drivers/md/md.c | 40 --------------------------------- drivers/md/md.h | 1 - drivers/md/raid1.c | 10 ++++----- drivers/md/raid10.c | 18 +++++++-------- fs/bio.c | 46 ++++++++++++++++++++++++++++++++++++++ include/linux/bio.h | 1 + 7 files changed, 61 insertions(+), 108 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index a4660bbee8a6..8d53ed293606 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1336,57 +1336,6 @@ static int blkfront_probe(struct xenbus_device *dev, return 0; } -/* - * This is a clone of md_trim_bio, used to split a bio into smaller ones - */ -static void trim_bio(struct bio *bio, int offset, int size) -{ - /* 'bio' is a cloned bio which we need to trim to match - * the given offset and size. - * This requires adjusting bi_sector, bi_size, and bi_io_vec - */ - int i; - struct bio_vec *bvec; - int sofar = 0; - - size <<= 9; - if (offset == 0 && size == bio->bi_size) - return; - - bio->bi_sector += offset; - bio->bi_size = size; - offset <<= 9; - clear_bit(BIO_SEG_VALID, &bio->bi_flags); - - while (bio->bi_idx < bio->bi_vcnt && - bio->bi_io_vec[bio->bi_idx].bv_len <= offset) { - /* remove this whole bio_vec */ - offset -= bio->bi_io_vec[bio->bi_idx].bv_len; - bio->bi_idx++; - } - if (bio->bi_idx < bio->bi_vcnt) { - bio->bi_io_vec[bio->bi_idx].bv_offset += offset; - bio->bi_io_vec[bio->bi_idx].bv_len -= offset; - } - /* avoid any complications with bi_idx being non-zero*/ - if (bio->bi_idx) { - memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx, - (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec)); - bio->bi_vcnt -= bio->bi_idx; - bio->bi_idx = 0; - } - /* Make sure vcnt and last bv are not too big */ - bio_for_each_segment(bvec, bio, i) { - if (sofar + bvec->bv_len > size) - bvec->bv_len = size - sofar; - if (bvec->bv_len == 0) { - bio->bi_vcnt = i; - break; - } - sofar += bvec->bv_len; - } -} - static void split_bio_end(struct bio *bio, int error) { struct split_bio *split_bio = bio->bi_private; @@ -1522,7 +1471,7 @@ static int blkif_recover(struct blkfront_info *info) (unsigned int)(bio->bi_size >> 9) - offset); cloned_bio = bio_clone(bio, GFP_NOIO); BUG_ON(cloned_bio == NULL); - trim_bio(cloned_bio, offset, size); + bio_trim(cloned_bio, offset, size); cloned_bio->bi_private = split_bio; cloned_bio->bi_end_io = split_bio_end; submit_bio(cloned_bio->bi_rw, cloned_bio); diff --git a/drivers/md/md.c b/drivers/md/md.c index 561a65f82e26..752119068d66 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -183,46 +183,6 @@ struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, } EXPORT_SYMBOL_GPL(bio_clone_mddev); -void md_trim_bio(struct bio *bio, int offset, int size) -{ - /* 'bio' is a cloned bio which we need to trim to match - * the given offset and size. - * This requires adjusting bi_sector, bi_size, and bi_io_vec - */ - int i; - struct bio_vec *bvec; - int sofar = 0; - - size <<= 9; - if (offset == 0 && size == bio->bi_size) - return; - - clear_bit(BIO_SEG_VALID, &bio->bi_flags); - - bio_advance(bio, offset << 9); - - bio->bi_size = size; - - /* avoid any complications with bi_idx being non-zero*/ - if (bio->bi_idx) { - memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx, - (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec)); - bio->bi_vcnt -= bio->bi_idx; - bio->bi_idx = 0; - } - /* Make sure vcnt and last bv are not too big */ - bio_for_each_segment(bvec, bio, i) { - if (sofar + bvec->bv_len > size) - bvec->bv_len = size - sofar; - if (bvec->bv_len == 0) { - bio->bi_vcnt = i; - break; - } - sofar += bvec->bv_len; - } -} -EXPORT_SYMBOL_GPL(md_trim_bio); - /* * We have a system wide 'event count' that is incremented * on any 'interesting' event, and readers of /proc/mdstat diff --git a/drivers/md/md.h b/drivers/md/md.h index 608050c43f17..c96456c16700 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -617,7 +617,6 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, struct mddev *mddev); extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, struct mddev *mddev); -extern void md_trim_bio(struct bio *bio, int offset, int size); extern void md_unplug(struct blk_plug_cb *cb, bool from_schedule); static inline int mddev_check_plugged(struct mddev *mddev) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index aacf6bf352d8..af6681b19776 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1097,8 +1097,8 @@ read_again: r1_bio->read_disk = rdisk; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(read_bio, r1_bio->sector - bio->bi_sector, - max_sectors); + bio_trim(read_bio, r1_bio->sector - bio->bi_sector, + max_sectors); r1_bio->bios[rdisk] = read_bio; @@ -1266,7 +1266,7 @@ read_again: continue; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(mbio, r1_bio->sector - bio->bi_sector, max_sectors); if (first_clone) { /* do behind I/O ? @@ -2126,7 +2126,7 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) wbio->bi_sector = r1_bio->sector; wbio->bi_size = r1_bio->sectors << 9; - md_trim_bio(wbio, sector - r1_bio->sector, sectors); + bio_trim(wbio, sector - r1_bio->sector, sectors); wbio->bi_sector += rdev->data_offset; wbio->bi_bdev = rdev->bdev; if (submit_bio_wait(WRITE, wbio) == 0) @@ -2241,7 +2241,7 @@ read_more: } r1_bio->read_disk = disk; bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev); - md_trim_bio(bio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(bio, r1_bio->sector - bio->bi_sector, max_sectors); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; printk_ratelimited(KERN_ERR diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 73dc8a377522..7c3508abb5e1 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1302,8 +1302,8 @@ read_again: slot = r10_bio->read_slot; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(read_bio, r10_bio->sector - bio->bi_sector, - max_sectors); + bio_trim(read_bio, r10_bio->sector - bio->bi_sector, + max_sectors); r10_bio->devs[slot].bio = read_bio; r10_bio->devs[slot].rdev = rdev; @@ -1510,8 +1510,8 @@ retry_write: if (r10_bio->devs[i].bio) { struct md_rdev *rdev = conf->mirrors[d].rdev; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); + bio_trim(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); r10_bio->devs[i].bio = mbio; mbio->bi_sector = (r10_bio->devs[i].addr+ @@ -1553,8 +1553,8 @@ retry_write: rdev = conf->mirrors[d].rdev; } mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); + bio_trim(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); r10_bio->devs[i].repl_bio = mbio; mbio->bi_sector = (r10_bio->devs[i].addr + @@ -2614,7 +2614,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) sectors = sect_to_write; /* Write at 'sector' for 'sectors' */ wbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(wbio, sector - bio->bi_sector, sectors); + bio_trim(wbio, sector - bio->bi_sector, sectors); wbio->bi_sector = (r10_bio->devs[i].addr+ choose_data_offset(r10_bio, rdev) + (sector - r10_bio->sector)); @@ -2687,9 +2687,7 @@ read_more: (unsigned long long)r10_bio->sector); bio = bio_clone_mddev(r10_bio->master_bio, GFP_NOIO, mddev); - md_trim_bio(bio, - r10_bio->sector - bio->bi_sector, - max_sectors); + bio_trim(bio, r10_bio->sector - bio->bi_sector, max_sectors); r10_bio->devs[slot].bio = bio; r10_bio->devs[slot].rdev = rdev; bio->bi_sector = r10_bio->devs[slot].addr diff --git a/fs/bio.c b/fs/bio.c index ea5035da4d9a..2bdb4e25ee77 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1804,6 +1804,52 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) } EXPORT_SYMBOL(bio_split); +/** + * bio_trim - trim a bio + * @bio: bio to trim + * @offset: number of sectors to trim from the front of @bio + * @size: size we want to trim @bio to, in sectors + */ +void bio_trim(struct bio *bio, int offset, int size) +{ + /* 'bio' is a cloned bio which we need to trim to match + * the given offset and size. + * This requires adjusting bi_sector, bi_size, and bi_io_vec + */ + int i; + struct bio_vec *bvec; + int sofar = 0; + + size <<= 9; + if (offset == 0 && size == bio->bi_size) + return; + + clear_bit(BIO_SEG_VALID, &bio->bi_flags); + + bio_advance(bio, offset << 9); + + bio->bi_size = size; + + /* avoid any complications with bi_idx being non-zero*/ + if (bio->bi_idx) { + memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx, + (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec)); + bio->bi_vcnt -= bio->bi_idx; + bio->bi_idx = 0; + } + /* Make sure vcnt and last bv are not too big */ + bio_for_each_segment(bvec, bio, i) { + if (sofar + bvec->bv_len > size) + bvec->bv_len = size - sofar; + if (bvec->bv_len == 0) { + bio->bi_vcnt = i; + break; + } + sofar += bvec->bv_len; + } +} +EXPORT_SYMBOL_GPL(bio_trim); + /** * bio_sector_offset - Find hardware sector offset in bio * @bio: bio to inspect diff --git a/include/linux/bio.h b/include/linux/bio.h index ec48bac5b039..162036aca741 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -218,6 +218,7 @@ struct bio_pair { }; extern struct bio_pair *bio_split(struct bio *bi, int first_sectors); extern void bio_pair_release(struct bio_pair *dbio); +extern void bio_trim(struct bio *bio, int offset, int size); extern struct bio_set *bioset_create(unsigned int, unsigned int); extern void bioset_free(struct bio_set *); -- cgit v1.2.3 From 370d6686683f44b6e869210eea2cf6a905b38a55 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Sat, 12 Oct 2013 06:33:47 +0200 Subject: mg_disk: remove deprecated IRQF_DISABLED This patch proposes to remove the use of the IRQF_DISABLED flag It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Jens Axboe --- drivers/block/mg_disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 77a60bedd7a3..7bc363f1ee82 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -936,7 +936,7 @@ static int mg_probe(struct platform_device *plat_dev) goto probe_err_3b; } err = request_irq(host->irq, mg_irq, - IRQF_DISABLED | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING, MG_DEV_NAME, host); if (err) { printk(KERN_ERR "%s:%d fail (request_irq err=%d)\n", -- cgit v1.2.3 From fbe363c476afe8ec992d3baf682670a4bd1b6ce6 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 12 Aug 2013 12:53:44 +0200 Subject: xen-blkfront: revoke foreign access for grants not mapped by the backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to keep the foreign access in a grant if it is not persistently mapped by the backend. This allows us to free grants that are not mapped by the backend, thus preventing blkfront from hoarding all grants. The main effect of this is that blkfront will only persistently map the same grants as the backend, and it will always try to use grants that are already mapped by the backend. Also the number of persistent grants in blkfront is the same as in blkback (and is controlled by the value in blkback). Signed-off-by: Roger Pau MonnĂ© Reviewed-by: David Vrabel Acked-by: Matt Wilson Cc: Konrad Rzeszutek Wilk Cc: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Jens Axboe --- drivers/block/xen-blkfront.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 8d53ed293606..429d52640940 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1013,13 +1013,38 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, } /* Add the persistent grant into the list of free grants */ for (i = 0; i < nseg; i++) { - list_add(&s->grants_used[i]->node, &info->persistent_gnts); - info->persistent_gnts_c++; + if (gnttab_query_foreign_access(s->grants_used[i]->gref)) { + /* + * If the grant is still mapped by the backend (the + * backend has chosen to make this grant persistent) + * we add it at the head of the list, so it will be + * reused first. + */ + list_add(&s->grants_used[i]->node, &info->persistent_gnts); + info->persistent_gnts_c++; + } else { + /* + * If the grant is not mapped by the backend we end the + * foreign access and add it to the tail of the list, + * so it will not be picked again unless we run out of + * persistent grants. + */ + gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL); + s->grants_used[i]->gref = GRANT_INVALID_REF; + list_add_tail(&s->grants_used[i]->node, &info->persistent_gnts); + } } if (s->req.operation == BLKIF_OP_INDIRECT) { for (i = 0; i < INDIRECT_GREFS(nseg); i++) { - list_add(&s->indirect_grants[i]->node, &info->persistent_gnts); - info->persistent_gnts_c++; + if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) { + list_add(&s->indirect_grants[i]->node, &info->persistent_gnts); + info->persistent_gnts_c++; + } else { + gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL); + s->indirect_grants[i]->gref = GRANT_INVALID_REF; + list_add_tail(&s->indirect_grants[i]->node, + &info->persistent_gnts); + } } } } -- cgit v1.2.3 From c47206e25f28232ff979994c32758c82841d81cd Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 12 Aug 2013 12:53:43 +0200 Subject: xen-blkfront: improve aproximation of required grants per request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve the calculation of required grants to process a request by using nr_phys_segments instead of always assuming a request is going to use all posible segments. nr_phys_segments contains the number of scatter-gather DMA addr+len pairs, which is basically what we put at every granted page. for_each_sg iterates over the DMA addr+len pairs and uses a grant page for each of them. Signed-off-by: Roger Pau MonnĂ© Reviewed-by: David Vrabel Cc: Konrad Rzeszutek Wilk Cc: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Jens Axboe --- drivers/block/xen-blkfront.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 429d52640940..5b8a15483a4c 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -400,10 +400,13 @@ static int blkif_queue_request(struct request *req) if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) return 1; - max_grefs = info->max_indirect_segments ? - info->max_indirect_segments + - INDIRECT_GREFS(info->max_indirect_segments) : - BLKIF_MAX_SEGMENTS_PER_REQUEST; + max_grefs = req->nr_phys_segments; + if (max_grefs > BLKIF_MAX_SEGMENTS_PER_REQUEST) + /* + * If we are using indirect segments we need to account + * for the indirect grefs used in the request. + */ + max_grefs += INDIRECT_GREFS(req->nr_phys_segments); /* Check if we have enough grants to allocate a requests */ if (info->persistent_gnts_c < max_grefs) { -- cgit v1.2.3 From ea5ec76d76da9279d12027c1828544c5ccbe7932 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 5 Sep 2013 13:00:14 +0200 Subject: xen/blkback: fix reference counting If the permission check fails, we drop a reference to the blkif without having taken it in the first place. The bug was introduced in commit 604c499cbbcc3d5fe5fb8d53306aa0fae1990109 (xen/blkback: Check device permissions before allowing OP_DISCARD). Cc: stable@vger.kernel.org Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Signed-off-by: Vegard Nossum Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Jens Axboe --- drivers/block/xen-blkback/blkback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index bf4b9d282c04..6620b73d0490 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -887,6 +887,8 @@ static int dispatch_discard_io(struct xen_blkif *blkif, unsigned long secure; struct phys_req preq; + xen_blkif_get(blkif); + preq.sector_number = req->u.discard.sector_number; preq.nr_sects = req->u.discard.nr_sectors; @@ -899,7 +901,6 @@ static int dispatch_discard_io(struct xen_blkif *blkif, } blkif->st_ds_req++; - xen_blkif_get(blkif); secure = (blkif->vbd.discard_secure && (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? BLKDEV_DISCARD_SECURE : 0; -- cgit v1.2.3 From ef7e7c82e02b602f29c2b87f42dcd6143a6777da Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 15 Oct 2013 14:14:38 -0600 Subject: loop: fix crash when using unassigned loop device When the loop module is loaded, it creates 8 loop devices /dev/loop[0-7]. The devices have no request routine and thus, when they are used without being assigned, a crash happens. For example, these commands cause crash (assuming there are no used loop devices): Kernel Fault: Code=26 regs=000000007f420980 (Addr=0000000000000010) CPU: 1 PID: 50 Comm: kworker/1:1 Not tainted 3.11.0 #1 Workqueue: ksnaphd do_metadata [dm_snapshot] task: 000000007fcf4078 ti: 000000007f420000 task.ti: 000000007f420000 [ 116.319988] YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI PSW: 00001000000001001111111100001111 Not tainted r00-03 000000ff0804ff0f 00000000408bf5d0 00000000402d8204 000000007b7ff6c0 r04-07 00000000408a95d0 000000007f420950 000000007b7ff6c0 000000007d06c930 r08-11 000000007f4205c0 0000000000000001 000000007f4205c0 000000007f4204b8 r12-15 0000000000000010 0000000000000000 0000000000000000 0000000000000000 r16-19 000000001108dd48 000000004061cd7c 000000007d859800 000000000800000f r20-23 0000000000000000 0000000000000008 0000000000000000 0000000000000000 r24-27 00000000ffffffff 000000007b7ff6c0 000000007d859800 00000000408a95d0 r28-31 0000000000000000 000000007f420950 000000007f420980 000000007f4208e8 sr00-03 0000000000000000 0000000000000000 0000000000000000 0000000000303000 sr04-07 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 117.549988] IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000402d82fc 00000000402d8300 IIR: 53820020 ISR: 0000000000000000 IOR: 0000000000000010 CPU: 1 CR30: 000000007f420000 CR31: ffffffffffffffff ORIG_R28: 0000000000000001 IAOQ[0]: generic_make_request+0x11c/0x1a0 IAOQ[1]: generic_make_request+0x120/0x1a0 RP(r2): generic_make_request+0x24/0x1a0 Backtrace: [<00000000402d83f0>] submit_bio+0x70/0x140 [<0000000011087c4c>] dispatch_io+0x234/0x478 [dm_mod] [<0000000011087f44>] sync_io+0xb4/0x190 [dm_mod] [<00000000110883bc>] dm_io+0x2c4/0x310 [dm_mod] [<00000000110bfcd0>] do_metadata+0x28/0xb0 [dm_snapshot] [<00000000401591d8>] process_one_work+0x160/0x460 [<0000000040159bc0>] worker_thread+0x300/0x478 [<0000000040161a70>] kthread+0x118/0x128 [<0000000040104020>] end_fault_vector+0x20/0x28 [<0000000040177220>] task_tick_fair+0x420/0x4d0 [<00000000401aa048>] invoke_rcu_core+0x50/0x60 [<00000000401ad5b8>] rcu_check_callbacks+0x210/0x8d8 [<000000004014aaa0>] update_process_times+0xa8/0xc0 [<00000000401ab86c>] rcu_process_callbacks+0x4b4/0x598 [<0000000040142408>] __do_softirq+0x250/0x2c0 [<00000000401789d0>] find_busiest_group+0x3c0/0xc70 [ 119.379988] Kernel panic - not syncing: Kernel Fault Rebooting in 1 seconds.. Signed-off-by: Mikulas Patocka Cc: stable@kernel.org Signed-off-by: Jens Axboe --- drivers/block/loop.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index dbdb88a4976c..c8dac7305244 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -894,13 +894,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, bio_list_init(&lo->lo_bio_list); - /* - * set queue make_request_fn, and add limits based on lower level - * device - */ - blk_queue_make_request(lo->lo_queue, loop_make_request); - lo->lo_queue->queuedata = lo; - if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync) blk_queue_flush(lo->lo_queue, REQ_FLUSH); @@ -1618,6 +1611,8 @@ static int loop_add(struct loop_device **l, int i) if (!lo) goto out; + lo->lo_state = Lo_unbound; + /* allocate id, if @id >= 0, we're requesting that specific id */ if (i >= 0) { err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL); @@ -1635,6 +1630,12 @@ static int loop_add(struct loop_device **l, int i) if (!lo->lo_queue) goto out_free_idr; + /* + * set queue make_request_fn + */ + blk_queue_make_request(lo->lo_queue, loop_make_request); + lo->lo_queue->queuedata = lo; + disk = lo->lo_disk = alloc_disk(1 << part_shift); if (!disk) goto out_free_queue; -- cgit v1.2.3 From e5feab229f199dadee91073fbef5b507046086fd Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Wed, 4 Sep 2013 13:59:02 -0500 Subject: rsxx: Handling failed pci_map_page on PowerPC and double free. The rsxx driver was not checking the correct value during a pci_map_page failure. Fixing this also uncovered a double free if the bio was returned before it was broken up into indiviadual 4k dmas, that is also fixed here. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/core.c | 3 ++- drivers/block/rsxx/dma.c | 47 ++++++++++++++++++++++++------------------ drivers/block/rsxx/rsxx_priv.h | 9 +++++++- 3 files changed, 37 insertions(+), 22 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index 6e85e21445eb..e740a650d546 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -654,7 +654,8 @@ static void rsxx_eeh_failure(struct pci_dev *dev) for (i = 0; i < card->n_targets; i++) { spin_lock_bh(&card->ctrl[i].queue_lock); cnt = rsxx_cleanup_dma_queue(&card->ctrl[i], - &card->ctrl[i].queue); + &card->ctrl[i].queue, + COMPLETE_DMA); spin_unlock_bh(&card->ctrl[i].queue_lock); cnt += rsxx_dma_cancel(&card->ctrl[i]); diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index bed32f16b084..71d1ca2a1444 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -221,6 +221,19 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) } /*----------------- RSXX DMA Handling -------------------*/ +static void rsxx_free_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma) +{ + if (!pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { + pci_unmap_page(ctrl->card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + } + + kmem_cache_free(rsxx_dma_pool, dma); +} + static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma, unsigned int status) @@ -232,21 +245,14 @@ static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl, if (status & DMA_CANCELLED) ctrl->stats.dma_cancelled++; - if (dma->dma_addr) - pci_unmap_page(ctrl->card->dev, dma->dma_addr, - get_dma_size(dma), - dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); - if (dma->cb) dma->cb(ctrl->card, dma->cb_data, status ? 1 : 0); - kmem_cache_free(rsxx_dma_pool, dma); + rsxx_free_dma(ctrl, dma); } int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, - struct list_head *q) + struct list_head *q, unsigned int done) { struct rsxx_dma *dma; struct rsxx_dma *tmp; @@ -254,7 +260,10 @@ int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, list_for_each_entry_safe(dma, tmp, q, list) { list_del(&dma->list); - rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); + if (done & COMPLETE_DMA) + rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); + else + rsxx_free_dma(ctrl, dma); cnt++; } @@ -370,7 +379,7 @@ static void dma_engine_stalled(unsigned long data) /* Clean up the DMA queue */ spin_lock(&ctrl->queue_lock); - cnt = rsxx_cleanup_dma_queue(ctrl, &ctrl->queue); + cnt = rsxx_cleanup_dma_queue(ctrl, &ctrl->queue, COMPLETE_DMA); spin_unlock(&ctrl->queue_lock); cnt += rsxx_dma_cancel(ctrl); @@ -623,7 +632,7 @@ static int rsxx_queue_dma(struct rsxx_cardinfo *card, dma->dma_addr = pci_map_page(card->dev, page, pg_off, dma_len, dir ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (!dma->dma_addr) { + if (pci_dma_mapping_error(card->dev, dma->dma_addr)) { kmem_cache_free(rsxx_dma_pool, dma); return -ENOMEM; } @@ -736,11 +745,9 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, return 0; bvec_err: - for (i = 0; i < card->n_targets; i++) { - spin_lock_bh(&card->ctrl[i].queue_lock); - rsxx_cleanup_dma_queue(&card->ctrl[i], &dma_list[i]); - spin_unlock_bh(&card->ctrl[i].queue_lock); - } + for (i = 0; i < card->n_targets; i++) + rsxx_cleanup_dma_queue(&card->ctrl[i], &dma_list[i], + FREE_DMA); return st; } @@ -990,7 +997,7 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card) /* Clean up the DMA queue */ spin_lock_bh(&ctrl->queue_lock); - rsxx_cleanup_dma_queue(ctrl, &ctrl->queue); + rsxx_cleanup_dma_queue(ctrl, &ctrl->queue, COMPLETE_DMA); spin_unlock_bh(&ctrl->queue_lock); rsxx_dma_cancel(ctrl); @@ -1045,7 +1052,7 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) card->ctrl[i].e_cnt = 0; list_for_each_entry(dma, &card->ctrl[i].queue, list) { - if (dma->dma_addr) + if (!pci_dma_mapping_error(card->dev, dma->dma_addr)) pci_unmap_page(card->dev, dma->dma_addr, get_dma_size(dma), dma->cmd == HW_CMD_BLK_WRITE ? @@ -1073,7 +1080,7 @@ int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) dma->cmd == HW_CMD_BLK_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (!dma->dma_addr) { + if (pci_dma_mapping_error(card->dev, dma->dma_addr)) { spin_unlock_bh(&card->ctrl[i].queue_lock); kmem_cache_free(rsxx_dma_pool, dma); return -ENOMEM; diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index 5ad5055a4104..82779058e8ec 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -345,6 +345,11 @@ enum rsxx_creg_stat { CREG_STAT_TAG_MASK = 0x0000ff00, }; +enum rsxx_dma_finish { + FREE_DMA = 0x0, + COMPLETE_DMA = 0x1, +}; + static inline unsigned int CREG_DATA(int N) { return CREG_DATA0 + (N << 2); @@ -379,7 +384,9 @@ typedef void (*rsxx_dma_cb)(struct rsxx_cardinfo *card, int rsxx_dma_setup(struct rsxx_cardinfo *card); void rsxx_dma_destroy(struct rsxx_cardinfo *card); int rsxx_dma_init(void); -int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, struct list_head *q); +int rsxx_cleanup_dma_queue(struct rsxx_dma_ctrl *ctrl, + struct list_head *q, + unsigned int done); int rsxx_dma_cancel(struct rsxx_dma_ctrl *ctrl); void rsxx_dma_cleanup(void); void rsxx_dma_queue_reset(struct rsxx_cardinfo *card); -- cgit v1.2.3 From 1b21f5b2ad6047995b19b15024353a9fa64810f1 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Wed, 4 Sep 2013 13:59:35 -0500 Subject: rsxx: Moving pci_map_page to prevent overflow. The pci_map_page function has been moved into our issued workqueue to prevent an us running out of mappable addresses on non-HWWD PCIe x8 slots. The maximum amount that can possible be mapped at one time now is: 255 dmas X 4 dma channels X 4096 Bytes. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/core.c | 5 ---- drivers/block/rsxx/dma.c | 70 +++++++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 47 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index e740a650d546..a8de2eec6ff3 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -749,10 +749,6 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev) card->eeh_state = 0; - st = rsxx_eeh_remap_dmas(card); - if (st) - goto failed_remap_dmas; - spin_lock_irqsave(&card->irq_lock, flags); if (card->n_targets & RSXX_MAX_TARGETS) rsxx_enable_ier_and_isr(card, CR_INTR_ALL_G); @@ -779,7 +775,6 @@ static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev) return PCI_ERS_RESULT_RECOVERED; failed_hw_buffers_init: -failed_remap_dmas: for (i = 0; i < card->n_targets; i++) { if (card->ctrl[i].status.buf) pci_free_consistent(card->dev, diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 71d1ca2a1444..34fd1018c8e5 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -397,6 +397,7 @@ static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl) int tag; int cmds_pending = 0; struct hw_cmd *hw_cmd_buf; + int dir; hw_cmd_buf = ctrl->cmd.buf; @@ -433,6 +434,28 @@ static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl) continue; } + if (dma->cmd == HW_CMD_BLK_WRITE) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + /* + * The function pci_map_page is placed here because we can + * only, by design, issue up to 255 commands to the hardware + * at one time per DMA channel. So the maximum amount of mapped + * memory would be 255 * 4 channels * 4096 Bytes which is less + * than 2GB, the limit of a x8 Non-HWWD PCIe slot. This way the + * pci_map_page function should never fail because of a + * lack of mappable memory. + */ + dma->dma_addr = pci_map_page(ctrl->card->dev, dma->page, + dma->pg_off, dma->sub_page.cnt << 9, dir); + if (pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { + push_tracker(ctrl->trackers, tag); + rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); + continue; + } + set_tracker_dma(ctrl->trackers, tag, dma); hw_cmd_buf[ctrl->cmd.idx].command = dma->cmd; hw_cmd_buf[ctrl->cmd.idx].tag = tag; @@ -629,14 +652,6 @@ static int rsxx_queue_dma(struct rsxx_cardinfo *card, if (!dma) return -ENOMEM; - dma->dma_addr = pci_map_page(card->dev, page, pg_off, dma_len, - dir ? PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(card->dev, dma->dma_addr)) { - kmem_cache_free(rsxx_dma_pool, dma); - return -ENOMEM; - } - dma->cmd = dir ? HW_CMD_BLK_WRITE : HW_CMD_BLK_READ; dma->laddr = laddr; dma->sub_page.off = (dma_off >> 9); @@ -1039,6 +1054,11 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) else card->ctrl[i].stats.reads_issued--; + pci_unmap_page(card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); list_add_tail(&dma->list, &issued_dmas[i]); push_tracker(card->ctrl[i].trackers, j); cnt++; @@ -1050,15 +1070,6 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth); card->ctrl[i].stats.sw_q_depth += cnt; card->ctrl[i].e_cnt = 0; - - list_for_each_entry(dma, &card->ctrl[i].queue, list) { - if (!pci_dma_mapping_error(card->dev, dma->dma_addr)) - pci_unmap_page(card->dev, dma->dma_addr, - get_dma_size(dma), - dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); - } spin_unlock_bh(&card->ctrl[i].queue_lock); } @@ -1067,31 +1078,6 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) return 0; } -int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card) -{ - struct rsxx_dma *dma; - int i; - - for (i = 0; i < card->n_targets; i++) { - spin_lock_bh(&card->ctrl[i].queue_lock); - list_for_each_entry(dma, &card->ctrl[i].queue, list) { - dma->dma_addr = pci_map_page(card->dev, dma->page, - dma->pg_off, get_dma_size(dma), - dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(card->dev, dma->dma_addr)) { - spin_unlock_bh(&card->ctrl[i].queue_lock); - kmem_cache_free(rsxx_dma_pool, dma); - return -ENOMEM; - } - } - spin_unlock_bh(&card->ctrl[i].queue_lock); - } - - return 0; -} - int rsxx_dma_init(void) { rsxx_dma_pool = KMEM_CACHE(rsxx_dma, SLAB_HWCACHE_ALIGN); -- cgit v1.2.3 From 8f8b899563f28ef26e381a6eb90d12dead77389f Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Wed, 11 Sep 2013 13:14:42 -0600 Subject: mtip32xx: Add SRSI support This patch add support for SRSI(Surprise Removal Surprise Insertion). Approach: --------- Surprise Removal: ----------------- On surprise removal of the device, gendisk, request queue, device index, sysfs entries, etc are retained as long as device is in use - mounted filesystem, device opened by an application, etc. The service thread breaks out of the main while loop, waits for pci remove to exit, and then waits for device to become free. When there no holders of the device, service thread cleans up the block and device related stuff and returns. Surprise Insertion: ------------------- No change, this scenario follows the normal pci probe() function flow. Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 453 +++++++++++++++++++++++--------------- drivers/block/mtip32xx/mtip32xx.h | 18 +- 2 files changed, 289 insertions(+), 182 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 952dbfe22126..76f3bc4f0c21 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -126,64 +126,30 @@ struct mtip_compat_ide_task_request_s { static bool mtip_check_surprise_removal(struct pci_dev *pdev) { u16 vendor_id = 0; + struct driver_data *dd = pci_get_drvdata(pdev); + + if (dd->sr) + return true; /* Read the vendorID from the configuration space */ pci_read_config_word(pdev, 0x00, &vendor_id); - if (vendor_id == 0xFFFF) + if (vendor_id == 0xFFFF) { + dd->sr = true; + if (dd->queue) + set_bit(QUEUE_FLAG_DEAD, &dd->queue->queue_flags); + else + dev_warn(&dd->pdev->dev, + "%s: dd->queue is NULL\n", __func__); + if (dd->port) { + set_bit(MTIP_PF_SR_CLEANUP_BIT, &dd->port->flags); + wake_up_interruptible(&dd->port->svc_wait); + } else + dev_warn(&dd->pdev->dev, + "%s: dd->port is NULL\n", __func__); return true; /* device removed */ - - return false; /* device present */ -} - -/* - * This function is called for clean the pending command in the - * command slot during the surprise removal of device and return - * error to the upper layer. - * - * @dd Pointer to the DRIVER_DATA structure. - * - * return value - * None - */ -static void mtip_command_cleanup(struct driver_data *dd) -{ - int group = 0, commandslot = 0, commandindex = 0; - struct mtip_cmd *command; - struct mtip_port *port = dd->port; - static int in_progress; - - if (in_progress) - return; - - in_progress = 1; - - for (group = 0; group < 4; group++) { - for (commandslot = 0; commandslot < 32; commandslot++) { - if (!(port->allocated[group] & (1 << commandslot))) - continue; - - commandindex = group << 5 | commandslot; - command = &port->commands[commandindex]; - - if (atomic_read(&command->active) - && (command->async_callback)) { - command->async_callback(command->async_data, - -ENODEV); - command->async_callback = NULL; - command->async_data = NULL; - } - - dma_unmap_sg(&port->dd->pdev->dev, - command->sg, - command->scatter_ents, - command->direction); - } } - up(&port->cmd_slot); - - set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); - in_progress = 0; + return false; /* device present */ } /* @@ -222,10 +188,7 @@ static int get_slot(struct mtip_port *port) } dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n"); - if (mtip_check_surprise_removal(port->dd->pdev)) { - /* Device not present, clean outstanding commands */ - mtip_command_cleanup(port->dd); - } + mtip_check_surprise_removal(port->dd->pdev); return -1; } @@ -245,6 +208,107 @@ static inline void release_slot(struct mtip_port *port, int tag) smp_mb__after_clear_bit(); } +/* + * IO completion function. + * + * This completion function is called by the driver ISR when a + * command that was issued by the kernel completes. It first calls the + * asynchronous completion function which normally calls back into the block + * layer passing the asynchronous callback data, then unmaps the + * scatter list associated with the completed command, and finally + * clears the allocated bit associated with the completed command. + * + * @port Pointer to the port data structure. + * @tag Tag of the command. + * @data Pointer to driver_data. + * @status Completion status. + * + * return value + * None + */ +static void mtip_async_complete(struct mtip_port *port, + int tag, + void *data, + int status) +{ + struct mtip_cmd *command; + struct driver_data *dd = data; + int cb_status = status ? -EIO : 0; + + if (unlikely(!dd) || unlikely(!port)) + return; + + command = &port->commands[tag]; + + if (unlikely(status == PORT_IRQ_TF_ERR)) { + dev_warn(&port->dd->pdev->dev, + "Command tag %d failed due to TFE\n", tag); + } + + /* Upper layer callback */ + if (likely(command->async_callback)) + command->async_callback(command->async_data, cb_status); + + command->async_callback = NULL; + command->comp_func = NULL; + + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + + /* Clear the allocated and active bits for the command */ + atomic_set(&port->commands[tag].active, 0); + release_slot(port, tag); + + up(&port->cmd_slot); +} + +/* + * This function is called for clean the pending command in the + * command slot during the surprise removal of device and return + * error to the upper layer. + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * None + */ +static void mtip_command_cleanup(struct driver_data *dd) +{ + int tag = 0; + struct mtip_cmd *cmd; + struct mtip_port *port = dd->port; + unsigned int num_cmd_slots = dd->slot_groups * 32; + + if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) + return; + + if (!port) + return; + + cmd = &port->commands[MTIP_TAG_INTERNAL]; + if (atomic_read(&cmd->active)) + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & + (1 << MTIP_TAG_INTERNAL)) + if (cmd->comp_func) + cmd->comp_func(port, MTIP_TAG_INTERNAL, + cmd->comp_data, -ENODEV); + + while (1) { + tag = find_next_bit(port->allocated, num_cmd_slots, tag); + if (tag >= num_cmd_slots) + break; + + cmd = &port->commands[tag]; + if (atomic_read(&cmd->active)) + mtip_async_complete(port, tag, dd, -ENODEV); + } + + set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); +} + /* * Reset the HBA (without sleeping) * @@ -584,6 +648,9 @@ static void mtip_timeout_function(unsigned long int data) if (unlikely(!port)) return; + if (unlikely(port->dd->sr)) + return; + if (test_bit(MTIP_DDF_RESUME_BIT, &port->dd->dd_flag)) { mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(30000)); @@ -674,66 +741,6 @@ static void mtip_timeout_function(unsigned long int data) jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); } -/* - * IO completion function. - * - * This completion function is called by the driver ISR when a - * command that was issued by the kernel completes. It first calls the - * asynchronous completion function which normally calls back into the block - * layer passing the asynchronous callback data, then unmaps the - * scatter list associated with the completed command, and finally - * clears the allocated bit associated with the completed command. - * - * @port Pointer to the port data structure. - * @tag Tag of the command. - * @data Pointer to driver_data. - * @status Completion status. - * - * return value - * None - */ -static void mtip_async_complete(struct mtip_port *port, - int tag, - void *data, - int status) -{ - struct mtip_cmd *command; - struct driver_data *dd = data; - int cb_status = status ? -EIO : 0; - - if (unlikely(!dd) || unlikely(!port)) - return; - - command = &port->commands[tag]; - - if (unlikely(status == PORT_IRQ_TF_ERR)) { - dev_warn(&port->dd->pdev->dev, - "Command tag %d failed due to TFE\n", tag); - } - - /* Upper layer callback */ - if (likely(command->async_callback)) - command->async_callback(command->async_data, cb_status); - - command->async_callback = NULL; - command->comp_func = NULL; - - /* Unmap the DMA scatter list entries */ - dma_unmap_sg(&dd->pdev->dev, - command->sg, - command->scatter_ents, - command->direction); - - /* Clear the allocated and active bits for the command */ - atomic_set(&port->commands[tag].active, 0); - release_slot(port, tag); - - if (unlikely(command->unaligned)) - up(&port->cmd_slot_unal); - else - up(&port->cmd_slot); -} - /* * Internal command completion callback function. * @@ -854,7 +861,6 @@ static void mtip_handle_tfe(struct driver_data *dd) "Missing completion func for tag %d", tag); if (mtip_check_surprise_removal(dd->pdev)) { - mtip_command_cleanup(dd); /* don't proceed further */ return; } @@ -1018,14 +1024,12 @@ static inline void mtip_workq_sdbfx(struct mtip_port *port, int group, command->comp_data, 0); } else { - dev_warn(&dd->pdev->dev, - "Null completion " - "for tag %d", + dev_dbg(&dd->pdev->dev, + "Null completion for tag %d", tag); if (mtip_check_surprise_removal( dd->pdev)) { - mtip_command_cleanup(dd); return; } } @@ -1145,7 +1149,6 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) if (unlikely(port_stat & PORT_IRQ_ERR)) { if (unlikely(mtip_check_surprise_removal(dd->pdev))) { - mtip_command_cleanup(dd); /* don't proceed further */ return IRQ_HANDLED; } @@ -3006,6 +3009,46 @@ static void mtip_hw_debugfs_exit(struct driver_data *dd) debugfs_remove_recursive(dd->dfs_node); } +static int mtip_free_orphan(struct driver_data *dd) +{ + struct kobject *kobj; + + if (dd->bdev) { + if (dd->bdev->bd_holders >= 1) + return -2; + + bdput(dd->bdev); + dd->bdev = NULL; + } + + mtip_hw_debugfs_exit(dd); + + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + + if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag) && + test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) { + put_disk(dd->disk); + } else { + if (dd->disk) { + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_exit(dd, kobj); + kobject_put(kobj); + } + del_gendisk(dd->disk); + dd->disk = NULL; + } + if (dd->queue) { + dd->queue->queuedata = NULL; + blk_cleanup_queue(dd->queue); + dd->queue = NULL; + } + } + kfree(dd); + return 0; +} /* * Perform any init/resume time hardware setup @@ -3154,6 +3197,7 @@ static int mtip_service_thread(void *data) unsigned long slot, slot_start, slot_wrap; unsigned int num_cmd_slots = dd->slot_groups * 32; struct mtip_port *port = dd->port; + int ret; while (1) { /* @@ -3164,13 +3208,18 @@ static int mtip_service_thread(void *data) !(port->flags & MTIP_PF_PAUSE_IO)); if (kthread_should_stop()) + goto st_out; + + set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); + + /* If I am an orphan, start self cleanup */ + if (test_bit(MTIP_PF_SR_CLEANUP_BIT, &port->flags)) break; if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) - break; + goto st_out; - set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; /* used to restrict the loop to one iteration */ @@ -3201,7 +3250,7 @@ static int mtip_service_thread(void *data) clear_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); } else if (test_bit(MTIP_PF_REBUILD_BIT, &port->flags)) { - if (!mtip_ftl_rebuild_poll(dd)) + if (mtip_ftl_rebuild_poll(dd) < 0) set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag); clear_bit(MTIP_PF_REBUILD_BIT, &port->flags); @@ -3209,8 +3258,30 @@ static int mtip_service_thread(void *data) clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags)) + goto st_out; + } + + /* wait for pci remove to exit */ + while (1) { + if (test_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag)) break; + msleep_interruptible(1000); + if (kthread_should_stop()) + goto st_out; } + + while (1) { + ret = mtip_free_orphan(dd); + if (!ret) { + /* NOTE: All data structures are invalid, do not + * access any here */ + return 0; + } + msleep_interruptible(1000); + if (kthread_should_stop()) + goto st_out; + } +st_out: return 0; } @@ -3437,13 +3508,13 @@ static int mtip_hw_init(struct driver_data *dd) rv = -EFAULT; goto out3; } + mtip_dump_identify(dd->port); if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == MTIP_FTL_REBUILD_MAGIC) { set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); return MTIP_FTL_REBUILD_MAGIC; } - mtip_dump_identify(dd->port); /* check write protect, over temp and rebuild statuses */ rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, @@ -3467,8 +3538,8 @@ static int mtip_hw_init(struct driver_data *dd) } if (buf[288] == 0xBF) { dev_info(&dd->pdev->dev, - "Drive indicates rebuild has failed.\n"); - /* TODO */ + "Drive is in security locked state.\n"); + set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag); } } @@ -3523,9 +3594,8 @@ static int mtip_hw_exit(struct driver_data *dd) * Send standby immediate (E0h) to the drive so that it * saves its state. */ - if (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { - - if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) + if (!dd->sr) { + if (!test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3551,6 +3621,7 @@ static int mtip_hw_exit(struct driver_data *dd) dd->port->command_list_dma); /* Free the memory allocated for the for structure. */ kfree(dd->port); + dd->port = NULL; return 0; } @@ -3572,7 +3643,8 @@ static int mtip_hw_shutdown(struct driver_data *dd) * Send standby immediate (E0h) to the drive so that it * saves its state. */ - mtip_standby_immediate(dd->port); + if (!dd->sr && dd->port) + mtip_standby_immediate(dd->port); return 0; } @@ -3887,6 +3959,10 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) bio_endio(bio, -ENODATA); return; } + if (test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) { + bio_endio(bio, -ENXIO); + return; + } } if (unlikely(bio->bi_rw & REQ_DISCARD)) { @@ -4010,6 +4086,8 @@ static int mtip_block_initialize(struct driver_data *dd) dd->disk->private_data = dd; dd->index = index; + mtip_hw_debugfs_init(dd); + /* * if rebuild pending, start the service thread, and delay the block * queue creation and add_disk() @@ -4068,6 +4146,7 @@ skip_create_disk: /* Enable the block device and add it to /dev */ add_disk(dd->disk); + dd->bdev = bdget_disk(dd->disk, 0); /* * Now that the disk is active, initialize any sysfs attributes * managed by the protocol layer. @@ -4077,7 +4156,6 @@ skip_create_disk: mtip_hw_sysfs_init(dd, kobj); kobject_put(kobj); } - mtip_hw_debugfs_init(dd); if (dd->mtip_svc_handler) { set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); @@ -4103,7 +4181,8 @@ start_service_thread: return rv; kthread_run_error: - mtip_hw_debugfs_exit(dd); + bdput(dd->bdev); + dd->bdev = NULL; /* Delete our gendisk. This also removes the device from /dev */ del_gendisk(dd->disk); @@ -4112,6 +4191,7 @@ read_capacity_error: blk_cleanup_queue(dd->queue); block_queue_alloc_init_error: + mtip_hw_debugfs_exit(dd); disk_index_error: spin_lock(&rssd_index_lock); ida_remove(&rssd_index_ida, index); @@ -4141,40 +4221,48 @@ static int mtip_block_remove(struct driver_data *dd) { struct kobject *kobj; - if (dd->mtip_svc_handler) { - set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); - wake_up_interruptible(&dd->port->svc_wait); - kthread_stop(dd->mtip_svc_handler); - } + if (!dd->sr) { + mtip_hw_debugfs_exit(dd); - /* Clean up the sysfs attributes, if created */ - if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); - if (kobj) { - mtip_hw_sysfs_exit(dd, kobj); - kobject_put(kobj); + if (dd->mtip_svc_handler) { + set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); + wake_up_interruptible(&dd->port->svc_wait); + kthread_stop(dd->mtip_svc_handler); } - } - mtip_hw_debugfs_exit(dd); - /* - * Delete our gendisk structure. This also removes the device - * from /dev - */ - if (dd->disk) { - if (dd->disk->queue) - del_gendisk(dd->disk); - else - put_disk(dd->disk); - } - - spin_lock(&rssd_index_lock); - ida_remove(&rssd_index_ida, dd->index); - spin_unlock(&rssd_index_lock); + /* Clean up the sysfs attributes, if created */ + if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_exit(dd, kobj); + kobject_put(kobj); + } + } + /* + * Delete our gendisk structure. This also removes the device + * from /dev + */ + if (dd->bdev) { + bdput(dd->bdev); + dd->bdev = NULL; + } + if (dd->disk) { + if (dd->disk->queue) { + del_gendisk(dd->disk); + blk_cleanup_queue(dd->queue); + dd->queue = NULL; + } else + put_disk(dd->disk); + } + dd->disk = NULL; - blk_cleanup_queue(dd->queue); - dd->disk = NULL; - dd->queue = NULL; + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + } else { + dev_info(&dd->pdev->dev, "device %s surprise removal\n", + dd->disk->disk_name); + } /* De-initialize the protocol layer. */ mtip_hw_exit(dd); @@ -4490,8 +4578,7 @@ done: static void mtip_pci_remove(struct pci_dev *pdev) { struct driver_data *dd = pci_get_drvdata(pdev); - int counter = 0; - unsigned long flags; + unsigned long flags, to; set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag); @@ -4500,17 +4587,22 @@ static void mtip_pci_remove(struct pci_dev *pdev) list_add(&dd->remove_list, &removing_list); spin_unlock_irqrestore(&dev_lock, flags); - if (mtip_check_surprise_removal(pdev)) { - while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { - counter++; - msleep(20); - if (counter == 10) { - /* Cleanup the outstanding commands */ - mtip_command_cleanup(dd); - break; - } - } + mtip_check_surprise_removal(pdev); + synchronize_irq(dd->pdev->irq); + + /* Spin until workers are done */ + to = jiffies + msecs_to_jiffies(4000); + do { + msleep(20); + } while (atomic_read(&dd->irq_workers_active) != 0 && + time_before(jiffies, to)); + + if (atomic_read(&dd->irq_workers_active) != 0) { + dev_warn(&dd->pdev->dev, + "Completion workers still active!\n"); } + /* Cleanup the outstanding commands */ + mtip_command_cleanup(dd); /* Clean up the block layer. */ mtip_block_remove(dd); @@ -4529,8 +4621,15 @@ static void mtip_pci_remove(struct pci_dev *pdev) list_del_init(&dd->remove_list); spin_unlock_irqrestore(&dev_lock, flags); - kfree(dd); + if (!dd->sr) + kfree(dd); + else + set_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag); + pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); + pci_set_drvdata(pdev, NULL); + pci_dev_put(pdev); + } /* diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 3bb8a295fbe4..9be7a1582ad3 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -140,6 +140,7 @@ enum { MTIP_PF_SVC_THD_ACTIVE_BIT = 4, MTIP_PF_ISSUE_CMDS_BIT = 5, MTIP_PF_REBUILD_BIT = 6, + MTIP_PF_SR_CLEANUP_BIT = 7, MTIP_PF_SVC_THD_STOP_BIT = 8, /* below are bit numbers in 'dd_flag' defined in driver_data */ @@ -147,15 +148,18 @@ enum { MTIP_DDF_REMOVE_PENDING_BIT = 1, MTIP_DDF_OVER_TEMP_BIT = 2, MTIP_DDF_WRITE_PROTECT_BIT = 3, - MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | - (1 << MTIP_DDF_SEC_LOCK_BIT) | - (1 << MTIP_DDF_OVER_TEMP_BIT) | - (1 << MTIP_DDF_WRITE_PROTECT_BIT)), - + MTIP_DDF_REMOVE_DONE_BIT = 4, MTIP_DDF_CLEANUP_BIT = 5, MTIP_DDF_RESUME_BIT = 6, MTIP_DDF_INIT_DONE_BIT = 7, MTIP_DDF_REBUILD_FAILED_BIT = 8, + + MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | + (1 << MTIP_DDF_SEC_LOCK_BIT) | + (1 << MTIP_DDF_OVER_TEMP_BIT) | + (1 << MTIP_DDF_WRITE_PROTECT_BIT) | + (1 << MTIP_DDF_REBUILD_FAILED_BIT)), + }; struct smart_attr { @@ -499,6 +503,8 @@ struct driver_data { bool trim_supp; /* flag indicating trim support */ + bool sr; + int numa_node; /* NUMA support */ char workq_name[32]; @@ -511,6 +517,8 @@ struct driver_data { int isr_binding; + struct block_device *bdev; + int unal_qdepth; /* qdepth of unaligned IO queue */ struct list_head online_list; /* linkage for online list */ -- cgit v1.2.3 From c8afd0dcbd14e2352258f2e2d359b36d0edd459f Mon Sep 17 00:00:00 2001 From: David Milburn Date: Thu, 23 May 2013 16:23:45 -0500 Subject: mtip32xx: dynamically allocate buffer in debugfs functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dynamically allocate buf to prevent warnings: drivers/block/mtip32xx/mtip32xx.c: In function ‘mtip_hw_read_device_status’: drivers/block/mtip32xx/mtip32xx.c:2823: warning: the frame size of 1056 bytes is larger than 1024 bytes drivers/block/mtip32xx/mtip32xx.c: In function ‘mtip_hw_read_registers’: drivers/block/mtip32xx/mtip32xx.c:2894: warning: the frame size of 1056 bytes is larger than 1024 bytes drivers/block/mtip32xx/mtip32xx.c: In function ‘mtip_hw_read_flags’: drivers/block/mtip32xx/mtip32xx.c:2917: warning: the frame size of 1056 bytes is larger than 1024 bytes Signed-off-by: David Milburn Acked-by: Asai Thambi S P Signed-off-by: Jens Axboe --- drivers/block/mtip32xx/mtip32xx.c | 47 ++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 76f3bc4f0c21..050c71267f14 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -2809,34 +2809,51 @@ static ssize_t show_device_status(struct device_driver *drv, char *buf) static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf, size_t len, loff_t *offset) { + struct driver_data *dd = (struct driver_data *)f->private_data; int size = *offset; - char buf[MTIP_DFS_MAX_BUF_SIZE]; + char *buf; + int rv = 0; if (!len || *offset) return 0; + buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL); + if (!buf) { + dev_err(&dd->pdev->dev, + "Memory allocation: status buffer\n"); + return -ENOMEM; + } + size += show_device_status(NULL, buf); *offset = size <= len ? size : len; size = copy_to_user(ubuf, buf, *offset); if (size) - return -EFAULT; + rv = -EFAULT; - return *offset; + kfree(buf); + return rv ? rv : *offset; } static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf, size_t len, loff_t *offset) { struct driver_data *dd = (struct driver_data *)f->private_data; - char buf[MTIP_DFS_MAX_BUF_SIZE]; + char *buf; u32 group_allocated; int size = *offset; - int n; + int n, rv = 0; if (!len || size) return 0; + buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL); + if (!buf) { + dev_err(&dd->pdev->dev, + "Memory allocation: register buffer\n"); + return -ENOMEM; + } + size += sprintf(&buf[size], "H/ S ACTive : [ 0x"); for (n = dd->slot_groups-1; n >= 0; n--) @@ -2891,21 +2908,30 @@ static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf, *offset = size <= len ? size : len; size = copy_to_user(ubuf, buf, *offset); if (size) - return -EFAULT; + rv = -EFAULT; - return *offset; + kfree(buf); + return rv ? rv : *offset; } static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf, size_t len, loff_t *offset) { struct driver_data *dd = (struct driver_data *)f->private_data; - char buf[MTIP_DFS_MAX_BUF_SIZE]; + char *buf; int size = *offset; + int rv = 0; if (!len || size) return 0; + buf = kzalloc(MTIP_DFS_MAX_BUF_SIZE, GFP_KERNEL); + if (!buf) { + dev_err(&dd->pdev->dev, + "Memory allocation: flag buffer\n"); + return -ENOMEM; + } + size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n", dd->port->flags); size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n", @@ -2914,9 +2940,10 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf, *offset = size <= len ? size : len; size = copy_to_user(ubuf, buf, *offset); if (size) - return -EFAULT; + rv = -EFAULT; - return *offset; + kfree(buf); + return rv ? rv : *offset; } static const struct file_operations mtip_device_status_fops = { -- cgit v1.2.3 From 0317cd6de852a70e0374e7eb40a013072274386f Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Fri, 27 Sep 2013 20:42:50 -0600 Subject: rsxx: Kernel Panic caused by mapping Discards This fixes a kernel panic injected by commit id 8d26750143341831bc312f61c5ed141eeb75b8d0 where discards are getting mapped through the pci_map_page function call. The driver will now start verifying that a dma is not a discard before issuing a the pci_map_page function call. Also, we are updating the driver version. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/dma.c | 43 ++++++++++++++++++++++-------------------- drivers/block/rsxx/rsxx_priv.h | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 34fd1018c8e5..4103601ae675 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -434,26 +434,29 @@ static void rsxx_issue_dmas(struct rsxx_dma_ctrl *ctrl) continue; } - if (dma->cmd == HW_CMD_BLK_WRITE) - dir = PCI_DMA_TODEVICE; - else - dir = PCI_DMA_FROMDEVICE; - - /* - * The function pci_map_page is placed here because we can - * only, by design, issue up to 255 commands to the hardware - * at one time per DMA channel. So the maximum amount of mapped - * memory would be 255 * 4 channels * 4096 Bytes which is less - * than 2GB, the limit of a x8 Non-HWWD PCIe slot. This way the - * pci_map_page function should never fail because of a - * lack of mappable memory. - */ - dma->dma_addr = pci_map_page(ctrl->card->dev, dma->page, - dma->pg_off, dma->sub_page.cnt << 9, dir); - if (pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { - push_tracker(ctrl->trackers, tag); - rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); - continue; + if (dma->cmd != HW_CMD_BLK_DISCARD) { + if (dma->cmd == HW_CMD_BLK_WRITE) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + /* + * The function pci_map_page is placed here because we + * can only, by design, issue up to 255 commands to the + * hardware at one time per DMA channel. So the maximum + * amount of mapped memory would be 255 * 4 channels * + * 4096 Bytes which is less than 2GB, the limit of a x8 + * Non-HWWD PCIe slot. This way the pci_map_page + * function should never fail because of a lack of + * mappable memory. + */ + dma->dma_addr = pci_map_page(ctrl->card->dev, dma->page, + dma->pg_off, dma->sub_page.cnt << 9, dir); + if (pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { + push_tracker(ctrl->trackers, tag); + rsxx_complete_dma(ctrl, dma, DMA_CANCELLED); + continue; + } } set_tracker_dma(ctrl->trackers, tag, dma); diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index 82779058e8ec..913740e53d31 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -52,7 +52,7 @@ struct proc_cmd; #define RS70_PCI_REV_SUPPORTED 4 #define DRIVER_NAME "rsxx" -#define DRIVER_VERSION "4.0" +#define DRIVER_VERSION "4.0.1.2498" /* Block size is 4096 */ #define RSXX_HW_BLK_SHIFT 12 -- cgit v1.2.3 From e67f86b31ae5be8a88bec27b5ecb18dc2ffc9c56 Mon Sep 17 00:00:00 2001 From: Akhil Bhansali Date: Tue, 15 Oct 2013 14:19:07 -0600 Subject: Add support for sTec's pci-e flash card Kronos Signed-off-by: Akhil Bhansali Signed-off-by: Ramprasad Chinthekindi Reviewed-by: Jeff Moyer Folded patch, contributions to clean up this driver from: Jens Axboe Dan Carpenter Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/Kconfig | 10 + drivers/block/Makefile | 2 + drivers/block/skd_main.c | 5817 +++++++++++++++++++++++++++++++++++++++++++++ drivers/block/skd_s1120.h | 354 +++ 4 files changed, 6183 insertions(+) create mode 100644 drivers/block/skd_main.c create mode 100644 drivers/block/skd_s1120.h (limited to 'drivers/block') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index e07a5fd58ad7..555aed0b50dd 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -316,6 +316,16 @@ config BLK_DEV_NVME To compile this driver as a module, choose M here: the module will be called nvme. +config BLK_DEV_SKD + tristate "STEC S1120 Block Driver" + depends on PCI + depends on 64BIT + ---help--- + Saying Y or M here will enable support for the + STEC, Inc. S1120 PCIe SSD. + + Use device /dev/skd$N amd /dev/skd$Np$M. + config BLK_DEV_OSD tristate "OSD object-as-blkdev support" depends on SCSI_OSD_ULD diff --git a/drivers/block/Makefile b/drivers/block/Makefile index ca07399a8d99..f33b36694289 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_MG_DISK) += mg_disk.o obj-$(CONFIG_SUNVDC) += sunvdc.o obj-$(CONFIG_BLK_DEV_NVME) += nvme.o +obj-$(CONFIG_BLK_DEV_SKD) += skd.o obj-$(CONFIG_BLK_DEV_OSD) += osdblk.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o @@ -43,4 +44,5 @@ obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/ nvme-y := nvme-core.o nvme-scsi.o +skd-y := skd_main.o swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c new file mode 100644 index 000000000000..3110f68ecedd --- /dev/null +++ b/drivers/block/skd_main.c @@ -0,0 +1,5817 @@ +/* Copyright 2012 STEC, Inc. + * + * This file is licensed under the terms of the 3-clause + * BSD License (http://opensource.org/licenses/BSD-3-Clause) + * or the GNU GPL-2.0 (http://www.gnu.org/licenses/gpl-2.0.html), + * at your option. Both licenses are also available in the LICENSE file + * distributed with this project. This file may not be copied, modified, + * or distributed except in accordance with those terms. + * Gordoni Waidhofer + * Initial Driver Design! + * Thomas Swann + * Interrupt handling. + * Ramprasad Chinthekindi + * biomode implementation. + * Akhil Bhansali + * Added support for DISCARD / FLUSH and FUA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skd_s1120.h" + +static int skd_dbg_level; +static int skd_isr_comp_limit = 4; + +enum { + STEC_LINK_2_5GTS = 0, + STEC_LINK_5GTS = 1, + STEC_LINK_8GTS = 2, + STEC_LINK_UNKNOWN = 0xFF +}; + +enum { + SKD_FLUSH_INITIALIZER, + SKD_FLUSH_ZERO_SIZE_FIRST, + SKD_FLUSH_DATA_SECOND, +}; + +#define DPRINTK(skdev, fmt, args ...) \ + do { \ + if (unlikely((skdev)->dbg_level > 0)) { \ + pr_err("%s:%s:%d " fmt, (skdev)->name, \ + __func__, __LINE__, ## args); \ + } \ + } while (0) + +#define SKD_ASSERT(expr) \ + do { \ + if (unlikely(!(expr))) { \ + pr_err("Assertion failed! %s,%s,%s,line=%d\n", \ + # expr, __FILE__, __func__, __LINE__); \ + } \ + } while (0) + +#define VPRINTK(skdev, fmt, args ...) \ + do { \ + if (unlikely((skdev)->dbg_level > 1)) { \ + pr_err("%s:%s:%d " fmt, (skdev)->name, \ + __func__, __LINE__, ## args); \ + } \ + } while (0) + + +#define DRV_NAME "skd" +#define DRV_VERSION "2.2.1" +#define DRV_BUILD_ID "0260" +#define PFX DRV_NAME ": " +#define DRV_BIN_VERSION 0x100 +#define DRV_VER_COMPL "2.2.1." DRV_BUILD_ID + +MODULE_AUTHOR("bug-reports: support@stec-inc.com"); +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_DESCRIPTION("STEC s1120 PCIe SSD block/BIO driver (b" DRV_BUILD_ID ")"); +MODULE_VERSION(DRV_VERSION "-" DRV_BUILD_ID); + +#define PCI_VENDOR_ID_STEC 0x1B39 +#define PCI_DEVICE_ID_S1120 0x0001 + +#define SKD_FUA_NV (1 << 1) +#define SKD_MINORS_PER_DEVICE 16 + +#define SKD_MAX_QUEUE_DEPTH 200u + +#define SKD_PAUSE_TIMEOUT (5 * 1000) + +#define SKD_N_FITMSG_BYTES (512u) + +#define SKD_N_SPECIAL_CONTEXT 32u +#define SKD_N_SPECIAL_FITMSG_BYTES (128u) + +/* SG elements are 32 bytes, so we can make this 4096 and still be under the + * 128KB limit. That allows 4096*4K = 16M xfer size + */ +#define SKD_N_SG_PER_REQ_DEFAULT 256u +#define SKD_N_SG_PER_SPECIAL 256u + +#define SKD_N_COMPLETION_ENTRY 256u +#define SKD_N_READ_CAP_BYTES (8u) + +#define SKD_N_INTERNAL_BYTES (512u) + +/* 5 bits of uniqifier, 0xF800 */ +#define SKD_ID_INCR (0x400) +#define SKD_ID_TABLE_MASK (3u << 8u) +#define SKD_ID_RW_REQUEST (0u << 8u) +#define SKD_ID_INTERNAL (1u << 8u) +#define SKD_ID_SPECIAL_REQUEST (2u << 8u) +#define SKD_ID_FIT_MSG (3u << 8u) +#define SKD_ID_SLOT_MASK 0x00FFu +#define SKD_ID_SLOT_AND_TABLE_MASK 0x03FFu + +#define SKD_N_TIMEOUT_SLOT 4u +#define SKD_TIMEOUT_SLOT_MASK 3u + +#define SKD_N_MAX_SECTORS 2048u + +#define SKD_MAX_RETRIES 2u + +#define SKD_TIMER_SECONDS(seconds) (seconds) +#define SKD_TIMER_MINUTES(minutes) ((minutes) * (60)) + +#define INQ_STD_NBYTES 36 +#define SKD_DISCARD_CDB_LENGTH 24 + +enum skd_drvr_state { + SKD_DRVR_STATE_LOAD, + SKD_DRVR_STATE_IDLE, + SKD_DRVR_STATE_BUSY, + SKD_DRVR_STATE_STARTING, + SKD_DRVR_STATE_ONLINE, + SKD_DRVR_STATE_PAUSING, + SKD_DRVR_STATE_PAUSED, + SKD_DRVR_STATE_DRAINING_TIMEOUT, + SKD_DRVR_STATE_RESTARTING, + SKD_DRVR_STATE_RESUMING, + SKD_DRVR_STATE_STOPPING, + SKD_DRVR_STATE_FAULT, + SKD_DRVR_STATE_DISAPPEARED, + SKD_DRVR_STATE_PROTOCOL_MISMATCH, + SKD_DRVR_STATE_BUSY_ERASE, + SKD_DRVR_STATE_BUSY_SANITIZE, + SKD_DRVR_STATE_BUSY_IMMINENT, + SKD_DRVR_STATE_WAIT_BOOT, + SKD_DRVR_STATE_SYNCING, +}; + +#define SKD_WAIT_BOOT_TIMO SKD_TIMER_SECONDS(90u) +#define SKD_STARTING_TIMO SKD_TIMER_SECONDS(8u) +#define SKD_RESTARTING_TIMO SKD_TIMER_MINUTES(4u) +#define SKD_DRAINING_TIMO SKD_TIMER_SECONDS(6u) +#define SKD_BUSY_TIMO SKD_TIMER_MINUTES(20u) +#define SKD_STARTED_BUSY_TIMO SKD_TIMER_SECONDS(60u) +#define SKD_START_WAIT_SECONDS 90u + +enum skd_req_state { + SKD_REQ_STATE_IDLE, + SKD_REQ_STATE_SETUP, + SKD_REQ_STATE_BUSY, + SKD_REQ_STATE_COMPLETED, + SKD_REQ_STATE_TIMEOUT, + SKD_REQ_STATE_ABORTED, +}; + +enum skd_fit_msg_state { + SKD_MSG_STATE_IDLE, + SKD_MSG_STATE_BUSY, +}; + +enum skd_check_status_action { + SKD_CHECK_STATUS_REPORT_GOOD, + SKD_CHECK_STATUS_REPORT_SMART_ALERT, + SKD_CHECK_STATUS_REQUEUE_REQUEST, + SKD_CHECK_STATUS_REPORT_ERROR, + SKD_CHECK_STATUS_BUSY_IMMINENT, +}; + +struct skd_fitmsg_context { + enum skd_fit_msg_state state; + + struct skd_fitmsg_context *next; + + u32 id; + u16 outstanding; + + u32 length; + u32 offset; + + u8 *msg_buf; + dma_addr_t mb_dma_address; +}; + +struct skd_request_context { + enum skd_req_state state; + + struct skd_request_context *next; + + u16 id; + u32 fitmsg_id; + + struct request *req; + struct bio *bio; + unsigned long start_time; + u8 flush_cmd; + u8 discard_page; + + u32 timeout_stamp; + u8 sg_data_dir; + struct scatterlist *sg; + u32 n_sg; + u32 sg_byte_count; + + struct fit_sg_descriptor *sksg_list; + dma_addr_t sksg_dma_address; + + struct fit_completion_entry_v1 completion; + + struct fit_comp_error_info err_info; + +}; +#define SKD_DATA_DIR_HOST_TO_CARD 1 +#define SKD_DATA_DIR_CARD_TO_HOST 2 +#define SKD_DATA_DIR_NONE 3 /* especially for DISCARD requests. */ + +struct skd_special_context { + struct skd_request_context req; + + u8 orphaned; + + void *data_buf; + dma_addr_t db_dma_address; + + u8 *msg_buf; + dma_addr_t mb_dma_address; +}; + +struct skd_sg_io { + fmode_t mode; + void __user *argp; + + struct sg_io_hdr sg; + + u8 cdb[16]; + + u32 dxfer_len; + u32 iovcnt; + struct sg_iovec *iov; + struct sg_iovec no_iov_iov; + + struct skd_special_context *skspcl; +}; + +typedef enum skd_irq_type { + SKD_IRQ_LEGACY, + SKD_IRQ_MSI, + SKD_IRQ_MSIX +} skd_irq_type_t; + +#define SKD_MAX_BARS 2 + +struct skd_device { + volatile void __iomem *mem_map[SKD_MAX_BARS]; + resource_size_t mem_phys[SKD_MAX_BARS]; + u32 mem_size[SKD_MAX_BARS]; + + skd_irq_type_t irq_type; + u32 msix_count; + struct skd_msix_entry *msix_entries; + + struct pci_dev *pdev; + int pcie_error_reporting_is_enabled; + + spinlock_t lock; + struct gendisk *disk; + struct request_queue *queue; + struct device *class_dev; + int gendisk_on; + int sync_done; + + atomic_t device_count; + u32 devno; + u32 major; + char name[32]; + char isr_name[30]; + + enum skd_drvr_state state; + u32 drive_state; + + u32 in_flight; + u32 cur_max_queue_depth; + u32 queue_low_water_mark; + u32 dev_max_queue_depth; + + u32 num_fitmsg_context; + u32 num_req_context; + + u32 timeout_slot[SKD_N_TIMEOUT_SLOT]; + u32 timeout_stamp; + struct skd_fitmsg_context *skmsg_free_list; + struct skd_fitmsg_context *skmsg_table; + + struct skd_request_context *skreq_free_list; + struct skd_request_context *skreq_table; + + struct skd_special_context *skspcl_free_list; + struct skd_special_context *skspcl_table; + + struct skd_special_context internal_skspcl; + u32 read_cap_blocksize; + u32 read_cap_last_lba; + int read_cap_is_valid; + int inquiry_is_valid; + u8 inq_serial_num[13]; /*12 chars plus null term */ + u8 id_str[80]; /* holds a composite name (pci + sernum) */ + + u8 skcomp_cycle; + u32 skcomp_ix; + struct fit_completion_entry_v1 *skcomp_table; + struct fit_comp_error_info *skerr_table; + dma_addr_t cq_dma_address; + + wait_queue_head_t waitq; + + struct timer_list timer; + u32 timer_countdown; + u32 timer_substate; + + int n_special; + int sgs_per_request; + u32 last_mtd; + + u32 proto_ver; + + int dbg_level; + u32 connect_time_stamp; + int connect_retries; +#define SKD_MAX_CONNECT_RETRIES 16 + u32 drive_jiffies; + + u32 timo_slot; + + + struct work_struct completion_worker; + + struct bio_list bio_queue; + int queue_stopped; + + struct list_head flush_list; +}; + +#define SKD_FLUSH_JOB "skd-flush-jobs" +struct kmem_cache *skd_flush_slab; + +/* + * These commands hold "nonzero size FLUSH bios", + * which are enqueud in skdev->flush_list during + * completion of "zero size FLUSH commands". + * It will be active in biomode. + */ +struct skd_flush_cmd { + void *cmd; + struct list_head flist; +}; + +#define SKD_WRITEL(DEV, VAL, OFF) skd_reg_write32(DEV, VAL, OFF) +#define SKD_READL(DEV, OFF) skd_reg_read32(DEV, OFF) +#define SKD_WRITEQ(DEV, VAL, OFF) skd_reg_write64(DEV, VAL, OFF) + +static inline u32 skd_reg_read32(struct skd_device *skdev, u32 offset) +{ + u32 val; + + if (likely(skdev->dbg_level < 2)) + return readl(skdev->mem_map[1] + offset); + else { + barrier(); + val = readl(skdev->mem_map[1] + offset); + barrier(); + VPRINTK(skdev, "offset %x = %x\n", offset, val); + return val; + } + +} + +static inline void skd_reg_write32(struct skd_device *skdev, u32 val, + u32 offset) +{ + if (likely(skdev->dbg_level < 2)) { + writel(val, skdev->mem_map[1] + offset); + barrier(); + readl(skdev->mem_map[1] + offset); + barrier(); + } else { + barrier(); + writel(val, skdev->mem_map[1] + offset); + barrier(); + readl(skdev->mem_map[1] + offset); + barrier(); + VPRINTK(skdev, "offset %x = %x\n", offset, val); + } +} + +static inline void skd_reg_write64(struct skd_device *skdev, u64 val, + u32 offset) +{ + if (likely(skdev->dbg_level < 2)) { + writeq(val, skdev->mem_map[1] + offset); + barrier(); + readq(skdev->mem_map[1] + offset); + barrier(); + } else { + barrier(); + writeq(val, skdev->mem_map[1] + offset); + barrier(); + readq(skdev->mem_map[1] + offset); + barrier(); + VPRINTK(skdev, "offset %x = %016llx\n", offset, val); + } +} + + +#define SKD_IRQ_DEFAULT SKD_IRQ_MSI +static int skd_isr_type = SKD_IRQ_DEFAULT; + +module_param(skd_isr_type, int, 0444); +MODULE_PARM_DESC(skd_isr_type, "Interrupt type capability." + " (0==legacy, 1==MSI, 2==MSI-X, default==1)"); + +#define SKD_MAX_REQ_PER_MSG_DEFAULT 1 +static int skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; + +module_param(skd_max_req_per_msg, int, 0444); +MODULE_PARM_DESC(skd_max_req_per_msg, + "Maximum SCSI requests packed in a single message." + " (1-14, default==1)"); + +#define SKD_MAX_QUEUE_DEPTH_DEFAULT 64 +#define SKD_MAX_QUEUE_DEPTH_DEFAULT_STR "64" +static int skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; + +module_param(skd_max_queue_depth, int, 0444); +MODULE_PARM_DESC(skd_max_queue_depth, + "Maximum SCSI requests issued to s1120." + " (1-200, default==" SKD_MAX_QUEUE_DEPTH_DEFAULT_STR ")"); + +static int skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; +module_param(skd_sgs_per_request, int, 0444); +MODULE_PARM_DESC(skd_sgs_per_request, + "Maximum SG elements per block request." + " (1-4096, default==256)"); + +static int skd_max_pass_thru = SKD_N_SPECIAL_CONTEXT; +module_param(skd_max_pass_thru, int, 0444); +MODULE_PARM_DESC(skd_max_pass_thru, + "Maximum SCSI pass-thru at a time." " (1-50, default==32)"); + +module_param(skd_dbg_level, int, 0444); +MODULE_PARM_DESC(skd_dbg_level, "s1120 debug level (0,1,2)"); + +module_param(skd_isr_comp_limit, int, 0444); +MODULE_PARM_DESC(skd_isr_comp_limit, "s1120 isr comp limit (0=none) default=4"); + +static int skd_bio; +module_param(skd_bio, int, 0444); +MODULE_PARM_DESC(skd_bio, + "Register as a bio device instead of block (0, 1) default=0"); + +/* Major device number dynamically assigned. */ +static u32 skd_major; + +static struct skd_device *skd_construct(struct pci_dev *pdev); +static void skd_destruct(struct skd_device *skdev); +static const struct block_device_operations skd_blockdev_ops; +static void skd_send_fitmsg(struct skd_device *skdev, + struct skd_fitmsg_context *skmsg); +static void skd_send_special_fitmsg(struct skd_device *skdev, + struct skd_special_context *skspcl); +static void skd_request_fn(struct request_queue *rq); +static void skd_end_request(struct skd_device *skdev, + struct skd_request_context *skreq, int error); +static int skd_preop_sg_list(struct skd_device *skdev, + struct skd_request_context *skreq); +static void skd_postop_sg_list(struct skd_device *skdev, + struct skd_request_context *skreq); + +static void skd_restart_device(struct skd_device *skdev); +static int skd_quiesce_dev(struct skd_device *skdev); +static int skd_unquiesce_dev(struct skd_device *skdev); +static void skd_release_special(struct skd_device *skdev, + struct skd_special_context *skspcl); +static void skd_disable_interrupts(struct skd_device *skdev); +static void skd_isr_fwstate(struct skd_device *skdev); +static void skd_recover_requests(struct skd_device *skdev, int requeue); +static void skd_soft_reset(struct skd_device *skdev); + +static const char *skd_name(struct skd_device *skdev); +const char *skd_drive_state_to_str(int state); +const char *skd_skdev_state_to_str(enum skd_drvr_state state); +static void skd_log_skdev(struct skd_device *skdev, const char *event); +static void skd_log_skmsg(struct skd_device *skdev, + struct skd_fitmsg_context *skmsg, const char *event); +static void skd_log_skreq(struct skd_device *skdev, + struct skd_request_context *skreq, const char *event); + +/* FLUSH FUA flag handling. */ +static int skd_flush_cmd_enqueue(struct skd_device *, void *); +static void *skd_flush_cmd_dequeue(struct skd_device *); + + +/* + ***************************************************************************** + * READ/WRITE REQUESTS + ***************************************************************************** + */ +static void skd_stop_queue(struct skd_device *skdev) +{ + if (!skd_bio) + blk_stop_queue(skdev->queue); + else + skdev->queue_stopped = 1; +} + +static void skd_unstop_queue(struct skd_device *skdev) +{ + if (!skd_bio) + queue_flag_clear(QUEUE_FLAG_STOPPED, skdev->queue); + else + skdev->queue_stopped = 0; +} + +static void skd_start_queue(struct skd_device *skdev) +{ + if (!skd_bio) { + blk_start_queue(skdev->queue); + } else { + pr_err("(%s): Starting queue\n", skd_name(skdev)); + skdev->queue_stopped = 0; + skd_request_fn(skdev->queue); + } +} + +static int skd_queue_stopped(struct skd_device *skdev) +{ + if (!skd_bio) + return blk_queue_stopped(skdev->queue); + else + return skdev->queue_stopped; +} + +static void skd_fail_all_pending_blk(struct skd_device *skdev) +{ + struct request_queue *q = skdev->queue; + struct request *req; + + for (;; ) { + req = blk_peek_request(q); + if (req == NULL) + break; + blk_start_request(req); + __blk_end_request_all(req, -EIO); + } +} + +static void skd_fail_all_pending_bio(struct skd_device *skdev) +{ + struct bio *bio; + int error = -EIO; + + for (;; ) { + bio = bio_list_pop(&skdev->bio_queue); + + if (bio == NULL) + break; + + bio_endio(bio, error); + } +} + +static void skd_fail_all_pending(struct skd_device *skdev) +{ + if (!skd_bio) + skd_fail_all_pending_blk(skdev); + else + skd_fail_all_pending_bio(skdev); +} + +static void skd_make_request(struct request_queue *q, struct bio *bio) +{ + struct skd_device *skdev = q->queuedata; + unsigned long flags; + + spin_lock_irqsave(&skdev->lock, flags); + + bio_list_add(&skdev->bio_queue, bio); + skd_request_fn(skdev->queue); + + spin_unlock_irqrestore(&skdev->lock, flags); +} + +static void +skd_prep_rw_cdb(struct skd_scsi_request *scsi_req, + int data_dir, unsigned lba, + unsigned count) +{ + if (data_dir == READ) + scsi_req->cdb[0] = 0x28; + else + scsi_req->cdb[0] = 0x2a; + + scsi_req->cdb[1] = 0; + scsi_req->cdb[2] = (lba & 0xff000000) >> 24; + scsi_req->cdb[3] = (lba & 0xff0000) >> 16; + scsi_req->cdb[4] = (lba & 0xff00) >> 8; + scsi_req->cdb[5] = (lba & 0xff); + scsi_req->cdb[6] = 0; + scsi_req->cdb[7] = (count & 0xff00) >> 8; + scsi_req->cdb[8] = count & 0xff; + scsi_req->cdb[9] = 0; +} + +static void +skd_prep_zerosize_flush_cdb(struct skd_scsi_request *scsi_req, + struct skd_request_context *skreq) +{ + skreq->flush_cmd = 1; + + scsi_req->cdb[0] = 0x35; + scsi_req->cdb[1] = 0; + scsi_req->cdb[2] = 0; + scsi_req->cdb[3] = 0; + scsi_req->cdb[4] = 0; + scsi_req->cdb[5] = 0; + scsi_req->cdb[6] = 0; + scsi_req->cdb[7] = 0; + scsi_req->cdb[8] = 0; + scsi_req->cdb[9] = 0; +} + +static void +skd_prep_discard_cdb(struct skd_scsi_request *scsi_req, + struct skd_request_context *skreq, + struct page *page, + u32 lba, u32 count) +{ + char *buf; + unsigned long len; + struct request *req; + + buf = page_address(page); + len = SKD_DISCARD_CDB_LENGTH; + + scsi_req->cdb[0] = UNMAP; + scsi_req->cdb[8] = len; + + put_unaligned_be16(6 + 16, &buf[0]); + put_unaligned_be16(16, &buf[2]); + put_unaligned_be64(lba, &buf[8]); + put_unaligned_be32(count, &buf[16]); + + if (!skd_bio) { + req = skreq->req; + blk_add_request_payload(req, page, len); + req->buffer = buf; + } else { + skreq->bio->bi_io_vec->bv_page = page; + skreq->bio->bi_io_vec->bv_offset = 0; + skreq->bio->bi_io_vec->bv_len = len; + + skreq->bio->bi_vcnt = 1; + skreq->bio->bi_phys_segments = 1; + } +} + +static void skd_request_fn_not_online(struct request_queue *q); + +static void skd_request_fn(struct request_queue *q) +{ + struct skd_device *skdev = q->queuedata; + struct skd_fitmsg_context *skmsg = NULL; + struct fit_msg_hdr *fmh = NULL; + struct skd_request_context *skreq; + struct request *req = NULL; + struct bio *bio = NULL; + struct skd_scsi_request *scsi_req; + struct page *page; + unsigned long io_flags; + int error; + u32 lba; + u32 count; + int data_dir; + u32 be_lba; + u32 be_count; + u64 be_dmaa; + u64 cmdctxt; + u32 timo_slot; + void *cmd_ptr; + int flush, fua; + + if (skdev->state != SKD_DRVR_STATE_ONLINE) { + skd_request_fn_not_online(q); + return; + } + + if (skd_queue_stopped(skdev)) { + if (skdev->skmsg_free_list == NULL || + skdev->skreq_free_list == NULL || + skdev->in_flight >= skdev->queue_low_water_mark) + /* There is still some kind of shortage */ + return; + + skd_unstop_queue(skdev); + } + + /* + * Stop conditions: + * - There are no more native requests + * - There are already the maximum number of requests in progress + * - There are no more skd_request_context entries + * - There are no more FIT msg buffers + */ + for (;; ) { + + flush = fua = 0; + + if (!skd_bio) { + req = blk_peek_request(q); + + /* Are there any native requests to start? */ + if (req == NULL) + break; + + lba = (u32)blk_rq_pos(req); + count = blk_rq_sectors(req); + data_dir = rq_data_dir(req); + io_flags = req->cmd_flags; + + if (io_flags & REQ_FLUSH) + flush++; + + if (io_flags & REQ_FUA) + fua++; + + VPRINTK(skdev, + "new req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + req, lba, lba, count, count, data_dir); + } else { + if (!list_empty(&skdev->flush_list)) { + /* Process data part of FLUSH request. */ + bio = (struct bio *)skd_flush_cmd_dequeue(skdev); + flush++; + VPRINTK(skdev, "processing FLUSH request with data.\n"); + } else { + /* peek at our bio queue */ + bio = bio_list_peek(&skdev->bio_queue); + } + + /* Are there any native requests to start? */ + if (bio == NULL) + break; + + lba = (u32)bio->bi_sector; + count = bio_sectors(bio); + data_dir = bio_data_dir(bio); + io_flags = bio->bi_rw; + + VPRINTK(skdev, + "new bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + bio, lba, lba, count, count, data_dir); + + if (io_flags & REQ_FLUSH) + flush++; + + if (io_flags & REQ_FUA) + fua++; + } + + /* At this point we know there is a request + * (from our bio q or req q depending on the way + * the driver is built do checks for resources. + */ + + /* Are too many requets already in progress? */ + if (skdev->in_flight >= skdev->cur_max_queue_depth) { + VPRINTK(skdev, "qdepth %d, limit %d\n", + skdev->in_flight, skdev->cur_max_queue_depth); + break; + } + + /* Is a skd_request_context available? */ + skreq = skdev->skreq_free_list; + if (skreq == NULL) { + VPRINTK(skdev, "Out of req=%p\n", q); + break; + } + SKD_ASSERT(skreq->state == SKD_REQ_STATE_IDLE); + SKD_ASSERT((skreq->id & SKD_ID_INCR) == 0); + + /* Now we check to see if we can get a fit msg */ + if (skmsg == NULL) { + if (skdev->skmsg_free_list == NULL) { + VPRINTK(skdev, "Out of msg\n"); + break; + } + } + + skreq->flush_cmd = 0; + skreq->n_sg = 0; + skreq->sg_byte_count = 0; + skreq->discard_page = 0; + + /* + * OK to now dequeue request from either bio or q. + * + * At this point we are comitted to either start or reject + * the native request. Note that skd_request_context is + * available but is still at the head of the free list. + */ + if (!skd_bio) { + blk_start_request(req); + skreq->req = req; + skreq->fitmsg_id = 0; + } else { + if (unlikely(flush == SKD_FLUSH_DATA_SECOND)) { + skreq->bio = bio; + } else { + skreq->bio = bio_list_pop(&skdev->bio_queue); + SKD_ASSERT(skreq->bio == bio); + skreq->start_time = jiffies; + part_inc_in_flight(&skdev->disk->part0, + bio_data_dir(bio)); + } + + skreq->fitmsg_id = 0; + } + + /* Either a FIT msg is in progress or we have to start one. */ + if (skmsg == NULL) { + /* Are there any FIT msg buffers available? */ + skmsg = skdev->skmsg_free_list; + if (skmsg == NULL) { + VPRINTK(skdev, "Out of msg skdev=%p\n", skdev); + break; + } + SKD_ASSERT(skmsg->state == SKD_MSG_STATE_IDLE); + SKD_ASSERT((skmsg->id & SKD_ID_INCR) == 0); + + skdev->skmsg_free_list = skmsg->next; + + skmsg->state = SKD_MSG_STATE_BUSY; + skmsg->id += SKD_ID_INCR; + + /* Initialize the FIT msg header */ + fmh = (struct fit_msg_hdr *)skmsg->msg_buf; + memset(fmh, 0, sizeof(*fmh)); + fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; + skmsg->length = sizeof(*fmh); + } + + skreq->fitmsg_id = skmsg->id; + + /* + * Note that a FIT msg may have just been started + * but contains no SoFIT requests yet. + */ + + /* + * Transcode the request, checking as we go. The outcome of + * the transcoding is represented by the error variable. + */ + cmd_ptr = &skmsg->msg_buf[skmsg->length]; + memset(cmd_ptr, 0, 32); + + be_lba = cpu_to_be32(lba); + be_count = cpu_to_be32(count); + be_dmaa = cpu_to_be64((u64)skreq->sksg_dma_address); + cmdctxt = skreq->id + SKD_ID_INCR; + + scsi_req = cmd_ptr; + scsi_req->hdr.tag = cmdctxt; + scsi_req->hdr.sg_list_dma_address = be_dmaa; + + if (data_dir == READ) + skreq->sg_data_dir = SKD_DATA_DIR_CARD_TO_HOST; + else + skreq->sg_data_dir = SKD_DATA_DIR_HOST_TO_CARD; + + if (io_flags & REQ_DISCARD) { + page = alloc_page(GFP_ATOMIC | __GFP_ZERO); + if (!page) { + pr_err("request_fn:Page allocation failed.\n"); + skd_end_request(skdev, skreq, -ENOMEM); + break; + } + skreq->discard_page = 1; + skd_prep_discard_cdb(scsi_req, skreq, page, lba, count); + + } else if (flush == SKD_FLUSH_ZERO_SIZE_FIRST) { + skd_prep_zerosize_flush_cdb(scsi_req, skreq); + SKD_ASSERT(skreq->flush_cmd == 1); + + } else { + skd_prep_rw_cdb(scsi_req, data_dir, lba, count); + } + + if (fua) + scsi_req->cdb[1] |= SKD_FUA_NV; + + if ((!skd_bio && !req->bio) || + (skd_bio && flush == SKD_FLUSH_ZERO_SIZE_FIRST)) + goto skip_sg; + + error = skd_preop_sg_list(skdev, skreq); + + if (error != 0) { + /* + * Complete the native request with error. + * Note that the request context is still at the + * head of the free list, and that the SoFIT request + * was encoded into the FIT msg buffer but the FIT + * msg length has not been updated. In short, the + * only resource that has been allocated but might + * not be used is that the FIT msg could be empty. + */ + DPRINTK(skdev, "error Out\n"); + skd_end_request(skdev, skreq, error); + continue; + } + +skip_sg: + scsi_req->hdr.sg_list_len_bytes = + cpu_to_be32(skreq->sg_byte_count); + + /* Complete resource allocations. */ + skdev->skreq_free_list = skreq->next; + skreq->state = SKD_REQ_STATE_BUSY; + skreq->id += SKD_ID_INCR; + + skmsg->length += sizeof(struct skd_scsi_request); + fmh->num_protocol_cmds_coalesced++; + + /* + * Update the active request counts. + * Capture the timeout timestamp. + */ + skreq->timeout_stamp = skdev->timeout_stamp; + timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; + skdev->timeout_slot[timo_slot]++; + skdev->in_flight++; + VPRINTK(skdev, "req=0x%x busy=%d\n", + skreq->id, skdev->in_flight); + + /* + * If the FIT msg buffer is full send it. + */ + if (skmsg->length >= SKD_N_FITMSG_BYTES || + fmh->num_protocol_cmds_coalesced >= skd_max_req_per_msg) { + skd_send_fitmsg(skdev, skmsg); + skmsg = NULL; + fmh = NULL; + } + } + + /* + * Is a FIT msg in progress? If it is empty put the buffer back + * on the free list. If it is non-empty send what we got. + * This minimizes latency when there are fewer requests than + * what fits in a FIT msg. + */ + if (skmsg != NULL) { + /* Bigger than just a FIT msg header? */ + if (skmsg->length > sizeof(struct fit_msg_hdr)) { + VPRINTK(skdev, "sending msg=%p, len %d\n", + skmsg, skmsg->length); + skd_send_fitmsg(skdev, skmsg); + } else { + /* + * The FIT msg is empty. It means we got started + * on the msg, but the requests were rejected. + */ + skmsg->state = SKD_MSG_STATE_IDLE; + skmsg->id += SKD_ID_INCR; + skmsg->next = skdev->skmsg_free_list; + skdev->skmsg_free_list = skmsg; + } + skmsg = NULL; + fmh = NULL; + } + + /* + * If req is non-NULL it means there is something to do but + * we are out of a resource. + */ + if (((!skd_bio) && req) || + ((skd_bio) && bio_list_peek(&skdev->bio_queue))) + skd_stop_queue(skdev); +} + +static void skd_end_request_blk(struct skd_device *skdev, + struct skd_request_context *skreq, int error) +{ + struct request *req = skreq->req; + unsigned int io_flags = req->cmd_flags; + + if ((io_flags & REQ_DISCARD) && + (skreq->discard_page == 1)) { + VPRINTK(skdev, "skd_end_request_blk, free the page!"); + free_page((unsigned long)req->buffer); + req->buffer = NULL; + } + + if (unlikely(error)) { + struct request *req = skreq->req; + char *cmd = (rq_data_dir(req) == READ) ? "read" : "write"; + u32 lba = (u32)blk_rq_pos(req); + u32 count = blk_rq_sectors(req); + + pr_err("(%s): Error cmd=%s sect=%u count=%u id=0x%x\n", + skd_name(skdev), cmd, lba, count, skreq->id); + } else + VPRINTK(skdev, "id=0x%x error=%d\n", skreq->id, error); + + __blk_end_request_all(skreq->req, error); +} + +static int skd_preop_sg_list_blk(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + struct request *req = skreq->req; + int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; + int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + struct scatterlist *sg = &skreq->sg[0]; + int n_sg; + int i; + + skreq->sg_byte_count = 0; + + /* SKD_ASSERT(skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD || + skreq->sg_data_dir == SKD_DATA_DIR_CARD_TO_HOST); */ + + n_sg = blk_rq_map_sg(skdev->queue, req, sg); + if (n_sg <= 0) + return -EINVAL; + + /* + * Map scatterlist to PCI bus addresses. + * Note PCI might change the number of entries. + */ + n_sg = pci_map_sg(skdev->pdev, sg, n_sg, pci_dir); + if (n_sg <= 0) + return -EINVAL; + + SKD_ASSERT(n_sg <= skdev->sgs_per_request); + + skreq->n_sg = n_sg; + + for (i = 0; i < n_sg; i++) { + struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; + u32 cnt = sg_dma_len(&sg[i]); + uint64_t dma_addr = sg_dma_address(&sg[i]); + + sgd->control = FIT_SGD_CONTROL_NOT_LAST; + sgd->byte_count = cnt; + skreq->sg_byte_count += cnt; + sgd->host_side_addr = dma_addr; + sgd->dev_side_addr = 0; + } + + skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL; + skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; + + if (unlikely(skdev->dbg_level > 1)) { + VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + for (i = 0; i < n_sg; i++) { + struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; + VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); + } + } + + return 0; +} + +static void skd_postop_sg_list_blk(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; + int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + + /* + * restore the next ptr for next IO request so we + * don't have to set it every time. + */ + skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = + skreq->sksg_dma_address + + ((skreq->n_sg) * sizeof(struct fit_sg_descriptor)); + pci_unmap_sg(skdev->pdev, &skreq->sg[0], skreq->n_sg, pci_dir); +} + +static void skd_end_request_bio(struct skd_device *skdev, + struct skd_request_context *skreq, int error) +{ + struct bio *bio = skreq->bio; + int rw = bio_data_dir(bio); + unsigned long io_flags = bio->bi_rw; + + if ((io_flags & REQ_DISCARD) && + (skreq->discard_page == 1)) { + VPRINTK(skdev, "biomode: skd_end_request: freeing DISCARD page.\n"); + free_page((unsigned long)page_address(bio->bi_io_vec->bv_page)); + } + + if (unlikely(error)) { + u32 lba = (u32)skreq->bio->bi_sector; + u32 count = bio_sectors(skreq->bio); + char *cmd = (rw == WRITE) ? "write" : "read"; + pr_err("(%s): Error cmd=%s sect=%u count=%u id=0x%x\n", + skd_name(skdev), cmd, lba, count, skreq->id); + } + { + int cpu = part_stat_lock(); + + if (likely(!error)) { + part_stat_inc(cpu, &skdev->disk->part0, ios[rw]); + part_stat_add(cpu, &skdev->disk->part0, sectors[rw], + bio_sectors(bio)); + } + part_stat_add(cpu, &skdev->disk->part0, ticks[rw], + jiffies - skreq->start_time); + part_dec_in_flight(&skdev->disk->part0, rw); + part_stat_unlock(); + } + + VPRINTK(skdev, "id=0x%x error=%d\n", skreq->id, error); + + bio_endio(skreq->bio, error); +} + +static int skd_preop_sg_list_bio(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + struct bio *bio = skreq->bio; + int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; + int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + int n_sg; + int i; + struct bio_vec *vec; + struct fit_sg_descriptor *sgd; + u64 dma_addr; + u32 count; + int errs = 0; + unsigned int io_flags = 0; + io_flags |= bio->bi_rw; + + skreq->sg_byte_count = 0; + n_sg = skreq->n_sg = skreq->bio->bi_vcnt; + + if (n_sg <= 0) + return -EINVAL; + + if (n_sg > skdev->sgs_per_request) { + pr_err("(%s): sg overflow n=%d\n", + skd_name(skdev), n_sg); + skreq->n_sg = 0; + return -EIO; + } + + for (i = 0; i < skreq->n_sg; i++) { + vec = bio_iovec_idx(bio, i); + dma_addr = pci_map_page(skdev->pdev, + vec->bv_page, + vec->bv_offset, vec->bv_len, pci_dir); + count = vec->bv_len; + + if (count == 0 || count > 64u * 1024u || (count & 3) != 0 + || (dma_addr & 3) != 0) { + pr_err( + "(%s): Bad sg ix=%d count=%d addr=0x%llx\n", + skd_name(skdev), i, count, dma_addr); + errs++; + } + + sgd = &skreq->sksg_list[i]; + + sgd->control = FIT_SGD_CONTROL_NOT_LAST; + sgd->byte_count = vec->bv_len; + skreq->sg_byte_count += vec->bv_len; + sgd->host_side_addr = dma_addr; + sgd->dev_side_addr = 0; /* not used */ + } + + skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL; + skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; + + + if (!(io_flags & REQ_DISCARD)) { + count = bio_sectors(bio) << 9u; + if (count != skreq->sg_byte_count) { + pr_err("(%s): mismatch count sg=%d req=%d\n", + skd_name(skdev), skreq->sg_byte_count, count); + errs++; + } + } + + if (unlikely(skdev->dbg_level > 1)) { + VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + for (i = 0; i < n_sg; i++) { + struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; + VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); + } + } + + if (errs != 0) { + skd_postop_sg_list(skdev, skreq); + skreq->n_sg = 0; + return -EIO; + } + + return 0; +} + +static int skd_preop_sg_list(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + if (!skd_bio) + return skd_preop_sg_list_blk(skdev, skreq); + else + return skd_preop_sg_list_bio(skdev, skreq); +} + +static void skd_postop_sg_list_bio(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; + int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; + int i; + struct fit_sg_descriptor *sgd; + + /* + * restore the next ptr for next IO request so we + * don't have to set it every time. + */ + skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = + skreq->sksg_dma_address + + ((skreq->n_sg) * sizeof(struct fit_sg_descriptor)); + + for (i = 0; i < skreq->n_sg; i++) { + sgd = &skreq->sksg_list[i]; + pci_unmap_page(skdev->pdev, sgd->host_side_addr, + sgd->byte_count, pci_dir); + } +} + +static void skd_postop_sg_list(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + if (!skd_bio) + skd_postop_sg_list_blk(skdev, skreq); + else + skd_postop_sg_list_bio(skdev, skreq); +} + +static void skd_end_request(struct skd_device *skdev, + struct skd_request_context *skreq, int error) +{ + if (likely(!skd_bio)) + skd_end_request_blk(skdev, skreq, error); + else + skd_end_request_bio(skdev, skreq, error); +} + +static void skd_request_fn_not_online(struct request_queue *q) +{ + struct skd_device *skdev = q->queuedata; + int error; + + SKD_ASSERT(skdev->state != SKD_DRVR_STATE_ONLINE); + + skd_log_skdev(skdev, "req_not_online"); + switch (skdev->state) { + case SKD_DRVR_STATE_PAUSING: + case SKD_DRVR_STATE_PAUSED: + case SKD_DRVR_STATE_STARTING: + case SKD_DRVR_STATE_RESTARTING: + case SKD_DRVR_STATE_WAIT_BOOT: + /* In case of starting, we haven't started the queue, + * so we can't get here... but requests are + * possibly hanging out waiting for us because we + * reported the dev/skd0 already. They'll wait + * forever if connect doesn't complete. + * What to do??? delay dev/skd0 ?? + */ + case SKD_DRVR_STATE_BUSY: + case SKD_DRVR_STATE_BUSY_IMMINENT: + case SKD_DRVR_STATE_BUSY_ERASE: + case SKD_DRVR_STATE_DRAINING_TIMEOUT: + return; + + case SKD_DRVR_STATE_BUSY_SANITIZE: + case SKD_DRVR_STATE_STOPPING: + case SKD_DRVR_STATE_SYNCING: + case SKD_DRVR_STATE_FAULT: + case SKD_DRVR_STATE_DISAPPEARED: + default: + error = -EIO; + break; + } + + /* If we get here, terminate all pending block requeusts + * with EIO and any scsi pass thru with appropriate sense + */ + + skd_fail_all_pending(skdev); +} + +/* + ***************************************************************************** + * TIMER + ***************************************************************************** + */ + +static void skd_timer_tick_not_online(struct skd_device *skdev); + +static void skd_timer_tick(ulong arg) +{ + struct skd_device *skdev = (struct skd_device *)arg; + + u32 timo_slot; + u32 overdue_timestamp; + unsigned long reqflags; + u32 state; + + if (skdev->state == SKD_DRVR_STATE_FAULT) + /* The driver has declared fault, and we want it to + * stay that way until driver is reloaded. + */ + return; + + spin_lock_irqsave(&skdev->lock, reqflags); + + state = SKD_READL(skdev, FIT_STATUS); + state &= FIT_SR_DRIVE_STATE_MASK; + if (state != skdev->drive_state) + skd_isr_fwstate(skdev); + + if (skdev->state != SKD_DRVR_STATE_ONLINE) { + skd_timer_tick_not_online(skdev); + goto timer_func_out; + } + skdev->timeout_stamp++; + timo_slot = skdev->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; + + /* + * All requests that happened during the previous use of + * this slot should be done by now. The previous use was + * over 7 seconds ago. + */ + if (skdev->timeout_slot[timo_slot] == 0) + goto timer_func_out; + + /* Something is overdue */ + overdue_timestamp = skdev->timeout_stamp - SKD_N_TIMEOUT_SLOT; + + DPRINTK(skdev, "found %d timeouts, draining busy=%d\n", + skdev->timeout_slot[timo_slot], skdev->in_flight); + pr_err("(%s): Overdue IOs (%d), busy %d\n", + skd_name(skdev), skdev->timeout_slot[timo_slot], + skdev->in_flight); + + skdev->timer_countdown = SKD_DRAINING_TIMO; + skdev->state = SKD_DRVR_STATE_DRAINING_TIMEOUT; + skdev->timo_slot = timo_slot; + skd_stop_queue(skdev); + +timer_func_out: + mod_timer(&skdev->timer, (jiffies + HZ)); + + spin_unlock_irqrestore(&skdev->lock, reqflags); +} + +static void skd_timer_tick_not_online(struct skd_device *skdev) +{ + switch (skdev->state) { + case SKD_DRVR_STATE_IDLE: + case SKD_DRVR_STATE_LOAD: + break; + case SKD_DRVR_STATE_BUSY_SANITIZE: + VPRINTK(skdev, "drive busy sanitize[%x], driver[%x]\n", + skdev->drive_state, skdev->state); + /* If we've been in sanitize for 3 seconds, we figure we're not + * going to get anymore completions, so recover requests now + */ + if (skdev->timer_countdown > 0) { + skdev->timer_countdown--; + return; + } + skd_recover_requests(skdev, 0); + break; + + case SKD_DRVR_STATE_BUSY: + case SKD_DRVR_STATE_BUSY_IMMINENT: + case SKD_DRVR_STATE_BUSY_ERASE: + VPRINTK(skdev, "busy[%x], countdown=%d\n", + skdev->state, skdev->timer_countdown); + if (skdev->timer_countdown > 0) { + skdev->timer_countdown--; + return; + } + DPRINTK(skdev, "busy[%x], timedout=%d, restarting device.", + skdev->state, skdev->timer_countdown); + skd_restart_device(skdev); + break; + + case SKD_DRVR_STATE_WAIT_BOOT: + case SKD_DRVR_STATE_STARTING: + if (skdev->timer_countdown > 0) { + skdev->timer_countdown--; + return; + } + /* For now, we fault the drive. Could attempt resets to + * revcover at some point. */ + skdev->state = SKD_DRVR_STATE_FAULT; + + pr_err("(%s): DriveFault Connect Timeout (%x)\n", + skd_name(skdev), skdev->drive_state); + + /*start the queue so we can respond with error to requests */ + /* wakeup anyone waiting for startup complete */ + skd_start_queue(skdev); + skdev->gendisk_on = -1; + wake_up_interruptible(&skdev->waitq); + break; + + case SKD_DRVR_STATE_ONLINE: + /* shouldn't get here. */ + break; + + case SKD_DRVR_STATE_PAUSING: + case SKD_DRVR_STATE_PAUSED: + break; + + case SKD_DRVR_STATE_DRAINING_TIMEOUT: + DPRINTK(skdev, + "draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n", + skdev->timo_slot, + skdev->timer_countdown, + skdev->in_flight, + skdev->timeout_slot[skdev->timo_slot]); + /* if the slot has cleared we can let the I/O continue */ + if (skdev->timeout_slot[skdev->timo_slot] == 0) { + DPRINTK(skdev, "Slot drained, starting queue.\n"); + skdev->state = SKD_DRVR_STATE_ONLINE; + skd_start_queue(skdev); + return; + } + if (skdev->timer_countdown > 0) { + skdev->timer_countdown--; + return; + } + skd_restart_device(skdev); + break; + + case SKD_DRVR_STATE_RESTARTING: + if (skdev->timer_countdown > 0) { + skdev->timer_countdown--; + return; + } + /* For now, we fault the drive. Could attempt resets to + * revcover at some point. */ + skdev->state = SKD_DRVR_STATE_FAULT; + pr_err("(%s): DriveFault Reconnect Timeout (%x)\n", + skd_name(skdev), skdev->drive_state); + + /* + * Recovering does two things: + * 1. completes IO with error + * 2. reclaims dma resources + * When is it safe to recover requests? + * - if the drive state is faulted + * - if the state is still soft reset after out timeout + * - if the drive registers are dead (state = FF) + * If it is "unsafe", we still need to recover, so we will + * disable pci bus mastering and disable our interrupts. + */ + + if ((skdev->drive_state == FIT_SR_DRIVE_SOFT_RESET) || + (skdev->drive_state == FIT_SR_DRIVE_FAULT) || + (skdev->drive_state == FIT_SR_DRIVE_STATE_MASK)) + /* It never came out of soft reset. Try to + * recover the requests and then let them + * fail. This is to mitigate hung processes. */ + skd_recover_requests(skdev, 0); + else { + pr_err("(%s): Disable BusMaster (%x)\n", + skd_name(skdev), skdev->drive_state); + pci_disable_device(skdev->pdev); + skd_disable_interrupts(skdev); + skd_recover_requests(skdev, 0); + } + + /*start the queue so we can respond with error to requests */ + /* wakeup anyone waiting for startup complete */ + skd_start_queue(skdev); + skdev->gendisk_on = -1; + wake_up_interruptible(&skdev->waitq); + break; + + case SKD_DRVR_STATE_RESUMING: + case SKD_DRVR_STATE_STOPPING: + case SKD_DRVR_STATE_SYNCING: + case SKD_DRVR_STATE_FAULT: + case SKD_DRVR_STATE_DISAPPEARED: + default: + break; + } +} + +static int skd_start_timer(struct skd_device *skdev) +{ + int rc; + + init_timer(&skdev->timer); + setup_timer(&skdev->timer, skd_timer_tick, (ulong)skdev); + + rc = mod_timer(&skdev->timer, (jiffies + HZ)); + if (rc) + pr_err("%s: failed to start timer %d\n", + __func__, rc); + return rc; +} + +static void skd_kill_timer(struct skd_device *skdev) +{ + del_timer_sync(&skdev->timer); +} + +/* + ***************************************************************************** + * IOCTL + ***************************************************************************** + */ +static int skd_ioctl_sg_io(struct skd_device *skdev, + fmode_t mode, void __user *argp); +static int skd_sg_io_get_and_check_args(struct skd_device *skdev, + struct skd_sg_io *sksgio); +static int skd_sg_io_obtain_skspcl(struct skd_device *skdev, + struct skd_sg_io *sksgio); +static int skd_sg_io_prep_buffering(struct skd_device *skdev, + struct skd_sg_io *sksgio); +static int skd_sg_io_copy_buffer(struct skd_device *skdev, + struct skd_sg_io *sksgio, int dxfer_dir); +static int skd_sg_io_send_fitmsg(struct skd_device *skdev, + struct skd_sg_io *sksgio); +static int skd_sg_io_await(struct skd_device *skdev, struct skd_sg_io *sksgio); +static int skd_sg_io_release_skspcl(struct skd_device *skdev, + struct skd_sg_io *sksgio); +static int skd_sg_io_put_status(struct skd_device *skdev, + struct skd_sg_io *sksgio); + +static void skd_complete_special(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 + *skcomp, + volatile struct fit_comp_error_info *skerr, + struct skd_special_context *skspcl); + +static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode, + uint cmd_in, ulong arg) +{ + int rc = 0; + struct gendisk *disk = bdev->bd_disk; + struct skd_device *skdev = disk->private_data; + void __user *p = (void *)arg; + + DPRINTK(skdev, "%s: CMD[%s] ioctl mode 0x%x, cmd 0x%x arg %0lx\n", + disk->disk_name, current->comm, mode, cmd_in, arg); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (cmd_in) { + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_VERSION_NUM: + rc = scsi_cmd_ioctl(disk->queue, disk, mode, cmd_in, p); + break; + case SG_IO: + rc = skd_ioctl_sg_io(skdev, mode, p); + break; + + default: + rc = -ENOTTY; + break; + } + + DPRINTK(skdev, "%s: completion rc %d\n", disk->disk_name, rc); + return rc; +} + +static int skd_ioctl_sg_io(struct skd_device *skdev, fmode_t mode, + void __user *argp) +{ + int rc; + struct skd_sg_io sksgio; + + memset(&sksgio, 0, sizeof(sksgio)); + sksgio.mode = mode; + sksgio.argp = argp; + sksgio.iov = &sksgio.no_iov_iov; + + switch (skdev->state) { + case SKD_DRVR_STATE_ONLINE: + case SKD_DRVR_STATE_BUSY_IMMINENT: + break; + + default: + DPRINTK(skdev, "drive not online\n"); + rc = -ENXIO; + goto out; + } + + if ((rc = skd_sg_io_get_and_check_args(skdev, &sksgio)) || + (rc = skd_sg_io_obtain_skspcl(skdev, &sksgio)) || + (rc = skd_sg_io_prep_buffering(skdev, &sksgio)) || + (rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_TO_DEV))) + goto out; + + if ((rc = skd_sg_io_send_fitmsg(skdev, &sksgio)) || + (rc = skd_sg_io_await(skdev, &sksgio))) + goto out; + + if ((rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_FROM_DEV)) || + (rc = skd_sg_io_put_status(skdev, &sksgio))) + goto out; + + rc = 0; + +out: + skd_sg_io_release_skspcl(skdev, &sksgio); + + if (sksgio.iov != NULL && sksgio.iov != &sksgio.no_iov_iov) + kfree(sksgio.iov); + return rc; +} + +static int skd_sg_io_get_and_check_args(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct sg_io_hdr *sgp = &sksgio->sg; + int i, acc; + + if (!access_ok(VERIFY_WRITE, sksgio->argp, sizeof(sg_io_hdr_t))) { + DPRINTK(skdev, "access sg failed %p\n", sksgio->argp); + return -EFAULT; + } + + if (__copy_from_user(sgp, sksgio->argp, sizeof(sg_io_hdr_t))) { + DPRINTK(skdev, "copy_from_user sg failed %p\n", sksgio->argp); + return -EFAULT; + } + + if (sgp->interface_id != SG_INTERFACE_ID_ORIG) { + DPRINTK(skdev, "interface_id invalid 0x%x\n", + sgp->interface_id); + return -EINVAL; + } + + if (sgp->cmd_len > sizeof(sksgio->cdb)) { + DPRINTK(skdev, "cmd_len invalid %d\n", sgp->cmd_len); + return -EINVAL; + } + + if (sgp->iovec_count > 256) { + DPRINTK(skdev, "iovec_count invalid %d\n", sgp->iovec_count); + return -EINVAL; + } + + if (sgp->dxfer_len > (PAGE_SIZE * SKD_N_SG_PER_SPECIAL)) { + DPRINTK(skdev, "dxfer_len invalid %d\n", sgp->dxfer_len); + return -EINVAL; + } + + switch (sgp->dxfer_direction) { + case SG_DXFER_NONE: + acc = -1; + break; + + case SG_DXFER_TO_DEV: + acc = VERIFY_READ; + break; + + case SG_DXFER_FROM_DEV: + case SG_DXFER_TO_FROM_DEV: + acc = VERIFY_WRITE; + break; + + default: + DPRINTK(skdev, "dxfer_dir invalid %d\n", sgp->dxfer_direction); + return -EINVAL; + } + + if (copy_from_user(sksgio->cdb, sgp->cmdp, sgp->cmd_len)) { + DPRINTK(skdev, "copy_from_user cmdp failed %p\n", sgp->cmdp); + return -EFAULT; + } + + if (sgp->mx_sb_len != 0) { + if (!access_ok(VERIFY_WRITE, sgp->sbp, sgp->mx_sb_len)) { + DPRINTK(skdev, "access sbp failed %p\n", sgp->sbp); + return -EFAULT; + } + } + + if (sgp->iovec_count == 0) { + sksgio->iov[0].iov_base = sgp->dxferp; + sksgio->iov[0].iov_len = sgp->dxfer_len; + sksgio->iovcnt = 1; + sksgio->dxfer_len = sgp->dxfer_len; + } else { + struct sg_iovec *iov; + uint nbytes = sizeof(*iov) * sgp->iovec_count; + size_t iov_data_len; + + iov = kmalloc(nbytes, GFP_KERNEL); + if (iov == NULL) { + DPRINTK(skdev, "alloc iovec failed %d\n", + sgp->iovec_count); + return -ENOMEM; + } + sksgio->iov = iov; + sksgio->iovcnt = sgp->iovec_count; + + if (copy_from_user(iov, sgp->dxferp, nbytes)) { + DPRINTK(skdev, "copy_from_user iovec failed %p\n", + sgp->dxferp); + return -EFAULT; + } + + /* + * Sum up the vecs, making sure they don't overflow + */ + iov_data_len = 0; + for (i = 0; i < sgp->iovec_count; i++) { + if (iov_data_len + iov[i].iov_len < iov_data_len) + return -EINVAL; + iov_data_len += iov[i].iov_len; + } + + /* SG_IO howto says that the shorter of the two wins */ + if (sgp->dxfer_len < iov_data_len) { + sksgio->iovcnt = iov_shorten((struct iovec *)iov, + sgp->iovec_count, + sgp->dxfer_len); + sksgio->dxfer_len = sgp->dxfer_len; + } else + sksgio->dxfer_len = iov_data_len; + } + + if (sgp->dxfer_direction != SG_DXFER_NONE) { + struct sg_iovec *iov = sksgio->iov; + for (i = 0; i < sksgio->iovcnt; i++, iov++) { + if (!access_ok(acc, iov->iov_base, iov->iov_len)) { + DPRINTK(skdev, "access data failed %p/%d\n", + iov->iov_base, (int)iov->iov_len); + return -EFAULT; + } + } + } + + return 0; +} + +static int skd_sg_io_obtain_skspcl(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct skd_special_context *skspcl = NULL; + int rc; + + for (;; ) { + ulong flags; + + spin_lock_irqsave(&skdev->lock, flags); + skspcl = skdev->skspcl_free_list; + if (skspcl != NULL) { + skdev->skspcl_free_list = + (struct skd_special_context *)skspcl->req.next; + skspcl->req.id += SKD_ID_INCR; + skspcl->req.state = SKD_REQ_STATE_SETUP; + skspcl->orphaned = 0; + skspcl->req.n_sg = 0; + } + spin_unlock_irqrestore(&skdev->lock, flags); + + if (skspcl != NULL) { + rc = 0; + break; + } + + DPRINTK(skdev, "blocking\n"); + + rc = wait_event_interruptible_timeout( + skdev->waitq, + (skdev->skspcl_free_list != NULL), + msecs_to_jiffies(sksgio->sg.timeout)); + + DPRINTK(skdev, "unblocking, rc=%d\n", rc); + + if (rc <= 0) { + if (rc == 0) + rc = -ETIMEDOUT; + else + rc = -EINTR; + break; + } + /* + * If we get here rc > 0 meaning the timeout to + * wait_event_interruptible_timeout() had time left, hence the + * sought event -- non-empty free list -- happened. + * Retry the allocation. + */ + } + sksgio->skspcl = skspcl; + + return rc; +} + +static int skd_skreq_prep_buffering(struct skd_device *skdev, + struct skd_request_context *skreq, + u32 dxfer_len) +{ + u32 resid = dxfer_len; + + /* + * The DMA engine must have aligned addresses and byte counts. + */ + resid += (-resid) & 3; + skreq->sg_byte_count = resid; + + skreq->n_sg = 0; + + while (resid > 0) { + u32 nbytes = PAGE_SIZE; + u32 ix = skreq->n_sg; + struct scatterlist *sg = &skreq->sg[ix]; + struct fit_sg_descriptor *sksg = &skreq->sksg_list[ix]; + struct page *page; + + if (nbytes > resid) + nbytes = resid; + + page = alloc_page(GFP_KERNEL); + if (page == NULL) + return -ENOMEM; + + sg_set_page(sg, page, nbytes, 0); + + /* TODO: This should be going through a pci_???() + * routine to do proper mapping. */ + sksg->control = FIT_SGD_CONTROL_NOT_LAST; + sksg->byte_count = nbytes; + + sksg->host_side_addr = sg_phys(sg); + + sksg->dev_side_addr = 0; + sksg->next_desc_ptr = skreq->sksg_dma_address + + (ix + 1) * sizeof(*sksg); + + skreq->n_sg++; + resid -= nbytes; + } + + if (skreq->n_sg > 0) { + u32 ix = skreq->n_sg - 1; + struct fit_sg_descriptor *sksg = &skreq->sksg_list[ix]; + + sksg->control = FIT_SGD_CONTROL_LAST; + sksg->next_desc_ptr = 0; + } + + if (unlikely(skdev->dbg_level > 1)) { + u32 i; + + VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + for (i = 0; i < skreq->n_sg; i++) { + struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; + + VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); + } + } + + return 0; +} + +static int skd_sg_io_prep_buffering(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct skd_special_context *skspcl = sksgio->skspcl; + struct skd_request_context *skreq = &skspcl->req; + u32 dxfer_len = sksgio->dxfer_len; + int rc; + + rc = skd_skreq_prep_buffering(skdev, skreq, dxfer_len); + /* + * Eventually, errors or not, skd_release_special() is called + * to recover allocations including partial allocations. + */ + return rc; +} + +static int skd_sg_io_copy_buffer(struct skd_device *skdev, + struct skd_sg_io *sksgio, int dxfer_dir) +{ + struct skd_special_context *skspcl = sksgio->skspcl; + u32 iov_ix = 0; + struct sg_iovec curiov; + u32 sksg_ix = 0; + u8 *bufp = NULL; + u32 buf_len = 0; + u32 resid = sksgio->dxfer_len; + int rc; + + curiov.iov_len = 0; + curiov.iov_base = NULL; + + if (dxfer_dir != sksgio->sg.dxfer_direction) { + if (dxfer_dir != SG_DXFER_TO_DEV || + sksgio->sg.dxfer_direction != SG_DXFER_TO_FROM_DEV) + return 0; + } + + while (resid > 0) { + u32 nbytes = PAGE_SIZE; + + if (curiov.iov_len == 0) { + curiov = sksgio->iov[iov_ix++]; + continue; + } + + if (buf_len == 0) { + struct page *page; + page = sg_page(&skspcl->req.sg[sksg_ix++]); + bufp = page_address(page); + buf_len = PAGE_SIZE; + } + + nbytes = min_t(u32, nbytes, resid); + nbytes = min_t(u32, nbytes, curiov.iov_len); + nbytes = min_t(u32, nbytes, buf_len); + + if (dxfer_dir == SG_DXFER_TO_DEV) + rc = __copy_from_user(bufp, curiov.iov_base, nbytes); + else + rc = __copy_to_user(curiov.iov_base, bufp, nbytes); + + if (rc) + return -EFAULT; + + resid -= nbytes; + curiov.iov_len -= nbytes; + curiov.iov_base += nbytes; + buf_len -= nbytes; + } + + return 0; +} + +static int skd_sg_io_send_fitmsg(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct skd_special_context *skspcl = sksgio->skspcl; + struct fit_msg_hdr *fmh = (struct fit_msg_hdr *)skspcl->msg_buf; + struct skd_scsi_request *scsi_req = (struct skd_scsi_request *)&fmh[1]; + + memset(skspcl->msg_buf, 0, SKD_N_SPECIAL_FITMSG_BYTES); + + /* Initialize the FIT msg header */ + fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; + fmh->num_protocol_cmds_coalesced = 1; + + /* Initialize the SCSI request */ + if (sksgio->sg.dxfer_direction != SG_DXFER_NONE) + scsi_req->hdr.sg_list_dma_address = + cpu_to_be64(skspcl->req.sksg_dma_address); + scsi_req->hdr.tag = skspcl->req.id; + scsi_req->hdr.sg_list_len_bytes = + cpu_to_be32(skspcl->req.sg_byte_count); + memcpy(scsi_req->cdb, sksgio->cdb, sizeof(scsi_req->cdb)); + + skspcl->req.state = SKD_REQ_STATE_BUSY; + skd_send_special_fitmsg(skdev, skspcl); + + return 0; +} + +static int skd_sg_io_await(struct skd_device *skdev, struct skd_sg_io *sksgio) +{ + unsigned long flags; + int rc; + + rc = wait_event_interruptible_timeout(skdev->waitq, + (sksgio->skspcl->req.state != + SKD_REQ_STATE_BUSY), + msecs_to_jiffies(sksgio->sg. + timeout)); + + spin_lock_irqsave(&skdev->lock, flags); + + if (sksgio->skspcl->req.state == SKD_REQ_STATE_ABORTED) { + DPRINTK(skdev, "skspcl %p aborted\n", sksgio->skspcl); + + /* Build check cond, sense and let command finish. */ + /* For a timeout, we must fabricate completion and sense + * data to complete the command */ + sksgio->skspcl->req.completion.status = + SAM_STAT_CHECK_CONDITION; + + memset(&sksgio->skspcl->req.err_info, 0, + sizeof(sksgio->skspcl->req.err_info)); + sksgio->skspcl->req.err_info.type = 0x70; + sksgio->skspcl->req.err_info.key = ABORTED_COMMAND; + sksgio->skspcl->req.err_info.code = 0x44; + sksgio->skspcl->req.err_info.qual = 0; + rc = 0; + } else if (sksgio->skspcl->req.state != SKD_REQ_STATE_BUSY) + /* No longer on the adapter. We finish. */ + rc = 0; + else { + /* Something's gone wrong. Still busy. Timeout or + * user interrupted (control-C). Mark as an orphan + * so it will be disposed when completed. */ + sksgio->skspcl->orphaned = 1; + sksgio->skspcl = NULL; + if (rc == 0) { + DPRINTK(skdev, "timed out %p (%u ms)\n", sksgio, + sksgio->sg.timeout); + rc = -ETIMEDOUT; + } else { + DPRINTK(skdev, "cntlc %p\n", sksgio); + rc = -EINTR; + } + } + + spin_unlock_irqrestore(&skdev->lock, flags); + + return rc; +} + +static int skd_sg_io_put_status(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct sg_io_hdr *sgp = &sksgio->sg; + struct skd_special_context *skspcl = sksgio->skspcl; + int resid = 0; + + u32 nb = be32_to_cpu(skspcl->req.completion.num_returned_bytes); + + sgp->status = skspcl->req.completion.status; + resid = sksgio->dxfer_len - nb; + + sgp->masked_status = sgp->status & STATUS_MASK; + sgp->msg_status = 0; + sgp->host_status = 0; + sgp->driver_status = 0; + sgp->resid = resid; + if (sgp->masked_status || sgp->host_status || sgp->driver_status) + sgp->info |= SG_INFO_CHECK; + + DPRINTK(skdev, "status %x masked %x resid 0x%x\n", sgp->status, + sgp->masked_status, sgp->resid); + + if (sgp->masked_status == SAM_STAT_CHECK_CONDITION) { + if (sgp->mx_sb_len > 0) { + struct fit_comp_error_info *ei = &skspcl->req.err_info; + u32 nbytes = sizeof(*ei); + + nbytes = min_t(u32, nbytes, sgp->mx_sb_len); + + sgp->sb_len_wr = nbytes; + + if (__copy_to_user(sgp->sbp, ei, nbytes)) { + DPRINTK(skdev, "copy_to_user sense failed %p\n", + sgp->sbp); + return -EFAULT; + } + } + } + + if (__copy_to_user(sksgio->argp, sgp, sizeof(sg_io_hdr_t))) { + DPRINTK(skdev, "copy_to_user sg failed %p\n", sksgio->argp); + return -EFAULT; + } + + return 0; +} + +static int skd_sg_io_release_skspcl(struct skd_device *skdev, + struct skd_sg_io *sksgio) +{ + struct skd_special_context *skspcl = sksgio->skspcl; + + if (skspcl != NULL) { + ulong flags; + + sksgio->skspcl = NULL; + + spin_lock_irqsave(&skdev->lock, flags); + skd_release_special(skdev, skspcl); + spin_unlock_irqrestore(&skdev->lock, flags); + } + + return 0; +} + +/* + ***************************************************************************** + * INTERNAL REQUESTS -- generated by driver itself + ***************************************************************************** + */ + +static int skd_format_internal_skspcl(struct skd_device *skdev) +{ + struct skd_special_context *skspcl = &skdev->internal_skspcl; + struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; + struct fit_msg_hdr *fmh; + uint64_t dma_address; + struct skd_scsi_request *scsi; + + fmh = (struct fit_msg_hdr *)&skspcl->msg_buf[0]; + fmh->protocol_id = FIT_PROTOCOL_ID_SOFIT; + fmh->num_protocol_cmds_coalesced = 1; + + scsi = (struct skd_scsi_request *)&skspcl->msg_buf[64]; + memset(scsi, 0, sizeof(*scsi)); + dma_address = skspcl->req.sksg_dma_address; + scsi->hdr.sg_list_dma_address = cpu_to_be64(dma_address); + sgd->control = FIT_SGD_CONTROL_LAST; + sgd->byte_count = 0; + sgd->host_side_addr = skspcl->db_dma_address; + sgd->dev_side_addr = 0; + sgd->next_desc_ptr = 0LL; + + return 1; +} + +#define WR_BUF_SIZE SKD_N_INTERNAL_BYTES + +static void skd_send_internal_skspcl(struct skd_device *skdev, + struct skd_special_context *skspcl, + u8 opcode) +{ + struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[0]; + struct skd_scsi_request *scsi; + unsigned char *buf = skspcl->data_buf; + int i; + + if (skspcl->req.state != SKD_REQ_STATE_IDLE) + /* + * A refresh is already in progress. + * Just wait for it to finish. + */ + return; + + SKD_ASSERT((skspcl->req.id & SKD_ID_INCR) == 0); + skspcl->req.state = SKD_REQ_STATE_BUSY; + skspcl->req.id += SKD_ID_INCR; + + scsi = (struct skd_scsi_request *)&skspcl->msg_buf[64]; + scsi->hdr.tag = skspcl->req.id; + + memset(scsi->cdb, 0, sizeof(scsi->cdb)); + + switch (opcode) { + case TEST_UNIT_READY: + scsi->cdb[0] = TEST_UNIT_READY; + sgd->byte_count = 0; + scsi->hdr.sg_list_len_bytes = 0; + break; + + case READ_CAPACITY: + scsi->cdb[0] = READ_CAPACITY; + sgd->byte_count = SKD_N_READ_CAP_BYTES; + scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); + break; + + case INQUIRY: + scsi->cdb[0] = INQUIRY; + scsi->cdb[1] = 0x01; /* evpd */ + scsi->cdb[2] = 0x80; /* serial number page */ + scsi->cdb[4] = 0x10; + sgd->byte_count = 16; + scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); + break; + + case SYNCHRONIZE_CACHE: + scsi->cdb[0] = SYNCHRONIZE_CACHE; + sgd->byte_count = 0; + scsi->hdr.sg_list_len_bytes = 0; + break; + + case WRITE_BUFFER: + scsi->cdb[0] = WRITE_BUFFER; + scsi->cdb[1] = 0x02; + scsi->cdb[7] = (WR_BUF_SIZE & 0xFF00) >> 8; + scsi->cdb[8] = WR_BUF_SIZE & 0xFF; + sgd->byte_count = WR_BUF_SIZE; + scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); + /* fill incrementing byte pattern */ + for (i = 0; i < sgd->byte_count; i++) + buf[i] = i & 0xFF; + break; + + case READ_BUFFER: + scsi->cdb[0] = READ_BUFFER; + scsi->cdb[1] = 0x02; + scsi->cdb[7] = (WR_BUF_SIZE & 0xFF00) >> 8; + scsi->cdb[8] = WR_BUF_SIZE & 0xFF; + sgd->byte_count = WR_BUF_SIZE; + scsi->hdr.sg_list_len_bytes = cpu_to_be32(sgd->byte_count); + memset(skspcl->data_buf, 0, sgd->byte_count); + break; + + default: + SKD_ASSERT("Don't know what to send"); + return; + + } + skd_send_special_fitmsg(skdev, skspcl); +} + +static void skd_refresh_device_data(struct skd_device *skdev) +{ + struct skd_special_context *skspcl = &skdev->internal_skspcl; + + skd_send_internal_skspcl(skdev, skspcl, TEST_UNIT_READY); +} + +static int skd_chk_read_buf(struct skd_device *skdev, + struct skd_special_context *skspcl) +{ + unsigned char *buf = skspcl->data_buf; + int i; + + /* check for incrementing byte pattern */ + for (i = 0; i < WR_BUF_SIZE; i++) + if (buf[i] != (i & 0xFF)) + return 1; + + return 0; +} + +static void skd_log_check_status(struct skd_device *skdev, u8 status, u8 key, + u8 code, u8 qual, u8 fruc) +{ + /* If the check condition is of special interest, log a message */ + if ((status == SAM_STAT_CHECK_CONDITION) && (key == 0x02) + && (code == 0x04) && (qual == 0x06)) { + pr_err("(%s): *** LOST_WRITE_DATA ERROR *** key/asc/" + "ascq/fruc %02x/%02x/%02x/%02x\n", + skd_name(skdev), key, code, qual, fruc); + } +} + +static void skd_complete_internal(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 + *skcomp, + volatile struct fit_comp_error_info *skerr, + struct skd_special_context *skspcl) +{ + u8 *buf = skspcl->data_buf; + u8 status; + int i; + struct skd_scsi_request *scsi = + (struct skd_scsi_request *)&skspcl->msg_buf[64]; + + SKD_ASSERT(skspcl == &skdev->internal_skspcl); + + DPRINTK(skdev, "complete internal %x\n", scsi->cdb[0]); + + skspcl->req.completion = *skcomp; + skspcl->req.state = SKD_REQ_STATE_IDLE; + skspcl->req.id += SKD_ID_INCR; + + status = skspcl->req.completion.status; + + skd_log_check_status(skdev, status, skerr->key, skerr->code, + skerr->qual, skerr->fruc); + + switch (scsi->cdb[0]) { + case TEST_UNIT_READY: + if (status == SAM_STAT_GOOD) + skd_send_internal_skspcl(skdev, skspcl, WRITE_BUFFER); + else if ((status == SAM_STAT_CHECK_CONDITION) && + (skerr->key == MEDIUM_ERROR)) + skd_send_internal_skspcl(skdev, skspcl, WRITE_BUFFER); + else { + if (skdev->state == SKD_DRVR_STATE_STOPPING) { + VPRINTK(skdev, "TUR failed, don't send anymore" + "state 0x%x\n", skdev->state); + return; + } + DPRINTK(skdev, "**** TUR failed, retry skerr\n"); + skd_send_internal_skspcl(skdev, skspcl, 0x00); + } + break; + + case WRITE_BUFFER: + if (status == SAM_STAT_GOOD) + skd_send_internal_skspcl(skdev, skspcl, READ_BUFFER); + else { + if (skdev->state == SKD_DRVR_STATE_STOPPING) { + VPRINTK(skdev, "write buffer failed, don't send" + " anymore state 0x%x\n", skdev->state); + return; + } + DPRINTK(skdev, + "**** write buffer failed, retry skerr\n"); + skd_send_internal_skspcl(skdev, skspcl, 0x00); + } + break; + + case READ_BUFFER: + if (status == SAM_STAT_GOOD) { + if (skd_chk_read_buf(skdev, skspcl) == 0) + skd_send_internal_skspcl(skdev, skspcl, + READ_CAPACITY); + else { + pr_err( + "(%s):*** W/R Buffer mismatch %d ***\n", + skd_name(skdev), skdev->connect_retries); + if (skdev->connect_retries < + SKD_MAX_CONNECT_RETRIES) { + skdev->connect_retries++; + skd_soft_reset(skdev); + } else { + pr_err( + "(%s): W/R Buffer Connect Error\n", + skd_name(skdev)); + return; + } + } + + } else { + if (skdev->state == SKD_DRVR_STATE_STOPPING) { + VPRINTK(skdev, + "read buffer failed, don't send anymore" + "state 0x%x\n", skdev->state); + return; + } + DPRINTK(skdev, + "**** read buffer failed, retry skerr\n"); + skd_send_internal_skspcl(skdev, skspcl, 0x00); + } + break; + + case READ_CAPACITY: + skdev->read_cap_is_valid = 0; + if (status == SAM_STAT_GOOD) { + skdev->read_cap_last_lba = + (buf[0] << 24) | (buf[1] << 16) | + (buf[2] << 8) | buf[3]; + skdev->read_cap_blocksize = + (buf[4] << 24) | (buf[5] << 16) | + (buf[6] << 8) | buf[7]; + + DPRINTK(skdev, "last lba %d, bs %d\n", + skdev->read_cap_last_lba, + skdev->read_cap_blocksize); + + set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); + + skdev->read_cap_is_valid = 1; + + skd_send_internal_skspcl(skdev, skspcl, INQUIRY); + } else if ((status == SAM_STAT_CHECK_CONDITION) && + (skerr->key == MEDIUM_ERROR)) { + skdev->read_cap_last_lba = ~0; + set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); + DPRINTK(skdev, + "**** MEDIUM ERROR caused READCAP to fail, ignore failure and continue to inquiry\n"); + skd_send_internal_skspcl(skdev, skspcl, INQUIRY); + } else { + DPRINTK(skdev, "**** READCAP failed, retry TUR\n"); + skd_send_internal_skspcl(skdev, skspcl, + TEST_UNIT_READY); + } + break; + + case INQUIRY: + skdev->inquiry_is_valid = 0; + if (status == SAM_STAT_GOOD) { + skdev->inquiry_is_valid = 1; + + for (i = 0; i < 12; i++) + skdev->inq_serial_num[i] = buf[i + 4]; + skdev->inq_serial_num[12] = 0; + } + + if (skd_unquiesce_dev(skdev) < 0) + DPRINTK(skdev, "**** failed, to ONLINE device\n"); + /* connection is complete */ + skdev->connect_retries = 0; + break; + + case SYNCHRONIZE_CACHE: + if (status == SAM_STAT_GOOD) + skdev->sync_done = 1; + else + skdev->sync_done = -1; + wake_up_interruptible(&skdev->waitq); + break; + + default: + SKD_ASSERT("we didn't send this"); + } +} + +/* + ***************************************************************************** + * FIT MESSAGES + ***************************************************************************** + */ + +static void skd_send_fitmsg(struct skd_device *skdev, + struct skd_fitmsg_context *skmsg) +{ + u64 qcmd; + struct fit_msg_hdr *fmh; + + VPRINTK(skdev, "dma address 0x%llx, busy=%d\n", + skmsg->mb_dma_address, skdev->in_flight); + VPRINTK(skdev, "msg_buf 0x%p, offset %x\n", + skmsg->msg_buf, skmsg->offset); + + qcmd = skmsg->mb_dma_address; + qcmd |= FIT_QCMD_QID_NORMAL; + + fmh = (struct fit_msg_hdr *)skmsg->msg_buf; + skmsg->outstanding = fmh->num_protocol_cmds_coalesced; + + if (unlikely(skdev->dbg_level > 1)) { + u8 *bp = (u8 *)skmsg->msg_buf; + int i; + for (i = 0; i < skmsg->length; i += 8) { + VPRINTK(skdev, " msg[%2d] %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + i, bp[i + 0], bp[i + 1], bp[i + 2], + bp[i + 3], bp[i + 4], bp[i + 5], + bp[i + 6], bp[i + 7]); + if (i == 0) + i = 64 - 8; + } + } + + if (skmsg->length > 256) + qcmd |= FIT_QCMD_MSGSIZE_512; + else if (skmsg->length > 128) + qcmd |= FIT_QCMD_MSGSIZE_256; + else if (skmsg->length > 64) + qcmd |= FIT_QCMD_MSGSIZE_128; + else + /* + * This makes no sense because the FIT msg header is + * 64 bytes. If the msg is only 64 bytes long it has + * no payload. + */ + qcmd |= FIT_QCMD_MSGSIZE_64; + + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); + +} + +static void skd_send_special_fitmsg(struct skd_device *skdev, + struct skd_special_context *skspcl) +{ + u64 qcmd; + + if (unlikely(skdev->dbg_level > 1)) { + u8 *bp = (u8 *)skspcl->msg_buf; + int i; + + for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) { + VPRINTK(skdev, + " spcl[%2d] %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", i, + bp[i + 0], bp[i + 1], bp[i + 2], bp[i + 3], + bp[i + 4], bp[i + 5], bp[i + 6], bp[i + 7]); + if (i == 0) + i = 64 - 8; + } + + VPRINTK(skdev, "skspcl=%p id=%04x sksg_list=%p sksg_dma=%llx\n", + skspcl, skspcl->req.id, skspcl->req.sksg_list, + skspcl->req.sksg_dma_address); + for (i = 0; i < skspcl->req.n_sg; i++) { + struct fit_sg_descriptor *sgd = + &skspcl->req.sksg_list[i]; + + VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); + } + } + + /* + * Special FIT msgs are always 128 bytes: a 64-byte FIT hdr + * and one 64-byte SSDI command. + */ + qcmd = skspcl->mb_dma_address; + qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128; + + SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND); +} + +/* + ***************************************************************************** + * COMPLETION QUEUE + ***************************************************************************** + */ + +static void skd_complete_other(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 *skcomp, + volatile struct fit_comp_error_info *skerr); + + +static void skd_requeue_request(struct skd_device *skdev, + struct skd_request_context *skreq); + +struct sns_info { + u8 type; + u8 stat; + u8 key; + u8 asc; + u8 ascq; + u8 mask; + enum skd_check_status_action action; +}; + +static struct sns_info skd_chkstat_table[] = { + /* Good */ + { 0x70, 0x02, RECOVERED_ERROR, 0, 0, 0x1c, + SKD_CHECK_STATUS_REPORT_GOOD }, + + /* Smart alerts */ + { 0x70, 0x02, NO_SENSE, 0x0B, 0x00, 0x1E, /* warnings */ + SKD_CHECK_STATUS_REPORT_SMART_ALERT }, + { 0x70, 0x02, NO_SENSE, 0x5D, 0x00, 0x1E, /* thresholds */ + SKD_CHECK_STATUS_REPORT_SMART_ALERT }, + { 0x70, 0x02, RECOVERED_ERROR, 0x0B, 0x01, 0x1F, /* temperature over trigger */ + SKD_CHECK_STATUS_REPORT_SMART_ALERT }, + + /* Retry (with limits) */ + { 0x70, 0x02, 0x0B, 0, 0, 0x1C, /* This one is for DMA ERROR */ + SKD_CHECK_STATUS_REQUEUE_REQUEST }, + { 0x70, 0x02, 0x06, 0x0B, 0x00, 0x1E, /* warnings */ + SKD_CHECK_STATUS_REQUEUE_REQUEST }, + { 0x70, 0x02, 0x06, 0x5D, 0x00, 0x1E, /* thresholds */ + SKD_CHECK_STATUS_REQUEUE_REQUEST }, + { 0x70, 0x02, 0x06, 0x80, 0x30, 0x1F, /* backup power */ + SKD_CHECK_STATUS_REQUEUE_REQUEST }, + + /* Busy (or about to be) */ + { 0x70, 0x02, 0x06, 0x3f, 0x01, 0x1F, /* fw changed */ + SKD_CHECK_STATUS_BUSY_IMMINENT }, +}; + +/* + * Look up status and sense data to decide how to handle the error + * from the device. + * mask says which fields must match e.g., mask=0x18 means check + * type and stat, ignore key, asc, ascq. + */ + +static enum skd_check_status_action skd_check_status(struct skd_device *skdev, + u8 cmp_status, + volatile struct fit_comp_error_info *skerr) +{ + int i, n; + + pr_err("(%s): key/asc/ascq/fruc %02x/%02x/%02x/%02x\n", + skd_name(skdev), skerr->key, skerr->code, skerr->qual, + skerr->fruc); + + VPRINTK(skdev, "stat: t=%02x stat=%02x k=%02x c=%02x q=%02x " + "fruc=%02x\n", skerr->type, cmp_status, skerr->key, + skerr->code, skerr->qual, skerr->fruc); + + /* Does the info match an entry in the good category? */ + n = sizeof(skd_chkstat_table) / sizeof(skd_chkstat_table[0]); + for (i = 0; i < n; i++) { + struct sns_info *sns = &skd_chkstat_table[i]; + + if (sns->mask & 0x10) + if (skerr->type != sns->type) + continue; + + if (sns->mask & 0x08) + if (cmp_status != sns->stat) + continue; + + if (sns->mask & 0x04) + if (skerr->key != sns->key) + continue; + + if (sns->mask & 0x02) + if (skerr->code != sns->asc) + continue; + + if (sns->mask & 0x01) + if (skerr->qual != sns->ascq) + continue; + + if (sns->action == SKD_CHECK_STATUS_REPORT_SMART_ALERT) { + pr_err("(%s): SMART Alert: sense key/asc/ascq " + "%02x/%02x/%02x\n", + skd_name(skdev), skerr->key, + skerr->code, skerr->qual); + } + return sns->action; + } + + /* No other match, so nonzero status means error, + * zero status means good + */ + if (cmp_status) { + DPRINTK(skdev, "status check: error\n"); + return SKD_CHECK_STATUS_REPORT_ERROR; + } + + DPRINTK(skdev, "status check good default\n"); + return SKD_CHECK_STATUS_REPORT_GOOD; +} + +static void skd_resolve_req_exception(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + u8 cmp_status = skreq->completion.status; + + switch (skd_check_status(skdev, cmp_status, &skreq->err_info)) { + case SKD_CHECK_STATUS_REPORT_GOOD: + case SKD_CHECK_STATUS_REPORT_SMART_ALERT: + skd_end_request(skdev, skreq, 0); + break; + + case SKD_CHECK_STATUS_BUSY_IMMINENT: + skd_log_skreq(skdev, skreq, "retry(busy)"); + skd_requeue_request(skdev, skreq); + pr_info("(%s) drive BUSY imminent\n", skd_name(skdev)); + skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT; + skdev->timer_countdown = SKD_TIMER_MINUTES(20); + skd_quiesce_dev(skdev); + break; + + case SKD_CHECK_STATUS_REQUEUE_REQUEST: + if (!skd_bio) { + if ((unsigned long) ++skreq->req->special < + SKD_MAX_RETRIES) { + skd_log_skreq(skdev, skreq, "retry"); + skd_requeue_request(skdev, skreq); + break; + } + } + /* fall through to report error */ + + case SKD_CHECK_STATUS_REPORT_ERROR: + default: + skd_end_request(skdev, skreq, -EIO); + break; + } +} + +static void skd_requeue_request(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + if (!skd_bio) { + blk_requeue_request(skdev->queue, skreq->req); + } else { + bio_list_add_head(&skdev->bio_queue, skreq->bio); + skreq->bio = NULL; + } +} + + + +/* assume spinlock is already held */ +static void skd_release_skreq(struct skd_device *skdev, + struct skd_request_context *skreq) +{ + u32 msg_slot; + struct skd_fitmsg_context *skmsg; + + u32 timo_slot; + + /* + * Reclaim the FIT msg buffer if this is + * the first of the requests it carried to + * be completed. The FIT msg buffer used to + * send this request cannot be reused until + * we are sure the s1120 card has copied + * it to its memory. The FIT msg might have + * contained several requests. As soon as + * any of them are completed we know that + * the entire FIT msg was transferred. + * Only the first completed request will + * match the FIT msg buffer id. The FIT + * msg buffer id is immediately updated. + * When subsequent requests complete the FIT + * msg buffer id won't match, so we know + * quite cheaply that it is already done. + */ + msg_slot = skreq->fitmsg_id & SKD_ID_SLOT_MASK; + SKD_ASSERT(msg_slot < skdev->num_fitmsg_context); + + skmsg = &skdev->skmsg_table[msg_slot]; + if (skmsg->id == skreq->fitmsg_id) { + SKD_ASSERT(skmsg->state == SKD_MSG_STATE_BUSY); + SKD_ASSERT(skmsg->outstanding > 0); + skmsg->outstanding--; + if (skmsg->outstanding == 0) { + skmsg->state = SKD_MSG_STATE_IDLE; + skmsg->id += SKD_ID_INCR; + skmsg->next = skdev->skmsg_free_list; + skdev->skmsg_free_list = skmsg; + } + } + + /* + * Decrease the number of active requests. + * Also decrements the count in the timeout slot. + */ + SKD_ASSERT(skdev->in_flight > 0); + skdev->in_flight -= 1; + + timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; + SKD_ASSERT(skdev->timeout_slot[timo_slot] > 0); + skdev->timeout_slot[timo_slot] -= 1; + + /* + * Reset backpointer + */ + if (likely(!skd_bio)) + skreq->req = NULL; + else + skreq->bio = NULL; + + + /* + * Reclaim the skd_request_context + */ + skreq->state = SKD_REQ_STATE_IDLE; + skreq->id += SKD_ID_INCR; + skreq->next = skdev->skreq_free_list; + skdev->skreq_free_list = skreq; +} + +#define DRIVER_INQ_EVPD_PAGE_CODE 0xDA + +static void skd_do_inq_page_00(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 *skcomp, + volatile struct fit_comp_error_info *skerr, + uint8_t *cdb, uint8_t *buf) +{ + uint16_t insert_pt, max_bytes, drive_pages, drive_bytes, new_size; + + /* Caller requested "supported pages". The driver needs to insert + * its page. + */ + VPRINTK(skdev, "skd_do_driver_inquiry: modify supported pages.\n"); + + /* If the device rejected the request because the CDB was + * improperly formed, then just leave. + */ + if (skcomp->status == SAM_STAT_CHECK_CONDITION && + skerr->key == ILLEGAL_REQUEST && skerr->code == 0x24) + return; + + /* Get the amount of space the caller allocated */ + max_bytes = (cdb[3] << 8) | cdb[4]; + + /* Get the number of pages actually returned by the device */ + drive_pages = (buf[2] << 8) | buf[3]; + drive_bytes = drive_pages + 4; + new_size = drive_pages + 1; + + /* Supported pages must be in numerical order, so find where + * the driver page needs to be inserted into the list of + * pages returned by the device. + */ + for (insert_pt = 4; insert_pt < drive_bytes; insert_pt++) { + if (buf[insert_pt] == DRIVER_INQ_EVPD_PAGE_CODE) + return; /* Device using this page code. abort */ + else if (buf[insert_pt] > DRIVER_INQ_EVPD_PAGE_CODE) + break; + } + + if (insert_pt < max_bytes) { + uint16_t u; + + /* Shift everything up one byte to make room. */ + for (u = new_size + 3; u > insert_pt; u--) + buf[u] = buf[u - 1]; + buf[insert_pt] = DRIVER_INQ_EVPD_PAGE_CODE; + + /* SCSI byte order increment of num_returned_bytes by 1 */ + skcomp->num_returned_bytes = + be32_to_cpu(skcomp->num_returned_bytes) + 1; + skcomp->num_returned_bytes = + be32_to_cpu(skcomp->num_returned_bytes); + } + + /* update page length field to reflect the driver's page too */ + buf[2] = (uint8_t)((new_size >> 8) & 0xFF); + buf[3] = (uint8_t)((new_size >> 0) & 0xFF); +} + +static void skd_get_link_info(struct pci_dev *pdev, u8 *speed, u8 *width) +{ + int pcie_reg; + u16 pci_bus_speed; + u8 pci_lanes; + + pcie_reg = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (pcie_reg) { + u16 linksta; + pci_read_config_word(pdev, pcie_reg + PCI_EXP_LNKSTA, &linksta); + + pci_bus_speed = linksta & 0xF; + pci_lanes = (linksta & 0x3F0) >> 4; + } else { + *speed = STEC_LINK_UNKNOWN; + *width = 0xFF; + return; + } + + switch (pci_bus_speed) { + case 1: + *speed = STEC_LINK_2_5GTS; + break; + case 2: + *speed = STEC_LINK_5GTS; + break; + case 3: + *speed = STEC_LINK_8GTS; + break; + default: + *speed = STEC_LINK_UNKNOWN; + break; + } + + if (pci_lanes <= 0x20) + *width = pci_lanes; + else + *width = 0xFF; +} + +static void skd_do_inq_page_da(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 *skcomp, + volatile struct fit_comp_error_info *skerr, + uint8_t *cdb, uint8_t *buf) +{ + unsigned max_bytes; + struct driver_inquiry_data inq; + u16 val; + + VPRINTK(skdev, "skd_do_driver_inquiry: return driver page\n"); + + memset(&inq, 0, sizeof(inq)); + + inq.page_code = DRIVER_INQ_EVPD_PAGE_CODE; + + if (skdev->pdev && skdev->pdev->bus) { + skd_get_link_info(skdev->pdev, + &inq.pcie_link_speed, &inq.pcie_link_lanes); + inq.pcie_bus_number = cpu_to_be16(skdev->pdev->bus->number); + inq.pcie_device_number = PCI_SLOT(skdev->pdev->devfn); + inq.pcie_function_number = PCI_FUNC(skdev->pdev->devfn); + + pci_read_config_word(skdev->pdev, PCI_VENDOR_ID, &val); + inq.pcie_vendor_id = cpu_to_be16(val); + + pci_read_config_word(skdev->pdev, PCI_DEVICE_ID, &val); + inq.pcie_device_id = cpu_to_be16(val); + + pci_read_config_word(skdev->pdev, PCI_SUBSYSTEM_VENDOR_ID, + &val); + inq.pcie_subsystem_vendor_id = cpu_to_be16(val); + + pci_read_config_word(skdev->pdev, PCI_SUBSYSTEM_ID, &val); + inq.pcie_subsystem_device_id = cpu_to_be16(val); + } else { + inq.pcie_bus_number = 0xFFFF; + inq.pcie_device_number = 0xFF; + inq.pcie_function_number = 0xFF; + inq.pcie_link_speed = 0xFF; + inq.pcie_link_lanes = 0xFF; + inq.pcie_vendor_id = 0xFFFF; + inq.pcie_device_id = 0xFFFF; + inq.pcie_subsystem_vendor_id = 0xFFFF; + inq.pcie_subsystem_device_id = 0xFFFF; + } + + /* Driver version, fixed lenth, padded with spaces on the right */ + inq.driver_version_length = sizeof(inq.driver_version); + memset(&inq.driver_version, ' ', sizeof(inq.driver_version)); + memcpy(inq.driver_version, DRV_VER_COMPL, + min(sizeof(inq.driver_version), strlen(DRV_VER_COMPL))); + + inq.page_length = cpu_to_be16((sizeof(inq) - 4)); + + /* Clear the error set by the device */ + skcomp->status = SAM_STAT_GOOD; + memset((void *)skerr, 0, sizeof(*skerr)); + + /* copy response into output buffer */ + max_bytes = (cdb[3] << 8) | cdb[4]; + memcpy(buf, &inq, min_t(unsigned, max_bytes, sizeof(inq))); + + skcomp->num_returned_bytes = + be32_to_cpu(min_t(uint16_t, max_bytes, sizeof(inq))); +} + +static void skd_do_driver_inq(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 *skcomp, + volatile struct fit_comp_error_info *skerr, + uint8_t *cdb, uint8_t *buf) +{ + if (!buf) + return; + else if (cdb[0] != INQUIRY) + return; /* Not an INQUIRY */ + else if ((cdb[1] & 1) == 0) + return; /* EVPD not set */ + else if (cdb[2] == 0) + /* Need to add driver's page to supported pages list */ + skd_do_inq_page_00(skdev, skcomp, skerr, cdb, buf); + else if (cdb[2] == DRIVER_INQ_EVPD_PAGE_CODE) + /* Caller requested driver's page */ + skd_do_inq_page_da(skdev, skcomp, skerr, cdb, buf); +} + +static unsigned char *skd_sg_1st_page_ptr(struct scatterlist *sg) +{ + if (!sg) + return NULL; + if (!sg_page(sg)) + return NULL; + return sg_virt(sg); +} + +static void skd_process_scsi_inq(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 + *skcomp, + volatile struct fit_comp_error_info *skerr, + struct skd_special_context *skspcl) +{ + uint8_t *buf; + struct fit_msg_hdr *fmh = (struct fit_msg_hdr *)skspcl->msg_buf; + struct skd_scsi_request *scsi_req = (struct skd_scsi_request *)&fmh[1]; + + dma_sync_sg_for_cpu(skdev->class_dev, skspcl->req.sg, skspcl->req.n_sg, + skspcl->req.sg_data_dir); + buf = skd_sg_1st_page_ptr(skspcl->req.sg); + + if (buf) + skd_do_driver_inq(skdev, skcomp, skerr, scsi_req->cdb, buf); +} + + +static int skd_isr_completion_posted(struct skd_device *skdev, + int limit, int *enqueued) +{ + volatile struct fit_completion_entry_v1 *skcmp = NULL; + volatile struct fit_comp_error_info *skerr; + u16 req_id; + u32 req_slot; + struct skd_request_context *skreq; + u16 cmp_cntxt = 0; + u8 cmp_status = 0; + u8 cmp_cycle = 0; + u32 cmp_bytes = 0; + int rc = 0; + int processed = 0; + int ret; + + + for (;; ) { + SKD_ASSERT(skdev->skcomp_ix < SKD_N_COMPLETION_ENTRY); + + skcmp = &skdev->skcomp_table[skdev->skcomp_ix]; + cmp_cycle = skcmp->cycle; + cmp_cntxt = skcmp->tag; + cmp_status = skcmp->status; + cmp_bytes = be32_to_cpu(skcmp->num_returned_bytes); + + skerr = &skdev->skerr_table[skdev->skcomp_ix]; + + VPRINTK(skdev, + "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d " + "busy=%d rbytes=0x%x proto=%d\n", skdev->skcomp_cycle, + skdev->skcomp_ix, cmp_cycle, cmp_cntxt, cmp_status, + skdev->in_flight, cmp_bytes, skdev->proto_ver); + + if (cmp_cycle != skdev->skcomp_cycle) { + VPRINTK(skdev, "end of completions\n"); + break; + } + /* + * Update the completion queue head index and possibly + * the completion cycle count. 8-bit wrap-around. + */ + skdev->skcomp_ix++; + if (skdev->skcomp_ix >= SKD_N_COMPLETION_ENTRY) { + skdev->skcomp_ix = 0; + skdev->skcomp_cycle++; + } + + /* + * The command context is a unique 32-bit ID. The low order + * bits help locate the request. The request is usually a + * r/w request (see skd_start() above) or a special request. + */ + req_id = cmp_cntxt; + req_slot = req_id & SKD_ID_SLOT_AND_TABLE_MASK; + + /* Is this other than a r/w request? */ + if (req_slot >= skdev->num_req_context) { + /* + * This is not a completion for a r/w request. + */ + skd_complete_other(skdev, skcmp, skerr); + continue; + } + + skreq = &skdev->skreq_table[req_slot]; + + /* + * Make sure the request ID for the slot matches. + */ + if (skreq->id != req_id) { + DPRINTK(skdev, "mismatch comp_id=0x%x req_id=0x%x\n", + req_id, skreq->id); + { + u16 new_id = cmp_cntxt; + pr_err("(%s): Completion mismatch " + "comp_id=0x%04x skreq=0x%04x new=0x%04x\n", + skd_name(skdev), req_id, + skreq->id, new_id); + + continue; + } + } + + SKD_ASSERT(skreq->state == SKD_REQ_STATE_BUSY); + + if (skreq->state == SKD_REQ_STATE_ABORTED) { + DPRINTK(skdev, "reclaim req %p id=%04x\n", + skreq, skreq->id); + /* a previously timed out command can + * now be cleaned up */ + skd_release_skreq(skdev, skreq); + continue; + } + + skreq->completion = *skcmp; + if (unlikely(cmp_status == SAM_STAT_CHECK_CONDITION)) { + skreq->err_info = *skerr; + skd_log_check_status(skdev, cmp_status, skerr->key, + skerr->code, skerr->qual, + skerr->fruc); + } + /* Release DMA resources for the request. */ + if (skreq->n_sg > 0) + skd_postop_sg_list(skdev, skreq); + + if (((!skd_bio) && !skreq->req) || + ((skd_bio) && !skreq->bio)) { + DPRINTK(skdev, "NULL backptr skdreq %p, " + "req=0x%x req_id=0x%x\n", + skreq, skreq->id, req_id); + } else { + /* + * Capture the outcome and post it back to the + * native request. + */ + if (likely(cmp_status == SAM_STAT_GOOD)) { + if (unlikely(skreq->flush_cmd)) { + if (skd_bio) { + /* if empty size bio, we are all done */ + if (bio_sectors(skreq->bio) == 0) { + skd_end_request(skdev, skreq, 0); + } else { + ret = skd_flush_cmd_enqueue(skdev, (void *)skreq->bio); + if (ret != 0) { + pr_err("Failed to enqueue flush bio with Data. Err=%d.\n", ret); + skd_end_request(skdev, skreq, ret); + } else { + ((*enqueued)++); + } + } + } else { + skd_end_request(skdev, skreq, 0); + } + } else { + skd_end_request(skdev, skreq, 0); + } + } else { + skd_resolve_req_exception(skdev, skreq); + } + } + + /* + * Release the skreq, its FIT msg (if one), timeout slot, + * and queue depth. + */ + skd_release_skreq(skdev, skreq); + + /* skd_isr_comp_limit equal zero means no limit */ + if (limit) { + if (++processed >= limit) { + rc = 1; + break; + } + } + } + + if ((skdev->state == SKD_DRVR_STATE_PAUSING) + && (skdev->in_flight) == 0) { + skdev->state = SKD_DRVR_STATE_PAUSED; + wake_up_interruptible(&skdev->waitq); + } + + return rc; +} + +static void skd_complete_other(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 *skcomp, + volatile struct fit_comp_error_info *skerr) +{ + u32 req_id = 0; + u32 req_table; + u32 req_slot; + struct skd_special_context *skspcl; + + req_id = skcomp->tag; + req_table = req_id & SKD_ID_TABLE_MASK; + req_slot = req_id & SKD_ID_SLOT_MASK; + + DPRINTK(skdev, "table=0x%x id=0x%x slot=%d\n", req_table, req_id, + req_slot); + + /* + * Based on the request id, determine how to dispatch this completion. + * This swich/case is finding the good cases and forwarding the + * completion entry. Errors are reported below the switch. + */ + switch (req_table) { + case SKD_ID_RW_REQUEST: + /* + * The caller, skd_completion_posted_isr() above, + * handles r/w requests. The only way we get here + * is if the req_slot is out of bounds. + */ + break; + + case SKD_ID_SPECIAL_REQUEST: + /* + * Make sure the req_slot is in bounds and that the id + * matches. + */ + if (req_slot < skdev->n_special) { + skspcl = &skdev->skspcl_table[req_slot]; + if (skspcl->req.id == req_id && + skspcl->req.state == SKD_REQ_STATE_BUSY) { + skd_complete_special(skdev, + skcomp, skerr, skspcl); + return; + } + } + break; + + case SKD_ID_INTERNAL: + if (req_slot == 0) { + skspcl = &skdev->internal_skspcl; + if (skspcl->req.id == req_id && + skspcl->req.state == SKD_REQ_STATE_BUSY) { + skd_complete_internal(skdev, + skcomp, skerr, skspcl); + return; + } + } + break; + + case SKD_ID_FIT_MSG: + /* + * These id's should never appear in a completion record. + */ + break; + + default: + /* + * These id's should never appear anywhere; + */ + break; + } + + /* + * If we get here it is a bad or stale id. + */ +} + +static void skd_complete_special(struct skd_device *skdev, + volatile struct fit_completion_entry_v1 + *skcomp, + volatile struct fit_comp_error_info *skerr, + struct skd_special_context *skspcl) +{ + DPRINTK(skdev, " completing special request %p\n", skspcl); + if (skspcl->orphaned) { + /* Discard orphaned request */ + /* ?: Can this release directly or does it need + * to use a worker? */ + DPRINTK(skdev, "release orphaned %p\n", skspcl); + skd_release_special(skdev, skspcl); + return; + } + + skd_process_scsi_inq(skdev, skcomp, skerr, skspcl); + + skspcl->req.state = SKD_REQ_STATE_COMPLETED; + skspcl->req.completion = *skcomp; + skspcl->req.err_info = *skerr; + + skd_log_check_status(skdev, skspcl->req.completion.status, skerr->key, + skerr->code, skerr->qual, skerr->fruc); + + wake_up_interruptible(&skdev->waitq); +} + +/* assume spinlock is already held */ +static void skd_release_special(struct skd_device *skdev, + struct skd_special_context *skspcl) +{ + int i, was_depleted; + + for (i = 0; i < skspcl->req.n_sg; i++) { + + struct page *page = sg_page(&skspcl->req.sg[i]); + __free_page(page); + } + + was_depleted = (skdev->skspcl_free_list == NULL); + + skspcl->req.state = SKD_REQ_STATE_IDLE; + skspcl->req.id += SKD_ID_INCR; + skspcl->req.next = + (struct skd_request_context *)skdev->skspcl_free_list; + skdev->skspcl_free_list = (struct skd_special_context *)skspcl; + + if (was_depleted) { + DPRINTK(skdev, "skspcl was depleted\n"); + /* Free list was depleted. Their might be waiters. */ + wake_up_interruptible(&skdev->waitq); + } +} + +static void skd_reset_skcomp(struct skd_device *skdev) +{ + u32 nbytes; + struct fit_completion_entry_v1 *skcomp; + + nbytes = sizeof(*skcomp) * SKD_N_COMPLETION_ENTRY; + nbytes += sizeof(struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY; + + memset(skdev->skcomp_table, 0, nbytes); + + skdev->skcomp_ix = 0; + skdev->skcomp_cycle = 1; +} + +/* + ***************************************************************************** + * INTERRUPTS + ***************************************************************************** + */ +static void skd_completion_worker(struct work_struct *work) +{ + struct skd_device *skdev = + container_of(work, struct skd_device, completion_worker); + unsigned long flags; + int flush_enqueued = 0; + + spin_lock_irqsave(&skdev->lock, flags); + + /* + * pass in limit=0, which means no limit.. + * process everything in compq + */ + skd_isr_completion_posted(skdev, 0, &flush_enqueued); + skd_request_fn(skdev->queue); + + spin_unlock_irqrestore(&skdev->lock, flags); +} + +static void skd_isr_msg_from_dev(struct skd_device *skdev); + +irqreturn_t +static skd_isr(int irq, void *ptr) +{ + struct skd_device *skdev; + u32 intstat; + u32 ack; + int rc = 0; + int deferred = 0; + int flush_enqueued = 0; + + skdev = (struct skd_device *)ptr; + spin_lock(&skdev->lock); + + for (;; ) { + intstat = SKD_READL(skdev, FIT_INT_STATUS_HOST); + + ack = FIT_INT_DEF_MASK; + ack &= intstat; + + VPRINTK(skdev, "intstat=0x%x ack=0x%x\n", intstat, ack); + + /* As long as there is an int pending on device, keep + * running loop. When none, get out, but if we've never + * done any processing, call completion handler? + */ + if (ack == 0) { + /* No interrupts on device, but run the completion + * processor anyway? + */ + if (rc == 0) + if (likely (skdev->state + == SKD_DRVR_STATE_ONLINE)) + deferred = 1; + break; + } + + rc = IRQ_HANDLED; + + SKD_WRITEL(skdev, ack, FIT_INT_STATUS_HOST); + + if (likely((skdev->state != SKD_DRVR_STATE_LOAD) && + (skdev->state != SKD_DRVR_STATE_STOPPING))) { + if (intstat & FIT_ISH_COMPLETION_POSTED) { + /* + * If we have already deferred completion + * processing, don't bother running it again + */ + if (deferred == 0) + deferred = + skd_isr_completion_posted(skdev, + skd_isr_comp_limit, &flush_enqueued); + } + + if (intstat & FIT_ISH_FW_STATE_CHANGE) { + skd_isr_fwstate(skdev); + if (skdev->state == SKD_DRVR_STATE_FAULT || + skdev->state == + SKD_DRVR_STATE_DISAPPEARED) { + spin_unlock(&skdev->lock); + return rc; + } + } + + if (intstat & FIT_ISH_MSG_FROM_DEV) + skd_isr_msg_from_dev(skdev); + } + } + + if (unlikely(flush_enqueued)) + skd_request_fn(skdev->queue); + + if (deferred) + schedule_work(&skdev->completion_worker); + else if (!flush_enqueued) + skd_request_fn(skdev->queue); + + spin_unlock(&skdev->lock); + + return rc; +} + + +static void skd_drive_fault(struct skd_device *skdev) +{ + skdev->state = SKD_DRVR_STATE_FAULT; + pr_err("(%s): Drive FAULT\n", skd_name(skdev)); +} + +static void skd_drive_disappeared(struct skd_device *skdev) +{ + skdev->state = SKD_DRVR_STATE_DISAPPEARED; + pr_err("(%s): Drive DISAPPEARED\n", skd_name(skdev)); +} + +static void skd_isr_fwstate(struct skd_device *skdev) +{ + u32 sense; + u32 state; + u32 mtd; + int prev_driver_state = skdev->state; + + sense = SKD_READL(skdev, FIT_STATUS); + state = sense & FIT_SR_DRIVE_STATE_MASK; + + pr_err("(%s): s1120 state %s(%d)=>%s(%d)\n", + skd_name(skdev), + skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, + skd_drive_state_to_str(state), state); + + skdev->drive_state = state; + + switch (skdev->drive_state) { + case FIT_SR_DRIVE_INIT: + if (skdev->state == SKD_DRVR_STATE_PROTOCOL_MISMATCH) { + skd_disable_interrupts(skdev); + break; + } + if (skdev->state == SKD_DRVR_STATE_RESTARTING) + skd_recover_requests(skdev, 0); + if (skdev->state == SKD_DRVR_STATE_WAIT_BOOT) { + skdev->timer_countdown = SKD_STARTING_TIMO; + skdev->state = SKD_DRVR_STATE_STARTING; + skd_soft_reset(skdev); + break; + } + mtd = FIT_MXD_CONS(FIT_MTD_FITFW_INIT, 0, 0); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_SR_DRIVE_ONLINE: + skdev->cur_max_queue_depth = skd_max_queue_depth; + if (skdev->cur_max_queue_depth > skdev->dev_max_queue_depth) + skdev->cur_max_queue_depth = skdev->dev_max_queue_depth; + + skdev->queue_low_water_mark = + skdev->cur_max_queue_depth * 2 / 3 + 1; + if (skdev->queue_low_water_mark < 1) + skdev->queue_low_water_mark = 1; + pr_info( + "(%s): Queue depth limit=%d dev=%d lowat=%d\n", + skd_name(skdev), + skdev->cur_max_queue_depth, + skdev->dev_max_queue_depth, skdev->queue_low_water_mark); + + skd_refresh_device_data(skdev); + break; + + case FIT_SR_DRIVE_BUSY: + skdev->state = SKD_DRVR_STATE_BUSY; + skdev->timer_countdown = SKD_BUSY_TIMO; + skd_quiesce_dev(skdev); + break; + case FIT_SR_DRIVE_BUSY_SANITIZE: + /* set timer for 3 seconds, we'll abort any unfinished + * commands after that expires + */ + skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; + skdev->timer_countdown = SKD_TIMER_SECONDS(3); + skd_start_queue(skdev); + break; + case FIT_SR_DRIVE_BUSY_ERASE: + skdev->state = SKD_DRVR_STATE_BUSY_ERASE; + skdev->timer_countdown = SKD_BUSY_TIMO; + break; + case FIT_SR_DRIVE_OFFLINE: + skdev->state = SKD_DRVR_STATE_IDLE; + break; + case FIT_SR_DRIVE_SOFT_RESET: + switch (skdev->state) { + case SKD_DRVR_STATE_STARTING: + case SKD_DRVR_STATE_RESTARTING: + /* Expected by a caller of skd_soft_reset() */ + break; + default: + skdev->state = SKD_DRVR_STATE_RESTARTING; + break; + } + break; + case FIT_SR_DRIVE_FW_BOOTING: + VPRINTK(skdev, "ISR FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name); + skdev->state = SKD_DRVR_STATE_WAIT_BOOT; + skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; + break; + + case FIT_SR_DRIVE_DEGRADED: + case FIT_SR_PCIE_LINK_DOWN: + case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: + break; + + case FIT_SR_DRIVE_FAULT: + skd_drive_fault(skdev); + skd_recover_requests(skdev, 0); + skd_start_queue(skdev); + break; + + /* PCIe bus returned all Fs? */ + case 0xFF: + pr_info("(%s): state=0x%x sense=0x%x\n", + skd_name(skdev), state, sense); + skd_drive_disappeared(skdev); + skd_recover_requests(skdev, 0); + skd_start_queue(skdev); + break; + default: + /* + * Uknown FW State. Wait for a state we recognize. + */ + break; + } + pr_err("(%s): Driver state %s(%d)=>%s(%d)\n", + skd_name(skdev), + skd_skdev_state_to_str(prev_driver_state), prev_driver_state, + skd_skdev_state_to_str(skdev->state), skdev->state); +} + +static void skd_recover_requests(struct skd_device *skdev, int requeue) +{ + int i; + + for (i = 0; i < skdev->num_req_context; i++) { + struct skd_request_context *skreq = &skdev->skreq_table[i]; + + if (skreq->state == SKD_REQ_STATE_BUSY) { + skd_log_skreq(skdev, skreq, "recover"); + + SKD_ASSERT((skreq->id & SKD_ID_INCR) != 0); + if (!skd_bio) + SKD_ASSERT(skreq->req != NULL); + else + SKD_ASSERT(skreq->bio != NULL); + + /* Release DMA resources for the request. */ + if (skreq->n_sg > 0) + skd_postop_sg_list(skdev, skreq); + + if (!skd_bio) { + if (requeue && + (unsigned long) ++skreq->req->special < + SKD_MAX_RETRIES) + skd_requeue_request(skdev, skreq); + else + skd_end_request(skdev, skreq, -EIO); + } else + skd_end_request(skdev, skreq, -EIO); + + if (!skd_bio) + skreq->req = NULL; + else + skreq->bio = NULL; + + skreq->state = SKD_REQ_STATE_IDLE; + skreq->id += SKD_ID_INCR; + + + } + if (i > 0) + skreq[-1].next = skreq; + skreq->next = NULL; + } + skdev->skreq_free_list = skdev->skreq_table; + + for (i = 0; i < skdev->num_fitmsg_context; i++) { + struct skd_fitmsg_context *skmsg = &skdev->skmsg_table[i]; + + if (skmsg->state == SKD_MSG_STATE_BUSY) { + skd_log_skmsg(skdev, skmsg, "salvaged"); + SKD_ASSERT((skmsg->id & SKD_ID_INCR) != 0); + skmsg->state = SKD_MSG_STATE_IDLE; + skmsg->id += SKD_ID_INCR; + } + if (i > 0) + skmsg[-1].next = skmsg; + skmsg->next = NULL; + } + skdev->skmsg_free_list = skdev->skmsg_table; + + for (i = 0; i < skdev->n_special; i++) { + struct skd_special_context *skspcl = &skdev->skspcl_table[i]; + + /* If orphaned, reclaim it because it has already been reported + * to the process as an error (it was just waiting for + * a completion that didn't come, and now it will never come) + * If busy, change to a state that will cause it to error + * out in the wait routine and let it do the normal + * reporting and reclaiming + */ + if (skspcl->req.state == SKD_REQ_STATE_BUSY) { + if (skspcl->orphaned) { + DPRINTK(skdev, "orphaned %p\n", skspcl); + skd_release_special(skdev, skspcl); + } else { + DPRINTK(skdev, "not orphaned %p\n", skspcl); + skspcl->req.state = SKD_REQ_STATE_ABORTED; + } + } + } + skdev->skspcl_free_list = skdev->skspcl_table; + + for (i = 0; i < SKD_N_TIMEOUT_SLOT; i++) + skdev->timeout_slot[i] = 0; + + skdev->in_flight = 0; +} + +static void skd_isr_msg_from_dev(struct skd_device *skdev) +{ + u32 mfd; + u32 mtd; + u32 data; + + mfd = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); + + DPRINTK(skdev, "mfd=0x%x last_mtd=0x%x\n", mfd, skdev->last_mtd); + + /* ignore any mtd that is an ack for something we didn't send */ + if (FIT_MXD_TYPE(mfd) != FIT_MXD_TYPE(skdev->last_mtd)) + return; + + switch (FIT_MXD_TYPE(mfd)) { + case FIT_MTD_FITFW_INIT: + skdev->proto_ver = FIT_PROTOCOL_MAJOR_VER(mfd); + + if (skdev->proto_ver != FIT_PROTOCOL_VERSION_1) { + pr_err("(%s): protocol mismatch\n", + skdev->name); + pr_err("(%s): got=%d support=%d\n", + skdev->name, skdev->proto_ver, + FIT_PROTOCOL_VERSION_1); + pr_err("(%s): please upgrade driver\n", + skdev->name); + skdev->state = SKD_DRVR_STATE_PROTOCOL_MISMATCH; + skd_soft_reset(skdev); + break; + } + mtd = FIT_MXD_CONS(FIT_MTD_GET_CMDQ_DEPTH, 0, 0); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_GET_CMDQ_DEPTH: + skdev->dev_max_queue_depth = FIT_MXD_DATA(mfd); + mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_DEPTH, 0, + SKD_N_COMPLETION_ENTRY); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_SET_COMPQ_DEPTH: + SKD_WRITEQ(skdev, skdev->cq_dma_address, FIT_MSG_TO_DEVICE_ARG); + mtd = FIT_MXD_CONS(FIT_MTD_SET_COMPQ_ADDR, 0, 0); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_SET_COMPQ_ADDR: + skd_reset_skcomp(skdev); + mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_HOST_ID, 0, skdev->devno); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_CMD_LOG_HOST_ID: + skdev->connect_time_stamp = get_seconds(); + data = skdev->connect_time_stamp & 0xFFFF; + mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_TIME_STAMP_LO, 0, data); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_CMD_LOG_TIME_STAMP_LO: + skdev->drive_jiffies = FIT_MXD_DATA(mfd); + data = (skdev->connect_time_stamp >> 16) & 0xFFFF; + mtd = FIT_MXD_CONS(FIT_MTD_CMD_LOG_TIME_STAMP_HI, 0, data); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + break; + + case FIT_MTD_CMD_LOG_TIME_STAMP_HI: + skdev->drive_jiffies |= (FIT_MXD_DATA(mfd) << 16); + mtd = FIT_MXD_CONS(FIT_MTD_ARM_QUEUE, 0, 0); + SKD_WRITEL(skdev, mtd, FIT_MSG_TO_DEVICE); + skdev->last_mtd = mtd; + + pr_err("(%s): Time sync driver=0x%x device=0x%x\n", + skd_name(skdev), + skdev->connect_time_stamp, skdev->drive_jiffies); + break; + + case FIT_MTD_ARM_QUEUE: + skdev->last_mtd = 0; + /* + * State should be, or soon will be, FIT_SR_DRIVE_ONLINE. + */ + break; + + default: + break; + } +} + +static void skd_disable_interrupts(struct skd_device *skdev) +{ + u32 sense; + + sense = SKD_READL(skdev, FIT_CONTROL); + sense &= ~FIT_CR_ENABLE_INTERRUPTS; + SKD_WRITEL(skdev, sense, FIT_CONTROL); + DPRINTK(skdev, "sense 0x%x\n", sense); + + /* Note that the 1s is written. A 1-bit means + * disable, a 0 means enable. + */ + SKD_WRITEL(skdev, ~0, FIT_INT_MASK_HOST); +} + +static void skd_enable_interrupts(struct skd_device *skdev) +{ + u32 val; + + /* unmask interrupts first */ + val = FIT_ISH_FW_STATE_CHANGE + + FIT_ISH_COMPLETION_POSTED + FIT_ISH_MSG_FROM_DEV; + + /* Note that the compliment of mask is written. A 1-bit means + * disable, a 0 means enable. */ + SKD_WRITEL(skdev, ~val, FIT_INT_MASK_HOST); + DPRINTK(skdev, "interrupt mask=0x%x\n", ~val); + + val = SKD_READL(skdev, FIT_CONTROL); + val |= FIT_CR_ENABLE_INTERRUPTS; + DPRINTK(skdev, "control=0x%x\n", val); + SKD_WRITEL(skdev, val, FIT_CONTROL); +} + +/* + ***************************************************************************** + * START, STOP, RESTART, QUIESCE, UNQUIESCE + ***************************************************************************** + */ + +static void skd_soft_reset(struct skd_device *skdev) +{ + u32 val; + + val = SKD_READL(skdev, FIT_CONTROL); + val |= (FIT_CR_SOFT_RESET); + DPRINTK(skdev, "control=0x%x\n", val); + SKD_WRITEL(skdev, val, FIT_CONTROL); +} + +static void skd_start_device(struct skd_device *skdev) +{ + unsigned long flags; + u32 sense; + u32 state; + + spin_lock_irqsave(&skdev->lock, flags); + + /* ack all ghost interrupts */ + SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); + + sense = SKD_READL(skdev, FIT_STATUS); + + DPRINTK(skdev, "initial status=0x%x\n", sense); + + state = sense & FIT_SR_DRIVE_STATE_MASK; + skdev->drive_state = state; + skdev->last_mtd = 0; + + skdev->state = SKD_DRVR_STATE_STARTING; + skdev->timer_countdown = SKD_STARTING_TIMO; + + skd_enable_interrupts(skdev); + + switch (skdev->drive_state) { + case FIT_SR_DRIVE_OFFLINE: + pr_err("(%s): Drive offline...\n", skd_name(skdev)); + break; + + case FIT_SR_DRIVE_FW_BOOTING: + VPRINTK(skdev, "FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name); + skdev->state = SKD_DRVR_STATE_WAIT_BOOT; + skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; + break; + + case FIT_SR_DRIVE_BUSY_SANITIZE: + pr_info("(%s): Start: BUSY_SANITIZE\n", + skd_name(skdev)); + skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; + skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; + break; + + case FIT_SR_DRIVE_BUSY_ERASE: + pr_info("(%s): Start: BUSY_ERASE\n", skd_name(skdev)); + skdev->state = SKD_DRVR_STATE_BUSY_ERASE; + skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; + break; + + case FIT_SR_DRIVE_INIT: + case FIT_SR_DRIVE_ONLINE: + skd_soft_reset(skdev); + break; + + case FIT_SR_DRIVE_BUSY: + pr_err("(%s): Drive Busy...\n", skd_name(skdev)); + skdev->state = SKD_DRVR_STATE_BUSY; + skdev->timer_countdown = SKD_STARTED_BUSY_TIMO; + break; + + case FIT_SR_DRIVE_SOFT_RESET: + pr_err("(%s) drive soft reset in prog\n", + skd_name(skdev)); + break; + + case FIT_SR_DRIVE_FAULT: + /* Fault state is bad...soft reset won't do it... + * Hard reset, maybe, but does it work on device? + * For now, just fault so the system doesn't hang. + */ + skd_drive_fault(skdev); + /*start the queue so we can respond with error to requests */ + VPRINTK(skdev, "starting %s queue\n", skdev->name); + skd_start_queue(skdev); + skdev->gendisk_on = -1; + wake_up_interruptible(&skdev->waitq); + break; + + case 0xFF: + /* Most likely the device isn't there or isn't responding + * to the BAR1 addresses. */ + skd_drive_disappeared(skdev); + /*start the queue so we can respond with error to requests */ + VPRINTK(skdev, "starting %s queue to error-out reqs\n", + skdev->name); + skd_start_queue(skdev); + skdev->gendisk_on = -1; + wake_up_interruptible(&skdev->waitq); + break; + + default: + pr_err("(%s) Start: unknown state %x\n", + skd_name(skdev), skdev->drive_state); + break; + } + + state = SKD_READL(skdev, FIT_CONTROL); + DPRINTK(skdev, "FIT Control Status=0x%x\n", state); + + state = SKD_READL(skdev, FIT_INT_STATUS_HOST); + DPRINTK(skdev, "Intr Status=0x%x\n", state); + + state = SKD_READL(skdev, FIT_INT_MASK_HOST); + DPRINTK(skdev, "Intr Mask=0x%x\n", state); + + state = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); + DPRINTK(skdev, "Msg from Dev=0x%x\n", state); + + state = SKD_READL(skdev, FIT_HW_VERSION); + DPRINTK(skdev, "HW version=0x%x\n", state); + + spin_unlock_irqrestore(&skdev->lock, flags); +} + +static void skd_stop_device(struct skd_device *skdev) +{ + unsigned long flags; + struct skd_special_context *skspcl = &skdev->internal_skspcl; + u32 dev_state; + int i; + + spin_lock_irqsave(&skdev->lock, flags); + + if (skdev->state != SKD_DRVR_STATE_ONLINE) { + pr_err("(%s): skd_stop_device not online no sync\n", + skd_name(skdev)); + goto stop_out; + } + + if (skspcl->req.state != SKD_REQ_STATE_IDLE) { + pr_err("(%s): skd_stop_device no special\n", + skd_name(skdev)); + goto stop_out; + } + + skdev->state = SKD_DRVR_STATE_SYNCING; + skdev->sync_done = 0; + + skd_send_internal_skspcl(skdev, skspcl, SYNCHRONIZE_CACHE); + + spin_unlock_irqrestore(&skdev->lock, flags); + + wait_event_interruptible_timeout(skdev->waitq, + (skdev->sync_done), (10 * HZ)); + + spin_lock_irqsave(&skdev->lock, flags); + + switch (skdev->sync_done) { + case 0: + pr_err("(%s): skd_stop_device no sync\n", + skd_name(skdev)); + break; + case 1: + pr_err("(%s): skd_stop_device sync done\n", + skd_name(skdev)); + break; + default: + pr_err("(%s): skd_stop_device sync error\n", + skd_name(skdev)); + } + +stop_out: + skdev->state = SKD_DRVR_STATE_STOPPING; + spin_unlock_irqrestore(&skdev->lock, flags); + + skd_kill_timer(skdev); + + spin_lock_irqsave(&skdev->lock, flags); + skd_disable_interrupts(skdev); + + /* ensure all ints on device are cleared */ + /* soft reset the device to unload with a clean slate */ + SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); + SKD_WRITEL(skdev, FIT_CR_SOFT_RESET, FIT_CONTROL); + + spin_unlock_irqrestore(&skdev->lock, flags); + + /* poll every 100ms, 1 second timeout */ + for (i = 0; i < 10; i++) { + dev_state = + SKD_READL(skdev, FIT_STATUS) & FIT_SR_DRIVE_STATE_MASK; + if (dev_state == FIT_SR_DRIVE_INIT) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(100)); + } + + if (dev_state != FIT_SR_DRIVE_INIT) + pr_err("(%s): skd_stop_device state error 0x%02x\n", + skd_name(skdev), dev_state); +} + +/* assume spinlock is held */ +static void skd_restart_device(struct skd_device *skdev) +{ + u32 state; + + /* ack all ghost interrupts */ + SKD_WRITEL(skdev, FIT_INT_DEF_MASK, FIT_INT_STATUS_HOST); + + state = SKD_READL(skdev, FIT_STATUS); + + DPRINTK(skdev, "drive status=0x%x\n", state); + + state &= FIT_SR_DRIVE_STATE_MASK; + skdev->drive_state = state; + skdev->last_mtd = 0; + + skdev->state = SKD_DRVR_STATE_RESTARTING; + skdev->timer_countdown = SKD_RESTARTING_TIMO; + + skd_soft_reset(skdev); +} + +/* assume spinlock is held */ +static int skd_quiesce_dev(struct skd_device *skdev) +{ + int rc = 0; + + switch (skdev->state) { + case SKD_DRVR_STATE_BUSY: + case SKD_DRVR_STATE_BUSY_IMMINENT: + VPRINTK(skdev, "stopping %s queue\n", skdev->name); + skd_stop_queue(skdev); + break; + case SKD_DRVR_STATE_ONLINE: + case SKD_DRVR_STATE_STOPPING: + case SKD_DRVR_STATE_SYNCING: + case SKD_DRVR_STATE_PAUSING: + case SKD_DRVR_STATE_PAUSED: + case SKD_DRVR_STATE_STARTING: + case SKD_DRVR_STATE_RESTARTING: + case SKD_DRVR_STATE_RESUMING: + default: + rc = -EINVAL; + VPRINTK(skdev, "state [%d] not implemented\n", skdev->state); + } + return rc; +} + +/* assume spinlock is held */ +static int skd_unquiesce_dev(struct skd_device *skdev) +{ + int prev_driver_state = skdev->state; + + skd_log_skdev(skdev, "unquiesce"); + if (skdev->state == SKD_DRVR_STATE_ONLINE) { + DPRINTK(skdev, "**** device already ONLINE\n"); + return 0; + } + if (skdev->drive_state != FIT_SR_DRIVE_ONLINE) { + /* + * If there has been an state change to other than + * ONLINE, we will rely on controller state change + * to come back online and restart the queue. + * The BUSY state means that driver is ready to + * continue normal processing but waiting for controller + * to become available. + */ + skdev->state = SKD_DRVR_STATE_BUSY; + DPRINTK(skdev, "drive BUSY state\n"); + return 0; + } + + /* + * Drive has just come online, driver is either in startup, + * paused performing a task, or bust waiting for hardware. + */ + switch (skdev->state) { + case SKD_DRVR_STATE_PAUSED: + case SKD_DRVR_STATE_BUSY: + case SKD_DRVR_STATE_BUSY_IMMINENT: + case SKD_DRVR_STATE_BUSY_ERASE: + case SKD_DRVR_STATE_STARTING: + case SKD_DRVR_STATE_RESTARTING: + case SKD_DRVR_STATE_FAULT: + case SKD_DRVR_STATE_IDLE: + case SKD_DRVR_STATE_LOAD: + skdev->state = SKD_DRVR_STATE_ONLINE; + pr_err("(%s): Driver state %s(%d)=>%s(%d)\n", + skd_name(skdev), + skd_skdev_state_to_str(prev_driver_state), + prev_driver_state, skd_skdev_state_to_str(skdev->state), + skdev->state); + DPRINTK(skdev, "**** device ONLINE...starting block queue\n"); + VPRINTK(skdev, "starting %s queue\n", skdev->name); + pr_info("(%s): STEC s1120 ONLINE\n", skd_name(skdev)); + skd_start_queue(skdev); + skdev->gendisk_on = 1; + wake_up_interruptible(&skdev->waitq); + break; + + case SKD_DRVR_STATE_DISAPPEARED: + default: + DPRINTK(skdev, "**** driver state %d, not implemented \n", + skdev->state); + return -EBUSY; + } + return 0; +} + +/* + ***************************************************************************** + * PCIe MSI/MSI-X INTERRUPT HANDLERS + ***************************************************************************** + */ + +static irqreturn_t skd_reserved_isr(int irq, void *skd_host_data) +{ + struct skd_device *skdev = skd_host_data; + unsigned long flags; + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_err("(%s): MSIX reserved irq %d = 0x%x\n", skd_name(skdev), + irq, SKD_READL(skdev, FIT_INT_STATUS_HOST)); + SKD_WRITEL(skdev, FIT_INT_RESERVED_MASK, FIT_INT_STATUS_HOST); + spin_unlock_irqrestore(&skdev->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t skd_statec_isr(int irq, void *skd_host_data) +{ + struct skd_device *skdev = skd_host_data; + unsigned long flags; + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + SKD_WRITEL(skdev, FIT_ISH_FW_STATE_CHANGE, FIT_INT_STATUS_HOST); + skd_isr_fwstate(skdev); + spin_unlock_irqrestore(&skdev->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t skd_comp_q(int irq, void *skd_host_data) +{ + struct skd_device *skdev = skd_host_data; + unsigned long flags; + int flush_enqueued = 0; + int deferred; + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + SKD_WRITEL(skdev, FIT_ISH_COMPLETION_POSTED, FIT_INT_STATUS_HOST); + deferred = skd_isr_completion_posted(skdev, skd_isr_comp_limit, + &flush_enqueued); + + if (flush_enqueued) + skd_request_fn(skdev->queue); + + if (deferred) + schedule_work(&skdev->completion_worker); + else if (!flush_enqueued) + skd_request_fn(skdev->queue); + + spin_unlock_irqrestore(&skdev->lock, flags); + + return IRQ_HANDLED; +} + +static irqreturn_t skd_msg_isr(int irq, void *skd_host_data) +{ + struct skd_device *skdev = skd_host_data; + unsigned long flags; + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + SKD_WRITEL(skdev, FIT_ISH_MSG_FROM_DEV, FIT_INT_STATUS_HOST); + skd_isr_msg_from_dev(skdev); + spin_unlock_irqrestore(&skdev->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t skd_qfull_isr(int irq, void *skd_host_data) +{ + struct skd_device *skdev = skd_host_data; + unsigned long flags; + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + SKD_WRITEL(skdev, FIT_INT_QUEUE_FULL, FIT_INT_STATUS_HOST); + spin_unlock_irqrestore(&skdev->lock, flags); + return IRQ_HANDLED; +} + +/* + ***************************************************************************** + * PCIe MSI/MSI-X SETUP + ***************************************************************************** + */ + +struct skd_msix_entry { + int have_irq; + u32 vector; + u32 entry; + struct skd_device *rsp; + char isr_name[30]; +}; + +struct skd_init_msix_entry { + const char *name; + irq_handler_t handler; +}; + +#define SKD_MAX_MSIX_COUNT 13 +#define SKD_MIN_MSIX_COUNT 7 +#define SKD_BASE_MSIX_IRQ 4 + +static struct skd_init_msix_entry msix_entries[SKD_MAX_MSIX_COUNT] = { + { "(DMA 0)", skd_reserved_isr }, + { "(DMA 1)", skd_reserved_isr }, + { "(DMA 2)", skd_reserved_isr }, + { "(DMA 3)", skd_reserved_isr }, + { "(State Change)", skd_statec_isr }, + { "(COMPL_Q)", skd_comp_q }, + { "(MSG)", skd_msg_isr }, + { "(Reserved)", skd_reserved_isr }, + { "(Reserved)", skd_reserved_isr }, + { "(Queue Full 0)", skd_qfull_isr }, + { "(Queue Full 1)", skd_qfull_isr }, + { "(Queue Full 2)", skd_qfull_isr }, + { "(Queue Full 3)", skd_qfull_isr }, +}; + +static void skd_release_msix(struct skd_device *skdev) +{ + struct skd_msix_entry *qentry; + int i; + + if (skdev->msix_entries == NULL) + return; + for (i = 0; i < skdev->msix_count; i++) { + qentry = &skdev->msix_entries[i]; + skdev = qentry->rsp; + + if (qentry->have_irq) + devm_free_irq(&skdev->pdev->dev, + qentry->vector, qentry->rsp); + } + pci_disable_msix(skdev->pdev); + kfree(skdev->msix_entries); + skdev->msix_count = 0; + skdev->msix_entries = NULL; +} + +static int skd_acquire_msix(struct skd_device *skdev) +{ + int i, rc; + struct pci_dev *pdev; + struct msix_entry *entries = NULL; + struct skd_msix_entry *qentry; + + pdev = skdev->pdev; + skdev->msix_count = SKD_MAX_MSIX_COUNT; + entries = kzalloc(sizeof(struct msix_entry) * SKD_MAX_MSIX_COUNT, + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) + entries[i].entry = i; + + rc = pci_enable_msix(pdev, entries, SKD_MAX_MSIX_COUNT); + if (rc < 0) + goto msix_out; + if (rc) { + if (rc < SKD_MIN_MSIX_COUNT) { + pr_err("(%s): failed to enable MSI-X %d\n", + skd_name(skdev), rc); + goto msix_out; + } + DPRINTK(skdev, "%s: <%s> allocated %d MSI-X vectors\n", + pci_name(pdev), skdev->name, rc); + + skdev->msix_count = rc; + rc = pci_enable_msix(pdev, entries, skdev->msix_count); + if (rc) { + pr_err("(%s): failed to enable MSI-X " + "support (%d) %d\n", + skd_name(skdev), skdev->msix_count, rc); + goto msix_out; + } + } + skdev->msix_entries = kzalloc(sizeof(struct skd_msix_entry) * + skdev->msix_count, GFP_KERNEL); + if (!skdev->msix_entries) { + rc = -ENOMEM; + skdev->msix_count = 0; + pr_err("(%s): msix table allocation error\n", + skd_name(skdev)); + goto msix_out; + } + + qentry = skdev->msix_entries; + for (i = 0; i < skdev->msix_count; i++) { + qentry->vector = entries[i].vector; + qentry->entry = entries[i].entry; + qentry->rsp = NULL; + qentry->have_irq = 0; + DPRINTK(skdev, "%s: <%s> msix (%d) vec %d, entry %x\n", + pci_name(pdev), skdev->name, + i, qentry->vector, qentry->entry); + qentry++; + } + + /* Enable MSI-X vectors for the base queue */ + for (i = 0; i < SKD_MAX_MSIX_COUNT; i++) { + qentry = &skdev->msix_entries[i]; + snprintf(qentry->isr_name, sizeof(qentry->isr_name), + "%s%d-msix %s", DRV_NAME, skdev->devno, + msix_entries[i].name); + rc = devm_request_irq(&skdev->pdev->dev, qentry->vector, + msix_entries[i].handler, 0, + qentry->isr_name, skdev); + if (rc) { + pr_err("(%s): Unable to register(%d) MSI-X " + "handler %d: %s\n", + skd_name(skdev), rc, i, qentry->isr_name); + goto msix_out; + } else { + qentry->have_irq = 1; + qentry->rsp = skdev; + } + } + DPRINTK(skdev, "%s: <%s> msix %d irq(s) enabled\n", + pci_name(pdev), skdev->name, skdev->msix_count); + return 0; + +msix_out: + if (entries) + kfree(entries); + skd_release_msix(skdev); + return rc; +} + +static int skd_acquire_irq(struct skd_device *skdev) +{ + int rc; + struct pci_dev *pdev; + + pdev = skdev->pdev; + skdev->msix_count = 0; + +RETRY_IRQ_TYPE: + switch (skdev->irq_type) { + case SKD_IRQ_MSIX: + rc = skd_acquire_msix(skdev); + if (!rc) + pr_info("(%s): MSI-X %d irqs enabled\n", + skd_name(skdev), skdev->msix_count); + else { + pr_err( + "(%s): failed to enable MSI-X, re-trying with MSI %d\n", + skd_name(skdev), rc); + skdev->irq_type = SKD_IRQ_MSI; + goto RETRY_IRQ_TYPE; + } + break; + case SKD_IRQ_MSI: + snprintf(skdev->isr_name, sizeof(skdev->isr_name), "%s%d-msi", + DRV_NAME, skdev->devno); + rc = pci_enable_msi(pdev); + if (!rc) { + rc = devm_request_irq(&pdev->dev, pdev->irq, skd_isr, 0, + skdev->isr_name, skdev); + if (rc) { + pci_disable_msi(pdev); + pr_err( + "(%s): failed to allocate the MSI interrupt %d\n", + skd_name(skdev), rc); + goto RETRY_IRQ_LEGACY; + } + pr_info("(%s): MSI irq %d enabled\n", + skd_name(skdev), pdev->irq); + } else { +RETRY_IRQ_LEGACY: + pr_err( + "(%s): failed to enable MSI, re-trying with LEGACY %d\n", + skd_name(skdev), rc); + skdev->irq_type = SKD_IRQ_LEGACY; + goto RETRY_IRQ_TYPE; + } + break; + case SKD_IRQ_LEGACY: + snprintf(skdev->isr_name, sizeof(skdev->isr_name), + "%s%d-legacy", DRV_NAME, skdev->devno); + rc = devm_request_irq(&pdev->dev, pdev->irq, skd_isr, + IRQF_SHARED, skdev->isr_name, skdev); + if (!rc) + pr_info("(%s): LEGACY irq %d enabled\n", + skd_name(skdev), pdev->irq); + else + pr_err("(%s): request LEGACY irq error %d\n", + skd_name(skdev), rc); + break; + default: + pr_info("(%s): irq_type %d invalid, re-set to %d\n", + skd_name(skdev), skdev->irq_type, SKD_IRQ_DEFAULT); + skdev->irq_type = SKD_IRQ_LEGACY; + goto RETRY_IRQ_TYPE; + } + return rc; +} + +static void skd_release_irq(struct skd_device *skdev) +{ + switch (skdev->irq_type) { + case SKD_IRQ_MSIX: + skd_release_msix(skdev); + break; + case SKD_IRQ_MSI: + devm_free_irq(&skdev->pdev->dev, skdev->pdev->irq, skdev); + pci_disable_msi(skdev->pdev); + break; + case SKD_IRQ_LEGACY: + devm_free_irq(&skdev->pdev->dev, skdev->pdev->irq, skdev); + break; + default: + pr_err("(%s): wrong irq type %d!", + skd_name(skdev), skdev->irq_type); + break; + } +} + +/* + ***************************************************************************** + * CONSTRUCT + ***************************************************************************** + */ + +static int skd_cons_skcomp(struct skd_device *skdev); +static int skd_cons_skmsg(struct skd_device *skdev); +static int skd_cons_skreq(struct skd_device *skdev); +static int skd_cons_skspcl(struct skd_device *skdev); +static int skd_cons_sksb(struct skd_device *skdev); +static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, + u32 n_sg, + dma_addr_t *ret_dma_addr); +static int skd_cons_disk(struct skd_device *skdev); + +#define SKD_N_DEV_TABLE 16u +static u32 skd_next_devno; + +static struct skd_device *skd_construct(struct pci_dev *pdev) +{ + struct skd_device *skdev; + int blk_major = skd_major; + int rc; + + skdev = kzalloc(sizeof(*skdev), GFP_KERNEL); + + if (!skdev) { + pr_err(PFX "(%s): memory alloc failure\n", + pci_name(pdev)); + return NULL; + } + + skdev->state = SKD_DRVR_STATE_LOAD; + skdev->pdev = pdev; + skdev->devno = skd_next_devno++; + skdev->major = blk_major; + skdev->irq_type = skd_isr_type; + sprintf(skdev->name, DRV_NAME "%d", skdev->devno); + skdev->dev_max_queue_depth = 0; + + skdev->num_req_context = skd_max_queue_depth; + skdev->num_fitmsg_context = skd_max_queue_depth; + skdev->n_special = skd_max_pass_thru; + skdev->cur_max_queue_depth = 1; + skdev->queue_low_water_mark = 1; + skdev->proto_ver = 99; + skdev->sgs_per_request = skd_sgs_per_request; + skdev->dbg_level = skd_dbg_level; + + if (skd_bio) + bio_list_init(&skdev->bio_queue); + + + atomic_set(&skdev->device_count, 0); + + spin_lock_init(&skdev->lock); + + INIT_WORK(&skdev->completion_worker, skd_completion_worker); + INIT_LIST_HEAD(&skdev->flush_list); + + VPRINTK(skdev, "skcomp\n"); + rc = skd_cons_skcomp(skdev); + if (rc < 0) + goto err_out; + + VPRINTK(skdev, "skmsg\n"); + rc = skd_cons_skmsg(skdev); + if (rc < 0) + goto err_out; + + VPRINTK(skdev, "skreq\n"); + rc = skd_cons_skreq(skdev); + if (rc < 0) + goto err_out; + + VPRINTK(skdev, "skspcl\n"); + rc = skd_cons_skspcl(skdev); + if (rc < 0) + goto err_out; + + VPRINTK(skdev, "sksb\n"); + rc = skd_cons_sksb(skdev); + if (rc < 0) + goto err_out; + + VPRINTK(skdev, "disk\n"); + rc = skd_cons_disk(skdev); + if (rc < 0) + goto err_out; + + + + DPRINTK(skdev, "VICTORY\n"); + return skdev; + +err_out: + DPRINTK(skdev, "construct failed\n"); + skd_destruct(skdev); + return NULL; +} + +static int skd_cons_skcomp(struct skd_device *skdev) +{ + int rc = 0; + struct fit_completion_entry_v1 *skcomp; + u32 nbytes; + + nbytes = sizeof(*skcomp) * SKD_N_COMPLETION_ENTRY; + nbytes += sizeof(struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY; + + VPRINTK(skdev, "comp pci_alloc, total bytes %d entries %d\n", nbytes, + SKD_N_COMPLETION_ENTRY); + + skcomp = pci_alloc_consistent(skdev->pdev, nbytes, + &skdev->cq_dma_address); + + if (skcomp == NULL) { + rc = -ENOMEM; + goto err_out; + } + + memset(skcomp, 0, nbytes); + + skdev->skcomp_table = skcomp; + skdev->skerr_table = (struct fit_comp_error_info *)((char *)skcomp + + sizeof(*skcomp) * + SKD_N_COMPLETION_ENTRY); + +err_out: + return rc; +} + +static int skd_cons_skmsg(struct skd_device *skdev) +{ + int rc = 0; + u32 i; + + VPRINTK(skdev, "skmsg_table kzalloc, struct %u, count %u total %lu\n", + sizeof(struct skd_fitmsg_context), + skdev->num_fitmsg_context, + (unsigned long) sizeof(struct skd_fitmsg_context) * + skdev->num_fitmsg_context); + + skdev->skmsg_table = kzalloc(sizeof(struct skd_fitmsg_context) + *skdev->num_fitmsg_context, GFP_KERNEL); + if (skdev->skmsg_table == NULL) { + rc = -ENOMEM; + goto err_out; + } + + for (i = 0; i < skdev->num_fitmsg_context; i++) { + struct skd_fitmsg_context *skmsg; + + skmsg = &skdev->skmsg_table[i]; + + skmsg->id = i + SKD_ID_FIT_MSG; + + skmsg->state = SKD_MSG_STATE_IDLE; + skmsg->msg_buf = pci_alloc_consistent(skdev->pdev, + SKD_N_FITMSG_BYTES + 64, + &skmsg->mb_dma_address); + + if (skmsg->msg_buf == NULL) { + rc = -ENOMEM; + goto err_out; + } + + skmsg->offset = (u32)((u64)skmsg->msg_buf & + (~FIT_QCMD_BASE_ADDRESS_MASK)); + skmsg->msg_buf += ~FIT_QCMD_BASE_ADDRESS_MASK; + skmsg->msg_buf = (u8 *)((u64)skmsg->msg_buf & + FIT_QCMD_BASE_ADDRESS_MASK); + skmsg->mb_dma_address += ~FIT_QCMD_BASE_ADDRESS_MASK; + skmsg->mb_dma_address &= FIT_QCMD_BASE_ADDRESS_MASK; + memset(skmsg->msg_buf, 0, SKD_N_FITMSG_BYTES); + + skmsg->next = &skmsg[1]; + } + + /* Free list is in order starting with the 0th entry. */ + skdev->skmsg_table[i - 1].next = NULL; + skdev->skmsg_free_list = skdev->skmsg_table; + +err_out: + return rc; +} + +static int skd_cons_skreq(struct skd_device *skdev) +{ + int rc = 0; + u32 i; + + VPRINTK(skdev, "skreq_table kzalloc, struct %u, count %u total %u\n", + sizeof(struct skd_request_context), + skdev->num_req_context, + sizeof(struct skd_request_context) * skdev->num_req_context); + + skdev->skreq_table = kzalloc(sizeof(struct skd_request_context) + * skdev->num_req_context, GFP_KERNEL); + if (skdev->skreq_table == NULL) { + rc = -ENOMEM; + goto err_out; + } + + VPRINTK(skdev, "alloc sg_table sg_per_req %u scatlist %u total %u\n", + skdev->sgs_per_request, sizeof(struct scatterlist), + skdev->sgs_per_request * sizeof(struct scatterlist)); + + for (i = 0; i < skdev->num_req_context; i++) { + struct skd_request_context *skreq; + + skreq = &skdev->skreq_table[i]; + + skreq->id = i + SKD_ID_RW_REQUEST; + skreq->state = SKD_REQ_STATE_IDLE; + + skreq->sg = kzalloc(sizeof(struct scatterlist) * + skdev->sgs_per_request, GFP_KERNEL); + if (skreq->sg == NULL) { + rc = -ENOMEM; + goto err_out; + } + sg_init_table(skreq->sg, skdev->sgs_per_request); + + skreq->sksg_list = skd_cons_sg_list(skdev, + skdev->sgs_per_request, + &skreq->sksg_dma_address); + + if (skreq->sksg_list == NULL) { + rc = -ENOMEM; + goto err_out; + } + + skreq->next = &skreq[1]; + } + + /* Free list is in order starting with the 0th entry. */ + skdev->skreq_table[i - 1].next = NULL; + skdev->skreq_free_list = skdev->skreq_table; + +err_out: + return rc; +} + +static int skd_cons_skspcl(struct skd_device *skdev) +{ + int rc = 0; + u32 i, nbytes; + + VPRINTK(skdev, "skspcl_table kzalloc, struct %u, count %u total %u\n", + sizeof(struct skd_special_context), + skdev->n_special, + sizeof(struct skd_special_context) * skdev->n_special); + + skdev->skspcl_table = kzalloc(sizeof(struct skd_special_context) + * skdev->n_special, GFP_KERNEL); + if (skdev->skspcl_table == NULL) { + rc = -ENOMEM; + goto err_out; + } + + for (i = 0; i < skdev->n_special; i++) { + struct skd_special_context *skspcl; + + skspcl = &skdev->skspcl_table[i]; + + skspcl->req.id = i + SKD_ID_SPECIAL_REQUEST; + skspcl->req.state = SKD_REQ_STATE_IDLE; + + skspcl->req.next = &skspcl[1].req; + + nbytes = SKD_N_SPECIAL_FITMSG_BYTES; + + skspcl->msg_buf = pci_alloc_consistent(skdev->pdev, nbytes, + &skspcl->mb_dma_address); + if (skspcl->msg_buf == NULL) { + rc = -ENOMEM; + goto err_out; + } + + memset(skspcl->msg_buf, 0, nbytes); + + skspcl->req.sg = kzalloc(sizeof(struct scatterlist) * + SKD_N_SG_PER_SPECIAL, GFP_KERNEL); + if (skspcl->req.sg == NULL) { + rc = -ENOMEM; + goto err_out; + } + + skspcl->req.sksg_list = skd_cons_sg_list(skdev, + SKD_N_SG_PER_SPECIAL, + &skspcl->req. + sksg_dma_address); + if (skspcl->req.sksg_list == NULL) { + rc = -ENOMEM; + goto err_out; + } + } + + /* Free list is in order starting with the 0th entry. */ + skdev->skspcl_table[i - 1].req.next = NULL; + skdev->skspcl_free_list = skdev->skspcl_table; + + return rc; + +err_out: + return rc; +} + +static int skd_cons_sksb(struct skd_device *skdev) +{ + int rc = 0; + struct skd_special_context *skspcl; + u32 nbytes; + + skspcl = &skdev->internal_skspcl; + + skspcl->req.id = 0 + SKD_ID_INTERNAL; + skspcl->req.state = SKD_REQ_STATE_IDLE; + + nbytes = SKD_N_INTERNAL_BYTES; + + skspcl->data_buf = pci_alloc_consistent(skdev->pdev, nbytes, + &skspcl->db_dma_address); + if (skspcl->data_buf == NULL) { + rc = -ENOMEM; + goto err_out; + } + + memset(skspcl->data_buf, 0, nbytes); + + nbytes = SKD_N_SPECIAL_FITMSG_BYTES; + skspcl->msg_buf = pci_alloc_consistent(skdev->pdev, nbytes, + &skspcl->mb_dma_address); + if (skspcl->msg_buf == NULL) { + rc = -ENOMEM; + goto err_out; + } + + memset(skspcl->msg_buf, 0, nbytes); + + skspcl->req.sksg_list = skd_cons_sg_list(skdev, 1, + &skspcl->req.sksg_dma_address); + if (skspcl->req.sksg_list == NULL) { + rc = -ENOMEM; + goto err_out; + } + + if (!skd_format_internal_skspcl(skdev)) { + rc = -EINVAL; + goto err_out; + } + +err_out: + return rc; +} + +static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, + u32 n_sg, + dma_addr_t *ret_dma_addr) +{ + struct fit_sg_descriptor *sg_list; + u32 nbytes; + + nbytes = sizeof(*sg_list) * n_sg; + + sg_list = pci_alloc_consistent(skdev->pdev, nbytes, ret_dma_addr); + + if (sg_list != NULL) { + uint64_t dma_address = *ret_dma_addr; + u32 i; + + memset(sg_list, 0, nbytes); + + for (i = 0; i < n_sg - 1; i++) { + uint64_t ndp_off; + ndp_off = (i + 1) * sizeof(struct fit_sg_descriptor); + + sg_list[i].next_desc_ptr = dma_address + ndp_off; + } + sg_list[i].next_desc_ptr = 0LL; + } + + return sg_list; +} + +static int skd_cons_disk(struct skd_device *skdev) +{ + int rc = 0; + struct gendisk *disk; + struct request_queue *q; + unsigned long flags; + + disk = alloc_disk(SKD_MINORS_PER_DEVICE); + if (!disk) { + rc = -ENOMEM; + goto err_out; + } + + skdev->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%u", skdev->devno); + + disk->major = skdev->major; + disk->first_minor = skdev->devno * SKD_MINORS_PER_DEVICE; + disk->fops = &skd_blockdev_ops; + disk->private_data = skdev; + + if (!skd_bio) { + q = blk_init_queue(skd_request_fn, &skdev->lock); + } else { + q = blk_alloc_queue(GFP_KERNEL); + q->queue_flags = QUEUE_FLAG_IO_STAT | QUEUE_FLAG_STACKABLE; + } + + if (!q) { + rc = -ENOMEM; + goto err_out; + } + + skdev->queue = q; + disk->queue = q; + q->queuedata = skdev; + + if (skd_bio) { + q->queue_lock = &skdev->lock; + blk_queue_make_request(q, skd_make_request); + } + + blk_queue_flush(q, REQ_FLUSH | REQ_FUA); + blk_queue_max_segments(q, skdev->sgs_per_request); + blk_queue_max_hw_sectors(q, SKD_N_MAX_SECTORS); + + /* set sysfs ptimal_io_size to 8K */ + blk_queue_io_opt(q, 8192); + + /* DISCARD Flag initialization. */ + q->limits.discard_granularity = 8192; + q->limits.discard_alignment = 0; + q->limits.max_discard_sectors = UINT_MAX >> 9; + q->limits.discard_zeroes_data = 1; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); + + spin_lock_irqsave(&skdev->lock, flags); + VPRINTK(skdev, "stopping %s queue\n", skdev->name); + skd_stop_queue(skdev); + spin_unlock_irqrestore(&skdev->lock, flags); + +err_out: + return rc; +} + +/* + ***************************************************************************** + * DESTRUCT (FREE) + ***************************************************************************** + */ + +static void skd_free_skcomp(struct skd_device *skdev); +static void skd_free_skmsg(struct skd_device *skdev); +static void skd_free_skreq(struct skd_device *skdev); +static void skd_free_skspcl(struct skd_device *skdev); +static void skd_free_sksb(struct skd_device *skdev); +static void skd_free_sg_list(struct skd_device *skdev, + struct fit_sg_descriptor *sg_list, + u32 n_sg, dma_addr_t dma_addr); +static void skd_free_disk(struct skd_device *skdev); + +static void skd_destruct(struct skd_device *skdev) +{ + if (skdev == NULL) + return; + + + VPRINTK(skdev, "disk\n"); + skd_free_disk(skdev); + + VPRINTK(skdev, "sksb\n"); + skd_free_sksb(skdev); + + VPRINTK(skdev, "skspcl\n"); + skd_free_skspcl(skdev); + + VPRINTK(skdev, "skreq\n"); + skd_free_skreq(skdev); + + VPRINTK(skdev, "skmsg\n"); + skd_free_skmsg(skdev); + + VPRINTK(skdev, "skcomp\n"); + skd_free_skcomp(skdev); + + VPRINTK(skdev, "skdev\n"); + kfree(skdev); +} + +static void skd_free_skcomp(struct skd_device *skdev) +{ + if (skdev->skcomp_table != NULL) { + u32 nbytes; + + nbytes = sizeof(skdev->skcomp_table[0]) * + SKD_N_COMPLETION_ENTRY; + pci_free_consistent(skdev->pdev, nbytes, + skdev->skcomp_table, skdev->cq_dma_address); + } + + skdev->skcomp_table = NULL; + skdev->cq_dma_address = 0; +} + +static void skd_free_skmsg(struct skd_device *skdev) +{ + u32 i; + + if (skdev->skmsg_table == NULL) + return; + + for (i = 0; i < skdev->num_fitmsg_context; i++) { + struct skd_fitmsg_context *skmsg; + + skmsg = &skdev->skmsg_table[i]; + + if (skmsg->msg_buf != NULL) { + skmsg->msg_buf += skmsg->offset; + skmsg->mb_dma_address += skmsg->offset; + pci_free_consistent(skdev->pdev, SKD_N_FITMSG_BYTES, + skmsg->msg_buf, + skmsg->mb_dma_address); + } + skmsg->msg_buf = NULL; + skmsg->mb_dma_address = 0; + } + + kfree(skdev->skmsg_table); + skdev->skmsg_table = NULL; +} + +static void skd_free_skreq(struct skd_device *skdev) +{ + u32 i; + + if (skdev->skreq_table == NULL) + return; + + for (i = 0; i < skdev->num_req_context; i++) { + struct skd_request_context *skreq; + + skreq = &skdev->skreq_table[i]; + + skd_free_sg_list(skdev, skreq->sksg_list, + skdev->sgs_per_request, + skreq->sksg_dma_address); + + skreq->sksg_list = NULL; + skreq->sksg_dma_address = 0; + + kfree(skreq->sg); + } + + kfree(skdev->skreq_table); + skdev->skreq_table = NULL; +} + +static void skd_free_skspcl(struct skd_device *skdev) +{ + u32 i; + u32 nbytes; + + if (skdev->skspcl_table == NULL) + return; + + for (i = 0; i < skdev->n_special; i++) { + struct skd_special_context *skspcl; + + skspcl = &skdev->skspcl_table[i]; + + if (skspcl->msg_buf != NULL) { + nbytes = SKD_N_SPECIAL_FITMSG_BYTES; + pci_free_consistent(skdev->pdev, nbytes, + skspcl->msg_buf, + skspcl->mb_dma_address); + } + + skspcl->msg_buf = NULL; + skspcl->mb_dma_address = 0; + + skd_free_sg_list(skdev, skspcl->req.sksg_list, + SKD_N_SG_PER_SPECIAL, + skspcl->req.sksg_dma_address); + + skspcl->req.sksg_list = NULL; + skspcl->req.sksg_dma_address = 0; + + kfree(skspcl->req.sg); + } + + kfree(skdev->skspcl_table); + skdev->skspcl_table = NULL; +} + +static void skd_free_sksb(struct skd_device *skdev) +{ + struct skd_special_context *skspcl; + u32 nbytes; + + skspcl = &skdev->internal_skspcl; + + if (skspcl->data_buf != NULL) { + nbytes = SKD_N_INTERNAL_BYTES; + + pci_free_consistent(skdev->pdev, nbytes, + skspcl->data_buf, skspcl->db_dma_address); + } + + skspcl->data_buf = NULL; + skspcl->db_dma_address = 0; + + if (skspcl->msg_buf != NULL) { + nbytes = SKD_N_SPECIAL_FITMSG_BYTES; + pci_free_consistent(skdev->pdev, nbytes, + skspcl->msg_buf, skspcl->mb_dma_address); + } + + skspcl->msg_buf = NULL; + skspcl->mb_dma_address = 0; + + skd_free_sg_list(skdev, skspcl->req.sksg_list, 1, + skspcl->req.sksg_dma_address); + + skspcl->req.sksg_list = NULL; + skspcl->req.sksg_dma_address = 0; +} + +static void skd_free_sg_list(struct skd_device *skdev, + struct fit_sg_descriptor *sg_list, + u32 n_sg, dma_addr_t dma_addr) +{ + if (sg_list != NULL) { + u32 nbytes; + + nbytes = sizeof(*sg_list) * n_sg; + + pci_free_consistent(skdev->pdev, nbytes, sg_list, dma_addr); + } +} + +static void skd_free_disk(struct skd_device *skdev) +{ + struct gendisk *disk = skdev->disk; + + if (disk != NULL) { + struct request_queue *q = disk->queue; + + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) + blk_cleanup_queue(q); + put_disk(disk); + } + skdev->disk = NULL; +} + + + +/* + ***************************************************************************** + * BLOCK DEVICE (BDEV) GLUE + ***************************************************************************** + */ + +static int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct skd_device *skdev; + u64 capacity; + + skdev = bdev->bd_disk->private_data; + + DPRINTK(skdev, "%s: CMD[%s] getgeo device\n", + bdev->bd_disk->disk_name, current->comm); + + if (skdev->read_cap_is_valid) { + capacity = get_capacity(skdev->disk); + geo->heads = 64; + geo->sectors = 255; + geo->cylinders = (capacity) / (255 * 64); + + return 0; + } + return -EIO; +} + +static int skd_bdev_attach(struct skd_device *skdev) +{ + DPRINTK(skdev, "add_disk\n"); + add_disk(skdev->disk); + return 0; +} + +static const struct block_device_operations skd_blockdev_ops = { + .owner = THIS_MODULE, + .ioctl = skd_bdev_ioctl, + .getgeo = skd_bdev_getgeo, +}; + + +/* + ***************************************************************************** + * PCIe DRIVER GLUE + ***************************************************************************** + */ + +static DEFINE_PCI_DEVICE_TABLE(skd_pci_tbl) = { + { PCI_VENDOR_ID_STEC, PCI_DEVICE_ID_S1120, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { 0 } /* terminate list */ +}; + +MODULE_DEVICE_TABLE(pci, skd_pci_tbl); + +static char *skd_pci_info(struct skd_device *skdev, char *str) +{ + int pcie_reg; + + strcpy(str, "PCIe ("); + pcie_reg = pci_find_capability(skdev->pdev, PCI_CAP_ID_EXP); + + if (pcie_reg) { + + char lwstr[6]; + uint16_t pcie_lstat, lspeed, lwidth; + + pcie_reg += 0x12; + pci_read_config_word(skdev->pdev, pcie_reg, &pcie_lstat); + lspeed = pcie_lstat & (0xF); + lwidth = (pcie_lstat & 0x3F0) >> 4; + + if (lspeed == 1) + strcat(str, "2.5GT/s "); + else if (lspeed == 2) + strcat(str, "5.0GT/s "); + else + strcat(str, " "); + snprintf(lwstr, sizeof(lwstr), "%dX)", lwidth); + strcat(str, lwstr); + } + return str; +} + +static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int i; + int rc = 0; + char pci_str[32]; + struct skd_device *skdev; + + pr_info("STEC s1120 Driver(%s) version %s-b%s\n", + DRV_NAME, DRV_VERSION, DRV_BUILD_ID); + pr_info("(skd?:??:[%s]): vendor=%04X device=%04x\n", + pci_name(pdev), pdev->vendor, pdev->device); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (!rc) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + + pr_err("(%s): consistent DMA mask error %d\n", + pci_name(pdev), rc); + } + } else { + (rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))); + if (rc) { + + pr_err("(%s): DMA mask error %d\n", + pci_name(pdev), rc); + goto err_out_regions; + } + } + + skdev = skd_construct(pdev); + if (skdev == NULL) + goto err_out_regions; + + skd_pci_info(skdev, pci_str); + pr_info("(%s): %s 64bit\n", skd_name(skdev), pci_str); + + pci_set_master(pdev); + rc = pci_enable_pcie_error_reporting(pdev); + if (rc) { + pr_err( + "(%s): bad enable of PCIe error reporting rc=%d\n", + skd_name(skdev), rc); + skdev->pcie_error_reporting_is_enabled = 0; + } else + skdev->pcie_error_reporting_is_enabled = 1; + + + pci_set_drvdata(pdev, skdev); + skdev->pdev = pdev; + skdev->disk->driverfs_dev = &pdev->dev; + + for (i = 0; i < SKD_MAX_BARS; i++) { + skdev->mem_phys[i] = pci_resource_start(pdev, i); + skdev->mem_size[i] = (u32)pci_resource_len(pdev, i); + skdev->mem_map[i] = ioremap(skdev->mem_phys[i], + skdev->mem_size[i]); + if (!skdev->mem_map[i]) { + pr_err("(%s): Unable to map adapter memory!\n", + skd_name(skdev)); + rc = -ENODEV; + goto err_out_iounmap; + } + DPRINTK(skdev, "mem_map=%p, phyd=%016llx, size=%d\n", + skdev->mem_map[i], + (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); + } + + rc = skd_acquire_irq(skdev); + if (rc) { + pr_err("(%s): interrupt resource error %d\n", + skd_name(skdev), rc); + goto err_out_iounmap; + } + + rc = skd_start_timer(skdev); + if (rc) + goto err_out_timer; + + init_waitqueue_head(&skdev->waitq); + + skd_start_device(skdev); + + rc = wait_event_interruptible_timeout(skdev->waitq, + (skdev->gendisk_on), + (SKD_START_WAIT_SECONDS * HZ)); + if (skdev->gendisk_on > 0) { + /* device came on-line after reset */ + skd_bdev_attach(skdev); + rc = 0; + } else { + /* we timed out, something is wrong with the device, + don't add the disk structure */ + pr_err( + "(%s): error: waiting for s1120 timed out %d!\n", + skd_name(skdev), rc); + /* in case of no error; we timeout with ENXIO */ + if (!rc) + rc = -ENXIO; + goto err_out_timer; + } + + +#ifdef SKD_VMK_POLL_HANDLER + if (skdev->irq_type == SKD_IRQ_MSIX) { + /* MSIX completion handler is being used for coredump */ + vmklnx_scsi_register_poll_handler(skdev->scsi_host, + skdev->msix_entries[5].vector, + skd_comp_q, skdev); + } else { + vmklnx_scsi_register_poll_handler(skdev->scsi_host, + skdev->pdev->irq, skd_isr, + skdev); + } +#endif /* SKD_VMK_POLL_HANDLER */ + + return rc; + +err_out_timer: + skd_stop_device(skdev); + skd_release_irq(skdev); + +err_out_iounmap: + for (i = 0; i < SKD_MAX_BARS; i++) + if (skdev->mem_map[i]) + iounmap(skdev->mem_map[i]); + + if (skdev->pcie_error_reporting_is_enabled) + pci_disable_pcie_error_reporting(pdev); + + skd_destruct(skdev); + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return rc; +} + +static void skd_pci_remove(struct pci_dev *pdev) +{ + int i; + struct skd_device *skdev; + + skdev = pci_get_drvdata(pdev); + if (!skdev) { + pr_err("%s: no device data for PCI\n", pci_name(pdev)); + return; + } + skd_stop_device(skdev); + skd_release_irq(skdev); + + for (i = 0; i < SKD_MAX_BARS; i++) + if (skdev->mem_map[i]) + iounmap((u32 *)skdev->mem_map[i]); + + if (skdev->pcie_error_reporting_is_enabled) + pci_disable_pcie_error_reporting(pdev); + + skd_destruct(skdev); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return; +} + +static int skd_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int i; + struct skd_device *skdev; + + skdev = pci_get_drvdata(pdev); + if (!skdev) { + pr_err("%s: no device data for PCI\n", pci_name(pdev)); + return -EIO; + } + + skd_stop_device(skdev); + + skd_release_irq(skdev); + + for (i = 0; i < SKD_MAX_BARS; i++) + if (skdev->mem_map[i]) + iounmap((u32 *)skdev->mem_map[i]); + + if (skdev->pcie_error_reporting_is_enabled) + pci_disable_pcie_error_reporting(pdev); + + pci_release_regions(pdev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int skd_pci_resume(struct pci_dev *pdev) +{ + int i; + int rc = 0; + struct skd_device *skdev; + + skdev = pci_get_drvdata(pdev); + if (!skdev) { + pr_err("%s: no device data for PCI\n", pci_name(pdev)); + return -1; + } + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (!rc) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + + pr_err("(%s): consistent DMA mask error %d\n", + pci_name(pdev), rc); + } + } else { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) { + + pr_err("(%s): DMA mask error %d\n", + pci_name(pdev), rc); + goto err_out_regions; + } + } + + pci_set_master(pdev); + rc = pci_enable_pcie_error_reporting(pdev); + if (rc) { + pr_err("(%s): bad enable of PCIe error reporting rc=%d\n", + skdev->name, rc); + skdev->pcie_error_reporting_is_enabled = 0; + } else + skdev->pcie_error_reporting_is_enabled = 1; + + for (i = 0; i < SKD_MAX_BARS; i++) { + + skdev->mem_phys[i] = pci_resource_start(pdev, i); + skdev->mem_size[i] = (u32)pci_resource_len(pdev, i); + skdev->mem_map[i] = ioremap(skdev->mem_phys[i], + skdev->mem_size[i]); + if (!skdev->mem_map[i]) { + pr_err("(%s): Unable to map adapter memory!\n", + skd_name(skdev)); + rc = -ENODEV; + goto err_out_iounmap; + } + DPRINTK(skdev, "mem_map=%p, phyd=%016llx, size=%d\n", + skdev->mem_map[i], + (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); + } + rc = skd_acquire_irq(skdev); + if (rc) { + + pr_err("(%s): interrupt resource error %d\n", + pci_name(pdev), rc); + goto err_out_iounmap; + } + + rc = skd_start_timer(skdev); + if (rc) + goto err_out_timer; + + init_waitqueue_head(&skdev->waitq); + + skd_start_device(skdev); + + return rc; + +err_out_timer: + skd_stop_device(skdev); + skd_release_irq(skdev); + +err_out_iounmap: + for (i = 0; i < SKD_MAX_BARS; i++) + if (skdev->mem_map[i]) + iounmap(skdev->mem_map[i]); + + if (skdev->pcie_error_reporting_is_enabled) + pci_disable_pcie_error_reporting(pdev); + +err_out_regions: + pci_release_regions(pdev); + +err_out: + pci_disable_device(pdev); + return rc; +} + +static void skd_pci_shutdown(struct pci_dev *pdev) +{ + struct skd_device *skdev; + + pr_err("skd_pci_shutdown called\n"); + + skdev = pci_get_drvdata(pdev); + if (!skdev) { + pr_err("%s: no device data for PCI\n", pci_name(pdev)); + return; + } + + pr_err("%s: calling stop\n", skd_name(skdev)); + skd_stop_device(skdev); +} + +static struct pci_driver skd_driver = { + .name = DRV_NAME, + .id_table = skd_pci_tbl, + .probe = skd_pci_probe, + .remove = skd_pci_remove, + .suspend = skd_pci_suspend, + .resume = skd_pci_resume, + .shutdown = skd_pci_shutdown, +}; + +/* + ***************************************************************************** + * LOGGING SUPPORT + ***************************************************************************** + */ + +static const char *skd_name(struct skd_device *skdev) +{ + memset(skdev->id_str, 0, sizeof(skdev->id_str)); + + if (skdev->inquiry_is_valid) + snprintf(skdev->id_str, sizeof(skdev->id_str), "%s:%s:[%s]", + skdev->name, skdev->inq_serial_num, + pci_name(skdev->pdev)); + else + snprintf(skdev->id_str, sizeof(skdev->id_str), "%s:??:[%s]", + skdev->name, pci_name(skdev->pdev)); + + return skdev->id_str; +} + +const char *skd_drive_state_to_str(int state) +{ + switch (state) { + case FIT_SR_DRIVE_OFFLINE: + return "OFFLINE"; + case FIT_SR_DRIVE_INIT: + return "INIT"; + case FIT_SR_DRIVE_ONLINE: + return "ONLINE"; + case FIT_SR_DRIVE_BUSY: + return "BUSY"; + case FIT_SR_DRIVE_FAULT: + return "FAULT"; + case FIT_SR_DRIVE_DEGRADED: + return "DEGRADED"; + case FIT_SR_PCIE_LINK_DOWN: + return "INK_DOWN"; + case FIT_SR_DRIVE_SOFT_RESET: + return "SOFT_RESET"; + case FIT_SR_DRIVE_NEED_FW_DOWNLOAD: + return "NEED_FW"; + case FIT_SR_DRIVE_INIT_FAULT: + return "INIT_FAULT"; + case FIT_SR_DRIVE_BUSY_SANITIZE: + return "BUSY_SANITIZE"; + case FIT_SR_DRIVE_BUSY_ERASE: + return "BUSY_ERASE"; + case FIT_SR_DRIVE_FW_BOOTING: + return "FW_BOOTING"; + default: + return "???"; + } +} + +const char *skd_skdev_state_to_str(enum skd_drvr_state state) +{ + switch (state) { + case SKD_DRVR_STATE_LOAD: + return "LOAD"; + case SKD_DRVR_STATE_IDLE: + return "IDLE"; + case SKD_DRVR_STATE_BUSY: + return "BUSY"; + case SKD_DRVR_STATE_STARTING: + return "STARTING"; + case SKD_DRVR_STATE_ONLINE: + return "ONLINE"; + case SKD_DRVR_STATE_PAUSING: + return "PAUSING"; + case SKD_DRVR_STATE_PAUSED: + return "PAUSED"; + case SKD_DRVR_STATE_DRAINING_TIMEOUT: + return "DRAINING_TIMEOUT"; + case SKD_DRVR_STATE_RESTARTING: + return "RESTARTING"; + case SKD_DRVR_STATE_RESUMING: + return "RESUMING"; + case SKD_DRVR_STATE_STOPPING: + return "STOPPING"; + case SKD_DRVR_STATE_SYNCING: + return "SYNCING"; + case SKD_DRVR_STATE_FAULT: + return "FAULT"; + case SKD_DRVR_STATE_DISAPPEARED: + return "DISAPPEARED"; + case SKD_DRVR_STATE_BUSY_ERASE: + return "BUSY_ERASE"; + case SKD_DRVR_STATE_BUSY_SANITIZE: + return "BUSY_SANITIZE"; + case SKD_DRVR_STATE_BUSY_IMMINENT: + return "BUSY_IMMINENT"; + case SKD_DRVR_STATE_WAIT_BOOT: + return "WAIT_BOOT"; + + default: + return "???"; + } +} + +const char *skd_skmsg_state_to_str(enum skd_fit_msg_state state) +{ + switch (state) { + case SKD_MSG_STATE_IDLE: + return "IDLE"; + case SKD_MSG_STATE_BUSY: + return "BUSY"; + default: + return "???"; + } +} + +const char *skd_skreq_state_to_str(enum skd_req_state state) +{ + switch (state) { + case SKD_REQ_STATE_IDLE: + return "IDLE"; + case SKD_REQ_STATE_SETUP: + return "SETUP"; + case SKD_REQ_STATE_BUSY: + return "BUSY"; + case SKD_REQ_STATE_COMPLETED: + return "COMPLETED"; + case SKD_REQ_STATE_TIMEOUT: + return "TIMEOUT"; + case SKD_REQ_STATE_ABORTED: + return "ABORTED"; + default: + return "???"; + } +} + +static void skd_log_skdev(struct skd_device *skdev, const char *event) +{ + DPRINTK(skdev, "(%s) skdev=%p event='%s'\n", skdev->name, skdev, event); + DPRINTK(skdev, " drive_state=%s(%d) driver_state=%s(%d)\n", + skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, + skd_skdev_state_to_str(skdev->state), skdev->state); + DPRINTK(skdev, " busy=%d limit=%d dev=%d lowat=%d\n", + skdev->in_flight, skdev->cur_max_queue_depth, + skdev->dev_max_queue_depth, skdev->queue_low_water_mark); + DPRINTK(skdev, " timestamp=0x%x cycle=%d cycle_ix=%d\n", + skdev->timeout_stamp, skdev->skcomp_cycle, skdev->skcomp_ix); +} + +static void skd_log_skmsg(struct skd_device *skdev, + struct skd_fitmsg_context *skmsg, const char *event) +{ + DPRINTK(skdev, "(%s) skmsg=%p event='%s'\n", skdev->name, skmsg, event); + DPRINTK(skdev, " state=%s(%d) id=0x%04x length=%d\n", + skd_skmsg_state_to_str(skmsg->state), skmsg->state, + skmsg->id, skmsg->length); +} + +static void skd_log_skreq(struct skd_device *skdev, + struct skd_request_context *skreq, const char *event) +{ + DPRINTK(skdev, "(%s) skreq=%p event='%s'\n", skdev->name, skreq, event); + DPRINTK(skdev, " state=%s(%d) id=0x%04x fitmsg=0x%04x\n", + skd_skreq_state_to_str(skreq->state), skreq->state, + skreq->id, skreq->fitmsg_id); + DPRINTK(skdev, " timo=0x%x sg_dir=%d n_sg=%d\n", + skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg); + + if (!skd_bio) { + if (skreq->req != NULL) { + struct request *req = skreq->req; + u32 lba = (u32)blk_rq_pos(req); + u32 count = blk_rq_sectors(req); + + DPRINTK(skdev, + " req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + req, lba, lba, count, count, + (int)rq_data_dir(req)); + } else + DPRINTK(skdev, " req=NULL\n"); + } else { + if (skreq->bio != NULL) { + struct bio *bio = skreq->bio; + u32 lba = (u32)bio->bi_sector; + u32 count = bio_sectors(bio); + + DPRINTK(skdev, + " bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + bio, lba, lba, count, count, + (int)bio_data_dir(bio)); + } else + DPRINTK(skdev, " req=NULL\n"); + } +} + +/* + ***************************************************************************** + * MODULE GLUE + ***************************************************************************** + */ + +static int __init skd_init(void) +{ + int rc = 0; + + pr_info(PFX " v%s-b%s loaded\n", DRV_VERSION, DRV_BUILD_ID); + + switch (skd_isr_type) { + case SKD_IRQ_LEGACY: + case SKD_IRQ_MSI: + case SKD_IRQ_MSIX: + break; + default: + pr_info("skd_isr_type %d invalid, re-set to %d\n", + skd_isr_type, SKD_IRQ_DEFAULT); + skd_isr_type = SKD_IRQ_DEFAULT; + } + + skd_flush_slab = kmem_cache_create(SKD_FLUSH_JOB, + sizeof(struct skd_flush_cmd), + 0, 0, NULL); + + if (!skd_flush_slab) { + pr_err("failed to allocated flush slab.\n"); + return -ENOMEM; + } + + if (skd_max_queue_depth < 1 + || skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { + pr_info( + "skd_max_queue_depth %d invalid, re-set to %d\n", + skd_max_queue_depth, SKD_MAX_QUEUE_DEPTH_DEFAULT); + skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; + } + + if (skd_max_req_per_msg < 1 || skd_max_req_per_msg > 14) { + pr_info( + "skd_max_req_per_msg %d invalid, re-set to %d\n", + skd_max_req_per_msg, SKD_MAX_REQ_PER_MSG_DEFAULT); + skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; + } + + if (skd_sgs_per_request < 1 || skd_sgs_per_request > 4096) { + pr_info( + "skd_sg_per_request %d invalid, re-set to %d\n", + skd_sgs_per_request, SKD_N_SG_PER_REQ_DEFAULT); + skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; + } + + if (skd_dbg_level < 0 || skd_dbg_level > 2) { + pr_info("skd_dbg_level %d invalid, re-set to %d\n", + skd_dbg_level, 0); + skd_dbg_level = 0; + } + + if (skd_isr_comp_limit < 0) { + pr_info("skd_isr_comp_limit %d invalid, set to %d\n", + skd_isr_comp_limit, 0); + skd_isr_comp_limit = 0; + } + + if (skd_max_pass_thru < 1 || skd_max_pass_thru > 50) { + pr_info("skd_max_pass_thru %d invalid, re-set to %d\n", + skd_max_pass_thru, SKD_N_SPECIAL_CONTEXT); + skd_max_pass_thru = SKD_N_SPECIAL_CONTEXT; + } + + /* Obtain major device number. */ + rc = register_blkdev(0, DRV_NAME); + if (rc < 0) + return rc; + + skd_major = rc; + + return pci_register_driver(&skd_driver); + +} + +static void __exit skd_exit(void) +{ + pr_info(PFX " v%s-b%s unloading\n", DRV_VERSION, DRV_BUILD_ID); + + unregister_blkdev(skd_major, DRV_NAME); + pci_unregister_driver(&skd_driver); + + kmem_cache_destroy(skd_flush_slab); +} + +static int +skd_flush_cmd_enqueue(struct skd_device *skdev, void *cmd) +{ + struct skd_flush_cmd *item; + + item = kmem_cache_zalloc(skd_flush_slab, GFP_ATOMIC); + if (!item) { + pr_err("skd_flush_cmd_enqueue: Failed to allocated item.\n"); + return -ENOMEM; + } + + item->cmd = cmd; + list_add_tail(&item->flist, &skdev->flush_list); + return 0; +} + +static void * +skd_flush_cmd_dequeue(struct skd_device *skdev) +{ + void *cmd; + struct skd_flush_cmd *item; + + item = list_entry(skdev->flush_list.next, struct skd_flush_cmd, flist); + list_del_init(&item->flist); + cmd = item->cmd; + kmem_cache_free(skd_flush_slab, item); + return cmd; +} + +module_init(skd_init); +module_exit(skd_exit); diff --git a/drivers/block/skd_s1120.h b/drivers/block/skd_s1120.h new file mode 100644 index 000000000000..bf01941cdd62 --- /dev/null +++ b/drivers/block/skd_s1120.h @@ -0,0 +1,354 @@ +/* Copyright 2012 STEC, Inc. + * + * This file is licensed under the terms of the 3-clause + * BSD License (http://opensource.org/licenses/BSD-3-Clause) + * or the GNU GPL-2.0 (http://www.gnu.org/licenses/gpl-2.0.html), + * at your option. Both licenses are also available in the LICENSE file + * distributed with this project. This file may not be copied, modified, + * or distributed except in accordance with those terms. + */ + + +#ifndef SKD_S1120_H +#define SKD_S1120_H + +#pragma pack(push, s1120_h, 1) + +/* + * Q-channel, 64-bit r/w + */ +#define FIT_Q_COMMAND 0x400u +#define FIT_QCMD_QID_MASK (0x3 << 1) +#define FIT_QCMD_QID0 (0x0 << 1) +#define FIT_QCMD_QID_NORMAL FIT_QCMD_QID0 +#ifndef SKD_OMIT_FROM_SRC_DIST +#define FIT_QCMD_QID1 (0x1 << 1) +#define FIT_QCMD_QID2 (0x2 << 1) +#define FIT_QCMD_QID3 (0x3 << 1) +#endif /* SKD_OMIT_FROM_SRC_DIST */ +#define FIT_QCMD_FLUSH_QUEUE (0ull) /* add QID */ +#define FIT_QCMD_MSGSIZE_MASK (0x3 << 4) +#define FIT_QCMD_MSGSIZE_64 (0x0 << 4) +#define FIT_QCMD_MSGSIZE_128 (0x1 << 4) +#define FIT_QCMD_MSGSIZE_256 (0x2 << 4) +#define FIT_QCMD_MSGSIZE_512 (0x3 << 4) +#define FIT_QCMD_BASE_ADDRESS_MASK (0xFFFFFFFFFFFFFFC0ull) + + +/* + * Control, 32-bit r/w + */ +#define FIT_CONTROL 0x500u +#ifndef SKD_OMIT_FROM_SRC_DIST +#define FIT_CR_HARD_RESET (1u << 0u) +#endif /* SKD_OMIT_FROM_SRC_DIST */ +#define FIT_CR_SOFT_RESET (1u << 1u) +#ifndef SKD_OMIT_FROM_SRC_DIST +#define FIT_CR_DIS_TIMESTAMPS (1u << 6u) +#endif /* SKD_OMIT_FROM_SRC_DIST */ +#define FIT_CR_ENABLE_INTERRUPTS (1u << 7u) + +/* + * Status, 32-bit, r/o + */ +#define FIT_STATUS 0x510u +#define FIT_SR_DRIVE_STATE_MASK 0x000000FFu +#ifndef SKD_OMIT_FROM_SRC_DIST +#define FIT_SR_SIGNATURE (0xFF << 8) +#define FIT_SR_PIO_DMA (1 << 16) +#endif /* SKD_OMIT_FROM_SRC_DIST */ +#define FIT_SR_DRIVE_OFFLINE 0x00 +#define FIT_SR_DRIVE_INIT 0x01 +/* #define FIT_SR_DRIVE_READY 0x02 */ +#define FIT_SR_DRIVE_ONLINE 0x03 +#define FIT_SR_DRIVE_BUSY 0x04 +#define FIT_SR_DRIVE_FAULT 0x05 +#define FIT_SR_DRIVE_DEGRADED 0x06 +#define FIT_SR_PCIE_LINK_DOWN 0x07 +#define FIT_SR_DRIVE_SOFT_RESET 0x08 +#define FIT_SR_DRIVE_INIT_FAULT 0x09 +#define FIT_SR_DRIVE_BUSY_SANITIZE 0x0A +#define FIT_SR_DRIVE_BUSY_ERASE 0x0B +#define FIT_SR_DRIVE_FW_BOOTING 0x0C +#define FIT_SR_DRIVE_NEED_FW_DOWNLOAD 0xFE +#define FIT_SR_DEVICE_MISSING 0xFF +#define FIT_SR__RESERVED 0xFFFFFF00u + +#ifndef SKD_OMIT_FROM_SRC_DIST +/* + * FIT_STATUS - Status register data definition + */ +#define FIT_SR_STATE_MASK (0xFF << 0) +#define FIT_SR_SIGNATURE (0xFF << 8) +#define FIT_SR_PIO_DMA (1 << 16) +#endif /* SKD_OMIT_FROM_SRC_DIST */ + + +/* + * Interrupt status, 32-bit r/w1c (w1c ==> write 1 to clear) + */ +#define FIT_INT_STATUS_HOST 0x520u +#define FIT_ISH_FW_STATE_CHANGE (1u << 0u) +#define FIT_ISH_COMPLETION_POSTED (1u << 1u) +#define FIT_ISH_MSG_FROM_DEV (1u << 2u) +#define FIT_ISH_UNDEFINED_3 (1u << 3u) +#define FIT_ISH_UNDEFINED_4 (1u << 4u) +#define FIT_ISH_Q0_FULL (1u << 5u) +#define FIT_ISH_Q1_FULL (1u << 6u) +#define FIT_ISH_Q2_FULL (1u << 7u) +#define FIT_ISH_Q3_FULL (1u << 8u) +#define FIT_ISH_QCMD_FIFO_OVERRUN (1u << 9u) +#define FIT_ISH_BAD_EXP_ROM_READ (1u << 10u) + + +#define FIT_INT_DEF_MASK \ + (FIT_ISH_FW_STATE_CHANGE | \ + FIT_ISH_COMPLETION_POSTED | \ + FIT_ISH_MSG_FROM_DEV | \ + FIT_ISH_Q0_FULL | \ + FIT_ISH_Q1_FULL | \ + FIT_ISH_Q2_FULL | \ + FIT_ISH_Q3_FULL | \ + FIT_ISH_QCMD_FIFO_OVERRUN | \ + FIT_ISH_BAD_EXP_ROM_READ) + +#define FIT_INT_QUEUE_FULL \ + (FIT_ISH_Q0_FULL | \ + FIT_ISH_Q1_FULL | \ + FIT_ISH_Q2_FULL | \ + FIT_ISH_Q3_FULL) + + +#define MSI_MSG_NWL_ERROR_0 0x00000000 +#define MSI_MSG_NWL_ERROR_1 0x00000001 +#define MSI_MSG_NWL_ERROR_2 0x00000002 +#define MSI_MSG_NWL_ERROR_3 0x00000003 +#define MSI_MSG_STATE_CHANGE 0x00000004 +#define MSI_MSG_COMPLETION_POSTED 0x00000005 +#define MSI_MSG_MSG_FROM_DEV 0x00000006 +#define MSI_MSG_RESERVED_0 0x00000007 +#define MSI_MSG_RESERVED_1 0x00000008 +#define MSI_MSG_QUEUE_0_FULL 0x00000009 +#define MSI_MSG_QUEUE_1_FULL 0x0000000A +#define MSI_MSG_QUEUE_2_FULL 0x0000000B +#define MSI_MSG_QUEUE_3_FULL 0x0000000C + + + +#define FIT_INT_RESERVED_MASK \ + (FIT_ISH_UNDEFINED_3 | \ + FIT_ISH_UNDEFINED_4) +/* + * Interrupt mask, 32-bit r/w + * Bit definitions are the same as FIT_INT_STATUS_HOST + */ +#define FIT_INT_MASK_HOST 0x528u + + +/* + * Message to device, 32-bit r/w + */ +#define FIT_MSG_TO_DEVICE 0x540u + +/* + * Message from device, 32-bit, r/o + */ +#define FIT_MSG_FROM_DEVICE 0x548u + + +/* + * 32-bit messages to/from device, composition/extraction macros + */ +#define FIT_MXD_CONS(TYPE, PARAM, DATA) \ + ((((TYPE) & 0xFFu) << 24u) | \ + (((PARAM) & 0xFFu) << 16u) | \ + (((DATA) & 0xFFFFu) << 0u)) +#define FIT_MXD_TYPE(MXD) (((MXD) >> 24u) & 0xFFu) +#define FIT_MXD_PARAM(MXD) (((MXD) >> 16u) & 0xFFu) +#define FIT_MXD_DATA(MXD) (((MXD) >> 0u) & 0xFFFFu) + + +/* + * Types of messages to/from device + */ +#define FIT_MTD_FITFW_INIT 0x01u +#define FIT_MTD_GET_CMDQ_DEPTH 0x02u +#define FIT_MTD_SET_COMPQ_DEPTH 0x03u +#define FIT_MTD_SET_COMPQ_ADDR 0x04u +#define FIT_MTD_ARM_QUEUE 0x05u +#define FIT_MTD_CMD_LOG_HOST_ID 0x07u +#define FIT_MTD_CMD_LOG_TIME_STAMP_LO 0x08u +#define FIT_MTD_CMD_LOG_TIME_STAMP_HI 0x09u +#define FIT_MFD_SMART_EXCEEDED 0x10u +#define FIT_MFD_POWER_DOWN 0x11u +#define FIT_MFD_OFFLINE 0x12u +#define FIT_MFD_ONLINE 0x13u +#define FIT_MFD_FW_RESTARTING 0x14u +#define FIT_MFD_PM_ACTIVE 0x15u +#define FIT_MFD_PM_STANDBY 0x16u +#define FIT_MFD_PM_SLEEP 0x17u +#define FIT_MFD_CMD_PROGRESS 0x18u + +#ifndef SKD_OMIT_FROM_SRC_DIST +#define FIT_MTD_DEBUG 0xFEu +#define FIT_MFD_DEBUG 0xFFu +#endif /* SKD_OMIT_FROM_SRC_DIST */ + +#define FIT_MFD_MASK (0xFFu) +#define FIT_MFD_DATA_MASK (0xFFu) +#define FIT_MFD_MSG(x) (((x) >> 24) & FIT_MFD_MASK) +#define FIT_MFD_DATA(x) ((x) & FIT_MFD_MASK) + + +/* + * Extra arg to FIT_MSG_TO_DEVICE, 64-bit r/w + * Used to set completion queue address (FIT_MTD_SET_COMPQ_ADDR) + * (was Response buffer in docs) + */ +#define FIT_MSG_TO_DEVICE_ARG 0x580u + +/* + * Hardware (ASIC) version, 32-bit r/o + */ +#define FIT_HW_VERSION 0x588u + +/* + * Scatter/gather list descriptor. + * 32-bytes and must be aligned on a 32-byte boundary. + * All fields are in little endian order. + */ +struct fit_sg_descriptor { + uint32_t control; + uint32_t byte_count; + uint64_t host_side_addr; + uint64_t dev_side_addr; + uint64_t next_desc_ptr; +}; + +#define FIT_SGD_CONTROL_NOT_LAST 0x000u +#define FIT_SGD_CONTROL_LAST 0x40Eu + +/* + * Header at the beginning of a FIT message. The header + * is followed by SSDI requests each 64 bytes. + * A FIT message can be up to 512 bytes long and must start + * on a 64-byte boundary. + */ +struct fit_msg_hdr { + uint8_t protocol_id; + uint8_t num_protocol_cmds_coalesced; + uint8_t _reserved[62]; +}; + +#define FIT_PROTOCOL_ID_FIT 1 +#define FIT_PROTOCOL_ID_SSDI 2 +#define FIT_PROTOCOL_ID_SOFIT 3 + + +#define FIT_PROTOCOL_MINOR_VER(mtd_val) ((mtd_val >> 16) & 0xF) +#define FIT_PROTOCOL_MAJOR_VER(mtd_val) ((mtd_val >> 20) & 0xF) + +#ifndef SKD_OMIT_FROM_SRC_DIST +/* + * Format of a completion entry. The completion queue is circular + * and must have at least as many entries as the maximum number + * of commands that may be issued to the device. + * + * There are no head/tail pointers. The cycle value is used to + * infer the presence of new completion records. + * Initially the cycle in all entries is 0, the index is 0, and + * the cycle value to expect is 1. When completions are added + * their cycle values are set to 1. When the index wraps the + * cycle value to expect is incremented. + * + * Command_context is opaque and taken verbatim from the SSDI command. + * All other fields are big endian. + */ +#endif /* SKD_OMIT_FROM_SRC_DIST */ +#define FIT_PROTOCOL_VERSION_0 0 + +/* + * Protocol major version 1 completion entry. + * The major protocol version is found in bits + * 20-23 of the FIT_MTD_FITFW_INIT response. + */ +struct fit_completion_entry_v1 { + uint32_t num_returned_bytes; + uint16_t tag; + uint8_t status; /* SCSI status */ + uint8_t cycle; +}; +#define FIT_PROTOCOL_VERSION_1 1 +#define FIT_PROTOCOL_VERSION_CURRENT FIT_PROTOCOL_VERSION_1 + +struct fit_comp_error_info { + uint8_t type:7; /* 00: Bits0-6 indicates the type of sense data. */ + uint8_t valid:1; /* 00: Bit 7 := 1 ==> info field is valid. */ + uint8_t reserved0; /* 01: Obsolete field */ + uint8_t key:4; /* 02: Bits0-3 indicate the sense key. */ + uint8_t reserved2:1; /* 02: Reserved bit. */ + uint8_t bad_length:1; /* 02: Incorrect Length Indicator */ + uint8_t end_medium:1; /* 02: End of Medium */ + uint8_t file_mark:1; /* 02: Filemark */ + uint8_t info[4]; /* 03: */ + uint8_t reserved1; /* 07: Additional Sense Length */ + uint8_t cmd_spec[4]; /* 08: Command Specific Information */ + uint8_t code; /* 0C: Additional Sense Code */ + uint8_t qual; /* 0D: Additional Sense Code Qualifier */ + uint8_t fruc; /* 0E: Field Replaceable Unit Code */ + uint8_t sks_high:7; /* 0F: Sense Key Specific (MSB) */ + uint8_t sks_valid:1; /* 0F: Sense Key Specific Valid */ + uint16_t sks_low; /* 10: Sense Key Specific (LSW) */ + uint16_t reserved3; /* 12: Part of additional sense bytes (unused) */ + uint16_t uec; /* 14: Additional Sense Bytes */ + uint64_t per; /* 16: Additional Sense Bytes */ + uint8_t reserved4[2]; /* 1E: Additional Sense Bytes (unused) */ +}; + + +/* Task management constants */ +#define SOFT_TASK_SIMPLE 0x00 +#define SOFT_TASK_HEAD_OF_QUEUE 0x01 +#define SOFT_TASK_ORDERED 0x02 + + +/* Version zero has the last 32 bits reserved, + * Version one has the last 32 bits sg_list_len_bytes; + */ +struct skd_command_header { + uint64_t sg_list_dma_address; + uint16_t tag; + uint8_t attribute; + uint8_t add_cdb_len; /* In 32 bit words */ + uint32_t sg_list_len_bytes; +}; + +struct skd_scsi_request { + struct skd_command_header hdr; + unsigned char cdb[16]; +/* unsigned char _reserved[16]; */ +}; + +struct driver_inquiry_data { + uint8_t peripheral_device_type:5; + uint8_t qualifier:3; + uint8_t page_code; + uint16_t page_length; + uint16_t pcie_bus_number; + uint8_t pcie_device_number; + uint8_t pcie_function_number; + uint8_t pcie_link_speed; + uint8_t pcie_link_lanes; + uint16_t pcie_vendor_id; + uint16_t pcie_device_id; + uint16_t pcie_subsystem_vendor_id; + uint16_t pcie_subsystem_device_id; + uint8_t reserved1[2]; + uint8_t reserved2[3]; + uint8_t driver_version_length; + uint8_t driver_version[0x14]; +}; + +#pragma pack(pop, s1120_h) + +#endif /* SKD_S1120_H */ -- cgit v1.2.3 From 7badfb1c34f85e2b68252e4596d96e9b76f2b0ac Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 17 Oct 2013 16:38:30 -0600 Subject: block: disable cpqarray in Kconfig Mike writes: "cpqarray hasn't been used in over 12 years. It's doubtful that anyone still uses the board. It's time the driver was removed from the mainline kernel. The only updates these days are minor and mostly done by people outside of HP." If nobody yells, we'll remove it from the kernel tree completely for 3.15. Signed-off-by: Jens Axboe --- drivers/block/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 555aed0b50dd..f616109a57a6 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -107,7 +107,7 @@ source "drivers/block/mtip32xx/Kconfig" config BLK_CPQ_DA tristate "Compaq SMART2 support" - depends on PCI && VIRT_TO_BUS + depends on PCI && VIRT_TO_BUS && 0 help This is the driver for Compaq Smart Array controllers. Everyone using these boards should say Y here. See the file -- cgit v1.2.3 From 69babf05cbe909a9a520b39772655f88b407f257 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Oct 2013 10:59:15 +0200 Subject: drbd: fix NULL pointer deref in module init error path If we want to iterate over the (as of yet still empty) list in the cleanup path, we need to initialize the list before the first goto fail. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_main.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 55635edf563b..9e3818b1bc83 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2750,13 +2750,6 @@ int __init drbd_init(void) return err; } - err = drbd_genl_register(); - if (err) { - printk(KERN_ERR "drbd: unable to register generic netlink family\n"); - goto fail; - } - - register_reboot_notifier(&drbd_notifier); /* @@ -2767,6 +2760,15 @@ int __init drbd_init(void) drbd_proc = NULL; /* play safe for drbd_cleanup */ idr_init(&minors); + rwlock_init(&global_state_lock); + INIT_LIST_HEAD(&drbd_tconns); + + err = drbd_genl_register(); + if (err) { + printk(KERN_ERR "drbd: unable to register generic netlink family\n"); + goto fail; + } + err = drbd_create_mempools(); if (err) goto fail; @@ -2778,9 +2780,6 @@ int __init drbd_init(void) goto fail; } - rwlock_init(&global_state_lock); - INIT_LIST_HEAD(&drbd_tconns); - retry.wq = create_singlethread_workqueue("drbd-reissue"); if (!retry.wq) { printk(KERN_ERR "drbd: unable to create retry workqueue\n"); -- cgit v1.2.3 From b874d231e115af9b2c4a7ed1a4c5ae2db8a21aaf Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 23 Oct 2013 10:59:16 +0200 Subject: drbd: Fix an connection drop issue after enabling allow-two-primaries Since drbd-8.4.0 it is possible to change the allow-two-primaries network option while the connection is established. The sequence code used to partially order packets from the data socket with packets from the meta-data socket, still assued that the allow-two-primaries option is constant while the connection is established. I.e. On a node that has the RESOLVE_CONFLICTS bits set, after enabling allow-two-primaries, when receiving the next data packet it timed out while waiting for the necessary packets on the data socket to arrive (wait_for_and_update_peer_seq() function). Fixed that by always tracking the sequence number, but only waiting for it if allow-two-primaries is set. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_receiver.c | 39 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 23 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index cc29cd3bf78b..12c59eb3b127 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1890,29 +1890,11 @@ static u32 seq_max(u32 a, u32 b) return seq_greater(a, b) ? a : b; } -static bool need_peer_seq(struct drbd_conf *mdev) -{ - struct drbd_tconn *tconn = mdev->tconn; - int tp; - - /* - * We only need to keep track of the last packet_seq number of our peer - * if we are in dual-primary mode and we have the resolve-conflicts flag set; see - * handle_write_conflicts(). - */ - - rcu_read_lock(); - tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries; - rcu_read_unlock(); - - return tp && test_bit(RESOLVE_CONFLICTS, &tconn->flags); -} - static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) { unsigned int newest_peer_seq; - if (need_peer_seq(mdev)) { + if (test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)) { spin_lock(&mdev->peer_seq_lock); newest_peer_seq = seq_max(mdev->peer_seq, peer_seq); mdev->peer_seq = newest_peer_seq; @@ -1972,22 +1954,31 @@ static int wait_for_and_update_peer_seq(struct drbd_conf *mdev, const u32 peer_s { DEFINE_WAIT(wait); long timeout; - int ret; + int ret = 0, tp; - if (!need_peer_seq(mdev)) + if (!test_bit(RESOLVE_CONFLICTS, &mdev->tconn->flags)) return 0; spin_lock(&mdev->peer_seq_lock); for (;;) { if (!seq_greater(peer_seq - 1, mdev->peer_seq)) { mdev->peer_seq = seq_max(mdev->peer_seq, peer_seq); - ret = 0; break; } + if (signal_pending(current)) { ret = -ERESTARTSYS; break; } + + rcu_read_lock(); + tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries; + rcu_read_unlock(); + + if (!tp) + break; + + /* Only need to wait if two_primaries is enabled */ prepare_to_wait(&mdev->seq_wait, &wait, TASK_INTERRUPTIBLE); spin_unlock(&mdev->peer_seq_lock); rcu_read_lock(); @@ -2228,8 +2219,10 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi) } goto out_interrupted; } - } else + } else { + update_peer_seq(mdev, peer_seq); spin_lock_irq(&mdev->tconn->req_lock); + } list_add(&peer_req->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->tconn->req_lock); -- cgit v1.2.3 From 57737adc965e45fcb03662fe6f93f6efb19e2c0a Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 23 Oct 2013 10:59:17 +0200 Subject: drbd: Fix adding of new minors with freshly created meta data Online adding of new minors with freshly created meta data to an resource with an established connection failed, with a wrong state transition on one side on one side of the new minor. Freshly created meta-data has a la_size (last agreed size) of 0. When we online add such devices, the code wrongly got into the code path for resyncing new storage that was added while the disk was detached. Fixed that by making the GREW from ZERO a special case. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 3 ++- drivers/block/drbd/drbd_nl.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 2d7f608d181c..0e06f0c5dd1e 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1474,7 +1474,8 @@ enum determine_dev_size { DS_ERROR = -1, DS_UNCHANGED = 0, DS_SHRUNK = 1, - DS_GREW = 2 + DS_GREW = 2, + DS_GREW_FROM_ZERO = 3, }; extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags, struct resize_parms *) __must_hold(local); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 8cc1e640f485..37dad18ba153 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -955,7 +955,7 @@ drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct res } if (size > la_size_sect) - rv = DS_GREW; + rv = la_size_sect ? DS_GREW : DS_GREW_FROM_ZERO; if (size < la_size_sect) rv = DS_SHRUNK; -- cgit v1.2.3 From d2da5b0cb522c48f8e2f311e6e9b212535371b56 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Oct 2013 10:59:18 +0200 Subject: drbd: fix decoding of bitmap vli rle for device sizes > 64 TB Symptoms: disconnect after bitmap exchange due to bitmap overflow (e:49731075554) while decoding bm RLE packet In the decoding step of the variable length integer run length encoding there was potentially an uncatched bitshift by wordsize (variable >> 64). The result of which is "undefined" :( (only "sometimes" the result is the desired 0) Fix: don't do any bit shift magic for shift == 64, just assign. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_receiver.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 12c59eb3b127..6fa6673b36b3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4125,7 +4125,11 @@ recv_bm_rle_bits(struct drbd_conf *mdev, (unsigned int)bs.buf_len); return -EIO; } - look_ahead >>= bits; + /* if we consumed all 64 bits, assign 0; >> 64 is "undefined"; */ + if (likely(bits < 64)) + look_ahead >>= bits; + else + look_ahead = 0; have -= bits; bits = bitstream_get_bits(&bs, &tmp, 64 - have); -- cgit v1.2.3 From 35f47ef1a1f069cd2f346314fb8212bb49571eac Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 23 Oct 2013 10:59:19 +0200 Subject: drbd: avoid to shrink max_bio_size due to peer re-configuration For a long time, the receiving side has spread "too large" incoming requests over multiple bios. No need to shrink our max_bio_size (max_hw_sectors) if the peer is reconfigured to use a different storage. The problem manifests itself if we are not the top of the device stack (DRBD is used a LVM PV). A hardware reconfiguration on the peer may cause the supported max_bio_size to shrink, and the connection handshake would now unnecessarily shrink the max_bio_size on the active node. There is no way to notify upper layers that they have to "re-stack" their limits. So they won't notice at all, and may keep submitting bios that are suddenly considered "too large for device". We already check for compatibility and ignore changes on the peer, the code only was masked out unless we have a fully established connection. We just need to allow it a bit earlier during the handshake. Also consider max_hw_sectors in our merge bvec function, just in case. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_nl.c | 4 ++-- drivers/block/drbd/drbd_req.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 37dad18ba153..c706d50a8b06 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1132,9 +1132,9 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev) /* We may ignore peer limits if the peer is modern enough. Because new from 8.3.8 onwards the peer can use multiple BIOs for a single peer_request */ - if (mdev->state.conn >= C_CONNECTED) { + if (mdev->state.conn >= C_WF_REPORT_PARAMS) { if (mdev->tconn->agreed_pro_version < 94) - peer = min( mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET); + peer = min(mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET); /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */ else if (mdev->tconn->agreed_pro_version == 94) peer = DRBD_MAX_SIZE_H80_PACKET; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index c24379ffd4e3..fec7bef44994 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1306,6 +1306,7 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct int backing_limit; if (bio_size && get_ldev(mdev)) { + unsigned int max_hw_sectors = queue_max_hw_sectors(q); struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; if (b->merge_bvec_fn) { @@ -1313,6 +1314,8 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct limit = min(limit, backing_limit); } put_ldev(mdev); + if ((limit >> 9) > max_hw_sectors) + limit = max_hw_sectors << 9; } return limit; } -- cgit v1.2.3 From e35f38bf73b6c9ec9521d9deb94198a419692db5 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Fri, 18 Oct 2013 17:11:46 -0500 Subject: rsxx: Disallow discards from being unmapped. This patch fixes a bug in which discards were always calling pci_unmap_page. Discards should never call the pci_unmap_page function call because they are never mapped. This caused a race condition on PowerPC systems when issuing discards, writes, and reads all at the same time. The pci_map_page function would eventually map logical address 0 for a read or write. Discards are always assigned a DMA address of 0 because they are never mapped. So if pci_map_page mapped address 0 for a DMA and a discard was "unmapped" then the address would be freed and would cause an EEH event to occur when Hardware accesses the address. This was injected/uncovered in commit: b347f9cf0bc8d42ee95ba1d3837fd93045ab336b The pci_dma_mapping_error function declares -1 a DMA_ERROR not 0 like initially thought So before we would never unmap discards because they were considered NULL. This patch should fall on top of commit id: fc1967bb08a6184ed44ef990e1dd4389901b809c Also, the driver version is being up dated. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/dma.c | 27 ++++++++++++++++----------- drivers/block/rsxx/rsxx_priv.h | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 4103601ae675..fc88ba3e1bd2 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -223,12 +223,14 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card) /*----------------- RSXX DMA Handling -------------------*/ static void rsxx_free_dma(struct rsxx_dma_ctrl *ctrl, struct rsxx_dma *dma) { - if (!pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { - pci_unmap_page(ctrl->card->dev, dma->dma_addr, - get_dma_size(dma), - dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); + if (dma->cmd != HW_CMD_BLK_DISCARD) { + if (!pci_dma_mapping_error(ctrl->card->dev, dma->dma_addr)) { + pci_unmap_page(ctrl->card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + } } kmem_cache_free(rsxx_dma_pool, dma); @@ -1057,11 +1059,14 @@ int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card) else card->ctrl[i].stats.reads_issued--; - pci_unmap_page(card->dev, dma->dma_addr, - get_dma_size(dma), - dma->cmd == HW_CMD_BLK_WRITE ? - PCI_DMA_TODEVICE : - PCI_DMA_FROMDEVICE); + if (dma->cmd != HW_CMD_BLK_DISCARD) { + pci_unmap_page(card->dev, dma->dma_addr, + get_dma_size(dma), + dma->cmd == HW_CMD_BLK_WRITE ? + PCI_DMA_TODEVICE : + PCI_DMA_FROMDEVICE); + } + list_add_tail(&dma->list, &issued_dmas[i]); push_tracker(card->ctrl[i].trackers, j); cnt++; diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index 913740e53d31..23fa05630fef 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -52,7 +52,7 @@ struct proc_cmd; #define RS70_PCI_REV_SUPPORTED 4 #define DRIVER_NAME "rsxx" -#define DRIVER_VERSION "4.0.1.2498" +#define DRIVER_VERSION "4.0.2.2510" /* Block size is 4096 */ #define RSXX_HW_BLK_SHIFT 12 -- cgit v1.2.3 From 8c49a77ca451541938f90008f419fca965b76b72 Mon Sep 17 00:00:00 2001 From: Philip J Kelleher Date: Fri, 18 Oct 2013 17:12:35 -0500 Subject: rsxx: Fix possible kernel panic with invalid config. This patch fixes a possible Kernel Panic on driver load if the configuration on the card is messed up or not yet set. The driver could possible give a 32 bit unsigned all Fs to the kernel as the device's block size. Now we only write the block size to the kernel if the configuration from the card is valid. Also, driver version is being updated. Signed-off-by: Philip J Kelleher Signed-off-by: Jens Axboe --- drivers/block/rsxx/dev.c | 8 +++++--- drivers/block/rsxx/rsxx_priv.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index d7af441880be..2284f5d3a54a 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -295,13 +295,15 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card) return -ENOMEM; } - blk_size = card->config.data.block_size; + if (card->config_valid) { + blk_size = card->config.data.block_size; + blk_queue_dma_alignment(card->queue, blk_size - 1); + blk_queue_logical_block_size(card->queue, blk_size); + } blk_queue_make_request(card->queue, rsxx_make_request); blk_queue_bounce_limit(card->queue, BLK_BOUNCE_ANY); - blk_queue_dma_alignment(card->queue, blk_size - 1); blk_queue_max_hw_sectors(card->queue, blkdev_max_hw_sectors); - blk_queue_logical_block_size(card->queue, blk_size); blk_queue_physical_block_size(card->queue, RSXX_HW_BLK_SIZE); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, card->queue); diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h index 23fa05630fef..6bbc64d0f690 100644 --- a/drivers/block/rsxx/rsxx_priv.h +++ b/drivers/block/rsxx/rsxx_priv.h @@ -52,7 +52,7 @@ struct proc_cmd; #define RS70_PCI_REV_SUPPORTED 4 #define DRIVER_NAME "rsxx" -#define DRIVER_VERSION "4.0.2.2510" +#define DRIVER_VERSION "4.0.3.2516" /* Block size is 4096 */ #define RSXX_HW_BLK_SHIFT 12 -- cgit v1.2.3 From f721bb0dbd3fd37f16c49c97155f40f22496a970 Mon Sep 17 00:00:00 2001 From: Akhil Bhansali Date: Wed, 23 Oct 2013 13:00:08 +0100 Subject: skd: Fix checkpatch ERRORS and removed unused functions This patch fixes checkpatch.pl errors for assignment in if condition. It also removes unused readq / readl function calls. As Andrew had disabled the compilation of drivers for 32 bit, I have modified format specifiers in few VPRINTKs to avoid warnings during 64 bit compilation. Signed-off-by: Akhil Bhansali Reviewed-by: Ramprasad Chinthekindi Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 53 ++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 3110f68ecedd..308bf474dc39 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -420,14 +420,10 @@ static inline void skd_reg_write32(struct skd_device *skdev, u32 val, if (likely(skdev->dbg_level < 2)) { writel(val, skdev->mem_map[1] + offset); barrier(); - readl(skdev->mem_map[1] + offset); - barrier(); } else { barrier(); writel(val, skdev->mem_map[1] + offset); barrier(); - readl(skdev->mem_map[1] + offset); - barrier(); VPRINTK(skdev, "offset %x = %x\n", offset, val); } } @@ -438,14 +434,10 @@ static inline void skd_reg_write64(struct skd_device *skdev, u64 val, if (likely(skdev->dbg_level < 2)) { writeq(val, skdev->mem_map[1] + offset); barrier(); - readq(skdev->mem_map[1] + offset); - barrier(); } else { barrier(); writeq(val, skdev->mem_map[1] + offset); barrier(); - readq(skdev->mem_map[1] + offset); - barrier(); VPRINTK(skdev, "offset %x = %016llx\n", offset, val); } } @@ -1656,18 +1648,36 @@ static int skd_ioctl_sg_io(struct skd_device *skdev, fmode_t mode, goto out; } - if ((rc = skd_sg_io_get_and_check_args(skdev, &sksgio)) || - (rc = skd_sg_io_obtain_skspcl(skdev, &sksgio)) || - (rc = skd_sg_io_prep_buffering(skdev, &sksgio)) || - (rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_TO_DEV))) + rc = skd_sg_io_get_and_check_args(skdev, &sksgio); + if (rc) + goto out; + + rc = skd_sg_io_obtain_skspcl(skdev, &sksgio); + if (rc) + goto out; + + rc = skd_sg_io_prep_buffering(skdev, &sksgio); + if (rc) + goto out; + + rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_TO_DEV); + if (rc) goto out; - if ((rc = skd_sg_io_send_fitmsg(skdev, &sksgio)) || - (rc = skd_sg_io_await(skdev, &sksgio))) + rc = skd_sg_io_send_fitmsg(skdev, &sksgio); + if (rc) goto out; - if ((rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_FROM_DEV)) || - (rc = skd_sg_io_put_status(skdev, &sksgio))) + rc = skd_sg_io_await(skdev, &sksgio); + if (rc) + goto out; + + rc = skd_sg_io_copy_buffer(skdev, &sksgio, SG_DXFER_FROM_DEV); + if (rc) + goto out; + + rc = skd_sg_io_put_status(skdev, &sksgio); + if (rc) goto out; rc = 0; @@ -4556,11 +4566,10 @@ static int skd_cons_skmsg(struct skd_device *skdev) int rc = 0; u32 i; - VPRINTK(skdev, "skmsg_table kzalloc, struct %u, count %u total %lu\n", + VPRINTK(skdev, "skmsg_table kzalloc, struct %lu, count %u total %lu\n", sizeof(struct skd_fitmsg_context), skdev->num_fitmsg_context, - (unsigned long) sizeof(struct skd_fitmsg_context) * - skdev->num_fitmsg_context); + sizeof(struct skd_fitmsg_context) * skdev->num_fitmsg_context); skdev->skmsg_table = kzalloc(sizeof(struct skd_fitmsg_context) *skdev->num_fitmsg_context, GFP_KERNEL); @@ -4611,7 +4620,7 @@ static int skd_cons_skreq(struct skd_device *skdev) int rc = 0; u32 i; - VPRINTK(skdev, "skreq_table kzalloc, struct %u, count %u total %u\n", + VPRINTK(skdev, "skreq_table kzalloc, struct %lu, count %u total %lu\n", sizeof(struct skd_request_context), skdev->num_req_context, sizeof(struct skd_request_context) * skdev->num_req_context); @@ -4623,7 +4632,7 @@ static int skd_cons_skreq(struct skd_device *skdev) goto err_out; } - VPRINTK(skdev, "alloc sg_table sg_per_req %u scatlist %u total %u\n", + VPRINTK(skdev, "alloc sg_table sg_per_req %u scatlist %lu total %lu\n", skdev->sgs_per_request, sizeof(struct scatterlist), skdev->sgs_per_request * sizeof(struct scatterlist)); @@ -4668,7 +4677,7 @@ static int skd_cons_skspcl(struct skd_device *skdev) int rc = 0; u32 i, nbytes; - VPRINTK(skdev, "skspcl_table kzalloc, struct %u, count %u total %u\n", + VPRINTK(skdev, "skspcl_table kzalloc, struct %lu, count %u total %lu\n", sizeof(struct skd_special_context), skdev->n_special, sizeof(struct skd_special_context) * skdev->n_special); -- cgit v1.2.3 From 2e44b42718ac49a397324a360df4ecab617b3fe2 Mon Sep 17 00:00:00 2001 From: rchinthekindi Date: Thu, 24 Oct 2013 12:51:23 +0100 Subject: skd: Replaced custom debug PRINTKs with pr_debug Replaced DPRINTK() and VPRINTK() with pr_debug(). Signed-off-by: Ramprasad C Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 691 ++++++++++++++++++++++++++++------------------- 1 file changed, 407 insertions(+), 284 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 308bf474dc39..ab17bff6b4f9 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -68,14 +68,6 @@ enum { SKD_FLUSH_DATA_SECOND, }; -#define DPRINTK(skdev, fmt, args ...) \ - do { \ - if (unlikely((skdev)->dbg_level > 0)) { \ - pr_err("%s:%s:%d " fmt, (skdev)->name, \ - __func__, __LINE__, ## args); \ - } \ - } while (0) - #define SKD_ASSERT(expr) \ do { \ if (unlikely(!(expr))) { \ @@ -84,15 +76,6 @@ enum { } \ } while (0) -#define VPRINTK(skdev, fmt, args ...) \ - do { \ - if (unlikely((skdev)->dbg_level > 1)) { \ - pr_err("%s:%s:%d " fmt, (skdev)->name, \ - __func__, __LINE__, ## args); \ - } \ - } while (0) - - #define DRV_NAME "skd" #define DRV_VERSION "2.2.1" #define DRV_BUILD_ID "0260" @@ -408,7 +391,8 @@ static inline u32 skd_reg_read32(struct skd_device *skdev, u32 offset) barrier(); val = readl(skdev->mem_map[1] + offset); barrier(); - VPRINTK(skdev, "offset %x = %x\n", offset, val); + pr_debug("%s:%s:%d offset %x = %x\n", + skdev->name, __func__, __LINE__, offset, val); return val; } @@ -424,7 +408,8 @@ static inline void skd_reg_write32(struct skd_device *skdev, u32 val, barrier(); writel(val, skdev->mem_map[1] + offset); barrier(); - VPRINTK(skdev, "offset %x = %x\n", offset, val); + pr_debug("%s:%s:%d offset %x = %x\n", + skdev->name, __func__, __LINE__, offset, val); } } @@ -438,7 +423,8 @@ static inline void skd_reg_write64(struct skd_device *skdev, u64 val, barrier(); writeq(val, skdev->mem_map[1] + offset); barrier(); - VPRINTK(skdev, "offset %x = %016llx\n", offset, val); + pr_debug("%s:%s:%d offset %x = %016llx\n", + skdev->name, __func__, __LINE__, offset, val); } } @@ -764,15 +750,17 @@ static void skd_request_fn(struct request_queue *q) if (io_flags & REQ_FUA) fua++; - VPRINTK(skdev, - "new req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - req, lba, lba, count, count, data_dir); + pr_debug("%s:%s:%d new req=%p lba=%u(0x%x) " + "count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + req, lba, lba, count, count, data_dir); } else { if (!list_empty(&skdev->flush_list)) { /* Process data part of FLUSH request. */ bio = (struct bio *)skd_flush_cmd_dequeue(skdev); flush++; - VPRINTK(skdev, "processing FLUSH request with data.\n"); + pr_debug("%s:%s:%d processing FLUSH request with data.\n", + skdev->name, __func__, __LINE__); } else { /* peek at our bio queue */ bio = bio_list_peek(&skdev->bio_queue); @@ -787,9 +775,10 @@ static void skd_request_fn(struct request_queue *q) data_dir = bio_data_dir(bio); io_flags = bio->bi_rw; - VPRINTK(skdev, - "new bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - bio, lba, lba, count, count, data_dir); + pr_debug("%s:%s:%d new bio=%p lba=%u(0x%x) " + "count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + bio, lba, lba, count, count, data_dir); if (io_flags & REQ_FLUSH) flush++; @@ -805,15 +794,17 @@ static void skd_request_fn(struct request_queue *q) /* Are too many requets already in progress? */ if (skdev->in_flight >= skdev->cur_max_queue_depth) { - VPRINTK(skdev, "qdepth %d, limit %d\n", - skdev->in_flight, skdev->cur_max_queue_depth); + pr_debug("%s:%s:%d qdepth %d, limit %d\n", + skdev->name, __func__, __LINE__, + skdev->in_flight, skdev->cur_max_queue_depth); break; } /* Is a skd_request_context available? */ skreq = skdev->skreq_free_list; if (skreq == NULL) { - VPRINTK(skdev, "Out of req=%p\n", q); + pr_debug("%s:%s:%d Out of req=%p\n", + skdev->name, __func__, __LINE__, q); break; } SKD_ASSERT(skreq->state == SKD_REQ_STATE_IDLE); @@ -822,7 +813,8 @@ static void skd_request_fn(struct request_queue *q) /* Now we check to see if we can get a fit msg */ if (skmsg == NULL) { if (skdev->skmsg_free_list == NULL) { - VPRINTK(skdev, "Out of msg\n"); + pr_debug("%s:%s:%d Out of msg\n", + skdev->name, __func__, __LINE__); break; } } @@ -862,7 +854,9 @@ static void skd_request_fn(struct request_queue *q) /* Are there any FIT msg buffers available? */ skmsg = skdev->skmsg_free_list; if (skmsg == NULL) { - VPRINTK(skdev, "Out of msg skdev=%p\n", skdev); + pr_debug("%s:%s:%d Out of msg skdev=%p\n", + skdev->name, __func__, __LINE__, + skdev); break; } SKD_ASSERT(skmsg->state == SKD_MSG_STATE_IDLE); @@ -945,7 +939,8 @@ static void skd_request_fn(struct request_queue *q) * only resource that has been allocated but might * not be used is that the FIT msg could be empty. */ - DPRINTK(skdev, "error Out\n"); + pr_debug("%s:%s:%d error Out\n", + skdev->name, __func__, __LINE__); skd_end_request(skdev, skreq, error); continue; } @@ -970,8 +965,9 @@ skip_sg: timo_slot = skreq->timeout_stamp & SKD_TIMEOUT_SLOT_MASK; skdev->timeout_slot[timo_slot]++; skdev->in_flight++; - VPRINTK(skdev, "req=0x%x busy=%d\n", - skreq->id, skdev->in_flight); + pr_debug("%s:%s:%d req=0x%x busy=%d\n", + skdev->name, __func__, __LINE__, + skreq->id, skdev->in_flight); /* * If the FIT msg buffer is full send it. @@ -993,8 +989,9 @@ skip_sg: if (skmsg != NULL) { /* Bigger than just a FIT msg header? */ if (skmsg->length > sizeof(struct fit_msg_hdr)) { - VPRINTK(skdev, "sending msg=%p, len %d\n", - skmsg, skmsg->length); + pr_debug("%s:%s:%d sending msg=%p, len %d\n", + skdev->name, __func__, __LINE__, + skmsg, skmsg->length); skd_send_fitmsg(skdev, skmsg); } else { /* @@ -1027,7 +1024,8 @@ static void skd_end_request_blk(struct skd_device *skdev, if ((io_flags & REQ_DISCARD) && (skreq->discard_page == 1)) { - VPRINTK(skdev, "skd_end_request_blk, free the page!"); + pr_debug("%s:%s:%d skd_end_request_blk, free the page!", + skdev->name, __func__, __LINE__); free_page((unsigned long)req->buffer); req->buffer = NULL; } @@ -1041,7 +1039,8 @@ static void skd_end_request_blk(struct skd_device *skdev, pr_err("(%s): Error cmd=%s sect=%u count=%u id=0x%x\n", skd_name(skdev), cmd, lba, count, skreq->id); } else - VPRINTK(skdev, "id=0x%x error=%d\n", skreq->id, error); + pr_debug("%s:%s:%d id=0x%x error=%d\n", + skdev->name, __func__, __LINE__, skreq->id, error); __blk_end_request_all(skreq->req, error); } @@ -1093,14 +1092,16 @@ static int skd_preop_sg_list_blk(struct skd_device *skdev, skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; if (unlikely(skdev->dbg_level > 1)) { - VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", - skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + pr_debug("%s:%s:%d skreq=%x sksg_list=%p sksg_dma=%llx\n", + skdev->name, __func__, __LINE__, + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); for (i = 0; i < n_sg; i++) { struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; - VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " - "addr=0x%llx next=0x%llx\n", - i, sgd->byte_count, sgd->control, - sgd->host_side_addr, sgd->next_desc_ptr); + pr_debug("%s:%s:%d sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + skdev->name, __func__, __LINE__, + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); } } @@ -1132,7 +1133,8 @@ static void skd_end_request_bio(struct skd_device *skdev, if ((io_flags & REQ_DISCARD) && (skreq->discard_page == 1)) { - VPRINTK(skdev, "biomode: skd_end_request: freeing DISCARD page.\n"); + pr_debug("%s:%s:%d biomode: skd_end_request: freeing DISCARD page.\n", + skdev->name, __func__, __LINE__); free_page((unsigned long)page_address(bio->bi_io_vec->bv_page)); } @@ -1157,7 +1159,8 @@ static void skd_end_request_bio(struct skd_device *skdev, part_stat_unlock(); } - VPRINTK(skdev, "id=0x%x error=%d\n", skreq->id, error); + pr_debug("%s:%s:%d id=0x%x error=%d\n", + skdev->name, __func__, __LINE__, skreq->id, error); bio_endio(skreq->bio, error); } @@ -1229,14 +1232,16 @@ static int skd_preop_sg_list_bio(struct skd_device *skdev, } if (unlikely(skdev->dbg_level > 1)) { - VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", - skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + pr_debug("%s:%s:%d skreq=%x sksg_list=%p sksg_dma=%llx\n", + skdev->name, __func__, __LINE__, + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); for (i = 0; i < n_sg; i++) { struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; - VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " - "addr=0x%llx next=0x%llx\n", - i, sgd->byte_count, sgd->control, - sgd->host_side_addr, sgd->next_desc_ptr); + pr_debug("%s:%s:%d sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + skdev->name, __func__, __LINE__, + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); } } @@ -1391,8 +1396,9 @@ static void skd_timer_tick(ulong arg) /* Something is overdue */ overdue_timestamp = skdev->timeout_stamp - SKD_N_TIMEOUT_SLOT; - DPRINTK(skdev, "found %d timeouts, draining busy=%d\n", - skdev->timeout_slot[timo_slot], skdev->in_flight); + pr_debug("%s:%s:%d found %d timeouts, draining busy=%d\n", + skdev->name, __func__, __LINE__, + skdev->timeout_slot[timo_slot], skdev->in_flight); pr_err("(%s): Overdue IOs (%d), busy %d\n", skd_name(skdev), skdev->timeout_slot[timo_slot], skdev->in_flight); @@ -1415,8 +1421,9 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) case SKD_DRVR_STATE_LOAD: break; case SKD_DRVR_STATE_BUSY_SANITIZE: - VPRINTK(skdev, "drive busy sanitize[%x], driver[%x]\n", - skdev->drive_state, skdev->state); + pr_debug("%s:%s:%d drive busy sanitize[%x], driver[%x]\n", + skdev->name, __func__, __LINE__, + skdev->drive_state, skdev->state); /* If we've been in sanitize for 3 seconds, we figure we're not * going to get anymore completions, so recover requests now */ @@ -1430,14 +1437,16 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) case SKD_DRVR_STATE_BUSY: case SKD_DRVR_STATE_BUSY_IMMINENT: case SKD_DRVR_STATE_BUSY_ERASE: - VPRINTK(skdev, "busy[%x], countdown=%d\n", - skdev->state, skdev->timer_countdown); + pr_debug("%s:%s:%d busy[%x], countdown=%d\n", + skdev->name, __func__, __LINE__, + skdev->state, skdev->timer_countdown); if (skdev->timer_countdown > 0) { skdev->timer_countdown--; return; } - DPRINTK(skdev, "busy[%x], timedout=%d, restarting device.", - skdev->state, skdev->timer_countdown); + pr_debug("%s:%s:%d busy[%x], timedout=%d, restarting device.", + skdev->name, __func__, __LINE__, + skdev->state, skdev->timer_countdown); skd_restart_device(skdev); break; @@ -1470,15 +1479,17 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) break; case SKD_DRVR_STATE_DRAINING_TIMEOUT: - DPRINTK(skdev, - "draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n", - skdev->timo_slot, - skdev->timer_countdown, - skdev->in_flight, - skdev->timeout_slot[skdev->timo_slot]); + pr_debug("%s:%s:%d " + "draining busy [%d] tick[%d] qdb[%d] tmls[%d]\n", + skdev->name, __func__, __LINE__, + skdev->timo_slot, + skdev->timer_countdown, + skdev->in_flight, + skdev->timeout_slot[skdev->timo_slot]); /* if the slot has cleared we can let the I/O continue */ if (skdev->timeout_slot[skdev->timo_slot] == 0) { - DPRINTK(skdev, "Slot drained, starting queue.\n"); + pr_debug("%s:%s:%d Slot drained, starting queue.\n", + skdev->name, __func__, __LINE__); skdev->state = SKD_DRVR_STATE_ONLINE; skd_start_queue(skdev); return; @@ -1601,8 +1612,9 @@ static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode, struct skd_device *skdev = disk->private_data; void __user *p = (void *)arg; - DPRINTK(skdev, "%s: CMD[%s] ioctl mode 0x%x, cmd 0x%x arg %0lx\n", - disk->disk_name, current->comm, mode, cmd_in, arg); + pr_debug("%s:%s:%d %s: CMD[%s] ioctl mode 0x%x, cmd 0x%x arg %0lx\n", + skdev->name, __func__, __LINE__, + disk->disk_name, current->comm, mode, cmd_in, arg); if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1622,7 +1634,8 @@ static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode, break; } - DPRINTK(skdev, "%s: completion rc %d\n", disk->disk_name, rc); + pr_debug("%s:%s:%d %s: completion rc %d\n", + skdev->name, __func__, __LINE__, disk->disk_name, rc); return rc; } @@ -1643,7 +1656,8 @@ static int skd_ioctl_sg_io(struct skd_device *skdev, fmode_t mode, break; default: - DPRINTK(skdev, "drive not online\n"); + pr_debug("%s:%s:%d drive not online\n", + skdev->name, __func__, __LINE__); rc = -ENXIO; goto out; } @@ -1697,33 +1711,38 @@ static int skd_sg_io_get_and_check_args(struct skd_device *skdev, int i, acc; if (!access_ok(VERIFY_WRITE, sksgio->argp, sizeof(sg_io_hdr_t))) { - DPRINTK(skdev, "access sg failed %p\n", sksgio->argp); + pr_debug("%s:%s:%d access sg failed %p\n", + skdev->name, __func__, __LINE__, sksgio->argp); return -EFAULT; } if (__copy_from_user(sgp, sksgio->argp, sizeof(sg_io_hdr_t))) { - DPRINTK(skdev, "copy_from_user sg failed %p\n", sksgio->argp); + pr_debug("%s:%s:%d copy_from_user sg failed %p\n", + skdev->name, __func__, __LINE__, sksgio->argp); return -EFAULT; } if (sgp->interface_id != SG_INTERFACE_ID_ORIG) { - DPRINTK(skdev, "interface_id invalid 0x%x\n", - sgp->interface_id); + pr_debug("%s:%s:%d interface_id invalid 0x%x\n", + skdev->name, __func__, __LINE__, sgp->interface_id); return -EINVAL; } if (sgp->cmd_len > sizeof(sksgio->cdb)) { - DPRINTK(skdev, "cmd_len invalid %d\n", sgp->cmd_len); + pr_debug("%s:%s:%d cmd_len invalid %d\n", + skdev->name, __func__, __LINE__, sgp->cmd_len); return -EINVAL; } if (sgp->iovec_count > 256) { - DPRINTK(skdev, "iovec_count invalid %d\n", sgp->iovec_count); + pr_debug("%s:%s:%d iovec_count invalid %d\n", + skdev->name, __func__, __LINE__, sgp->iovec_count); return -EINVAL; } if (sgp->dxfer_len > (PAGE_SIZE * SKD_N_SG_PER_SPECIAL)) { - DPRINTK(skdev, "dxfer_len invalid %d\n", sgp->dxfer_len); + pr_debug("%s:%s:%d dxfer_len invalid %d\n", + skdev->name, __func__, __LINE__, sgp->dxfer_len); return -EINVAL; } @@ -1742,18 +1761,21 @@ static int skd_sg_io_get_and_check_args(struct skd_device *skdev, break; default: - DPRINTK(skdev, "dxfer_dir invalid %d\n", sgp->dxfer_direction); + pr_debug("%s:%s:%d dxfer_dir invalid %d\n", + skdev->name, __func__, __LINE__, sgp->dxfer_direction); return -EINVAL; } if (copy_from_user(sksgio->cdb, sgp->cmdp, sgp->cmd_len)) { - DPRINTK(skdev, "copy_from_user cmdp failed %p\n", sgp->cmdp); + pr_debug("%s:%s:%d copy_from_user cmdp failed %p\n", + skdev->name, __func__, __LINE__, sgp->cmdp); return -EFAULT; } if (sgp->mx_sb_len != 0) { if (!access_ok(VERIFY_WRITE, sgp->sbp, sgp->mx_sb_len)) { - DPRINTK(skdev, "access sbp failed %p\n", sgp->sbp); + pr_debug("%s:%s:%d access sbp failed %p\n", + skdev->name, __func__, __LINE__, sgp->sbp); return -EFAULT; } } @@ -1770,16 +1792,17 @@ static int skd_sg_io_get_and_check_args(struct skd_device *skdev, iov = kmalloc(nbytes, GFP_KERNEL); if (iov == NULL) { - DPRINTK(skdev, "alloc iovec failed %d\n", - sgp->iovec_count); + pr_debug("%s:%s:%d alloc iovec failed %d\n", + skdev->name, __func__, __LINE__, + sgp->iovec_count); return -ENOMEM; } sksgio->iov = iov; sksgio->iovcnt = sgp->iovec_count; if (copy_from_user(iov, sgp->dxferp, nbytes)) { - DPRINTK(skdev, "copy_from_user iovec failed %p\n", - sgp->dxferp); + pr_debug("%s:%s:%d copy_from_user iovec failed %p\n", + skdev->name, __func__, __LINE__, sgp->dxferp); return -EFAULT; } @@ -1807,8 +1830,9 @@ static int skd_sg_io_get_and_check_args(struct skd_device *skdev, struct sg_iovec *iov = sksgio->iov; for (i = 0; i < sksgio->iovcnt; i++, iov++) { if (!access_ok(acc, iov->iov_base, iov->iov_len)) { - DPRINTK(skdev, "access data failed %p/%d\n", - iov->iov_base, (int)iov->iov_len); + pr_debug("%s:%s:%d access data failed %p/%d\n", + skdev->name, __func__, __LINE__, + iov->iov_base, (int)iov->iov_len); return -EFAULT; } } @@ -1843,14 +1867,16 @@ static int skd_sg_io_obtain_skspcl(struct skd_device *skdev, break; } - DPRINTK(skdev, "blocking\n"); + pr_debug("%s:%s:%d blocking\n", + skdev->name, __func__, __LINE__); rc = wait_event_interruptible_timeout( skdev->waitq, (skdev->skspcl_free_list != NULL), msecs_to_jiffies(sksgio->sg.timeout)); - DPRINTK(skdev, "unblocking, rc=%d\n", rc); + pr_debug("%s:%s:%d unblocking, rc=%d\n", + skdev->name, __func__, __LINE__, rc); if (rc <= 0) { if (rc == 0) @@ -1927,15 +1953,17 @@ static int skd_skreq_prep_buffering(struct skd_device *skdev, if (unlikely(skdev->dbg_level > 1)) { u32 i; - VPRINTK(skdev, "skreq=%x sksg_list=%p sksg_dma=%llx\n", - skreq->id, skreq->sksg_list, skreq->sksg_dma_address); + pr_debug("%s:%s:%d skreq=%x sksg_list=%p sksg_dma=%llx\n", + skdev->name, __func__, __LINE__, + skreq->id, skreq->sksg_list, skreq->sksg_dma_address); for (i = 0; i < skreq->n_sg; i++) { struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; - VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " - "addr=0x%llx next=0x%llx\n", - i, sgd->byte_count, sgd->control, - sgd->host_side_addr, sgd->next_desc_ptr); + pr_debug("%s:%s:%d sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + skdev->name, __func__, __LINE__, + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); } } @@ -2057,7 +2085,8 @@ static int skd_sg_io_await(struct skd_device *skdev, struct skd_sg_io *sksgio) spin_lock_irqsave(&skdev->lock, flags); if (sksgio->skspcl->req.state == SKD_REQ_STATE_ABORTED) { - DPRINTK(skdev, "skspcl %p aborted\n", sksgio->skspcl); + pr_debug("%s:%s:%d skspcl %p aborted\n", + skdev->name, __func__, __LINE__, sksgio->skspcl); /* Build check cond, sense and let command finish. */ /* For a timeout, we must fabricate completion and sense @@ -2082,11 +2111,13 @@ static int skd_sg_io_await(struct skd_device *skdev, struct skd_sg_io *sksgio) sksgio->skspcl->orphaned = 1; sksgio->skspcl = NULL; if (rc == 0) { - DPRINTK(skdev, "timed out %p (%u ms)\n", sksgio, - sksgio->sg.timeout); + pr_debug("%s:%s:%d timed out %p (%u ms)\n", + skdev->name, __func__, __LINE__, + sksgio, sksgio->sg.timeout); rc = -ETIMEDOUT; } else { - DPRINTK(skdev, "cntlc %p\n", sksgio); + pr_debug("%s:%s:%d cntlc %p\n", + skdev->name, __func__, __LINE__, sksgio); rc = -EINTR; } } @@ -2116,8 +2147,9 @@ static int skd_sg_io_put_status(struct skd_device *skdev, if (sgp->masked_status || sgp->host_status || sgp->driver_status) sgp->info |= SG_INFO_CHECK; - DPRINTK(skdev, "status %x masked %x resid 0x%x\n", sgp->status, - sgp->masked_status, sgp->resid); + pr_debug("%s:%s:%d status %x masked %x resid 0x%x\n", + skdev->name, __func__, __LINE__, + sgp->status, sgp->masked_status, sgp->resid); if (sgp->masked_status == SAM_STAT_CHECK_CONDITION) { if (sgp->mx_sb_len > 0) { @@ -2129,15 +2161,17 @@ static int skd_sg_io_put_status(struct skd_device *skdev, sgp->sb_len_wr = nbytes; if (__copy_to_user(sgp->sbp, ei, nbytes)) { - DPRINTK(skdev, "copy_to_user sense failed %p\n", - sgp->sbp); + pr_debug("%s:%s:%d copy_to_user sense failed %p\n", + skdev->name, __func__, __LINE__, + sgp->sbp); return -EFAULT; } } } if (__copy_to_user(sksgio->argp, sgp, sizeof(sg_io_hdr_t))) { - DPRINTK(skdev, "copy_to_user sg failed %p\n", sksgio->argp); + pr_debug("%s:%s:%d copy_to_user sg failed %p\n", + skdev->name, __func__, __LINE__, sksgio->argp); return -EFAULT; } @@ -2325,7 +2359,8 @@ static void skd_complete_internal(struct skd_device *skdev, SKD_ASSERT(skspcl == &skdev->internal_skspcl); - DPRINTK(skdev, "complete internal %x\n", scsi->cdb[0]); + pr_debug("%s:%s:%d complete internal %x\n", + skdev->name, __func__, __LINE__, scsi->cdb[0]); skspcl->req.completion = *skcomp; skspcl->req.state = SKD_REQ_STATE_IDLE; @@ -2345,11 +2380,13 @@ static void skd_complete_internal(struct skd_device *skdev, skd_send_internal_skspcl(skdev, skspcl, WRITE_BUFFER); else { if (skdev->state == SKD_DRVR_STATE_STOPPING) { - VPRINTK(skdev, "TUR failed, don't send anymore" - "state 0x%x\n", skdev->state); + pr_debug("%s:%s:%d TUR failed, don't send anymore state 0x%x\n", + skdev->name, __func__, __LINE__, + skdev->state); return; } - DPRINTK(skdev, "**** TUR failed, retry skerr\n"); + pr_debug("%s:%s:%d **** TUR failed, retry skerr\n", + skdev->name, __func__, __LINE__); skd_send_internal_skspcl(skdev, skspcl, 0x00); } break; @@ -2359,12 +2396,13 @@ static void skd_complete_internal(struct skd_device *skdev, skd_send_internal_skspcl(skdev, skspcl, READ_BUFFER); else { if (skdev->state == SKD_DRVR_STATE_STOPPING) { - VPRINTK(skdev, "write buffer failed, don't send" - " anymore state 0x%x\n", skdev->state); + pr_debug("%s:%s:%d write buffer failed, don't send anymore state 0x%x\n", + skdev->name, __func__, __LINE__, + skdev->state); return; } - DPRINTK(skdev, - "**** write buffer failed, retry skerr\n"); + pr_debug("%s:%s:%d **** write buffer failed, retry skerr\n", + skdev->name, __func__, __LINE__); skd_send_internal_skspcl(skdev, skspcl, 0x00); } break; @@ -2392,13 +2430,15 @@ static void skd_complete_internal(struct skd_device *skdev, } else { if (skdev->state == SKD_DRVR_STATE_STOPPING) { - VPRINTK(skdev, - "read buffer failed, don't send anymore" - "state 0x%x\n", skdev->state); + pr_debug("%s:%s:%d " + "read buffer failed, don't send anymore state 0x%x\n", + skdev->name, __func__, __LINE__, + skdev->state); return; } - DPRINTK(skdev, - "**** read buffer failed, retry skerr\n"); + pr_debug("%s:%s:%d " + "**** read buffer failed, retry skerr\n", + skdev->name, __func__, __LINE__); skd_send_internal_skspcl(skdev, skspcl, 0x00); } break; @@ -2413,9 +2453,10 @@ static void skd_complete_internal(struct skd_device *skdev, (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; - DPRINTK(skdev, "last lba %d, bs %d\n", - skdev->read_cap_last_lba, - skdev->read_cap_blocksize); + pr_debug("%s:%s:%d last lba %d, bs %d\n", + skdev->name, __func__, __LINE__, + skdev->read_cap_last_lba, + skdev->read_cap_blocksize); set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); @@ -2426,11 +2467,13 @@ static void skd_complete_internal(struct skd_device *skdev, (skerr->key == MEDIUM_ERROR)) { skdev->read_cap_last_lba = ~0; set_capacity(skdev->disk, skdev->read_cap_last_lba + 1); - DPRINTK(skdev, - "**** MEDIUM ERROR caused READCAP to fail, ignore failure and continue to inquiry\n"); + pr_debug("%s:%s:%d " + "**** MEDIUM ERROR caused READCAP to fail, ignore failure and continue to inquiry\n", + skdev->name, __func__, __LINE__); skd_send_internal_skspcl(skdev, skspcl, INQUIRY); } else { - DPRINTK(skdev, "**** READCAP failed, retry TUR\n"); + pr_debug("%s:%s:%d **** READCAP failed, retry TUR\n", + skdev->name, __func__, __LINE__); skd_send_internal_skspcl(skdev, skspcl, TEST_UNIT_READY); } @@ -2447,7 +2490,8 @@ static void skd_complete_internal(struct skd_device *skdev, } if (skd_unquiesce_dev(skdev) < 0) - DPRINTK(skdev, "**** failed, to ONLINE device\n"); + pr_debug("%s:%s:%d **** failed, to ONLINE device\n", + skdev->name, __func__, __LINE__); /* connection is complete */ skdev->connect_retries = 0; break; @@ -2477,10 +2521,12 @@ static void skd_send_fitmsg(struct skd_device *skdev, u64 qcmd; struct fit_msg_hdr *fmh; - VPRINTK(skdev, "dma address 0x%llx, busy=%d\n", - skmsg->mb_dma_address, skdev->in_flight); - VPRINTK(skdev, "msg_buf 0x%p, offset %x\n", - skmsg->msg_buf, skmsg->offset); + pr_debug("%s:%s:%d dma address 0x%llx, busy=%d\n", + skdev->name, __func__, __LINE__, + skmsg->mb_dma_address, skdev->in_flight); + pr_debug("%s:%s:%d msg_buf 0x%p, offset %x\n", + skdev->name, __func__, __LINE__, + skmsg->msg_buf, skmsg->offset); qcmd = skmsg->mb_dma_address; qcmd |= FIT_QCMD_QID_NORMAL; @@ -2492,11 +2538,12 @@ static void skd_send_fitmsg(struct skd_device *skdev, u8 *bp = (u8 *)skmsg->msg_buf; int i; for (i = 0; i < skmsg->length; i += 8) { - VPRINTK(skdev, " msg[%2d] %02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - i, bp[i + 0], bp[i + 1], bp[i + 2], - bp[i + 3], bp[i + 4], bp[i + 5], - bp[i + 6], bp[i + 7]); + pr_debug("%s:%s:%d msg[%2d] %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + skdev->name, __func__, __LINE__, + i, bp[i + 0], bp[i + 1], bp[i + 2], + bp[i + 3], bp[i + 4], bp[i + 5], + bp[i + 6], bp[i + 7]); if (i == 0) i = 64 - 8; } @@ -2530,26 +2577,28 @@ static void skd_send_special_fitmsg(struct skd_device *skdev, int i; for (i = 0; i < SKD_N_SPECIAL_FITMSG_BYTES; i += 8) { - VPRINTK(skdev, - " spcl[%2d] %02x %02x %02x %02x " - "%02x %02x %02x %02x\n", i, - bp[i + 0], bp[i + 1], bp[i + 2], bp[i + 3], - bp[i + 4], bp[i + 5], bp[i + 6], bp[i + 7]); + pr_debug("%s:%s:%d spcl[%2d] %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + skdev->name, __func__, __LINE__, i, + bp[i + 0], bp[i + 1], bp[i + 2], bp[i + 3], + bp[i + 4], bp[i + 5], bp[i + 6], bp[i + 7]); if (i == 0) i = 64 - 8; } - VPRINTK(skdev, "skspcl=%p id=%04x sksg_list=%p sksg_dma=%llx\n", - skspcl, skspcl->req.id, skspcl->req.sksg_list, - skspcl->req.sksg_dma_address); + pr_debug("%s:%s:%d skspcl=%p id=%04x sksg_list=%p sksg_dma=%llx\n", + skdev->name, __func__, __LINE__, + skspcl, skspcl->req.id, skspcl->req.sksg_list, + skspcl->req.sksg_dma_address); for (i = 0; i < skspcl->req.n_sg; i++) { struct fit_sg_descriptor *sgd = &skspcl->req.sksg_list[i]; - VPRINTK(skdev, " sg[%d] count=%u ctrl=0x%x " - "addr=0x%llx next=0x%llx\n", - i, sgd->byte_count, sgd->control, - sgd->host_side_addr, sgd->next_desc_ptr); + pr_debug("%s:%s:%d sg[%d] count=%u ctrl=0x%x " + "addr=0x%llx next=0x%llx\n", + skdev->name, __func__, __LINE__, + i, sgd->byte_count, sgd->control, + sgd->host_side_addr, sgd->next_desc_ptr); } } @@ -2632,9 +2681,9 @@ static enum skd_check_status_action skd_check_status(struct skd_device *skdev, skd_name(skdev), skerr->key, skerr->code, skerr->qual, skerr->fruc); - VPRINTK(skdev, "stat: t=%02x stat=%02x k=%02x c=%02x q=%02x " - "fruc=%02x\n", skerr->type, cmp_status, skerr->key, - skerr->code, skerr->qual, skerr->fruc); + pr_debug("%s:%s:%d stat: t=%02x stat=%02x k=%02x c=%02x q=%02x fruc=%02x\n", + skdev->name, __func__, __LINE__, skerr->type, cmp_status, + skerr->key, skerr->code, skerr->qual, skerr->fruc); /* Does the info match an entry in the good category? */ n = sizeof(skd_chkstat_table) / sizeof(skd_chkstat_table[0]); @@ -2674,11 +2723,13 @@ static enum skd_check_status_action skd_check_status(struct skd_device *skdev, * zero status means good */ if (cmp_status) { - DPRINTK(skdev, "status check: error\n"); + pr_debug("%s:%s:%d status check: error\n", + skdev->name, __func__, __LINE__); return SKD_CHECK_STATUS_REPORT_ERROR; } - DPRINTK(skdev, "status check good default\n"); + pr_debug("%s:%s:%d status check good default\n", + skdev->name, __func__, __LINE__); return SKD_CHECK_STATUS_REPORT_GOOD; } @@ -2816,7 +2867,8 @@ static void skd_do_inq_page_00(struct skd_device *skdev, /* Caller requested "supported pages". The driver needs to insert * its page. */ - VPRINTK(skdev, "skd_do_driver_inquiry: modify supported pages.\n"); + pr_debug("%s:%s:%d skd_do_driver_inquiry: modify supported pages.\n", + skdev->name, __func__, __LINE__); /* If the device rejected the request because the CDB was * improperly formed, then just leave. @@ -2913,7 +2965,8 @@ static void skd_do_inq_page_da(struct skd_device *skdev, struct driver_inquiry_data inq; u16 val; - VPRINTK(skdev, "skd_do_driver_inquiry: return driver page\n"); + pr_debug("%s:%s:%d skd_do_driver_inquiry: return driver page\n", + skdev->name, __func__, __LINE__); memset(&inq, 0, sizeof(inq)); @@ -3045,14 +3098,16 @@ static int skd_isr_completion_posted(struct skd_device *skdev, skerr = &skdev->skerr_table[skdev->skcomp_ix]; - VPRINTK(skdev, - "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d " - "busy=%d rbytes=0x%x proto=%d\n", skdev->skcomp_cycle, - skdev->skcomp_ix, cmp_cycle, cmp_cntxt, cmp_status, - skdev->in_flight, cmp_bytes, skdev->proto_ver); + pr_debug("%s:%s:%d " + "cycle=%d ix=%d got cycle=%d cmdctxt=0x%x stat=%d " + "busy=%d rbytes=0x%x proto=%d\n", + skdev->name, __func__, __LINE__, skdev->skcomp_cycle, + skdev->skcomp_ix, cmp_cycle, cmp_cntxt, cmp_status, + skdev->in_flight, cmp_bytes, skdev->proto_ver); if (cmp_cycle != skdev->skcomp_cycle) { - VPRINTK(skdev, "end of completions\n"); + pr_debug("%s:%s:%d end of completions\n", + skdev->name, __func__, __LINE__); break; } /* @@ -3088,8 +3143,9 @@ static int skd_isr_completion_posted(struct skd_device *skdev, * Make sure the request ID for the slot matches. */ if (skreq->id != req_id) { - DPRINTK(skdev, "mismatch comp_id=0x%x req_id=0x%x\n", - req_id, skreq->id); + pr_debug("%s:%s:%d mismatch comp_id=0x%x req_id=0x%x\n", + skdev->name, __func__, __LINE__, + req_id, skreq->id); { u16 new_id = cmp_cntxt; pr_err("(%s): Completion mismatch " @@ -3104,8 +3160,9 @@ static int skd_isr_completion_posted(struct skd_device *skdev, SKD_ASSERT(skreq->state == SKD_REQ_STATE_BUSY); if (skreq->state == SKD_REQ_STATE_ABORTED) { - DPRINTK(skdev, "reclaim req %p id=%04x\n", - skreq, skreq->id); + pr_debug("%s:%s:%d reclaim req %p id=%04x\n", + skdev->name, __func__, __LINE__, + skreq, skreq->id); /* a previously timed out command can * now be cleaned up */ skd_release_skreq(skdev, skreq); @@ -3125,9 +3182,10 @@ static int skd_isr_completion_posted(struct skd_device *skdev, if (((!skd_bio) && !skreq->req) || ((skd_bio) && !skreq->bio)) { - DPRINTK(skdev, "NULL backptr skdreq %p, " - "req=0x%x req_id=0x%x\n", - skreq, skreq->id, req_id); + pr_debug("%s:%s:%d NULL backptr skdreq %p, " + "req=0x%x req_id=0x%x\n", + skdev->name, __func__, __LINE__, + skreq, skreq->id, req_id); } else { /* * Capture the outcome and post it back to the @@ -3196,8 +3254,9 @@ static void skd_complete_other(struct skd_device *skdev, req_table = req_id & SKD_ID_TABLE_MASK; req_slot = req_id & SKD_ID_SLOT_MASK; - DPRINTK(skdev, "table=0x%x id=0x%x slot=%d\n", req_table, req_id, - req_slot); + pr_debug("%s:%s:%d table=0x%x id=0x%x slot=%d\n", + skdev->name, __func__, __LINE__, + req_table, req_id, req_slot); /* * Based on the request id, determine how to dispatch this completion. @@ -3265,12 +3324,14 @@ static void skd_complete_special(struct skd_device *skdev, volatile struct fit_comp_error_info *skerr, struct skd_special_context *skspcl) { - DPRINTK(skdev, " completing special request %p\n", skspcl); + pr_debug("%s:%s:%d completing special request %p\n", + skdev->name, __func__, __LINE__, skspcl); if (skspcl->orphaned) { /* Discard orphaned request */ /* ?: Can this release directly or does it need * to use a worker? */ - DPRINTK(skdev, "release orphaned %p\n", skspcl); + pr_debug("%s:%s:%d release orphaned %p\n", + skdev->name, __func__, __LINE__, skspcl); skd_release_special(skdev, skspcl); return; } @@ -3308,7 +3369,8 @@ static void skd_release_special(struct skd_device *skdev, skdev->skspcl_free_list = (struct skd_special_context *)skspcl; if (was_depleted) { - DPRINTK(skdev, "skspcl was depleted\n"); + pr_debug("%s:%s:%d skspcl was depleted\n", + skdev->name, __func__, __LINE__); /* Free list was depleted. Their might be waiters. */ wake_up_interruptible(&skdev->waitq); } @@ -3373,7 +3435,8 @@ static skd_isr(int irq, void *ptr) ack = FIT_INT_DEF_MASK; ack &= intstat; - VPRINTK(skdev, "intstat=0x%x ack=0x%x\n", intstat, ack); + pr_debug("%s:%s:%d intstat=0x%x ack=0x%x\n", + skdev->name, __func__, __LINE__, intstat, ack); /* As long as there is an int pending on device, keep * running loop. When none, get out, but if we've never @@ -3534,7 +3597,8 @@ static void skd_isr_fwstate(struct skd_device *skdev) } break; case FIT_SR_DRIVE_FW_BOOTING: - VPRINTK(skdev, "ISR FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name); + pr_debug("%s:%s:%d ISR FIT_SR_DRIVE_FW_BOOTING %s\n", + skdev->name, __func__, __LINE__, skdev->name); skdev->state = SKD_DRVR_STATE_WAIT_BOOT; skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; break; @@ -3643,10 +3707,14 @@ static void skd_recover_requests(struct skd_device *skdev, int requeue) */ if (skspcl->req.state == SKD_REQ_STATE_BUSY) { if (skspcl->orphaned) { - DPRINTK(skdev, "orphaned %p\n", skspcl); + pr_debug("%s:%s:%d orphaned %p\n", + skdev->name, __func__, __LINE__, + skspcl); skd_release_special(skdev, skspcl); } else { - DPRINTK(skdev, "not orphaned %p\n", skspcl); + pr_debug("%s:%s:%d not orphaned %p\n", + skdev->name, __func__, __LINE__, + skspcl); skspcl->req.state = SKD_REQ_STATE_ABORTED; } } @@ -3667,7 +3735,8 @@ static void skd_isr_msg_from_dev(struct skd_device *skdev) mfd = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); - DPRINTK(skdev, "mfd=0x%x last_mtd=0x%x\n", mfd, skdev->last_mtd); + pr_debug("%s:%s:%d mfd=0x%x last_mtd=0x%x\n", + skdev->name, __func__, __LINE__, mfd, skdev->last_mtd); /* ignore any mtd that is an ack for something we didn't send */ if (FIT_MXD_TYPE(mfd) != FIT_MXD_TYPE(skdev->last_mtd)) @@ -3762,7 +3831,8 @@ static void skd_disable_interrupts(struct skd_device *skdev) sense = SKD_READL(skdev, FIT_CONTROL); sense &= ~FIT_CR_ENABLE_INTERRUPTS; SKD_WRITEL(skdev, sense, FIT_CONTROL); - DPRINTK(skdev, "sense 0x%x\n", sense); + pr_debug("%s:%s:%d sense 0x%x\n", + skdev->name, __func__, __LINE__, sense); /* Note that the 1s is written. A 1-bit means * disable, a 0 means enable. @@ -3781,11 +3851,13 @@ static void skd_enable_interrupts(struct skd_device *skdev) /* Note that the compliment of mask is written. A 1-bit means * disable, a 0 means enable. */ SKD_WRITEL(skdev, ~val, FIT_INT_MASK_HOST); - DPRINTK(skdev, "interrupt mask=0x%x\n", ~val); + pr_debug("%s:%s:%d interrupt mask=0x%x\n", + skdev->name, __func__, __LINE__, ~val); val = SKD_READL(skdev, FIT_CONTROL); val |= FIT_CR_ENABLE_INTERRUPTS; - DPRINTK(skdev, "control=0x%x\n", val); + pr_debug("%s:%s:%d control=0x%x\n", + skdev->name, __func__, __LINE__, val); SKD_WRITEL(skdev, val, FIT_CONTROL); } @@ -3801,7 +3873,8 @@ static void skd_soft_reset(struct skd_device *skdev) val = SKD_READL(skdev, FIT_CONTROL); val |= (FIT_CR_SOFT_RESET); - DPRINTK(skdev, "control=0x%x\n", val); + pr_debug("%s:%s:%d control=0x%x\n", + skdev->name, __func__, __LINE__, val); SKD_WRITEL(skdev, val, FIT_CONTROL); } @@ -3818,7 +3891,8 @@ static void skd_start_device(struct skd_device *skdev) sense = SKD_READL(skdev, FIT_STATUS); - DPRINTK(skdev, "initial status=0x%x\n", sense); + pr_debug("%s:%s:%d initial status=0x%x\n", + skdev->name, __func__, __LINE__, sense); state = sense & FIT_SR_DRIVE_STATE_MASK; skdev->drive_state = state; @@ -3835,7 +3909,8 @@ static void skd_start_device(struct skd_device *skdev) break; case FIT_SR_DRIVE_FW_BOOTING: - VPRINTK(skdev, "FIT_SR_DRIVE_FW_BOOTING %s\n", skdev->name); + pr_debug("%s:%s:%d FIT_SR_DRIVE_FW_BOOTING %s\n", + skdev->name, __func__, __LINE__, skdev->name); skdev->state = SKD_DRVR_STATE_WAIT_BOOT; skdev->timer_countdown = SKD_WAIT_BOOT_TIMO; break; @@ -3876,7 +3951,8 @@ static void skd_start_device(struct skd_device *skdev) */ skd_drive_fault(skdev); /*start the queue so we can respond with error to requests */ - VPRINTK(skdev, "starting %s queue\n", skdev->name); + pr_debug("%s:%s:%d starting %s queue\n", + skdev->name, __func__, __LINE__, skdev->name); skd_start_queue(skdev); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); @@ -3887,8 +3963,8 @@ static void skd_start_device(struct skd_device *skdev) * to the BAR1 addresses. */ skd_drive_disappeared(skdev); /*start the queue so we can respond with error to requests */ - VPRINTK(skdev, "starting %s queue to error-out reqs\n", - skdev->name); + pr_debug("%s:%s:%d starting %s queue to error-out reqs\n", + skdev->name, __func__, __LINE__, skdev->name); skd_start_queue(skdev); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); @@ -3901,19 +3977,24 @@ static void skd_start_device(struct skd_device *skdev) } state = SKD_READL(skdev, FIT_CONTROL); - DPRINTK(skdev, "FIT Control Status=0x%x\n", state); + pr_debug("%s:%s:%d FIT Control Status=0x%x\n", + skdev->name, __func__, __LINE__, state); state = SKD_READL(skdev, FIT_INT_STATUS_HOST); - DPRINTK(skdev, "Intr Status=0x%x\n", state); + pr_debug("%s:%s:%d Intr Status=0x%x\n", + skdev->name, __func__, __LINE__, state); state = SKD_READL(skdev, FIT_INT_MASK_HOST); - DPRINTK(skdev, "Intr Mask=0x%x\n", state); + pr_debug("%s:%s:%d Intr Mask=0x%x\n", + skdev->name, __func__, __LINE__, state); state = SKD_READL(skdev, FIT_MSG_FROM_DEVICE); - DPRINTK(skdev, "Msg from Dev=0x%x\n", state); + pr_debug("%s:%s:%d Msg from Dev=0x%x\n", + skdev->name, __func__, __LINE__, state); state = SKD_READL(skdev, FIT_HW_VERSION); - DPRINTK(skdev, "HW version=0x%x\n", state); + pr_debug("%s:%s:%d HW version=0x%x\n", + skdev->name, __func__, __LINE__, state); spin_unlock_irqrestore(&skdev->lock, flags); } @@ -4006,7 +4087,8 @@ static void skd_restart_device(struct skd_device *skdev) state = SKD_READL(skdev, FIT_STATUS); - DPRINTK(skdev, "drive status=0x%x\n", state); + pr_debug("%s:%s:%d drive status=0x%x\n", + skdev->name, __func__, __LINE__, state); state &= FIT_SR_DRIVE_STATE_MASK; skdev->drive_state = state; @@ -4026,7 +4108,8 @@ static int skd_quiesce_dev(struct skd_device *skdev) switch (skdev->state) { case SKD_DRVR_STATE_BUSY: case SKD_DRVR_STATE_BUSY_IMMINENT: - VPRINTK(skdev, "stopping %s queue\n", skdev->name); + pr_debug("%s:%s:%d stopping %s queue\n", + skdev->name, __func__, __LINE__, skdev->name); skd_stop_queue(skdev); break; case SKD_DRVR_STATE_ONLINE: @@ -4039,7 +4122,8 @@ static int skd_quiesce_dev(struct skd_device *skdev) case SKD_DRVR_STATE_RESUMING: default: rc = -EINVAL; - VPRINTK(skdev, "state [%d] not implemented\n", skdev->state); + pr_debug("%s:%s:%d state [%d] not implemented\n", + skdev->name, __func__, __LINE__, skdev->state); } return rc; } @@ -4051,7 +4135,8 @@ static int skd_unquiesce_dev(struct skd_device *skdev) skd_log_skdev(skdev, "unquiesce"); if (skdev->state == SKD_DRVR_STATE_ONLINE) { - DPRINTK(skdev, "**** device already ONLINE\n"); + pr_debug("%s:%s:%d **** device already ONLINE\n", + skdev->name, __func__, __LINE__); return 0; } if (skdev->drive_state != FIT_SR_DRIVE_ONLINE) { @@ -4064,7 +4149,8 @@ static int skd_unquiesce_dev(struct skd_device *skdev) * to become available. */ skdev->state = SKD_DRVR_STATE_BUSY; - DPRINTK(skdev, "drive BUSY state\n"); + pr_debug("%s:%s:%d drive BUSY state\n", + skdev->name, __func__, __LINE__); return 0; } @@ -4088,8 +4174,10 @@ static int skd_unquiesce_dev(struct skd_device *skdev) skd_skdev_state_to_str(prev_driver_state), prev_driver_state, skd_skdev_state_to_str(skdev->state), skdev->state); - DPRINTK(skdev, "**** device ONLINE...starting block queue\n"); - VPRINTK(skdev, "starting %s queue\n", skdev->name); + pr_debug("%s:%s:%d **** device ONLINE...starting block queue\n", + skdev->name, __func__, __LINE__); + pr_debug("%s:%s:%d starting %s queue\n", + skdev->name, __func__, __LINE__, skdev->name); pr_info("(%s): STEC s1120 ONLINE\n", skd_name(skdev)); skd_start_queue(skdev); skdev->gendisk_on = 1; @@ -4098,8 +4186,9 @@ static int skd_unquiesce_dev(struct skd_device *skdev) case SKD_DRVR_STATE_DISAPPEARED: default: - DPRINTK(skdev, "**** driver state %d, not implemented \n", - skdev->state); + pr_debug("%s:%s:%d **** driver state %d, not implemented \n", + skdev->name, __func__, __LINE__, + skdev->state); return -EBUSY; } return 0; @@ -4117,7 +4206,9 @@ static irqreturn_t skd_reserved_isr(int irq, void *skd_host_data) unsigned long flags; spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_debug("%s:%s:%d MSIX = 0x%x\n", + skdev->name, __func__, __LINE__, + SKD_READL(skdev, FIT_INT_STATUS_HOST)); pr_err("(%s): MSIX reserved irq %d = 0x%x\n", skd_name(skdev), irq, SKD_READL(skdev, FIT_INT_STATUS_HOST)); SKD_WRITEL(skdev, FIT_INT_RESERVED_MASK, FIT_INT_STATUS_HOST); @@ -4131,7 +4222,9 @@ static irqreturn_t skd_statec_isr(int irq, void *skd_host_data) unsigned long flags; spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_debug("%s:%s:%d MSIX = 0x%x\n", + skdev->name, __func__, __LINE__, + SKD_READL(skdev, FIT_INT_STATUS_HOST)); SKD_WRITEL(skdev, FIT_ISH_FW_STATE_CHANGE, FIT_INT_STATUS_HOST); skd_isr_fwstate(skdev); spin_unlock_irqrestore(&skdev->lock, flags); @@ -4146,7 +4239,9 @@ static irqreturn_t skd_comp_q(int irq, void *skd_host_data) int deferred; spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_debug("%s:%s:%d MSIX = 0x%x\n", + skdev->name, __func__, __LINE__, + SKD_READL(skdev, FIT_INT_STATUS_HOST)); SKD_WRITEL(skdev, FIT_ISH_COMPLETION_POSTED, FIT_INT_STATUS_HOST); deferred = skd_isr_completion_posted(skdev, skd_isr_comp_limit, &flush_enqueued); @@ -4170,7 +4265,9 @@ static irqreturn_t skd_msg_isr(int irq, void *skd_host_data) unsigned long flags; spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_debug("%s:%s:%d MSIX = 0x%x\n", + skdev->name, __func__, __LINE__, + SKD_READL(skdev, FIT_INT_STATUS_HOST)); SKD_WRITEL(skdev, FIT_ISH_MSG_FROM_DEV, FIT_INT_STATUS_HOST); skd_isr_msg_from_dev(skdev); spin_unlock_irqrestore(&skdev->lock, flags); @@ -4183,7 +4280,9 @@ static irqreturn_t skd_qfull_isr(int irq, void *skd_host_data) unsigned long flags; spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "MSIX = 0x%x\n", SKD_READL(skdev, FIT_INT_STATUS_HOST)); + pr_debug("%s:%s:%d MSIX = 0x%x\n", + skdev->name, __func__, __LINE__, + SKD_READL(skdev, FIT_INT_STATUS_HOST)); SKD_WRITEL(skdev, FIT_INT_QUEUE_FULL, FIT_INT_STATUS_HOST); spin_unlock_irqrestore(&skdev->lock, flags); return IRQ_HANDLED; @@ -4275,8 +4374,9 @@ static int skd_acquire_msix(struct skd_device *skdev) skd_name(skdev), rc); goto msix_out; } - DPRINTK(skdev, "%s: <%s> allocated %d MSI-X vectors\n", - pci_name(pdev), skdev->name, rc); + pr_debug("%s:%s:%d %s: <%s> allocated %d MSI-X vectors\n", + skdev->name, __func__, __LINE__, + pci_name(pdev), skdev->name, rc); skdev->msix_count = rc; rc = pci_enable_msix(pdev, entries, skdev->msix_count); @@ -4303,9 +4403,10 @@ static int skd_acquire_msix(struct skd_device *skdev) qentry->entry = entries[i].entry; qentry->rsp = NULL; qentry->have_irq = 0; - DPRINTK(skdev, "%s: <%s> msix (%d) vec %d, entry %x\n", - pci_name(pdev), skdev->name, - i, qentry->vector, qentry->entry); + pr_debug("%s:%s:%d %s: <%s> msix (%d) vec %d, entry %x\n", + skdev->name, __func__, __LINE__, + pci_name(pdev), skdev->name, + i, qentry->vector, qentry->entry); qentry++; } @@ -4328,8 +4429,9 @@ static int skd_acquire_msix(struct skd_device *skdev) qentry->rsp = skdev; } } - DPRINTK(skdev, "%s: <%s> msix %d irq(s) enabled\n", - pci_name(pdev), skdev->name, skdev->msix_count); + pr_debug("%s:%s:%d %s: <%s> msix %d irq(s) enabled\n", + skdev->name, __func__, __LINE__, + pci_name(pdev), skdev->name, skdev->msix_count); return 0; msix_out: @@ -4489,43 +4591,42 @@ static struct skd_device *skd_construct(struct pci_dev *pdev) INIT_WORK(&skdev->completion_worker, skd_completion_worker); INIT_LIST_HEAD(&skdev->flush_list); - VPRINTK(skdev, "skcomp\n"); + pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); rc = skd_cons_skcomp(skdev); if (rc < 0) goto err_out; - VPRINTK(skdev, "skmsg\n"); + pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); rc = skd_cons_skmsg(skdev); if (rc < 0) goto err_out; - VPRINTK(skdev, "skreq\n"); + pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); rc = skd_cons_skreq(skdev); if (rc < 0) goto err_out; - VPRINTK(skdev, "skspcl\n"); + pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); rc = skd_cons_skspcl(skdev); if (rc < 0) goto err_out; - VPRINTK(skdev, "sksb\n"); + pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); rc = skd_cons_sksb(skdev); if (rc < 0) goto err_out; - VPRINTK(skdev, "disk\n"); + pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); rc = skd_cons_disk(skdev); if (rc < 0) goto err_out; - - - DPRINTK(skdev, "VICTORY\n"); + pr_debug("%s:%s:%d VICTORY\n", skdev->name, __func__, __LINE__); return skdev; err_out: - DPRINTK(skdev, "construct failed\n"); + pr_debug("%s:%s:%d construct failed\n", + skdev->name, __func__, __LINE__); skd_destruct(skdev); return NULL; } @@ -4539,8 +4640,9 @@ static int skd_cons_skcomp(struct skd_device *skdev) nbytes = sizeof(*skcomp) * SKD_N_COMPLETION_ENTRY; nbytes += sizeof(struct fit_comp_error_info) * SKD_N_COMPLETION_ENTRY; - VPRINTK(skdev, "comp pci_alloc, total bytes %d entries %d\n", nbytes, - SKD_N_COMPLETION_ENTRY); + pr_debug("%s:%s:%d comp pci_alloc, total bytes %d entries %d\n", + skdev->name, __func__, __LINE__, + nbytes, SKD_N_COMPLETION_ENTRY); skcomp = pci_alloc_consistent(skdev->pdev, nbytes, &skdev->cq_dma_address); @@ -4566,10 +4668,11 @@ static int skd_cons_skmsg(struct skd_device *skdev) int rc = 0; u32 i; - VPRINTK(skdev, "skmsg_table kzalloc, struct %lu, count %u total %lu\n", - sizeof(struct skd_fitmsg_context), - skdev->num_fitmsg_context, - sizeof(struct skd_fitmsg_context) * skdev->num_fitmsg_context); + pr_debug("%s:%s:%d skmsg_table kzalloc, struct %lu, count %u total %lu\n", + skdev->name, __func__, __LINE__, + sizeof(struct skd_fitmsg_context), + skdev->num_fitmsg_context, + sizeof(struct skd_fitmsg_context) * skdev->num_fitmsg_context); skdev->skmsg_table = kzalloc(sizeof(struct skd_fitmsg_context) *skdev->num_fitmsg_context, GFP_KERNEL); @@ -4620,10 +4723,11 @@ static int skd_cons_skreq(struct skd_device *skdev) int rc = 0; u32 i; - VPRINTK(skdev, "skreq_table kzalloc, struct %lu, count %u total %lu\n", - sizeof(struct skd_request_context), - skdev->num_req_context, - sizeof(struct skd_request_context) * skdev->num_req_context); + pr_debug("%s:%s:%d skreq_table kzalloc, struct %lu, count %u total %lu\n", + skdev->name, __func__, __LINE__, + sizeof(struct skd_request_context), + skdev->num_req_context, + sizeof(struct skd_request_context) * skdev->num_req_context); skdev->skreq_table = kzalloc(sizeof(struct skd_request_context) * skdev->num_req_context, GFP_KERNEL); @@ -4632,9 +4736,10 @@ static int skd_cons_skreq(struct skd_device *skdev) goto err_out; } - VPRINTK(skdev, "alloc sg_table sg_per_req %u scatlist %lu total %lu\n", - skdev->sgs_per_request, sizeof(struct scatterlist), - skdev->sgs_per_request * sizeof(struct scatterlist)); + pr_debug("%s:%s:%d alloc sg_table sg_per_req %u scatlist %lu total %lu\n", + skdev->name, __func__, __LINE__, + skdev->sgs_per_request, sizeof(struct scatterlist), + skdev->sgs_per_request * sizeof(struct scatterlist)); for (i = 0; i < skdev->num_req_context; i++) { struct skd_request_context *skreq; @@ -4677,10 +4782,11 @@ static int skd_cons_skspcl(struct skd_device *skdev) int rc = 0; u32 i, nbytes; - VPRINTK(skdev, "skspcl_table kzalloc, struct %lu, count %u total %lu\n", - sizeof(struct skd_special_context), - skdev->n_special, - sizeof(struct skd_special_context) * skdev->n_special); + pr_debug("%s:%s:%d skspcl_table kzalloc, struct %lu, count %u total %lu\n", + skdev->name, __func__, __LINE__, + sizeof(struct skd_special_context), + skdev->n_special, + sizeof(struct skd_special_context) * skdev->n_special); skdev->skspcl_table = kzalloc(sizeof(struct skd_special_context) * skdev->n_special, GFP_KERNEL); @@ -4872,7 +4978,8 @@ static int skd_cons_disk(struct skd_device *skdev) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); spin_lock_irqsave(&skdev->lock, flags); - VPRINTK(skdev, "stopping %s queue\n", skdev->name); + pr_debug("%s:%s:%d stopping %s queue\n", + skdev->name, __func__, __LINE__, skdev->name); skd_stop_queue(skdev); spin_unlock_irqrestore(&skdev->lock, flags); @@ -4902,25 +5009,25 @@ static void skd_destruct(struct skd_device *skdev) return; - VPRINTK(skdev, "disk\n"); + pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); skd_free_disk(skdev); - VPRINTK(skdev, "sksb\n"); + pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); skd_free_sksb(skdev); - VPRINTK(skdev, "skspcl\n"); + pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); skd_free_skspcl(skdev); - VPRINTK(skdev, "skreq\n"); + pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); skd_free_skreq(skdev); - VPRINTK(skdev, "skmsg\n"); + pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); skd_free_skmsg(skdev); - VPRINTK(skdev, "skcomp\n"); + pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); skd_free_skcomp(skdev); - VPRINTK(skdev, "skdev\n"); + pr_debug("%s:%s:%d skdev\n", skdev->name, __func__, __LINE__); kfree(skdev); } @@ -5106,8 +5213,9 @@ static int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) skdev = bdev->bd_disk->private_data; - DPRINTK(skdev, "%s: CMD[%s] getgeo device\n", - bdev->bd_disk->disk_name, current->comm); + pr_debug("%s:%s:%d %s: CMD[%s] getgeo device\n", + skdev->name, __func__, __LINE__, + bdev->bd_disk->disk_name, current->comm); if (skdev->read_cap_is_valid) { capacity = get_capacity(skdev->disk); @@ -5122,7 +5230,7 @@ static int skd_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo) static int skd_bdev_attach(struct skd_device *skdev) { - DPRINTK(skdev, "add_disk\n"); + pr_debug("%s:%s:%d add_disk\n", skdev->name, __func__, __LINE__); add_disk(skdev->disk); return 0; } @@ -5245,9 +5353,10 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) rc = -ENODEV; goto err_out_iounmap; } - DPRINTK(skdev, "mem_map=%p, phyd=%016llx, size=%d\n", - skdev->mem_map[i], - (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); + pr_debug("%s:%s:%d mem_map=%p, phyd=%016llx, size=%d\n", + skdev->name, __func__, __LINE__, + skdev->mem_map[i], + (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); } rc = skd_acquire_irq(skdev); @@ -5441,9 +5550,10 @@ static int skd_pci_resume(struct pci_dev *pdev) rc = -ENODEV; goto err_out_iounmap; } - DPRINTK(skdev, "mem_map=%p, phyd=%016llx, size=%d\n", - skdev->mem_map[i], - (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); + pr_debug("%s:%s:%d mem_map=%p, phyd=%016llx, size=%d\n", + skdev->name, __func__, __LINE__, + skdev->mem_map[i], + (uint64_t)skdev->mem_phys[i], skdev->mem_size[i]); } rc = skd_acquire_irq(skdev); if (rc) { @@ -5643,35 +5753,44 @@ const char *skd_skreq_state_to_str(enum skd_req_state state) static void skd_log_skdev(struct skd_device *skdev, const char *event) { - DPRINTK(skdev, "(%s) skdev=%p event='%s'\n", skdev->name, skdev, event); - DPRINTK(skdev, " drive_state=%s(%d) driver_state=%s(%d)\n", - skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, - skd_skdev_state_to_str(skdev->state), skdev->state); - DPRINTK(skdev, " busy=%d limit=%d dev=%d lowat=%d\n", - skdev->in_flight, skdev->cur_max_queue_depth, - skdev->dev_max_queue_depth, skdev->queue_low_water_mark); - DPRINTK(skdev, " timestamp=0x%x cycle=%d cycle_ix=%d\n", - skdev->timeout_stamp, skdev->skcomp_cycle, skdev->skcomp_ix); + pr_debug("%s:%s:%d (%s) skdev=%p event='%s'\n", + skdev->name, __func__, __LINE__, skdev->name, skdev, event); + pr_debug("%s:%s:%d drive_state=%s(%d) driver_state=%s(%d)\n", + skdev->name, __func__, __LINE__, + skd_drive_state_to_str(skdev->drive_state), skdev->drive_state, + skd_skdev_state_to_str(skdev->state), skdev->state); + pr_debug("%s:%s:%d busy=%d limit=%d dev=%d lowat=%d\n", + skdev->name, __func__, __LINE__, + skdev->in_flight, skdev->cur_max_queue_depth, + skdev->dev_max_queue_depth, skdev->queue_low_water_mark); + pr_debug("%s:%s:%d timestamp=0x%x cycle=%d cycle_ix=%d\n", + skdev->name, __func__, __LINE__, + skdev->timeout_stamp, skdev->skcomp_cycle, skdev->skcomp_ix); } static void skd_log_skmsg(struct skd_device *skdev, struct skd_fitmsg_context *skmsg, const char *event) { - DPRINTK(skdev, "(%s) skmsg=%p event='%s'\n", skdev->name, skmsg, event); - DPRINTK(skdev, " state=%s(%d) id=0x%04x length=%d\n", - skd_skmsg_state_to_str(skmsg->state), skmsg->state, - skmsg->id, skmsg->length); + pr_debug("%s:%s:%d (%s) skmsg=%p event='%s'\n", + skdev->name, __func__, __LINE__, skdev->name, skmsg, event); + pr_debug("%s:%s:%d state=%s(%d) id=0x%04x length=%d\n", + skdev->name, __func__, __LINE__, + skd_skmsg_state_to_str(skmsg->state), skmsg->state, + skmsg->id, skmsg->length); } static void skd_log_skreq(struct skd_device *skdev, struct skd_request_context *skreq, const char *event) { - DPRINTK(skdev, "(%s) skreq=%p event='%s'\n", skdev->name, skreq, event); - DPRINTK(skdev, " state=%s(%d) id=0x%04x fitmsg=0x%04x\n", - skd_skreq_state_to_str(skreq->state), skreq->state, - skreq->id, skreq->fitmsg_id); - DPRINTK(skdev, " timo=0x%x sg_dir=%d n_sg=%d\n", - skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg); + pr_debug("%s:%s:%d (%s) skreq=%p event='%s'\n", + skdev->name, __func__, __LINE__, skdev->name, skreq, event); + pr_debug("%s:%s:%d state=%s(%d) id=0x%04x fitmsg=0x%04x\n", + skdev->name, __func__, __LINE__, + skd_skreq_state_to_str(skreq->state), skreq->state, + skreq->id, skreq->fitmsg_id); + pr_debug("%s:%s:%d timo=0x%x sg_dir=%d n_sg=%d\n", + skdev->name, __func__, __LINE__, + skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg); if (!skd_bio) { if (skreq->req != NULL) { @@ -5679,24 +5798,28 @@ static void skd_log_skreq(struct skd_device *skdev, u32 lba = (u32)blk_rq_pos(req); u32 count = blk_rq_sectors(req); - DPRINTK(skdev, - " req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - req, lba, lba, count, count, - (int)rq_data_dir(req)); + pr_debug("%s:%s:%d " + "req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + req, lba, lba, count, count, + (int)rq_data_dir(req)); } else - DPRINTK(skdev, " req=NULL\n"); + pr_debug("%s:%s:%d req=NULL\n", + skdev->name, __func__, __LINE__); } else { if (skreq->bio != NULL) { struct bio *bio = skreq->bio; u32 lba = (u32)bio->bi_sector; u32 count = bio_sectors(bio); - DPRINTK(skdev, - " bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - bio, lba, lba, count, count, - (int)bio_data_dir(bio)); + pr_debug("%s:%s:%d " + "bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + bio, lba, lba, count, count, + (int)bio_data_dir(bio)); } else - DPRINTK(skdev, " req=NULL\n"); + pr_debug("%s:%s:%d req=NULL\n", + skdev->name, __func__, __LINE__); } } -- cgit v1.2.3 From b88fac630bf71bd0af44502d6688e99a5426d438 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 29 Oct 2013 13:46:06 -0600 Subject: cciss: return 0 from driver probe function on success, not 1 A return value of 1 is interpreted as an error Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index edfa2515bc86..0c004ac05811 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -5183,7 +5183,7 @@ reinit_after_soft_reset: rebuild_lun_table(h, 1, 0); cciss_engage_scsi(h); h->busy_initializing = 0; - return 1; + return 0; clean4: cciss_free_cmd_pool(h); -- cgit v1.2.3 From 1762b57fcbe365c2e3f79769a7fe77942ea3165f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 30 Oct 2013 13:23:53 +0800 Subject: skd: fix error return code in skd_pci_probe() Fix to return -ENOMEM in the skd construct error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index ab17bff6b4f9..1a8717fce41d 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -5321,8 +5321,10 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } skdev = skd_construct(pdev); - if (skdev == NULL) + if (skdev == NULL) { + rc = -ENOMEM; goto err_out_regions; + } skd_pci_info(skdev, pci_str); pr_info("(%s): %s 64bit\n", skd_name(skdev), pci_str); -- cgit v1.2.3 From fcd37eb3c1347193935d07a82b84dfc7d418dd05 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Nov 2013 10:14:56 -0600 Subject: skd: rip out bio path The skd driver has a selectable rq or bio based queueing model. For 3.14, we want to turn this into a single blk-mq interface instead. With the immutable biovecs being merged in 3.13, the bio model would need patches to even work. So rip it out, with a conversion pending for blk-mq in the next release. Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 529 ++++++----------------------------------------- 1 file changed, 62 insertions(+), 467 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 1a8717fce41d..49e1e8b48422 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -354,13 +354,7 @@ struct skd_device { u32 timo_slot; - struct work_struct completion_worker; - - struct bio_list bio_queue; - int queue_stopped; - - struct list_head flush_list; }; #define SKD_FLUSH_JOB "skd-flush-jobs" @@ -470,11 +464,6 @@ MODULE_PARM_DESC(skd_dbg_level, "s1120 debug level (0,1,2)"); module_param(skd_isr_comp_limit, int, 0444); MODULE_PARM_DESC(skd_isr_comp_limit, "s1120 isr comp limit (0=none) default=4"); -static int skd_bio; -module_param(skd_bio, int, 0444); -MODULE_PARM_DESC(skd_bio, - "Register as a bio device instead of block (0, 1) default=0"); - /* Major device number dynamically assigned. */ static u32 skd_major; @@ -512,11 +501,6 @@ static void skd_log_skmsg(struct skd_device *skdev, static void skd_log_skreq(struct skd_device *skdev, struct skd_request_context *skreq, const char *event); -/* FLUSH FUA flag handling. */ -static int skd_flush_cmd_enqueue(struct skd_device *, void *); -static void *skd_flush_cmd_dequeue(struct skd_device *); - - /* ***************************************************************************** * READ/WRITE REQUESTS @@ -524,40 +508,25 @@ static void *skd_flush_cmd_dequeue(struct skd_device *); */ static void skd_stop_queue(struct skd_device *skdev) { - if (!skd_bio) - blk_stop_queue(skdev->queue); - else - skdev->queue_stopped = 1; + blk_stop_queue(skdev->queue); } static void skd_unstop_queue(struct skd_device *skdev) { - if (!skd_bio) - queue_flag_clear(QUEUE_FLAG_STOPPED, skdev->queue); - else - skdev->queue_stopped = 0; + queue_flag_clear(QUEUE_FLAG_STOPPED, skdev->queue); } static void skd_start_queue(struct skd_device *skdev) { - if (!skd_bio) { - blk_start_queue(skdev->queue); - } else { - pr_err("(%s): Starting queue\n", skd_name(skdev)); - skdev->queue_stopped = 0; - skd_request_fn(skdev->queue); - } + blk_start_queue(skdev->queue); } static int skd_queue_stopped(struct skd_device *skdev) { - if (!skd_bio) - return blk_queue_stopped(skdev->queue); - else - return skdev->queue_stopped; + return blk_queue_stopped(skdev->queue); } -static void skd_fail_all_pending_blk(struct skd_device *skdev) +static void skd_fail_all_pending(struct skd_device *skdev) { struct request_queue *q = skdev->queue; struct request *req; @@ -571,42 +540,6 @@ static void skd_fail_all_pending_blk(struct skd_device *skdev) } } -static void skd_fail_all_pending_bio(struct skd_device *skdev) -{ - struct bio *bio; - int error = -EIO; - - for (;; ) { - bio = bio_list_pop(&skdev->bio_queue); - - if (bio == NULL) - break; - - bio_endio(bio, error); - } -} - -static void skd_fail_all_pending(struct skd_device *skdev) -{ - if (!skd_bio) - skd_fail_all_pending_blk(skdev); - else - skd_fail_all_pending_bio(skdev); -} - -static void skd_make_request(struct request_queue *q, struct bio *bio) -{ - struct skd_device *skdev = q->queuedata; - unsigned long flags; - - spin_lock_irqsave(&skdev->lock, flags); - - bio_list_add(&skdev->bio_queue, bio); - skd_request_fn(skdev->queue); - - spin_unlock_irqrestore(&skdev->lock, flags); -} - static void skd_prep_rw_cdb(struct skd_scsi_request *scsi_req, int data_dir, unsigned lba, @@ -667,18 +600,9 @@ skd_prep_discard_cdb(struct skd_scsi_request *scsi_req, put_unaligned_be64(lba, &buf[8]); put_unaligned_be32(count, &buf[16]); - if (!skd_bio) { - req = skreq->req; - blk_add_request_payload(req, page, len); - req->buffer = buf; - } else { - skreq->bio->bi_io_vec->bv_page = page; - skreq->bio->bi_io_vec->bv_offset = 0; - skreq->bio->bi_io_vec->bv_len = len; - - skreq->bio->bi_vcnt = 1; - skreq->bio->bi_phys_segments = 1; - } + req = skreq->req; + blk_add_request_payload(req, page, len); + req->buffer = buf; } static void skd_request_fn_not_online(struct request_queue *q); @@ -690,7 +614,6 @@ static void skd_request_fn(struct request_queue *q) struct fit_msg_hdr *fmh = NULL; struct skd_request_context *skreq; struct request *req = NULL; - struct bio *bio = NULL; struct skd_scsi_request *scsi_req; struct page *page; unsigned long io_flags; @@ -732,60 +655,27 @@ static void skd_request_fn(struct request_queue *q) flush = fua = 0; - if (!skd_bio) { - req = blk_peek_request(q); - - /* Are there any native requests to start? */ - if (req == NULL) - break; - - lba = (u32)blk_rq_pos(req); - count = blk_rq_sectors(req); - data_dir = rq_data_dir(req); - io_flags = req->cmd_flags; - - if (io_flags & REQ_FLUSH) - flush++; - - if (io_flags & REQ_FUA) - fua++; + req = blk_peek_request(q); - pr_debug("%s:%s:%d new req=%p lba=%u(0x%x) " - "count=%u(0x%x) dir=%d\n", - skdev->name, __func__, __LINE__, - req, lba, lba, count, count, data_dir); - } else { - if (!list_empty(&skdev->flush_list)) { - /* Process data part of FLUSH request. */ - bio = (struct bio *)skd_flush_cmd_dequeue(skdev); - flush++; - pr_debug("%s:%s:%d processing FLUSH request with data.\n", - skdev->name, __func__, __LINE__); - } else { - /* peek at our bio queue */ - bio = bio_list_peek(&skdev->bio_queue); - } + /* Are there any native requests to start? */ + if (req == NULL) + break; - /* Are there any native requests to start? */ - if (bio == NULL) - break; + lba = (u32)blk_rq_pos(req); + count = blk_rq_sectors(req); + data_dir = rq_data_dir(req); + io_flags = req->cmd_flags; - lba = (u32)bio->bi_sector; - count = bio_sectors(bio); - data_dir = bio_data_dir(bio); - io_flags = bio->bi_rw; + if (io_flags & REQ_FLUSH) + flush++; - pr_debug("%s:%s:%d new bio=%p lba=%u(0x%x) " - "count=%u(0x%x) dir=%d\n", - skdev->name, __func__, __LINE__, - bio, lba, lba, count, count, data_dir); + if (io_flags & REQ_FUA) + fua++; - if (io_flags & REQ_FLUSH) - flush++; - - if (io_flags & REQ_FUA) - fua++; - } + pr_debug("%s:%s:%d new req=%p lba=%u(0x%x) " + "count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + req, lba, lba, count, count, data_dir); /* At this point we know there is a request * (from our bio q or req q depending on the way @@ -831,23 +721,9 @@ static void skd_request_fn(struct request_queue *q) * the native request. Note that skd_request_context is * available but is still at the head of the free list. */ - if (!skd_bio) { - blk_start_request(req); - skreq->req = req; - skreq->fitmsg_id = 0; - } else { - if (unlikely(flush == SKD_FLUSH_DATA_SECOND)) { - skreq->bio = bio; - } else { - skreq->bio = bio_list_pop(&skdev->bio_queue); - SKD_ASSERT(skreq->bio == bio); - skreq->start_time = jiffies; - part_inc_in_flight(&skdev->disk->part0, - bio_data_dir(bio)); - } - - skreq->fitmsg_id = 0; - } + blk_start_request(req); + skreq->req = req; + skreq->fitmsg_id = 0; /* Either a FIT msg is in progress or we have to start one. */ if (skmsg == NULL) { @@ -923,8 +799,7 @@ static void skd_request_fn(struct request_queue *q) if (fua) scsi_req->cdb[1] |= SKD_FUA_NV; - if ((!skd_bio && !req->bio) || - (skd_bio && flush == SKD_FLUSH_ZERO_SIZE_FIRST)) + if (!req->bio) goto skip_sg; error = skd_preop_sg_list(skdev, skreq); @@ -1011,8 +886,7 @@ skip_sg: * If req is non-NULL it means there is something to do but * we are out of a resource. */ - if (((!skd_bio) && req) || - ((skd_bio) && bio_list_peek(&skdev->bio_queue))) + if (req) skd_stop_queue(skdev); } @@ -1045,7 +919,7 @@ static void skd_end_request_blk(struct skd_device *skdev, __blk_end_request_all(skreq->req, error); } -static int skd_preop_sg_list_blk(struct skd_device *skdev, +static int skd_preop_sg_list(struct skd_device *skdev, struct skd_request_context *skreq) { struct request *req = skreq->req; @@ -1108,7 +982,7 @@ static int skd_preop_sg_list_blk(struct skd_device *skdev, return 0; } -static void skd_postop_sg_list_blk(struct skd_device *skdev, +static void skd_postop_sg_list(struct skd_device *skdev, struct skd_request_context *skreq) { int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; @@ -1124,184 +998,10 @@ static void skd_postop_sg_list_blk(struct skd_device *skdev, pci_unmap_sg(skdev->pdev, &skreq->sg[0], skreq->n_sg, pci_dir); } -static void skd_end_request_bio(struct skd_device *skdev, - struct skd_request_context *skreq, int error) -{ - struct bio *bio = skreq->bio; - int rw = bio_data_dir(bio); - unsigned long io_flags = bio->bi_rw; - - if ((io_flags & REQ_DISCARD) && - (skreq->discard_page == 1)) { - pr_debug("%s:%s:%d biomode: skd_end_request: freeing DISCARD page.\n", - skdev->name, __func__, __LINE__); - free_page((unsigned long)page_address(bio->bi_io_vec->bv_page)); - } - - if (unlikely(error)) { - u32 lba = (u32)skreq->bio->bi_sector; - u32 count = bio_sectors(skreq->bio); - char *cmd = (rw == WRITE) ? "write" : "read"; - pr_err("(%s): Error cmd=%s sect=%u count=%u id=0x%x\n", - skd_name(skdev), cmd, lba, count, skreq->id); - } - { - int cpu = part_stat_lock(); - - if (likely(!error)) { - part_stat_inc(cpu, &skdev->disk->part0, ios[rw]); - part_stat_add(cpu, &skdev->disk->part0, sectors[rw], - bio_sectors(bio)); - } - part_stat_add(cpu, &skdev->disk->part0, ticks[rw], - jiffies - skreq->start_time); - part_dec_in_flight(&skdev->disk->part0, rw); - part_stat_unlock(); - } - - pr_debug("%s:%s:%d id=0x%x error=%d\n", - skdev->name, __func__, __LINE__, skreq->id, error); - - bio_endio(skreq->bio, error); -} - -static int skd_preop_sg_list_bio(struct skd_device *skdev, - struct skd_request_context *skreq) -{ - struct bio *bio = skreq->bio; - int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; - int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; - int n_sg; - int i; - struct bio_vec *vec; - struct fit_sg_descriptor *sgd; - u64 dma_addr; - u32 count; - int errs = 0; - unsigned int io_flags = 0; - io_flags |= bio->bi_rw; - - skreq->sg_byte_count = 0; - n_sg = skreq->n_sg = skreq->bio->bi_vcnt; - - if (n_sg <= 0) - return -EINVAL; - - if (n_sg > skdev->sgs_per_request) { - pr_err("(%s): sg overflow n=%d\n", - skd_name(skdev), n_sg); - skreq->n_sg = 0; - return -EIO; - } - - for (i = 0; i < skreq->n_sg; i++) { - vec = bio_iovec_idx(bio, i); - dma_addr = pci_map_page(skdev->pdev, - vec->bv_page, - vec->bv_offset, vec->bv_len, pci_dir); - count = vec->bv_len; - - if (count == 0 || count > 64u * 1024u || (count & 3) != 0 - || (dma_addr & 3) != 0) { - pr_err( - "(%s): Bad sg ix=%d count=%d addr=0x%llx\n", - skd_name(skdev), i, count, dma_addr); - errs++; - } - - sgd = &skreq->sksg_list[i]; - - sgd->control = FIT_SGD_CONTROL_NOT_LAST; - sgd->byte_count = vec->bv_len; - skreq->sg_byte_count += vec->bv_len; - sgd->host_side_addr = dma_addr; - sgd->dev_side_addr = 0; /* not used */ - } - - skreq->sksg_list[n_sg - 1].next_desc_ptr = 0LL; - skreq->sksg_list[n_sg - 1].control = FIT_SGD_CONTROL_LAST; - - - if (!(io_flags & REQ_DISCARD)) { - count = bio_sectors(bio) << 9u; - if (count != skreq->sg_byte_count) { - pr_err("(%s): mismatch count sg=%d req=%d\n", - skd_name(skdev), skreq->sg_byte_count, count); - errs++; - } - } - - if (unlikely(skdev->dbg_level > 1)) { - pr_debug("%s:%s:%d skreq=%x sksg_list=%p sksg_dma=%llx\n", - skdev->name, __func__, __LINE__, - skreq->id, skreq->sksg_list, skreq->sksg_dma_address); - for (i = 0; i < n_sg; i++) { - struct fit_sg_descriptor *sgd = &skreq->sksg_list[i]; - pr_debug("%s:%s:%d sg[%d] count=%u ctrl=0x%x " - "addr=0x%llx next=0x%llx\n", - skdev->name, __func__, __LINE__, - i, sgd->byte_count, sgd->control, - sgd->host_side_addr, sgd->next_desc_ptr); - } - } - - if (errs != 0) { - skd_postop_sg_list(skdev, skreq); - skreq->n_sg = 0; - return -EIO; - } - - return 0; -} - -static int skd_preop_sg_list(struct skd_device *skdev, - struct skd_request_context *skreq) -{ - if (!skd_bio) - return skd_preop_sg_list_blk(skdev, skreq); - else - return skd_preop_sg_list_bio(skdev, skreq); -} - -static void skd_postop_sg_list_bio(struct skd_device *skdev, - struct skd_request_context *skreq) -{ - int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; - int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; - int i; - struct fit_sg_descriptor *sgd; - - /* - * restore the next ptr for next IO request so we - * don't have to set it every time. - */ - skreq->sksg_list[skreq->n_sg - 1].next_desc_ptr = - skreq->sksg_dma_address + - ((skreq->n_sg) * sizeof(struct fit_sg_descriptor)); - - for (i = 0; i < skreq->n_sg; i++) { - sgd = &skreq->sksg_list[i]; - pci_unmap_page(skdev->pdev, sgd->host_side_addr, - sgd->byte_count, pci_dir); - } -} - -static void skd_postop_sg_list(struct skd_device *skdev, - struct skd_request_context *skreq) -{ - if (!skd_bio) - skd_postop_sg_list_blk(skdev, skreq); - else - skd_postop_sg_list_bio(skdev, skreq); -} - static void skd_end_request(struct skd_device *skdev, struct skd_request_context *skreq, int error) { - if (likely(!skd_bio)) - skd_end_request_blk(skdev, skreq, error); - else - skd_end_request_bio(skdev, skreq, error); + skd_end_request_blk(skdev, skreq, error); } static void skd_request_fn_not_online(struct request_queue *q) @@ -2754,13 +2454,10 @@ static void skd_resolve_req_exception(struct skd_device *skdev, break; case SKD_CHECK_STATUS_REQUEUE_REQUEST: - if (!skd_bio) { - if ((unsigned long) ++skreq->req->special < - SKD_MAX_RETRIES) { - skd_log_skreq(skdev, skreq, "retry"); - skd_requeue_request(skdev, skreq); - break; - } + if ((unsigned long) ++skreq->req->special < SKD_MAX_RETRIES) { + skd_log_skreq(skdev, skreq, "retry"); + skd_requeue_request(skdev, skreq); + break; } /* fall through to report error */ @@ -2774,12 +2471,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev, static void skd_requeue_request(struct skd_device *skdev, struct skd_request_context *skreq) { - if (!skd_bio) { - blk_requeue_request(skdev->queue, skreq->req); - } else { - bio_list_add_head(&skdev->bio_queue, skreq->bio); - skreq->bio = NULL; - } + blk_requeue_request(skdev->queue, skreq->req); } @@ -2840,11 +2532,7 @@ static void skd_release_skreq(struct skd_device *skdev, /* * Reset backpointer */ - if (likely(!skd_bio)) - skreq->req = NULL; - else - skreq->bio = NULL; - + skreq->req = NULL; /* * Reclaim the skd_request_context @@ -3084,8 +2772,6 @@ static int skd_isr_completion_posted(struct skd_device *skdev, u32 cmp_bytes = 0; int rc = 0; int processed = 0; - int ret; - for (;; ) { SKD_ASSERT(skdev->skcomp_ix < SKD_N_COMPLETION_ENTRY); @@ -3180,8 +2866,7 @@ static int skd_isr_completion_posted(struct skd_device *skdev, if (skreq->n_sg > 0) skd_postop_sg_list(skdev, skreq); - if (((!skd_bio) && !skreq->req) || - ((skd_bio) && !skreq->bio)) { + if (!skreq->req) { pr_debug("%s:%s:%d NULL backptr skdreq %p, " "req=0x%x req_id=0x%x\n", skdev->name, __func__, __LINE__, @@ -3191,30 +2876,10 @@ static int skd_isr_completion_posted(struct skd_device *skdev, * Capture the outcome and post it back to the * native request. */ - if (likely(cmp_status == SAM_STAT_GOOD)) { - if (unlikely(skreq->flush_cmd)) { - if (skd_bio) { - /* if empty size bio, we are all done */ - if (bio_sectors(skreq->bio) == 0) { - skd_end_request(skdev, skreq, 0); - } else { - ret = skd_flush_cmd_enqueue(skdev, (void *)skreq->bio); - if (ret != 0) { - pr_err("Failed to enqueue flush bio with Data. Err=%d.\n", ret); - skd_end_request(skdev, skreq, ret); - } else { - ((*enqueued)++); - } - } - } else { - skd_end_request(skdev, skreq, 0); - } - } else { - skd_end_request(skdev, skreq, 0); - } - } else { + if (likely(cmp_status == SAM_STAT_GOOD)) + skd_end_request(skdev, skreq, 0); + else skd_resolve_req_exception(skdev, skreq); - } } /* @@ -3645,29 +3310,20 @@ static void skd_recover_requests(struct skd_device *skdev, int requeue) skd_log_skreq(skdev, skreq, "recover"); SKD_ASSERT((skreq->id & SKD_ID_INCR) != 0); - if (!skd_bio) - SKD_ASSERT(skreq->req != NULL); - else - SKD_ASSERT(skreq->bio != NULL); + SKD_ASSERT(skreq->req != NULL); /* Release DMA resources for the request. */ if (skreq->n_sg > 0) skd_postop_sg_list(skdev, skreq); - if (!skd_bio) { - if (requeue && - (unsigned long) ++skreq->req->special < - SKD_MAX_RETRIES) - skd_requeue_request(skdev, skreq); - else - skd_end_request(skdev, skreq, -EIO); - } else + if (requeue && + (unsigned long) ++skreq->req->special < + SKD_MAX_RETRIES) + skd_requeue_request(skdev, skreq); + else skd_end_request(skdev, skreq, -EIO); - if (!skd_bio) - skreq->req = NULL; - else - skreq->bio = NULL; + skreq->req = NULL; skreq->state = SKD_REQ_STATE_IDLE; skreq->id += SKD_ID_INCR; @@ -4580,16 +4236,11 @@ static struct skd_device *skd_construct(struct pci_dev *pdev) skdev->sgs_per_request = skd_sgs_per_request; skdev->dbg_level = skd_dbg_level; - if (skd_bio) - bio_list_init(&skdev->bio_queue); - - atomic_set(&skdev->device_count, 0); spin_lock_init(&skdev->lock); INIT_WORK(&skdev->completion_worker, skd_completion_worker); - INIT_LIST_HEAD(&skdev->flush_list); pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); rc = skd_cons_skcomp(skdev); @@ -4941,13 +4592,7 @@ static int skd_cons_disk(struct skd_device *skdev) disk->fops = &skd_blockdev_ops; disk->private_data = skdev; - if (!skd_bio) { - q = blk_init_queue(skd_request_fn, &skdev->lock); - } else { - q = blk_alloc_queue(GFP_KERNEL); - q->queue_flags = QUEUE_FLAG_IO_STAT | QUEUE_FLAG_STACKABLE; - } - + q = blk_init_queue(skd_request_fn, &skdev->lock); if (!q) { rc = -ENOMEM; goto err_out; @@ -4957,11 +4602,6 @@ static int skd_cons_disk(struct skd_device *skdev) disk->queue = q; q->queuedata = skdev; - if (skd_bio) { - q->queue_lock = &skdev->lock; - blk_queue_make_request(q, skd_make_request); - } - blk_queue_flush(q, REQ_FLUSH | REQ_FUA); blk_queue_max_segments(q, skdev->sgs_per_request); blk_queue_max_hw_sectors(q, SKD_N_MAX_SECTORS); @@ -5794,35 +5434,19 @@ static void skd_log_skreq(struct skd_device *skdev, skdev->name, __func__, __LINE__, skreq->timeout_stamp, skreq->sg_data_dir, skreq->n_sg); - if (!skd_bio) { - if (skreq->req != NULL) { - struct request *req = skreq->req; - u32 lba = (u32)blk_rq_pos(req); - u32 count = blk_rq_sectors(req); - - pr_debug("%s:%s:%d " - "req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - skdev->name, __func__, __LINE__, - req, lba, lba, count, count, - (int)rq_data_dir(req)); - } else - pr_debug("%s:%s:%d req=NULL\n", - skdev->name, __func__, __LINE__); - } else { - if (skreq->bio != NULL) { - struct bio *bio = skreq->bio; - u32 lba = (u32)bio->bi_sector; - u32 count = bio_sectors(bio); + if (skreq->req != NULL) { + struct request *req = skreq->req; + u32 lba = (u32)blk_rq_pos(req); + u32 count = blk_rq_sectors(req); - pr_debug("%s:%s:%d " - "bio=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", - skdev->name, __func__, __LINE__, - bio, lba, lba, count, count, - (int)bio_data_dir(bio)); - } else - pr_debug("%s:%s:%d req=NULL\n", - skdev->name, __func__, __LINE__); - } + pr_debug("%s:%s:%d " + "req=%p lba=%u(0x%x) count=%u(0x%x) dir=%d\n", + skdev->name, __func__, __LINE__, + req, lba, lba, count, count, + (int)rq_data_dir(req)); + } else + pr_debug("%s:%s:%d req=NULL\n", + skdev->name, __func__, __LINE__); } /* @@ -5918,34 +5542,5 @@ static void __exit skd_exit(void) kmem_cache_destroy(skd_flush_slab); } -static int -skd_flush_cmd_enqueue(struct skd_device *skdev, void *cmd) -{ - struct skd_flush_cmd *item; - - item = kmem_cache_zalloc(skd_flush_slab, GFP_ATOMIC); - if (!item) { - pr_err("skd_flush_cmd_enqueue: Failed to allocated item.\n"); - return -ENOMEM; - } - - item->cmd = cmd; - list_add_tail(&item->flist, &skdev->flush_list); - return 0; -} - -static void * -skd_flush_cmd_dequeue(struct skd_device *skdev) -{ - void *cmd; - struct skd_flush_cmd *item; - - item = list_entry(skdev->flush_list.next, struct skd_flush_cmd, flist); - list_del_init(&item->flist); - cmd = item->cmd; - kmem_cache_free(skd_flush_slab, item); - return cmd; -} - module_init(skd_init); module_exit(skd_exit); -- cgit v1.2.3 From 6a5ec65b9acee39f9af4a15a81858d5fc07498d0 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Nov 2013 10:38:45 -0600 Subject: skd: cleanup the skd_*() function block wrapping Just call the block functions directly, don't wrap them in skd helpers. With only one queueing model enabled, there's no point in doing that. Also kill the ->start_time and ->bio from the skd_request_context, we don't use those anymore. Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 52 ++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 49e1e8b48422..d404d7646d9c 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -214,8 +214,6 @@ struct skd_request_context { u32 fitmsg_id; struct request *req; - struct bio *bio; - unsigned long start_time; u8 flush_cmd; u8 discard_page; @@ -506,26 +504,6 @@ static void skd_log_skreq(struct skd_device *skdev, * READ/WRITE REQUESTS ***************************************************************************** */ -static void skd_stop_queue(struct skd_device *skdev) -{ - blk_stop_queue(skdev->queue); -} - -static void skd_unstop_queue(struct skd_device *skdev) -{ - queue_flag_clear(QUEUE_FLAG_STOPPED, skdev->queue); -} - -static void skd_start_queue(struct skd_device *skdev) -{ - blk_start_queue(skdev->queue); -} - -static int skd_queue_stopped(struct skd_device *skdev) -{ - return blk_queue_stopped(skdev->queue); -} - static void skd_fail_all_pending(struct skd_device *skdev) { struct request_queue *q = skdev->queue; @@ -634,14 +612,14 @@ static void skd_request_fn(struct request_queue *q) return; } - if (skd_queue_stopped(skdev)) { + if (blk_queue_stopped(skdev->queue)) { if (skdev->skmsg_free_list == NULL || skdev->skreq_free_list == NULL || skdev->in_flight >= skdev->queue_low_water_mark) /* There is still some kind of shortage */ return; - skd_unstop_queue(skdev); + queue_flag_clear(QUEUE_FLAG_STOPPED, skdev->queue); } /* @@ -887,7 +865,7 @@ skip_sg: * we are out of a resource. */ if (req) - skd_stop_queue(skdev); + blk_stop_queue(skdev->queue); } static void skd_end_request_blk(struct skd_device *skdev, @@ -1106,7 +1084,7 @@ static void skd_timer_tick(ulong arg) skdev->timer_countdown = SKD_DRAINING_TIMO; skdev->state = SKD_DRVR_STATE_DRAINING_TIMEOUT; skdev->timo_slot = timo_slot; - skd_stop_queue(skdev); + blk_stop_queue(skdev->queue); timer_func_out: mod_timer(&skdev->timer, (jiffies + HZ)); @@ -1165,7 +1143,7 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) /*start the queue so we can respond with error to requests */ /* wakeup anyone waiting for startup complete */ - skd_start_queue(skdev); + blk_start_queue(skdev->queue); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); break; @@ -1191,7 +1169,7 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) pr_debug("%s:%s:%d Slot drained, starting queue.\n", skdev->name, __func__, __LINE__); skdev->state = SKD_DRVR_STATE_ONLINE; - skd_start_queue(skdev); + blk_start_queue(skdev->queue); return; } if (skdev->timer_countdown > 0) { @@ -1241,7 +1219,7 @@ static void skd_timer_tick_not_online(struct skd_device *skdev) /*start the queue so we can respond with error to requests */ /* wakeup anyone waiting for startup complete */ - skd_start_queue(skdev); + blk_start_queue(skdev->queue); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); break; @@ -3241,7 +3219,7 @@ static void skd_isr_fwstate(struct skd_device *skdev) */ skdev->state = SKD_DRVR_STATE_BUSY_SANITIZE; skdev->timer_countdown = SKD_TIMER_SECONDS(3); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); break; case FIT_SR_DRIVE_BUSY_ERASE: skdev->state = SKD_DRVR_STATE_BUSY_ERASE; @@ -3276,7 +3254,7 @@ static void skd_isr_fwstate(struct skd_device *skdev) case FIT_SR_DRIVE_FAULT: skd_drive_fault(skdev); skd_recover_requests(skdev, 0); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); break; /* PCIe bus returned all Fs? */ @@ -3285,7 +3263,7 @@ static void skd_isr_fwstate(struct skd_device *skdev) skd_name(skdev), state, sense); skd_drive_disappeared(skdev); skd_recover_requests(skdev, 0); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); break; default: /* @@ -3609,7 +3587,7 @@ static void skd_start_device(struct skd_device *skdev) /*start the queue so we can respond with error to requests */ pr_debug("%s:%s:%d starting %s queue\n", skdev->name, __func__, __LINE__, skdev->name); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); break; @@ -3621,7 +3599,7 @@ static void skd_start_device(struct skd_device *skdev) /*start the queue so we can respond with error to requests */ pr_debug("%s:%s:%d starting %s queue to error-out reqs\n", skdev->name, __func__, __LINE__, skdev->name); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); skdev->gendisk_on = -1; wake_up_interruptible(&skdev->waitq); break; @@ -3766,7 +3744,7 @@ static int skd_quiesce_dev(struct skd_device *skdev) case SKD_DRVR_STATE_BUSY_IMMINENT: pr_debug("%s:%s:%d stopping %s queue\n", skdev->name, __func__, __LINE__, skdev->name); - skd_stop_queue(skdev); + blk_stop_queue(skdev->queue); break; case SKD_DRVR_STATE_ONLINE: case SKD_DRVR_STATE_STOPPING: @@ -3835,7 +3813,7 @@ static int skd_unquiesce_dev(struct skd_device *skdev) pr_debug("%s:%s:%d starting %s queue\n", skdev->name, __func__, __LINE__, skdev->name); pr_info("(%s): STEC s1120 ONLINE\n", skd_name(skdev)); - skd_start_queue(skdev); + blk_start_queue(skdev->queue); skdev->gendisk_on = 1; wake_up_interruptible(&skdev->waitq); break; @@ -4620,7 +4598,7 @@ static int skd_cons_disk(struct skd_device *skdev) spin_lock_irqsave(&skdev->lock, flags); pr_debug("%s:%s:%d stopping %s queue\n", skdev->name, __func__, __LINE__, skdev->name); - skd_stop_queue(skdev); + blk_stop_queue(skdev->queue); spin_unlock_irqrestore(&skdev->lock, flags); err_out: -- cgit v1.2.3 From 38d4a1bb994e87057bc8b59e393931904b6b8bc0 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 1 Nov 2013 15:05:10 -0400 Subject: skd: more removal of bio-based code Remove skd_flush_cmd structure and skd_flush_slab. Remove skd_end_request wrapper around skd_end_request_blk. Remove skd_requeue_request, use blk_requeue_request directly. Cleanup some comments (remove "bio" info) and whitespace. Signed-off-by: Mike Snitzer Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 91 +++++++++++------------------------------------- 1 file changed, 20 insertions(+), 71 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index d404d7646d9c..5dc5b39e5b85 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -86,7 +86,7 @@ enum { MODULE_AUTHOR("bug-reports: support@stec-inc.com"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("STEC s1120 PCIe SSD block/BIO driver (b" DRV_BUILD_ID ")"); +MODULE_DESCRIPTION("STEC s1120 PCIe SSD block driver (b" DRV_BUILD_ID ")"); MODULE_VERSION(DRV_VERSION "-" DRV_BUILD_ID); #define PCI_VENDOR_ID_STEC 0x1B39 @@ -352,21 +352,8 @@ struct skd_device { u32 timo_slot; - struct work_struct completion_worker; -}; - -#define SKD_FLUSH_JOB "skd-flush-jobs" -struct kmem_cache *skd_flush_slab; -/* - * These commands hold "nonzero size FLUSH bios", - * which are enqueud in skdev->flush_list during - * completion of "zero size FLUSH commands". - * It will be active in biomode. - */ -struct skd_flush_cmd { - void *cmd; - struct list_head flist; + struct work_struct completion_worker; }; #define SKD_WRITEL(DEV, VAL, OFF) skd_reg_write32(DEV, VAL, OFF) @@ -541,7 +528,7 @@ skd_prep_rw_cdb(struct skd_scsi_request *scsi_req, static void skd_prep_zerosize_flush_cdb(struct skd_scsi_request *scsi_req, - struct skd_request_context *skreq) + struct skd_request_context *skreq) { skreq->flush_cmd = 1; @@ -559,9 +546,9 @@ skd_prep_zerosize_flush_cdb(struct skd_scsi_request *scsi_req, static void skd_prep_discard_cdb(struct skd_scsi_request *scsi_req, - struct skd_request_context *skreq, - struct page *page, - u32 lba, u32 count) + struct skd_request_context *skreq, + struct page *page, + u32 lba, u32 count) { char *buf; unsigned long len; @@ -655,10 +642,7 @@ static void skd_request_fn(struct request_queue *q) skdev->name, __func__, __LINE__, req, lba, lba, count, count, data_dir); - /* At this point we know there is a request - * (from our bio q or req q depending on the way - * the driver is built do checks for resources. - */ + /* At this point we know there is a request */ /* Are too many requets already in progress? */ if (skdev->in_flight >= skdev->cur_max_queue_depth) { @@ -693,7 +677,7 @@ static void skd_request_fn(struct request_queue *q) skreq->discard_page = 0; /* - * OK to now dequeue request from either bio or q. + * OK to now dequeue request from q. * * At this point we are comitted to either start or reject * the native request. Note that skd_request_context is @@ -868,15 +852,15 @@ skip_sg: blk_stop_queue(skdev->queue); } -static void skd_end_request_blk(struct skd_device *skdev, - struct skd_request_context *skreq, int error) +static void skd_end_request(struct skd_device *skdev, + struct skd_request_context *skreq, int error) { struct request *req = skreq->req; unsigned int io_flags = req->cmd_flags; if ((io_flags & REQ_DISCARD) && (skreq->discard_page == 1)) { - pr_debug("%s:%s:%d skd_end_request_blk, free the page!", + pr_debug("%s:%s:%d, free the page!", skdev->name, __func__, __LINE__); free_page((unsigned long)req->buffer); req->buffer = NULL; @@ -898,7 +882,7 @@ static void skd_end_request_blk(struct skd_device *skdev, } static int skd_preop_sg_list(struct skd_device *skdev, - struct skd_request_context *skreq) + struct skd_request_context *skreq) { struct request *req = skreq->req; int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; @@ -961,7 +945,7 @@ static int skd_preop_sg_list(struct skd_device *skdev, } static void skd_postop_sg_list(struct skd_device *skdev, - struct skd_request_context *skreq) + struct skd_request_context *skreq) { int writing = skreq->sg_data_dir == SKD_DATA_DIR_HOST_TO_CARD; int pci_dir = writing ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE; @@ -976,12 +960,6 @@ static void skd_postop_sg_list(struct skd_device *skdev, pci_unmap_sg(skdev->pdev, &skreq->sg[0], skreq->n_sg, pci_dir); } -static void skd_end_request(struct skd_device *skdev, - struct skd_request_context *skreq, int error) -{ - skd_end_request_blk(skdev, skreq, error); -} - static void skd_request_fn_not_online(struct request_queue *q) { struct skd_device *skdev = q->queuedata; @@ -1525,7 +1503,7 @@ static int skd_sg_io_obtain_skspcl(struct skd_device *skdev, struct skd_special_context *skspcl = NULL; int rc; - for (;; ) { + for (;;) { ulong flags; spin_lock_irqsave(&skdev->lock, flags); @@ -2300,10 +2278,6 @@ static void skd_complete_other(struct skd_device *skdev, volatile struct fit_completion_entry_v1 *skcomp, volatile struct fit_comp_error_info *skerr); - -static void skd_requeue_request(struct skd_device *skdev, - struct skd_request_context *skreq); - struct sns_info { u8 type; u8 stat; @@ -2349,9 +2323,9 @@ static struct sns_info skd_chkstat_table[] = { * type and stat, ignore key, asc, ascq. */ -static enum skd_check_status_action skd_check_status(struct skd_device *skdev, - u8 cmp_status, - volatile struct fit_comp_error_info *skerr) +static enum skd_check_status_action +skd_check_status(struct skd_device *skdev, + u8 cmp_status, volatile struct fit_comp_error_info *skerr) { int i, n; @@ -2424,7 +2398,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev, case SKD_CHECK_STATUS_BUSY_IMMINENT: skd_log_skreq(skdev, skreq, "retry(busy)"); - skd_requeue_request(skdev, skreq); + blk_requeue_request(skdev->queue, skreq->req); pr_info("(%s) drive BUSY imminent\n", skd_name(skdev)); skdev->state = SKD_DRVR_STATE_BUSY_IMMINENT; skdev->timer_countdown = SKD_TIMER_MINUTES(20); @@ -2434,7 +2408,7 @@ static void skd_resolve_req_exception(struct skd_device *skdev, case SKD_CHECK_STATUS_REQUEUE_REQUEST: if ((unsigned long) ++skreq->req->special < SKD_MAX_RETRIES) { skd_log_skreq(skdev, skreq, "retry"); - skd_requeue_request(skdev, skreq); + blk_requeue_request(skdev->queue, skreq->req); break; } /* fall through to report error */ @@ -2446,14 +2420,6 @@ static void skd_resolve_req_exception(struct skd_device *skdev, } } -static void skd_requeue_request(struct skd_device *skdev, - struct skd_request_context *skreq) -{ - blk_requeue_request(skdev->queue, skreq->req); -} - - - /* assume spinlock is already held */ static void skd_release_skreq(struct skd_device *skdev, struct skd_request_context *skreq) @@ -2998,7 +2964,6 @@ static void skd_release_special(struct skd_device *skdev, int i, was_depleted; for (i = 0; i < skspcl->req.n_sg; i++) { - struct page *page = sg_page(&skspcl->req.sg[i]); __free_page(page); } @@ -3141,7 +3106,6 @@ static skd_isr(int irq, void *ptr) return rc; } - static void skd_drive_fault(struct skd_device *skdev) { skdev->state = SKD_DRVR_STATE_FAULT; @@ -3297,7 +3261,7 @@ static void skd_recover_requests(struct skd_device *skdev, int requeue) if (requeue && (unsigned long) ++skreq->req->special < SKD_MAX_RETRIES) - skd_requeue_request(skdev, skreq); + blk_requeue_request(skdev->queue, skreq->req); else skd_end_request(skdev, skreq, -EIO); @@ -3305,8 +3269,6 @@ static void skd_recover_requests(struct skd_device *skdev, int requeue) skreq->state = SKD_REQ_STATE_IDLE; skreq->id += SKD_ID_INCR; - - } if (i > 0) skreq[-1].next = skreq; @@ -3879,7 +3841,6 @@ static irqreturn_t skd_comp_q(int irq, void *skd_host_data) SKD_WRITEL(skdev, FIT_ISH_COMPLETION_POSTED, FIT_INT_STATUS_HOST); deferred = skd_isr_completion_posted(skdev, skd_isr_comp_limit, &flush_enqueued); - if (flush_enqueued) skd_request_fn(skdev->queue); @@ -5450,15 +5411,6 @@ static int __init skd_init(void) skd_isr_type = SKD_IRQ_DEFAULT; } - skd_flush_slab = kmem_cache_create(SKD_FLUSH_JOB, - sizeof(struct skd_flush_cmd), - 0, 0, NULL); - - if (!skd_flush_slab) { - pr_err("failed to allocated flush slab.\n"); - return -ENOMEM; - } - if (skd_max_queue_depth < 1 || skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { pr_info( @@ -5507,7 +5459,6 @@ static int __init skd_init(void) skd_major = rc; return pci_register_driver(&skd_driver); - } static void __exit skd_exit(void) @@ -5516,8 +5467,6 @@ static void __exit skd_exit(void) unregister_blkdev(skd_major, DRV_NAME); pci_unregister_driver(&skd_driver); - - kmem_cache_destroy(skd_flush_slab); } module_init(skd_init); -- cgit v1.2.3 From a073ae953ee20b33c8463f76d563fd7e2851c0ac Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:36:59 +0100 Subject: skd: fix unregister_blkdev() placement register_blkdev() is called before pci_register_driver() in skd_init() so unregister_blkdev() should be called after pci_unregister_driver() in skd_exit(). Fix it. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 5dc5b39e5b85..6f09bca3a24f 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -5465,8 +5465,8 @@ static void __exit skd_exit(void) { pr_info(PFX " v%s-b%s unloading\n", DRV_VERSION, DRV_BUILD_ID); - unregister_blkdev(skd_major, DRV_NAME); pci_unregister_driver(&skd_driver); + unregister_blkdev(skd_major, DRV_NAME); } module_init(skd_init); -- cgit v1.2.3 From 2b91c55222a0b2381e12328ca8cc60e6a823a998 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:00 +0100 Subject: skd: fix error paths in skd_init() Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 6f09bca3a24f..8c96d182601d 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -5396,7 +5396,7 @@ static void skd_log_skreq(struct skd_device *skdev, static int __init skd_init(void) { - int rc = 0; + int rc = -ENOMEM; pr_info(PFX " v%s-b%s loaded\n", DRV_VERSION, DRV_BUILD_ID); @@ -5454,11 +5454,21 @@ static int __init skd_init(void) /* Obtain major device number. */ rc = register_blkdev(0, DRV_NAME); if (rc < 0) - return rc; + goto err_register_blkdev; skd_major = rc; - return pci_register_driver(&skd_driver); + rc = pci_register_driver(&skd_driver); + if (rc < 0) + goto err_pci_register_driver; + + return rc; + +err_pci_register_driver: + unregister_blkdev(skd_major, DRV_NAME); + +err_register_blkdev: + return rc; } static void __exit skd_exit(void) -- cgit v1.2.3 From fbed149ab328b72f501a3344ab4f20f712c63392 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:01 +0100 Subject: skd: fix error messages in skd_init() * change priority level from KERN_INFO to KERN_ERR * add "skd: " prefix * do minor CodingStyle fixes Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 8c96d182601d..99d5d1251c45 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -5406,47 +5406,44 @@ static int __init skd_init(void) case SKD_IRQ_MSIX: break; default: - pr_info("skd_isr_type %d invalid, re-set to %d\n", + pr_err(PFX "skd_isr_type %d invalid, re-set to %d\n", skd_isr_type, SKD_IRQ_DEFAULT); skd_isr_type = SKD_IRQ_DEFAULT; } - if (skd_max_queue_depth < 1 - || skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { - pr_info( - "skd_max_queue_depth %d invalid, re-set to %d\n", + if (skd_max_queue_depth < 1 || + skd_max_queue_depth > SKD_MAX_QUEUE_DEPTH) { + pr_err(PFX "skd_max_queue_depth %d invalid, re-set to %d\n", skd_max_queue_depth, SKD_MAX_QUEUE_DEPTH_DEFAULT); skd_max_queue_depth = SKD_MAX_QUEUE_DEPTH_DEFAULT; } if (skd_max_req_per_msg < 1 || skd_max_req_per_msg > 14) { - pr_info( - "skd_max_req_per_msg %d invalid, re-set to %d\n", + pr_err(PFX "skd_max_req_per_msg %d invalid, re-set to %d\n", skd_max_req_per_msg, SKD_MAX_REQ_PER_MSG_DEFAULT); skd_max_req_per_msg = SKD_MAX_REQ_PER_MSG_DEFAULT; } if (skd_sgs_per_request < 1 || skd_sgs_per_request > 4096) { - pr_info( - "skd_sg_per_request %d invalid, re-set to %d\n", + pr_err(PFX "skd_sg_per_request %d invalid, re-set to %d\n", skd_sgs_per_request, SKD_N_SG_PER_REQ_DEFAULT); skd_sgs_per_request = SKD_N_SG_PER_REQ_DEFAULT; } if (skd_dbg_level < 0 || skd_dbg_level > 2) { - pr_info("skd_dbg_level %d invalid, re-set to %d\n", + pr_err(PFX "skd_dbg_level %d invalid, re-set to %d\n", skd_dbg_level, 0); skd_dbg_level = 0; } if (skd_isr_comp_limit < 0) { - pr_info("skd_isr_comp_limit %d invalid, set to %d\n", + pr_err(PFX "skd_isr_comp_limit %d invalid, set to %d\n", skd_isr_comp_limit, 0); skd_isr_comp_limit = 0; } if (skd_max_pass_thru < 1 || skd_max_pass_thru > 50) { - pr_info("skd_max_pass_thru %d invalid, re-set to %d\n", + pr_err(PFX "skd_max_pass_thru %d invalid, re-set to %d\n", skd_max_pass_thru, SKD_N_SPECIAL_CONTEXT); skd_max_pass_thru = SKD_N_SPECIAL_CONTEXT; } -- cgit v1.2.3 From b8df6647c248db457f1c2fb4f0f6350beaf16f9e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:02 +0100 Subject: skd: register block device only if some devices are present Register block device in skd_pci_probe() instead of in skd_init() so it is registered only if some devices are present (currently it is always registered when the driver is loaded). Please note that this change depends on the fact that register_blkdev(0, ...) never returns 0. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 99d5d1251c45..9ff34be89f99 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -4899,6 +4899,14 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } + if (!skd_major) { + rc = register_blkdev(0, DRV_NAME); + if (rc < 0) + goto err_out_regions; + BUG_ON(!rc); + skd_major = rc; + } + skdev = skd_construct(pdev); if (skdev == NULL) { rc = -ENOMEM; @@ -5396,8 +5404,6 @@ static void skd_log_skreq(struct skd_device *skdev, static int __init skd_init(void) { - int rc = -ENOMEM; - pr_info(PFX " v%s-b%s loaded\n", DRV_VERSION, DRV_BUILD_ID); switch (skd_isr_type) { @@ -5448,24 +5454,7 @@ static int __init skd_init(void) skd_max_pass_thru = SKD_N_SPECIAL_CONTEXT; } - /* Obtain major device number. */ - rc = register_blkdev(0, DRV_NAME); - if (rc < 0) - goto err_register_blkdev; - - skd_major = rc; - - rc = pci_register_driver(&skd_driver); - if (rc < 0) - goto err_pci_register_driver; - - return rc; - -err_pci_register_driver: - unregister_blkdev(skd_major, DRV_NAME); - -err_register_blkdev: - return rc; + return pci_register_driver(&skd_driver); } static void __exit skd_exit(void) @@ -5473,7 +5462,9 @@ static void __exit skd_exit(void) pr_info(PFX " v%s-b%s unloading\n", DRV_VERSION, DRV_BUILD_ID); pci_unregister_driver(&skd_driver); - unregister_blkdev(skd_major, DRV_NAME); + + if (skd_major) + unregister_blkdev(skd_major, DRV_NAME); } module_init(skd_init); -- cgit v1.2.3 From 43504631d04253d9866b9fbd2e06aed2e88a692b Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:03 +0100 Subject: skd: remove SCSI subsystem specific includes This is not a SCSI host driver so remove SCSI subsystem specific includes. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 9ff34be89f99..47d8a6a0a0cf 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -42,9 +42,6 @@ #include #include #include -#include -#include -#include #include #include #include -- cgit v1.2.3 From 4ca90b533278f15849287b5b6c0c7dc45b134cde Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:04 +0100 Subject: skd: use Use instead of . Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 47d8a6a0a0cf..e3dfd0dae44a 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include "skd_s1120.h" -- cgit v1.2.3 From ebedd16dab5e7cf22fb1156b74fa53f0233389a7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:05 +0100 Subject: skd: remove redundant skdev->pdev assignment from skd_pci_probe() skdev->pdev is set to pdev twice in skd_pci_probe(), first time through skd_construct() call and the second time directly in the function. Remove the second assignment as it is not needed. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index e3dfd0dae44a..70118a12eb37 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -4925,7 +4925,7 @@ static int skd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, skdev); - skdev->pdev = pdev; + skdev->disk->driverfs_dev = &pdev->dev; for (i = 0; i < SKD_MAX_BARS; i++) { -- cgit v1.2.3 From 7f74e5e94477b7b859c239661399af1fe37927f8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:06 +0100 Subject: skd: remove SKD_OMIT_FROM_SRC_DIST ifdefs SKD_OMIT_FROM_SRC_DIST is never defined. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_s1120.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_s1120.h b/drivers/block/skd_s1120.h index bf01941cdd62..426581e6d170 100644 --- a/drivers/block/skd_s1120.h +++ b/drivers/block/skd_s1120.h @@ -21,11 +21,9 @@ #define FIT_QCMD_QID_MASK (0x3 << 1) #define FIT_QCMD_QID0 (0x0 << 1) #define FIT_QCMD_QID_NORMAL FIT_QCMD_QID0 -#ifndef SKD_OMIT_FROM_SRC_DIST #define FIT_QCMD_QID1 (0x1 << 1) #define FIT_QCMD_QID2 (0x2 << 1) #define FIT_QCMD_QID3 (0x3 << 1) -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_QCMD_FLUSH_QUEUE (0ull) /* add QID */ #define FIT_QCMD_MSGSIZE_MASK (0x3 << 4) #define FIT_QCMD_MSGSIZE_64 (0x0 << 4) @@ -39,13 +37,9 @@ * Control, 32-bit r/w */ #define FIT_CONTROL 0x500u -#ifndef SKD_OMIT_FROM_SRC_DIST #define FIT_CR_HARD_RESET (1u << 0u) -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_CR_SOFT_RESET (1u << 1u) -#ifndef SKD_OMIT_FROM_SRC_DIST #define FIT_CR_DIS_TIMESTAMPS (1u << 6u) -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_CR_ENABLE_INTERRUPTS (1u << 7u) /* @@ -53,10 +47,8 @@ */ #define FIT_STATUS 0x510u #define FIT_SR_DRIVE_STATE_MASK 0x000000FFu -#ifndef SKD_OMIT_FROM_SRC_DIST #define FIT_SR_SIGNATURE (0xFF << 8) #define FIT_SR_PIO_DMA (1 << 16) -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_SR_DRIVE_OFFLINE 0x00 #define FIT_SR_DRIVE_INIT 0x01 /* #define FIT_SR_DRIVE_READY 0x02 */ @@ -74,14 +66,12 @@ #define FIT_SR_DEVICE_MISSING 0xFF #define FIT_SR__RESERVED 0xFFFFFF00u -#ifndef SKD_OMIT_FROM_SRC_DIST /* * FIT_STATUS - Status register data definition */ #define FIT_SR_STATE_MASK (0xFF << 0) #define FIT_SR_SIGNATURE (0xFF << 8) #define FIT_SR_PIO_DMA (1 << 16) -#endif /* SKD_OMIT_FROM_SRC_DIST */ /* @@ -189,10 +179,8 @@ #define FIT_MFD_PM_SLEEP 0x17u #define FIT_MFD_CMD_PROGRESS 0x18u -#ifndef SKD_OMIT_FROM_SRC_DIST #define FIT_MTD_DEBUG 0xFEu #define FIT_MFD_DEBUG 0xFFu -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_MFD_MASK (0xFFu) #define FIT_MFD_DATA_MASK (0xFFu) @@ -248,7 +236,6 @@ struct fit_msg_hdr { #define FIT_PROTOCOL_MINOR_VER(mtd_val) ((mtd_val >> 16) & 0xF) #define FIT_PROTOCOL_MAJOR_VER(mtd_val) ((mtd_val >> 20) & 0xF) -#ifndef SKD_OMIT_FROM_SRC_DIST /* * Format of a completion entry. The completion queue is circular * and must have at least as many entries as the maximum number @@ -264,7 +251,6 @@ struct fit_msg_hdr { * Command_context is opaque and taken verbatim from the SSDI command. * All other fields are big endian. */ -#endif /* SKD_OMIT_FROM_SRC_DIST */ #define FIT_PROTOCOL_VERSION_0 0 /* -- cgit v1.2.3 From fec23f63115622cfc82ed92e5d9348cb81c69173 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:07 +0100 Subject: skd: cleanup skd_do_inq_page_da() skdev->pdev and skdev->pdev->bus are always different than NULL in skd_do_inq_page_da() so simplify the code accordingly. Also cache skdev->pdev value in pdev variable while at it. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 70118a12eb37..2886a8c3a64d 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -2590,6 +2590,7 @@ static void skd_do_inq_page_da(struct skd_device *skdev, volatile struct fit_comp_error_info *skerr, uint8_t *cdb, uint8_t *buf) { + struct pci_dev *pdev = skdev->pdev; unsigned max_bytes; struct driver_inquiry_data inq; u16 val; @@ -2601,36 +2602,22 @@ static void skd_do_inq_page_da(struct skd_device *skdev, inq.page_code = DRIVER_INQ_EVPD_PAGE_CODE; - if (skdev->pdev && skdev->pdev->bus) { - skd_get_link_info(skdev->pdev, - &inq.pcie_link_speed, &inq.pcie_link_lanes); - inq.pcie_bus_number = cpu_to_be16(skdev->pdev->bus->number); - inq.pcie_device_number = PCI_SLOT(skdev->pdev->devfn); - inq.pcie_function_number = PCI_FUNC(skdev->pdev->devfn); + skd_get_link_info(pdev, &inq.pcie_link_speed, &inq.pcie_link_lanes); + inq.pcie_bus_number = cpu_to_be16(pdev->bus->number); + inq.pcie_device_number = PCI_SLOT(pdev->devfn); + inq.pcie_function_number = PCI_FUNC(pdev->devfn); - pci_read_config_word(skdev->pdev, PCI_VENDOR_ID, &val); - inq.pcie_vendor_id = cpu_to_be16(val); + pci_read_config_word(pdev, PCI_VENDOR_ID, &val); + inq.pcie_vendor_id = cpu_to_be16(val); - pci_read_config_word(skdev->pdev, PCI_DEVICE_ID, &val); - inq.pcie_device_id = cpu_to_be16(val); + pci_read_config_word(pdev, PCI_DEVICE_ID, &val); + inq.pcie_device_id = cpu_to_be16(val); - pci_read_config_word(skdev->pdev, PCI_SUBSYSTEM_VENDOR_ID, - &val); - inq.pcie_subsystem_vendor_id = cpu_to_be16(val); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &val); + inq.pcie_subsystem_vendor_id = cpu_to_be16(val); - pci_read_config_word(skdev->pdev, PCI_SUBSYSTEM_ID, &val); - inq.pcie_subsystem_device_id = cpu_to_be16(val); - } else { - inq.pcie_bus_number = 0xFFFF; - inq.pcie_device_number = 0xFF; - inq.pcie_function_number = 0xFF; - inq.pcie_link_speed = 0xFF; - inq.pcie_link_lanes = 0xFF; - inq.pcie_vendor_id = 0xFFFF; - inq.pcie_device_id = 0xFFFF; - inq.pcie_subsystem_vendor_id = 0xFFFF; - inq.pcie_subsystem_device_id = 0xFFFF; - } + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &val); + inq.pcie_subsystem_device_id = cpu_to_be16(val); /* Driver version, fixed lenth, padded with spaces on the right */ inq.driver_version_length = sizeof(inq.driver_version); -- cgit v1.2.3 From 542d7b0015b8cb30d7c0772657408c6a6e9a8675 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:08 +0100 Subject: skd: reorder construct/destruct code Reorder placement of skd_construct(), skd_cons_sg_list(), skd_destruct() and skd_free_sg_list() functions. Then remove no longer needed function prototypes. Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_main.c | 305 ++++++++++++++++++++++------------------------- 1 file changed, 141 insertions(+), 164 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 2886a8c3a64d..9199c93be926 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -449,7 +449,6 @@ MODULE_PARM_DESC(skd_isr_comp_limit, "s1120 isr comp limit (0=none) default=4"); /* Major device number dynamically assigned. */ static u32 skd_major; -static struct skd_device *skd_construct(struct pci_dev *pdev); static void skd_destruct(struct skd_device *skdev); static const struct block_device_operations skd_blockdev_ops; static void skd_send_fitmsg(struct skd_device *skdev, @@ -4115,96 +4114,6 @@ static void skd_release_irq(struct skd_device *skdev) ***************************************************************************** */ -static int skd_cons_skcomp(struct skd_device *skdev); -static int skd_cons_skmsg(struct skd_device *skdev); -static int skd_cons_skreq(struct skd_device *skdev); -static int skd_cons_skspcl(struct skd_device *skdev); -static int skd_cons_sksb(struct skd_device *skdev); -static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, - u32 n_sg, - dma_addr_t *ret_dma_addr); -static int skd_cons_disk(struct skd_device *skdev); - -#define SKD_N_DEV_TABLE 16u -static u32 skd_next_devno; - -static struct skd_device *skd_construct(struct pci_dev *pdev) -{ - struct skd_device *skdev; - int blk_major = skd_major; - int rc; - - skdev = kzalloc(sizeof(*skdev), GFP_KERNEL); - - if (!skdev) { - pr_err(PFX "(%s): memory alloc failure\n", - pci_name(pdev)); - return NULL; - } - - skdev->state = SKD_DRVR_STATE_LOAD; - skdev->pdev = pdev; - skdev->devno = skd_next_devno++; - skdev->major = blk_major; - skdev->irq_type = skd_isr_type; - sprintf(skdev->name, DRV_NAME "%d", skdev->devno); - skdev->dev_max_queue_depth = 0; - - skdev->num_req_context = skd_max_queue_depth; - skdev->num_fitmsg_context = skd_max_queue_depth; - skdev->n_special = skd_max_pass_thru; - skdev->cur_max_queue_depth = 1; - skdev->queue_low_water_mark = 1; - skdev->proto_ver = 99; - skdev->sgs_per_request = skd_sgs_per_request; - skdev->dbg_level = skd_dbg_level; - - atomic_set(&skdev->device_count, 0); - - spin_lock_init(&skdev->lock); - - INIT_WORK(&skdev->completion_worker, skd_completion_worker); - - pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); - rc = skd_cons_skcomp(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); - rc = skd_cons_skmsg(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); - rc = skd_cons_skreq(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); - rc = skd_cons_skspcl(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); - rc = skd_cons_sksb(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); - rc = skd_cons_disk(skdev); - if (rc < 0) - goto err_out; - - pr_debug("%s:%s:%d VICTORY\n", skdev->name, __func__, __LINE__); - return skdev; - -err_out: - pr_debug("%s:%s:%d construct failed\n", - skdev->name, __func__, __LINE__); - skd_destruct(skdev); - return NULL; -} - static int skd_cons_skcomp(struct skd_device *skdev) { int rc = 0; @@ -4292,6 +4201,35 @@ err_out: return rc; } +static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, + u32 n_sg, + dma_addr_t *ret_dma_addr) +{ + struct fit_sg_descriptor *sg_list; + u32 nbytes; + + nbytes = sizeof(*sg_list) * n_sg; + + sg_list = pci_alloc_consistent(skdev->pdev, nbytes, ret_dma_addr); + + if (sg_list != NULL) { + uint64_t dma_address = *ret_dma_addr; + u32 i; + + memset(sg_list, 0, nbytes); + + for (i = 0; i < n_sg - 1; i++) { + uint64_t ndp_off; + ndp_off = (i + 1) * sizeof(struct fit_sg_descriptor); + + sg_list[i].next_desc_ptr = dma_address + ndp_off; + } + sg_list[i].next_desc_ptr = 0LL; + } + + return sg_list; +} + static int skd_cons_skreq(struct skd_device *skdev) { int rc = 0; @@ -4465,35 +4403,6 @@ err_out: return rc; } -static struct fit_sg_descriptor *skd_cons_sg_list(struct skd_device *skdev, - u32 n_sg, - dma_addr_t *ret_dma_addr) -{ - struct fit_sg_descriptor *sg_list; - u32 nbytes; - - nbytes = sizeof(*sg_list) * n_sg; - - sg_list = pci_alloc_consistent(skdev->pdev, nbytes, ret_dma_addr); - - if (sg_list != NULL) { - uint64_t dma_address = *ret_dma_addr; - u32 i; - - memset(sg_list, 0, nbytes); - - for (i = 0; i < n_sg - 1; i++) { - uint64_t ndp_off; - ndp_off = (i + 1) * sizeof(struct fit_sg_descriptor); - - sg_list[i].next_desc_ptr = dma_address + ndp_off; - } - sg_list[i].next_desc_ptr = 0LL; - } - - return sg_list; -} - static int skd_cons_disk(struct skd_device *skdev) { int rc = 0; @@ -4550,50 +4459,92 @@ err_out: return rc; } -/* - ***************************************************************************** - * DESTRUCT (FREE) - ***************************************************************************** - */ - -static void skd_free_skcomp(struct skd_device *skdev); -static void skd_free_skmsg(struct skd_device *skdev); -static void skd_free_skreq(struct skd_device *skdev); -static void skd_free_skspcl(struct skd_device *skdev); -static void skd_free_sksb(struct skd_device *skdev); -static void skd_free_sg_list(struct skd_device *skdev, - struct fit_sg_descriptor *sg_list, - u32 n_sg, dma_addr_t dma_addr); -static void skd_free_disk(struct skd_device *skdev); +#define SKD_N_DEV_TABLE 16u +static u32 skd_next_devno; -static void skd_destruct(struct skd_device *skdev) +static struct skd_device *skd_construct(struct pci_dev *pdev) { - if (skdev == NULL) - return; + struct skd_device *skdev; + int blk_major = skd_major; + int rc; + skdev = kzalloc(sizeof(*skdev), GFP_KERNEL); - pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); - skd_free_disk(skdev); + if (!skdev) { + pr_err(PFX "(%s): memory alloc failure\n", + pci_name(pdev)); + return NULL; + } - pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); - skd_free_sksb(skdev); + skdev->state = SKD_DRVR_STATE_LOAD; + skdev->pdev = pdev; + skdev->devno = skd_next_devno++; + skdev->major = blk_major; + skdev->irq_type = skd_isr_type; + sprintf(skdev->name, DRV_NAME "%d", skdev->devno); + skdev->dev_max_queue_depth = 0; - pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); - skd_free_skspcl(skdev); + skdev->num_req_context = skd_max_queue_depth; + skdev->num_fitmsg_context = skd_max_queue_depth; + skdev->n_special = skd_max_pass_thru; + skdev->cur_max_queue_depth = 1; + skdev->queue_low_water_mark = 1; + skdev->proto_ver = 99; + skdev->sgs_per_request = skd_sgs_per_request; + skdev->dbg_level = skd_dbg_level; - pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); - skd_free_skreq(skdev); + atomic_set(&skdev->device_count, 0); - pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); - skd_free_skmsg(skdev); + spin_lock_init(&skdev->lock); + + INIT_WORK(&skdev->completion_worker, skd_completion_worker); pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); - skd_free_skcomp(skdev); + rc = skd_cons_skcomp(skdev); + if (rc < 0) + goto err_out; - pr_debug("%s:%s:%d skdev\n", skdev->name, __func__, __LINE__); - kfree(skdev); + pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); + rc = skd_cons_skmsg(skdev); + if (rc < 0) + goto err_out; + + pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); + rc = skd_cons_skreq(skdev); + if (rc < 0) + goto err_out; + + pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); + rc = skd_cons_skspcl(skdev); + if (rc < 0) + goto err_out; + + pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); + rc = skd_cons_sksb(skdev); + if (rc < 0) + goto err_out; + + pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); + rc = skd_cons_disk(skdev); + if (rc < 0) + goto err_out; + + pr_debug("%s:%s:%d VICTORY\n", skdev->name, __func__, __LINE__); + return skdev; + +err_out: + pr_debug("%s:%s:%d construct failed\n", + skdev->name, __func__, __LINE__); + skd_destruct(skdev); + return NULL; } +/* + ***************************************************************************** + * DESTRUCT (FREE) + ***************************************************************************** + */ + static void skd_free_skcomp(struct skd_device *skdev) { if (skdev->skcomp_table != NULL) { @@ -4636,6 +4587,19 @@ static void skd_free_skmsg(struct skd_device *skdev) skdev->skmsg_table = NULL; } +static void skd_free_sg_list(struct skd_device *skdev, + struct fit_sg_descriptor *sg_list, + u32 n_sg, dma_addr_t dma_addr) +{ + if (sg_list != NULL) { + u32 nbytes; + + nbytes = sizeof(*sg_list) * n_sg; + + pci_free_consistent(skdev->pdev, nbytes, sg_list, dma_addr); + } +} + static void skd_free_skreq(struct skd_device *skdev) { u32 i; @@ -4732,19 +4696,6 @@ static void skd_free_sksb(struct skd_device *skdev) skspcl->req.sksg_dma_address = 0; } -static void skd_free_sg_list(struct skd_device *skdev, - struct fit_sg_descriptor *sg_list, - u32 n_sg, dma_addr_t dma_addr) -{ - if (sg_list != NULL) { - u32 nbytes; - - nbytes = sizeof(*sg_list) * n_sg; - - pci_free_consistent(skdev->pdev, nbytes, sg_list, dma_addr); - } -} - static void skd_free_disk(struct skd_device *skdev) { struct gendisk *disk = skdev->disk; @@ -4761,7 +4712,33 @@ static void skd_free_disk(struct skd_device *skdev) skdev->disk = NULL; } +static void skd_destruct(struct skd_device *skdev) +{ + if (skdev == NULL) + return; + + + pr_debug("%s:%s:%d disk\n", skdev->name, __func__, __LINE__); + skd_free_disk(skdev); + + pr_debug("%s:%s:%d sksb\n", skdev->name, __func__, __LINE__); + skd_free_sksb(skdev); + + pr_debug("%s:%s:%d skspcl\n", skdev->name, __func__, __LINE__); + skd_free_skspcl(skdev); + + pr_debug("%s:%s:%d skreq\n", skdev->name, __func__, __LINE__); + skd_free_skreq(skdev); + + pr_debug("%s:%s:%d skmsg\n", skdev->name, __func__, __LINE__); + skd_free_skmsg(skdev); + pr_debug("%s:%s:%d skcomp\n", skdev->name, __func__, __LINE__); + skd_free_skcomp(skdev); + + pr_debug("%s:%s:%d skdev\n", skdev->name, __func__, __LINE__); + kfree(skdev); +} /* ***************************************************************************** -- cgit v1.2.3 From f1a3c6191369632ada5b709997b91a7f15045ff4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Nov 2013 12:37:09 +0100 Subject: skd: fix formatting in skd_s1120.h Cc: Akhil Bhansali Cc: Jeff Moyer Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Jens Axboe --- drivers/block/skd_s1120.h | 230 ++++++++++++++++++++++------------------------ 1 file changed, 110 insertions(+), 120 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/skd_s1120.h b/drivers/block/skd_s1120.h index 426581e6d170..61c757ff0161 100644 --- a/drivers/block/skd_s1120.h +++ b/drivers/block/skd_s1120.h @@ -17,30 +17,29 @@ /* * Q-channel, 64-bit r/w */ -#define FIT_Q_COMMAND 0x400u -#define FIT_QCMD_QID_MASK (0x3 << 1) -#define FIT_QCMD_QID0 (0x0 << 1) -#define FIT_QCMD_QID_NORMAL FIT_QCMD_QID0 -#define FIT_QCMD_QID1 (0x1 << 1) -#define FIT_QCMD_QID2 (0x2 << 1) -#define FIT_QCMD_QID3 (0x3 << 1) -#define FIT_QCMD_FLUSH_QUEUE (0ull) /* add QID */ -#define FIT_QCMD_MSGSIZE_MASK (0x3 << 4) -#define FIT_QCMD_MSGSIZE_64 (0x0 << 4) -#define FIT_QCMD_MSGSIZE_128 (0x1 << 4) -#define FIT_QCMD_MSGSIZE_256 (0x2 << 4) -#define FIT_QCMD_MSGSIZE_512 (0x3 << 4) -#define FIT_QCMD_BASE_ADDRESS_MASK (0xFFFFFFFFFFFFFFC0ull) - +#define FIT_Q_COMMAND 0x400u +#define FIT_QCMD_QID_MASK (0x3 << 1) +#define FIT_QCMD_QID0 (0x0 << 1) +#define FIT_QCMD_QID_NORMAL FIT_QCMD_QID0 +#define FIT_QCMD_QID1 (0x1 << 1) +#define FIT_QCMD_QID2 (0x2 << 1) +#define FIT_QCMD_QID3 (0x3 << 1) +#define FIT_QCMD_FLUSH_QUEUE (0ull) /* add QID */ +#define FIT_QCMD_MSGSIZE_MASK (0x3 << 4) +#define FIT_QCMD_MSGSIZE_64 (0x0 << 4) +#define FIT_QCMD_MSGSIZE_128 (0x1 << 4) +#define FIT_QCMD_MSGSIZE_256 (0x2 << 4) +#define FIT_QCMD_MSGSIZE_512 (0x3 << 4) +#define FIT_QCMD_BASE_ADDRESS_MASK (0xFFFFFFFFFFFFFFC0ull) /* * Control, 32-bit r/w */ -#define FIT_CONTROL 0x500u -#define FIT_CR_HARD_RESET (1u << 0u) -#define FIT_CR_SOFT_RESET (1u << 1u) -#define FIT_CR_DIS_TIMESTAMPS (1u << 6u) -#define FIT_CR_ENABLE_INTERRUPTS (1u << 7u) +#define FIT_CONTROL 0x500u +#define FIT_CR_HARD_RESET (1u << 0u) +#define FIT_CR_SOFT_RESET (1u << 1u) +#define FIT_CR_DIS_TIMESTAMPS (1u << 6u) +#define FIT_CR_ENABLE_INTERRUPTS (1u << 7u) /* * Status, 32-bit, r/o @@ -63,88 +62,82 @@ #define FIT_SR_DRIVE_BUSY_ERASE 0x0B #define FIT_SR_DRIVE_FW_BOOTING 0x0C #define FIT_SR_DRIVE_NEED_FW_DOWNLOAD 0xFE -#define FIT_SR_DEVICE_MISSING 0xFF +#define FIT_SR_DEVICE_MISSING 0xFF #define FIT_SR__RESERVED 0xFFFFFF00u /* * FIT_STATUS - Status register data definition */ -#define FIT_SR_STATE_MASK (0xFF << 0) -#define FIT_SR_SIGNATURE (0xFF << 8) -#define FIT_SR_PIO_DMA (1 << 16) - +#define FIT_SR_STATE_MASK (0xFF << 0) +#define FIT_SR_SIGNATURE (0xFF << 8) +#define FIT_SR_PIO_DMA (1 << 16) /* * Interrupt status, 32-bit r/w1c (w1c ==> write 1 to clear) */ -#define FIT_INT_STATUS_HOST 0x520u -#define FIT_ISH_FW_STATE_CHANGE (1u << 0u) -#define FIT_ISH_COMPLETION_POSTED (1u << 1u) -#define FIT_ISH_MSG_FROM_DEV (1u << 2u) -#define FIT_ISH_UNDEFINED_3 (1u << 3u) -#define FIT_ISH_UNDEFINED_4 (1u << 4u) -#define FIT_ISH_Q0_FULL (1u << 5u) -#define FIT_ISH_Q1_FULL (1u << 6u) -#define FIT_ISH_Q2_FULL (1u << 7u) -#define FIT_ISH_Q3_FULL (1u << 8u) -#define FIT_ISH_QCMD_FIFO_OVERRUN (1u << 9u) -#define FIT_ISH_BAD_EXP_ROM_READ (1u << 10u) - - -#define FIT_INT_DEF_MASK \ - (FIT_ISH_FW_STATE_CHANGE | \ - FIT_ISH_COMPLETION_POSTED | \ - FIT_ISH_MSG_FROM_DEV | \ - FIT_ISH_Q0_FULL | \ - FIT_ISH_Q1_FULL | \ - FIT_ISH_Q2_FULL | \ - FIT_ISH_Q3_FULL | \ - FIT_ISH_QCMD_FIFO_OVERRUN | \ - FIT_ISH_BAD_EXP_ROM_READ) - -#define FIT_INT_QUEUE_FULL \ - (FIT_ISH_Q0_FULL | \ - FIT_ISH_Q1_FULL | \ - FIT_ISH_Q2_FULL | \ - FIT_ISH_Q3_FULL) - - -#define MSI_MSG_NWL_ERROR_0 0x00000000 -#define MSI_MSG_NWL_ERROR_1 0x00000001 -#define MSI_MSG_NWL_ERROR_2 0x00000002 -#define MSI_MSG_NWL_ERROR_3 0x00000003 -#define MSI_MSG_STATE_CHANGE 0x00000004 -#define MSI_MSG_COMPLETION_POSTED 0x00000005 -#define MSI_MSG_MSG_FROM_DEV 0x00000006 -#define MSI_MSG_RESERVED_0 0x00000007 -#define MSI_MSG_RESERVED_1 0x00000008 -#define MSI_MSG_QUEUE_0_FULL 0x00000009 -#define MSI_MSG_QUEUE_1_FULL 0x0000000A -#define MSI_MSG_QUEUE_2_FULL 0x0000000B -#define MSI_MSG_QUEUE_3_FULL 0x0000000C - - - -#define FIT_INT_RESERVED_MASK \ - (FIT_ISH_UNDEFINED_3 | \ - FIT_ISH_UNDEFINED_4) +#define FIT_INT_STATUS_HOST 0x520u +#define FIT_ISH_FW_STATE_CHANGE (1u << 0u) +#define FIT_ISH_COMPLETION_POSTED (1u << 1u) +#define FIT_ISH_MSG_FROM_DEV (1u << 2u) +#define FIT_ISH_UNDEFINED_3 (1u << 3u) +#define FIT_ISH_UNDEFINED_4 (1u << 4u) +#define FIT_ISH_Q0_FULL (1u << 5u) +#define FIT_ISH_Q1_FULL (1u << 6u) +#define FIT_ISH_Q2_FULL (1u << 7u) +#define FIT_ISH_Q3_FULL (1u << 8u) +#define FIT_ISH_QCMD_FIFO_OVERRUN (1u << 9u) +#define FIT_ISH_BAD_EXP_ROM_READ (1u << 10u) + +#define FIT_INT_DEF_MASK \ + (FIT_ISH_FW_STATE_CHANGE | \ + FIT_ISH_COMPLETION_POSTED | \ + FIT_ISH_MSG_FROM_DEV | \ + FIT_ISH_Q0_FULL | \ + FIT_ISH_Q1_FULL | \ + FIT_ISH_Q2_FULL | \ + FIT_ISH_Q3_FULL | \ + FIT_ISH_QCMD_FIFO_OVERRUN | \ + FIT_ISH_BAD_EXP_ROM_READ) + +#define FIT_INT_QUEUE_FULL \ + (FIT_ISH_Q0_FULL | \ + FIT_ISH_Q1_FULL | \ + FIT_ISH_Q2_FULL | \ + FIT_ISH_Q3_FULL) + +#define MSI_MSG_NWL_ERROR_0 0x00000000 +#define MSI_MSG_NWL_ERROR_1 0x00000001 +#define MSI_MSG_NWL_ERROR_2 0x00000002 +#define MSI_MSG_NWL_ERROR_3 0x00000003 +#define MSI_MSG_STATE_CHANGE 0x00000004 +#define MSI_MSG_COMPLETION_POSTED 0x00000005 +#define MSI_MSG_MSG_FROM_DEV 0x00000006 +#define MSI_MSG_RESERVED_0 0x00000007 +#define MSI_MSG_RESERVED_1 0x00000008 +#define MSI_MSG_QUEUE_0_FULL 0x00000009 +#define MSI_MSG_QUEUE_1_FULL 0x0000000A +#define MSI_MSG_QUEUE_2_FULL 0x0000000B +#define MSI_MSG_QUEUE_3_FULL 0x0000000C + +#define FIT_INT_RESERVED_MASK \ + (FIT_ISH_UNDEFINED_3 | \ + FIT_ISH_UNDEFINED_4) + /* * Interrupt mask, 32-bit r/w * Bit definitions are the same as FIT_INT_STATUS_HOST */ -#define FIT_INT_MASK_HOST 0x528u - +#define FIT_INT_MASK_HOST 0x528u /* * Message to device, 32-bit r/w */ -#define FIT_MSG_TO_DEVICE 0x540u +#define FIT_MSG_TO_DEVICE 0x540u /* * Message from device, 32-bit, r/o */ -#define FIT_MSG_FROM_DEVICE 0x548u - +#define FIT_MSG_FROM_DEVICE 0x548u /* * 32-bit messages to/from device, composition/extraction macros @@ -153,52 +146,50 @@ ((((TYPE) & 0xFFu) << 24u) | \ (((PARAM) & 0xFFu) << 16u) | \ (((DATA) & 0xFFFFu) << 0u)) -#define FIT_MXD_TYPE(MXD) (((MXD) >> 24u) & 0xFFu) -#define FIT_MXD_PARAM(MXD) (((MXD) >> 16u) & 0xFFu) -#define FIT_MXD_DATA(MXD) (((MXD) >> 0u) & 0xFFFFu) - +#define FIT_MXD_TYPE(MXD) (((MXD) >> 24u) & 0xFFu) +#define FIT_MXD_PARAM(MXD) (((MXD) >> 16u) & 0xFFu) +#define FIT_MXD_DATA(MXD) (((MXD) >> 0u) & 0xFFFFu) /* * Types of messages to/from device */ -#define FIT_MTD_FITFW_INIT 0x01u -#define FIT_MTD_GET_CMDQ_DEPTH 0x02u -#define FIT_MTD_SET_COMPQ_DEPTH 0x03u -#define FIT_MTD_SET_COMPQ_ADDR 0x04u -#define FIT_MTD_ARM_QUEUE 0x05u -#define FIT_MTD_CMD_LOG_HOST_ID 0x07u -#define FIT_MTD_CMD_LOG_TIME_STAMP_LO 0x08u -#define FIT_MTD_CMD_LOG_TIME_STAMP_HI 0x09u -#define FIT_MFD_SMART_EXCEEDED 0x10u -#define FIT_MFD_POWER_DOWN 0x11u -#define FIT_MFD_OFFLINE 0x12u -#define FIT_MFD_ONLINE 0x13u -#define FIT_MFD_FW_RESTARTING 0x14u -#define FIT_MFD_PM_ACTIVE 0x15u -#define FIT_MFD_PM_STANDBY 0x16u -#define FIT_MFD_PM_SLEEP 0x17u -#define FIT_MFD_CMD_PROGRESS 0x18u - -#define FIT_MTD_DEBUG 0xFEu -#define FIT_MFD_DEBUG 0xFFu +#define FIT_MTD_FITFW_INIT 0x01u +#define FIT_MTD_GET_CMDQ_DEPTH 0x02u +#define FIT_MTD_SET_COMPQ_DEPTH 0x03u +#define FIT_MTD_SET_COMPQ_ADDR 0x04u +#define FIT_MTD_ARM_QUEUE 0x05u +#define FIT_MTD_CMD_LOG_HOST_ID 0x07u +#define FIT_MTD_CMD_LOG_TIME_STAMP_LO 0x08u +#define FIT_MTD_CMD_LOG_TIME_STAMP_HI 0x09u +#define FIT_MFD_SMART_EXCEEDED 0x10u +#define FIT_MFD_POWER_DOWN 0x11u +#define FIT_MFD_OFFLINE 0x12u +#define FIT_MFD_ONLINE 0x13u +#define FIT_MFD_FW_RESTARTING 0x14u +#define FIT_MFD_PM_ACTIVE 0x15u +#define FIT_MFD_PM_STANDBY 0x16u +#define FIT_MFD_PM_SLEEP 0x17u +#define FIT_MFD_CMD_PROGRESS 0x18u + +#define FIT_MTD_DEBUG 0xFEu +#define FIT_MFD_DEBUG 0xFFu #define FIT_MFD_MASK (0xFFu) #define FIT_MFD_DATA_MASK (0xFFu) #define FIT_MFD_MSG(x) (((x) >> 24) & FIT_MFD_MASK) #define FIT_MFD_DATA(x) ((x) & FIT_MFD_MASK) - /* * Extra arg to FIT_MSG_TO_DEVICE, 64-bit r/w * Used to set completion queue address (FIT_MTD_SET_COMPQ_ADDR) * (was Response buffer in docs) */ -#define FIT_MSG_TO_DEVICE_ARG 0x580u +#define FIT_MSG_TO_DEVICE_ARG 0x580u /* * Hardware (ASIC) version, 32-bit r/o */ -#define FIT_HW_VERSION 0x588u +#define FIT_HW_VERSION 0x588u /* * Scatter/gather list descriptor. @@ -213,8 +204,8 @@ struct fit_sg_descriptor { uint64_t next_desc_ptr; }; -#define FIT_SGD_CONTROL_NOT_LAST 0x000u -#define FIT_SGD_CONTROL_LAST 0x40Eu +#define FIT_SGD_CONTROL_NOT_LAST 0x000u +#define FIT_SGD_CONTROL_LAST 0x40Eu /* * Header at the beginning of a FIT message. The header @@ -228,9 +219,9 @@ struct fit_msg_hdr { uint8_t _reserved[62]; }; -#define FIT_PROTOCOL_ID_FIT 1 -#define FIT_PROTOCOL_ID_SSDI 2 -#define FIT_PROTOCOL_ID_SOFIT 3 +#define FIT_PROTOCOL_ID_FIT 1 +#define FIT_PROTOCOL_ID_SSDI 2 +#define FIT_PROTOCOL_ID_SOFIT 3 #define FIT_PROTOCOL_MINOR_VER(mtd_val) ((mtd_val >> 16) & 0xF) @@ -251,7 +242,7 @@ struct fit_msg_hdr { * Command_context is opaque and taken verbatim from the SSDI command. * All other fields are big endian. */ -#define FIT_PROTOCOL_VERSION_0 0 +#define FIT_PROTOCOL_VERSION_0 0 /* * Protocol major version 1 completion entry. @@ -264,8 +255,8 @@ struct fit_completion_entry_v1 { uint8_t status; /* SCSI status */ uint8_t cycle; }; -#define FIT_PROTOCOL_VERSION_1 1 -#define FIT_PROTOCOL_VERSION_CURRENT FIT_PROTOCOL_VERSION_1 +#define FIT_PROTOCOL_VERSION_1 1 +#define FIT_PROTOCOL_VERSION_CURRENT FIT_PROTOCOL_VERSION_1 struct fit_comp_error_info { uint8_t type:7; /* 00: Bits0-6 indicates the type of sense data. */ @@ -293,10 +284,9 @@ struct fit_comp_error_info { /* Task management constants */ -#define SOFT_TASK_SIMPLE 0x00 -#define SOFT_TASK_HEAD_OF_QUEUE 0x01 -#define SOFT_TASK_ORDERED 0x02 - +#define SOFT_TASK_SIMPLE 0x00 +#define SOFT_TASK_HEAD_OF_QUEUE 0x01 +#define SOFT_TASK_ORDERED 0x02 /* Version zero has the last 32 bits reserved, * Version one has the last 32 bits sg_list_len_bytes; -- cgit v1.2.3 From bfe11d6de1c416cea4f3f0f35f864162063ce3fa Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Tue, 29 Oct 2013 18:31:14 +0100 Subject: xen-blkfront: restore the non-persistent data path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When persistent grants were added they were always used, even if the backend doesn't have this feature (there's no harm in always using the same set of pages). This restores the old data path when the backend doesn't have persistent grants, removing the burden of doing a memcpy when it is not actually needed. Signed-off-by: Roger Pau MonnĂ© Reported-by: Felipe Franciosi Cc: Felipe Franciosi Cc: Konrad Rzeszutek Wilk Cc: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk [v2: Fix up whitespace issues] --- drivers/block/xen-blkfront.c | 125 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 25 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5b8a15483a4c..432db1b59b00 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -121,7 +121,8 @@ struct blkfront_info struct work_struct work; struct gnttab_free_callback callback; struct blk_shadow shadow[BLK_RING_SIZE]; - struct list_head persistent_gnts; + struct list_head grants; + struct list_head indirect_pages; unsigned int persistent_gnts_c; unsigned long shadow_free; unsigned int feature_flush; @@ -200,15 +201,17 @@ static int fill_grant_buffer(struct blkfront_info *info, int num) if (!gnt_list_entry) goto out_of_memory; - granted_page = alloc_page(GFP_NOIO); - if (!granted_page) { - kfree(gnt_list_entry); - goto out_of_memory; + if (info->feature_persistent) { + granted_page = alloc_page(GFP_NOIO); + if (!granted_page) { + kfree(gnt_list_entry); + goto out_of_memory; + } + gnt_list_entry->pfn = page_to_pfn(granted_page); } - gnt_list_entry->pfn = page_to_pfn(granted_page); gnt_list_entry->gref = GRANT_INVALID_REF; - list_add(&gnt_list_entry->node, &info->persistent_gnts); + list_add(&gnt_list_entry->node, &info->grants); i++; } @@ -216,9 +219,10 @@ static int fill_grant_buffer(struct blkfront_info *info, int num) out_of_memory: list_for_each_entry_safe(gnt_list_entry, n, - &info->persistent_gnts, node) { + &info->grants, node) { list_del(&gnt_list_entry->node); - __free_page(pfn_to_page(gnt_list_entry->pfn)); + if (info->feature_persistent) + __free_page(pfn_to_page(gnt_list_entry->pfn)); kfree(gnt_list_entry); i--; } @@ -227,13 +231,14 @@ out_of_memory: } static struct grant *get_grant(grant_ref_t *gref_head, + unsigned long pfn, struct blkfront_info *info) { struct grant *gnt_list_entry; unsigned long buffer_mfn; - BUG_ON(list_empty(&info->persistent_gnts)); - gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, + BUG_ON(list_empty(&info->grants)); + gnt_list_entry = list_first_entry(&info->grants, struct grant, node); list_del(&gnt_list_entry->node); @@ -245,6 +250,10 @@ static struct grant *get_grant(grant_ref_t *gref_head, /* Assign a gref to this page */ gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); BUG_ON(gnt_list_entry->gref == -ENOSPC); + if (!info->feature_persistent) { + BUG_ON(!pfn); + gnt_list_entry->pfn = pfn; + } buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); gnttab_grant_foreign_access_ref(gnt_list_entry->gref, info->xbdev->otherend_id, @@ -480,22 +489,34 @@ static int blkif_queue_request(struct request *req) if ((ring_req->operation == BLKIF_OP_INDIRECT) && (i % SEGS_PER_INDIRECT_FRAME == 0)) { + unsigned long pfn; + if (segments) kunmap_atomic(segments); n = i / SEGS_PER_INDIRECT_FRAME; - gnt_list_entry = get_grant(&gref_head, info); + if (!info->feature_persistent) { + struct page *indirect_page; + + /* Fetch a pre-allocated page to use for indirect grefs */ + BUG_ON(list_empty(&info->indirect_pages)); + indirect_page = list_first_entry(&info->indirect_pages, + struct page, lru); + list_del(&indirect_page->lru); + pfn = page_to_pfn(indirect_page); + } + gnt_list_entry = get_grant(&gref_head, pfn, info); info->shadow[id].indirect_grants[n] = gnt_list_entry; segments = kmap_atomic(pfn_to_page(gnt_list_entry->pfn)); ring_req->u.indirect.indirect_grefs[n] = gnt_list_entry->gref; } - gnt_list_entry = get_grant(&gref_head, info); + gnt_list_entry = get_grant(&gref_head, page_to_pfn(sg_page(sg)), info); ref = gnt_list_entry->gref; info->shadow[id].grants_used[i] = gnt_list_entry; - if (rq_data_dir(req)) { + if (rq_data_dir(req) && info->feature_persistent) { char *bvec_data; void *shared_data; @@ -907,21 +928,36 @@ static void blkif_free(struct blkfront_info *info, int suspend) blk_stop_queue(info->rq); /* Remove all persistent grants */ - if (!list_empty(&info->persistent_gnts)) { + if (!list_empty(&info->grants)) { list_for_each_entry_safe(persistent_gnt, n, - &info->persistent_gnts, node) { + &info->grants, node) { list_del(&persistent_gnt->node); if (persistent_gnt->gref != GRANT_INVALID_REF) { gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); info->persistent_gnts_c--; } - __free_page(pfn_to_page(persistent_gnt->pfn)); + if (info->feature_persistent) + __free_page(pfn_to_page(persistent_gnt->pfn)); kfree(persistent_gnt); } } BUG_ON(info->persistent_gnts_c != 0); + /* + * Remove indirect pages, this only happens when using indirect + * descriptors but not persistent grants + */ + if (!list_empty(&info->indirect_pages)) { + struct page *indirect_page, *n; + + BUG_ON(info->feature_persistent); + list_for_each_entry_safe(indirect_page, n, &info->indirect_pages, lru) { + list_del(&indirect_page->lru); + __free_page(indirect_page); + } + } + for (i = 0; i < BLK_RING_SIZE; i++) { /* * Clear persistent grants present in requests already @@ -936,7 +972,8 @@ static void blkif_free(struct blkfront_info *info, int suspend) for (j = 0; j < segs; j++) { persistent_gnt = info->shadow[i].grants_used[j]; gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); - __free_page(pfn_to_page(persistent_gnt->pfn)); + if (info->feature_persistent) + __free_page(pfn_to_page(persistent_gnt->pfn)); kfree(persistent_gnt); } @@ -995,7 +1032,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, nseg = s->req.operation == BLKIF_OP_INDIRECT ? s->req.u.indirect.nr_segments : s->req.u.rw.nr_segments; - if (bret->operation == BLKIF_OP_READ) { + if (bret->operation == BLKIF_OP_READ && info->feature_persistent) { /* * Copy the data received from the backend into the bvec. * Since bv_offset can be different than 0, and bv_len different @@ -1023,7 +1060,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, * we add it at the head of the list, so it will be * reused first. */ - list_add(&s->grants_used[i]->node, &info->persistent_gnts); + if (!info->feature_persistent) + pr_alert_ratelimited("backed has not unmapped grant: %u\n", + s->grants_used[i]->gref); + list_add(&s->grants_used[i]->node, &info->grants); info->persistent_gnts_c++; } else { /* @@ -1034,19 +1074,29 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, */ gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL); s->grants_used[i]->gref = GRANT_INVALID_REF; - list_add_tail(&s->grants_used[i]->node, &info->persistent_gnts); + list_add_tail(&s->grants_used[i]->node, &info->grants); } } if (s->req.operation == BLKIF_OP_INDIRECT) { for (i = 0; i < INDIRECT_GREFS(nseg); i++) { if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) { - list_add(&s->indirect_grants[i]->node, &info->persistent_gnts); + if (!info->feature_persistent) + pr_alert_ratelimited("backed has not unmapped grant: %u\n", + s->indirect_grants[i]->gref); + list_add(&s->indirect_grants[i]->node, &info->grants); info->persistent_gnts_c++; } else { + struct page *indirect_page; + gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL); + /* + * Add the used indirect page back to the list of + * available pages for indirect grefs. + */ + indirect_page = pfn_to_page(s->indirect_grants[i]->pfn); + list_add(&indirect_page->lru, &info->indirect_pages); s->indirect_grants[i]->gref = GRANT_INVALID_REF; - list_add_tail(&s->indirect_grants[i]->node, - &info->persistent_gnts); + list_add_tail(&s->indirect_grants[i]->node, &info->grants); } } } @@ -1341,7 +1391,8 @@ static int blkfront_probe(struct xenbus_device *dev, spin_lock_init(&info->io_lock); info->xbdev = dev; info->vdevice = vdevice; - INIT_LIST_HEAD(&info->persistent_gnts); + INIT_LIST_HEAD(&info->grants); + INIT_LIST_HEAD(&info->indirect_pages); info->persistent_gnts_c = 0; info->connected = BLKIF_STATE_DISCONNECTED; INIT_WORK(&info->work, blkif_restart_queue); @@ -1637,6 +1688,23 @@ static int blkfront_setup_indirect(struct blkfront_info *info) if (err) goto out_of_memory; + if (!info->feature_persistent && info->max_indirect_segments) { + /* + * We are using indirect descriptors but not persistent + * grants, we need to allocate a set of pages that can be + * used for mapping indirect grefs + */ + int num = INDIRECT_GREFS(segs) * BLK_RING_SIZE; + + BUG_ON(!list_empty(&info->indirect_pages)); + for (i = 0; i < num; i++) { + struct page *indirect_page = alloc_page(GFP_NOIO); + if (!indirect_page) + goto out_of_memory; + list_add(&indirect_page->lru, &info->indirect_pages); + } + } + for (i = 0; i < BLK_RING_SIZE; i++) { info->shadow[i].grants_used = kzalloc( sizeof(info->shadow[i].grants_used[0]) * segs, @@ -1667,6 +1735,13 @@ out_of_memory: kfree(info->shadow[i].indirect_grants); info->shadow[i].indirect_grants = NULL; } + if (!list_empty(&info->indirect_pages)) { + struct page *indirect_page, *n; + list_for_each_entry_safe(indirect_page, n, &info->indirect_pages, lru) { + list_del(&indirect_page->lru); + __free_page(indirect_page); + } + } return -ENOMEM; } -- cgit v1.2.3 From 49c2856af779bb1a36fa598804e4c0b2251fae57 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Nov 2013 09:24:02 +0100 Subject: pktcdvd: debugfs functions return NULL on error My static checker complains correctly that this is potential NULL dereference because debugfs functions return NULL on error. They return an ERR_PTR if they are configured out. We don't need to check for ERR_PTR because if debugfs is stubbed out the dummy functions won't complain about that. We don't need to check the values before calling debugfs_remove() because that accepts ERR_PTRs and NULL pointers. We don't need to set pkt->dfs_f_info to NULL in pkt_debugfs_dev_new() because it was initialized with kzalloc() so I have removed that. Signed-off-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Jiri Kosina --- drivers/block/pktcdvd.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 56188475cfd3..ff8668c5efb1 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -473,45 +473,31 @@ static void pkt_debugfs_dev_new(struct pktcdvd_device *pd) { if (!pkt_debugfs_root) return; - pd->dfs_f_info = NULL; pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root); - if (IS_ERR(pd->dfs_d_root)) { - pd->dfs_d_root = NULL; + if (!pd->dfs_d_root) return; - } + pd->dfs_f_info = debugfs_create_file("info", S_IRUGO, pd->dfs_d_root, pd, &debug_fops); - if (IS_ERR(pd->dfs_f_info)) { - pd->dfs_f_info = NULL; - return; - } } static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd) { if (!pkt_debugfs_root) return; - if (pd->dfs_f_info) - debugfs_remove(pd->dfs_f_info); + debugfs_remove(pd->dfs_f_info); + debugfs_remove(pd->dfs_d_root); pd->dfs_f_info = NULL; - if (pd->dfs_d_root) - debugfs_remove(pd->dfs_d_root); pd->dfs_d_root = NULL; } static void pkt_debugfs_init(void) { pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL); - if (IS_ERR(pkt_debugfs_root)) { - pkt_debugfs_root = NULL; - return; - } } static void pkt_debugfs_cleanup(void) { - if (!pkt_debugfs_root) - return; debugfs_remove(pkt_debugfs_root); pkt_debugfs_root = NULL; } -- cgit v1.2.3 From 1cf7e9c68fe84248174e998922b39e508375e7c1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 1 Nov 2013 10:52:52 -0600 Subject: virtio_blk: blk-mq support Switch virtio-blk from the dual support for old-style requests and bios to use the block-multiqueue. Acked-by: Asias He Signed-off-by: Jens Axboe Signed-off-by: Christoph Hellwig --- drivers/block/virtio_blk.c | 322 +++++++++------------------------------------ 1 file changed, 65 insertions(+), 257 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 5cdf88b7ad9e..7455fe24bbbe 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -11,12 +11,11 @@ #include #include #include +#include +#include #define PART_BITS 4 -static bool use_bio; -module_param(use_bio, bool, S_IRUGO); - static int major; static DEFINE_IDA(vd_index_ida); @@ -26,13 +25,11 @@ struct virtio_blk { struct virtio_device *vdev; struct virtqueue *vq; - wait_queue_head_t queue_wait; + spinlock_t vq_lock; /* The disk structure for the kernel. */ struct gendisk *disk; - mempool_t *pool; - /* Process context for config space updates */ struct work_struct config_work; @@ -47,31 +44,17 @@ struct virtio_blk /* Ida index - used to track minor number allocations. */ int index; - - /* Scatterlist: can be too big for stack. */ - struct scatterlist sg[/*sg_elems*/]; }; struct virtblk_req { struct request *req; - struct bio *bio; struct virtio_blk_outhdr out_hdr; struct virtio_scsi_inhdr in_hdr; - struct work_struct work; - struct virtio_blk *vblk; - int flags; u8 status; struct scatterlist sg[]; }; -enum { - VBLK_IS_FLUSH = 1, - VBLK_REQ_FLUSH = 2, - VBLK_REQ_DATA = 4, - VBLK_REQ_FUA = 8, -}; - static inline int virtblk_result(struct virtblk_req *vbr) { switch (vbr->status) { @@ -84,22 +67,6 @@ static inline int virtblk_result(struct virtblk_req *vbr) } } -static inline struct virtblk_req *virtblk_alloc_req(struct virtio_blk *vblk, - gfp_t gfp_mask) -{ - struct virtblk_req *vbr; - - vbr = mempool_alloc(vblk->pool, gfp_mask); - if (!vbr) - return NULL; - - vbr->vblk = vblk; - if (use_bio) - sg_init_table(vbr->sg, vblk->sg_elems); - - return vbr; -} - static int __virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr, struct scatterlist *data_sg, @@ -143,83 +110,8 @@ static int __virtblk_add_req(struct virtqueue *vq, return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); } -static void virtblk_add_req(struct virtblk_req *vbr, bool have_data) -{ - struct virtio_blk *vblk = vbr->vblk; - DEFINE_WAIT(wait); - int ret; - - spin_lock_irq(vblk->disk->queue->queue_lock); - while (unlikely((ret = __virtblk_add_req(vblk->vq, vbr, vbr->sg, - have_data)) < 0)) { - prepare_to_wait_exclusive(&vblk->queue_wait, &wait, - TASK_UNINTERRUPTIBLE); - - spin_unlock_irq(vblk->disk->queue->queue_lock); - io_schedule(); - spin_lock_irq(vblk->disk->queue->queue_lock); - - finish_wait(&vblk->queue_wait, &wait); - } - - virtqueue_kick(vblk->vq); - spin_unlock_irq(vblk->disk->queue->queue_lock); -} - -static void virtblk_bio_send_flush(struct virtblk_req *vbr) -{ - vbr->flags |= VBLK_IS_FLUSH; - vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH; - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = 0; - - virtblk_add_req(vbr, false); -} - -static void virtblk_bio_send_data(struct virtblk_req *vbr) -{ - struct virtio_blk *vblk = vbr->vblk; - struct bio *bio = vbr->bio; - bool have_data; - - vbr->flags &= ~VBLK_IS_FLUSH; - vbr->out_hdr.type = 0; - vbr->out_hdr.sector = bio->bi_sector; - vbr->out_hdr.ioprio = bio_prio(bio); - - if (blk_bio_map_sg(vblk->disk->queue, bio, vbr->sg)) { - have_data = true; - if (bio->bi_rw & REQ_WRITE) - vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; - else - vbr->out_hdr.type |= VIRTIO_BLK_T_IN; - } else - have_data = false; - - virtblk_add_req(vbr, have_data); -} - -static void virtblk_bio_send_data_work(struct work_struct *work) -{ - struct virtblk_req *vbr; - - vbr = container_of(work, struct virtblk_req, work); - - virtblk_bio_send_data(vbr); -} - -static void virtblk_bio_send_flush_work(struct work_struct *work) -{ - struct virtblk_req *vbr; - - vbr = container_of(work, struct virtblk_req, work); - - virtblk_bio_send_flush(vbr); -} - static inline void virtblk_request_done(struct virtblk_req *vbr) { - struct virtio_blk *vblk = vbr->vblk; struct request *req = vbr->req; int error = virtblk_result(vbr); @@ -231,90 +123,43 @@ static inline void virtblk_request_done(struct virtblk_req *vbr) req->errors = (error != 0); } - __blk_end_request_all(req, error); - mempool_free(vbr, vblk->pool); -} - -static inline void virtblk_bio_flush_done(struct virtblk_req *vbr) -{ - struct virtio_blk *vblk = vbr->vblk; - - if (vbr->flags & VBLK_REQ_DATA) { - /* Send out the actual write data */ - INIT_WORK(&vbr->work, virtblk_bio_send_data_work); - queue_work(virtblk_wq, &vbr->work); - } else { - bio_endio(vbr->bio, virtblk_result(vbr)); - mempool_free(vbr, vblk->pool); - } -} - -static inline void virtblk_bio_data_done(struct virtblk_req *vbr) -{ - struct virtio_blk *vblk = vbr->vblk; - - if (unlikely(vbr->flags & VBLK_REQ_FUA)) { - /* Send out a flush before end the bio */ - vbr->flags &= ~VBLK_REQ_DATA; - INIT_WORK(&vbr->work, virtblk_bio_send_flush_work); - queue_work(virtblk_wq, &vbr->work); - } else { - bio_endio(vbr->bio, virtblk_result(vbr)); - mempool_free(vbr, vblk->pool); - } -} - -static inline void virtblk_bio_done(struct virtblk_req *vbr) -{ - if (unlikely(vbr->flags & VBLK_IS_FLUSH)) - virtblk_bio_flush_done(vbr); - else - virtblk_bio_data_done(vbr); + blk_mq_end_io(req, error); } static void virtblk_done(struct virtqueue *vq) { struct virtio_blk *vblk = vq->vdev->priv; - bool bio_done = false, req_done = false; + bool req_done = false; struct virtblk_req *vbr; unsigned long flags; unsigned int len; - spin_lock_irqsave(vblk->disk->queue->queue_lock, flags); + spin_lock_irqsave(&vblk->vq_lock, flags); do { virtqueue_disable_cb(vq); while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) { - if (vbr->bio) { - virtblk_bio_done(vbr); - bio_done = true; - } else { - virtblk_request_done(vbr); - req_done = true; - } + virtblk_request_done(vbr); + req_done = true; } } while (!virtqueue_enable_cb(vq)); + spin_unlock_irqrestore(&vblk->vq_lock, flags); + /* In case queue is stopped waiting for more buffers. */ if (req_done) - blk_start_queue(vblk->disk->queue); - spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags); - - if (bio_done) - wake_up(&vblk->queue_wait); + blk_mq_start_stopped_hw_queues(vblk->disk->queue); } -static bool do_req(struct request_queue *q, struct virtio_blk *vblk, - struct request *req) +static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req) { + struct virtio_blk *vblk = hctx->queue->queuedata; + struct virtblk_req *vbr = req->special; + unsigned long flags; unsigned int num; - struct virtblk_req *vbr; + const bool last = (req->cmd_flags & REQ_END) != 0; - vbr = virtblk_alloc_req(vblk, GFP_ATOMIC); - if (!vbr) - /* When another request finishes we'll try again. */ - return false; + BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); vbr->req = req; - vbr->bio = NULL; if (req->cmd_flags & REQ_FLUSH) { vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH; vbr->out_hdr.sector = 0; @@ -342,7 +187,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, } } - num = blk_rq_map_sg(q, vbr->req, vblk->sg); + num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg); if (num) { if (rq_data_dir(vbr->req) == WRITE) vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; @@ -350,63 +195,18 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, vbr->out_hdr.type |= VIRTIO_BLK_T_IN; } - if (__virtblk_add_req(vblk->vq, vbr, vblk->sg, num) < 0) { - mempool_free(vbr, vblk->pool); - return false; - } - - return true; -} - -static void virtblk_request(struct request_queue *q) -{ - struct virtio_blk *vblk = q->queuedata; - struct request *req; - unsigned int issued = 0; - - while ((req = blk_peek_request(q)) != NULL) { - BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); - - /* If this request fails, stop queue and wait for something to - finish to restart it. */ - if (!do_req(q, vblk, req)) { - blk_stop_queue(q); - break; - } - blk_start_request(req); - issued++; - } - - if (issued) + spin_lock_irqsave(&vblk->vq_lock, flags); + if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) { + spin_unlock_irqrestore(&vblk->vq_lock, flags); + blk_mq_stop_hw_queue(hctx); virtqueue_kick(vblk->vq); -} - -static void virtblk_make_request(struct request_queue *q, struct bio *bio) -{ - struct virtio_blk *vblk = q->queuedata; - struct virtblk_req *vbr; - - BUG_ON(bio->bi_phys_segments + 2 > vblk->sg_elems); - - vbr = virtblk_alloc_req(vblk, GFP_NOIO); - if (!vbr) { - bio_endio(bio, -ENOMEM); - return; + return BLK_MQ_RQ_QUEUE_BUSY; } + spin_unlock_irqrestore(&vblk->vq_lock, flags); - vbr->bio = bio; - vbr->flags = 0; - if (bio->bi_rw & REQ_FLUSH) - vbr->flags |= VBLK_REQ_FLUSH; - if (bio->bi_rw & REQ_FUA) - vbr->flags |= VBLK_REQ_FUA; - if (bio->bi_size) - vbr->flags |= VBLK_REQ_DATA; - - if (unlikely(vbr->flags & VBLK_REQ_FLUSH)) - virtblk_bio_send_flush(vbr); - else - virtblk_bio_send_data(vbr); + if (last) + virtqueue_kick(vblk->vq); + return BLK_MQ_RQ_QUEUE_OK; } /* return id (s/n) string for *disk to *id_str @@ -680,12 +480,35 @@ static const struct device_attribute dev_attr_cache_type_rw = __ATTR(cache_type, S_IRUGO|S_IWUSR, virtblk_cache_type_show, virtblk_cache_type_store); +static struct blk_mq_ops virtio_mq_ops = { + .queue_rq = virtio_queue_rq, + .map_queue = blk_mq_map_queue, + .alloc_hctx = blk_mq_alloc_single_hw_queue, + .free_hctx = blk_mq_free_single_hw_queue, +}; + +static struct blk_mq_reg virtio_mq_reg = { + .ops = &virtio_mq_ops, + .nr_hw_queues = 1, + .queue_depth = 64, + .numa_node = NUMA_NO_NODE, + .flags = BLK_MQ_F_SHOULD_MERGE, +}; + +static void virtblk_init_vbr(void *data, struct blk_mq_hw_ctx *hctx, + struct request *rq, unsigned int nr) +{ + struct virtio_blk *vblk = data; + struct virtblk_req *vbr = rq->special; + + sg_init_table(vbr->sg, vblk->sg_elems); +} + static int virtblk_probe(struct virtio_device *vdev) { struct virtio_blk *vblk; struct request_queue *q; int err, index; - int pool_size; u64 cap; u32 v, blk_size, sg_elems, opt_io_size; @@ -709,17 +532,14 @@ static int virtblk_probe(struct virtio_device *vdev) /* We need an extra sg elements at head and tail. */ sg_elems += 2; - vdev->priv = vblk = kmalloc(sizeof(*vblk) + - sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL); + vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); if (!vblk) { err = -ENOMEM; goto out_free_index; } - init_waitqueue_head(&vblk->queue_wait); vblk->vdev = vdev; vblk->sg_elems = sg_elems; - sg_init_table(vblk->sg, vblk->sg_elems); mutex_init(&vblk->config_lock); INIT_WORK(&vblk->config_work, virtblk_config_changed_work); @@ -728,31 +548,27 @@ static int virtblk_probe(struct virtio_device *vdev) err = init_vq(vblk); if (err) goto out_free_vblk; - - pool_size = sizeof(struct virtblk_req); - if (use_bio) - pool_size += sizeof(struct scatterlist) * sg_elems; - vblk->pool = mempool_create_kmalloc_pool(1, pool_size); - if (!vblk->pool) { - err = -ENOMEM; - goto out_free_vq; - } + spin_lock_init(&vblk->vq_lock); /* FIXME: How many partitions? How long is a piece of string? */ vblk->disk = alloc_disk(1 << PART_BITS); if (!vblk->disk) { err = -ENOMEM; - goto out_mempool; + goto out_free_vq; } - q = vblk->disk->queue = blk_init_queue(virtblk_request, NULL); + virtio_mq_reg.cmd_size = + sizeof(struct virtblk_req) + + sizeof(struct scatterlist) * sg_elems; + + q = vblk->disk->queue = blk_mq_init_queue(&virtio_mq_reg, vblk); if (!q) { err = -ENOMEM; goto out_put_disk; } - if (use_bio) - blk_queue_make_request(q, virtblk_make_request); + blk_mq_init_commands(q, virtblk_init_vbr, vblk); + q->queuedata = vblk; virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN); @@ -857,8 +673,6 @@ out_del_disk: blk_cleanup_queue(vblk->disk->queue); out_put_disk: put_disk(vblk->disk); -out_mempool: - mempool_destroy(vblk->pool); out_free_vq: vdev->config->del_vqs(vdev); out_free_vblk: @@ -890,7 +704,6 @@ static void virtblk_remove(struct virtio_device *vdev) refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount); put_disk(vblk->disk); - mempool_destroy(vblk->pool); vdev->config->del_vqs(vdev); kfree(vblk); @@ -914,10 +727,7 @@ static int virtblk_freeze(struct virtio_device *vdev) flush_work(&vblk->config_work); - spin_lock_irq(vblk->disk->queue->queue_lock); - blk_stop_queue(vblk->disk->queue); - spin_unlock_irq(vblk->disk->queue->queue_lock); - blk_sync_queue(vblk->disk->queue); + blk_mq_stop_hw_queues(vblk->disk->queue); vdev->config->del_vqs(vdev); return 0; @@ -930,11 +740,9 @@ static int virtblk_restore(struct virtio_device *vdev) vblk->config_enable = true; ret = init_vq(vdev->priv); - if (!ret) { - spin_lock_irq(vblk->disk->queue->queue_lock); - blk_start_queue(vblk->disk->queue); - spin_unlock_irq(vblk->disk->queue->queue_lock); - } + if (!ret) + blk_mq_start_stopped_hw_queues(vblk->disk->queue); + return ret; } #endif -- cgit v1.2.3 From 16735d022f72b20ddbb2274b8e109f69575e9b2b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 14 Nov 2013 14:32:02 -0800 Subject: tree-wide: use reinit_completion instead of INIT_COMPLETION Use this new function to make code more comprehensible, since we are reinitialzing the completion, not initializing. [akpm@linux-foundation.org: linux-next resyncs] Signed-off-by: Wolfram Sang Acked-by: Linus Walleij (personally at LCE13) Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-tegra/apbio.c | 2 +- arch/powerpc/platforms/powermac/low_i2c.c | 6 +++--- arch/powerpc/platforms/pseries/suspend.c | 2 +- crypto/af_alg.c | 2 +- crypto/tcrypt.c | 4 ++-- crypto/testmgr.c | 12 ++++++------ drivers/ata/libata-eh.c | 4 ++-- drivers/base/power/main.c | 4 ++-- drivers/block/amiflop.c | 2 +- drivers/block/cciss.c | 4 ++-- drivers/char/hw_random/timeriomem-rng.c | 2 +- drivers/crypto/tegra-aes.c | 2 +- drivers/firewire/core-transaction.c | 2 +- drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c | 2 +- drivers/hid/hid-wiimote.h | 2 +- drivers/hwmon/jz4740-hwmon.c | 2 +- drivers/i2c/busses/i2c-at91.c | 2 +- drivers/i2c/busses/i2c-bcm2835.c | 2 +- drivers/i2c/busses/i2c-davinci.c | 2 +- drivers/i2c/busses/i2c-designware-core.c | 2 +- drivers/i2c/busses/i2c-ismt.c | 2 +- drivers/i2c/busses/i2c-mxs.c | 2 +- drivers/i2c/busses/i2c-omap.c | 2 +- drivers/i2c/busses/i2c-tegra.c | 2 +- drivers/i2c/busses/i2c-wmt.c | 4 ++-- drivers/iio/adc/ad_sigma_delta.c | 6 +++--- drivers/iio/adc/nau7802.c | 2 +- drivers/input/touchscreen/cyttsp_core.c | 2 +- drivers/md/dm-crypt.c | 2 +- drivers/media/platform/blackfin/bfin_capture.c | 2 +- drivers/media/radio/radio-wl1273.c | 10 +++++----- drivers/media/radio/si470x/radio-si470x-common.c | 4 ++-- drivers/media/rc/iguanair.c | 2 +- drivers/memstick/core/memstick.c | 2 +- drivers/memstick/host/r592.c | 2 +- drivers/misc/mic/card/mic_virtio.c | 2 +- drivers/misc/mic/host/mic_boot.c | 2 +- drivers/misc/ti-st/st_kim.c | 12 ++++++------ drivers/mtd/nand/mxc_nand.c | 2 +- drivers/mtd/nand/r852.c | 2 +- drivers/mtd/onenand/omap2.c | 10 +++++----- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 2 +- drivers/net/ieee802154/at86rf230.c | 2 +- drivers/net/ieee802154/mrf24j40.c | 2 +- drivers/net/wireless/ath/ath10k/htc.c | 4 ++-- drivers/net/wireless/ath/ath10k/mac.c | 18 +++++++++--------- drivers/net/wireless/ath/carl9170/usb.c | 2 +- drivers/net/wireless/ath/wil6210/main.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 4 ++-- drivers/net/wireless/zd1211rw/zd_usb.c | 2 +- drivers/parport/parport_ip32.c | 4 ++-- drivers/platform/x86/apple-gmux.c | 2 +- drivers/power/ab8500_fg.c | 4 ++-- drivers/power/jz4740-battery.c | 2 +- drivers/rtc/rtc-hid-sensor-time.c | 2 +- drivers/spi/spi-bcm2835.c | 2 +- drivers/spi/spi-clps711x.c | 2 +- drivers/spi/spi-davinci.c | 2 +- drivers/spi/spi-fsl-espi.c | 2 +- drivers/spi/spi-fsl-spi.c | 2 +- drivers/spi/spi-mpc512x-psc.c | 2 +- drivers/spi/spi-mxs.c | 2 +- drivers/spi/spi-s3c64xx.c | 2 +- drivers/spi/spi-sh-msiof.c | 2 +- drivers/spi/spi-sirf.c | 4 ++-- drivers/spi/spi-tegra114.c | 6 +++--- drivers/spi/spi-tegra20-sflash.c | 2 +- drivers/spi/spi-tegra20-slink.c | 6 +++--- drivers/spi/spi-xilinx.c | 2 +- drivers/spi/spi.c | 2 +- drivers/staging/iio/adc/mxs-lradc.c | 2 +- drivers/staging/media/solo6x10/solo6x10-p2m.c | 2 +- drivers/staging/tidspbridge/core/sync.c | 4 ++-- drivers/staging/tidspbridge/include/dspbridge/sync.h | 2 +- drivers/staging/tidspbridge/rmgr/drv_interface.c | 6 +++--- drivers/tty/metag_da.c | 2 +- drivers/usb/c67x00/c67x00-sched.c | 2 +- drivers/usb/gadget/f_fs.c | 2 +- drivers/usb/serial/mos7720.c | 2 +- drivers/video/exynos/exynos_mipi_dsi_common.c | 4 ++-- drivers/video/omap2/displays-new/encoder-tpd12s015.c | 2 +- fs/ecryptfs/crypto.c | 2 +- fs/nfs/nfs4state.c | 2 +- fs/ocfs2/dlmglue.c | 4 ++-- sound/firewire/dice.c | 2 +- sound/soc/samsung/ac97.c | 6 +++--- 86 files changed, 138 insertions(+), 138 deletions(-) (limited to 'drivers/block') diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index d7aa52ea6cfc..bc471973cf04 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -114,7 +114,7 @@ static int do_dma_transfer(unsigned long apb_add, dma_desc->callback = apb_dma_complete; dma_desc->callback_param = NULL; - INIT_COMPLETION(tegra_apb_wait); + reinit_completion(&tegra_apb_wait); dmaengine_submit(dma_desc); dma_async_issue_pending(tegra_apb_dma_chan); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index fc536f2971c0..7553b6a77c64 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -452,7 +452,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, */ if (use_irq) { /* Clear completion */ - INIT_COMPLETION(host->complete); + reinit_completion(&host->complete); /* Ack stale interrupts */ kw_write_reg(reg_isr, kw_read_reg(reg_isr)); /* Arm timeout */ @@ -717,7 +717,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, return -EINVAL; } - INIT_COMPLETION(comp); + reinit_completion(&comp); req->data[0] = PMU_I2C_CMD; req->reply[0] = 0xff; req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; @@ -748,7 +748,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, hdr->bus = PMU_I2C_BUS_STATUS; - INIT_COMPLETION(comp); + reinit_completion(&comp); req->data[0] = PMU_I2C_CMD; req->reply[0] = 0xff; req->nbytes = 2; diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index 5f997e79d570..16a255255d30 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -106,7 +106,7 @@ static int pseries_prepare_late(void) atomic_set(&suspend_data.done, 0); atomic_set(&suspend_data.error, 0); suspend_data.complete = &suspend_work; - INIT_COMPLETION(suspend_work); + reinit_completion(&suspend_work); return 0; } diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ac33d5f30778..966f893711b3 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -434,7 +434,7 @@ int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) case -EINPROGRESS: case -EBUSY: wait_for_completion(&completion->completion); - INIT_COMPLETION(completion->completion); + reinit_completion(&completion->completion); err = completion->err; break; }; diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 25a5934f0e50..1ab8258fcf56 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -493,7 +493,7 @@ static inline int do_one_ahash_op(struct ahash_request *req, int ret) ret = wait_for_completion_interruptible(&tr->completion); if (!ret) ret = tr->err; - INIT_COMPLETION(tr->completion); + reinit_completion(&tr->completion); } return ret; } @@ -721,7 +721,7 @@ static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret) ret = wait_for_completion_interruptible(&tr->completion); if (!ret) ret = tr->err; - INIT_COMPLETION(tr->completion); + reinit_completion(&tr->completion); } return ret; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index e091ef6e1791..432afc03e7c3 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -179,7 +179,7 @@ static int do_one_async_hash_op(struct ahash_request *req, ret = wait_for_completion_interruptible(&tr->completion); if (!ret) ret = tr->err; - INIT_COMPLETION(tr->completion); + reinit_completion(&tr->completion); } return ret; } @@ -336,7 +336,7 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, ret = wait_for_completion_interruptible( &tresult.completion); if (!ret && !(ret = tresult.err)) { - INIT_COMPLETION(tresult.completion); + reinit_completion(&tresult.completion); break; } /* fall through */ @@ -543,7 +543,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc, ret = wait_for_completion_interruptible( &result.completion); if (!ret && !(ret = result.err)) { - INIT_COMPLETION(result.completion); + reinit_completion(&result.completion); break; } case -EBADMSG: @@ -697,7 +697,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc, ret = wait_for_completion_interruptible( &result.completion); if (!ret && !(ret = result.err)) { - INIT_COMPLETION(result.completion); + reinit_completion(&result.completion); break; } case -EBADMSG: @@ -983,7 +983,7 @@ static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc, ret = wait_for_completion_interruptible( &result.completion); if (!ret && !((ret = result.err))) { - INIT_COMPLETION(result.completion); + reinit_completion(&result.completion); break; } /* fall through */ @@ -1086,7 +1086,7 @@ static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc, ret = wait_for_completion_interruptible( &result.completion); if (!ret && !((ret = result.err))) { - INIT_COMPLETION(result.completion); + reinit_completion(&result.completion); break; } /* fall through */ diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 77bbc8266883..92d7797223be 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3017,7 +3017,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap) * ourselves at the beginning of each pass over the loop. * * Additionally, all write accesses to &ap->park_req_pending - * through INIT_COMPLETION() (see below) or complete_all() + * through reinit_completion() (see below) or complete_all() * (see ata_scsi_park_store()) are protected by the host lock. * As a result we have that park_req_pending.done is zero on * exit from this function, i.e. when ATA_EH_PARK actions for @@ -3031,7 +3031,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap) */ spin_lock_irqsave(ap->lock, flags); - INIT_COMPLETION(ap->park_req_pending); + reinit_completion(&ap->park_req_pending); ata_for_each_link(link, ap, EDGE) { ata_for_each_dev(dev, link, ALL) { struct ata_eh_info *ehi = &link->eh_info; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ee039afe9078..c12e9b9556be 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -757,7 +757,7 @@ void dpm_resume(pm_message_t state) async_error = 0; list_for_each_entry(dev, &dpm_suspended_list, power.entry) { - INIT_COMPLETION(dev->power.completion); + reinit_completion(&dev->power.completion); if (is_async(dev)) { get_device(dev); async_schedule(async_resume, dev); @@ -1237,7 +1237,7 @@ static void async_suspend(void *data, async_cookie_t cookie) static int device_suspend(struct device *dev) { - INIT_COMPLETION(dev->power.completion); + reinit_completion(&dev->power.completion); if (pm_async_enabled && dev->power.async_suspend) { get_device(dev); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 4ff85b8785ee..748dea4f34dc 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -343,7 +343,7 @@ static int fd_motor_on(int nr) unit[nr].motor = 1; fd_select(nr); - INIT_COMPLETION(motor_on_completion); + reinit_completion(&motor_on_completion); motor_on_timer.data = nr; mod_timer(&motor_on_timer, jiffies + HZ/2); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 0c004ac05811..b35fc4f5237c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2808,7 +2808,7 @@ resend_cmd2: /* erase the old error information */ memset(c->err_info, 0, sizeof(ErrorInfo_struct)); return_status = IO_OK; - INIT_COMPLETION(wait); + reinit_completion(&wait); goto resend_cmd2; } @@ -3669,7 +3669,7 @@ static int add_to_scan_list(struct ctlr_info *h) } } if (!found && !h->busy_scanning) { - INIT_COMPLETION(h->scan_wait); + reinit_completion(&h->scan_wait); list_add_tail(&h->scan_list, &scan_q); ret = 1; } diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index d2120ba8f3f9..73ce739f8e19 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -79,7 +79,7 @@ static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data) priv->expires = cur + delay; priv->present = 0; - INIT_COMPLETION(priv->completion); + reinit_completion(&priv->completion); mod_timer(&priv->timer, priv->expires); return 4; diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c index 2d58da972ae2..fa05e3c329bd 100644 --- a/drivers/crypto/tegra-aes.c +++ b/drivers/crypto/tegra-aes.c @@ -268,7 +268,7 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr, aes_writel(dd, value, TEGRA_AES_SECURE_INPUT_SELECT); aes_writel(dd, out_addr, TEGRA_AES_SECURE_DEST_ADDR); - INIT_COMPLETION(dd->op_complete); + reinit_completion(&dd->op_complete); for (i = 0; i < AES_HW_MAX_ICQ_LENGTH - 1; i++) { do { diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index e5af0e3a26ec..0e799516a2ab 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -477,7 +477,7 @@ void fw_send_phy_config(struct fw_card *card, phy_config_packet.header[1] = data; phy_config_packet.header[2] = ~data; phy_config_packet.generation = generation; - INIT_COMPLETION(phy_config_done); + reinit_completion(&phy_config_done); card->driver->send_request(card, &phy_config_packet); wait_for_completion_timeout(&phy_config_done, timeout); diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c index 1eb86c79523e..e28107061148 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c @@ -99,7 +99,7 @@ static int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg) i2c_dev->status = I2C_STAT_INIT; i2c_dev->msg = pmsg; i2c_dev->buf_offset = 0; - INIT_COMPLETION(i2c_dev->complete); + reinit_completion(&i2c_dev->complete); /* Enable I2C transaction */ temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION; diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 75db0c400037..cfa63b0825b0 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h @@ -327,7 +327,7 @@ static inline void wiimote_cmd_acquire_noint(struct wiimote_data *wdata) static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd, __u32 opt) { - INIT_COMPLETION(wdata->state.ready); + reinit_completion(&wdata->state.ready); wdata->state.cmd = cmd; wdata->state.opt = opt; } diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index e0d66b9590ab..a183e488db78 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -66,7 +66,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, mutex_lock(&hwmon->lock); - INIT_COMPLETION(*completion); + reinit_completion(completion); enable_irq(hwmon->irq); hwmon->cell->enable(to_platform_device(dev)); diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index fd059308affa..8edba9de76df 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -371,7 +371,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); - INIT_COMPLETION(dev->cmd_complete); + reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; if (!dev->buf_len) { diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index ea4b08fc3353..d7e8600f31fb 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -151,7 +151,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, i2c_dev->msg_buf = msg->buf; i2c_dev->msg_buf_remaining = msg->len; - INIT_COMPLETION(i2c_dev->completion); + reinit_completion(&i2c_dev->completion); bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 132369fad4e0..960dec61c64e 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -323,7 +323,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len); - INIT_COMPLETION(dev->cmd_complete); + reinit_completion(&dev->cmd_complete); dev->cmd_err = 0; /* Take I2C out of reset and configure it as master */ diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 5888feef1ac5..e89e3e2145e5 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -613,7 +613,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) mutex_lock(&dev->lock); pm_runtime_get_sync(dev->dev); - INIT_COMPLETION(dev->cmd_complete); + reinit_completion(&dev->cmd_complete); dev->msgs = msgs; dev->msgs_num = num; dev->cmd_err = 0; diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 1672effbcebb..0043ede234c2 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -541,7 +541,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->dptr_high = upper_32_bits(dma_addr); } - INIT_COMPLETION(priv->cmp); + reinit_completion(&priv->cmp); /* Add the descriptor */ ismt_submit_desc(priv); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index b7c857774708..3aedd86a6468 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -505,7 +505,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, return err; } } else { - INIT_COMPLETION(i2c->cmd_complete); + reinit_completion(&i2c->cmd_complete); ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); if (ret) return ret; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9967a6f9c2ff..a6a891d7970d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -543,7 +543,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - INIT_COMPLETION(dev->cmd_complete); + reinit_completion(&dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index c457cb447c66..e661edee4d0c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -544,7 +544,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, i2c_dev->msg_buf_remaining = msg->len; i2c_dev->msg_err = I2C_ERR_NONE; i2c_dev->msg_read = (msg->flags & I2C_M_RD); - INIT_COMPLETION(i2c_dev->msg_complete); + reinit_completion(&i2c_dev->msg_complete); packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | PACKET_HEADER0_PROTOCOL_I2C | diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index c65da3d913a0..31395fa8121d 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -158,7 +158,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, writew(val, i2c_dev->base + REG_CR); } - INIT_COMPLETION(i2c_dev->complete); + reinit_completion(&i2c_dev->complete); if (i2c_dev->mode == I2C_MODE_STANDARD) tcr_val = TCR_STANDARD_MODE; @@ -247,7 +247,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, writew(val, i2c_dev->base + REG_CR); } - INIT_COMPLETION(i2c_dev->complete); + reinit_completion(&i2c_dev->complete); if (i2c_dev->mode == I2C_MODE_STANDARD) tcr_val = TCR_STANDARD_MODE; diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index e6fbd3e70981..9a4e0e32a771 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -188,7 +188,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; - INIT_COMPLETION(sigma_delta->completion); + reinit_completion(&sigma_delta->completion); ret = ad_sigma_delta_set_mode(sigma_delta, mode); if (ret < 0) @@ -259,7 +259,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, spi_bus_lock(sigma_delta->spi->master); sigma_delta->bus_locked = true; - INIT_COMPLETION(sigma_delta->completion); + reinit_completion(&sigma_delta->completion); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); @@ -343,7 +343,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) { struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); - INIT_COMPLETION(sigma_delta->completion); + reinit_completion(&sigma_delta->completion); wait_for_completion_timeout(&sigma_delta->completion, HZ); if (!sigma_delta->irq_dis) { diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 54c5babe6746..e525aa6475c4 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -190,7 +190,7 @@ static int nau7802_read_irq(struct iio_dev *indio_dev, struct nau7802_state *st = iio_priv(indio_dev); int ret; - INIT_COMPLETION(st->value_ok); + reinit_completion(&st->value_ok); enable_irq(st->client->irq); nau7802_sync(st); diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index d53e0b72a407..4204841cdc49 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -242,7 +242,7 @@ static int cyttsp_soft_reset(struct cyttsp *ts) int retval; /* wait for interrupt to set ready completion */ - INIT_COMPLETION(ts->bl_ready); + reinit_completion(&ts->bl_ready); ts->state = CY_BL_STATE; enable_irq(ts->irq); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 50ea7ed24dce..81b0fa660452 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -950,7 +950,7 @@ static int crypt_convert(struct crypt_config *cc, /* async */ case -EBUSY: wait_for_completion(&ctx->restart); - INIT_COMPLETION(ctx->restart); + reinit_completion(&ctx->restart); /* fall through*/ case -EINPROGRESS: this_cc->req = NULL; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 4c1105977090..281916591437 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -422,7 +422,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } - INIT_COMPLETION(bcap_dev->comp); + reinit_completion(&bcap_dev->comp); bcap_dev->stop = false; return 0; } diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 97c2c18803ef..9cf6731fb816 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -375,7 +375,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) if (r) return r; - INIT_COMPLETION(radio->busy); + reinit_completion(&radio->busy); /* wait for the FR IRQ */ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); @@ -389,7 +389,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) if (r) return r; - INIT_COMPLETION(radio->busy); + reinit_completion(&radio->busy); /* wait for the POWER_ENB IRQ */ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); @@ -444,7 +444,7 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) goto err; } - INIT_COMPLETION(radio->busy); + reinit_completion(&radio->busy); r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); if (!r) { @@ -805,7 +805,7 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, if (level < SCHAR_MIN || level > SCHAR_MAX) return -EINVAL; - INIT_COMPLETION(radio->busy); + reinit_completion(&radio->busy); dev_dbg(radio->dev, "%s: BUSY\n", __func__); r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); @@ -847,7 +847,7 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, if (r) goto out; - INIT_COMPLETION(radio->busy); + reinit_completion(&radio->busy); dev_dbg(radio->dev, "%s: BUSY\n", __func__); r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 5c57e5b0f949..0bd250068285 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -218,7 +218,7 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) goto done; /* wait till tune operation has completed */ - INIT_COMPLETION(radio->completion); + reinit_completion(&radio->completion); retval = wait_for_completion_timeout(&radio->completion, msecs_to_jiffies(tune_timeout)); if (!retval) @@ -341,7 +341,7 @@ static int si470x_set_seek(struct si470x_device *radio, return retval; /* wait till tune operation has completed */ - INIT_COMPLETION(radio->completion); + reinit_completion(&radio->completion); retval = wait_for_completion_timeout(&radio->completion, msecs_to_jiffies(seek_timeout)); if (!retval) diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 19632b1c2190..b53626ba6f49 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -207,7 +207,7 @@ static int iguanair_send(struct iguanair *ir, unsigned size) { int rc; - INIT_COMPLETION(ir->completion); + reinit_completion(&ir->completion); ir->urb_out->transfer_buffer_length = size; rc = usb_submit_urb(ir->urb_out, GFP_KERNEL); diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index bbf4aea1627d..a0547dbf9806 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -253,7 +253,7 @@ void memstick_new_req(struct memstick_host *host) { if (host->card) { host->retries = cmd_retries; - INIT_COMPLETION(host->card->mrq_complete); + reinit_completion(&host->card->mrq_complete); host->request(host); } } diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 1b6e91345222..31727bf285d0 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -290,7 +290,7 @@ static int r592_transfer_fifo_dma(struct r592_device *dev) dbg_verbose("doing dma transfer"); dev->dma_error = 0; - INIT_COMPLETION(dev->dma_done); + reinit_completion(&dev->dma_done); /* TODO: hidden assumption about nenth beeing always 1 */ sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c index 914cc9b2caad..8aa42e738acc 100644 --- a/drivers/misc/mic/card/mic_virtio.c +++ b/drivers/misc/mic/card/mic_virtio.c @@ -493,7 +493,7 @@ static int mic_remove_device(struct mic_device_desc __iomem *d, ioread8(&dc->config_change), ioread8(&d->type), mvdev); status = ioread8(&d->status); - INIT_COMPLETION(mvdev->reset_done); + reinit_completion(&mvdev->reset_done); unregister_virtio_device(&mvdev->vdev); mic_free_card_irq(mvdev->virtio_cookie, mvdev); if (status & VIRTIO_CONFIG_S_DRIVER_OK) diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index b079c65eed6d..7558d9186438 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c @@ -38,7 +38,7 @@ static void mic_reset(struct mic_device *mdev) #define MIC_RESET_TO (45) - INIT_COMPLETION(mdev->reset_wait); + reinit_completion(&mdev->reset_wait); mdev->ops->reset_fw_ready(mdev); mdev->ops->reset(mdev); diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 83907c720594..96853a09788a 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -218,7 +218,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) pr_debug("%s", __func__); - INIT_COMPLETION(kim_gdata->kim_rcvd); + reinit_completion(&kim_gdata->kim_rcvd); if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) { pr_err("kim: couldn't write 4 bytes"); return -EIO; @@ -229,7 +229,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) pr_err(" waiting for ver info- timed out "); return -ETIMEDOUT; } - INIT_COMPLETION(kim_gdata->kim_rcvd); + reinit_completion(&kim_gdata->kim_rcvd); /* the positions 12 & 13 in the response buffer provide with the * chip, major & minor numbers */ @@ -362,7 +362,7 @@ static long download_firmware(struct kim_data_s *kim_gdata) /* reinit completion before sending for the * relevant wait */ - INIT_COMPLETION(kim_gdata->kim_rcvd); + reinit_completion(&kim_gdata->kim_rcvd); /* * Free space found in uart buffer, call st_int_write @@ -398,7 +398,7 @@ static long download_firmware(struct kim_data_s *kim_gdata) release_firmware(kim_gdata->fw_entry); return -ETIMEDOUT; } - INIT_COMPLETION(kim_gdata->kim_rcvd); + reinit_completion(&kim_gdata->kim_rcvd); break; case ACTION_DELAY: /* sleep */ pr_info("sleep command in scr"); @@ -474,7 +474,7 @@ long st_kim_start(void *kim_data) gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); mdelay(100); /* re-initialize the completion */ - INIT_COMPLETION(kim_gdata->ldisc_installed); + reinit_completion(&kim_gdata->ldisc_installed); /* send notification to UIM */ kim_gdata->ldisc_install = 1; pr_info("ldisc_install = 1"); @@ -525,7 +525,7 @@ long st_kim_stop(void *kim_data) kim_gdata->kim_pdev->dev.platform_data; struct tty_struct *tty = kim_gdata->core_data->tty; - INIT_COMPLETION(kim_gdata->ldisc_installed); + reinit_completion(&kim_gdata->ldisc_installed); if (tty) { /* can be called before ldisc is installed */ /* Flush any pending characters in the driver and discipline. */ diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 4edea7f4462f..9dfdb06c508b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -396,7 +396,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) if (useirq) { if (!host->devtype_data->check_int(host)) { - INIT_COMPLETION(host->op_completion); + reinit_completion(&host->op_completion); irq_control(host, 1); wait_for_completion(&host->op_completion); } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 9dcf02d22aa8..325930db3f04 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -181,7 +181,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) /* Set dma direction */ dev->dma_dir = do_read; dev->dma_stage = 1; - INIT_COMPLETION(dev->dma_done); + reinit_completion(&dev->dma_done); dbg_verbose("doing dma %s ", do_read ? "read" : "write"); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 2362909d20c0..6547c84afc3a 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -159,7 +159,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); } - INIT_COMPLETION(c->irq_done); + reinit_completion(&c->irq_done); if (c->gpio_irq) { result = gpio_get_value(c->gpio_irq); if (result == -1) { @@ -349,7 +349,7 @@ static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - INIT_COMPLETION(c->dma_done); + reinit_completion(&c->dma_done); omap_start_dma(c->dma_channel); timeout = jiffies + msecs_to_jiffies(20); @@ -420,7 +420,7 @@ static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - INIT_COMPLETION(c->dma_done); + reinit_completion(&c->dma_done); omap_start_dma(c->dma_channel); timeout = jiffies + msecs_to_jiffies(20); @@ -499,7 +499,7 @@ static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - INIT_COMPLETION(c->dma_done); + reinit_completion(&c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); @@ -544,7 +544,7 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, dma_dst, 0, 0); - INIT_COMPLETION(c->dma_done); + reinit_completion(&c->dma_done); omap_start_dma(c->dma_channel); wait_for_completion(&c->dma_done); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 09810ddd11ec..a01a6a74ee3a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3537,7 +3537,7 @@ int qlcnic_83xx_resume(struct qlcnic_adapter *adapter) void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx) { - INIT_COMPLETION(mbx->completion); + reinit_completion(&mbx->completion); set_bit(QLC_83XX_MBX_READY, &mbx->status); } diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6f10b4964726..2cbe1c249996 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -561,7 +561,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) spin_lock_irqsave(&lp->lock, flags); lp->is_tx = 1; - INIT_COMPLETION(lp->tx_complete); + reinit_completion(&lp->tx_complete); spin_unlock_irqrestore(&lp->lock, flags); rc = at86rf230_write_fbuf(lp, skb->data, skb->len); diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 0632d34905c7..c6e46d6e9f75 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -343,7 +343,7 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb) if (ret) goto err; - INIT_COMPLETION(devrec->tx_complete); + reinit_completion(&devrec->tx_complete); /* Set TXNTRIG bit of TXNCON to send packet */ ret = read_short_reg(devrec, REG_TXNCON, &val); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 3118d7506734..edae50b52806 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -534,7 +534,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc) u16 credit_count; u16 credit_size; - INIT_COMPLETION(htc->ctl_resp); + reinit_completion(&htc->ctl_resp); status = ath10k_hif_start(htc->ar); if (status) { @@ -669,7 +669,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc, req_msg->flags = __cpu_to_le16(flags); req_msg->service_id = __cpu_to_le16(conn_req->service_id); - INIT_COMPLETION(htc->ctl_resp); + reinit_completion(&htc->ctl_resp); status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb); if (status) { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0b1cc516e778..97ac8c87cba2 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -92,7 +92,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->install_key_done); + reinit_completion(&ar->install_key_done); ret = ath10k_send_key(arvif, key, cmd, macaddr); if (ret) @@ -438,7 +438,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->vdev_setup_done); + reinit_completion(&ar->vdev_setup_done); arg.vdev_id = arvif->vdev_id; arg.dtim_period = arvif->dtim_period; @@ -491,7 +491,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) lockdep_assert_held(&ar->conf_mutex); - INIT_COMPLETION(ar->vdev_setup_done); + reinit_completion(&ar->vdev_setup_done); ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { @@ -1666,7 +1666,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) } spin_lock_bh(&ar->data_lock); - INIT_COMPLETION(ar->offchan_tx_completed); + reinit_completion(&ar->offchan_tx_completed); ar->offchan_tx_skb = skb; spin_unlock_bh(&ar->data_lock); @@ -2476,8 +2476,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, goto exit; } - INIT_COMPLETION(ar->scan.started); - INIT_COMPLETION(ar->scan.completed); + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); ar->scan.in_progress = true; ar->scan.aborting = false; ar->scan.is_roc = false; @@ -2832,9 +2832,9 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, goto exit; } - INIT_COMPLETION(ar->scan.started); - INIT_COMPLETION(ar->scan.completed); - INIT_COMPLETION(ar->scan.on_channel); + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); ar->scan.in_progress = true; ar->scan.aborting = false; ar->scan.is_roc = true; diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 307bc0ddff99..ca115f33746f 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -773,7 +773,7 @@ void carl9170_usb_stop(struct ar9170 *ar) complete_all(&ar->cmd_wait); /* This is required to prevent an early completion on _start */ - INIT_COMPLETION(ar->cmd_wait); + reinit_completion(&ar->cmd_wait); /* * Note: diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0a2844c48a60..fd30cddd5882 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -250,7 +250,7 @@ int wil_reset(struct wil6210_priv *wil) /* init after reset */ wil->pending_connect_cid = -1; - INIT_COMPLETION(wil->wmi_ready); + reinit_completion(&wil->wmi_ready); /* TODO: release MAC reset */ wil6210_enable_irq(wil); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d7a974532909..5b5b952d47b1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1148,7 +1148,7 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - INIT_COMPLETION(afx_hdl->act_frm_scan); + reinit_completion(&afx_hdl->act_frm_scan); set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); afx_hdl->is_active = true; afx_hdl->peer_chan = P2P_INVALID_CHANNEL; @@ -1501,7 +1501,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, brcmf_dbg(TRACE, "Enter\n"); - INIT_COMPLETION(p2p->send_af_done); + reinit_completion(&p2p->send_af_done); clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 7ef0b4a181e1..84d94f572a46 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1619,7 +1619,7 @@ static void prepare_read_regs_int(struct zd_usb *usb, atomic_set(&intr->read_regs_enabled, 1); intr->read_regs.req = req; intr->read_regs.req_count = count; - INIT_COMPLETION(intr->read_regs.completion); + reinit_completion(&intr->read_regs.completion); spin_unlock_irq(&intr->lock); } diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index d4716273651e..c864f82bd37d 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -1331,7 +1331,7 @@ static unsigned int parport_ip32_fwp_wait_interrupt(struct parport *p) break; /* Initialize mutex used to take interrupts into account */ - INIT_COMPLETION(priv->irq_complete); + reinit_completion(&priv->irq_complete); /* Enable serviceIntr */ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0); @@ -1446,7 +1446,7 @@ static size_t parport_ip32_fifo_write_block_dma(struct parport *p, priv->irq_mode = PARPORT_IP32_IRQ_HERE; parport_ip32_dma_start(DMA_TO_DEVICE, (void *)buf, len); - INIT_COMPLETION(priv->irq_complete); + reinit_completion(&priv->irq_complete); parport_ip32_frob_econtrol(p, ECR_DMAEN | ECR_SERVINTR, ECR_DMAEN); nfault_timeout = min((unsigned long)physport->cad->timeout, diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 8eea2efbbb6d..605a9be55129 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -289,7 +289,7 @@ static int gmux_switchto(enum vga_switcheroo_client_id id) static int gmux_set_discrete_state(struct apple_gmux_data *gmux_data, enum vga_switcheroo_state state) { - INIT_COMPLETION(gmux_data->powerchange_done); + reinit_completion(&gmux_data->powerchange_done); if (state == VGA_SWITCHEROO_ON) { gmux_write8(gmux_data, GMUX_PORT_DISCRETE_POWER, 1); diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 754970717c31..3cb4178e397c 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -574,8 +574,8 @@ int ab8500_fg_inst_curr_start(struct ab8500_fg *di) } /* Return and WFI */ - INIT_COMPLETION(di->ab8500_fg_started); - INIT_COMPLETION(di->ab8500_fg_complete); + reinit_completion(&di->ab8500_fg_started); + reinit_completion(&di->ab8500_fg_complete); enable_irq(di->irq); /* Note: cc_lock is still locked */ diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index d9686aa9270a..6c8931d4ad62 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -73,7 +73,7 @@ static long jz_battery_read_voltage(struct jz_battery *battery) mutex_lock(&battery->lock); - INIT_COMPLETION(battery->read_completion); + reinit_completion(&battery->read_completion); enable_irq(battery->irq); battery->cell->enable(battery->pdev); diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index a34e5cfd2ab5..965a9da70867 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -209,7 +209,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) platform_get_drvdata(to_platform_device(dev)); int ret; - INIT_COMPLETION(time_state->comp_last_time); + reinit_completion(&time_state->comp_last_time); /* get a report with all values through requesting one value */ sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, HID_USAGE_SENSOR_TIME, hid_time_addresses[0], diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 4c332143a310..3ed666fe840a 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -217,7 +217,7 @@ static int bcm2835_spi_start_transfer(struct spi_device *spi, cs |= spi->chip_select; } - INIT_COMPLETION(bs->done); + reinit_completion(&bs->done); bs->tx_buf = tfr->tx_buf; bs->rx_buf = tfr->rx_buf; bs->len = tfr->len; diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index e2a5a426b2ef..6f03d7e6435d 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -105,7 +105,7 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH)); - INIT_COMPLETION(hw->done); + reinit_completion(&hw->done); hw->count = 0; hw->len = xfer->len; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index dd72445ba2ea..50b2d88c8190 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -554,7 +554,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); set_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); - INIT_COMPLETION(dspi->done); + reinit_completion(&dspi->done); if (spicfg->io_type == SPI_IO_TYPE_INTR) set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 32200d4f8780..80d8f40f7e05 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -232,7 +232,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; - INIT_COMPLETION(mpc8xxx_spi->done); + reinit_completion(&mpc8xxx_spi->done); /* Set SPCOM[CS] and SPCOM[TRANLEN] field */ if ((t->len - 1) > SPCOM_TRANLEN_MAX) { diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 2129fcd1c31b..119f7af94537 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -339,7 +339,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; - INIT_COMPLETION(mpc8xxx_spi->done); + reinit_completion(&mpc8xxx_spi->done); if (mpc8xxx_spi->flags & SPI_CPM_MODE) ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 58d5ee0e4443..9602bbd8d7ea 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -167,7 +167,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi, } /* have the ISR trigger when the TX FIFO is empty */ - INIT_COMPLETION(mps->txisrdone); + reinit_completion(&mps->txisrdone); out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY); out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY); wait_for_completion(&mps->txisrdone); diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index de333059a9a7..73afb56c08cc 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -202,7 +202,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, if (!dma_xfer) return -ENOMEM; - INIT_COMPLETION(spi->c); + reinit_completion(&spi->c); /* Chip select was already programmed into CTRL0 */ ctrl0 = readl(ssp->base + HW_SSP_CTRL0); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 9e2020df9e0f..4c4b0a1219a7 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -890,7 +890,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, unsigned long flags; int use_dma; - INIT_COMPLETION(sdd->xfer_completion); + reinit_completion(&sdd->xfer_completion); /* Only BPW and Speed may change across transfers */ bpw = xfer->bits_per_word; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2a95435a6a11..c74298cf70e2 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -465,7 +465,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); /* start by setting frame bit */ - INIT_COMPLETION(p->done); + reinit_completion(&p->done); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 592b4aff651f..ed5e501c4652 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -305,8 +305,8 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; - INIT_COMPLETION(sspi->rx_done); - INIT_COMPLETION(sspi->tx_done); + reinit_completion(&sspi->rx_done); + reinit_completion(&sspi->tx_done); writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 9146bb3c2489..aaecfb3ebf58 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -451,7 +451,7 @@ static void tegra_spi_dma_complete(void *args) static int tegra_spi_start_tx_dma(struct tegra_spi_data *tspi, int len) { - INIT_COMPLETION(tspi->tx_dma_complete); + reinit_completion(&tspi->tx_dma_complete); tspi->tx_dma_desc = dmaengine_prep_slave_single(tspi->tx_dma_chan, tspi->tx_dma_phys, len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -470,7 +470,7 @@ static int tegra_spi_start_tx_dma(struct tegra_spi_data *tspi, int len) static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len) { - INIT_COMPLETION(tspi->rx_dma_complete); + reinit_completion(&tspi->rx_dma_complete); tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma_chan, tspi->rx_dma_phys, len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -844,7 +844,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { unsigned long cmd1; - INIT_COMPLETION(tspi->xfer_completion); + reinit_completion(&tspi->xfer_completion); cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 79be8ce6a9d1..4dc8e8129459 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -339,7 +339,7 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master, msg->actual_length = 0; single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { - INIT_COMPLETION(tsd->xfer_completion); + reinit_completion(&tsd->xfer_completion); ret = tegra_sflash_start_transfer_one(spi, xfer, is_first_msg, single_xfer); if (ret < 0) { diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index af0a67886ae8..e66715ba37ed 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -462,7 +462,7 @@ static void tegra_slink_dma_complete(void *args) static int tegra_slink_start_tx_dma(struct tegra_slink_data *tspi, int len) { - INIT_COMPLETION(tspi->tx_dma_complete); + reinit_completion(&tspi->tx_dma_complete); tspi->tx_dma_desc = dmaengine_prep_slave_single(tspi->tx_dma_chan, tspi->tx_dma_phys, len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -481,7 +481,7 @@ static int tegra_slink_start_tx_dma(struct tegra_slink_data *tspi, int len) static int tegra_slink_start_rx_dma(struct tegra_slink_data *tspi, int len) { - INIT_COMPLETION(tspi->rx_dma_complete); + reinit_completion(&tspi->rx_dma_complete); tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma_chan, tspi->rx_dma_phys, len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -836,7 +836,7 @@ static int tegra_slink_transfer_one(struct spi_master *master, struct tegra_slink_data *tspi = spi_master_get_devdata(master); int ret; - INIT_COMPLETION(tspi->xfer_completion); + reinit_completion(&tspi->xfer_completion); ret = tegra_slink_start_transfer_one(spi, xfer); if (ret < 0) { dev_err(tspi->dev, diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index ec3a83f52ea2..6d4ce4615163 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -258,7 +258,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->tx_ptr = t->tx_buf; xspi->rx_ptr = t->rx_buf; xspi->remaining_bytes = t->len; - INIT_COMPLETION(xspi->done); + reinit_completion(&xspi->done); /* Enable the transmit empty interrupt, which we use to determine diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 927998aa5e71..8d85ddc46011 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -571,7 +571,7 @@ static int spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { trace_spi_transfer_start(msg, xfer); - INIT_COMPLETION(master->xfer_completion); + reinit_completion(&master->xfer_completion); ret = master->transfer_one(master, msg->spi, xfer); if (ret < 0) { diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index aeae76b77be5..e2dd7830b320 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -783,7 +783,7 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, if (!ret) return -EBUSY; - INIT_COMPLETION(lradc->completion); + reinit_completion(&lradc->completion); /* * No buffered operation in progress, map the channel and trigger it. diff --git a/drivers/staging/media/solo6x10/solo6x10-p2m.c b/drivers/staging/media/solo6x10/solo6x10-p2m.c index 333594189b81..7f2f2472655b 100644 --- a/drivers/staging/media/solo6x10/solo6x10-p2m.c +++ b/drivers/staging/media/solo6x10/solo6x10-p2m.c @@ -87,7 +87,7 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev, if (mutex_lock_interruptible(&p2m_dev->mutex)) return -EINTR; - INIT_COMPLETION(p2m_dev->completion); + reinit_completion(&p2m_dev->completion); p2m_dev->error = 0; if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) { diff --git a/drivers/staging/tidspbridge/core/sync.c b/drivers/staging/tidspbridge/core/sync.c index 7bb550acaf4a..743ff09d82d2 100644 --- a/drivers/staging/tidspbridge/core/sync.c +++ b/drivers/staging/tidspbridge/core/sync.c @@ -72,7 +72,7 @@ int sync_wait_on_multiple_events(struct sync_object **events, spin_lock_bh(&sync_lock); for (i = 0; i < count; i++) { if (completion_done(&events[i]->comp)) { - INIT_COMPLETION(events[i]->comp); + reinit_completion(&events[i]->comp); *index = i; spin_unlock_bh(&sync_lock); status = 0; @@ -92,7 +92,7 @@ int sync_wait_on_multiple_events(struct sync_object **events, spin_lock_bh(&sync_lock); for (i = 0; i < count; i++) { if (completion_done(&events[i]->comp)) { - INIT_COMPLETION(events[i]->comp); + reinit_completion(&events[i]->comp); *index = i; status = 0; } diff --git a/drivers/staging/tidspbridge/include/dspbridge/sync.h b/drivers/staging/tidspbridge/include/dspbridge/sync.h index 58a0d5c5543d..fc19b9707087 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/sync.h +++ b/drivers/staging/tidspbridge/include/dspbridge/sync.h @@ -59,7 +59,7 @@ static inline void sync_init_event(struct sync_object *event) static inline void sync_reset_event(struct sync_object *event) { - INIT_COMPLETION(event->comp); + reinit_completion(&event->comp); event->multi_comp = NULL; } diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c index 6d04eb48bfbc..1aa4a3fd0f1b 100644 --- a/drivers/staging/tidspbridge/rmgr/drv_interface.c +++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c @@ -332,7 +332,7 @@ static void bridge_recover(struct work_struct *work) struct dev_object *dev; struct cfg_devnode *dev_node; if (atomic_read(&bridge_cref)) { - INIT_COMPLETION(bridge_comp); + reinit_completion(&bridge_comp); while (!wait_for_completion_timeout(&bridge_comp, msecs_to_jiffies(REC_TIMEOUT))) pr_info("%s:%d handle(s) still opened\n", @@ -348,7 +348,7 @@ static void bridge_recover(struct work_struct *work) void bridge_recover_schedule(void) { - INIT_COMPLETION(bridge_open_comp); + reinit_completion(&bridge_open_comp); recover = true; queue_work(bridge_rec_queue, &bridge_recovery_work); } @@ -389,7 +389,7 @@ static int omap3_bridge_startup(struct platform_device *pdev) #ifdef CONFIG_TIDSPBRIDGE_RECOVERY bridge_rec_queue = create_workqueue("bridge_rec_queue"); INIT_WORK(&bridge_recovery_work, bridge_recover); - INIT_COMPLETION(bridge_comp); + reinit_completion(&bridge_comp); #endif #ifdef CONFIG_PM diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c index 0e888621f484..7332e2ca4615 100644 --- a/drivers/tty/metag_da.c +++ b/drivers/tty/metag_da.c @@ -495,7 +495,7 @@ static int dashtty_write(struct tty_struct *tty, const unsigned char *buf, count = dport->xmit_cnt; /* xmit buffer no longer empty? */ if (count) - INIT_COMPLETION(dport->xmit_empty); + reinit_completion(&dport->xmit_empty); mutex_unlock(&dport->xmit_lock); if (total) { diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index aa491627a45b..892cc96466eb 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -344,7 +344,7 @@ void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) /* it could happen that we reinitialize this completion, while * somebody was waiting for that completion. The timeout and * while loop handle such cases, but this might be improved */ - INIT_COMPLETION(c67x00->endpoint_disable); + reinit_completion(&c67x00->endpoint_disable); c67x00_sched_kick(c67x00); wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 44cf775a8627..774e8b89cdb5 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -373,7 +373,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) if (req->buf == NULL) req->buf = (void *)0xDEADBABE; - INIT_COMPLETION(ffs->ep0req_completion); + reinit_completion(&ffs->ep0req_completion); ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); if (unlikely(ret < 0)) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 84657e07dc5d..439c951f261b 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -455,7 +455,7 @@ static int parport_prologue(struct parport *pp) return -1; } mos_parport->msg_pending = true; /* synch usb call pending */ - INIT_COMPLETION(mos_parport->syncmsg_compl); + reinit_completion(&mos_parport->syncmsg_compl); spin_unlock(&release_lock); mutex_lock(&mos_parport->serial->disc_mutex); diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 7eed957b6014..85edabfdef5a 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -220,7 +220,7 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, case MIPI_DSI_DCS_LONG_WRITE: { unsigned int size, payload = 0; - INIT_COMPLETION(dsim_wr_comp); + reinit_completion(&dsim_wr_comp); size = data_size * 4; @@ -356,7 +356,7 @@ int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id, msleep(20); mutex_lock(&dsim->lock); - INIT_COMPLETION(dsim_rd_comp); + reinit_completion(&dsim_rd_comp); exynos_mipi_dsi_rd_tx_header(dsim, MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size); diff --git a/drivers/video/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/omap2/displays-new/encoder-tpd12s015.c index 798ef200b055..d5c936cb217f 100644 --- a/drivers/video/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/omap2/displays-new/encoder-tpd12s015.c @@ -69,7 +69,7 @@ static int tpd_connect(struct omap_dss_device *dssdev, dst->src = dssdev; dssdev->dst = dst; - INIT_COMPLETION(ddata->hpd_completion); + reinit_completion(&ddata->hpd_completion); gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); /* DC-DC converter needs at max 300us to get to 90% of 5V */ diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 000eae2782b6..2f6735dbf1a9 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -392,7 +392,7 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, wait_for_completion(&ecr->completion); rc = ecr->rc; - INIT_COMPLETION(ecr->completion); + reinit_completion(&ecr->completion); } out: ablkcipher_request_free(req); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c8e729deb4f7..74a7e12e10df 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -244,7 +244,7 @@ static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl) set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); spin_lock(&tbl->slot_tbl_lock); if (tbl->highest_used_slotid != NFS4_NO_SLOT) { - INIT_COMPLETION(tbl->complete); + reinit_completion(&tbl->complete); spin_unlock(&tbl->slot_tbl_lock); return wait_for_completion_interruptible(&tbl->complete); } diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 3a44a648dae7..3407b2c62b21 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -1304,7 +1304,7 @@ static int ocfs2_wait_for_mask(struct ocfs2_mask_waiter *mw) { wait_for_completion(&mw->mw_complete); /* Re-arm the completion in case we want to wait on it again */ - INIT_COMPLETION(mw->mw_complete); + reinit_completion(&mw->mw_complete); return mw->mw_status; } @@ -1355,7 +1355,7 @@ static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, else ret = mw->mw_status; /* Re-arm the completion in case we want to wait on it again */ - INIT_COMPLETION(mw->mw_complete); + reinit_completion(&mw->mw_complete); return ret; } diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index 6feee6614193..57bcd31fcc12 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c @@ -543,7 +543,7 @@ static int dice_change_rate(struct dice *dice, unsigned int clock_rate) __be32 value; int err; - INIT_COMPLETION(dice->clock_accepted); + reinit_completion(&dice->clock_accepted); value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1); err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 2acf987844e8..350ba23a9893 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -74,7 +74,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97) if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) return; /* Return if already active */ - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; @@ -103,7 +103,7 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, s3c_ac97_activate(ac97); - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); @@ -140,7 +140,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, s3c_ac97_activate(ac97); - INIT_COMPLETION(s3c_ac97.done); + reinit_completion(&s3c_ac97.done); ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); -- cgit v1.2.3 From f02b9ac35a47dff745c7637fbc095f01cc03646e Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Tue, 19 Nov 2013 18:57:24 -0700 Subject: virtio-blk: virtqueue_kick() must be ordered with other virtqueue operations It isn't safe to call it without holding the vblk->vq_lock. Reported-by: Dave Chinner Signed-off-by: Shaohua Li Fixed another condition of virtqueue_kick() not holding the lock. Signed-off-by: Jens Axboe --- drivers/block/virtio_blk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 588479d58f52..6a680d4de7f1 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -199,15 +199,16 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req) spin_lock_irqsave(&vblk->vq_lock, flags); if (__virtblk_add_req(vblk->vq, vbr, vbr->sg, num) < 0) { + virtqueue_kick(vblk->vq); spin_unlock_irqrestore(&vblk->vq_lock, flags); blk_mq_stop_hw_queue(hctx); - virtqueue_kick(vblk->vq); return BLK_MQ_RQ_QUEUE_BUSY; } - spin_unlock_irqrestore(&vblk->vq_lock, flags); if (last) virtqueue_kick(vblk->vq); + + spin_unlock_irqrestore(&vblk->vq_lock, flags); return BLK_MQ_RQ_QUEUE_OK; } -- cgit v1.2.3 From 044c8d4b15743f6e0a4cb6f2aeb32745a116ebff Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Thu, 21 Nov 2013 14:32:01 -0800 Subject: kernel: remove CONFIG_USE_GENERIC_SMP_HELPERS cleanly Remove CONFIG_USE_GENERIC_SMP_HELPERS left by commit 0a06ff068f12 ("kernel: remove CONFIG_USE_GENERIC_SMP_HELPERS"). Signed-off-by: Yuanhan Liu Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/null_blk.c | 8 ++++---- net/Kconfig | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index b5d842370cc9..ea192ec029c4 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -223,7 +223,7 @@ static void null_softirq_done_fn(struct request *rq) blk_end_request_all(rq, 0); } -#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS) +#ifdef CONFIG_SMP static void null_ipi_cmd_end_io(void *data) { @@ -260,7 +260,7 @@ static void null_cmd_end_ipi(struct nullb_cmd *cmd) put_cpu(); } -#endif /* CONFIG_SMP && CONFIG_USE_GENERIC_SMP_HELPERS */ +#endif /* CONFIG_SMP */ static inline void null_handle_cmd(struct nullb_cmd *cmd) { @@ -270,7 +270,7 @@ static inline void null_handle_cmd(struct nullb_cmd *cmd) end_cmd(cmd); break; case NULL_IRQ_SOFTIRQ: -#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS) +#ifdef CONFIG_SMP null_cmd_end_ipi(cmd); #else end_cmd(cmd); @@ -571,7 +571,7 @@ static int __init null_init(void) { unsigned int i; -#if !defined(CONFIG_SMP) || !defined(CONFIG_USE_GENERIC_SMP_HELPERS) +#if !defined(CONFIG_SMP) if (irqmode == NULL_IRQ_SOFTIRQ) { pr_warn("null_blk: softirq completions not available.\n"); pr_warn("null_blk: using direct completions.\n"); diff --git a/net/Kconfig b/net/Kconfig index 0715db64a5c3..d334678c0bd8 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -224,7 +224,7 @@ source "net/hsr/Kconfig" config RPS boolean - depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS + depends on SMP && SYSFS default y config RFS_ACCEL @@ -235,7 +235,7 @@ config RFS_ACCEL config XPS boolean - depends on SMP && USE_GENERIC_SMP_HELPERS + depends on SMP default y config NETPRIO_CGROUP -- cgit v1.2.3 From 427bfe07e6744c058ce6fc4aa187cda96b635539 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 14 Nov 2013 14:29:52 -0700 Subject: xen-blkfront: Silence pfn maybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pfn cannot actually be used unless (!info->feature_persistent), nor is pfn accessed in get_grant() unless (!info->feature_persistent), but silence this warning anyway. gcc-4.8 drivers/block/xen-blkfront.c: In function 'do_blkif_request': drivers/block/xen-blkfront.c:508:20: warning: 'pfn' may be used uninitialized in this function [-Wmaybe-uninitialized] gnt_list_entry = get_grant(&gref_head, pfn, info); ^ drivers/block/xen-blkfront.c:492:19: note: 'pfn' was declared here unsigned long pfn; Cc: Konrad Rzeszutek Wilk Cc: Boris Ostrovsky Cc: David Vrabel Signed-off-by: Tim Gardner Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Roger Pau MonnĂ© --- drivers/block/xen-blkfront.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 432db1b59b00..5f926de61950 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -489,7 +489,7 @@ static int blkif_queue_request(struct request *req) if ((ring_req->operation == BLKIF_OP_INDIRECT) && (i % SEGS_PER_INDIRECT_FRAME == 0)) { - unsigned long pfn; + unsigned long uninitialized_var(pfn); if (segments) kunmap_atomic(segments); -- cgit v1.2.3 From 2f089cb89d2f47702c31bd584c12badc88bbe17c Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 9 Nov 2013 13:36:09 -0200 Subject: block: xen-blkfront: Fix possible NULL ptr dereference In the blkif_release function the bdget_disk() call might returns a NULL ptr which might be dereferenced on bdev->bd_openers checking Signed-off-by: Felipe Pena Signed-off-by: Konrad Rzeszutek Wilk [v2: Added WARN per Roger's suggestion] --- drivers/block/xen-blkfront.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/block') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5f926de61950..c4a4c9006288 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2011,6 +2011,10 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) bdev = bdget_disk(disk, 0); + if (!bdev) { + WARN(1, "Block device %s yanked out from us!\n", disk->disk_name); + goto out_mutex; + } if (bdev->bd_openers) goto out; @@ -2041,6 +2045,7 @@ static void blkif_release(struct gendisk *disk, fmode_t mode) out: bdput(bdev); +out_mutex: mutex_unlock(&blkfront_mutex); } -- cgit v1.2.3 From 57053d8c5c59562cac156513740c10b502a40968 Mon Sep 17 00:00:00 2001 From: Matias Bjorling Date: Tue, 10 Dec 2013 16:50:38 +0100 Subject: null_blk: mem garbage on NUMA systems during init For NUMA systems, initializing the blk-mq layer and using per node hctx. We initialize submit queues to 1, while blk-mq nr_hw_queues is initialized to the number of NUMA nodes. This makes the null_init_hctx function overwrite memory outside of what it allocated. In my case it lead to writing garbage into struct request_queue's mq_map. Signed-off-by: Matias Bjorling Cc: Jens Axboe Signed-off-by: Linus Torvalds --- drivers/block/null_blk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/block') diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index ea192ec029c4..f370fc13aea5 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -495,23 +495,23 @@ static int null_add_dev(void) spin_lock_init(&nullb->lock); + if (queue_mode == NULL_Q_MQ && use_per_node_hctx) + submit_queues = nr_online_nodes; + if (setup_queues(nullb)) goto err; if (queue_mode == NULL_Q_MQ) { null_mq_reg.numa_node = home_node; null_mq_reg.queue_depth = hw_queue_depth; + null_mq_reg.nr_hw_queues = submit_queues; if (use_per_node_hctx) { null_mq_reg.ops->alloc_hctx = null_alloc_hctx; null_mq_reg.ops->free_hctx = null_free_hctx; - - null_mq_reg.nr_hw_queues = nr_online_nodes; } else { null_mq_reg.ops->alloc_hctx = blk_mq_alloc_single_hw_queue; null_mq_reg.ops->free_hctx = blk_mq_free_single_hw_queue; - - null_mq_reg.nr_hw_queues = submit_queues; } nullb->q = blk_mq_init_queue(&null_mq_reg, nullb); -- cgit v1.2.3