diff options
-rw-r--r-- | drivers/scsi/hosts.c | 4 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 43 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 33 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 10 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 43 |
5 files changed, 107 insertions, 26 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 2ffdc9e0532d..38c3a291efac 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -263,6 +263,10 @@ static void scsi_host_dev_release(struct device *dev) | |||
263 | kthread_stop(shost->ehandler); | 263 | kthread_stop(shost->ehandler); |
264 | if (shost->work_q) | 264 | if (shost->work_q) |
265 | destroy_workqueue(shost->work_q); | 265 | destroy_workqueue(shost->work_q); |
266 | if (shost->uspace_req_q) { | ||
267 | kfree(shost->uspace_req_q->queuedata); | ||
268 | scsi_free_queue(shost->uspace_req_q); | ||
269 | } | ||
266 | 270 | ||
267 | scsi_destroy_command_freelist(shost); | 271 | scsi_destroy_command_freelist(shost); |
268 | if (shost->bqt) | 272 | if (shost->bqt) |
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 780d6dc92b42..fafc00deaade 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -156,8 +156,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { | |||
156 | 156 | ||
157 | static DEFINE_MUTEX(host_cmd_pool_mutex); | 157 | static DEFINE_MUTEX(host_cmd_pool_mutex); |
158 | 158 | ||
159 | static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, | 159 | struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) |
160 | gfp_t gfp_mask) | ||
161 | { | 160 | { |
162 | struct scsi_cmnd *cmd; | 161 | struct scsi_cmnd *cmd; |
163 | 162 | ||
@@ -178,6 +177,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, | |||
178 | 177 | ||
179 | return cmd; | 178 | return cmd; |
180 | } | 179 | } |
180 | EXPORT_SYMBOL_GPL(__scsi_get_command); | ||
181 | 181 | ||
182 | /* | 182 | /* |
183 | * Function: scsi_get_command() | 183 | * Function: scsi_get_command() |
@@ -214,9 +214,29 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) | |||
214 | put_device(&dev->sdev_gendev); | 214 | put_device(&dev->sdev_gendev); |
215 | 215 | ||
216 | return cmd; | 216 | return cmd; |
217 | } | 217 | } |
218 | EXPORT_SYMBOL(scsi_get_command); | 218 | EXPORT_SYMBOL(scsi_get_command); |
219 | 219 | ||
220 | void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, | ||
221 | struct device *dev) | ||
222 | { | ||
223 | unsigned long flags; | ||
224 | |||
225 | /* changing locks here, don't need to restore the irq state */ | ||
226 | spin_lock_irqsave(&shost->free_list_lock, flags); | ||
227 | if (unlikely(list_empty(&shost->free_list))) { | ||
228 | list_add(&cmd->list, &shost->free_list); | ||
229 | cmd = NULL; | ||
230 | } | ||
231 | spin_unlock_irqrestore(&shost->free_list_lock, flags); | ||
232 | |||
233 | if (likely(cmd != NULL)) | ||
234 | kmem_cache_free(shost->cmd_pool->slab, cmd); | ||
235 | |||
236 | put_device(dev); | ||
237 | } | ||
238 | EXPORT_SYMBOL(__scsi_put_command); | ||
239 | |||
220 | /* | 240 | /* |
221 | * Function: scsi_put_command() | 241 | * Function: scsi_put_command() |
222 | * | 242 | * |
@@ -231,26 +251,15 @@ EXPORT_SYMBOL(scsi_get_command); | |||
231 | void scsi_put_command(struct scsi_cmnd *cmd) | 251 | void scsi_put_command(struct scsi_cmnd *cmd) |
232 | { | 252 | { |
233 | struct scsi_device *sdev = cmd->device; | 253 | struct scsi_device *sdev = cmd->device; |
234 | struct Scsi_Host *shost = sdev->host; | ||
235 | unsigned long flags; | 254 | unsigned long flags; |
236 | 255 | ||
237 | /* serious error if the command hasn't come from a device list */ | 256 | /* serious error if the command hasn't come from a device list */ |
238 | spin_lock_irqsave(&cmd->device->list_lock, flags); | 257 | spin_lock_irqsave(&cmd->device->list_lock, flags); |
239 | BUG_ON(list_empty(&cmd->list)); | 258 | BUG_ON(list_empty(&cmd->list)); |
240 | list_del_init(&cmd->list); | 259 | list_del_init(&cmd->list); |
241 | spin_unlock(&cmd->device->list_lock); | 260 | spin_unlock_irqrestore(&cmd->device->list_lock, flags); |
242 | /* changing locks here, don't need to restore the irq state */ | ||
243 | spin_lock(&shost->free_list_lock); | ||
244 | if (unlikely(list_empty(&shost->free_list))) { | ||
245 | list_add(&cmd->list, &shost->free_list); | ||
246 | cmd = NULL; | ||
247 | } | ||
248 | spin_unlock_irqrestore(&shost->free_list_lock, flags); | ||
249 | 261 | ||
250 | if (likely(cmd != NULL)) | 262 | __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev); |
251 | kmem_cache_free(shost->cmd_pool->slab, cmd); | ||
252 | |||
253 | put_device(&sdev->sdev_gendev); | ||
254 | } | 263 | } |
255 | EXPORT_SYMBOL(scsi_put_command); | 264 | EXPORT_SYMBOL(scsi_put_command); |
256 | 265 | ||
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 2f12f9f12fcb..fb616c69151f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -704,7 +704,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, | |||
704 | return NULL; | 704 | return NULL; |
705 | } | 705 | } |
706 | 706 | ||
707 | static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) | 707 | struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) |
708 | { | 708 | { |
709 | struct scsi_host_sg_pool *sgp; | 709 | struct scsi_host_sg_pool *sgp; |
710 | struct scatterlist *sgl; | 710 | struct scatterlist *sgl; |
@@ -745,7 +745,9 @@ static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_m | |||
745 | return sgl; | 745 | return sgl; |
746 | } | 746 | } |
747 | 747 | ||
748 | static void scsi_free_sgtable(struct scatterlist *sgl, int index) | 748 | EXPORT_SYMBOL(scsi_alloc_sgtable); |
749 | |||
750 | void scsi_free_sgtable(struct scatterlist *sgl, int index) | ||
749 | { | 751 | { |
750 | struct scsi_host_sg_pool *sgp; | 752 | struct scsi_host_sg_pool *sgp; |
751 | 753 | ||
@@ -755,6 +757,8 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index) | |||
755 | mempool_free(sgl, sgp->pool); | 757 | mempool_free(sgl, sgp->pool); |
756 | } | 758 | } |
757 | 759 | ||
760 | EXPORT_SYMBOL(scsi_free_sgtable); | ||
761 | |||
758 | /* | 762 | /* |
759 | * Function: scsi_release_buffers() | 763 | * Function: scsi_release_buffers() |
760 | * | 764 | * |
@@ -1567,29 +1571,40 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) | |||
1567 | } | 1571 | } |
1568 | EXPORT_SYMBOL(scsi_calculate_bounce_limit); | 1572 | EXPORT_SYMBOL(scsi_calculate_bounce_limit); |
1569 | 1573 | ||
1570 | struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) | 1574 | struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, |
1575 | request_fn_proc *request_fn) | ||
1571 | { | 1576 | { |
1572 | struct Scsi_Host *shost = sdev->host; | ||
1573 | struct request_queue *q; | 1577 | struct request_queue *q; |
1574 | 1578 | ||
1575 | q = blk_init_queue(scsi_request_fn, NULL); | 1579 | q = blk_init_queue(request_fn, NULL); |
1576 | if (!q) | 1580 | if (!q) |
1577 | return NULL; | 1581 | return NULL; |
1578 | 1582 | ||
1579 | blk_queue_prep_rq(q, scsi_prep_fn); | ||
1580 | |||
1581 | blk_queue_max_hw_segments(q, shost->sg_tablesize); | 1583 | blk_queue_max_hw_segments(q, shost->sg_tablesize); |
1582 | blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); | 1584 | blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); |
1583 | blk_queue_max_sectors(q, shost->max_sectors); | 1585 | blk_queue_max_sectors(q, shost->max_sectors); |
1584 | blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); | 1586 | blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); |
1585 | blk_queue_segment_boundary(q, shost->dma_boundary); | 1587 | blk_queue_segment_boundary(q, shost->dma_boundary); |
1586 | blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); | ||
1587 | blk_queue_softirq_done(q, scsi_softirq_done); | ||
1588 | 1588 | ||
1589 | if (!shost->use_clustering) | 1589 | if (!shost->use_clustering) |
1590 | clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); | 1590 | clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); |
1591 | return q; | 1591 | return q; |
1592 | } | 1592 | } |
1593 | EXPORT_SYMBOL(__scsi_alloc_queue); | ||
1594 | |||
1595 | struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) | ||
1596 | { | ||
1597 | struct request_queue *q; | ||
1598 | |||
1599 | q = __scsi_alloc_queue(sdev->host, scsi_request_fn); | ||
1600 | if (!q) | ||
1601 | return NULL; | ||
1602 | |||
1603 | blk_queue_prep_rq(q, scsi_prep_fn); | ||
1604 | blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); | ||
1605 | blk_queue_softirq_done(q, scsi_softirq_done); | ||
1606 | return q; | ||
1607 | } | ||
1593 | 1608 | ||
1594 | void scsi_free_queue(struct request_queue *q) | 1609 | void scsi_free_queue(struct request_queue *q) |
1595 | { | 1610 | { |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index be117f812deb..d6948d0e8cdb 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | struct request; | 9 | struct request; |
10 | struct scatterlist; | 10 | struct scatterlist; |
11 | struct Scsi_Host; | ||
11 | struct scsi_device; | 12 | struct scsi_device; |
12 | 13 | ||
13 | 14 | ||
@@ -72,6 +73,9 @@ struct scsi_cmnd { | |||
72 | unsigned short use_sg; /* Number of pieces of scatter-gather */ | 73 | unsigned short use_sg; /* Number of pieces of scatter-gather */ |
73 | unsigned short sglist_len; /* size of malloc'd scatter-gather list */ | 74 | unsigned short sglist_len; /* size of malloc'd scatter-gather list */ |
74 | 75 | ||
76 | /* offset in cmd we are at (for multi-transfer tgt cmds) */ | ||
77 | unsigned offset; | ||
78 | |||
75 | unsigned underflow; /* Return error if less than | 79 | unsigned underflow; /* Return error if less than |
76 | this amount is transferred */ | 80 | this amount is transferred */ |
77 | 81 | ||
@@ -119,7 +123,10 @@ struct scsi_cmnd { | |||
119 | }; | 123 | }; |
120 | 124 | ||
121 | extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); | 125 | extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); |
126 | extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t); | ||
122 | extern void scsi_put_command(struct scsi_cmnd *); | 127 | extern void scsi_put_command(struct scsi_cmnd *); |
128 | extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *, | ||
129 | struct device *); | ||
123 | extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); | 130 | extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); |
124 | extern void scsi_finish_command(struct scsi_cmnd *cmd); | 131 | extern void scsi_finish_command(struct scsi_cmnd *cmd); |
125 | extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); | 132 | extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); |
@@ -128,4 +135,7 @@ extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, | |||
128 | size_t *offset, size_t *len); | 135 | size_t *offset, size_t *len); |
129 | extern void scsi_kunmap_atomic_sg(void *virt); | 136 | extern void scsi_kunmap_atomic_sg(void *virt); |
130 | 137 | ||
138 | extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t); | ||
139 | extern void scsi_free_sgtable(struct scatterlist *, int); | ||
140 | |||
131 | #endif /* _SCSI_SCSI_CMND_H */ | 141 | #endif /* _SCSI_SCSI_CMND_H */ |
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 6d8945d71c65..7f1f411d07af 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/workqueue.h> | 7 | #include <linux/workqueue.h> |
8 | #include <linux/mutex.h> | 8 | #include <linux/mutex.h> |
9 | 9 | ||
10 | struct request_queue; | ||
10 | struct block_device; | 11 | struct block_device; |
11 | struct completion; | 12 | struct completion; |
12 | struct module; | 13 | struct module; |
@@ -124,6 +125,39 @@ struct scsi_host_template { | |||
124 | void (*done)(struct scsi_cmnd *)); | 125 | void (*done)(struct scsi_cmnd *)); |
125 | 126 | ||
126 | /* | 127 | /* |
128 | * The transfer functions are used to queue a scsi command to | ||
129 | * the LLD. When the driver is finished processing the command | ||
130 | * the done callback is invoked. | ||
131 | * | ||
132 | * return values: see queuecommand | ||
133 | * | ||
134 | * If the LLD accepts the cmd, it should set the result to an | ||
135 | * appropriate value when completed before calling the done function. | ||
136 | * | ||
137 | * STATUS: REQUIRED FOR TARGET DRIVERS | ||
138 | */ | ||
139 | /* TODO: rename */ | ||
140 | int (* transfer_response)(struct scsi_cmnd *, | ||
141 | void (*done)(struct scsi_cmnd *)); | ||
142 | /* | ||
143 | * This is called to inform the LLD to transfer cmd->request_bufflen | ||
144 | * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg | ||
145 | * speciefies the number of scatterlist entried in the command | ||
146 | * and cmd->request_buffer contains the scatterlist. | ||
147 | * | ||
148 | * If the command cannot be processed in one transfer_data call | ||
149 | * becuase a scatterlist within the LLD's limits cannot be | ||
150 | * created then transfer_data will be called multiple times. | ||
151 | * It is initially called from process context, and later | ||
152 | * calls are from the interrup context. | ||
153 | */ | ||
154 | int (* transfer_data)(struct scsi_cmnd *, | ||
155 | void (*done)(struct scsi_cmnd *)); | ||
156 | |||
157 | /* Used as callback for the completion of task management request. */ | ||
158 | int (* tsk_mgmt_response)(u64 mid, int result); | ||
159 | |||
160 | /* | ||
127 | * This is an error handling strategy routine. You don't need to | 161 | * This is an error handling strategy routine. You don't need to |
128 | * define one of these if you don't want to - there is a default | 162 | * define one of these if you don't want to - there is a default |
129 | * routine that is present that should work in most cases. For those | 163 | * routine that is present that should work in most cases. For those |
@@ -589,6 +623,12 @@ struct Scsi_Host { | |||
589 | */ | 623 | */ |
590 | unsigned int max_host_blocked; | 624 | unsigned int max_host_blocked; |
591 | 625 | ||
626 | /* | ||
627 | * q used for scsi_tgt msgs, async events or any other requests that | ||
628 | * need to be processed in userspace | ||
629 | */ | ||
630 | struct request_queue *uspace_req_q; | ||
631 | |||
592 | /* legacy crap */ | 632 | /* legacy crap */ |
593 | unsigned long base; | 633 | unsigned long base; |
594 | unsigned long io_port; | 634 | unsigned long io_port; |
@@ -687,6 +727,9 @@ extern void scsi_unblock_requests(struct Scsi_Host *); | |||
687 | extern void scsi_block_requests(struct Scsi_Host *); | 727 | extern void scsi_block_requests(struct Scsi_Host *); |
688 | 728 | ||
689 | struct class_container; | 729 | struct class_container; |
730 | |||
731 | extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, | ||
732 | void (*) (struct request_queue *)); | ||
690 | /* | 733 | /* |
691 | * These two functions are used to allocate and free a pseudo device | 734 | * These two functions are used to allocate and free a pseudo device |
692 | * which will connect to the host adapter itself rather than any | 735 | * which will connect to the host adapter itself rather than any |