From 3c1cf6c0333348b40fd321022793608551d57425 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 3 Apr 2007 14:47:47 +0000 Subject: [PATCH] Parse() functions made generic git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@105 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scsi_tgt.h | 56 ++++- scst/src/dev_handlers/scst_cdrom.c | 120 +++-------- scst/src/dev_handlers/scst_changer.c | 26 +-- scst/src/dev_handlers/scst_disk.c | 98 ++------- scst/src/dev_handlers/scst_modisk.c | 118 +++-------- scst/src/dev_handlers/scst_processor.c | 27 +-- scst/src/dev_handlers/scst_raid.c | 27 +-- scst/src/dev_handlers/scst_tape.c | 54 +---- scst/src/dev_handlers/scst_vdisk.c | 123 +---------- scst/src/scst.c | 8 + scst/src/scst_lib.c | 270 +++++++++++++++++++++++++ 11 files changed, 439 insertions(+), 488 deletions(-) diff --git a/scst/include/scsi_tgt.h b/scst/include/scsi_tgt.h index 89f5e0de6..ac24231c3 100644 --- a/scst/include/scsi_tgt.h +++ b/scst/include/scsi_tgt.h @@ -443,10 +443,22 @@ #define SCST_RES_3RDPTY 0x10 #define SCST_RES_LONGID 0x02 +/************************************************************* + ** Bits in the READ POSITION command + *************************************************************/ +#define TCLP_BIT 4 +#define LONG_BIT 2 +#define BT_BIT 1 + /************************************************************* ** Misc SCSI constants *************************************************************/ #define SCST_SENSE_ASC_UA_RESET 0x29 +#define READ_CAP_LEN 8 +#define READ_CAP16_LEN 12 +#define BYTCHK 0x02 +#define POSITION_LEN_SHORT 20 +#define POSITION_LEN_LONG 32 /************************************************************* ** Name of the entry in /proc @@ -754,8 +766,7 @@ struct scst_dev_type * * MUST HAVE */ - int (*parse) (struct scst_cmd *cmd, - const struct scst_info_cdb *cdb_info); + int (*parse) (struct scst_cmd *cmd, struct scst_info_cdb *cdb_info); /* * Called to execute CDB. Useful, for instance, to implement @@ -2299,4 +2310,45 @@ static inline void scst_thr_data_put(struct scst_thr_data_hdr *data) data->free_fn(data); } +/** + ** Generic parse() support routines + **/ + +/* Calculates and returns block shift for the given sector size */ +int scst_calc_block_shift(int sector_size); + +/* Generic parse() for SBC (disk) devices */ +int scst_sbc_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for MMC (cdrom) devices */ +int scst_cdrom_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for MO disk devices */ +int scst_modisk_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift); + +/* Generic parse() for tape devices */ +int scst_tape_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_size); + +/* Generic parse() functions for other devices */ +int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb); +static inline int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} +static inline int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} +static inline int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb) +{ + return scst_null_parse(cmd, info_cdb); +} + #endif /* __SCST_H */ diff --git a/scst/src/dev_handlers/scst_cdrom.c b/scst/src/dev_handlers/scst_cdrom.c index 531f9dbd4..ab4b3cff1 100644 --- a/scst/src/dev_handlers/scst_cdrom.c +++ b/scst/src/dev_handlers/scst_cdrom.c @@ -37,23 +37,18 @@ dev_done: cdrom_done, \ } -#define CDROM_RETRIES 2 #define CDROM_SMALL_TIMEOUT (3 * HZ) #define CDROM_REG_TIMEOUT (900 * HZ) #define CDROM_LONG_TIMEOUT (14000 * HZ) -#define READ_CAP_LEN 8 - -/* Flags */ -#define BYTCHK 0x02 struct cdrom_params { - int sector_size; + int block_shift; }; int cdrom_attach(struct scst_device *); void cdrom_detach(struct scst_device *); -int cdrom_parse(struct scst_cmd *, const struct scst_info_cdb *); +int cdrom_parse(struct scst_cmd *, struct scst_info_cdb *); int cdrom_done(struct scst_cmd *); static struct scst_dev_type cdrom_devtype = CDROM_TYPE; @@ -117,7 +112,7 @@ int cdrom_attach(struct scst_device *dev) TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - CDROM_REG_TIMEOUT, CDROM_RETRIES, 0); + CDROM_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -128,22 +123,22 @@ int cdrom_attach(struct scst_device *dev) if (!--retries) { PRINT_ERROR_PR("UA not clear after %d retries", SCST_DEV_UA_RETRIES); - cdrom->sector_size = 2048; + cdrom->block_shift = 11; /* 2048 bytes */ // res = -ENODEV; goto out_free_buf; } } if (res == 0) { - cdrom->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + if (sector_size == 0) + sector_size = 2048; + cdrom->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", - cdrom->sector_size, dev->scsi_dev->scsi_level, SCSI_2); - if (!cdrom->sector_size) { - cdrom->sector_size = 2048; - } + sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); - cdrom->sector_size = 2048; + cdrom->block_shift = 11; /* 2048 bytes */ // res = -ENODEV; goto out_free_buf; } @@ -195,19 +190,20 @@ void cdrom_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int cdrom_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct cdrom_params *cdrom; - int fixed; + struct cdrom_params *cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + scst_cdrom_generic_parse(cmd, info_cdb, cdrom->block_shift); + + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = CDROM_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -215,62 +211,6 @@ int cdrom_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) } else { cmd->timeout = CDROM_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", - info_cdb->op_name, - info_cdb->direction, - info_cdb->flags, - info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); - - cmd->cdb[1] &= 0x1f; - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case GPCMD_SET_STREAMING: - cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + - ((*(cmd->cdb + 10)) & 0xff); - cmd->bufflen &= 0xffff; - break; - case GPCMD_READ_CD: - cmd->bufflen = cmd->bufflen >> 8; - break; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * cdrom->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); return res; } @@ -308,13 +248,9 @@ int cdrom_done(struct scst_cmd *cmd) case READ_CAPACITY: { /* Always keep track of cdrom capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * cdrom->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -331,12 +267,16 @@ int cdrom_done(struct scst_cmd *cmd) sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - if (!sector_size) - sector_size = 2048; - cdrom->sector_size = sector_size; - TRACE_DBG("Sector size is %i", cdrom->sector_size); - scst_put_buf(cmd, buffer); + if (sector_size == 0) + sector_size = 2048; + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * cdrom->block_shift access atomic + */ + barrier(); + cdrom->block_shift = block_shift; break; } default: diff --git a/scst/src/dev_handlers/scst_changer.c b/scst/src/dev_handlers/scst_changer.c index c2fbb7428..34b50310f 100644 --- a/scst/src/dev_handlers/scst_changer.c +++ b/scst/src/dev_handlers/scst_changer.c @@ -42,7 +42,7 @@ int changer_attach(struct scst_device *); void changer_detach(struct scst_device *); -int changer_parse(struct scst_cmd *, const struct scst_info_cdb *); +int changer_parse(struct scst_cmd *, struct scst_info_cdb *); int changer_done(struct scst_cmd *); static struct scst_dev_type changer_devtype = CHANGER_TYPE; @@ -124,16 +124,11 @@ void changer_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int changer_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int changer_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ + scst_changer_generic_parse(cmd, info_cdb); cmd->retries = 1; @@ -143,21 +138,6 @@ int changer_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) cmd->timeout = CHANGER_TIMEOUT; } - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 0b5891af6..644589f91 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -56,23 +56,18 @@ exec: disk_exec, \ } -#define DISK_RETRIES 5 #define DISK_SMALL_TIMEOUT (3 * HZ) #define DISK_REG_TIMEOUT (60 * HZ) #define DISK_LONG_TIMEOUT (3600 * HZ) -#define READ_CAP_LEN 8 - -/* Flags */ -#define BYTCHK 0x02 struct disk_params { - int sector_size; + int block_shift; }; int disk_attach(struct scst_device *dev); void disk_detach(struct scst_device *dev); -int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cmd); +int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cmd); int disk_done(struct scst_cmd *cmd); int disk_exec(struct scst_cmd *cmd); @@ -193,7 +188,7 @@ int disk_attach(struct scst_device *dev) TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - DISK_REG_TIMEOUT, DISK_RETRIES, 0); + DISK_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -209,12 +204,9 @@ int disk_attach(struct scst_device *dev) } } if (res == 0) { - disk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - TRACE_DBG("Sector size is %i", disk->sector_size); - if (!disk->sector_size) { - disk->sector_size = 512; - } + disk->block_shift = scst_calc_block_shift(sector_size); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); res = -ENODEV; @@ -268,20 +260,19 @@ void disk_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { + struct disk_params *disk = (struct disk_params *)cmd->dev->dh_priv; int res = SCST_CMD_STATE_DEFAULT; - struct disk_params *disk; - int fixed; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ - cmd->retries = DISK_RETRIES; + scst_sbc_generic_parse(cmd, info_cdb, disk->block_shift); + + cmd->retries = 1; if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = DISK_SMALL_TIMEOUT; @@ -291,49 +282,6 @@ int disk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) cmd->timeout = DISK_REG_TIMEOUT; } - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - disk = (struct disk_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * disk->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT_RES(res); return res; } @@ -371,13 +319,9 @@ int disk_done(struct scst_cmd *cmd) case READ_CAPACITY: { /* Always keep track of disk capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * disk->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -394,12 +338,14 @@ int disk_done(struct scst_cmd *cmd) sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - if (!sector_size) - sector_size = 512; - disk->sector_size = sector_size; - TRACE_DBG("Sector size is %i", disk->sector_size); - scst_put_buf(cmd, buffer); + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * disk->block_shift access atomic + */ + barrier(); + disk->block_shift = block_shift; break; } default: diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index e1ec071c2..d63fb9093 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -56,23 +56,20 @@ exec: modisk_exec, \ } -#define MODISK_RETRIES 2 #define MODISK_SMALL_TIMEOUT (3 * HZ) #define MODISK_REG_TIMEOUT (900 * HZ) #define MODISK_LONG_TIMEOUT (14000 * HZ) -#define READ_CAP_LEN 8 -#define MODISK_SECTOR_SIZE 1024 -/* Flags */ -#define BYTCHK 0x02 +#define MODISK_BLOCK_SHIFT 10 +#define MODISK_SECTOR_SIZE (1 << MODISK_BLOCK_SHIFT) struct modisk_params { - int sector_size; + int block_shift; }; int modisk_attach(struct scst_device *); void modisk_detach(struct scst_device *); -int modisk_parse(struct scst_cmd *, const struct scst_info_cdb *); +int modisk_parse(struct scst_cmd *, struct scst_info_cdb *); int modisk_done(struct scst_cmd *); int modisk_exec(struct scst_cmd *); @@ -171,7 +168,7 @@ int modisk_attach(struct scst_device *dev) res = -ENOMEM; goto out; } - modisk->sector_size = MODISK_SECTOR_SIZE; + modisk->block_shift = MODISK_BLOCK_SHIFT; /* * If the device is offline, don't try to read capacity or any @@ -205,7 +202,7 @@ int modisk_attach(struct scst_device *dev) TRACE_DBG("%s", "Doing READ_CAPACITY"); res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer, buffer_size, sbuff, - MODISK_REG_TIMEOUT, MODISK_RETRIES, 0); + MODISK_REG_TIMEOUT, 3, 0); TRACE_DBG("READ_CAPACITY done: %x", res); @@ -220,13 +217,13 @@ int modisk_attach(struct scst_device *dev) } } if (res == 0) { - modisk->sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | + int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + if (sector_size == 0) + sector_size = MODISK_SECTOR_SIZE; + modisk->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", - modisk->sector_size, dev->scsi_dev->scsi_level, SCSI_2); - if (!modisk->sector_size) { - modisk->sector_size = MODISK_SECTOR_SIZE; - } + sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); @@ -282,19 +279,20 @@ void modisk_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int modisk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct modisk_params *modisk; - int fixed; + struct modisk_params *modisk = (struct modisk_params*)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + scst_modisk_generic_parse(cmd, info_cdb, modisk->block_shift); + + cmd->retries = 1; + if (info_cdb->flags & SCST_SMALL_TIMEOUT) { cmd->timeout = MODISK_SMALL_TIMEOUT; } else if (info_cdb->flags & SCST_LONG_TIMEOUT) { @@ -302,62 +300,6 @@ int modisk_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) } else { cmd->timeout = MODISK_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", - info_cdb->op_name, - info_cdb->direction, - info_cdb->flags, - info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); - - cmd->cdb[1] &= 0x1f; - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case 0xB6 /* SET_STREAMING */ : - cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + - ((*(cmd->cdb + 10)) & 0xff); - cmd->bufflen &= 0xffff; - break; - case 0xBE /* READ_CD */ : - cmd->bufflen = cmd->bufflen >> 8; - break; -#if 0 - case SYNCHRONIZE_CACHE: - cmd->underflow = 0; - break; -#endif - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - modisk = (struct modisk_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * modisk->sector_size; - } - - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT_RES(res); return res; } @@ -395,13 +337,9 @@ int modisk_done(struct scst_cmd *cmd) case READ_CAPACITY: { /* Always keep track of modisk capacity */ - int buffer_size; - /* - * To force the compiler not to optimize it out to keep - * modisk->sector_size access atomic - */ - volatile int sector_size; + int buffer_size, sector_size, block_shift; uint8_t *buffer; + buffer_size = scst_get_buf_first(cmd, &buffer); if (unlikely(buffer_size <= 0)) { PRINT_ERROR_PR("%s: Unable to get the buffer", @@ -418,12 +356,16 @@ int modisk_done(struct scst_cmd *cmd) sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); + scst_put_buf(cmd, buffer); if (!sector_size) sector_size = MODISK_SECTOR_SIZE; - modisk->sector_size = sector_size; - TRACE_DBG("Sector size is %i", modisk->sector_size); - - scst_put_buf(cmd, buffer); + block_shift = scst_calc_block_shift(sector_size); + /* + * To force the compiler not to optimize it out to keep + * cdrom->block_shift access atomic + */ + barrier(); + modisk->block_shift = block_shift; break; } default: diff --git a/scst/src/dev_handlers/scst_processor.c b/scst/src/dev_handlers/scst_processor.c index 70f342711..3b25645f9 100644 --- a/scst/src/dev_handlers/scst_processor.c +++ b/scst/src/dev_handlers/scst_processor.c @@ -42,7 +42,7 @@ int processor_attach(struct scst_device *); void processor_detach(struct scst_device *); -int processor_parse(struct scst_cmd *, const struct scst_info_cdb *); +int processor_parse(struct scst_cmd *, struct scst_info_cdb *); int processor_done(struct scst_cmd *); static struct scst_dev_type processor_devtype = PROCESSOR_TYPE; @@ -124,16 +124,11 @@ void processor_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int processor_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int processor_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ + scst_processor_generic_parse(cmd, info_cdb); cmd->retries = 1; @@ -142,22 +137,6 @@ int processor_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) } else { cmd->timeout = PROCESSOR_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } diff --git a/scst/src/dev_handlers/scst_raid.c b/scst/src/dev_handlers/scst_raid.c index ad155a761..73c60d226 100644 --- a/scst/src/dev_handlers/scst_raid.c +++ b/scst/src/dev_handlers/scst_raid.c @@ -42,7 +42,7 @@ int raid_attach(struct scst_device *); void raid_detach(struct scst_device *); -int raid_parse(struct scst_cmd *, const struct scst_info_cdb *); +int raid_parse(struct scst_cmd *, struct scst_info_cdb *); int raid_done(struct scst_cmd *); static struct scst_dev_type raid_devtype = RAID_TYPE; @@ -124,16 +124,11 @@ void raid_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int raid_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int raid_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ + scst_raid_generic_parse(cmd, info_cdb); cmd->retries = 1; @@ -142,22 +137,6 @@ int raid_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) } else { cmd->timeout = RAID_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); -#if 0 - switch (cmd->cdb[0]) { - default: - /* It's all good */ - break; - } -#endif - TRACE_DBG("res %d bufflen %zd direct %d", - res, cmd->bufflen, cmd->data_direction); - - TRACE_EXIT(); - return res; } diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 1c13caaf4..1f16036c9 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -65,14 +65,6 @@ /* The fixed bit in READ/WRITE/VERIFY */ #define SILI_BIT 2 -/* Bits in the READ POSITION command */ -#define TCLP_BIT 4 -#define LONG_BIT 2 -#define BT_BIT 1 - -#define POSITION_LEN_SHORT 20 -#define POSITION_LEN_LONG 32 - struct tape_params { spinlock_t tp_lock; @@ -85,7 +77,7 @@ struct tape_params int tape_attach(struct scst_device *); void tape_detach(struct scst_device *); -int tape_parse(struct scst_cmd *, const struct scst_info_cdb *); +int tape_parse(struct scst_cmd *, struct scst_info_cdb *); int tape_done(struct scst_cmd *); int tape_exec(struct scst_cmd *); @@ -280,18 +272,18 @@ void tape_detach(struct scst_device *dev) * * Note: Not all states are allowed on return ********************************************************************/ -int tape_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) +int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct tape_params *tape; + struct tape_params *tape = (struct tape_params*)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary + /* + * No need for locks here, since *_detach() can not be called, + * when there are existing commands. */ + scst_tape_generic_parse(cmd, info_cdb, tape->block_size); + cmd->retries = 1; if (info_cdb->flags & SCST_SMALL_TIMEOUT) { @@ -301,36 +293,6 @@ int tape_parse(struct scst_cmd *cmd, const struct scst_info_cdb *info_cdb) } else { cmd->timeout = TAPE_REG_TIMEOUT; } - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - if (cmd->cdb[0] == READ_POSITION) { - int tclp = cmd->cdb[1] & TCLP_BIT; - int long_bit = cmd->cdb[1] & LONG_BIT; - int bt = cmd->cdb[1] & BT_BIT; - - if ((tclp == long_bit) && (!bt || !long_bit)) { - cmd->bufflen = - tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT; - cmd->data_direction = SCST_DATA_READ; - } else { - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - } - } - - if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) { - /* - * No need for locks here, since *_detach() can not be called, - * when there are existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - cmd->bufflen = info_cdb->transfer_len * tape->block_size; - } - - TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index ca18e36ea..417ac1dee 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -65,13 +65,8 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] = /* 4 byte ASCII Product Revision Level - left aligned */ #define SCST_FIO_REV " 096" -#define READ_CAP_LEN 8 -#define READ_CAP16_LEN 12 - #define MAX_USN_LEN 20 -#define BYTCHK 0x02 - #define INQ_BUF_SZ 128 #define EVPD 0x01 #define CMDDT 0x02 @@ -145,9 +140,9 @@ static int vdisk_attach(struct scst_device *dev); static void vdisk_detach(struct scst_device *dev); static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev); static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev); -static int vdisk_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); +static int vdisk_parse(struct scst_cmd *, struct scst_info_cdb *info_cdb); static int vdisk_do_job(struct scst_cmd *cmd); -static int vcdrom_parse(struct scst_cmd *, const struct scst_info_cdb *info_cdb); +static int vcdrom_parse(struct scst_cmd *, struct scst_info_cdb *info_cdb); static int vcdrom_exec(struct scst_cmd *cmd); static void vdisk_exec_read(struct scst_cmd *cmd, struct scst_vdisk_thr *thr, loff_t loff); @@ -835,67 +830,13 @@ out: * Note: Not all states are allowed on return ********************************************************************/ static int vdisk_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) + struct scst_info_cdb *info_cdb) { - int res = SCST_CMD_STATE_DEFAULT; - int fixed; struct scst_vdisk_dev *virt_dev = (struct scst_vdisk_dev *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case SERVICE_ACTION_IN: - if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) { - cmd->bufflen = READ_CAP16_LEN; - cmd->data_direction = SCST_DATA_READ; - } - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT(); - return res; + scst_sbc_generic_parse(cmd, info_cdb, virt_dev->block_shift); + return SCST_CMD_STATE_DEFAULT; } /******************************************************************** @@ -910,61 +851,13 @@ static int vdisk_parse(struct scst_cmd *cmd, * Note: Not all states are allowed on return ********************************************************************/ static int vcdrom_parse(struct scst_cmd *cmd, - const struct scst_info_cdb *info_cdb) + struct scst_info_cdb *info_cdb) { - int res = SCST_CMD_STATE_DEFAULT; - int fixed; struct scst_vdisk_dev *virt_dev = (struct scst_vdisk_dev *)cmd->dev->dh_priv; - TRACE_ENTRY(); - - /* - * SCST sets good defaults for cmd->data_direction and cmd->bufflen - * based on info_cdb, therefore change them only if necessary - */ - - TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", - info_cdb->op_name, - info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); - - fixed = info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED; - switch (cmd->cdb[0]) { - case READ_CAPACITY: - cmd->bufflen = READ_CAP_LEN; - cmd->data_direction = SCST_DATA_READ; - break; - case VERIFY_6: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - if ((cmd->cdb[1] & BYTCHK) == 0) { - cmd->data_len = - info_cdb->transfer_len << virt_dev->block_shift; - cmd->bufflen = 0; - cmd->data_direction = SCST_DATA_NONE; - fixed = 0; - } else - cmd->data_len = 0; - break; - default: - /* It's all good */ - break; - } - - if (fixed) { - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cmd->bufflen = info_cdb->transfer_len << virt_dev->block_shift; - } - - TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", - res, cmd->bufflen, cmd->data_len, cmd->data_direction); - - TRACE_EXIT_HRES(res); - return res; + scst_cdrom_generic_parse(cmd, info_cdb, virt_dev->block_shift); + return SCST_CMD_STATE_DEFAULT; } /******************************************************************** diff --git a/scst/src/scst.c b/scst/src/scst.c index d7db289a1..b340d983f 100644 --- a/scst/src/scst.c +++ b/scst/src/scst.c @@ -1476,6 +1476,14 @@ EXPORT_SYMBOL(scst_del_all_thr_data); EXPORT_SYMBOL(scst_dev_del_all_thr_data); EXPORT_SYMBOL(scst_find_thr_data); +/* Generic parse() routines */ +EXPORT_SYMBOL(scst_calc_block_shift); +EXPORT_SYMBOL(scst_sbc_generic_parse); +EXPORT_SYMBOL(scst_cdrom_generic_parse); +EXPORT_SYMBOL(scst_modisk_generic_parse); +EXPORT_SYMBOL(scst_tape_generic_parse); +EXPORT_SYMBOL(scst_null_parse); + /* * Other Commands */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 9c10e0a88..ac9a4da17 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1829,6 +1830,275 @@ out_err: goto out; } +int scst_calc_block_shift(int sector_size) +{ + int block_shift = 0; + int t = sector_size; + + if (sector_size == 0) + sector_size = 512; + + while(1) { + if ((t & 1) != 0) + break; + t >>= 1; + block_shift++; + } + if (block_shift < 9) { + PRINT_ERROR_PR("Wrong sector size %d", sector_size); + block_shift = -1; + } + + TRACE_EXIT_RES(block_shift); + return block_shift; +} + +int scst_sbc_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); + + switch (cmd->cdb[0]) { + case READ_CAPACITY: + cmd->bufflen = READ_CAP_LEN; + cmd->data_direction = SCST_DATA_READ; + break; + case SERVICE_ACTION_IN: + if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) { + cmd->bufflen = READ_CAP16_LEN; + cmd->data_direction = SCST_DATA_READ; + } + break; + case VERIFY_6: + case VERIFY: + case VERIFY_12: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } else + cmd->data_len = 0; + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) { + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. + */ + cmd->bufflen = info_cdb->transfer_len << block_shift; + } + + TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", + res, cmd->bufflen, cmd->data_len, cmd->data_direction); + + TRACE_EXIT_RES(res); + return res; +} + +int scst_cdrom_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", + info_cdb->op_name, + info_cdb->direction, + info_cdb->flags, + info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); + + cmd->cdb[1] &= 0x1f; + + switch (cmd->cdb[0]) { + case READ_CAPACITY: + cmd->bufflen = READ_CAP_LEN; + cmd->data_direction = SCST_DATA_READ; + break; + case GPCMD_SET_STREAMING: + cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + + ((*(cmd->cdb + 10)) & 0xff); + cmd->bufflen &= 0xffff; + break; + case GPCMD_READ_CD: + cmd->bufflen = cmd->bufflen >> 8; + break; + case VERIFY_6: + case VERIFY: + case VERIFY_12: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) + cmd->bufflen = info_cdb->transfer_len << block_shift; + + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT(); + return res; +} + +int scst_modisk_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_shift) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d lun %d(%d)", + info_cdb->op_name, + info_cdb->direction, + info_cdb->flags, + info_cdb->transfer_len, cmd->lun, (cmd->cdb[1] >> 5) & 7); + + cmd->cdb[1] &= 0x1f; + + switch (cmd->cdb[0]) { + case READ_CAPACITY: + cmd->bufflen = READ_CAP_LEN; + cmd->data_direction = SCST_DATA_READ; + break; + case 0xB6 /* SET_STREAMING */ : + cmd->bufflen = (((*(cmd->cdb + 9)) & 0xff) << 8) + + ((*(cmd->cdb + 10)) & 0xff); + cmd->bufflen &= 0xffff; + break; + case 0xBE /* READ_CD */ : + cmd->bufflen = cmd->bufflen >> 8; + break; + case VERIFY_6: + case VERIFY: + case VERIFY_12: + case VERIFY_16: + if ((cmd->cdb[1] & BYTCHK) == 0) { + cmd->data_len = + info_cdb->transfer_len << block_shift; + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; + } + break; + default: + /* It's all good */ + break; + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) + cmd->bufflen = info_cdb->transfer_len << block_shift;; + + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT_RES(res); + return res; +} + +int scst_tape_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int block_size) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); + + if (cmd->cdb[0] == READ_POSITION) { + int tclp = cmd->cdb[1] & TCLP_BIT; + int long_bit = cmd->cdb[1] & LONG_BIT; + int bt = cmd->cdb[1] & BT_BIT; + + if ((tclp == long_bit) && (!bt || !long_bit)) { + cmd->bufflen = + tclp ? POSITION_LEN_LONG : POSITION_LEN_SHORT; + cmd->data_direction = SCST_DATA_READ; + } else { + cmd->bufflen = 0; + cmd->data_direction = SCST_DATA_NONE; + } + } + + if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) + cmd->bufflen = info_cdb->transfer_len * block_size; + + TRACE_EXIT_RES(res); + return res; +} + +int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) +{ + int res = 0; + + TRACE_ENTRY(); + + /* + * SCST sets good defaults for cmd->data_direction and cmd->bufflen + * based on info_cdb, therefore change them only if necessary + */ + + TRACE_DBG("op_name <%s> direct %d flags %d transfer_len %d", + info_cdb->op_name, + info_cdb->direction, info_cdb->flags, info_cdb->transfer_len); +#if 0 + switch (cmd->cdb[0]) { + default: + /* It's all good */ + break; + } +#endif + TRACE_DBG("res %d bufflen %zd direct %d", + res, cmd->bufflen, cmd->data_direction); + + TRACE_EXIT(); + return res; +} + /* Called under dev_lock and BH off */ void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd,