Various fixes, cleanups updates and preparations

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@108 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-04-03 15:44:44 +00:00
parent 8f692614cf
commit 62b075c66d
25 changed files with 1124 additions and 766 deletions

View File

@@ -416,6 +416,10 @@ Also it has an advantage over FILEIO that it doesn't copy data between
the system cache and the commands data buffers, so it saves a
considerable amount of CPU power and memory bandwidth.
IMPORTANT: Since data in BLOCKIO and FILEIO modes are not consistent between
========= them, if you try to use a device in both those modes simultaneously,
you will almost instantly corrupt your data on that device.
Performance
-----------

View File

@@ -1,7 +1,7 @@
/*
* include/scsi_tgt.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Main SCSI target mid-level include file.
@@ -34,6 +34,8 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi.h>
#include <scst_const.h>
/* Version numbers, the same as for the kernel */
#define SCST_VERSION_CODE 0x000906
#define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
@@ -96,6 +98,13 @@
*************************************************************/
#define SCST_CMD_STATE_NEED_THREAD_CTX 100
/*************************************************************
** Can be retuned instead of cmd's state by dev handlers'
** parse function, if the cmd processing should be stopped
** for now. The cmd will be restarted by dev handlers itself.
*************************************************************/
#define SCST_CMD_STATE_STOP 101
/*************************************************************
** States of mgmt command processing state machine
*************************************************************/
@@ -240,14 +249,6 @@
*************************************************************/
#define SCST_DEFAULT_TIMEOUT (30*HZ)
/*************************************************************
** Data direction aliases
*************************************************************/
#define SCST_DATA_UNKNOWN DMA_BIDIRECTIONAL
#define SCST_DATA_WRITE DMA_TO_DEVICE
#define SCST_DATA_READ DMA_FROM_DEVICE
#define SCST_DATA_NONE DMA_NONE
/*************************************************************
** Flags of cmd->tgt_resp_flags
*************************************************************/
@@ -261,48 +262,6 @@
*/
#define SCST_TSC_FLAG_STATUS 0x2
/*************************************************************
** Values for management functions
*************************************************************/
#define SCST_ABORT_TASK 0
#define SCST_ABORT_TASK_SET 1
#define SCST_CLEAR_ACA 2
#define SCST_CLEAR_TASK_SET 3
#define SCST_LUN_RESET 4
#define SCST_TARGET_RESET 5
/** SCST extensions **/
/*
* Notifies about I_T nexus loss event in the corresponding session.
* Aborts all tasks there, resets the reservation, if any, and sets
* up the I_T Nexus loss UA.
*/
#define SCST_NEXUS_LOSS_SESS 6
/* Aborts all tasks in the corresponding session with TASK_ABORTED status */
#define SCST_ABORT_ALL_TASKS_SESS 7
/*
* Notifies about I_T nexus loss event. Aborts all tasks in all sessions
* of the tgt, resets the reservations, if any, and sets up the I_T Nexus
* loss UA.
*/
#define SCST_NEXUS_LOSS 8
/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */
#define SCST_ABORT_ALL_TASKS 9
/*************************************************************
** Values for mgmt cmd's status field. Codes taken from iSCSI
*************************************************************/
#define SCST_MGMT_STATUS_SUCCESS 0
#define SCST_MGMT_STATUS_TASK_NOT_EXIST -1
#define SCST_MGMT_STATUS_LUN_NOT_EXIST -2
#define SCST_MGMT_STATUS_FN_NOT_SUPPORTED -5
#define SCST_MGMT_STATUS_REJECTED -255
#define SCST_MGMT_STATUS_FAILED -129
/*************************************************************
** Additional return code for dev handler's task_mgmt_fn()
*************************************************************/
@@ -366,6 +325,9 @@
/* Set if tgt_dev is RESERVED by another session */
#define SCST_TGT_DEV_RESERVED 1
/* Set HEAD OF QUEUE cmd is being executed */
#define SCST_TGT_DEV_HQ_ACTIVE 2
/* Set if the corresponding context is atomic */
#define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC 5
#define SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC 6
@@ -374,106 +336,15 @@
#define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9
#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10
/* Set HEAD OF QUEUE cmd is being executed */
#define SCST_TGT_DEV_HQ_ACTIVE 12
#ifdef DEBUG_TM
#define SCST_TGT_DEV_UNDER_TM_DBG 20
#endif
/*************************************************************
** Commands that are not listed anywhere else
*************************************************************/
#ifndef REPORT_DEVICE_IDENTIFIER
#define REPORT_DEVICE_IDENTIFIER 0xA3
#endif
#ifndef INIT_ELEMENT_STATUS
#define INIT_ELEMENT_STATUS 0x07
#endif
#ifndef INIT_ELEMENT_STATUS_RANGE
#define INIT_ELEMENT_STATUS_RANGE 0x37
#endif
#ifndef PREVENT_ALLOW_MEDIUM
#define PREVENT_ALLOW_MEDIUM 0x1E
#endif
#ifndef READ_ATTRIBUTE
#define READ_ATTRIBUTE 0x8C
#endif
#ifndef REQUEST_VOLUME_ADDRESS
#define REQUEST_VOLUME_ADDRESS 0xB5
#endif
#ifndef WRITE_ATTRIBUTE
#define WRITE_ATTRIBUTE 0x8D
#endif
#ifndef WRITE_VERIFY_16
#define WRITE_VERIFY_16 0x8E
#endif
#ifndef VERIFY_6
#define VERIFY_6 0x13
#endif
#ifndef VERIFY_12
#define VERIFY_12 0xAF
#endif
/*************************************************************
** Control byte field in CDB
*************************************************************/
#ifndef CONTROL_BYTE_LINK_BIT
#define CONTROL_BYTE_LINK_BIT 0x01
#endif
#ifndef CONTROL_BYTE_NACA_BIT
#define CONTROL_BYTE_NACA_BIT 0x04
#endif
/*************************************************************
** Byte 1 in INQUIRY CDB
*************************************************************/
#define SCST_INQ_EVPD 0x01
/*************************************************************
** Byte 3 in Standard INQUIRY data
*************************************************************/
#define SCST_INQ_BYTE3 3
#define SCST_INQ_NORMACA_BIT 0x20
/*************************************************************
** Byte 2 in RESERVE_10 CDB
*************************************************************/
#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
*************************************************************/
#define SCST_PROC_ENTRY_NAME "scsi_tgt"
/*************************************************************
** Used with scst_set_cmd_error()
*************************************************************/
#define SCST_LOAD_SENSE(key_asc_ascq) key_asc_ascq
#define SCST_SENSE_VALID(sense) ((((uint8_t *)(sense))[0] & 0x70) == 0x70)
#define SCST_NO_SENSE(sense) (((uint8_t *)(sense))[2] == 0)
/*************************************************************
* TYPES
*************************************************************/
@@ -751,13 +622,21 @@ struct scst_dev_type
unsigned dev_done_atomic:1;
unsigned dedicated_thread:1;
/* Set, if no /proc files should be automatically created by SCST */
unsigned no_proc:1;
/* Set if expected_sn in cmd->scst_cmd_done() */
unsigned inc_expected_sn_on_done:1;
/*
* Called to parse CDB from the cmd and initialize
* cmd->bufflen and cmd->data_direction (both - REQUIRED).
* Returns the command's next state or SCST_CMD_STATE_DEFAULT,
* if the next default state should be used, or
* SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
* context, but requires sleeping. In the last case, the function
* context, but requires sleeping, or SCST_CMD_STATE_STOP if the
* command should not be further processed for now. In the
* SCST_CMD_STATE_NEED_THREAD_CTX case the function
* will be recalled in the thread context, where sleeping is allowed.
*
* Pay attention to "atomic" attribute of the cmd, which can be get
@@ -899,7 +778,10 @@ struct scst_tgt
struct timer_list retry_timer;
int retry_timer_active;
/* Maximum SG table size */
/*
* Maximum SG table size. Needed here, since different cards on the
* same target template can have different SG table limitations.
*/
int sg_tablesize;
/* Used for storage of target driver private stuff */
@@ -979,15 +861,6 @@ struct scst_session
void (*unreg_done_fn) (struct scst_session *sess);
};
enum scst_cmd_queue_type
{
SCST_CMD_QUEUE_UNTAGGED = 0,
SCST_CMD_QUEUE_SIMPLE,
SCST_CMD_QUEUE_ORDERED,
SCST_CMD_QUEUE_HEAD_OF_QUEUE,
SCST_CMD_QUEUE_ACA
};
struct scst_cmd_lists
{
spinlock_t cmd_list_lock;
@@ -1100,13 +973,19 @@ struct scst_cmd
unsigned int may_need_dma_sync:1;
/* Set if the cmd was done or aborted out of its SN */
unsigned long out_of_sn:1;
/* Set if the cmd is HEAD OF QUEUE */
unsigned long head_of_queue:1;
unsigned int out_of_sn:1;
/* Set if the cmd is deferred HEAD OF QUEUE */
unsigned long hq_deferred:1;
unsigned int hq_deferred:1;
/* Set if the internal parse should be skipped */
unsigned int skip_parse:1;
/*
* Set if inc expected_sn in cmd->scst_cmd_done() (to
* save extra dereferences)
*/
unsigned inc_expected_sn_on_done:1;
/**************************************************************/
@@ -1128,7 +1007,7 @@ struct scst_cmd
struct list_head sn_cmd_list_entry;
/* Cmd's serial number, used to execute cmd's in order of arrival */
unsigned int sn;
unsigned long sn;
/* The corresponding sn_slot in tgt_dev->sn_slots */
atomic_t *sn_slot;
@@ -1143,7 +1022,7 @@ struct scst_cmd
uint32_t tag;
/* CDB and its len */
uint8_t cdb[MAX_COMMAND_SIZE];
uint8_t cdb[SCST_MAX_CDB_SIZE];
int cdb_len;
enum scst_cmd_queue_type queue_type;
@@ -1156,17 +1035,21 @@ struct scst_cmd
/* Remote initiator supplied values, if any */
scst_data_direction expected_data_direction;
unsigned int expected_transfer_len;
int expected_transfer_len;
/* cmd data length */
size_t data_len;
/*
* Cmd data length. Could be different from bufflen for commands like
* VERIFY, which transfer different amount of data (if any), than
* processed.
*/
int data_len;
/* Completition routine */
void (*scst_cmd_done) (struct scst_cmd *cmd, int next_state);
struct sgv_pool_obj *sgv; /* sgv object */
size_t bufflen; /* cmd buffer length */
int bufflen; /* cmd buffer length */
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -1199,7 +1082,7 @@ struct scst_cmd
*/
int orig_sg_cnt, orig_sg_entry, orig_entry_len;
uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* sense buffer */
uint8_t sense_buffer[SCST_SENSE_BUFFERSIZE]; /* sense buffer */
/* The corresponding mgmt cmd, if any, protected by sess_list_lock */
struct scst_mgmt_cmd *mgmt_cmnd;
@@ -1359,6 +1242,10 @@ struct scst_tgt_dev
/* How many cmds alive on this dev in this session */
atomic_t cmd_count;
int gfp_mask;
struct sgv_pool *pool;
int max_sg_cnt;
unsigned long tgt_dev_flags; /* tgt_dev's async flags */
/*
@@ -1371,13 +1258,18 @@ struct scst_tgt_dev
*/
int def_cmd_count;
spinlock_t sn_lock;
int expected_sn;
int curr_sn;
unsigned long expected_sn, curr_sn;
struct list_head deferred_cmd_list;
struct list_head skipped_sn_list;
struct list_head hq_cmd_list;
unsigned short prev_cmd_ordered; /* Set if the prev cmd was ORDERED */
short num_free_sn_slots;
/*
* Set if the prev cmd was ORDERED. Size must allow unprotected
* modifications
*/
unsigned long prev_cmd_ordered;
int num_free_sn_slots;
atomic_t *cur_sn_slot;
atomic_t sn_slots[10];
@@ -1471,7 +1363,7 @@ struct scst_tgt_dev_UA
/* List entry in tgt_dev->UA_list */
struct list_head UA_list_entry;
/* Unit Attention sense */
uint8_t UA_sense_buffer[SCSI_SENSE_BUFFERSIZE];
uint8_t UA_sense_buffer[SCST_SENSE_BUFFERSIZE];
};
enum scst_cdb_flags
@@ -1480,6 +1372,7 @@ enum scst_cdb_flags
SCST_SMALL_TIMEOUT = 0x02,
SCST_LONG_TIMEOUT = 0x04,
SCST_UNKNOWN_LENGTH = 0x08,
SCST_INFO_INVALID = 0x10,
};
struct scst_info_cdb
@@ -1491,28 +1384,6 @@ struct scst_info_cdb
const char *op_name;
};
/*
* Sense data for the appropriate errors. Can be used with
* scst_set_cmd_error()
*/
#define scst_sense_no_sense NO_SENSE, 0x00, 0
#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0
#define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0
#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0
#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0
#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0
#define scst_sense_reset_UA UNIT_ATTENTION, 0x29, 0
#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7
#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0
#define scst_sense_lun_not_supported ILLEGAL_REQUEST, 0x25, 0
#define scst_sense_data_protect DATA_PROTECT, 0x00, 0
#define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0
#define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0
#define scst_sense_medium_changed_UA UNIT_ATTENTION, 0x28, 0
#define scst_sense_read_error MEDIUM_ERROR, 0x11, 0
#define scst_sense_write_error MEDIUM_ERROR, 0x03, 0
#define scst_sense_not_ready NOT_READY, 0x04, 0x10
#ifndef smp_mb__after_set_bit
/* There is no smp_mb__after_set_bit() in the kernel */
#define smp_mb__after_set_bit() smp_mb();
@@ -1787,6 +1658,20 @@ static inline int scst_to_tgt_dma_dir(int scst_dir)
return scst_dir;
}
/*
* Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise.
* Dev handlers parse() and dev_done() not called for such commands.
*/
static inline int scst_is_cmd_local(struct scst_cmd *cmd)
{
int res = 0;
switch (cmd->cdb[0]) {
case REPORT_LUNS:
res = 1;
}
return res;
}
/*
* Registers a virtual device.
* Parameters:
@@ -2047,7 +1932,7 @@ static inline scst_data_direction scst_cmd_get_expected_data_direction(
return cmd->expected_data_direction;
}
static inline unsigned int scst_cmd_get_expected_transfer_len(
static inline int scst_cmd_get_expected_transfer_len(
struct scst_cmd *cmd)
{
return cmd->expected_transfer_len;
@@ -2055,7 +1940,7 @@ static inline unsigned int scst_cmd_get_expected_transfer_len(
static inline void scst_cmd_set_expected(struct scst_cmd *cmd,
scst_data_direction expected_data_direction,
unsigned int expected_transfer_len)
int expected_transfer_len)
{
cmd->expected_data_direction = expected_data_direction;
cmd->expected_transfer_len = expected_transfer_len;
@@ -2162,6 +2047,13 @@ static inline int scst_get_buf_count(struct scst_cmd *cmd)
void scst_suspend_activity(void);
void scst_resume_activity(void);
/*
* Main SCST commands processing routing. Must be used only by dev handlers.
* Argument context sets the execution context, only SCST_CONTEXT_DIRECT and
* SCST_CONTEXT_DIRECT_ATOMIC are allowed.
*/
void scst_process_active_cmd(struct scst_cmd *cmd, int context);
/*
* Returns target driver's root entry in SCST's /proc hierarchy.
* The driver can create own files/directoryes here, which should
@@ -2310,6 +2202,34 @@ static inline void scst_thr_data_put(struct scst_thr_data_hdr *data)
data->free_fn(data);
}
/* SGV pool routines and flag bits */
/* Set if the allocated object must be not from the cache */
#define SCST_POOL_ALLOC_NO_CACHED 1
/* Set if there should not be any memory allocations on a cache miss */
#define SCST_POOL_NO_ALLOC_ON_CACHE_MISS 2
/* Set an object should be returned even if it doesn't have SG vector built */
#define SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL 4
struct sgv_pool_obj;
struct sgv_pool;
struct sgv_pool *sgv_pool_create(const char *name, int clustered);
void sgv_pool_destroy(struct sgv_pool *pool);
void sgv_pool_set_allocator(struct sgv_pool *pool,
struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *),
void (*free_pages_fn)(struct scatterlist *, int, void *));
struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size,
unsigned long gfp_mask, int atomic, int *count,
struct sgv_pool_obj **sgv, void *priv);
void sgv_pool_free(struct sgv_pool_obj *sgv);
void *sgv_get_priv(struct sgv_pool_obj *sgv);
/**
** Generic parse() support routines.
** Done via pointer on functions to avoid unneeded dereferences on
@@ -2341,15 +2261,18 @@ int scst_tape_generic_parse(struct scst_cmd *cmd,
/* Generic parse() for changer devices */
int scst_changer_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing);
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd));
/* Generic parse() for "processor" devices */
int scst_processor_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing);
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd));
/* Generic parse() for RAID devices */
int scst_raid_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing);
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd));
/**
** Generic dev_done() support routines.

243
scst/include/scst_const.h Normal file
View File

@@ -0,0 +1,243 @@
/*
* include/scst_const.h
*
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* Contains macroses for execution tracing and error reporting
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __SCST_CONST_H
#define __SCST_CONST_H
#include <scsi/scsi.h>
/*** Shared constants between user and kernel spaces ***/
/* Max size of CDB */
#define SCST_MAX_CDB_SIZE 16
/* Max size of sense */
#define SCST_SENSE_BUFFERSIZE 96
/*************************************************************
** Values for task management functions
*************************************************************/
#define SCST_ABORT_TASK 0
#define SCST_ABORT_TASK_SET 1
#define SCST_CLEAR_ACA 2
#define SCST_CLEAR_TASK_SET 3
#define SCST_LUN_RESET 4
#define SCST_TARGET_RESET 5
/** SCST extensions **/
/*
* Notifies about I_T nexus loss event in the corresponding session.
* Aborts all tasks there, resets the reservation, if any, and sets
* up the I_T Nexus loss UA.
*/
#define SCST_NEXUS_LOSS_SESS 6
/* Aborts all tasks in the corresponding session with TASK_ABORTED status */
#define SCST_ABORT_ALL_TASKS_SESS 7
/*
* Notifies about I_T nexus loss event. Aborts all tasks in all sessions
* of the tgt, resets the reservations, if any, and sets up the I_T Nexus
* loss UA.
*/
#define SCST_NEXUS_LOSS 8
/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */
#define SCST_ABORT_ALL_TASKS 9
/*************************************************************
** Values for mgmt cmd's status field. Codes taken from iSCSI
*************************************************************/
#define SCST_MGMT_STATUS_SUCCESS 0
#define SCST_MGMT_STATUS_TASK_NOT_EXIST -1
#define SCST_MGMT_STATUS_LUN_NOT_EXIST -2
#define SCST_MGMT_STATUS_FN_NOT_SUPPORTED -5
#define SCST_MGMT_STATUS_REJECTED -255
#define SCST_MGMT_STATUS_FAILED -129
/*************************************************************
** SCSI task attribute queue types
*************************************************************/
enum scst_cmd_queue_type
{
SCST_CMD_QUEUE_UNTAGGED = 0,
SCST_CMD_QUEUE_SIMPLE,
SCST_CMD_QUEUE_ORDERED,
SCST_CMD_QUEUE_HEAD_OF_QUEUE,
SCST_CMD_QUEUE_ACA
};
/*************************************************************
** Data direction aliases
*************************************************************/
#define SCST_DATA_UNKNOWN 0
#define SCST_DATA_WRITE 1
#define SCST_DATA_READ 2
#define SCST_DATA_NONE 3
/*************************************************************
** Sense manipulation and examination
*************************************************************/
#define SCST_LOAD_SENSE(key_asc_ascq) key_asc_ascq
#define SCST_SENSE_VALID(sense) ((((uint8_t *)(sense))[0] & 0x70) == 0x70)
#define SCST_NO_SENSE(sense) (((uint8_t *)(sense))[2] == 0)
/*************************************************************
** Sense data for the appropriate errors. Can be used with
** scst_set_cmd_error()
*************************************************************/
#define scst_sense_no_sense NO_SENSE, 0x00, 0
#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0
#define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0
#define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0
#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0
#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0
#define scst_sense_reset_UA UNIT_ATTENTION, 0x29, 0
#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7
#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0
#define scst_sense_lun_not_supported ILLEGAL_REQUEST, 0x25, 0
#define scst_sense_data_protect DATA_PROTECT, 0x00, 0
#define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0
#define scst_sense_block_out_range_error ILLEGAL_REQUEST, 0x21, 0
#define scst_sense_medium_changed_UA UNIT_ATTENTION, 0x28, 0
#define scst_sense_read_error MEDIUM_ERROR, 0x11, 0
#define scst_sense_write_error MEDIUM_ERROR, 0x03, 0
#define scst_sense_not_ready NOT_READY, 0x04, 0x10
/*************************************************************
* SCSI opcodes not listed anywhere else
*************************************************************/
#ifndef REPORT_DEVICE_IDENTIFIER
#define REPORT_DEVICE_IDENTIFIER 0xA3
#endif
#ifndef INIT_ELEMENT_STATUS
#define INIT_ELEMENT_STATUS 0x07
#endif
#ifndef INIT_ELEMENT_STATUS_RANGE
#define INIT_ELEMENT_STATUS_RANGE 0x37
#endif
#ifndef PREVENT_ALLOW_MEDIUM
#define PREVENT_ALLOW_MEDIUM 0x1E
#endif
#ifndef READ_ATTRIBUTE
#define READ_ATTRIBUTE 0x8C
#endif
#ifndef REQUEST_VOLUME_ADDRESS
#define REQUEST_VOLUME_ADDRESS 0xB5
#endif
#ifndef WRITE_ATTRIBUTE
#define WRITE_ATTRIBUTE 0x8D
#endif
#ifndef WRITE_VERIFY_16
#define WRITE_VERIFY_16 0x8E
#endif
#ifndef VERIFY_6
#define VERIFY_6 0x13
#endif
#ifndef VERIFY_12
#define VERIFY_12 0xAF
#endif
#ifndef READ_16
#define READ_16 0x88
#endif
#ifndef WRITE_16
#define WRITE_16 0x8a
#endif
#ifndef VERIFY_16
#define VERIFY_16 0x8f
#endif
#ifndef SERVICE_ACTION_IN
#define SERVICE_ACTION_IN 0x9e
#endif
#ifndef SAI_READ_CAPACITY_16
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#endif
#ifndef MI_REPORT_TARGET_PGS
/* values for maintenance in */
#define MI_REPORT_TARGET_PGS 0x0a
#endif
#ifndef REPORT_LUNS
#define REPORT_LUNS 0xa0
#endif
/*************************************************************
** SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
** T10/1561-D Revision 4 Draft dated 7th November 2002.
*************************************************************/
#define SAM_STAT_GOOD 0x00
#define SAM_STAT_CHECK_CONDITION 0x02
#define SAM_STAT_CONDITION_MET 0x04
#define SAM_STAT_BUSY 0x08
#define SAM_STAT_INTERMEDIATE 0x10
#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
#define SAM_STAT_RESERVATION_CONFLICT 0x18
#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
#define SAM_STAT_TASK_SET_FULL 0x28
#define SAM_STAT_ACA_ACTIVE 0x30
#define SAM_STAT_TASK_ABORTED 0x40
/*************************************************************
** Control byte field in CDB
*************************************************************/
#ifndef CONTROL_BYTE_LINK_BIT
#define CONTROL_BYTE_LINK_BIT 0x01
#endif
#ifndef CONTROL_BYTE_NACA_BIT
#define CONTROL_BYTE_NACA_BIT 0x04
#endif
/*************************************************************
** Byte 1 in INQUIRY CDB
*************************************************************/
#define SCST_INQ_EVPD 0x01
/*************************************************************
** Byte 3 in Standard INQUIRY data
*************************************************************/
#define SCST_INQ_BYTE3 3
#define SCST_INQ_NORMACA_BIT 0x20
/*************************************************************
** Byte 2 in RESERVE_10 CDB
*************************************************************/
#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
#endif /* __SCST_CONST_H */

View File

@@ -1,7 +1,7 @@
/*
* include/scst_debug.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains macroses for execution tracing and error reporting
@@ -100,7 +100,7 @@
#if defined(DEBUG) || defined(TRACING)
extern int debug_print_prefix(unsigned long trace_flag, const char *func, int line);
extern void debug_print_buffer(unsigned long trace_flag, const void *data, int len);
extern void debug_print_buffer(const void *data, int len);
#define TRACE(trace, format, args...) \
do { \
@@ -138,7 +138,7 @@ do { \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s%s:", __tflag, message); \
debug_print_buffer(trace_flag, buff, len); \
debug_print_buffer(buff, len); \
} \
} while(0)
@@ -152,7 +152,7 @@ do { \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s%s:", __tflag, message); \
debug_print_buffer(trace_flag, buff, len); \
debug_print_buffer(buff, len); \
} \
} while(0)

View File

@@ -70,6 +70,7 @@ install: all
install -d $(INSTALL_DIR_H)
install -m 644 ../include/scsi_tgt.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_debug.h $(INSTALL_DIR_H)
install -m 644 ../include/scst_const.h $(INSTALL_DIR_H)
ifneq ($(MODS_VERS),)
rm -f $(INSTALL_DIR_H)/Module.symvers
install -m 644 Modules.symvers $(INSTALL_DIR_H)
@@ -91,7 +92,7 @@ endif
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
INSTALL_DIR_H := /usr/local/include/scst
EXTRA_CFLAGS += -I$(SCST_INC_DIR)
EXTRA_CFLAGS += -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter
#EXTRA_CFLAGS += -DSTRICT_SERIALIZING
@@ -102,7 +103,7 @@ EXTRA_CFLAGS += -DEXTRACHECKS
#EXTRA_CFLAGS += -DTRACING
EXTRA_CFLAGS += -DDEBUG
EXTRA_CFLAGS += -DDEBUG -g
#EXTRA_CFLAGS += -DDEBUG_TM -DTM_DBG_GO_OFFLINE=0
#EXTRA_CFLAGS += -DDEBUG_RETRY
#EXTRA_CFLAGS += -DDEBUG_OOM

View File

@@ -61,10 +61,12 @@ endif
INSTALL_DIR := /lib/modules/$(shell uname -r)/extra
EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR)
EXTRA_CFLAGS += -I$(SUBDIRS) -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter
EXTRA_CFLAGS += -DEXTRACHECKS
#EXTRA_CFLAGS += -DTRACING
EXTRA_CFLAGS += -DDEBUG
EXTRA_CFLAGS += -DDEBUG -g
clean:
rm -f *.o *.ko .*.cmd *.mod.c .*.d .depend Modules.symvers Module.symvers

View File

@@ -1,7 +1,7 @@
/*
* scst_cdrom.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI CDROM (type 5) dev handler
@@ -71,7 +71,7 @@ int cdrom_attach(struct scst_device *dev)
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct cdrom_params *params;
@@ -140,7 +140,7 @@ int cdrom_attach(struct scst_device *dev)
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);
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
params->block_shift = CDROM_DEF_BLOCK_SHIFT;
// res = -ENODEV;
goto out_free_buf;
@@ -186,6 +186,10 @@ void cdrom_detach(struct scst_device *dev)
static int cdrom_get_block_shift(struct scst_cmd *cmd)
{
struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
return params->block_shift;
}
@@ -203,12 +207,6 @@ static int cdrom_get_block_shift(struct scst_cmd *cmd)
int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift);
@@ -227,6 +225,10 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
static void cdrom_set_block_shift(struct scst_cmd *cmd, int block_shift)
{
struct cdrom_params *params = (struct cdrom_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
if (block_shift != 0)
params->block_shift = block_shift;
else
@@ -251,10 +253,6 @@ int cdrom_done(struct scst_cmd *cmd)
TRACE_ENTRY();
/*
* 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);
TRACE_EXIT_RES(res);
@@ -299,3 +297,6 @@ module_init(cdrom_init);
module_exit(cdrom_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_DESCRIPTION("SCSI CDROM (type 5) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_changer.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI medium changer (type 8) dev handler
@@ -158,9 +158,6 @@ int changer_done(struct scst_cmd *cmd)
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
@@ -175,7 +172,6 @@ int changer_done(struct scst_cmd *cmd)
}
#endif
out:
TRACE_EXIT();
return res;
}
@@ -217,4 +213,7 @@ static void __exit changer_exit(void)
module_init(changer_init);
module_exit(changer_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI medium changer (type 8) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -15,8 +15,8 @@
#ifdef DEBUG
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | TRACE_MGMT_DEBUG | \
TRACE_SPECIAL)
TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | \
TRACE_MGMT_DEBUG | TRACE_SPECIAL)
#else
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR)
#endif

View File

@@ -1,7 +1,7 @@
/*
* scst_disk.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI disk (type 0) dev handler
@@ -147,7 +147,7 @@ int disk_attach(struct scst_device *dev)
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct disk_params *params;
@@ -213,7 +213,7 @@ int disk_attach(struct scst_device *dev)
else
params->block_shift = scst_calc_block_shift(sector_size);
} else {
TRACE_BUFFER("Sense set", sbuff, SCSI_SENSE_BUFFERSIZE);
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
res = -ENODEV;
goto out_free_buf;
}
@@ -258,6 +258,10 @@ void disk_detach(struct scst_device *dev)
static int disk_get_block_shift(struct scst_cmd *cmd)
{
struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
return params->block_shift;
}
@@ -276,11 +280,6 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift);
cmd->retries = 1;
@@ -299,6 +298,10 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift)
{
struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
if (block_shift != 0)
params->block_shift = block_shift;
else
@@ -323,10 +326,6 @@ int disk_done(struct scst_cmd *cmd)
TRACE_ENTRY();
/*
* 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);
TRACE_EXIT_RES(res);
@@ -373,4 +372,7 @@ int disk_exec(struct scst_cmd *cmd)
return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI disk (type 0) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_modisk.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI MO disk (type 7) dev handler
@@ -147,7 +147,7 @@ int modisk_attach(struct scst_device *dev)
const int buffer_size = 512;
uint8_t *buffer = NULL;
int retries;
unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
enum dma_data_direction data_dir;
unsigned char *sbuff;
struct modisk_params *params;
@@ -226,7 +226,7 @@ int modisk_attach(struct scst_device *dev)
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);
TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
if (sbuff[2] != NOT_READY)
res = -ENODEV;
@@ -273,6 +273,10 @@ void modisk_detach(struct scst_device *dev)
static int modisk_get_block_shift(struct scst_cmd *cmd)
{
struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
return params->block_shift;
}
@@ -291,11 +295,6 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift);
cmd->retries = 1;
@@ -313,6 +312,10 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
static void modisk_set_block_shift(struct scst_cmd *cmd, int block_shift)
{
struct modisk_params *params = (struct modisk_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be
* called, when there are existing commands.
*/
if (block_shift != 0)
params->block_shift = block_shift;
else
@@ -337,10 +340,6 @@ int modisk_done(struct scst_cmd *cmd)
TRACE_ENTRY();
/*
* 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);
TRACE_EXIT_RES(res);
@@ -387,4 +386,7 @@ int modisk_exec(struct scst_cmd *cmd)
return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI MO disk (type 7) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_processor.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI medium processor (type 3) dev handler
@@ -157,9 +157,6 @@ int processor_done(struct scst_cmd *cmd)
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
@@ -174,7 +171,6 @@ int processor_done(struct scst_cmd *cmd)
}
#endif
out:
TRACE_EXIT();
return res;
}
@@ -216,4 +212,7 @@ static void __exit processor_exit(void)
module_init(processor_init);
module_exit(processor_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI medium processor (type 3) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_raid.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI raid(controller) (type 0xC) dev handler
@@ -157,9 +157,6 @@ int raid_done(struct scst_cmd *cmd)
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
@@ -174,7 +171,6 @@ int raid_done(struct scst_cmd *cmd)
}
#endif
out:
TRACE_EXIT();
return res;
}
@@ -216,4 +212,7 @@ static void __exit raid_exit(void)
module_init(raid_init);
module_exit(raid_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI raid(controller) (type 0xC) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_tape.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* SCSI tape (type 1) dev handler
@@ -261,6 +261,10 @@ void tape_detach(struct scst_device *dev)
static int tape_get_block_size(struct scst_cmd *cmd)
{
struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be called,
* when there are existing commands.
*/
return params->block_size;
}
@@ -279,11 +283,6 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
{
int res = SCST_CMD_STATE_DEFAULT;
/*
* No need for locks here, since *_detach() can not be called,
* when there are existing commands.
*/
scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size);
cmd->retries = 1;
@@ -301,6 +300,10 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
static void tape_set_block_size(struct scst_cmd *cmd, int block_size)
{
struct tape_params *params = (struct tape_params *)cmd->dev->dh_priv;
/*
* No need for locks here, since *_detach() can not be called, when
* there are existing commands.
*/
params->block_size = block_size;
return;
}
@@ -324,11 +327,6 @@ int tape_done(struct scst_cmd *cmd)
TRACE_ENTRY();
/*
* 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)) {
res = scst_tape_generic_dev_done(cmd, tape_set_block_size);
} else if ((status == SAM_STAT_CHECK_CONDITION) &&
@@ -413,4 +411,7 @@ int tape_exec(struct scst_cmd *cmd)
return res;
}
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI tape (type 1) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst_vdisk.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
* (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com>
* (C) 2007 Ross Walker <rswwalker at hotmail dot com>
@@ -44,12 +44,14 @@
#define TRACE_ORDER 0x80000000
#if defined(DEBUG) || defined(TRACING)
static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
{
{ TRACE_ORDER, "order" },
{ 0, NULL }
};
#define trace_log_tbl vdisk_proc_local_trace_tbl
#endif
#include "scst_dev_handler.h"
@@ -122,6 +124,10 @@ struct scst_vdisk_dev {
};
struct scst_vdisk_tgt_dev {
/*
* Used without locking since SCST core ensures that only commands
* of the same type per tgt_dev can be processed simultaneously
*/
enum scst_cmd_queue_type last_write_cmd_queue_type;
};
@@ -949,10 +955,6 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
goto out_free;
}
/*
* ToDo: write through/back flags as well as read only one.
*/
if (cmd->cdb[1] & CMDDT) {
TRACE_DBG("%s", "INQUIRY: CMDDT is unsupported");
scst_set_cmd_error(cmd,
@@ -969,7 +971,7 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
int dev_id_num;
char dev_id_str[6];
for (dev_id_num = 0, i = 0; i < strlen(virt_dev->name); i++) {
for (dev_id_num = 0, i = 0; i < (int)strlen(virt_dev->name); i++) {
dev_id_num += virt_dev->name[i];
}
len = scnprintf(dev_id_str, 6, "%d", dev_id_num);
@@ -1218,8 +1220,6 @@ static void vdisk_exec_mode_sense(struct scst_cmd *cmd)
goto out_free;
}
memset(buf, 0, sizeof(buf));
if (0x3 == pcontrol) {
TRACE_DBG("%s", "MODE SENSE: Saving values not supported");
scst_set_cmd_error(cmd,
@@ -2029,7 +2029,7 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
need_new_bio = 1;
for (j = 0; j < cmd->sg_cnt; ++j) {
unsigned int len, bytes, off, thislen;
int len, bytes, off, thislen;
struct page *page;
page = sgl[j].page;
@@ -2171,7 +2171,7 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
compare = 1;
while (length > 0) {
len_mem = length > LEN_MEM ? LEN_MEM : length;
len_mem = (length > LEN_MEM) ? LEN_MEM : length;
TRACE_DBG("Verify: length %zd - len_mem %zd", length, len_mem);
if (!virt_dev->nullio)
@@ -2190,8 +2190,7 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
scst_put_buf(cmd, address_sav);
goto out_set_fs;
}
if (compare && memcmp(address, mem_verify, len_mem) != 0)
{
if (compare && memcmp(address, mem_verify, len_mem) != 0) {
TRACE_DBG("Verify: error memcmp length %zd", length);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_miscompare_error));
@@ -2200,8 +2199,7 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
}
length -= len_mem;
address += len_mem;
if (compare && length <= 0)
{
if (compare && length <= 0) {
scst_put_buf(cmd, address_sav);
length = scst_get_buf_next(cmd, &address);
address_sav = address;
@@ -2398,7 +2396,6 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
if (isdigit(*p)) {
char *pp;
uint32_t t;
block_size = simple_strtoul(p, &pp, 0);
p = pp;
if ((*p != '\0') && !isspace(*p)) {
@@ -2409,17 +2406,8 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
while (isspace(*p) && *p != '\0')
p++;
t = block_size;
block_shift = 0;
while(1) {
if ((t & 1) != 0)
break;
t >>= 1;
block_shift++;
}
block_shift = scst_calc_block_shift(block_size);
if (block_shift < 9) {
PRINT_ERROR_PR("Wrong block size %d",
block_size);
res = -EINVAL;
goto out_free_vdev;
}
@@ -3088,4 +3076,8 @@ static void __exit exit_scst_vdisk_driver(void)
module_init(init_scst_vdisk_driver);
module_exit(exit_scst_vdisk_driver);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI disk (type 0) and CDROM (type 5) dev handler for "
"SCST using files on file systems or block devices");
MODULE_VERSION(SCST_VERSION_STRING);

View File

@@ -1,7 +1,7 @@
/*
* scst.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -111,7 +111,7 @@ int scst_virt_dev_last_id = 1; /* protected by scst_mutex */
* could fail in improper places.
*/
spinlock_t scst_temp_UA_lock = SPIN_LOCK_UNLOCKED;
uint8_t scst_temp_UA[SCSI_SENSE_BUFFERSIZE];
uint8_t scst_temp_UA[SCST_SENSE_BUFFERSIZE];
module_param_named(scst_threads, scst_threads, int, 0);
MODULE_PARM_DESC(scst_threads, "SCSI target threads count");
@@ -705,7 +705,7 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
#ifdef VDISK_ONLY
if (dev_type->exec == NULL) {
PRINT_ERROR_PR("Pass-through dev handlers (handler %s) not "
PRINT_ERROR_PR("Pass-through dev handlers (handler \"%s\") not "
"supported. Recompile SCST with undefined VDISK_ONLY",
dev_type->name);
res = -EINVAL;
@@ -722,8 +722,8 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
exist = 0;
list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
if (strcmp(dt->name, dev_type->name) == 0) {
PRINT_ERROR_PR("Device type handler %s already exist",
dt->name);
PRINT_ERROR_PR("Device type handler \"%s\" already "
"exist", dt->name);
exist = 1;
break;
}
@@ -749,7 +749,7 @@ int scst_register_dev_driver(struct scst_dev_type *dev_type)
scst_resume_activity();
if (res == 0) {
PRINT_INFO_PR("Device handler %s for type %d registered "
PRINT_INFO_PR("Device handler \"%s\" for type %d registered "
"successfully", dev_type->name, dev_type->type);
}
@@ -762,7 +762,7 @@ out_up:
out_err:
scst_resume_activity();
PRINT_ERROR_PR("Failed to register device handler %s for type %d",
PRINT_ERROR_PR("Failed to register device handler \"%s\" for type %d",
dev_type->name, dev_type->type);
goto out;
}
@@ -785,7 +785,7 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type)
}
}
if (!found) {
PRINT_ERROR_PR("Dev handler %s isn't registered",
PRINT_ERROR_PR("Dev handler \"%s\" isn't registered",
dev_type->name);
goto out_up;
}
@@ -804,7 +804,7 @@ void scst_unregister_dev_driver(struct scst_dev_type *dev_type)
scst_cleanup_proc_dev_handler_dir_entries(dev_type);
PRINT_INFO_PR("Device handler %s for type %d unloaded",
PRINT_INFO_PR("Device handler \"%s\" for type %d unloaded",
dev_type->name, dev_type->type);
out:
@@ -827,20 +827,28 @@ int scst_register_virtual_dev_driver(struct scst_dev_type *dev_type)
if (res != 0)
goto out_err;
res = scst_build_proc_dev_handler_dir_entries(dev_type);
if (res < 0)
goto out_err;
PRINT_INFO_PR("Virtuel device handler %s for type %d registered "
"successfully", dev_type->name, dev_type->type);
if (!dev_type->no_proc) {
res = scst_build_proc_dev_handler_dir_entries(dev_type);
if (res < 0)
goto out_err;
}
if (dev_type->type != -1) {
PRINT_INFO_PR("Virtual device handler %s for type %d "
"registered successfully", dev_type->name,
dev_type->type);
} else {
PRINT_INFO_PR("Virtual device handler \"%s\" registered "
"successfully", dev_type->name);
}
out:
TRACE_EXIT_RES(res);
return res;
out_err:
PRINT_ERROR_PR("Failed to register virtual device handler %s for "
"type %d", dev_type->name, dev_type->type);
PRINT_ERROR_PR("Failed to register virtual device handler \"%s\"",
dev_type->name);
goto out;
}
@@ -848,10 +856,10 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type)
{
TRACE_ENTRY();
scst_cleanup_proc_dev_handler_dir_entries(dev_type);
if (!dev_type->no_proc)
scst_cleanup_proc_dev_handler_dir_entries(dev_type);
PRINT_INFO_PR("Device handler %s for type %d unloaded",
dev_type->name, dev_type->type);
PRINT_INFO_PR("Device handler \"%s\" unloaded", dev_type->name);
TRACE_EXIT();
return;
@@ -1195,14 +1203,21 @@ static int __init init_scst(void)
{
struct scsi_sense_hdr *shdr;
BUILD_BUG_ON((sizeof(cmd->sense_buffer) < sizeof(*shdr)) &&
(sizeof(cmd->sense_buffer) >= SCSI_SENSE_BUFFERSIZE));
(sizeof(cmd->sense_buffer) >= SCST_SENSE_BUFFERSIZE));
}
#endif
{
struct scst_tgt_dev *t;
struct scst_cmd *c;
BUILD_BUG_ON(sizeof(t->curr_sn) != sizeof(t->expected_sn));
BUILD_BUG_ON(sizeof(c->sn) != sizeof(t->expected_sn));
}
BUILD_BUG_ON(SCST_DATA_UNKNOWN != DMA_BIDIRECTIONAL);
BUILD_BUG_ON(SCST_DATA_WRITE != DMA_TO_DEVICE);
BUILD_BUG_ON(SCST_DATA_READ != DMA_FROM_DEVICE);
BUILD_BUG_ON(SCST_DATA_NONE != DMA_NONE);
spin_lock_init(&scst_main_cmd_lists.cmd_list_lock);
INIT_LIST_HEAD(&scst_main_cmd_lists.active_cmd_list);
init_waitqueue_head(&scst_main_cmd_lists.cmd_list_waitQ);
@@ -1275,7 +1290,7 @@ static int __init init_scst(void)
scst_scsi_op_list_init();
for (i = 0; i < ARRAY_SIZE(scst_tasklets); i++) {
for (i = 0; i < (int)ARRAY_SIZE(scst_tasklets); i++) {
spin_lock_init(&scst_tasklets[i].tasklet_lock);
INIT_LIST_HEAD(&scst_tasklets[i].tasklet_cmd_list);
tasklet_init(&scst_tasklets[i].tasklet, (void*)scst_cmd_tasklet,
@@ -1425,6 +1440,8 @@ EXPORT_SYMBOL(scst_set_cmd_error_status);
EXPORT_SYMBOL(scst_set_cmd_error);
EXPORT_SYMBOL(scst_set_resp_data_len);
EXPORT_SYMBOL(scst_process_active_cmd);
/*
* Target Driver Side (i.e. HBA)
*/
@@ -1476,6 +1493,14 @@ EXPORT_SYMBOL(scst_del_all_thr_data);
EXPORT_SYMBOL(scst_dev_del_all_thr_data);
EXPORT_SYMBOL(scst_find_thr_data);
/* SGV pool routines */
EXPORT_SYMBOL(sgv_pool_create);
EXPORT_SYMBOL(sgv_pool_destroy);
EXPORT_SYMBOL(sgv_pool_set_allocator);
EXPORT_SYMBOL(sgv_pool_alloc);
EXPORT_SYMBOL(sgv_pool_free);
EXPORT_SYMBOL(sgv_get_priv);
/* Generic parse() routines */
EXPORT_SYMBOL(scst_calc_block_shift);
EXPORT_SYMBOL(scst_sbc_generic_parse);

View File

@@ -1,7 +1,7 @@
/*
* scst_cdbprobe.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -509,6 +509,6 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
#define WRITE_LONG_2 0xea
*/
#define SCST_CDB_TBL_SIZE ((sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops)))
#define SCST_CDB_TBL_SIZE ((int)(sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops)))
#endif /* __SCST_CDBPROBE_H */

View File

@@ -1,7 +1,7 @@
/*
* include/scst_debug.c
* scst_debug.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Contains helper functions for execution tracing and error reporting.
@@ -52,8 +52,7 @@ int debug_print_prefix(unsigned long trace_flag, const char *func,
return i;
}
void debug_print_buffer(unsigned long trace_flag, const void *data,
int len)
void debug_print_buffer(const void *data, int len)
{
int z, z1, i;
const unsigned char *buf = (const unsigned char *) data;

View File

@@ -1,7 +1,7 @@
/*
* scst_lib.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -126,7 +126,7 @@ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len)
l += cmd->sg[i].length;
if (l >= resp_data_len) {
int left = resp_data_len - (l - cmd->sg[i].length);
TRACE(TRACE_SG, "cmd %p (tag %d), "
TRACE(TRACE_SG|TRACE_MEMORY, "cmd %p (tag %d), "
"resp_data_len %d, i %d, cmd->sg[i].length %d, "
"left %d", cmd, cmd->tag, resp_data_len, i,
cmd->sg[i].length, left);
@@ -387,6 +387,7 @@ out:
static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
struct scst_acg_dev *acg_dev)
{
int ini_sg, ini_unchecked_isa_dma, ini_use_clustering;
struct scst_tgt_dev *tgt_dev;
struct scst_device *dev = acg_dev->dev;
int rc, i;
@@ -413,6 +414,40 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev->sess = sess;
atomic_set(&tgt_dev->cmd_count, 0);
tgt_dev->gfp_mask = __GFP_NOWARN;
tgt_dev->pool = &scst_sgv.norm;
if (tgt_dev->dev->scsi_dev != NULL) {
ini_sg = tgt_dev->dev->scsi_dev->host->sg_tablesize;
ini_unchecked_isa_dma =
tgt_dev->dev->scsi_dev->host->unchecked_isa_dma;
ini_use_clustering =
(tgt_dev->dev->scsi_dev->host->use_clustering ==
ENABLE_CLUSTERING);
} else {
ini_sg = (1 << 15) /* infinite */;
ini_unchecked_isa_dma = 0;
ini_use_clustering = 0;
}
tgt_dev->max_sg_cnt = min(ini_sg, sess->tgt->sg_tablesize);
if ((sess->tgt->tgtt->use_clustering || ini_use_clustering) &&
!sess->tgt->tgtt->no_clustering) {
TRACE_MEM("%s", "Use clustering");
tgt_dev->pool = &scst_sgv.norm_clust;
}
if (sess->tgt->tgtt->unchecked_isa_dma || ini_unchecked_isa_dma) {
TRACE_MEM("%s", "Use ISA DMA memory");
tgt_dev->gfp_mask |= GFP_DMA;
tgt_dev->pool = &scst_sgv.dma;
} else {
#ifdef SCST_HIGHMEM
gfp_mask |= __GFP_HIGHMEM;
tgt_dev->pool = &scst_sgv.highmem;
#endif
}
tgt_dev->p_cmd_lists = &scst_main_cmd_lists;
if (dev->scsi_dev != NULL) {
@@ -437,7 +472,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev->expected_sn = 1;
tgt_dev->num_free_sn_slots = ARRAY_SIZE(tgt_dev->sn_slots);
tgt_dev->cur_sn_slot = &tgt_dev->sn_slots[0];
for(i = 0; i < ARRAY_SIZE(tgt_dev->sn_slots); i++)
for(i = 0; i < (int)ARRAY_SIZE(tgt_dev->sn_slots); i++)
atomic_set(&tgt_dev->sn_slots[i], 0);
if (dev->handler->parse_atomic &&
@@ -908,8 +943,8 @@ struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd)
TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned",
buf, len);
memcpy(orig_cmd->sense_buffer, buf,
(sizeof(orig_cmd->sense_buffer) > len) ?
len : sizeof(orig_cmd->sense_buffer));
((int)sizeof(orig_cmd->sense_buffer) > len) ?
len : (int)sizeof(orig_cmd->sense_buffer));
} else {
PRINT_ERROR_PR("%s", "Unable to get the sense via "
"REQUEST SENSE, returning HARDWARE ERROR");
@@ -992,7 +1027,7 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
{
struct scsi_device *scsi_dev;
unsigned char cdb[6];
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
unsigned char *sense;
int rc;
TRACE_ENTRY();
@@ -1000,6 +1035,9 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
if (tgt_dev->dev->scsi_dev == NULL)
goto out;
/* We can't afford missing RELEASE due to memory shortage */
sense = kzalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
scsi_dev = tgt_dev->dev->scsi_dev;
memset(cdb, 0, sizeof(cdb));
@@ -1010,13 +1048,15 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI "
"mid-level");
rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
sense, SCST_DEFAULT_TIMEOUT,
3, GFP_KERNEL);
sense, SCST_DEFAULT_TIMEOUT, 3, GFP_KERNEL);
if (rc) {
PRINT_INFO_PR("scsi_execute() failed: %d", rc);
goto out;
goto out_free;
}
out_free:
kfree(sense);
out:
TRACE_EXIT();
return;
@@ -1220,6 +1260,8 @@ void scst_free_cmd(struct scst_cmd *cmd)
if (unlikely(cmd->mgmt_cmnd))
scst_complete_cmd_mgmt(cmd, cmd->mgmt_cmnd);
scst_check_restore_sg_buff(cmd);
if (unlikely(cmd->internal)) {
if (cmd->bufflen > 0)
scst_release_space(cmd);
@@ -1250,7 +1292,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
#ifdef EXTRACHECKS
if (unlikely(!cmd->sent_to_midlev)) {
PRINT_ERROR_PR("Finishing not executed cmd %p (opcode "
"%d, target %s, lun %Ld, sn %d, expected_sn %d)",
"%d, target %s, lun %Ld, sn %ld, expected_sn %ld)",
cmd, cmd->cdb[0], cmd->tgtt->name, (uint64_t)cmd->lun,
cmd->sn, cmd->tgt_dev->expected_sn);
scst_unblock_deferred(cmd->tgt_dev, cmd);
@@ -1258,7 +1300,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
#endif
if (unlikely(cmd->out_of_sn)) {
TRACE_SN("Out of SN cmd %p (tag %d, sn %d), "
TRACE_SN("Out of SN cmd %p (tag %d, sn %ld), "
"destroy=%d", cmd, cmd->tag, cmd->sn, destroy);
destroy = test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED,
&cmd->cmd_flags);
@@ -1421,97 +1463,36 @@ void scst_release_request(struct scst_cmd *cmd)
int scst_alloc_space(struct scst_cmd *cmd)
{
int tgt_sg = cmd->tgt->sg_tablesize;
int ini_sg;
int gfp_mask;
int res = -ENOMEM;
int ini_unchecked_isa_dma, ini_use_clustering;
int use_clustering = 0;
struct sgv_pool *pool;
int atomic = scst_cmd_atomic(cmd);
int flags;
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
TRACE_ENTRY();
if (cmd->data_buf_alloced) {
TRACE_MEM("%s", "data_buf_alloced set, returning");
sBUG_ON(cmd->sg == NULL);
res = 0;
goto out;
}
gfp_mask = tgt_dev->gfp_mask | (atomic ? GFP_ATOMIC : GFP_KERNEL);
gfp_mask = __GFP_NOWARN;
gfp_mask |= (atomic ? GFP_ATOMIC : GFP_KERNEL);
pool = &scst_sgv.norm;
if (cmd->dev->scsi_dev != NULL) {
ini_sg = cmd->dev->scsi_dev->host->sg_tablesize;
ini_unchecked_isa_dma =
cmd->dev->scsi_dev->host->unchecked_isa_dma;
ini_use_clustering =
(cmd->dev->scsi_dev->host->use_clustering ==
ENABLE_CLUSTERING);
}
else {
ini_sg = (1 << 15) /* infinite */;
ini_unchecked_isa_dma = 0;
ini_use_clustering = 0;
}
if ((cmd->tgtt->use_clustering || ini_use_clustering) &&
!cmd->tgtt->no_clustering)
{
TRACE_MEM("%s", "Use clustering");
pool = &scst_sgv.norm_clust;
use_clustering = 1;
}
if (cmd->tgtt->unchecked_isa_dma || ini_unchecked_isa_dma) {
TRACE_MEM("%s", "Use ISA DMA memory");
gfp_mask |= GFP_DMA;
pool = &scst_sgv.dma;
} else {
#ifdef SCST_HIGHMEM
gfp_mask |= __GFP_HIGHMEM;
pool = &scst_sgv.highmem;
#endif
}
if (cmd->no_sgv) {
if (atomic)
goto out;
cmd->sg = scst_alloc(cmd->bufflen, gfp_mask, use_clustering,
&cmd->sg_cnt);
} else {
cmd->sg = sgv_pool_alloc(pool, cmd->bufflen, gfp_mask, atomic,
&cmd->sg_cnt, &cmd->sgv);
}
flags = atomic ? SCST_POOL_NO_ALLOC_ON_CACHE_MISS : 0;
if (cmd->no_sgv)
flags |= SCST_POOL_ALLOC_NO_CACHED;
cmd->sg = sgv_pool_alloc(tgt_dev->pool, cmd->bufflen, gfp_mask, flags,
&cmd->sg_cnt, &cmd->sgv, NULL);
if (cmd->sg == NULL)
goto out;
if (unlikely(cmd->sg_cnt > ini_sg)) {
if (unlikely(cmd->sg_cnt > tgt_dev->max_sg_cnt)) {
static int ll;
if (ll < 10) {
PRINT_INFO("Unable to complete command due to "
"underlying device SG IO count limitation "
"(requested %d, available %d)", cmd->sg_cnt,
ini_sg);
"SG IO count limitation (requested %d, "
"available %d, tgt lim %d)", cmd->sg_cnt,
tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize);
ll++;
}
goto out_sg_free;
}
if (unlikely(cmd->sg_cnt > tgt_sg)) {
static int ll;
if (ll < 10) {
PRINT_INFO("Unable to complete command due to "
"target device %s SG IO count limitation "
"(requested %d, available %d)", cmd->tgtt->name,
cmd->sg_cnt, tgt_sg);
ll++;
}
goto out_sg_free;
}
res = 0;
out:
@@ -1519,10 +1500,7 @@ out:
return res;
out_sg_free:
if (cmd->no_sgv)
scst_free(cmd->sg, cmd->sg_cnt);
else
sgv_pool_free(cmd->sgv);
sgv_pool_free(cmd->sgv);
cmd->sgv = NULL;
cmd->sg = NULL;
cmd->sg_cnt = 0;
@@ -1533,16 +1511,15 @@ void scst_release_space(struct scst_cmd *cmd)
{
TRACE_ENTRY();
if (cmd->sgv == NULL)
goto out;
if (cmd->data_buf_alloced) {
TRACE_MEM("%s", "data_buf_alloced set, returning");
goto out;
}
if (cmd->sgv) {
scst_check_restore_sg_buff(cmd);
sgv_pool_free(cmd->sgv);
} else if (cmd->sg)
scst_free(cmd->sg, cmd->sg_cnt);
sgv_pool_free(cmd->sgv);
cmd->sgv = NULL;
cmd->sg_cnt = 0;
@@ -1565,7 +1542,7 @@ int __scst_get_buf(struct scst_cmd *cmd, uint8_t **buf)
*buf = NULL;
if (i >= cmd->sg_cnt)
if ((i >= cmd->sg_cnt) || unlikely(sg == NULL))
goto out;
#ifdef SCST_HIGHMEM
/*
@@ -1712,6 +1689,8 @@ int scst_get_cdb_info(const uint8_t *cdb_p, int dev_type,
TRACE(TRACE_SCSI, "Unknown opcode 0x%x for type %d", op,
dev_type);
res = -1;
memset(info_p, 0, sizeof(*info_p));
info_p->flags = SCST_INFO_INVALID;
goto out;
}
@@ -1833,11 +1812,12 @@ out_err:
int scst_calc_block_shift(int sector_size)
{
int block_shift = 0;
int t = sector_size;
int t;
if (sector_size == 0)
sector_size = 512;
t = sector_size;
while(1) {
if ((t & 1) != 0)
break;
@@ -2104,19 +2084,22 @@ static int scst_null_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
}
int scst_changer_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing)
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd))
{
return scst_null_parse(cmd, info_cdb);
}
int scst_processor_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing)
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd))
{
return scst_null_parse(cmd, info_cdb);
}
int scst_raid_generic_parse(struct scst_cmd *cmd,
struct scst_info_cdb *info_cdb, int nothing)
struct scst_info_cdb *info_cdb,
int (*nothing)(struct scst_cmd *cmd))
{
return scst_null_parse(cmd, info_cdb);
}
@@ -2130,9 +2113,6 @@ int scst_block_generic_dev_done(struct scst_cmd *cmd,
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
@@ -2149,9 +2129,8 @@ int scst_block_generic_dev_done(struct scst_cmd *cmd,
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);
PRINT_ERROR_PR("%s: Unable to get the buffer "
"(%d)", __FUNCTION__, buffer_size);
goto out;
}
@@ -2191,9 +2170,6 @@ int scst_tape_generic_dev_done(struct scst_cmd *cmd,
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
@@ -2205,9 +2181,8 @@ int scst_tape_generic_dev_done(struct scst_cmd *cmd,
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);
PRINT_ERROR_PR("%s: Unable to get the buffer (%d)",
__FUNCTION__, buffer_size);
goto out;
}
break;
@@ -2395,7 +2370,7 @@ void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
}
memset(UA_entry, 0, sizeof(*UA_entry));
if (sense_len > sizeof(UA_entry->UA_sense_buffer))
if (sense_len > (int)sizeof(UA_entry->UA_sense_buffer))
sense_len = sizeof(UA_entry->UA_sense_buffer);
memcpy(UA_entry->UA_sense_buffer, sense, sense_len);
set_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags);
@@ -2531,7 +2506,7 @@ int scst_check_hq_cmd(struct scst_cmd *cmd)
struct scst_cmd *__scst_check_deferred_commands(struct scst_tgt_dev *tgt_dev)
{
struct scst_cmd *res = NULL, *cmd, *t;
int expected_sn = tgt_dev->expected_sn;
typeof(tgt_dev->expected_sn) expected_sn = tgt_dev->expected_sn;
spin_lock_irq(&tgt_dev->sn_lock);
@@ -2565,7 +2540,7 @@ restart:
list_for_each_entry_safe(cmd, t, &tgt_dev->deferred_cmd_list,
sn_cmd_list_entry) {
if (cmd->sn == expected_sn) {
TRACE_SN("Deferred command %p (sn %d) found",
TRACE_SN("Deferred command %p (sn %ld) found",
cmd, cmd->sn);
tgt_dev->def_cmd_count--;
list_del(&cmd->sn_cmd_list_entry);
@@ -2594,12 +2569,13 @@ restart:
* !! sn_slot and sn_cmd_list_entry, could be !!
* !! already destroyed !!
*/
TRACE_SN("cmd %p (tag %d) with skipped sn %d found",
TRACE_SN("cmd %p (tag %d) with skipped sn %ld found",
cmd, cmd->tag, cmd->sn);
tgt_dev->def_cmd_count--;
list_del(&cmd->sn_cmd_list_entry);
spin_unlock_irq(&tgt_dev->sn_lock);
EXTRACHECKS_BUG_ON(cmd->head_of_queue);
EXTRACHECKS_BUG_ON(cmd->queue_type ==
SCST_CMD_QUEUE_HEAD_OF_QUEUE);
if (test_and_set_bit(SCST_CMD_CAN_BE_DESTROYED,
&cmd->cmd_flags)) {
scst_destroy_put_cmd(cmd);
@@ -2691,6 +2667,8 @@ int scst_inc_on_dev_cmd(struct scst_cmd *cmd)
int res = 0;
struct scst_device *dev = cmd->dev;
TRACE_ENTRY();
sBUG_ON(cmd->blocking);
atomic_inc(&dev->on_dev_count);
@@ -2707,7 +2685,7 @@ int scst_inc_on_dev_cmd(struct scst_cmd *cmd)
&dev->blocked_cmd_list);
res = 1;
} else {
__scst_block_dev(cmd->dev);
__scst_block_dev(dev);
cmd->blocking = 1;
}
spin_unlock_bh(&dev->dev_lock);
@@ -2735,17 +2713,19 @@ repeat:
}
spin_unlock_bh(&dev->dev_lock);
}
if (unlikely(cmd->dev->dev_serialized)) {
if (unlikely(dev->dev_serialized)) {
spin_lock_bh(&dev->dev_lock);
barrier(); /* to reread block_count */
if (cmd->dev->block_count == 0) {
if (dev->block_count == 0) {
TRACE_MGMT_DBG("cmd %p (tag %d), blocking further "
"cmds due to serializing (dev %p)", cmd,
cmd->tag, dev);
__scst_block_dev(cmd->dev);
__scst_block_dev(dev);
cmd->blocking = 1;
} else {
spin_unlock_bh(&dev->dev_lock);
TRACE_MGMT_DBG("Somebody blocked the device, "
"repeating (count %d)", dev->block_count);
goto repeat;
}
spin_unlock_bh(&dev->dev_lock);
@@ -2753,6 +2733,7 @@ repeat:
#endif
out:
TRACE_EXIT_RES(res);
return res;
out_unlock:
@@ -2780,7 +2761,7 @@ void scst_unblock_cmds(struct scst_device *dev)
* scst_inc_expected_sn().
*/
if (likely(!cmd->internal) && likely(!cmd->retry)) {
int expected_sn;
typeof(cmd->tgt_dev->expected_sn) expected_sn;
if (cmd->tgt_dev == NULL)
sBUG();
expected_sn = cmd->tgt_dev->expected_sn;
@@ -2812,7 +2793,7 @@ void scst_unblock_cmds(struct scst_device *dev)
list_del(&cmd->blocked_cmd_list_entry);
TRACE_MGMT_DBG("Adding blocked cmd %p to active cmd list", cmd);
spin_lock(&cmd->cmd_lists->cmd_list_lock);
if (unlikely(cmd->head_of_queue))
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -2833,7 +2814,7 @@ static struct scst_cmd *__scst_unblock_deferred(
{
struct scst_cmd *res = NULL;
if (out_of_sn_cmd->head_of_queue) {
if (out_of_sn_cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE) {
TRACE_SN("HQ out_of_sn_cmd %p", out_of_sn_cmd);
spin_lock_irq(&out_of_sn_cmd->tgt_dev->sn_lock);
list_del(&out_of_sn_cmd->sn_cmd_list_entry);
@@ -2848,8 +2829,8 @@ static struct scst_cmd *__scst_unblock_deferred(
tgt_dev->def_cmd_count++;
list_add_tail(&out_of_sn_cmd->sn_cmd_list_entry,
&tgt_dev->skipped_sn_list);
TRACE_SN("out_of_sn_cmd %p with sn %d added to skipped_sn_list "
"(expected_sn %d)", out_of_sn_cmd, out_of_sn_cmd->sn,
TRACE_SN("out_of_sn_cmd %p with sn %ld added to skipped_sn_list "
"(expected_sn %ld)", out_of_sn_cmd, out_of_sn_cmd->sn,
tgt_dev->expected_sn);
spin_unlock_irq(&tgt_dev->sn_lock);
}
@@ -2873,7 +2854,7 @@ void scst_unblock_deferred(struct scst_tgt_dev *tgt_dev,
if (cmd != NULL) {
unsigned long flags;
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
TRACE_SN("cmd %p with sn %d added to the head of active cmd "
TRACE_SN("cmd %p with sn %ld added to the head of active cmd "
"list", cmd, cmd->sn);
list_add(&cmd->cmd_list_entry, &cmd->cmd_lists->active_cmd_list);
wake_up(&cmd->cmd_lists->cmd_list_waitQ);

View File

@@ -1,7 +1,7 @@
/*
* scst_sgv_pool.c
*
* Copyright (C) 2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2006-2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -41,9 +41,11 @@
* of the existing SLAB code.
*/
atomic_t sgv_big_total_alloc;
atomic_t sgv_other_total_alloc;
DECLARE_MUTEX(scst_sgv_pool_mutex);
LIST_HEAD(scst_sgv_pool_list);
static int scst_check_clustering(struct scatterlist *sg, int cur, int hint)
{
int res = -1;
@@ -111,7 +113,8 @@ out_head:
goto out;
}
static void scst_free_sg_entries(struct scatterlist *sg, int sg_count)
static void scst_free_sys_sg_entries(struct scatterlist *sg, int sg_count,
void *priv)
{
int i;
@@ -151,8 +154,23 @@ static void scst_free_sg_entries(struct scatterlist *sg, int sg_count)
}
}
static struct page *scst_alloc_sys_pages(struct scatterlist *sg,
gfp_t gfp_mask, void *priv)
{
sg->page = alloc_pages(gfp_mask, 0);
sg->offset = 0;
sg->length = PAGE_SIZE;
TRACE_MEM("page=%p, sg=%p, priv=%p", sg->page, sg, priv);
if (sg->page == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of "
"sg page failed");
}
return sg->page;
}
static int scst_alloc_sg_entries(struct scatterlist *sg, int pages,
unsigned long gfp_mask, int clustered, struct trans_tbl_ent *trans_tbl)
gfp_t gfp_mask, int clustered, struct trans_tbl_ent *trans_tbl,
const struct sgv_pool_alloc_fns *alloc_fns, void *priv)
{
int sg_count = 0;
int pg, i, j;
@@ -161,25 +179,23 @@ static int scst_alloc_sg_entries(struct scatterlist *sg, int pages,
TRACE_MEM("pages=%d, clustered=%d", pages, clustered);
#if 0
mask |= __GFP_COLD;
gfp_mask |= __GFP_COLD;
#endif
#ifdef SCST_STRICT_SECURITY
mask |= __GFP_ZERO;
gfp_mask |= __GFP_ZERO;
#endif
for (pg = 0; pg < pages; pg++) {
void *rc;
#ifdef DEBUG_OOM
if ((scst_random() % 10000) == 55)
sg[sg_count].page = NULL;
void *rc = NULL;
else
#endif
sg[sg_count].page = alloc_pages(gfp_mask, 0);
if (sg[sg_count].page == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of "
"sg page failed");
rc = alloc_fns->alloc_pages_fn(&sg[sg_count], gfp_mask,
priv);
if (rc == NULL)
goto out_no_mem;
}
sg[sg_count].length = PAGE_SIZE;
if (clustered) {
merged = scst_check_clustering(sg, sg_count, merged);
if (merged == -1)
@@ -190,13 +206,16 @@ static int scst_alloc_sg_entries(struct scatterlist *sg, int pages,
sg_count);
}
if (clustered && trans_tbl) {
if (clustered && (trans_tbl != NULL)) {
pg = 0;
for (i = 0; i < pages; i++) {
int n = sg[i].length >> PAGE_SHIFT;
int n = (sg[i].length >> PAGE_SHIFT) +
((sg[i].length & ~PAGE_MASK) != 0);
trans_tbl[i].pg_count = pg;
for (j = 0; j < n; j++)
trans_tbl[pg++].sg_num = i+1;
TRACE_MEM("i=%d, n=%d, pg_count=%d", i, n,
trans_tbl[i].pg_count);
}
}
@@ -205,118 +224,222 @@ out:
return sg_count;
out_no_mem:
scst_free_sg_entries(sg, sg_count);
alloc_fns->free_pages_fn(sg, sg_count, priv);
sg_count = 0;
goto out;
}
struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, int size,
unsigned long gfp_mask, int atomic, int *count,
struct sgv_pool_obj **sgv)
static inline struct scatterlist *sgv_alloc_sg_entries(int pages_to_alloc,
unsigned long gfp_mask)
{
int esz;
struct scatterlist *res;
esz = pages_to_alloc * sizeof(*res);
res = (struct scatterlist*)kzalloc(esz, gfp_mask);
if (unlikely(res == NULL)) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
"SG vector failed (size %d)", esz);
}
return res;
}
struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, unsigned int size,
unsigned long gfp_mask, int flags, int *count,
struct sgv_pool_obj **sgv, void *priv)
{
struct sgv_pool_obj *obj;
int order, pages, cnt, sg;
struct scatterlist *res = NULL;
int order, pages, cnt;
struct scatterlist *res;
int pages_to_alloc;
struct kmem_cache *cache;
struct trans_tbl_ent *trans_tbl;
int no_cached = flags & SCST_POOL_ALLOC_NO_CACHED;
if (unlikely(size == 0))
return NULL;
sBUG_ON(size == 0);
pages = (size >> PAGE_SHIFT) + ((size & ~PAGE_MASK) != 0);
order = get_order(size);
TRACE_MEM("size=%d, pages=%d, order=%d", size, pages, order);
TRACE_MEM("size=%d, pages=%d, order=%d, flags=%x, *sgv %p", size, pages,
order, flags, *sgv);
if (order >= SGV_POOL_ELEMENTS) {
obj = NULL;
if (atomic)
goto out;
atomic_inc(&sgv_big_total_alloc);
atomic_dec(&sgv_other_total_alloc);
res = scst_alloc(size, gfp_mask, pool->clustered, count);
goto out;
if (*sgv != NULL) {
obj = *sgv;
TRACE_MEM("Supplied sgv_obj %p", obj);
pages_to_alloc = obj->sg_count;
cache = obj->owner_cache;
trans_tbl = obj->trans_tbl;
EXTRACHECKS_BUG_ON(obj->sg_entries != NULL);
obj->sg_entries = sgv_alloc_sg_entries(pages_to_alloc, gfp_mask);
if (unlikely(obj->sg_entries == NULL))
goto out_fail_free;
goto alloc;
}
obj = kmem_cache_alloc(pool->caches[order],
gfp_mask & ~(__GFP_HIGHMEM|GFP_DMA));
if (obj == NULL) {
if (!atomic) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
"failed (size %d)", size);
if ((order < SGV_POOL_ELEMENTS) && !no_cached) {
cache = pool->caches[order];
obj = kmem_cache_alloc(cache,
gfp_mask & ~(__GFP_HIGHMEM|GFP_DMA));
if (unlikely(obj == NULL)) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of "
"sgv_pool_obj failed (size %d)", size);
goto out_fail;
}
goto out;
}
if (obj->owner_cache != pool->caches[order]) {
int esz, epg, eorder;
if (atomic)
goto out_free;
esz = (1 << order) * sizeof(obj->entries[0]);
epg = (esz >> PAGE_SHIFT) + ((esz & ~PAGE_MASK) != 0);
eorder = get_order(esz);
TRACE_MEM("Brand new sgv_obj %p (esz=%d, epg=%d, eorder=%d)",
obj, esz, epg, eorder);
obj->eorder = eorder;
obj->entries = (struct scatterlist*)__get_free_pages(
gfp_mask|__GFP_ZERO, eorder);
if (obj->entries == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool_obj "
"SG vector order %d failed", eorder);
goto out_free;
if (obj->sg_entries != NULL) {
TRACE_MEM("Cached sgv_obj %p", obj);
EXTRACHECKS_BUG_ON(obj->owner_cache != cache);
atomic_inc(&pool->acc.hit_alloc);
atomic_inc(&pool->cache_acc[order].hit_alloc);
goto success;
}
obj->sg_count = scst_alloc_sg_entries(obj->entries, (1 << order),
gfp_mask, pool->clustered, obj->trans_tbl);
if (obj->sg_count <= 0)
goto out_free_entries;
obj->owner_cache = pool->caches[order];
obj->owner_cache = cache;
pages_to_alloc = (1 << order);
if (flags & SCST_POOL_NO_ALLOC_ON_CACHE_MISS) {
if (flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL)
goto out_return;
else
goto out_fail_free;
}
TRACE_MEM("Brand new sgv_obj %p", obj);
obj->sg_entries = sgv_alloc_sg_entries(pages_to_alloc, gfp_mask);
if (unlikely(obj->sg_entries == NULL))
goto out_fail_free;
trans_tbl = obj->trans_tbl;
/*
* No need to clear trans_tbl, if needed, it will be fully
* rewritten in scst_alloc_sg_entries()
*/
} else {
TRACE_MEM("Cached sgv_obj %p", obj);
atomic_inc(&pool->acc.hit_alloc);
atomic_inc(&pool->cache_acc[order].hit_alloc);
int sz;
pages_to_alloc = pages;
if (flags & SCST_POOL_NO_ALLOC_ON_CACHE_MISS)
goto out_return2;
cache = NULL;
sz = sizeof(*obj) + pages*sizeof(obj->sg_entries[0]);
obj = kzalloc(sz, gfp_mask);
if (unlikely(obj == NULL)) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of "
"sgv_pool_obj failed (size %d)", size);
goto out_fail;
}
obj->sg_entries = (struct scatterlist*)obj->trans_tbl;
trans_tbl = NULL;
TRACE_MEM("Big or no_cached sgv_obj %p (size %d)", obj, sz);
}
obj->allocator_priv = priv;
obj->owner_pool = pool;
alloc:
obj->sg_count = scst_alloc_sg_entries(obj->sg_entries,
pages_to_alloc, gfp_mask, pool->clustered, trans_tbl,
&pool->alloc_fns, priv);
if (unlikely(obj->sg_count <= 0)) {
if ((flags & SCST_POOL_RETURN_OBJ_ON_ALLOC_FAIL) && cache) {
kfree(obj->sg_entries);
obj->sg_entries = NULL;
goto out_return1;
} else
goto out_fail_free_sg_entries;
}
success:
atomic_inc(&pool->acc.total_alloc);
atomic_inc(&pool->cache_acc[order].total_alloc);
if (pool->clustered)
cnt = obj->trans_tbl[pages-1].sg_num;
else
cnt = pages;
sg = cnt-1;
obj->orig_sg = sg;
obj->orig_length = obj->entries[sg].length;
if (pool->clustered) {
obj->entries[sg].length =
(pages - obj->trans_tbl[sg].pg_count) << PAGE_SHIFT;
}
if (size & ~PAGE_MASK) {
obj->entries[sg].length -= PAGE_SIZE - (size & ~PAGE_MASK);
if (cache) {
int sg;
atomic_inc(&pool->cache_acc[order].total_alloc);
if (pool->clustered)
cnt = obj->trans_tbl[pages-1].sg_num;
else
cnt = obj->sg_count;
sg = cnt-1;
obj->orig_sg = sg;
obj->orig_length = obj->sg_entries[sg].length;
if (pool->clustered) {
obj->sg_entries[sg].length =
(pages - obj->trans_tbl[sg].pg_count) << PAGE_SHIFT;
}
} else {
cnt = obj->sg_count;
if (no_cached)
atomic_inc(&pool->other_alloc);
else
atomic_inc(&pool->big_alloc);
}
*count = cnt;
TRACE_MEM("sgv_obj=%p (size=%d, pages=%d, "
"sg_count=%d, count=%d, last_len=%d)", obj, size, pages,
obj->sg_count, *count, obj->entries[obj->orig_sg].length);
res = obj->entries;
res = obj->sg_entries;
*sgv = obj;
if (size & ~PAGE_MASK)
obj->sg_entries[cnt-1].length -= PAGE_SIZE - (size & ~PAGE_MASK);
TRACE_MEM("sgv_obj=%p, sg_entries %p (size=%d, pages=%d, sg_count=%d, "
"count=%d, last_len=%d)", obj, obj->sg_entries, size, pages,
obj->sg_count, *count, obj->sg_entries[obj->orig_sg].length);
out:
return res;
out_free_entries:
free_pages((unsigned long)obj->entries, obj->eorder);
obj->entries = NULL;
out_return:
obj->allocator_priv = priv;
obj->owner_pool = pool;
out_free:
kmem_cache_free(pool->caches[order], obj);
obj = NULL;
out_return1:
*sgv = obj;
obj->sg_count = pages_to_alloc;
TRACE_MEM("Returning failed sgv_obj %p (count %d)", obj, *count);
out_return2:
*count = pages_to_alloc;
res = NULL;
goto out;
out_fail_free_sg_entries:
if (cache) {
kfree(obj->sg_entries);
obj->sg_entries = NULL;
}
out_fail_free:
if (cache)
kmem_cache_free(pool->caches[order], obj);
else
kfree(obj);
out_fail:
res = NULL;
*count = 0;
*sgv = NULL;
TRACE_MEM("%s", "Allocation failed");
goto out;
}
static void sgv_ctor(void *data, struct kmem_cache *c, unsigned long flags)
void *sgv_get_priv(struct sgv_pool_obj *sgv)
{
return sgv->allocator_priv;
}
void sgv_pool_free(struct sgv_pool_obj *sgv)
{
TRACE_MEM("Freeing sgv_obj %p, owner_cache %p, sg_entries %p, "
"sg_count %d, allocator_priv %p", sgv, sgv->owner_cache,
sgv->sg_entries, sgv->sg_count, sgv->allocator_priv);
if (sgv->owner_cache != NULL) {
if (likely(sgv->sg_entries != NULL))
sgv->sg_entries[sgv->orig_sg].length = sgv->orig_length;
kmem_cache_free(sgv->owner_cache, sgv);
} else {
sgv->owner_pool->alloc_fns.free_pages_fn(sgv->sg_entries,
sgv->sg_count, sgv->allocator_priv);
kfree(sgv);
}
return;
}
static void sgv_ctor(void *data, struct kmem_cache *c, unsigned long flags)
{
struct sgv_pool_obj *obj = data;
@@ -326,46 +449,27 @@ static void sgv_ctor(void *data, struct kmem_cache *c, unsigned long flags)
TRACE_MEM("Constructor for sgv_obj %p", obj);
memset(obj, 0, sizeof(*obj));
return;
}
static void __sgv_dtor(void *data, int pages)
static void sgv_dtor(void *data, struct kmem_cache *k, unsigned long f)
{
struct sgv_pool_obj *obj = data;
TRACE_MEM("Destructor for sgv_obj %p", obj);
if (obj->entries) {
scst_free_sg_entries(obj->entries, obj->sg_count);
free_pages((unsigned long)obj->entries, obj->eorder);
if (obj->sg_entries) {
obj->owner_pool->alloc_fns.free_pages_fn(obj->sg_entries,
obj->sg_count, obj->allocator_priv);
kfree(obj->sg_entries);
}
return;
}
#define SGV_DTOR_NAME(order) sgv_dtor##order
#define SGV_DTOR(order) static void sgv_dtor##order(void *d, struct kmem_cache *k, \
unsigned long f) { __sgv_dtor(d, 1 << order); }
SGV_DTOR(0);
SGV_DTOR(1);
SGV_DTOR(2);
SGV_DTOR(3);
SGV_DTOR(4);
SGV_DTOR(5);
SGV_DTOR(6);
SGV_DTOR(7);
SGV_DTOR(8);
SGV_DTOR(9);
SGV_DTOR(10);
typedef void (*dtor_t)(void *, struct kmem_cache *, unsigned long);
dtor_t cache_dtors[SGV_POOL_ELEMENTS] =
{ SGV_DTOR_NAME(0), SGV_DTOR_NAME(1), SGV_DTOR_NAME(2), SGV_DTOR_NAME(3),
SGV_DTOR_NAME(4), SGV_DTOR_NAME(5), SGV_DTOR_NAME(6), SGV_DTOR_NAME(7),
SGV_DTOR_NAME(8), SGV_DTOR_NAME(9), SGV_DTOR_NAME(10) };
struct scatterlist *scst_alloc(int size, unsigned long gfp_mask,
int use_clustering, int *count)
{
struct scatterlist *res;
int pages = (size >> PAGE_SHIFT) + ((size & ~PAGE_MASK) != 0);
struct sgv_pool_alloc_fns sys_alloc_fns = {
scst_alloc_sys_pages, scst_free_sys_sg_entries };
TRACE_ENTRY();
@@ -376,7 +480,7 @@ struct scatterlist *scst_alloc(int size, unsigned long gfp_mask,
goto out;
*count = scst_alloc_sg_entries(res, pages, gfp_mask, use_clustering,
NULL);
NULL, &sys_alloc_fns, NULL);
if (*count <= 0)
goto out_free;
@@ -395,7 +499,7 @@ out_free:
void scst_free(struct scatterlist *sg, int count)
{
TRACE_MEM("Freeing sg=%p", sg);
scst_free_sg_entries(sg, count);
scst_free_sys_sg_entries(sg, count, NULL);
kfree(sg);
}
@@ -408,10 +512,22 @@ int sgv_pool_init(struct sgv_pool *pool, const char *name, int clustered)
TRACE_ENTRY();
memset(pool, 0, sizeof(*pool));
pool->clustered = clustered;
TRACE_MEM("sizeof(*obj)=%zd, clustered=%d, sizeof(obj->trans_tbl[0])=%zd",
sizeof(*obj), clustered, sizeof(obj->trans_tbl[0]));
atomic_set(&pool->other_alloc, 0);
atomic_set(&pool->big_alloc, 0);
atomic_set(&pool->acc.total_alloc, 0);
atomic_set(&pool->acc.hit_alloc, 0);
pool->clustered = clustered;
pool->alloc_fns.alloc_pages_fn = scst_alloc_sys_pages;
pool->alloc_fns.free_pages_fn = scst_free_sys_sg_entries;
TRACE_MEM("name %s, sizeof(*obj)=%zd, clustered=%d, "
"sizeof(obj->trans_tbl[0])=%zd", name, sizeof(*obj), clustered,
sizeof(obj->trans_tbl[0]));
strncpy(pool->name, name, sizeof(pool->name)-1);
pool->name[sizeof(pool->name)-1] = '\0';
for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
int size, pages;
@@ -427,7 +543,7 @@ int sgv_pool_init(struct sgv_pool *pool, const char *name, int clustered)
scnprintf(pool->cache_names[i], sizeof(pool->cache_names[i]),
"%s-%luK", name, (PAGE_SIZE >> 10) << i);
pool->caches[i] = kmem_cache_create(pool->cache_names[i],
size, 0, SCST_SLAB_FLAGS, sgv_ctor, cache_dtors[i]);
size, 0, SCST_SLAB_FLAGS, sgv_ctor, sgv_dtor);
if (pool->caches[i] == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of sgv_pool cache "
"%s(%d) failed", name, i);
@@ -435,6 +551,10 @@ int sgv_pool_init(struct sgv_pool *pool, const char *name, int clustered)
}
}
down(&scst_sgv_pool_mutex);
list_add_tail(&pool->sgv_pool_list_entry, &scst_sgv_pool_list);
up(&scst_sgv_pool_mutex);
res = 0;
out:
@@ -464,9 +584,22 @@ void sgv_pool_deinit(struct sgv_pool *pool)
pool->caches[i] = NULL;
}
down(&scst_sgv_pool_mutex);
list_del(&pool->sgv_pool_list_entry);
up(&scst_sgv_pool_mutex);
TRACE_EXIT();
}
void sgv_pool_set_allocator(struct sgv_pool *pool,
struct page *(*alloc_pages_fn)(struct scatterlist *, gfp_t, void *),
void (*free_pages_fn)(struct scatterlist *, int, void *))
{
pool->alloc_fns.alloc_pages_fn = alloc_pages_fn;
pool->alloc_fns.free_pages_fn = free_pages_fn;
return;
}
struct sgv_pool *sgv_pool_create(const char *name, int clustered)
{
struct sgv_pool *pool;
@@ -510,7 +643,6 @@ int scst_sgv_pools_init(struct scst_sgv_pools *pools)
TRACE_ENTRY();
atomic_set(&sgv_big_total_alloc, 0);
atomic_set(&sgv_other_total_alloc, 0);
res = sgv_pool_init(&pools->norm, "sgv", 0);

View File

@@ -1,7 +1,7 @@
/*
* scst_sgv_pool.h
*
* Copyright (C) 2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2006-2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -27,7 +27,7 @@
/*
* sg_num is indexed by the page number, pg_count is indexed by the sg number.
* Made in one entry to simplify the code (eg all sizeof(*) parts) and save
* the CPU cache for non-clustered case.
* some CPU cache for non-clustered case.
*/
struct trans_tbl_ent {
unsigned short sg_num;
@@ -37,11 +37,12 @@ struct trans_tbl_ent {
struct sgv_pool_obj
{
struct kmem_cache *owner_cache;
int eorder;
struct sgv_pool *owner_pool;
int orig_sg;
int orig_length;
int sg_count;
struct scatterlist *entries;
struct scatterlist *sg_entries;
void *allocator_priv;
struct trans_tbl_ent trans_tbl[0];
};
@@ -50,14 +51,28 @@ struct sgv_pool_acc
atomic_t total_alloc, hit_alloc;
};
struct sgv_pool_alloc_fns
{
struct page *(*alloc_pages_fn)(struct scatterlist *sg, gfp_t gfp_mask,
void *priv);
void (*free_pages_fn)(struct scatterlist *sg, int sg_count,
void *priv);
};
struct sgv_pool
{
struct sgv_pool_acc acc;
struct sgv_pool_acc cache_acc[SGV_POOL_ELEMENTS];
unsigned int clustered:1;
unsigned int clustered;
struct sgv_pool_alloc_fns alloc_fns;
/* 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 */
struct kmem_cache *caches[SGV_POOL_ELEMENTS];
atomic_t big_alloc, other_alloc;
struct sgv_pool_acc acc;
struct sgv_pool_acc cache_acc[SGV_POOL_ELEMENTS];
char cache_names[SGV_POOL_ELEMENTS][25];
char name[25];
struct list_head sgv_pool_list_entry;
};
struct scst_sgv_pools
@@ -69,29 +84,17 @@ struct scst_sgv_pools
#endif
};
extern atomic_t sgv_big_total_alloc;
extern atomic_t sgv_other_total_alloc;
extern struct semaphore scst_sgv_pool_mutex;
extern struct list_head scst_sgv_pool_list;
extern struct sgv_pool *sgv_pool_create(const char *name, int clustered);
extern void sgv_pool_destroy(struct sgv_pool *pool);
extern int sgv_pool_init(struct sgv_pool *pool, const char *name,
int sgv_pool_init(struct sgv_pool *pool, const char *name,
int clustered);
extern void sgv_pool_deinit(struct sgv_pool *pool);
extern struct scatterlist *sgv_pool_alloc(struct sgv_pool *pool, int size,
unsigned long gfp_mask, int atomic, int *count,
struct sgv_pool_obj **sgv);
static inline void sgv_pool_free(struct sgv_pool_obj *sgv)
{
TRACE_MEM("Freeing sgv_obj %p", sgv);
sgv->entries[sgv->orig_sg].length = sgv->orig_length;
kmem_cache_free(sgv->owner_cache, sgv);
}
void sgv_pool_deinit(struct sgv_pool *pool);
static inline struct scatterlist *sgv_pool_sg(struct sgv_pool_obj *obj)
{
return obj->entries;
return obj->sg_entries;
}
extern int scst_sgv_pools_init(struct scst_sgv_pools *pools);

View File

@@ -1,7 +1,7 @@
/*
* scst_module.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* Support for loading target modules. The usage is similar to scsi_module.c

View File

@@ -1,7 +1,7 @@
/*
* scst_priv.h
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -55,8 +55,8 @@ extern unsigned long scst_trace_flag;
~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
*/
#define SCST_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_RETRY)
TRACE_LINE | TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | \
TRACE_MGMT_DEBUG | TRACE_RETRY)
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
@@ -214,7 +214,7 @@ extern int __scst_add_cmd_threads(int num);
extern void __scst_del_cmd_threads(int num);
extern spinlock_t scst_temp_UA_lock;
extern uint8_t scst_temp_UA[SCSI_SENSE_BUFFERSIZE];
extern uint8_t scst_temp_UA[SCST_SENSE_BUFFERSIZE];
extern struct scst_cmd *__scst_check_deferred_commands(
struct scst_tgt_dev *tgt_dev);
@@ -392,20 +392,6 @@ static inline int scst_is_implicit_hq(struct scst_cmd *cmd)
((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)))));
}
/*
* Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise.
* Dev handlers parse() and dev_done() not called for such commands.
*/
static inline int scst_is_cmd_local(struct scst_cmd *cmd)
{
int res = 0;
switch (cmd->cdb[0]) {
case REPORT_LUNS:
res = 1;
}
return res;
}
/*
* Some notes on devices "blocking". Blocking means that no
* commands will go from SCST to underlying SCSI device until it
@@ -424,7 +410,7 @@ static inline void __scst_block_dev(struct scst_device *dev)
}
static inline void scst_block_dev(struct scst_device *dev,
unsigned int outstanding)
int outstanding)
{
spin_lock_bh(&dev->dev_lock);
__scst_block_dev(dev);
@@ -536,6 +522,10 @@ static inline void scst_set_sense(uint8_t *buffer, int len, int key,
static inline void scst_check_restore_sg_buff(struct scst_cmd *cmd)
{
if (cmd->sg_buff_modified) {
TRACE_MEM("cmd %p, sg %p, orig_sg_entry %d, "
"orig_entry_len %d, orig_sg_cnt %d", cmd, cmd->sg,
cmd->orig_sg_entry, cmd->orig_entry_len,
cmd->orig_sg_cnt);
cmd->sg[cmd->orig_sg_entry].length = cmd->orig_entry_len;
cmd->sg_cnt = cmd->orig_sg_cnt;
}

View File

@@ -1,7 +1,7 @@
/*
* scst_proc.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -948,9 +948,8 @@ int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
TRACE_ENTRY();
if (dev_type->proc_dev_type_root) {
goto out;
}
sBUG_ON(dev_type->proc_dev_type_root);
/* create the proc directory entry for the dev type handler */
dev_type->proc_dev_type_root = proc_mkdir(dev_type->name,
scst_proc_scsi_tgt);
@@ -961,15 +960,17 @@ int scst_build_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
}
scst_dev_handler_type_proc_data.data = dev_type;
p = scst_create_proc_entry(dev_type->proc_dev_type_root,
if (dev_type->type >= 0) {
p = scst_create_proc_entry(dev_type->proc_dev_type_root,
SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
&scst_dev_handler_type_proc_data);
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler entry %s in /proc/%s/%s",
SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
SCST_PROC_ENTRY_NAME, dev_type->name);
goto out_remove;
if (p == NULL) {
PRINT_ERROR_PR("Not enough memory to register dev "
"handler entry %s in /proc/%s/%s",
SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
SCST_PROC_ENTRY_NAME, dev_type->name);
goto out_remove;
}
}
if (dev_type->read_proc || dev_type->write_proc) {
@@ -991,8 +992,9 @@ out:
return res;
out_remove1:
remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
dev_type->proc_dev_type_root);
if (dev_type->type >= 0)
remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
dev_type->proc_dev_type_root);
out_remove:
remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
@@ -1006,16 +1008,16 @@ void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type)
{
TRACE_ENTRY();
if (dev_type->proc_dev_type_root) {
sBUG_ON(dev_type->proc_dev_type_root == NULL);
if (dev_type->type >= 0) {
remove_proc_entry(SCST_PROC_DEV_HANDLER_TYPE_ENTRY_NAME,
dev_type->proc_dev_type_root);
if (dev_type->read_proc || dev_type->write_proc) {
remove_proc_entry(dev_type->name,
dev_type->proc_dev_type_root);
}
remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
dev_type->proc_dev_type_root = NULL;
}
if (dev_type->read_proc || dev_type->write_proc)
remove_proc_entry(dev_type->name, dev_type->proc_dev_type_root);
remove_proc_entry(dev_type->name, scst_proc_scsi_tgt);
dev_type->proc_dev_type_root = NULL;
TRACE_EXIT();
return;
@@ -1208,7 +1210,7 @@ static int scst_proc_assign_handler(char *buf)
{
int res = 0;
char *p = buf, *e, *ee;
int host, channel = 0, id = 0, lun = 0;
unsigned int host, channel = 0, id = 0, lun = 0;
struct scst_device *d, *dev = NULL;
struct scst_dev_type *dt, *handler = NULL;
@@ -1308,7 +1310,7 @@ static int scst_proc_groups_devices_write(struct file *file, const char __user *
{
int res = length, action, virt = 0, rc, read_only = 0;
char *buffer, *p, *e = NULL;
int host, channel = 0, id = 0, lun = 0, virt_lun;
unsigned int host, channel = 0, id = 0, lun = 0, virt_lun;
struct scst_acg *acg = (struct scst_acg *)PDE(file->f_dentry->d_inode)->data;
struct scst_acg_dev *acg_dev = NULL, *acg_dev_tmp;
struct scst_device *d, *dev = NULL;
@@ -1671,7 +1673,7 @@ static int scst_dev_handler_type_info_show(struct seq_file *seq, void *v)
TRACE_ENTRY();
seq_printf(seq, "%d - %s\n", dev_type->type,
dev_type->type > ARRAY_SIZE(scst_proc_dev_handler_type) ?
dev_type->type > (int)ARRAY_SIZE(scst_proc_dev_handler_type) ?
"unknown" : scst_proc_dev_handler_type[dev_type->type]);
TRACE_EXIT();
@@ -1721,37 +1723,41 @@ static struct scst_proc_data scst_sessions_proc_data = {
.show = scst_sessions_info_show,
};
static int scst_do_sgv_read(struct seq_file *seq, const struct sgv_pool *pool, const char *name)
static void scst_do_sgv_read(struct seq_file *seq, const struct sgv_pool *pool)
{
int i;
seq_printf(seq, "\n%-20s %-11d %-11d\n", name, atomic_read(&pool->acc.hit_alloc),
seq_printf(seq, "\n%-30s %-11d %-11d\n", pool->name,
atomic_read(&pool->acc.hit_alloc),
atomic_read(&pool->acc.total_alloc));
for (i = 0; i < SGV_POOL_ELEMENTS; i++) {
seq_printf(seq, " %-18s %-11d %-11d\n", pool->cache_names[i],
seq_printf(seq, " %-28s %-11d %-11d\n", pool->cache_names[i],
atomic_read(&pool->cache_acc[i].hit_alloc),
atomic_read(&pool->cache_acc[i].total_alloc));
}
return 0;
seq_printf(seq, " %-28s %-11d %-11d\n", "big/other", atomic_read(&pool->big_alloc),
atomic_read(&pool->other_alloc));
return;
}
static int scst_sgv_info_show(struct seq_file *seq, void *v)
{
struct sgv_pool *pool;
TRACE_ENTRY();
seq_printf(seq, "%-20s %-11s %-11s", "Name", "Hit", "Total");
seq_printf(seq, "%-30s %-11s %-11s", "Name", "Hit", "Total");
scst_do_sgv_read(seq, &scst_sgv.norm, "sgv");
scst_do_sgv_read(seq, &scst_sgv.norm_clust, "sgv-clust");
scst_do_sgv_read(seq, &scst_sgv.dma, "sgv-dma");
down(&scst_sgv_pool_mutex);
list_for_each_entry(pool, &scst_sgv_pool_list, sgv_pool_list_entry) {
scst_do_sgv_read(seq, pool);
}
up(&scst_sgv_pool_mutex);
#ifdef SCST_HIGHMEM
scst_do_sgv_read(seq, &scst_sgv.highmem, "sgv-highmem");
#endif
seq_printf(seq, "\n%-32s %-11d\n", "big", atomic_read(&sgv_big_total_alloc));
seq_printf(seq, "%-32s %-11d\n", "other", atomic_read(&sgv_other_total_alloc));
seq_printf(seq, "\n%-42s %-11d\n", "other", atomic_read(&sgv_other_total_alloc));
TRACE_EXIT();
return 0;

View File

@@ -1,7 +1,7 @@
/*
* scst_targ.c
*
* Copyright (C) 2004-2006 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
* and Leonid Stoljar
*
* This program is free software; you can redistribute it and/or
@@ -32,7 +32,6 @@
static void scst_cmd_set_sn(struct scst_cmd *cmd);
static int __scst_init_cmd(struct scst_cmd *cmd);
static int scst_process_active_cmd(struct scst_cmd *cmd, int context);
static inline void scst_schedule_tasklet(struct scst_cmd *cmd)
{
@@ -83,7 +82,7 @@ struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
cmd->lun = scst_unpack_lun(lun, lun_len);
if (cdb_len <= MAX_COMMAND_SIZE) {
if (cdb_len <= SCST_MAX_CDB_SIZE) {
memcpy(cmd->cdb, cdb, cdb_len);
cmd->cdb_len = cdb_len;
}
@@ -112,6 +111,8 @@ static int scst_init_cmd(struct scst_cmd *cmd, int context)
rc = __scst_init_cmd(cmd);
if (unlikely(rc > 0))
goto out_redirect;
else if (unlikely(rc != 0))
goto out;
/* Small context optimization */
if (((context == SCST_CONTEXT_TASKLET) ||
@@ -249,7 +250,7 @@ active:
case SCST_CONTEXT_THREAD:
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
if (unlikely(cmd->head_of_queue))
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -272,8 +273,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
struct scst_device *dev = cmd->dev;
struct scst_info_cdb cdb_info;
int atomic = scst_cmd_atomic(cmd);
int orig_bufflen = cmd->bufflen;
int set_dir = 1;
int orig_bufflen;
TRACE_ENTRY();
@@ -285,6 +285,11 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
goto out;
}
cmd->inc_expected_sn_on_done = dev->handler->inc_expected_sn_on_done;
if (cmd->skip_parse)
goto call_parse;
/*
* Expected transfer data supplied by the SCSI transport via the
* target driver are untrusted, so we prefer to fetch them from CDB.
@@ -319,8 +324,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
goto out_xmit;
}
}
else {
} else {
PRINT_ERROR_PR("Unknown opcode 0x%02x for %s and "
"target %s not supplied expected values. "
"Returning INVALID OPCODE.", cmd->cdb[0],
@@ -363,14 +367,32 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
goto out_xmit;
}
call_parse:
orig_bufflen = cmd->bufflen;
if (likely(!scst_is_cmd_local(cmd))) {
TRACE_DBG("Calling dev handler %s parse(%p)",
dev->handler->name, cmd);
TRACE_BUFF_FLAG(TRACE_SEND_BOT, "Parsing: ", cmd->cdb, cmd->cdb_len);
state = dev->handler->parse(cmd, &cdb_info);
/* Caution: cmd can be already dead here */
TRACE_DBG("Dev handler %s parse() returned %d",
dev->handler->name, state);
switch (state) {
case SCST_CMD_STATE_NEED_THREAD_CTX:
TRACE_DBG("Dev handler %s parse() requested thread "
"context, rescheduling", dev->handler->name);
res = SCST_CMD_STATE_RES_NEED_THREAD;
goto out;
case SCST_CMD_STATE_STOP:
TRACE_DBG("Dev handler %s parse() requested stop "
"processing", dev->handler->name);
res = SCST_CMD_STATE_RES_CONT_NEXT;
goto out;
}
if (state == SCST_CMD_STATE_DEFAULT)
state = SCST_CMD_STATE_PREPARE_SPACE;
}
@@ -390,32 +412,32 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
if (cmd->data_len == -1)
cmd->data_len = cmd->bufflen;
if (cmd->data_buf_alloced && (orig_bufflen < cmd->bufflen)) {
if (cmd->data_buf_alloced && (orig_bufflen > cmd->bufflen)) {
PRINT_ERROR_PR("Target driver supplied data buffer (size %d), "
"is less, than required (size %d)", orig_bufflen,
cmd->bufflen);
"is less, than required (size %d)", cmd->bufflen,
orig_bufflen);
goto out_error;
}
#ifdef EXTRACHECKS
if (state != SCST_CMD_STATE_NEED_THREAD_CTX) {
if (((cmd->data_direction == SCST_DATA_UNKNOWN) &&
(state != SCST_CMD_STATE_DEV_PARSE)) ||
((cmd->bufflen != 0) &&
(cmd->data_direction == SCST_DATA_NONE)) ||
((cmd->bufflen == 0) &&
(cmd->data_direction != SCST_DATA_NONE)) ||
((cmd->bufflen != 0) && (cmd->sg == NULL) &&
(state > SCST_CMD_STATE_PREPARE_SPACE)))
{
PRINT_ERROR_PR("Dev handler %s parse() returned "
"invalid cmd data_direction %d, "
"bufflen %zd or state %d (opcode 0x%x)",
dev->handler->name,
cmd->data_direction, cmd->bufflen,
state, cmd->cdb[0]);
goto out_error;
}
if ((state != SCST_CMD_STATE_XMIT_RESP) &&
(((cmd->data_direction == SCST_DATA_UNKNOWN) &&
(state != SCST_CMD_STATE_DEV_PARSE)) ||
((cmd->bufflen != 0) &&
(cmd->data_direction == SCST_DATA_NONE) &&
(cmd->status == 0)) ||
((cmd->bufflen == 0) &&
(cmd->data_direction != SCST_DATA_NONE)) ||
((cmd->bufflen != 0) && (cmd->sg == NULL) &&
(state > SCST_CMD_STATE_PREPARE_SPACE))))
{
PRINT_ERROR_PR("Dev handler %s parse() returned "
"invalid cmd data_direction %d, "
"bufflen %zd or state %d (opcode 0x%x)",
dev->handler->name,
cmd->data_direction, cmd->bufflen,
state, cmd->cdb[0]);
goto out_error;
}
#endif
@@ -431,14 +453,6 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
res = SCST_CMD_STATE_RES_CONT_SAME;
break;
case SCST_CMD_STATE_NEED_THREAD_CTX:
TRACE_DBG("Dev handler %s parse() requested thread "
"context, rescheduling", dev->handler->name);
res = SCST_CMD_STATE_RES_NEED_THREAD;
set_dir = 0;
break;
default:
if (state >= 0) {
PRINT_ERROR_PR("Dev handler %s parse() returned "
@@ -452,7 +466,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
goto out_error;
}
if ((cmd->resp_data_len == -1) && set_dir) {
if (cmd->resp_data_len == -1) {
if (cmd->data_direction == SCST_DATA_READ)
cmd->resp_data_len = cmd->bufflen;
else
@@ -572,23 +586,29 @@ static void scst_low_cur_max_cmd_mem(void)
static int scst_prepare_space(struct scst_cmd *cmd)
{
int r, res = SCST_CMD_STATE_RES_CONT_SAME;
int r = 0, res = SCST_CMD_STATE_RES_CONT_SAME;
TRACE_ENTRY();
if (cmd->data_direction == SCST_DATA_NONE)
goto prep_done;
r = scst_check_mem(cmd);
if (unlikely(r != 0))
goto out;
if (cmd->data_buf_tgt_alloc) {
int orig_bufflen = cmd->bufflen;
TRACE_MEM("%s", "Custom tgt data buf allocation requested");
if (unlikely(cmd->data_buf_alloced)) {
PRINT_ERROR_PR("Target driver %s requested own data "
"allocation, but dev handler %s already "
"allocated them", cmd->tgtt->name,
cmd->dev->handler->name);
goto out_error;
}
r = cmd->tgtt->alloc_data_buf(cmd);
if (r > 0)
r = scst_alloc_space(cmd);
goto alloc;
else if (r == 0) {
cmd->data_buf_alloced = 1;
if (unlikely(orig_bufflen < cmd->bufflen)) {
@@ -596,16 +616,23 @@ static int scst_prepare_space(struct scst_cmd *cmd)
"buffer (size %d), is less, than "
"required (size %d)", orig_bufflen,
cmd->bufflen);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
cmd->state = SCST_CMD_STATE_DEV_DONE;
res = SCST_CMD_STATE_RES_CONT_SAME;
goto out;
goto out_error;
}
}
} else
r = scst_alloc_space(cmd);
goto check;
}
alloc:
if (!cmd->data_buf_alloced) {
r = scst_check_mem(cmd);
if (unlikely(r != 0))
goto out;
r = scst_alloc_space(cmd);
} else {
TRACE_MEM("%s", "data_buf_alloced set, returning");
}
check:
if (r != 0) {
if (scst_cmd_atomic(cmd)) {
TRACE_MEM("%s", "Atomic memory allocation failed, "
@@ -667,6 +694,12 @@ out_no_space:
cmd->state = SCST_CMD_STATE_DEV_DONE;
res = SCST_CMD_STATE_RES_CONT_SAME;
goto out;
out_error:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
cmd->state = SCST_CMD_STATE_DEV_DONE;
res = SCST_CMD_STATE_RES_CONT_SAME;
goto out;
}
void scst_restart_cmd(struct scst_cmd *cmd, int status, int pref_context)
@@ -898,7 +931,7 @@ void scst_proccess_redirect_cmd(struct scst_cmd *cmd, int context,
scst_check_retries(cmd->tgt);
spin_lock_irqsave(&cmd->cmd_lists->cmd_list_lock, flags);
TRACE_DBG("Adding cmd %p to active cmd list", cmd);
if (unlikely(cmd->head_of_queue))
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -975,6 +1008,24 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context)
return;
}
static void scst_inc_check_expected_sn(struct scst_cmd *cmd)
{
struct scst_cmd *c;
if (likely(cmd->queue_type != SCST_CMD_QUEUE_HEAD_OF_QUEUE))
scst_inc_expected_sn(cmd->tgt_dev, cmd->sn_slot);
c = scst_check_deferred_commands(cmd->tgt_dev);
if (c != NULL) {
unsigned long flags;
spin_lock_irqsave(&c->cmd_lists->cmd_list_lock, flags);
TRACE_SN("Adding cmd %p to active cmd list", c);
list_add_tail(&c->cmd_list_entry,
&c->cmd_lists->active_cmd_list);
wake_up(&c->cmd_lists->cmd_list_waitQ);
spin_unlock_irqrestore(&c->cmd_lists->cmd_list_lock, flags);
}
}
static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
const uint8_t *rq_sense, int rq_sense_len, int resid)
{
@@ -982,6 +1033,9 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
TRACE_ENTRY();
if (cmd->inc_expected_sn_on_done)
scst_inc_check_expected_sn(cmd);
cmd->status = result & 0xff;
cmd->msg_status = msg_byte(result);
cmd->host_status = host_byte(result);
@@ -1117,7 +1171,7 @@ static void scst_cmd_done(void *data, char *sense, int result, int resid)
if (cmd == NULL)
goto out;
scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid);
scst_do_cmd_done(cmd, result, sense, SCST_SENSE_BUFFERSIZE, resid);
cmd->state = SCST_CMD_STATE_DEV_DONE;
@@ -1136,6 +1190,9 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state)
scst_dec_on_dev_cmd(cmd, 0);
if (cmd->inc_expected_sn_on_done)
scst_inc_check_expected_sn(cmd);
if (next_state == SCST_CMD_STATE_DEFAULT)
next_state = SCST_CMD_STATE_DEV_DONE;
@@ -1740,7 +1797,7 @@ inc:
*/
tgt_dev->expected_sn++;
smp_mb(); /* write must be before def_cmd_count read */
TRACE_SN("Next expected_sn: %d", tgt_dev->expected_sn);
TRACE_SN("Next expected_sn: %ld", tgt_dev->expected_sn);
out:
return;
@@ -1751,7 +1808,7 @@ static int scst_send_to_midlev(struct scst_cmd *cmd)
int res, rc;
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
struct scst_device *dev = cmd->dev;
int expected_sn;
typeof(tgt_dev->expected_sn) expected_sn;
int count;
TRACE_ENTRY();
@@ -1780,7 +1837,7 @@ static int scst_send_to_midlev(struct scst_cmd *cmd)
EXTRACHECKS_BUG_ON(cmd->no_sn);
if (unlikely(cmd->head_of_queue)) {
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE)) {
/*
* W/o get() there will be a race, when cmd is executed and
* destroyed before "goto out_unplug"
@@ -1817,8 +1874,8 @@ static int scst_send_to_midlev(struct scst_cmd *cmd)
cmd->state = SCST_CMD_STATE_DEV_DONE;
res = SCST_CMD_STATE_RES_CONT_SAME;
} else {
TRACE_SN("Deferring cmd %p (sn=%d, "
"expected_sn=%d, hq_cmd_active=%d)", cmd,
TRACE_SN("Deferring cmd %p (sn=%ld, "
"expected_sn=%ld, hq_cmd_active=%d)", cmd,
cmd->sn, expected_sn,
test_bit(SCST_TGT_DEV_HQ_ACTIVE,
&tgt_dev->tgt_dev_flags));
@@ -1830,7 +1887,7 @@ static int scst_send_to_midlev(struct scst_cmd *cmd)
__scst_dec_on_dev_cmd(dev, cmd_blocking);
goto out_dec_cmd_count;
} else {
TRACE_SN("Somebody incremented expected_sn %d, "
TRACE_SN("Somebody incremented expected_sn %ld, "
"continuing", expected_sn);
tgt_dev->def_cmd_count--;
spin_unlock_irq(&tgt_dev->sn_lock);
@@ -1841,7 +1898,8 @@ exec:
count = 0;
while(1) {
atomic_t *slot = cmd->sn_slot;
int hq = cmd->head_of_queue;
int hq = (cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE);
int inc_expected_sn_on_done = cmd->inc_expected_sn_on_done;
rc = scst_do_send_to_midlev(cmd);
if (rc == SCST_EXEC_NEED_THREAD) {
TRACE_DBG("%s", "scst_do_send_to_midlev() requested "
@@ -1865,7 +1923,7 @@ exec:
sBUG_ON(rc != SCST_EXEC_COMPLETED);
/* !! At this point cmd can be already freed !! */
count++;
if (likely(!hq))
if ( !inc_expected_sn_on_done && likely(!hq))
scst_inc_expected_sn(tgt_dev, slot);
cmd = scst_check_deferred_commands(tgt_dev);
if (cmd == NULL)
@@ -2245,7 +2303,7 @@ static int scst_xmit_response(struct scst_cmd *cmd)
* commands.
*/
if (unlikely(!cmd->sent_to_midlev) && (cmd->tgt_dev != NULL)) {
TRACE_SN("cmd %p was not sent to mid-lev (sn %d)",
TRACE_SN("cmd %p was not sent to mid-lev (sn %ld)",
cmd, cmd->sn);
scst_unblock_deferred(cmd->tgt_dev, cmd);
cmd->sent_to_midlev = 1;
@@ -2438,7 +2496,7 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd)
if (likely(tgt_dev->num_free_sn_slots >= 0)) {
if (atomic_inc_return(tgt_dev->cur_sn_slot) == 1) {
tgt_dev->curr_sn++;
TRACE_SN("Incremented curr_sn %d",
TRACE_SN("Incremented curr_sn %ld",
tgt_dev->curr_sn);
}
cmd->sn_slot = tgt_dev->cur_sn_slot;
@@ -2481,7 +2539,6 @@ ordered:
case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
TRACE(TRACE_SCSI|TRACE_SCSI_SERIALIZING, "HQ cmd %p "
"(op %x)", cmd, cmd->cdb[0]);
cmd->head_of_queue = 1;
spin_lock_irqsave(&tgt_dev->sn_lock, flags);
/* Add in the head as required by SAM */
list_add(&cmd->sn_cmd_list_entry, &tgt_dev->hq_cmd_list);
@@ -2495,8 +2552,8 @@ ordered:
goto ordered;
}
TRACE_SN("cmd(%p)->sn: %d (tgt_dev %p, *cur_sn_slot %d, "
"num_free_sn_slots %d, prev_cmd_ordered %d, "
TRACE_SN("cmd(%p)->sn: %ld (tgt_dev %p, *cur_sn_slot %d, "
"num_free_sn_slots %d, prev_cmd_ordered %ld, "
"cur_sn_slot %d)", cmd, cmd->sn, tgt_dev,
atomic_read(tgt_dev->cur_sn_slot),
tgt_dev->num_free_sn_slots, tgt_dev->prev_cmd_ordered,
@@ -2651,7 +2708,7 @@ restart:
spin_lock(&cmd->cmd_lists->cmd_list_lock);
TRACE_MGMT_DBG("Adding cmd %p to active cmd list", cmd);
if (unlikely(cmd->head_of_queue))
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
list_add(&cmd->cmd_list_entry,
&cmd->cmd_lists->active_cmd_list);
else
@@ -2720,7 +2777,7 @@ int scst_init_cmd_thread(void *arg)
}
/* Called with no locks held */
static int scst_process_active_cmd(struct scst_cmd *cmd, int context)
void scst_process_active_cmd(struct scst_cmd *cmd, int context)
{
int res;
@@ -2813,8 +2870,8 @@ static int scst_process_active_cmd(struct scst_cmd *cmd, int context)
} else
sBUG();
TRACE_EXIT_RES(res);
return res;
TRACE_EXIT();
return;
}
/* Called under cmd_list_lock and IRQs disabled */
@@ -2829,17 +2886,12 @@ static void scst_do_job_active(struct list_head *cmd_list,
#endif
while (!list_empty(cmd_list)) {
int rc;
struct scst_cmd *cmd = list_entry(cmd_list->next, typeof(*cmd),
cmd_list_entry);
TRACE_DBG("Deleting cmd %p from active cmd list", cmd);
list_del(&cmd->cmd_list_entry);
spin_unlock_irq(cmd_list_lock);
rc = scst_process_active_cmd(cmd, context);
if (unlikely((rc != SCST_CMD_STATE_RES_CONT_NEXT) &&
(rc != SCST_CMD_STATE_RES_NEED_THREAD))) {
sBUG();
}
scst_process_active_cmd(cmd, context);
spin_lock_irq(cmd_list_lock);
}
@@ -3302,7 +3354,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
}
scst_cmd_get(cmd);
spin_unlock_irq(&sess->sess_list_lock);
TRACE(TRACE_MGMT, "Cmd %p for tag %d (sn %d) found, "
TRACE(TRACE_MGMT, "Cmd %p for tag %d (sn %ld) found, "
"aborting it", cmd, mcmd->tag, cmd->sn);
mcmd->cmd_to_abort = cmd;
scst_abort_cmd(cmd, mcmd, 0, 1);
@@ -3646,36 +3698,38 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
mcmd->sess->tgt->tgtt->name);
}
switch (mcmd->fn) {
case SCST_ABORT_TASK_SET:
case SCST_CLEAR_TASK_SET:
case SCST_LUN_RESET:
scst_unblock_dev(mcmd->mcmd_tgt_dev->dev);
break;
if (mcmd->mcmd_tgt_dev != NULL) {
switch (mcmd->fn) {
case SCST_ABORT_TASK_SET:
case SCST_CLEAR_TASK_SET:
case SCST_LUN_RESET:
scst_unblock_dev(mcmd->mcmd_tgt_dev->dev);
break;
case SCST_TARGET_RESET:
case SCST_ABORT_ALL_TASKS:
case SCST_NEXUS_LOSS:
down(&scst_mutex);
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
scst_unblock_dev(dev);
case SCST_TARGET_RESET:
case SCST_ABORT_ALL_TASKS:
case SCST_NEXUS_LOSS:
down(&scst_mutex);
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
scst_unblock_dev(dev);
}
up(&scst_mutex);
break;
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
down(&scst_mutex);
list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry) {
scst_unblock_dev(tgt_dev->dev);
}
up(&scst_mutex);
break;
case SCST_CLEAR_ACA:
default:
break;
}
up(&scst_mutex);
break;
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
down(&scst_mutex);
list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry) {
scst_unblock_dev(tgt_dev->dev);
}
up(&scst_mutex);
break;
case SCST_CLEAR_ACA:
default:
break;
}
mcmd->tgt_priv = NULL;