aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r--drivers/scsi/scsi_lib.c66
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3574ba935af8..701a328f7beb 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -16,6 +16,7 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/pci.h> 17#include <linux/pci.h>
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/hardirq.h>
19 20
20#include <scsi/scsi.h> 21#include <scsi/scsi.h>
21#include <scsi/scsi_dbg.h> 22#include <scsi/scsi_dbg.h>
@@ -436,6 +437,7 @@ free_bios:
436 * scsi_execute_async - insert request 437 * scsi_execute_async - insert request
437 * @sdev: scsi device 438 * @sdev: scsi device
438 * @cmd: scsi command 439 * @cmd: scsi command
440 * @cmd_len: length of scsi cdb
439 * @data_direction: data direction 441 * @data_direction: data direction
440 * @buffer: data buffer (this can be a kernel buffer or scatterlist) 442 * @buffer: data buffer (this can be a kernel buffer or scatterlist)
441 * @bufflen: len of buffer 443 * @bufflen: len of buffer
@@ -445,7 +447,7 @@ free_bios:
445 * @flags: or into request flags 447 * @flags: or into request flags
446 **/ 448 **/
447int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, 449int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
448 int data_direction, void *buffer, unsigned bufflen, 450 int cmd_len, int data_direction, void *buffer, unsigned bufflen,
449 int use_sg, int timeout, int retries, void *privdata, 451 int use_sg, int timeout, int retries, void *privdata,
450 void (*done)(void *, char *, int, int), gfp_t gfp) 452 void (*done)(void *, char *, int, int), gfp_t gfp)
451{ 453{
@@ -472,7 +474,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
472 if (err) 474 if (err)
473 goto free_req; 475 goto free_req;
474 476
475 req->cmd_len = COMMAND_SIZE(cmd[0]); 477 req->cmd_len = cmd_len;
476 memcpy(req->cmd, cmd, req->cmd_len); 478 memcpy(req->cmd, cmd, req->cmd_len);
477 req->sense = sioc->sense; 479 req->sense = sioc->sense;
478 req->sense_len = 0; 480 req->sense_len = 0;
@@ -1496,7 +1498,7 @@ static void scsi_kill_request(struct request *req, request_queue_t *q)
1496static void scsi_softirq_done(struct request *rq) 1498static void scsi_softirq_done(struct request *rq)
1497{ 1499{
1498 struct scsi_cmnd *cmd = rq->completion_data; 1500 struct scsi_cmnd *cmd = rq->completion_data;
1499 unsigned long wait_for = cmd->allowed * cmd->timeout_per_command; 1501 unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
1500 int disposition; 1502 int disposition;
1501 1503
1502 INIT_LIST_HEAD(&cmd->eh_entry); 1504 INIT_LIST_HEAD(&cmd->eh_entry);
@@ -2247,3 +2249,61 @@ scsi_target_unblock(struct device *dev)
2247 device_for_each_child(dev, NULL, target_unblock); 2249 device_for_each_child(dev, NULL, target_unblock);
2248} 2250}
2249EXPORT_SYMBOL_GPL(scsi_target_unblock); 2251EXPORT_SYMBOL_GPL(scsi_target_unblock);
2252
2253
2254struct work_queue_work {
2255 struct work_struct work;
2256 void (*fn)(void *);
2257 void *data;
2258};
2259
2260static void execute_in_process_context_work(void *data)
2261{
2262 void (*fn)(void *data);
2263 struct work_queue_work *wqw = data;
2264
2265 fn = wqw->fn;
2266 data = wqw->data;
2267
2268 kfree(wqw);
2269
2270 fn(data);
2271}
2272
2273/**
2274 * scsi_execute_in_process_context - reliably execute the routine with user context
2275 * @fn: the function to execute
2276 * @data: data to pass to the function
2277 *
2278 * Executes the function immediately if process context is available,
2279 * otherwise schedules the function for delayed execution.
2280 *
2281 * Returns: 0 - function was executed
2282 * 1 - function was scheduled for execution
2283 * <0 - error
2284 */
2285int scsi_execute_in_process_context(void (*fn)(void *data), void *data)
2286{
2287 struct work_queue_work *wqw;
2288
2289 if (!in_interrupt()) {
2290 fn(data);
2291 return 0;
2292 }
2293
2294 wqw = kmalloc(sizeof(struct work_queue_work), GFP_ATOMIC);
2295
2296 if (unlikely(!wqw)) {
2297 printk(KERN_ERR "Failed to allocate memory\n");
2298 WARN_ON(1);
2299 return -ENOMEM;
2300 }
2301
2302 INIT_WORK(&wqw->work, execute_in_process_context_work, wqw);
2303 wqw->fn = fn;
2304 wqw->data = data;
2305 schedule_work(&wqw->work);
2306
2307 return 1;
2308}
2309EXPORT_SYMBOL_GPL(scsi_execute_in_process_context);