Skip to content

Commit

Permalink
[SCSI] move ULD attachment into the prep function
Browse files Browse the repository at this point in the history
One of the intents of the block prep function was to allow ULDs to use
it for preprocessing.  The original SCSI model was to have a single prep
function and add a pointer indirect filter to build the necessary
commands.  This patch reverses that, does away with the init_command
field of the scsi_driver structure and makes ULDs attach directly to the
prep function instead.  The value is really that it allows us to begin
to separate the ULDs from the SCSI mid layer (as long as they don't use
any core functions---which is hard at the moment---a ULD doesn't even
need SCSI to bind).

Acked-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
James Bottomley authored and James Bottomley committed Oct 12, 2007
1 parent d3849d5 commit 7f9a6bc
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 82 deletions.
84 changes: 37 additions & 47 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,9 +1039,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);

/* release the command and kill it */
scsi_release_buffers(cmd);
scsi_put_command(cmd);
return BLKPREP_KILL;
}

Expand Down Expand Up @@ -1078,9 +1075,13 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
scsi_io_completion(cmd, cmd->request_bufflen);
}

static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
int ret = scsi_prep_state_check(sdev, req);

if (ret != BLKPREP_OK)
return ret;

cmd = scsi_get_cmd_from_req(sdev, req);
if (unlikely(!cmd))
Expand Down Expand Up @@ -1126,18 +1127,20 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
cmd->done = scsi_blk_pc_done;
return BLKPREP_OK;
}
EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);

/*
* Setup a REQ_TYPE_FS command. These are simple read/write request
* from filesystems that still need to be translated to SCSI CDBs from
* the ULD.
*/
static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
struct scsi_driver *drv;
int ret;
int ret = scsi_prep_state_check(sdev, req);

if (ret != BLKPREP_OK)
return ret;
/*
* Filesystem requests must transfer data.
*/
Expand All @@ -1147,26 +1150,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;

ret = scsi_init_io(cmd);
if (unlikely(ret))
return ret;

/*
* 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;
}

return BLKPREP_OK;
return scsi_init_io(cmd);
}
EXPORT_SYMBOL(scsi_setup_fs_cmnd);

static int scsi_prep_fn(struct request_queue *q, struct request *req)
int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
{
struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_OK;

/*
Expand Down Expand Up @@ -1212,35 +1201,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
ret = BLKPREP_KILL;
break;
}

if (ret != BLKPREP_OK)
goto out;
}
return ret;
}
EXPORT_SYMBOL(scsi_prep_state_check);

switch (req->cmd_type) {
case REQ_TYPE_BLOCK_PC:
ret = scsi_setup_blk_pc_cmnd(sdev, req);
break;
case REQ_TYPE_FS:
ret = scsi_setup_fs_cmnd(sdev, req);
break;
default:
/*
* All other command types are not supported.
*
* Note that these days the SCSI subsystem does not use
* REQ_TYPE_SPECIAL requests anymore. These are only used
* (directly or via blk_insert_request) by non-SCSI drivers.
*/
blk_dump_rq_flags(req, "SCSI bad req");
ret = BLKPREP_KILL;
break;
}
int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
{
struct scsi_device *sdev = q->queuedata;

out:
switch (ret) {
case BLKPREP_KILL:
req->errors = DID_NO_CONNECT << 16;
/* release the command and kill it */
if (req->special) {
struct scsi_cmnd *cmd = req->special;
scsi_release_buffers(cmd);
scsi_put_command(cmd);
req->special = NULL;
}
break;
case BLKPREP_DEFER:
/*
Expand All @@ -1257,6 +1236,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)

return ret;
}
EXPORT_SYMBOL(scsi_prep_return);

static int scsi_prep_fn(struct request_queue *q, struct request *req)
{
struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_KILL;

if (req->cmd_type == REQ_TYPE_BLOCK_PC)
ret = scsi_setup_blk_pc_cmnd(sdev, req);
return scsi_prep_return(q, req, ret);
}

/*
* scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
Expand Down
48 changes: 34 additions & 14 deletions drivers/scsi/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ static struct scsi_driver sd_template = {
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
.init_command = sd_init_command,
};

/*
Expand Down Expand Up @@ -331,14 +330,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
static int sd_init_command(struct scsi_cmnd * SCpnt)
static int sd_prep_fn(struct request_queue *q, struct request *rq)
{
struct scsi_device *sdp = SCpnt->device;
struct request *rq = SCpnt->request;
struct scsi_cmnd *SCpnt;
struct scsi_device *sdp = q->queuedata;
struct gendisk *disk = rq->rq_disk;
sector_t block = rq->sector;
unsigned int this_count = SCpnt->request_bufflen >> 9;
unsigned int this_count = rq->nr_sectors;
unsigned int timeout = sdp->timeout;
int ret;

if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
goto out;
} else if (rq->cmd_type != REQ_TYPE_FS) {
ret = BLKPREP_KILL;
goto out;
}
ret = scsi_setup_fs_cmnd(sdp, rq);
if (ret != BLKPREP_OK)
goto out;
SCpnt = rq->special;

/* from here on until we're complete, any goto out
* is used for a killable error condition */
ret = BLKPREP_KILL;

SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
"sd_init_command: block=%llu, "
Expand All @@ -353,7 +369,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
"Retry with 0x%p\n", SCpnt));
return 0;
goto out;
}

if (sdp->changed) {
Expand All @@ -362,8 +378,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* the changed bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return 0;
goto out;
}

SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
(unsigned long long)block));

Expand All @@ -382,7 +399,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 1) || (rq->nr_sectors & 1)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
return 0;
goto out;
} else {
block = block >> 1;
this_count = this_count >> 1;
Expand All @@ -392,7 +409,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 3) || (rq->nr_sectors & 3)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
return 0;
goto out;
} else {
block = block >> 2;
this_count = this_count >> 2;
Expand All @@ -402,15 +419,15 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 7) || (rq->nr_sectors & 7)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
return 0;
goto out;
} else {
block = block >> 3;
this_count = this_count >> 3;
}
}
if (rq_data_dir(rq) == WRITE) {
if (!sdp->writeable) {
return 0;
goto out;
}
SCpnt->cmnd[0] = WRITE_6;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
Expand All @@ -419,7 +436,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
return 0;
goto out;
}

SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
Expand Down Expand Up @@ -470,7 +487,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
scmd_printk(KERN_ERR, SCpnt,
"FUA write on READ/WRITE(6) drive\n");
return 0;
goto out;
}

SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
Expand Down Expand Up @@ -501,7 +518,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* This indicates that the command is ready from our end to be
* queued.
*/
return 1;
ret = BLKPREP_OK;
out:
return scsi_prep_return(q, rq, ret);
}

/**
Expand Down Expand Up @@ -1669,6 +1688,7 @@ static int sd_probe(struct device *dev)

sd_revalidate_disk(gd);

blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);

gd->driverfs_dev = &sdp->sdev_gendev;
Expand Down
Loading

0 comments on commit 7f9a6bc

Please sign in to comment.