diff --git a/scst/include/scsi_tgt.h b/scst/include/scsi_tgt.h index ac24231c3..e99e38a57 100644 --- a/scst/include/scsi_tgt.h +++ b/scst/include/scsi_tgt.h @@ -2311,7 +2311,9 @@ static inline void scst_thr_data_put(struct scst_thr_data_hdr *data) } /** - ** Generic parse() support routines + ** Generic parse() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. **/ /* Calculates and returns block shift for the given sector size */ @@ -2319,36 +2321,48 @@ 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); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for MMC (cdrom) devices */ int scst_cdrom_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for MO disk devices */ int scst_modisk_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift); + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)); /* Generic parse() for tape devices */ int scst_tape_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_size); + struct scst_info_cdb *info_cdb, + int (*get_block_size)(struct scst_cmd *cmd)); -/* 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); -} +/* Generic parse() for changer devices */ +int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); + +/* Generic parse() for "processor" devices */ +int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); + +/* Generic parse() for RAID devices */ +int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing); + +/** + ** Generic dev_done() support routines. + ** Done via pointer on functions to avoid unneeded dereferences on + ** the fast path. + **/ + +/* Generic dev_done() for block devices */ +int scst_block_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)); + +/* Generic dev_done() for tape devices */ +int scst_tape_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_size)(struct scst_cmd *cmd, int block_size)); #endif /* __SCST_H */ diff --git a/scst/src/dev_handlers/scst_cdrom.c b/scst/src/dev_handlers/scst_cdrom.c index ab4b3cff1..c87826408 100644 --- a/scst/src/dev_handlers/scst_cdrom.c +++ b/scst/src/dev_handlers/scst_cdrom.c @@ -41,6 +41,8 @@ #define CDROM_REG_TIMEOUT (900 * HZ) #define CDROM_LONG_TIMEOUT (14000 * HZ) +#define CDROM_DEF_BLOCK_SHIFT 11 + struct cdrom_params { int block_shift; @@ -72,7 +74,7 @@ int cdrom_attach(struct scst_device *dev) unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct cdrom_params *cdrom; + struct cdrom_params *params; TRACE_ENTRY(); @@ -83,8 +85,8 @@ int cdrom_attach(struct scst_device *dev) goto out; } - cdrom = kzalloc(sizeof(*cdrom), GFP_KERNEL); - if (cdrom == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct cdrom_params"); res = -ENOMEM; @@ -95,7 +97,7 @@ int cdrom_attach(struct scst_device *dev) if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_cdrom; + goto out_free_params; } /* Clear any existing UA's and get cdrom capacity (cdrom block size) */ @@ -123,7 +125,7 @@ int cdrom_attach(struct scst_device *dev) if (!--retries) { PRINT_ERROR_PR("UA not clear after %d retries", SCST_DEV_UA_RETRIES); - cdrom->block_shift = 11; /* 2048 bytes */ + params->block_shift = CDROM_DEF_BLOCK_SHIFT; // res = -ENODEV; goto out_free_buf; } @@ -132,13 +134,14 @@ int cdrom_attach(struct scst_device *dev) 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); + params->block_shift = CDROM_DEF_BLOCK_SHIFT; + else + params->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); - cdrom->block_shift = 11; /* 2048 bytes */ + params->block_shift = CDROM_DEF_BLOCK_SHIFT; // res = -ENODEV; goto out_free_buf; } @@ -146,11 +149,11 @@ int cdrom_attach(struct scst_device *dev) out_free_buf: kfree(buffer); -out_free_cdrom: +out_free_params: if (res == 0) - dev->dh_priv = cdrom; + dev->dh_priv = params; else - kfree(cdrom); + kfree(params); out: TRACE_EXIT(); @@ -168,17 +171,24 @@ out: ************************************************************/ void cdrom_detach(struct scst_device *dev) { - struct cdrom_params *cdrom = (struct cdrom_params *)dev->dh_priv; + struct cdrom_params *params = + (struct cdrom_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(cdrom); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int cdrom_get_block_shift(struct scst_cmd *cmd) +{ + struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: cdrom_parse * @@ -193,14 +203,14 @@ void cdrom_detach(struct scst_device *dev) int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct cdrom_params *cdrom = (struct cdrom_params *)cmd->dev->dh_priv; + /* * 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); + scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift); cmd->retries = 1; @@ -214,6 +224,16 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) return res; } +static void cdrom_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = CDROM_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: cdrom_done * @@ -227,69 +247,17 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) ********************************************************************/ int cdrom_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct cdrom_params *cdrom; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, cdrom_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of cdrom capacity */ - 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", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - cdrom = (struct cdrom_params *)cmd->dev->dh_priv; - sector_size = - ((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - 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: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: - TRACE_EXIT(); + TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/dev_handlers/scst_changer.c b/scst/src/dev_handlers/scst_changer.c index 34b50310f..e11d3fcbb 100644 --- a/scst/src/dev_handlers/scst_changer.c +++ b/scst/src/dev_handlers/scst_changer.c @@ -128,7 +128,7 @@ int changer_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - scst_changer_generic_parse(cmd, info_cdb); + scst_changer_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 644589f91..671afbe5e 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -60,6 +60,8 @@ #define DISK_REG_TIMEOUT (60 * HZ) #define DISK_LONG_TIMEOUT (3600 * HZ) +#define DISK_DEF_BLOCK_SHIFT 9 + struct disk_params { int block_shift; @@ -148,7 +150,7 @@ int disk_attach(struct scst_device *dev) unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct disk_params *disk; + struct disk_params *params; TRACE_ENTRY(); @@ -159,8 +161,8 @@ int disk_attach(struct scst_device *dev) goto out; } - disk = kzalloc(sizeof(*disk), GFP_KERNEL); - if (disk == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct disk_params"); res = -ENOMEM; @@ -171,7 +173,7 @@ int disk_attach(struct scst_device *dev) if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_disk; + goto out_free_params; } /* Clear any existing UA's and get disk capacity (disk block size) */ @@ -206,7 +208,10 @@ int disk_attach(struct scst_device *dev) if (res == 0) { int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0)); - disk->block_shift = scst_calc_block_shift(sector_size); + if (sector_size == 0) + params->block_shift = DISK_DEF_BLOCK_SHIFT; + else + params->block_shift = scst_calc_block_shift(sector_size); } else { TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE); res = -ENODEV; @@ -216,11 +221,11 @@ int disk_attach(struct scst_device *dev) out_free_buf: kfree(buffer); -out_free_disk: +out_free_params: if (res == 0) - dev->dh_priv = disk; + dev->dh_priv = params; else - kfree(disk); + kfree(params); out: TRACE_EXIT_RES(res); @@ -238,17 +243,24 @@ out: ************************************************************/ void disk_detach(struct scst_device *dev) { - struct disk_params *disk = (struct disk_params *)dev->dh_priv; + struct disk_params *params = + (struct disk_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(disk); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int disk_get_block_shift(struct scst_cmd *cmd) +{ + struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: disk_parse * @@ -262,7 +274,6 @@ void disk_detach(struct scst_device *dev) ********************************************************************/ 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; /* @@ -270,7 +281,7 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) * called, when there are existing commands. */ - scst_sbc_generic_parse(cmd, info_cdb, disk->block_shift); + scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift); cmd->retries = 1; @@ -285,6 +296,16 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) return res; } +static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = DISK_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: disk_done * @@ -298,66 +319,16 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) ********************************************************************/ int disk_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct disk_params *disk; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, disk_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of disk capacity */ - 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", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - disk = (struct disk_params *)cmd->dev->dh_priv; - sector_size = - ((buffer[4] << 24) | (buffer[5] << 16) | - (buffer[6] << 8) | (buffer[7] << 0)); - 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: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index d63fb9093..b1c5d4fc1 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -59,8 +59,8 @@ #define MODISK_SMALL_TIMEOUT (3 * HZ) #define MODISK_REG_TIMEOUT (900 * HZ) #define MODISK_LONG_TIMEOUT (14000 * HZ) -#define MODISK_BLOCK_SHIFT 10 -#define MODISK_SECTOR_SIZE (1 << MODISK_BLOCK_SHIFT) + +#define MODISK_DEF_BLOCK_SHIFT 10 struct modisk_params { @@ -150,7 +150,7 @@ int modisk_attach(struct scst_device *dev) unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; enum dma_data_direction data_dir; unsigned char *sbuff; - struct modisk_params *modisk; + struct modisk_params *params; TRACE_ENTRY(); @@ -161,14 +161,14 @@ int modisk_attach(struct scst_device *dev) goto out; } - modisk = kzalloc(sizeof(*modisk), GFP_KERNEL); - if (modisk == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct modisk_params"); res = -ENOMEM; goto out; } - modisk->block_shift = MODISK_BLOCK_SHIFT; + params->block_shift = MODISK_DEF_BLOCK_SHIFT; /* * If the device is offline, don't try to read capacity or any @@ -178,14 +178,14 @@ int modisk_attach(struct scst_device *dev) { TRACE_DBG("%s", "Device is offline"); res = -ENODEV; - goto out_free_modisk; + goto out_free_params; } buffer = kzalloc(buffer_size, GFP_KERNEL); if (!buffer) { TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure"); res = -ENOMEM; - goto out_free_modisk; + goto out_free_params; } /* Clear any existing UA's and get modisk capacity (modisk block size) */ @@ -220,8 +220,9 @@ int modisk_attach(struct scst_device *dev) 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); + params->block_shift = MODISK_DEF_BLOCK_SHIFT; + else + params->block_shift = scst_calc_block_shift(sector_size); TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)", sector_size, dev->scsi_dev->scsi_level, SCSI_2); } else { @@ -235,11 +236,11 @@ int modisk_attach(struct scst_device *dev) out_free_buf: kfree(buffer); -out_free_modisk: +out_free_params: if (res == 0) - dev->dh_priv = modisk; + dev->dh_priv = params; else - kfree(modisk); + kfree(params); out: TRACE_EXIT_RES(res); @@ -257,17 +258,24 @@ out: ************************************************************/ void modisk_detach(struct scst_device *dev) { - struct modisk_params *modisk = (struct modisk_params *)dev->dh_priv; + struct modisk_params *params = + (struct modisk_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(modisk); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int modisk_get_block_shift(struct scst_cmd *cmd) +{ + struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + return params->block_shift; +} + /******************************************************************** * Function: modisk_parse * @@ -282,14 +290,13 @@ void modisk_detach(struct scst_device *dev) int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - struct modisk_params *modisk = (struct modisk_params*)cmd->dev->dh_priv; /* * 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); + scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift); cmd->retries = 1; @@ -303,6 +310,16 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) return res; } +static void modisk_set_block_shift(struct scst_cmd *cmd, int block_shift) +{ + struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv; + if (block_shift != 0) + params->block_shift = block_shift; + else + params->block_shift = MODISK_DEF_BLOCK_SHIFT; + return; +} + /******************************************************************** * Function: modisk_done * @@ -316,68 +333,16 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) ********************************************************************/ int modisk_done(struct scst_cmd *cmd) { - int opcode = cmd->cdb[0]; - int status = cmd->status; - struct modisk_params *modisk; - int res = SCST_CMD_STATE_DEFAULT; + int res; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be + * called, when there are existing commands. */ + res = scst_block_generic_dev_done(cmd, modisk_set_block_shift); - if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - switch (opcode) { - case READ_CAPACITY: - { - /* Always keep track of modisk capacity */ - 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", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - modisk = (struct modisk_params *)cmd->dev->dh_priv; - 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; - 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: - /* It's all good */ - break; - } - } - - TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " - "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); - -out: TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/dev_handlers/scst_processor.c b/scst/src/dev_handlers/scst_processor.c index 3b25645f9..2b097f5bd 100644 --- a/scst/src/dev_handlers/scst_processor.c +++ b/scst/src/dev_handlers/scst_processor.c @@ -128,7 +128,7 @@ int processor_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - scst_processor_generic_parse(cmd, info_cdb); + scst_processor_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; diff --git a/scst/src/dev_handlers/scst_raid.c b/scst/src/dev_handlers/scst_raid.c index 73c60d226..5afa803e7 100644 --- a/scst/src/dev_handlers/scst_raid.c +++ b/scst/src/dev_handlers/scst_raid.c @@ -128,7 +128,7 @@ int raid_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = SCST_CMD_STATE_DEFAULT; - scst_raid_generic_parse(cmd, info_cdb); + scst_raid_generic_parse(cmd, info_cdb, 0); cmd->retries = 1; diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 1f16036c9..dc260ac81 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -62,16 +62,13 @@ #define TAPE_REG_TIMEOUT (900 * HZ) #define TAPE_LONG_TIMEOUT (14000 * HZ) +#define TAPE_DEF_BLOCK_SIZE 512 + /* The fixed bit in READ/WRITE/VERIFY */ #define SILI_BIT 2 struct tape_params { - spinlock_t tp_lock; - uint8_t density; - uint8_t mode; - uint8_t speed; - uint8_t medium_type; int block_size; }; @@ -155,7 +152,7 @@ int tape_attach(struct scst_device *dev) struct scsi_mode_data data; const int buffer_size = 512; uint8_t *buffer = NULL; - struct tape_params *tape; + struct tape_params *params; TRACE_ENTRY(); @@ -166,14 +163,13 @@ int tape_attach(struct scst_device *dev) goto out; } - tape = kzalloc(sizeof(*tape), GFP_KERNEL); - if (tape == NULL) { + params = kzalloc(sizeof(*params), GFP_KERNEL); + if (params == NULL) { TRACE(TRACE_OUT_OF_MEM, "%s", "Unable to allocate struct tape_params"); res = -ENOMEM; goto out; } - spin_lock_init(&tape->tp_lock); buffer = kmalloc(buffer_size, GFP_KERNEL); if (!buffer) { @@ -205,21 +201,21 @@ int tape_attach(struct scst_device *dev) TRACE_DBG("MODE_SENSE done: %x", res); if (res == 0) { + int medium_type, mode, speed, density; if (buffer[3] == 8) { - tape->block_size = ((buffer[9] << 16) | + params->block_size = ((buffer[9] << 16) | (buffer[10] << 8) | (buffer[11] << 0)); } else { - tape->block_size = 512; + params->block_size = TAPE_DEF_BLOCK_SIZE; } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - tape->density = buffer[4]; + medium_type = buffer[1]; + mode = (buffer[2] & 0x70) >> 4; + speed = buffer[2] & 0x0f; + density = buffer[4]; TRACE_DBG("Tape: lun %d. bs %d. type 0x%02x mode 0x%02x " "speed 0x%02x dens 0x%02x", dev->scsi_dev->lun, - tape->block_size, tape->medium_type, - tape->mode, tape->speed, tape->density); + params->block_size, medium_type, mode, speed, density); } else { res = -ENODEV; goto out_free_buf; @@ -230,9 +226,9 @@ out_free_buf: out_free_req: if (res == 0) - dev->dh_priv = tape; + dev->dh_priv = params; else - kfree(tape); + kfree(params); out: TRACE_EXIT_RES(res); @@ -250,17 +246,24 @@ out: ************************************************************/ void tape_detach(struct scst_device *dev) { - struct tape_params *tape = (struct tape_params *)dev->dh_priv; + struct tape_params *params = + (struct tape_params *)dev->dh_priv; TRACE_ENTRY(); - kfree(tape); + kfree(params); dev->dh_priv = NULL; TRACE_EXIT(); return; } +static int tape_get_block_size(struct scst_cmd *cmd) +{ + struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + return params->block_size; +} + /******************************************************************** * Function: tape_parse * @@ -275,14 +278,13 @@ void tape_detach(struct scst_device *dev) 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*)cmd->dev->dh_priv; /* * 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); + scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size); cmd->retries = 1; @@ -296,6 +298,13 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) return res; } +static void tape_set_block_size(struct scst_cmd *cmd, int block_size) +{ + struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv; + params->block_size = block_size; + return; +} + /******************************************************************** * Function: tape_done * @@ -311,94 +320,21 @@ int tape_done(struct scst_cmd *cmd) { int opcode = cmd->cdb[0]; int status = cmd->status; - struct tape_params *tape; int res = SCST_CMD_STATE_DEFAULT; TRACE_ENTRY(); - if (unlikely(cmd->sg == NULL)) - goto out; - - /* - * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len - * based on cmd->status and cmd->data_direction, therefore change - * them only if necessary + /* + * No need for locks here, since *_detach() can not be called, when + * there are existing commands. */ if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { - int buffer_size; - uint8_t *buffer = NULL; - - switch (opcode) { - case MODE_SENSE: - case MODE_SELECT: - buffer_size = scst_get_buf_first(cmd, &buffer); - if (unlikely(buffer_size <= 0)) { - PRINT_ERROR_PR("%s: Unable to get the buffer", - __FUNCTION__); - scst_set_busy(cmd); - goto out; - } - break; - } - - switch (opcode) { - case MODE_SENSE: - TRACE_DBG("%s", "MODE_SENSE"); - if ((cmd->cdb[2] & 0xC0) == 0) { - /* - * No need for locks here, since *_detach() - * can not be called, when there are - * existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - spin_lock_bh(&tape->tp_lock); - if (buffer[3] == 8) { - tape->block_size = (buffer[9] << 16) | - (buffer[10] << 8) | buffer[11]; - } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - tape->density = buffer[4]; - spin_unlock_bh(&tape->tp_lock); - } - break; - case MODE_SELECT: - TRACE_DBG("%s", "MODE_SELECT"); - /* - * No need for locks here, since *_detach() can not be - * called, when there are existing commands. - */ - tape = (struct tape_params *)cmd->dev->dh_priv; - spin_lock_bh(&tape->tp_lock); - if (buffer[3] == 8) { - tape->block_size = - (buffer[9] << 16) | (buffer[10] << 8) | - (buffer[11]); - } - tape->medium_type = buffer[1]; - tape->mode = (buffer[2] & 0x70) >> 4; - tape->speed = buffer[2] & 0x0f; - if (buffer[4] != 0x7f) - tape->density = buffer[4]; - spin_unlock_bh(&tape->tp_lock); - break; - default: - /* It's all good */ - break; - } - - switch (opcode) { - case MODE_SENSE: - case MODE_SELECT: - scst_put_buf(cmd, buffer); - break; - } - } - else if ((status == SAM_STAT_CHECK_CONDITION) && + res = scst_tape_generic_dev_done(cmd, tape_set_block_size); + } else if ((status == SAM_STAT_CHECK_CONDITION) && SCST_SENSE_VALID(cmd->sense_buffer)) { + struct tape_params *params; TRACE_DBG("%s", "Extended sense"); if (opcode == READ_6 && !(cmd->cdb[1] & SILI_BIT) && (cmd->sense_buffer[2] & 0xe0)) { /* EOF, EOM, or ILI */ @@ -428,8 +364,8 @@ int tape_done(struct scst_cmd *cmd) * *_detach() can not be called, when * there are existing commands. */ - tape = (struct tape_params *)cmd->dev->dh_priv; - resp_data_len *= tape->block_size; + params = (struct tape_params *)cmd->dev->dh_priv; + resp_data_len *= params->block_size; } scst_set_resp_data_len(cmd, resp_data_len); } @@ -439,7 +375,6 @@ int tape_done(struct scst_cmd *cmd) TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); -out: 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 417ac1dee..b650a39e6 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -818,6 +818,13 @@ out: return SCST_EXEC_COMPLETED; } +static int vdisk_get_block_shift(struct scst_cmd *cmd) +{ + struct scst_vdisk_dev *virt_dev = + (struct scst_vdisk_dev *)cmd->dev->dh_priv; + return virt_dev->block_shift; +} + /******************************************************************** * Function: vdisk_parse * @@ -832,10 +839,7 @@ out: static int vdisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { - struct scst_vdisk_dev *virt_dev = - (struct scst_vdisk_dev *)cmd->dev->dh_priv; - - scst_sbc_generic_parse(cmd, info_cdb, virt_dev->block_shift); + scst_sbc_generic_parse(cmd, info_cdb, vdisk_get_block_shift); return SCST_CMD_STATE_DEFAULT; } @@ -853,10 +857,7 @@ static int vdisk_parse(struct scst_cmd *cmd, static int vcdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { - struct scst_vdisk_dev *virt_dev = - (struct scst_vdisk_dev *)cmd->dev->dh_priv; - - scst_cdrom_generic_parse(cmd, info_cdb, virt_dev->block_shift); + scst_cdrom_generic_parse(cmd, info_cdb, vdisk_get_block_shift); return SCST_CMD_STATE_DEFAULT; } diff --git a/scst/src/scst.c b/scst/src/scst.c index b340d983f..ae792a095 100644 --- a/scst/src/scst.c +++ b/scst/src/scst.c @@ -96,7 +96,7 @@ LIST_HEAD(scst_sess_mgmt_list); DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ); -DECLARE_MUTEX(scst_suspend_mutex);; +DECLARE_MUTEX(scst_suspend_mutex); LIST_HEAD(scst_cmd_lists_list); /* protected by scst_suspend_mutex */ static int scst_threads; @@ -1482,7 +1482,13 @@ 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); +EXPORT_SYMBOL(scst_changer_generic_parse); +EXPORT_SYMBOL(scst_processor_generic_parse); +EXPORT_SYMBOL(scst_raid_generic_parse); + +/* Generic dev_done() routines */ +EXPORT_SYMBOL(scst_block_generic_dev_done); +EXPORT_SYMBOL(scst_tape_generic_dev_done); /* * Other Commands diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index ac9a4da17..26b3855f9 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1854,7 +1854,8 @@ int scst_calc_block_shift(int sector_size) } int scst_sbc_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -1886,7 +1887,7 @@ int scst_sbc_generic_parse(struct scst_cmd *cmd, case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -1903,7 +1904,7 @@ int scst_sbc_generic_parse(struct scst_cmd *cmd, * No need for locks here, since *_detach() can not be * called, when there are existing commands. */ - cmd->bufflen = info_cdb->transfer_len << block_shift; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); } TRACE_DBG("res %d, bufflen %zd, data_len %zd, direct %d", @@ -1914,7 +1915,8 @@ int scst_sbc_generic_parse(struct scst_cmd *cmd, } int scst_cdrom_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -1952,7 +1954,7 @@ int scst_cdrom_generic_parse(struct scst_cmd *cmd, case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -1964,7 +1966,7 @@ int scst_cdrom_generic_parse(struct scst_cmd *cmd, } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) - cmd->bufflen = info_cdb->transfer_len << block_shift; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); TRACE_DBG("res %d bufflen %zd direct %d", res, cmd->bufflen, cmd->data_direction); @@ -1974,7 +1976,8 @@ int scst_cdrom_generic_parse(struct scst_cmd *cmd, } int scst_modisk_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_shift) + struct scst_info_cdb *info_cdb, + int (*get_block_shift)(struct scst_cmd *cmd)) { int res = 0; @@ -2012,7 +2015,7 @@ int scst_modisk_generic_parse(struct scst_cmd *cmd, case VERIFY_16: if ((cmd->cdb[1] & BYTCHK) == 0) { cmd->data_len = - info_cdb->transfer_len << block_shift; + info_cdb->transfer_len << get_block_shift(cmd); cmd->bufflen = 0; cmd->data_direction = SCST_DATA_NONE; info_cdb->flags &= ~SCST_TRANSFER_LEN_TYPE_FIXED; @@ -2024,7 +2027,7 @@ int scst_modisk_generic_parse(struct scst_cmd *cmd, } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED) - cmd->bufflen = info_cdb->transfer_len << block_shift;; + cmd->bufflen = info_cdb->transfer_len << get_block_shift(cmd); TRACE_DBG("res %d bufflen %zd direct %d", res, cmd->bufflen, cmd->data_direction); @@ -2034,7 +2037,8 @@ int scst_modisk_generic_parse(struct scst_cmd *cmd, } int scst_tape_generic_parse(struct scst_cmd *cmd, - struct scst_info_cdb *info_cdb, int block_size) + struct scst_info_cdb *info_cdb, + int (*get_block_size)(struct scst_cmd *cmd)) { int res = 0; @@ -2065,13 +2069,13 @@ int scst_tape_generic_parse(struct scst_cmd *cmd, } if (info_cdb->flags & SCST_TRANSFER_LEN_TYPE_FIXED & cmd->cdb[1]) - cmd->bufflen = info_cdb->transfer_len * block_size; + cmd->bufflen = info_cdb->transfer_len * get_block_size(cmd); TRACE_EXIT_RES(res); return res; } -int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) +static int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) { int res = 0; @@ -2099,6 +2103,152 @@ int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb) return res; } +int scst_changer_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_processor_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_raid_generic_parse(struct scst_cmd *cmd, + struct scst_info_cdb *info_cdb, int nothing) +{ + return scst_null_parse(cmd, info_cdb); +} + +int scst_block_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_shift)(struct scst_cmd *cmd, int block_shift)) +{ + int opcode = cmd->cdb[0]; + int status = cmd->status; + int res = SCST_CMD_STATE_DEFAULT; + + TRACE_ENTRY(); + + if (unlikely(cmd->sg == NULL)) + goto out; + + /* + * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len + * based on cmd->status and cmd->data_direction, therefore change + * them only if necessary + */ + + if ((status == SAM_STAT_GOOD) || (status == SAM_STAT_CONDITION_MET)) { + switch (opcode) { + case READ_CAPACITY: + { + /* Always keep track of disk capacity */ + int buffer_size, sector_size, sh; + 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", + __FUNCTION__); + scst_set_busy(cmd); + goto out; + } + + sector_size = + ((buffer[4] << 24) | (buffer[5] << 16) | + (buffer[6] << 8) | (buffer[7] << 0)); + scst_put_buf(cmd, buffer); + if (sector_size != 0) + sh = scst_calc_block_shift(sector_size); + else + sh = 0; + set_block_shift(cmd, sh); + TRACE(TRACE_SCSI, "block_shift %d", sh); + break; + } + default: + /* It's all good */ + break; + } + } + + TRACE_DBG("cmd->tgt_resp_flags=%x, cmd->resp_data_len=%d, " + "res=%d", cmd->tgt_resp_flags, cmd->resp_data_len, res); + +out: + TRACE_EXIT_RES(res); + return res; +} + +int scst_tape_generic_dev_done(struct scst_cmd *cmd, + void (*set_block_size)(struct scst_cmd *cmd, int block_shift)) +{ + int opcode = cmd->cdb[0]; + int res = SCST_CMD_STATE_DEFAULT; + int buffer_size, bs; + uint8_t *buffer = NULL; + + TRACE_ENTRY(); + + if (unlikely(cmd->sg == NULL)) + goto out; + + /* + * SCST sets good defaults for cmd->tgt_resp_flags and cmd->resp_data_len + * based on cmd->status and cmd->data_direction, therefore change + * them only if necessary + */ + + switch (opcode) { + case MODE_SENSE: + case MODE_SELECT: + buffer_size = scst_get_buf_first(cmd, &buffer); + if (unlikely(buffer_size <= 0)) { + PRINT_ERROR_PR("%s: Unable to get the buffer", + __FUNCTION__); + scst_set_busy(cmd); + goto out; + } + break; + } + + switch (opcode) { + case MODE_SENSE: + TRACE_DBG("%s", "MODE_SENSE"); + if ((cmd->cdb[2] & 0xC0) == 0) { + if (buffer[3] == 8) { + bs = (buffer[9] << 16) | + (buffer[10] << 8) | buffer[11]; + set_block_size(cmd, bs); + } + } + break; + case MODE_SELECT: + TRACE_DBG("%s", "MODE_SELECT"); + if (buffer[3] == 8) { + bs = (buffer[9] << 16) | (buffer[10] << 8) | + (buffer[11]); + set_block_size(cmd, bs); + } + break; + default: + /* It's all good */ + break; + } + + switch (opcode) { + case MODE_SENSE: + case MODE_SELECT: + scst_put_buf(cmd, buffer); + break; + } + +out: + TRACE_EXIT_RES(res); + 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,