On Tue, Sep 25 2007 at 15:37 +0200, Matthew Wilcox <[EMAIL PROTECTED]> wrote:
> Christoph grabbed me on IRC and we debated some of my plans for scsi_cmnd;
> with his permission I'm summarising the result of that debate for posterity.
> There's four main things discussed:
>
> 1. I'm going to be writing and posting patches over the next week or so
> to kill all the (ab)uses of ->scsi_done in drivers. Once that is done,
> I'll post a patch that exports the midlayer's scsi_done and switch all
> the drivers to calling that. After that, I'll post another patch that
> changes the prototype *and the semantics* of queuecommand; the midlayer
> will no longer take the host_lock for the driver. I'll just push the
> acquisition down into queuecommand, and it'll be up to individual driver
> authors to do something sensible with it then.
>
> 2. Thanks to a thinko, we also discussed the upper-layer ->done. We think
> it should be feasible to move this from the scsi_cmnd to the scsi_device
> since sg doesn't use it.
>
> 3. We also discussed scsi_pointer. It's really quite crufty, and it
> gets recycled for storing all kinds of things. The ambitious plan here
> is to change the whole way scsi_cmnds are allocated. Code is clearer
> than my description ...
>
> sym2.c:
>
> struct sym2_cmnd {
> struct scsi_cmnd cmd;
> int Phase;
> char *data_in;
> }
>
> struct scsi_host_template sym2_template {
> .cmnd_size = sizeof(sym2_cmnd);
> }
>
> int sym2_queuecommand(struct scsi_cmnd *scp)
> {
> struct sym2_cmnd *cmnd = container_of(scp, sym2_cmnd, cmd);
> }
>
> The midlayer will create a slab pool per host template for allocating
> scsi_cmnd.
>
I have in my Q a small variation on this principle where I wanted
to allocate bigger commands for bidi-able hosts like iscsi_tcp. So
not to pay the extra allocation per command. Above will do just fine.
> As I said, it's ambitious. But it'll let us get rid of scsi_pointer
> and host_scribble entirely.
>
This all is an excellent idea and you will find that in the patchset to
gdth, I have made the work of one driver a bit easier for you.
I suggest gradual work, where both Scp and host_scribble are intact
but the .cmnd_size and mechanics are available with few major drivers
moved to that. Than one kernel after that deprecating both, while
converting lots of drivers, and 1-2 kernels after that remove them when
all drivers are converted. Don't sit on a large patchset with lots of
drivers and submit them all at once.
> 4. We don't understand why sense_buffer is 96 bytes long. mkp says that
> devices are coming which need more than 96 bytes (the standard allows up
> to 252). I propose splitting the 96-byte buffer like so:
>
> -#define SCSI_SENSE_BUFFERSIZE 96
> - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
> + unsigned char sense_buffer_head[8];
> + unsigned char *sense_buffer_desc;
>
> and then adding:
>
> +int scsi_set_sense_buffer(struct scsi_cmnd *cmd, unsigned char *sense,
> + int sense_len)
> +{
> + int len = min(sense[7], sense_len - 8);
> + memcpy(cmd->sense_buffer_head, sense, min(8, sense_len));
> + if (len <= 0)
> + return 0;
> + cmd->sense_buffer_desc = kmalloc(len, GFP_ATOMIC);
> + if (!cmd->sense_buffer_desc)
> + return 1;
> + memcpy(cmd->sense_buffer_desc, sense + 8, len);
> + return 0;
> +}
> +EXPORT_SYMBOL(scsi_set_sense_buffer);
>
> Drivers then do something like:
>
> - memset(&cmd->sense_buffer, 0,
> sizeof(cmd->sense_buffer))
> - memcpy(cmd->sense_buffer, cp->sns_bbuf,
> - min(sizeof(cmd->sense_buffer),
> - (size_t)SYM_SNS_BBUF_LEN));
> + scsi_set_sense_buffer(cmd, cp->sns_bbuf,
> + SYM_SNS_BBUF_LEN);
>
> or even ...
>
> - /* Copy Sense Data into sense buffer. */
> - memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
> -
> if (!(scsi_status & SS_SENSE_LEN_VALID))
> break;
>
> - if (sense_len >= sizeof(cp->sense_buffer))
> - sense_len = sizeof(cp->sense_buffer);
> -
> - CMD_ACTUAL_SNSLEN(cp) = sense_len;
> - sp->request_sense_length = sense_len;
> - sp->request_sense_ptr = cp->sense_buffer;
> -
> - if (sp->request_sense_length > 32)
> - sense_len = 32;
> -
> - memcpy(cp->sense_buffer, sense_data, sense_len);
> -
> - sp->request_sense_ptr += sense_len;
> - sp->request_sense_length -= sense_len;
> - if (sp->request_sense_length != 0)
> - ha->status_srb = sp;
> + scsi_set_sense_buffer(cp, sense_data, sense_len);
>
Please review my patches to scsi_error and the REQUEST_SENSE paths
(James are they not going to be accepted into 2.6.24-rcx?)
I have introduced an abstract way to convert a command to point to
it's sense buffer, So drivers can now transfer data to the sense buffer
the way they do to regular IO, throw an sg_list.
Also if you are converting to pointers than please do not do the above.
struct request already has a sense pointer and length. Directly use
these. The transient first 8 bytes are not necessary, and just complicate
the code. The all sense allocation can be settled with part 3 of your mail
above. we can widen it to be:
struct scsi_host_template sym2_template {
.cmnd_size = sizeof(sym2_cmnd);
.sense_size = SYM_SNS_BBUF_LEN;
.bidi_cmnd = 1;
}
By default .sense_size will be 96 allocated from cmnd-pool and pointed
to by the struct request pointers.
Drivers that want privately allocated space can put 0 in .sense_size
and use Christoph's alloc/destroy_cmnd to set up their own.
Drivers should access all these members throw accessors So to be abstracted
from all that.
> If any of this seems unwelcome, please say so. It's going to be a lot of
> churn (and part 4 may well take six months or more), so I'd like people
> to voice objections now rather than later.
>
RFC patches early and set up a git tree, if possible. I will help in any way
I can also with drivers.
Boaz
-
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