[ cc-ing Jens so he can intervene in case I got him wrong in the first
place. ]
Hi Doug,
Douglas Gilbert <[EMAIL PROTECTED]> wrote:
> Elias,
> If you want to define a SCSI operation code for
> internal use within the kernel, please make sure
> that the byte isn't in the range 0 to 255 (inclusive).
> Those ones are either t10 defined, reserved or vendor
> specific for logical_unit or target use.
Sorry, I originally intended to raise this particular point more
specifically as I had already suspected conflicts with reserved
spaces; just forgot to mention it.
>
> IOW don't do it!
>
> Better would be to flag the request for internal use.
Well, the request will be flagged REQ_TYPE_LINUX_BLOCK which, as I
understand, could be read as internal use in this sense. Originally, I
thought it would be easiest to generate some sort of an internal scsi
command in order to reuse the functions for dispatch of BLOCK-PC
requests to low level drivers. From your reaction I take it that this
might actually do more harm than good.
Are you suggesting to implement a seperate path for LINUX_BLOCK
requests to be dispatched to low level drivers then? This would
require these drivers to register yet another entry point with the
scsi midlayer, wouldn't it?
>
> If you really want to tweak SCSI cdb's, try the last
> byte (a.k.a. the control byte). Also consider that
> we a broadening the application of the pass-through
> code and other packet based protocols could be present.
Yeu lost me there, I'm afraid. I'm not really keen on tweaking cdbs if
there was a better solution. All I want is an implementation that
allows scsi midlayer as well as low level drivers to act upon
LINUX_BLOCK commands as appropriate. Jens had a set of generic
commands like eject and flush in mind when implementing this request
type. He also suggested to make disk parking a command of this type.
Perhaps, you can point me in the right direction make scsi midlayer
and the ata subsystem aware of REQ_TYPE_LINUX_BLOCK commands.
>
> Doug Gilbert
>
>
> Elias Oltmanns wrote:
>> Hi there,
>>
>> in 2.6.19 the request type REQ_TYPE_LINUX_BLOCK has been introduced.
>> This is meant for generic block layer commands to the lower level
>> drivers. I'd like to use this mechanism for a generic queue freezing
>> and disk parking facility. The idea is to issue a command like
>> REQ_LB_OP_PROTECT to the device driver associated to the queue so it
>> can do about it what ever it sees fit. On command completion, the
>> block layer then stops the queue until the unfreeze command is passed
>> in. The IDLE IMMEDIATE command in recent ATA specs provides an unload
>> disk heads feature which I'd like to use when the generic block layer
>> command is issued to an ATA device.
>>
>> Since ATA is implemented as a subsystem of the scsi subsystem, I
>> thought it would be best to add an scsi_cmnd opcode LINUX_BLOCK_CMD to
>> include/scsi/scsi.h and deal with commands of this type very much like
>> block_pc commands. The difference between these two types is that when
>> LINUX_BLOCK_CMD commands are taken off the queue, it is dealt with by
>> a special function of the midlayer to see if there is something to be
>> done about it regardless of the lld associated with the device in
>> question, and then the very same command is passed on to the low level
>> driver to give it a chance to do the more specific stuff.
>>
>> In my particular case of a generic disk protect command, the midlayer
>> would be responsible for setting sdev_state to SDEV_BLOCK and the ATA
>> subsystem would issue the actual park command.
>>
>> The patch attached is a first attempt of a generic implementation of
>> LINUX_BLOCK commands into the scsi midlayer. It probably doesn't apply
>> cleanly to 2.6.19 as I've just extracted it from my disk parking
>> branch, so it mainly serves as an example to comment on. Please let me
>> know what you think about this approach and whether I should post a
>> seperate patch for official integration into main line or whether it
>> would be sufficient to leave it a part of the disk parking patch to be
>> submitted later on.
>>
>> Regards,
>>
>> Elias
>> -----------------------
>> drivers/ata/libata-scsi.c | 39 ++++++++++++++++++++++++++++++++++-
>> drivers/scsi/scsi_lib.c | 50
>> +++++++++++++++++++++++++++++++++++++++++----
>> include/linux/blkdev.h | 1 +
>> include/scsi/scsi.h | 1 +
>> 4 files changed, 86 insertions(+), 5 deletions(-)
>> drivers/scsi/scsi.c | 3 ++-
>>
>> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
>> index a8acf71..6f1c351 100644
>> --- a/drivers/ata/libata-scsi.c
>> +++ b/drivers/ata/libata-scsi.c
>> @@ -2558,6 +2558,41 @@ static struct ata_device * ata_find_dev(
>> return NULL;
>> }
>>
>> +/**
>> + * ata_scsi_linux_block - handling of generic block layer commands
>> + * @dev: ATA device to which the command is addressed
>> + * @cmd: SCSI command to execute
>> + * @done: SCSI command completion function
>> + *
>> + * This function checks to see if we recognise the generic block layer
>> + * command and should do anything about it. If we don't know the command,
>> + * we indicate this in a sense response. However, we should fail
>> + * gracefully since the midlayer might handle this command appropriately
>> + * anyway, even without low level intervention.
>> + *
>> + * LOCKING:
>> + * spin_lock_irqsave(host lock)
>> + *
>> + * RETURNS:
>> + * Zero on success, non-zero on failure.
>> + */
>> +
>> +static int ata_scsi_linux_block(struct ata_device *dev, struct scsi_cmnd
>> *cmd,
>> + void (*done)(struct scsi_cmnd *))
>> +{
>> + struct request *req = cmd->request;
>> + int ret = 0;
>> +
>> + switch (req->cmd[0]) {
>> + default:
>> + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
>> + /* "Invalid command operation code" */
>> + done(cmd);
>> + break;
>> + }
>> + return ret;
>> +}
>> +
>> static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
>> const struct scsi_device *scsidev)
>> {
>> @@ -2856,7 +2891,9 @@ static inline int __ata_scsi_queuecmd(st
>> {
>> int rc = 0;
>>
>> - if (dev->class == ATA_DEV_ATA) {
>> + if (cmd->cmnd[0] == LINUX_BLOCK_CMD)
>> + rc = ata_scsi_linux_block(dev, cmd, done);
>> + else if (dev->class == ATA_DEV_ATA) {
>> ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
>> cmd->cmnd[0]);
>>
>> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
>> index cbb274d..d8e0be4 100644
>> --- a/drivers/scsi/scsi_lib.c
>> +++ b/drivers/scsi/scsi_lib.c
>> @@ -832,7 +832,8 @@ void scsi_io_completion(struct scsi_cmnd
>> sense_deferred = scsi_sense_is_deferred(&sshdr);
>> }
>>
>> - if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
>> + if (blk_pc_request(req) /* SG_IO ioctl from block level */
>> + || blk_lb_request(req)) {
>> req->errors = result;
>> if (result) {
>> clear_errors = 0;
>> @@ -998,7 +999,7 @@ static int scsi_init_io(struct scsi_cmnd
>> /*
>> * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
>> */
>> - if (blk_pc_request(req) && !req->bio) {
>> + if ((blk_pc_request(req) || blk_lb_request(req)) && !req->bio) {
>> cmd->request_bufflen = req->data_len;
>> cmd->request_buffer = req->data;
>> req->buffer = req->data;
>> @@ -1101,6 +1102,32 @@ static void scsi_setup_blk_pc_cmnd(struc
>> cmd->done = scsi_blk_pc_done;
>> }
>>
>> +static void scsi_blk_lb_done(struct scsi_cmnd *cmd)
>> +{
>> + BUG_ON(!blk_lb_request(cmd->request));
>> + scsi_io_completion(cmd, cmd->request_bufflen);
>> +}
>> +
>> +static void scsi_setup_blk_lb_cmnd(struct scsi_cmnd *cmd)
>> +{
>> + struct request *req = cmd->request;
>> +
>> + BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
>> + cmd->cmnd[0] = LINUX_BLOCK_CMD;
>> + cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
>> + if (!req->data_len)
>> + cmd->sc_data_direction = DMA_NONE;
>> + else if (rq_data_dir(req) == WRITE)
>> + cmd->sc_data_direction = DMA_TO_DEVICE;
>> + else
>> + cmd->sc_data_direction = DMA_FROM_DEVICE;
>> +
>> + cmd->transfersize = req->data_len;
>> + cmd->allowed = req->retries;
>> + cmd->timeout_per_command = req->timeout;
>> + cmd->done = scsi_blk_lb_done;
>> +}
>> +
>> static int scsi_prep_fn(struct request_queue *q, struct request *req)
>> {
>> struct scsi_device *sdev = q->queuedata;
>> @@ -1144,7 +1171,8 @@ static int scsi_prep_fn(struct request_q
>> */
>> if (blk_special_request(req) && req->special)
>> cmd = req->special;
>> - else if (blk_pc_request(req) || blk_fs_request(req)) {
>> + else if (blk_pc_request(req) || blk_fs_request(req)
>> + || blk_lb_request(req)) {
>> if (unlikely(specials_only) && !(req->cmd_flags & REQ_PREEMPT)){
>> if (specials_only == SDEV_QUIESCE ||
>> specials_only == SDEV_BLOCK)
>> @@ -1185,7 +1213,8 @@ static int scsi_prep_fn(struct request_q
>> * lock. We hope REQ_STARTED prevents anything untoward from
>> * happening now.
>> */
>> - if (blk_fs_request(req) || blk_pc_request(req)) {
>> + if (blk_fs_request(req) || blk_pc_request(req)
>> + || blk_lb_request(req)) {
>> int ret;
>>
>> /*
>> @@ -1219,6 +1248,8 @@ static int scsi_prep_fn(struct request_q
>> */
>> if (blk_pc_request(req)) {
>> scsi_setup_blk_pc_cmnd(cmd);
>> + } else if (blk_lb_request(req)) {
>> + scsi_setup_blk_lb_cmnd(cmd);
>> } else if (req->rq_disk) {
>> struct scsi_driver *drv;
>>
>> @@ -1355,6 +1386,12 @@ static void scsi_kill_request(struct req
>> __scsi_done(cmd);
>> }
>>
>> +static void scsi_lb_handler(struct request *req)
>> +{
>> + switch (req->cmd[0]) {
>> + }
>> +}
>> +
>> static void scsi_softirq_done(struct request *rq)
>> {
>> struct scsi_cmnd *cmd = rq->completion_data;
>> @@ -1483,6 +1520,11 @@ static void scsi_request_fn(struct reque
>> * the timers for timeouts.
>> */
>> scsi_init_cmd_errh(cmd);
>> + /* Have a look at LINUX_BLOCK requests and see what midlayer
>> + * can do before llds take action as implemented
>> + */
>> + if (blk_lb_request(req))
>> + scsi_lb_handler(req);
>>
>> /*
>> * Dispatch the command to the low-level driver.
>> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
>> index 838e7b0..ece9a89 100644
>> --- a/include/linux/blkdev.h
>> +++ b/include/linux/blkdev.h
>> @@ -552,6 +552,7 @@ #define blk_fs_request(rq) ((rq)->cmd_ty
>> #define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
>> #define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL)
>> #define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE)
>> +#define blk_lb_request(rq) ((rq)->cmd_type == REQ_TYPE_LINUX_BLOCK)
>>
>> #define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST)
>> #define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED)
>> diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
>> index 5c0e979..b36fa4e 100644
>> --- a/include/scsi/scsi.h
>> +++ b/include/scsi/scsi.h
>> @@ -112,6 +112,7 @@ #define WRITE_LONG_2 0xea
>> #define READ_16 0x88
>> #define WRITE_16 0x8a
>> #define VERIFY_16 0x8f
>> +#define LINUX_BLOCK_CMD 0xf0
>> #define SERVICE_ACTION_IN 0x9e
>> /* values for service action in */
>> #define SAI_READ_CAPACITY_16 0x10
>> -
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>> the body of a message to [EMAIL PROTECTED]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to [EMAIL PROTECTED]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html