mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-22 21:21:28 +00:00
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:
@@ -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
|
||||
-----------
|
||||
|
||||
|
||||
@@ -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
243
scst/include/scst_const.h
Normal 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 */
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user