Skip to content

Commit

Permalink
[SCSI] use scatter lists for all block pc requests and simplify hw ha…
Browse files Browse the repository at this point in the history
…ndlers

Here's the proof of concept for this one.  It converts scsi_wait_req to
do correct REQ_BLOCK_PC submission (and works nicely in my setup).

The final goal should be to eliminate struct scsi_request, but that
can't be done until the character submission paths of sg and st are also
modified.

There's some loss of functionality to this: retries are no longer
controllable (except by setting REQ_FASTFAIL) and the wait_req API needs
to be altered, but it looks very nice.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
James Bottomley authored and James Bottomley committed Aug 28, 2005
1 parent 31151ba commit e537a36
Showing 1 changed file with 59 additions and 37 deletions.
96 changes: 59 additions & 37 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,23 +232,6 @@ void scsi_do_req(struct scsi_request *sreq, const void *cmnd,
}
EXPORT_SYMBOL(scsi_do_req);

static void scsi_wait_done(struct scsi_cmnd *cmd)
{
struct request *req = cmd->request;
struct request_queue *q = cmd->device->request_queue;
unsigned long flags;

req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */

spin_lock_irqsave(q->queue_lock, flags);
if (blk_rq_tagged(req))
blk_queue_end_tag(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);

if (req->waiting)
complete(req->waiting);
}

/* This is the end routine we get to if a command was never attached
* to the request. Simply complete the request without changing
* rq_status; this will cause a DRIVER_ERROR. */
Expand All @@ -263,19 +246,36 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
unsigned bufflen, int timeout, int retries)
{
DECLARE_COMPLETION(wait);

sreq->sr_request->waiting = &wait;
sreq->sr_request->rq_status = RQ_SCSI_BUSY;
sreq->sr_request->end_io = scsi_wait_req_end_io;
scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
timeout, retries);
struct request *req;

if (bufflen)
req = blk_rq_map_kern(sreq->sr_device->request_queue,
sreq->sr_data_direction == DMA_TO_DEVICE,
buffer, bufflen, __GFP_WAIT);
else
req = blk_get_request(sreq->sr_device->request_queue, READ,
__GFP_WAIT);
req->flags |= REQ_NOMERGE;
req->waiting = &wait;
req->end_io = scsi_wait_req_end_io;
req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]);
req->sense = sreq->sr_sense_buffer;
req->sense_len = 0;
memcpy(req->cmd, cmnd, req->cmd_len);
req->timeout = timeout;
req->flags |= REQ_BLOCK_PC;
req->rq_disk = NULL;
blk_insert_request(sreq->sr_device->request_queue, req,
sreq->sr_data_direction == DMA_TO_DEVICE, NULL);
wait_for_completion(&wait);
sreq->sr_request->waiting = NULL;
if (sreq->sr_request->rq_status != RQ_SCSI_DONE)
sreq->sr_result = req->errors;
if (req->errors)
sreq->sr_result |= (DRIVER_ERROR << 24);

__scsi_release_request(sreq);
blk_put_request(req);
}

EXPORT_SYMBOL(scsi_wait_req);

/*
Expand Down Expand Up @@ -878,11 +878,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
return;
}
if (result) {
printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
"= 0x%x\n", cmd->device->host->host_no,
cmd->device->channel,
cmd->device->id,
cmd->device->lun, result);
if (!(req->flags & REQ_SPECIAL))
printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
"= 0x%x\n", cmd->device->host->host_no,
cmd->device->channel,
cmd->device->id,
cmd->device->lun, result);

if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
Expand Down Expand Up @@ -1020,6 +1021,12 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
return -EOPNOTSUPP;
}

static void scsi_generic_done(struct scsi_cmnd *cmd)
{
BUG_ON(!blk_pc_request(cmd->request));
scsi_io_completion(cmd, cmd->result == 0 ? cmd->bufflen : 0, 0);
}

static int scsi_prep_fn(struct request_queue *q, struct request *req)
{
struct scsi_device *sdev = q->queuedata;
Expand Down Expand Up @@ -1061,7 +1068,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
* these two cases differently. We differentiate by looking
* at request->cmd, as this tells us the real story.
*/
if (req->flags & REQ_SPECIAL) {
if (req->flags & REQ_SPECIAL && req->special) {
struct scsi_request *sreq = req->special;

if (sreq->sr_magic == SCSI_REQ_MAGIC) {
Expand All @@ -1073,7 +1080,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
cmd = req->special;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {

if(unlikely(specials_only)) {
if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
if(specials_only == SDEV_QUIESCE ||
specials_only == SDEV_BLOCK)
return BLKPREP_DEFER;
Expand Down Expand Up @@ -1142,11 +1149,26 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
/*
* Initialize the actual SCSI command for this request.
*/
drv = *(struct scsi_driver **)req->rq_disk->private_data;
if (unlikely(!drv->init_command(cmd))) {
scsi_release_buffers(cmd);
scsi_put_command(cmd);
return BLKPREP_KILL;
if (req->rq_disk) {
drv = *(struct scsi_driver **)req->rq_disk->private_data;
if (unlikely(!drv->init_command(cmd))) {
scsi_release_buffers(cmd);
scsi_put_command(cmd);
return BLKPREP_KILL;
}
} else {
memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
if (rq_data_dir(req) == WRITE)
cmd->sc_data_direction = DMA_TO_DEVICE;
else if (req->data_len)
cmd->sc_data_direction = DMA_FROM_DEVICE;
else
cmd->sc_data_direction = DMA_NONE;

cmd->transfersize = req->data_len;
cmd->allowed = 3;
cmd->timeout_per_command = req->timeout;
cmd->done = scsi_generic_done;
}
}

Expand Down

0 comments on commit e537a36

Please sign in to comment.