Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (62 commits) target: Fix compile warning w/ missing module.h include target: Remove legacy se_task->task_timer and associated logic target: Fix incorrect transport_sent usage target: re-use the command S/G list for single-task commands target: Fix BIDI t_task_cdb handling in transport_generic_new_cmd target: remove transport_allocate_tasks target: merge transport_new_cmd_obj into transport_generic_new_cmd target: remove the task_sg_bidi field se_task and pSCSI BIDI support target: transport_subsystem_check_init cleanups target: use a workqueue for I/O completions target: remove unused TRANSPORT_ states target: remove TRANSPORT_DEFERRED_CMD state target: remove the TRANSPORT_REMOVE state target: move depth_left manipulation out of transport_generic_request_failure target: stop task timers earlier target: remove TF_TIMER_STOP target: factor some duplicate code for stopping a task target: fix list walking in transport_free_dev_tasks target: use transport_cmd_check_stop_to_fabric consistently target: do not pass the queue object to transport_remove_cmd_from_queue ...
This commit is contained in:
commit
7c1953ddb6
|
@ -6,7 +6,6 @@ target_core_mod-y := target_core_configfs.o \
|
||||||
target_core_hba.o \
|
target_core_hba.o \
|
||||||
target_core_pr.o \
|
target_core_pr.o \
|
||||||
target_core_alua.o \
|
target_core_alua.o \
|
||||||
target_core_scdb.o \
|
|
||||||
target_core_tmr.o \
|
target_core_tmr.o \
|
||||||
target_core_tpg.o \
|
target_core_tpg.o \
|
||||||
target_core_transport.o \
|
target_core_transport.o \
|
||||||
|
|
|
@ -765,7 +765,7 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
|
||||||
u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
|
u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
|
||||||
cmd->se_cmd.t_data_nents;
|
cmd->se_cmd.t_data_nents;
|
||||||
|
|
||||||
iov_count += TRANSPORT_IOV_DATA_BUFFER;
|
iov_count += ISCSI_IOV_DATA_BUFFER;
|
||||||
|
|
||||||
cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
|
cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
|
||||||
if (!cmd->iov_data) {
|
if (!cmd->iov_data) {
|
||||||
|
@ -3538,16 +3538,8 @@ get_immediate:
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
/*
|
|
||||||
* Determine if a struct se_cmd is assoicated with
|
iscsit_free_cmd(cmd);
|
||||||
* this struct iscsi_cmd.
|
|
||||||
*/
|
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
|
|
||||||
!(cmd->tmr_req))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
transport_generic_free_cmd(&cmd->se_cmd,
|
|
||||||
1, 0);
|
|
||||||
goto get_immediate;
|
goto get_immediate;
|
||||||
case ISTATE_SEND_NOPIN_WANT_RESPONSE:
|
case ISTATE_SEND_NOPIN_WANT_RESPONSE:
|
||||||
spin_unlock_bh(&cmd->istate_lock);
|
spin_unlock_bh(&cmd->istate_lock);
|
||||||
|
@ -3940,7 +3932,6 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
|
||||||
{
|
{
|
||||||
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
|
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
|
||||||
struct iscsi_session *sess = conn->sess;
|
struct iscsi_session *sess = conn->sess;
|
||||||
struct se_cmd *se_cmd;
|
|
||||||
/*
|
/*
|
||||||
* We expect this function to only ever be called from either RX or TX
|
* We expect this function to only ever be called from either RX or TX
|
||||||
* thread context via iscsit_close_connection() once the other context
|
* thread context via iscsit_close_connection() once the other context
|
||||||
|
@ -3948,35 +3939,13 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
|
||||||
*/
|
*/
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
|
list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) {
|
|
||||||
|
|
||||||
list_del(&cmd->i_list);
|
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
|
||||||
iscsit_increment_maxcmdsn(cmd, sess);
|
|
||||||
se_cmd = &cmd->se_cmd;
|
|
||||||
/*
|
|
||||||
* Special cases for active iSCSI TMR, and
|
|
||||||
* transport_lookup_cmd_lun() failing from
|
|
||||||
* iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd().
|
|
||||||
*/
|
|
||||||
if (cmd->tmr_req && se_cmd->transport_wait_for_tasks)
|
|
||||||
se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
|
|
||||||
else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)
|
|
||||||
transport_release_cmd(se_cmd);
|
|
||||||
else
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
|
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
|
|
||||||
iscsit_increment_maxcmdsn(cmd, sess);
|
iscsit_increment_maxcmdsn(cmd, sess);
|
||||||
se_cmd = &cmd->se_cmd;
|
|
||||||
|
|
||||||
if (se_cmd->transport_wait_for_tasks)
|
iscsit_free_cmd(cmd);
|
||||||
se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
|
|
||||||
|
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
@ -27,40 +28,11 @@
|
||||||
#include "iscsi_target_nego.h"
|
#include "iscsi_target_nego.h"
|
||||||
#include "iscsi_target_auth.h"
|
#include "iscsi_target_auth.h"
|
||||||
|
|
||||||
static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2])
|
|
||||||
{
|
|
||||||
unsigned char result = 0;
|
|
||||||
/*
|
|
||||||
* MSB
|
|
||||||
*/
|
|
||||||
if ((val[0] >= 'a') && (val[0] <= 'f'))
|
|
||||||
result = ((val[0] - 'a' + 10) & 0xf) << 4;
|
|
||||||
else
|
|
||||||
if ((val[0] >= 'A') && (val[0] <= 'F'))
|
|
||||||
result = ((val[0] - 'A' + 10) & 0xf) << 4;
|
|
||||||
else /* digit */
|
|
||||||
result = ((val[0] - '0') & 0xf) << 4;
|
|
||||||
/*
|
|
||||||
* LSB
|
|
||||||
*/
|
|
||||||
if ((val[1] >= 'a') && (val[1] <= 'f'))
|
|
||||||
result |= ((val[1] - 'a' + 10) & 0xf);
|
|
||||||
else
|
|
||||||
if ((val[1] >= 'A') && (val[1] <= 'F'))
|
|
||||||
result |= ((val[1] - 'A' + 10) & 0xf);
|
|
||||||
else /* digit */
|
|
||||||
result |= ((val[1] - '0') & 0xf);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
|
static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
|
||||||
{
|
{
|
||||||
int i, j = 0;
|
int j = DIV_ROUND_UP(len, 2);
|
||||||
|
|
||||||
for (i = 0; i < len; i += 2) {
|
hex2bin(dst, src, j);
|
||||||
dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[j] = '\0';
|
dst[j] = '\0';
|
||||||
return j;
|
return j;
|
||||||
|
|
|
@ -57,6 +57,9 @@
|
||||||
#define TA_PROD_MODE_WRITE_PROTECT 0
|
#define TA_PROD_MODE_WRITE_PROTECT 0
|
||||||
#define TA_CACHE_CORE_NPS 0
|
#define TA_CACHE_CORE_NPS 0
|
||||||
|
|
||||||
|
|
||||||
|
#define ISCSI_IOV_DATA_BUFFER 5
|
||||||
|
|
||||||
enum tpg_np_network_transport_table {
|
enum tpg_np_network_transport_table {
|
||||||
ISCSI_TCP = 0,
|
ISCSI_TCP = 0,
|
||||||
ISCSI_SCTP_TCP = 1,
|
ISCSI_SCTP_TCP = 1,
|
||||||
|
@ -425,7 +428,6 @@ struct iscsi_cmd {
|
||||||
/* Number of times struct iscsi_cmd is present in immediate queue */
|
/* Number of times struct iscsi_cmd is present in immediate queue */
|
||||||
atomic_t immed_queue_count;
|
atomic_t immed_queue_count;
|
||||||
atomic_t response_queue_count;
|
atomic_t response_queue_count;
|
||||||
atomic_t transport_sent;
|
|
||||||
spinlock_t datain_lock;
|
spinlock_t datain_lock;
|
||||||
spinlock_t dataout_timeout_lock;
|
spinlock_t dataout_timeout_lock;
|
||||||
/* spinlock for protecting struct iscsi_cmd->i_state */
|
/* spinlock for protecting struct iscsi_cmd->i_state */
|
||||||
|
|
|
@ -143,12 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
cmd->conn = NULL;
|
cmd->conn = NULL;
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
iscsit_free_cmd(cmd);
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 1);
|
|
||||||
spin_lock(&cr->conn_recovery_cmd_lock);
|
spin_lock(&cr->conn_recovery_cmd_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
|
@ -170,12 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
cmd->conn = NULL;
|
cmd->conn = NULL;
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
iscsit_free_cmd(cmd);
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 1);
|
|
||||||
spin_lock(&cr->conn_recovery_cmd_lock);
|
spin_lock(&cr->conn_recovery_cmd_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
|
@ -260,12 +250,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
|
||||||
iscsit_remove_cmd_from_connection_recovery(cmd, sess);
|
iscsit_remove_cmd_from_connection_recovery(cmd, sess);
|
||||||
|
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
iscsit_free_cmd(cmd);
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 0);
|
|
||||||
spin_lock(&cr->conn_recovery_cmd_lock);
|
spin_lock(&cr->conn_recovery_cmd_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&cr->conn_recovery_cmd_lock);
|
spin_unlock(&cr->conn_recovery_cmd_lock);
|
||||||
|
@ -319,12 +304,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
|
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
iscsit_free_cmd(cmd);
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 1);
|
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
|
@ -377,13 +357,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
|
||||||
|
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
|
iscsit_free_cmd(cmd);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 0);
|
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -403,13 +377,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
|
||||||
(cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
|
(cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
|
||||||
list_del(&cmd->i_list);
|
list_del(&cmd->i_list);
|
||||||
spin_unlock_bh(&conn->cmd_lock);
|
spin_unlock_bh(&conn->cmd_lock);
|
||||||
|
iscsit_free_cmd(cmd);
|
||||||
if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
|
|
||||||
!(cmd->se_cmd.transport_wait_for_tasks))
|
|
||||||
iscsit_release_cmd(cmd);
|
|
||||||
else
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(
|
|
||||||
&cmd->se_cmd, 1, 1);
|
|
||||||
spin_lock_bh(&conn->cmd_lock);
|
spin_lock_bh(&conn->cmd_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -434,10 +402,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
|
||||||
|
|
||||||
iscsit_free_all_datain_reqs(cmd);
|
iscsit_free_all_datain_reqs(cmd);
|
||||||
|
|
||||||
if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
|
transport_wait_for_tasks(&cmd->se_cmd);
|
||||||
cmd->se_cmd.transport_wait_for_tasks)
|
|
||||||
cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd,
|
|
||||||
0, 0);
|
|
||||||
/*
|
/*
|
||||||
* Add the struct iscsi_cmd to the connection recovery cmd list
|
* Add the struct iscsi_cmd to the connection recovery cmd list
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -250,7 +250,7 @@ static int iscsit_task_reassign_complete_write(
|
||||||
* so if we have received all DataOUT we can safety ignore Initiator.
|
* so if we have received all DataOUT we can safety ignore Initiator.
|
||||||
*/
|
*/
|
||||||
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
|
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
|
||||||
if (!atomic_read(&cmd->transport_sent)) {
|
if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
|
||||||
pr_debug("WRITE ITT: 0x%08x: t_state: %d"
|
pr_debug("WRITE ITT: 0x%08x: t_state: %d"
|
||||||
" never sent to transport\n",
|
" never sent to transport\n",
|
||||||
cmd->init_task_tag, cmd->se_cmd.t_state);
|
cmd->init_task_tag, cmd->se_cmd.t_state);
|
||||||
|
@ -314,11 +314,11 @@ static int iscsit_task_reassign_complete_read(
|
||||||
cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
|
cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!atomic_read(&cmd->transport_sent)) {
|
if (!atomic_read(&cmd->se_cmd.t_transport_sent)) {
|
||||||
pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
|
pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
|
||||||
" transport\n", cmd->init_task_tag,
|
" transport\n", cmd->init_task_tag,
|
||||||
cmd->se_cmd.t_state);
|
cmd->se_cmd.t_state);
|
||||||
transport_generic_handle_cdb(se_cmd);
|
transport_handle_cdb_direct(se_cmd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,7 +289,8 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
|
||||||
}
|
}
|
||||||
|
|
||||||
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
|
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
|
||||||
(void *)cmd->tmr_req, tcm_function);
|
(void *)cmd->tmr_req, tcm_function,
|
||||||
|
GFP_KERNEL);
|
||||||
if (!se_cmd->se_tmr_req)
|
if (!se_cmd->se_tmr_req)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -839,6 +840,23 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
|
||||||
kmem_cache_free(lio_cmd_cache, cmd);
|
kmem_cache_free(lio_cmd_cache, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iscsit_free_cmd(struct iscsi_cmd *cmd)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Determine if a struct se_cmd is assoicated with
|
||||||
|
* this struct iscsi_cmd.
|
||||||
|
*/
|
||||||
|
switch (cmd->iscsi_opcode) {
|
||||||
|
case ISCSI_OP_SCSI_CMD:
|
||||||
|
case ISCSI_OP_SCSI_TMFUNC:
|
||||||
|
transport_generic_free_cmd(&cmd->se_cmd, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
iscsit_release_cmd(cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int iscsit_check_session_usage_count(struct iscsi_session *sess)
|
int iscsit_check_session_usage_count(struct iscsi_session *sess)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&sess->session_usage_lock);
|
spin_lock_bh(&sess->session_usage_lock);
|
||||||
|
|
|
@ -30,6 +30,7 @@ extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_c
|
||||||
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
|
extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
|
||||||
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
|
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
|
||||||
extern void iscsit_release_cmd(struct iscsi_cmd *);
|
extern void iscsit_release_cmd(struct iscsi_cmd *);
|
||||||
|
extern void iscsit_free_cmd(struct iscsi_cmd *);
|
||||||
extern int iscsit_check_session_usage_count(struct iscsi_session *);
|
extern int iscsit_check_session_usage_count(struct iscsi_session *);
|
||||||
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
|
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
|
||||||
extern void iscsit_inc_session_usage_count(struct iscsi_session *);
|
extern void iscsit_inc_session_usage_count(struct iscsi_session *);
|
||||||
|
|
|
@ -200,7 +200,7 @@ static void tcm_loop_check_stop_free(struct se_cmd *se_cmd)
|
||||||
* Release the struct se_cmd, which will make a callback to release
|
* Release the struct se_cmd, which will make a callback to release
|
||||||
* struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
|
* struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
|
||||||
*/
|
*/
|
||||||
transport_generic_free_cmd(se_cmd, 0, 0);
|
transport_generic_free_cmd(se_cmd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
|
static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
|
||||||
|
@ -290,6 +290,15 @@ static int tcm_loop_queuecommand(
|
||||||
*/
|
*/
|
||||||
tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
|
tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
|
||||||
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
|
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
|
||||||
|
/*
|
||||||
|
* Ensure that this tl_tpg reference from the incoming sc->device->id
|
||||||
|
* has already been configured via tcm_loop_make_naa_tpg().
|
||||||
|
*/
|
||||||
|
if (!tl_tpg->tl_hba) {
|
||||||
|
set_host_byte(sc, DID_NO_CONNECT);
|
||||||
|
sc->scsi_done(sc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
se_tpg = &tl_tpg->tl_se_tpg;
|
se_tpg = &tl_tpg->tl_se_tpg;
|
||||||
/*
|
/*
|
||||||
* Determine the SAM Task Attribute and allocate tl_cmd and
|
* Determine the SAM Task Attribute and allocate tl_cmd and
|
||||||
|
@ -366,7 +375,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
|
||||||
* Allocate the LUN_RESET TMR
|
* Allocate the LUN_RESET TMR
|
||||||
*/
|
*/
|
||||||
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
|
se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, tl_tmr,
|
||||||
TMR_LUN_RESET);
|
TMR_LUN_RESET, GFP_KERNEL);
|
||||||
if (IS_ERR(se_cmd->se_tmr_req))
|
if (IS_ERR(se_cmd->se_tmr_req))
|
||||||
goto release;
|
goto release;
|
||||||
/*
|
/*
|
||||||
|
@ -388,7 +397,7 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
|
||||||
SUCCESS : FAILED;
|
SUCCESS : FAILED;
|
||||||
release:
|
release:
|
||||||
if (se_cmd)
|
if (se_cmd)
|
||||||
transport_generic_free_cmd(se_cmd, 1, 0);
|
transport_generic_free_cmd(se_cmd, 1);
|
||||||
else
|
else
|
||||||
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
|
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
|
||||||
kfree(tl_tmr);
|
kfree(tl_tmr);
|
||||||
|
@ -1245,6 +1254,9 @@ void tcm_loop_drop_naa_tpg(
|
||||||
*/
|
*/
|
||||||
core_tpg_deregister(se_tpg);
|
core_tpg_deregister(se_tpg);
|
||||||
|
|
||||||
|
tl_tpg->tl_hba = NULL;
|
||||||
|
tl_tpg->tl_tpgt = 0;
|
||||||
|
|
||||||
pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s"
|
pr_debug("TCM_Loop_ConfigFS: Deallocated Emulated %s"
|
||||||
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
|
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
|
||||||
config_item_name(&wwn->wwn_group.cg_item), tpgt);
|
config_item_name(&wwn->wwn_group.cg_item), tpgt);
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/configfs.h>
|
#include <linux/configfs.h>
|
||||||
|
@ -68,12 +67,32 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
|
u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
|
||||||
Target port group descriptor */
|
Target port group descriptor */
|
||||||
|
/*
|
||||||
|
* Need at least 4 bytes of response data or else we can't
|
||||||
|
* even fit the return data length.
|
||||||
|
*/
|
||||||
|
if (cmd->data_length < 4) {
|
||||||
|
pr_warn("REPORT TARGET PORT GROUPS allocation length %u"
|
||||||
|
" too small\n", cmd->data_length);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
buf = transport_kmap_first_data_page(cmd);
|
buf = transport_kmap_first_data_page(cmd);
|
||||||
|
|
||||||
spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
|
spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
|
||||||
list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list,
|
list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list,
|
||||||
tg_pt_gp_list) {
|
tg_pt_gp_list) {
|
||||||
|
/*
|
||||||
|
* Check if the Target port group and Target port descriptor list
|
||||||
|
* based on tg_pt_gp_members count will fit into the response payload.
|
||||||
|
* Otherwise, bump rd_len to let the initiator know we have exceeded
|
||||||
|
* the allocation length and the response is truncated.
|
||||||
|
*/
|
||||||
|
if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) >
|
||||||
|
cmd->data_length) {
|
||||||
|
rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* PREF: Preferred target port bit, determine if this
|
* PREF: Preferred target port bit, determine if this
|
||||||
* bit should be set for port group.
|
* bit should be set for port group.
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/module.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
|
|
||||||
|
@ -156,11 +156,12 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off)
|
target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
|
||||||
{
|
{
|
||||||
unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
|
unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
|
||||||
unsigned char *buf = buf_off;
|
int cnt;
|
||||||
int cnt = 0, next = 1;
|
bool next = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
|
* Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on
|
||||||
* byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
|
* byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field
|
||||||
|
@ -169,19 +170,18 @@ target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_of
|
||||||
* NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
|
* NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure
|
||||||
* per device uniqeness.
|
* per device uniqeness.
|
||||||
*/
|
*/
|
||||||
while (*p != '\0') {
|
for (cnt = 0; *p && cnt < 13; p++) {
|
||||||
if (cnt >= 13)
|
int val = hex_to_bin(*p);
|
||||||
break;
|
|
||||||
if (!isxdigit(*p)) {
|
if (val < 0)
|
||||||
p++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (next != 0) {
|
if (next) {
|
||||||
buf[cnt++] |= hex_to_bin(*p++);
|
next = false;
|
||||||
next = 0;
|
buf[cnt++] |= val;
|
||||||
} else {
|
} else {
|
||||||
buf[cnt] = hex_to_bin(*p++) << 4;
|
next = true;
|
||||||
next = 1;
|
buf[cnt] = val << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1266,3 +1266,52 @@ transport_emulate_control_cdb(struct se_task *task)
|
||||||
|
|
||||||
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a CDB into @cdb that is based on the one the intiator sent us,
|
||||||
|
* but updated to only cover the sectors that the current task handles.
|
||||||
|
*/
|
||||||
|
void target_get_task_cdb(struct se_task *task, unsigned char *cdb)
|
||||||
|
{
|
||||||
|
struct se_cmd *cmd = task->task_se_cmd;
|
||||||
|
unsigned int cdb_len = scsi_command_size(cmd->t_task_cdb);
|
||||||
|
|
||||||
|
memcpy(cdb, cmd->t_task_cdb, cdb_len);
|
||||||
|
if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
|
||||||
|
unsigned long long lba = task->task_lba;
|
||||||
|
u32 sectors = task->task_sectors;
|
||||||
|
|
||||||
|
switch (cdb_len) {
|
||||||
|
case 6:
|
||||||
|
/* 21-bit LBA and 8-bit sectors */
|
||||||
|
cdb[1] = (lba >> 16) & 0x1f;
|
||||||
|
cdb[2] = (lba >> 8) & 0xff;
|
||||||
|
cdb[3] = lba & 0xff;
|
||||||
|
cdb[4] = sectors & 0xff;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
/* 32-bit LBA and 16-bit sectors */
|
||||||
|
put_unaligned_be32(lba, &cdb[2]);
|
||||||
|
put_unaligned_be16(sectors, &cdb[7]);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
/* 32-bit LBA and 32-bit sectors */
|
||||||
|
put_unaligned_be32(lba, &cdb[2]);
|
||||||
|
put_unaligned_be32(sectors, &cdb[6]);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
/* 64-bit LBA and 32-bit sectors */
|
||||||
|
put_unaligned_be64(lba, &cdb[2]);
|
||||||
|
put_unaligned_be32(sectors, &cdb[10]);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
/* 64-bit LBA and 32-bit sectors, extended CDB */
|
||||||
|
put_unaligned_be64(lba, &cdb[12]);
|
||||||
|
put_unaligned_be32(sectors, &cdb[28]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(target_get_task_cdb);
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -132,14 +131,6 @@ static struct config_group *target_core_register_fabric(
|
||||||
|
|
||||||
pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:"
|
pr_debug("Target_Core_ConfigFS: REGISTER -> group: %p name:"
|
||||||
" %s\n", group, name);
|
" %s\n", group, name);
|
||||||
/*
|
|
||||||
* Ensure that TCM subsystem plugins are loaded at this point for
|
|
||||||
* using the RAMDISK_DR virtual LUN 0 and all other struct se_port
|
|
||||||
* LUN symlinks.
|
|
||||||
*/
|
|
||||||
if (transport_subsystem_check_init() < 0)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Below are some hardcoded request_module() calls to automatically
|
* Below are some hardcoded request_module() calls to automatically
|
||||||
* local fabric modules when the following is called:
|
* local fabric modules when the following is called:
|
||||||
|
@ -725,9 +716,6 @@ SE_DEV_ATTR_RO(hw_queue_depth);
|
||||||
DEF_DEV_ATTRIB(queue_depth);
|
DEF_DEV_ATTRIB(queue_depth);
|
||||||
SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
|
SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
|
||||||
|
|
||||||
DEF_DEV_ATTRIB(task_timeout);
|
|
||||||
SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);
|
|
||||||
|
|
||||||
DEF_DEV_ATTRIB(max_unmap_lba_count);
|
DEF_DEV_ATTRIB(max_unmap_lba_count);
|
||||||
SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
|
SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
|
||||||
|
|
||||||
|
@ -761,7 +749,6 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
|
||||||
&target_core_dev_attrib_optimal_sectors.attr,
|
&target_core_dev_attrib_optimal_sectors.attr,
|
||||||
&target_core_dev_attrib_hw_queue_depth.attr,
|
&target_core_dev_attrib_hw_queue_depth.attr,
|
||||||
&target_core_dev_attrib_queue_depth.attr,
|
&target_core_dev_attrib_queue_depth.attr,
|
||||||
&target_core_dev_attrib_task_timeout.attr,
|
|
||||||
&target_core_dev_attrib_max_unmap_lba_count.attr,
|
&target_core_dev_attrib_max_unmap_lba_count.attr,
|
||||||
&target_core_dev_attrib_max_unmap_block_desc_count.attr,
|
&target_core_dev_attrib_max_unmap_block_desc_count.attr,
|
||||||
&target_core_dev_attrib_unmap_granularity.attr,
|
&target_core_dev_attrib_unmap_granularity.attr,
|
||||||
|
@ -3080,8 +3067,7 @@ static struct config_group *target_core_call_addhbatotarget(
|
||||||
/*
|
/*
|
||||||
* Load up TCM subsystem plugins if they have not already been loaded.
|
* Load up TCM subsystem plugins if they have not already been loaded.
|
||||||
*/
|
*/
|
||||||
if (transport_subsystem_check_init() < 0)
|
transport_subsystem_check_init();
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
|
hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
|
||||||
if (IS_ERR(hba))
|
if (IS_ERR(hba))
|
||||||
|
|
|
@ -914,21 +914,6 @@ void se_dev_set_default_attribs(
|
||||||
dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth;
|
dev->se_sub_dev->se_dev_attrib.queue_depth = dev_limits->queue_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
|
|
||||||
{
|
|
||||||
if (task_timeout > DA_TASK_TIMEOUT_MAX) {
|
|
||||||
pr_err("dev[%p]: Passed task_timeout: %u larger then"
|
|
||||||
" DA_TASK_TIMEOUT_MAX\n", dev, task_timeout);
|
|
||||||
return -EINVAL;
|
|
||||||
} else {
|
|
||||||
dev->se_sub_dev->se_dev_attrib.task_timeout = task_timeout;
|
|
||||||
pr_debug("dev[%p]: Set SE Device task_timeout: %u\n",
|
|
||||||
dev, task_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int se_dev_set_max_unmap_lba_count(
|
int se_dev_set_max_unmap_lba_count(
|
||||||
struct se_device *dev,
|
struct se_device *dev,
|
||||||
u32 max_unmap_lba_count)
|
u32 max_unmap_lba_count)
|
||||||
|
@ -972,36 +957,24 @@ int se_dev_set_unmap_granularity_alignment(
|
||||||
|
|
||||||
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
|
int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
|
||||||
{
|
{
|
||||||
if ((flag != 0) && (flag != 1)) {
|
if (flag != 0 && flag != 1) {
|
||||||
pr_err("Illegal value %d\n", flag);
|
pr_err("Illegal value %d\n", flag);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (dev->transport->dpo_emulated == NULL) {
|
|
||||||
pr_err("dev->transport->dpo_emulated is NULL\n");
|
pr_err("dpo_emulated not supported\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
if (dev->transport->dpo_emulated(dev) == 0) {
|
|
||||||
pr_err("dev->transport->dpo_emulated not supported\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
dev->se_sub_dev->se_dev_attrib.emulate_dpo = flag;
|
|
||||||
pr_debug("dev[%p]: SE Device Page Out (DPO) Emulation"
|
|
||||||
" bit: %d\n", dev, dev->se_sub_dev->se_dev_attrib.emulate_dpo);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
|
int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
|
||||||
{
|
{
|
||||||
if ((flag != 0) && (flag != 1)) {
|
if (flag != 0 && flag != 1) {
|
||||||
pr_err("Illegal value %d\n", flag);
|
pr_err("Illegal value %d\n", flag);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (dev->transport->fua_write_emulated == NULL) {
|
|
||||||
pr_err("dev->transport->fua_write_emulated is NULL\n");
|
if (dev->transport->fua_write_emulated == 0) {
|
||||||
return -EINVAL;
|
pr_err("fua_write_emulated not supported\n");
|
||||||
}
|
|
||||||
if (dev->transport->fua_write_emulated(dev) == 0) {
|
|
||||||
pr_err("dev->transport->fua_write_emulated not supported\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
|
dev->se_sub_dev->se_dev_attrib.emulate_fua_write = flag;
|
||||||
|
@ -1012,36 +985,23 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
|
||||||
|
|
||||||
int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
|
int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
|
||||||
{
|
{
|
||||||
if ((flag != 0) && (flag != 1)) {
|
if (flag != 0 && flag != 1) {
|
||||||
pr_err("Illegal value %d\n", flag);
|
pr_err("Illegal value %d\n", flag);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (dev->transport->fua_read_emulated == NULL) {
|
|
||||||
pr_err("dev->transport->fua_read_emulated is NULL\n");
|
pr_err("ua read emulated not supported\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
if (dev->transport->fua_read_emulated(dev) == 0) {
|
|
||||||
pr_err("dev->transport->fua_read_emulated not supported\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
dev->se_sub_dev->se_dev_attrib.emulate_fua_read = flag;
|
|
||||||
pr_debug("dev[%p]: SE Device Forced Unit Access READs: %d\n",
|
|
||||||
dev, dev->se_sub_dev->se_dev_attrib.emulate_fua_read);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
|
int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
|
||||||
{
|
{
|
||||||
if ((flag != 0) && (flag != 1)) {
|
if (flag != 0 && flag != 1) {
|
||||||
pr_err("Illegal value %d\n", flag);
|
pr_err("Illegal value %d\n", flag);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (dev->transport->write_cache_emulated == NULL) {
|
if (dev->transport->write_cache_emulated == 0) {
|
||||||
pr_err("dev->transport->write_cache_emulated is NULL\n");
|
pr_err("write_cache_emulated not supported\n");
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (dev->transport->write_cache_emulated(dev) == 0) {
|
|
||||||
pr_err("dev->transport->write_cache_emulated not supported\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
|
dev->se_sub_dev->se_dev_attrib.emulate_write_cache = flag;
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
@ -273,13 +272,14 @@ fd_alloc_task(unsigned char *cdb)
|
||||||
static int fd_do_readv(struct se_task *task)
|
static int fd_do_readv(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct fd_request *req = FILE_REQ(task);
|
struct fd_request *req = FILE_REQ(task);
|
||||||
struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
|
struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
|
||||||
|
struct fd_dev *dev = se_dev->dev_ptr;
|
||||||
struct file *fd = dev->fd_file;
|
struct file *fd = dev->fd_file;
|
||||||
struct scatterlist *sg = task->task_sg;
|
struct scatterlist *sg = task->task_sg;
|
||||||
struct iovec *iov;
|
struct iovec *iov;
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
loff_t pos = (task->task_lba *
|
loff_t pos = (task->task_lba *
|
||||||
task->se_dev->se_sub_dev->se_dev_attrib.block_size);
|
se_dev->se_sub_dev->se_dev_attrib.block_size);
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
|
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
|
||||||
|
@ -325,13 +325,14 @@ static int fd_do_readv(struct se_task *task)
|
||||||
static int fd_do_writev(struct se_task *task)
|
static int fd_do_writev(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct fd_request *req = FILE_REQ(task);
|
struct fd_request *req = FILE_REQ(task);
|
||||||
struct fd_dev *dev = req->fd_task.se_dev->dev_ptr;
|
struct se_device *se_dev = req->fd_task.task_se_cmd->se_dev;
|
||||||
|
struct fd_dev *dev = se_dev->dev_ptr;
|
||||||
struct file *fd = dev->fd_file;
|
struct file *fd = dev->fd_file;
|
||||||
struct scatterlist *sg = task->task_sg;
|
struct scatterlist *sg = task->task_sg;
|
||||||
struct iovec *iov;
|
struct iovec *iov;
|
||||||
mm_segment_t old_fs;
|
mm_segment_t old_fs;
|
||||||
loff_t pos = (task->task_lba *
|
loff_t pos = (task->task_lba *
|
||||||
task->se_dev->se_sub_dev->se_dev_attrib.block_size);
|
se_dev->se_sub_dev->se_dev_attrib.block_size);
|
||||||
int ret, i = 0;
|
int ret, i = 0;
|
||||||
|
|
||||||
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
|
iov = kzalloc(sizeof(struct iovec) * task->task_sg_nents, GFP_KERNEL);
|
||||||
|
@ -398,33 +399,6 @@ static void fd_emulate_sync_cache(struct se_task *task)
|
||||||
transport_complete_sync_cache(cmd, ret == 0);
|
transport_complete_sync_cache(cmd, ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Tell TCM Core that we are capable of WriteCache emulation for
|
|
||||||
* an underlying struct se_device.
|
|
||||||
*/
|
|
||||||
static int fd_emulated_write_cache(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fd_emulated_dpo(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
|
|
||||||
* for TYPE_DISK.
|
|
||||||
*/
|
|
||||||
static int fd_emulated_fua_write(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fd_emulated_fua_read(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WRITE Force Unit Access (FUA) emulation on a per struct se_task
|
* WRITE Force Unit Access (FUA) emulation on a per struct se_task
|
||||||
* LBA range basis..
|
* LBA range basis..
|
||||||
|
@ -608,17 +582,6 @@ static ssize_t fd_show_configfs_dev_params(
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fd_get_cdb(): (Part of se_subsystem_api_t template)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static unsigned char *fd_get_cdb(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct fd_request *req = FILE_REQ(task);
|
|
||||||
|
|
||||||
return req->fd_scsi_cdb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
|
/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -650,15 +613,13 @@ static struct se_subsystem_api fileio_template = {
|
||||||
.name = "fileio",
|
.name = "fileio",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
|
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
|
||||||
|
.write_cache_emulated = 1,
|
||||||
|
.fua_write_emulated = 1,
|
||||||
.attach_hba = fd_attach_hba,
|
.attach_hba = fd_attach_hba,
|
||||||
.detach_hba = fd_detach_hba,
|
.detach_hba = fd_detach_hba,
|
||||||
.allocate_virtdevice = fd_allocate_virtdevice,
|
.allocate_virtdevice = fd_allocate_virtdevice,
|
||||||
.create_virtdevice = fd_create_virtdevice,
|
.create_virtdevice = fd_create_virtdevice,
|
||||||
.free_device = fd_free_device,
|
.free_device = fd_free_device,
|
||||||
.dpo_emulated = fd_emulated_dpo,
|
|
||||||
.fua_write_emulated = fd_emulated_fua_write,
|
|
||||||
.fua_read_emulated = fd_emulated_fua_read,
|
|
||||||
.write_cache_emulated = fd_emulated_write_cache,
|
|
||||||
.alloc_task = fd_alloc_task,
|
.alloc_task = fd_alloc_task,
|
||||||
.do_task = fd_do_task,
|
.do_task = fd_do_task,
|
||||||
.do_sync_cache = fd_emulate_sync_cache,
|
.do_sync_cache = fd_emulate_sync_cache,
|
||||||
|
@ -666,7 +627,6 @@ static struct se_subsystem_api fileio_template = {
|
||||||
.check_configfs_dev_params = fd_check_configfs_dev_params,
|
.check_configfs_dev_params = fd_check_configfs_dev_params,
|
||||||
.set_configfs_dev_params = fd_set_configfs_dev_params,
|
.set_configfs_dev_params = fd_set_configfs_dev_params,
|
||||||
.show_configfs_dev_params = fd_show_configfs_dev_params,
|
.show_configfs_dev_params = fd_show_configfs_dev_params,
|
||||||
.get_cdb = fd_get_cdb,
|
|
||||||
.get_device_rev = fd_get_device_rev,
|
.get_device_rev = fd_get_device_rev,
|
||||||
.get_device_type = fd_get_device_type,
|
.get_device_type = fd_get_device_type,
|
||||||
.get_blocks = fd_get_blocks,
|
.get_blocks = fd_get_blocks,
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
|
|
||||||
struct fd_request {
|
struct fd_request {
|
||||||
struct se_task fd_task;
|
struct se_task fd_task;
|
||||||
/* SCSI CDB from iSCSI Command PDU */
|
};
|
||||||
unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
|
|
||||||
} ____cacheline_aligned;
|
|
||||||
|
|
||||||
#define FBDF_HAS_PATH 0x01
|
#define FBDF_HAS_PATH 0x01
|
||||||
#define FBDF_HAS_SIZE 0x02
|
#define FBDF_HAS_SIZE 0x02
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
@ -314,104 +313,42 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(
|
||||||
return blocks_long;
|
return blocks_long;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iblock_end_io_flush(struct bio *bio, int err)
|
||||||
|
{
|
||||||
|
struct se_cmd *cmd = bio->bi_private;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
pr_err("IBLOCK: cache flush failed: %d\n", err);
|
||||||
|
|
||||||
|
if (cmd)
|
||||||
|
transport_complete_sync_cache(cmd, err == 0);
|
||||||
|
bio_put(bio);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emulate SYCHRONIZE_CACHE_*
|
* Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must
|
||||||
|
* always flush the whole cache.
|
||||||
*/
|
*/
|
||||||
static void iblock_emulate_sync_cache(struct se_task *task)
|
static void iblock_emulate_sync_cache(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct se_cmd *cmd = task->task_se_cmd;
|
struct se_cmd *cmd = task->task_se_cmd;
|
||||||
struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
|
struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
|
||||||
int immed = (cmd->t_task_cdb[1] & 0x2);
|
int immed = (cmd->t_task_cdb[1] & 0x2);
|
||||||
sector_t error_sector;
|
struct bio *bio;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the Immediate bit is set, queue up the GOOD response
|
* If the Immediate bit is set, queue up the GOOD response
|
||||||
* for this SYNCHRONIZE_CACHE op
|
* for this SYNCHRONIZE_CACHE op.
|
||||||
*/
|
*/
|
||||||
if (immed)
|
if (immed)
|
||||||
transport_complete_sync_cache(cmd, 1);
|
transport_complete_sync_cache(cmd, 1);
|
||||||
|
|
||||||
/*
|
bio = bio_alloc(GFP_KERNEL, 0);
|
||||||
* blkdev_issue_flush() does not support a specifying a range, so
|
bio->bi_end_io = iblock_end_io_flush;
|
||||||
* we have to flush the entire cache.
|
bio->bi_bdev = ib_dev->ibd_bd;
|
||||||
*/
|
|
||||||
ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector);
|
|
||||||
if (ret != 0) {
|
|
||||||
pr_err("IBLOCK: block_issue_flush() failed: %d "
|
|
||||||
" error_sector: %llu\n", ret,
|
|
||||||
(unsigned long long)error_sector);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!immed)
|
if (!immed)
|
||||||
transport_complete_sync_cache(cmd, ret == 0);
|
bio->bi_private = cmd;
|
||||||
}
|
submit_bio(WRITE_FLUSH, bio);
|
||||||
|
|
||||||
/*
|
|
||||||
* Tell TCM Core that we are capable of WriteCache emulation for
|
|
||||||
* an underlying struct se_device.
|
|
||||||
*/
|
|
||||||
static int iblock_emulated_write_cache(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iblock_emulated_dpo(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
|
|
||||||
* for TYPE_DISK.
|
|
||||||
*/
|
|
||||||
static int iblock_emulated_fua_write(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iblock_emulated_fua_read(struct se_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iblock_do_task(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct se_device *dev = task->task_se_cmd->se_dev;
|
|
||||||
struct iblock_req *req = IBLOCK_REQ(task);
|
|
||||||
struct bio *bio = req->ib_bio, *nbio = NULL;
|
|
||||||
struct blk_plug plug;
|
|
||||||
int rw;
|
|
||||||
|
|
||||||
if (task->task_data_direction == DMA_TO_DEVICE) {
|
|
||||||
/*
|
|
||||||
* Force data to disk if we pretend to not have a volatile
|
|
||||||
* write cache, or the initiator set the Force Unit Access bit.
|
|
||||||
*/
|
|
||||||
if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
|
|
||||||
(dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
|
|
||||||
task->task_se_cmd->t_tasks_fua))
|
|
||||||
rw = WRITE_FUA;
|
|
||||||
else
|
|
||||||
rw = WRITE;
|
|
||||||
} else {
|
|
||||||
rw = READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
blk_start_plug(&plug);
|
|
||||||
while (bio) {
|
|
||||||
nbio = bio->bi_next;
|
|
||||||
bio->bi_next = NULL;
|
|
||||||
pr_debug("Calling submit_bio() task: %p bio: %p"
|
|
||||||
" bio->bi_sector: %llu\n", task, bio,
|
|
||||||
(unsigned long long)bio->bi_sector);
|
|
||||||
|
|
||||||
submit_bio(rw, bio);
|
|
||||||
bio = nbio;
|
|
||||||
}
|
|
||||||
blk_finish_plug(&plug);
|
|
||||||
|
|
||||||
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
|
static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
|
||||||
|
@ -425,20 +362,7 @@ static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
|
||||||
|
|
||||||
static void iblock_free_task(struct se_task *task)
|
static void iblock_free_task(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct iblock_req *req = IBLOCK_REQ(task);
|
kfree(IBLOCK_REQ(task));
|
||||||
struct bio *bio, *hbio = req->ib_bio;
|
|
||||||
/*
|
|
||||||
* We only release the bio(s) here if iblock_bio_done() has not called
|
|
||||||
* bio_put() -> iblock_bio_destructor().
|
|
||||||
*/
|
|
||||||
while (hbio != NULL) {
|
|
||||||
bio = hbio;
|
|
||||||
hbio = hbio->bi_next;
|
|
||||||
bio->bi_next = NULL;
|
|
||||||
bio_put(bio);
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(req);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -552,25 +476,21 @@ static ssize_t iblock_show_configfs_dev_params(
|
||||||
static void iblock_bio_destructor(struct bio *bio)
|
static void iblock_bio_destructor(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct se_task *task = bio->bi_private;
|
struct se_task *task = bio->bi_private;
|
||||||
struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
|
struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
|
||||||
|
|
||||||
bio_free(bio, ib_dev->ibd_bio_set);
|
bio_free(bio, ib_dev->ibd_bio_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bio *iblock_get_bio(
|
static struct bio *
|
||||||
struct se_task *task,
|
iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
|
||||||
struct iblock_req *ib_req,
|
|
||||||
struct iblock_dev *ib_dev,
|
|
||||||
int *ret,
|
|
||||||
sector_t lba,
|
|
||||||
u32 sg_num)
|
|
||||||
{
|
{
|
||||||
|
struct iblock_dev *ib_dev = task->task_se_cmd->se_dev->dev_ptr;
|
||||||
|
struct iblock_req *ib_req = IBLOCK_REQ(task);
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
|
|
||||||
bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
|
bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
pr_err("Unable to allocate memory for bio\n");
|
pr_err("Unable to allocate memory for bio\n");
|
||||||
*ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,17 +511,33 @@ static struct bio *iblock_get_bio(
|
||||||
return bio;
|
return bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iblock_map_data_SG(struct se_task *task)
|
static int iblock_do_task(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct se_cmd *cmd = task->task_se_cmd;
|
struct se_cmd *cmd = task->task_se_cmd;
|
||||||
struct se_device *dev = cmd->se_dev;
|
struct se_device *dev = cmd->se_dev;
|
||||||
struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
|
struct bio *bio;
|
||||||
struct iblock_req *ib_req = IBLOCK_REQ(task);
|
struct bio_list list;
|
||||||
struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
|
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int ret = 0;
|
|
||||||
u32 i, sg_num = task->task_sg_nents;
|
u32 i, sg_num = task->task_sg_nents;
|
||||||
sector_t block_lba;
|
sector_t block_lba;
|
||||||
|
struct blk_plug plug;
|
||||||
|
int rw;
|
||||||
|
|
||||||
|
if (task->task_data_direction == DMA_TO_DEVICE) {
|
||||||
|
/*
|
||||||
|
* Force data to disk if we pretend to not have a volatile
|
||||||
|
* write cache, or the initiator set the Force Unit Access bit.
|
||||||
|
*/
|
||||||
|
if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 ||
|
||||||
|
(dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
|
||||||
|
task->task_se_cmd->t_tasks_fua))
|
||||||
|
rw = WRITE_FUA;
|
||||||
|
else
|
||||||
|
rw = WRITE;
|
||||||
|
} else {
|
||||||
|
rw = READ;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do starting conversion up from non 512-byte blocksize with
|
* Do starting conversion up from non 512-byte blocksize with
|
||||||
* struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
|
* struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
|
||||||
|
@ -620,68 +556,43 @@ static int iblock_map_data_SG(struct se_task *task)
|
||||||
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num);
|
bio = iblock_get_bio(task, block_lba, sg_num);
|
||||||
if (!bio)
|
if (!bio)
|
||||||
return ret;
|
return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
||||||
|
|
||||||
|
bio_list_init(&list);
|
||||||
|
bio_list_add(&list, bio);
|
||||||
|
|
||||||
ib_req->ib_bio = bio;
|
|
||||||
hbio = tbio = bio;
|
|
||||||
/*
|
|
||||||
* Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
|
|
||||||
* from task->task_sg -> struct scatterlist memory.
|
|
||||||
*/
|
|
||||||
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
|
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
|
||||||
pr_debug("task: %p bio: %p Calling bio_add_page(): page:"
|
/*
|
||||||
" %p len: %u offset: %u\n", task, bio, sg_page(sg),
|
* XXX: if the length the device accepts is shorter than the
|
||||||
sg->length, sg->offset);
|
* length of the S/G list entry this will cause and
|
||||||
again:
|
* endless loop. Better hope no driver uses huge pages.
|
||||||
ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset);
|
*/
|
||||||
if (ret != sg->length) {
|
while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
|
||||||
|
!= sg->length) {
|
||||||
pr_debug("*** Set bio->bi_sector: %llu\n",
|
bio = iblock_get_bio(task, block_lba, sg_num);
|
||||||
(unsigned long long)bio->bi_sector);
|
|
||||||
pr_debug("** task->task_size: %u\n",
|
|
||||||
task->task_size);
|
|
||||||
pr_debug("*** bio->bi_max_vecs: %u\n",
|
|
||||||
bio->bi_max_vecs);
|
|
||||||
pr_debug("*** bio->bi_vcnt: %u\n",
|
|
||||||
bio->bi_vcnt);
|
|
||||||
|
|
||||||
bio = iblock_get_bio(task, ib_req, ib_dev, &ret,
|
|
||||||
block_lba, sg_num);
|
|
||||||
if (!bio)
|
if (!bio)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
bio_list_add(&list, bio);
|
||||||
tbio = tbio->bi_next = bio;
|
|
||||||
pr_debug("-----------------> Added +1 bio: %p to"
|
|
||||||
" list, Going to again\n", bio);
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always in 512 byte units for Linux/Block */
|
/* Always in 512 byte units for Linux/Block */
|
||||||
block_lba += sg->length >> IBLOCK_LBA_SHIFT;
|
block_lba += sg->length >> IBLOCK_LBA_SHIFT;
|
||||||
sg_num--;
|
sg_num--;
|
||||||
pr_debug("task: %p bio-add_page() passed!, decremented"
|
|
||||||
" sg_num to %u\n", task, sg_num);
|
|
||||||
pr_debug("task: %p bio_add_page() passed!, increased lba"
|
|
||||||
" to %llu\n", task, (unsigned long long)block_lba);
|
|
||||||
pr_debug("task: %p bio_add_page() passed!, bio->bi_vcnt:"
|
|
||||||
" %u\n", task, bio->bi_vcnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
blk_start_plug(&plug);
|
||||||
|
while ((bio = bio_list_pop(&list)))
|
||||||
|
submit_bio(rw, bio);
|
||||||
|
blk_finish_plug(&plug);
|
||||||
|
|
||||||
|
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
while (hbio) {
|
while ((bio = bio_list_pop(&list)))
|
||||||
bio = hbio;
|
|
||||||
hbio = hbio->bi_next;
|
|
||||||
bio->bi_next = NULL;
|
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
}
|
return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char *iblock_get_cdb(struct se_task *task)
|
|
||||||
{
|
|
||||||
return IBLOCK_REQ(task)->ib_scsi_cdb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 iblock_get_device_rev(struct se_device *dev)
|
static u32 iblock_get_device_rev(struct se_device *dev)
|
||||||
|
@ -707,6 +618,7 @@ static void iblock_bio_done(struct bio *bio, int err)
|
||||||
{
|
{
|
||||||
struct se_task *task = bio->bi_private;
|
struct se_task *task = bio->bi_private;
|
||||||
struct iblock_req *ibr = IBLOCK_REQ(task);
|
struct iblock_req *ibr = IBLOCK_REQ(task);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set -EIO if !BIO_UPTODATE and the passed is still err=0
|
* Set -EIO if !BIO_UPTODATE and the passed is still err=0
|
||||||
*/
|
*/
|
||||||
|
@ -721,50 +633,31 @@ static void iblock_bio_done(struct bio *bio, int err)
|
||||||
*/
|
*/
|
||||||
atomic_inc(&ibr->ib_bio_err_cnt);
|
atomic_inc(&ibr->ib_bio_err_cnt);
|
||||||
smp_mb__after_atomic_inc();
|
smp_mb__after_atomic_inc();
|
||||||
bio_put(bio);
|
|
||||||
/*
|
|
||||||
* Wait to complete the task until the last bio as completed.
|
|
||||||
*/
|
|
||||||
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
|
|
||||||
return;
|
|
||||||
|
|
||||||
ibr->ib_bio = NULL;
|
|
||||||
transport_complete_task(task, 0);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
|
|
||||||
task, bio, task->task_lba, (unsigned long long)bio->bi_sector, err);
|
|
||||||
/*
|
|
||||||
* bio_put() will call iblock_bio_destructor() to release the bio back
|
|
||||||
* to ibr->ib_bio_set.
|
|
||||||
*/
|
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
/*
|
|
||||||
* Wait to complete the task until the last bio as completed.
|
|
||||||
*/
|
|
||||||
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
|
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
* Return GOOD status for task if zero ib_bio_err_cnt exists.
|
pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
|
||||||
*/
|
task, bio, task->task_lba,
|
||||||
ibr->ib_bio = NULL;
|
(unsigned long long)bio->bi_sector, err);
|
||||||
transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt)));
|
|
||||||
|
transport_complete_task(task, !atomic_read(&ibr->ib_bio_err_cnt));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct se_subsystem_api iblock_template = {
|
static struct se_subsystem_api iblock_template = {
|
||||||
.name = "iblock",
|
.name = "iblock",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
|
.transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
|
||||||
.map_data_SG = iblock_map_data_SG,
|
.write_cache_emulated = 1,
|
||||||
|
.fua_write_emulated = 1,
|
||||||
.attach_hba = iblock_attach_hba,
|
.attach_hba = iblock_attach_hba,
|
||||||
.detach_hba = iblock_detach_hba,
|
.detach_hba = iblock_detach_hba,
|
||||||
.allocate_virtdevice = iblock_allocate_virtdevice,
|
.allocate_virtdevice = iblock_allocate_virtdevice,
|
||||||
.create_virtdevice = iblock_create_virtdevice,
|
.create_virtdevice = iblock_create_virtdevice,
|
||||||
.free_device = iblock_free_device,
|
.free_device = iblock_free_device,
|
||||||
.dpo_emulated = iblock_emulated_dpo,
|
|
||||||
.fua_write_emulated = iblock_emulated_fua_write,
|
|
||||||
.fua_read_emulated = iblock_emulated_fua_read,
|
|
||||||
.write_cache_emulated = iblock_emulated_write_cache,
|
|
||||||
.alloc_task = iblock_alloc_task,
|
.alloc_task = iblock_alloc_task,
|
||||||
.do_task = iblock_do_task,
|
.do_task = iblock_do_task,
|
||||||
.do_discard = iblock_do_discard,
|
.do_discard = iblock_do_discard,
|
||||||
|
@ -773,7 +666,6 @@ static struct se_subsystem_api iblock_template = {
|
||||||
.check_configfs_dev_params = iblock_check_configfs_dev_params,
|
.check_configfs_dev_params = iblock_check_configfs_dev_params,
|
||||||
.set_configfs_dev_params = iblock_set_configfs_dev_params,
|
.set_configfs_dev_params = iblock_set_configfs_dev_params,
|
||||||
.show_configfs_dev_params = iblock_show_configfs_dev_params,
|
.show_configfs_dev_params = iblock_show_configfs_dev_params,
|
||||||
.get_cdb = iblock_get_cdb,
|
|
||||||
.get_device_rev = iblock_get_device_rev,
|
.get_device_rev = iblock_get_device_rev,
|
||||||
.get_device_type = iblock_get_device_type,
|
.get_device_type = iblock_get_device_type,
|
||||||
.get_blocks = iblock_get_blocks,
|
.get_blocks = iblock_get_blocks,
|
||||||
|
|
|
@ -8,10 +8,8 @@
|
||||||
|
|
||||||
struct iblock_req {
|
struct iblock_req {
|
||||||
struct se_task ib_task;
|
struct se_task ib_task;
|
||||||
unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
|
|
||||||
atomic_t ib_bio_cnt;
|
atomic_t ib_bio_cnt;
|
||||||
atomic_t ib_bio_err_cnt;
|
atomic_t ib_bio_err_cnt;
|
||||||
struct bio *ib_bio;
|
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
#define IBDF_HAS_UDEV_PATH 0x01
|
#define IBDF_HAS_UDEV_PATH 0x01
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
@ -567,7 +566,7 @@ static struct se_device *pscsi_create_virtdevice(
|
||||||
if (IS_ERR(sh)) {
|
if (IS_ERR(sh)) {
|
||||||
pr_err("pSCSI: Unable to locate"
|
pr_err("pSCSI: Unable to locate"
|
||||||
" pdv_host_id: %d\n", pdv->pdv_host_id);
|
" pdv_host_id: %d\n", pdv->pdv_host_id);
|
||||||
return (struct se_device *) sh;
|
return ERR_CAST(sh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -677,7 +676,7 @@ static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
|
||||||
*/
|
*/
|
||||||
static int pscsi_transport_complete(struct se_task *task)
|
static int pscsi_transport_complete(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
|
struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
|
||||||
struct scsi_device *sd = pdv->pdv_sd;
|
struct scsi_device *sd = pdv->pdv_sd;
|
||||||
int result;
|
int result;
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
||||||
|
@ -777,95 +776,6 @@ pscsi_alloc_task(unsigned char *cdb)
|
||||||
return &pt->pscsi_task;
|
return &pt->pscsi_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pscsi_blk_init_request(
|
|
||||||
struct se_task *task,
|
|
||||||
struct pscsi_plugin_task *pt,
|
|
||||||
struct request *req,
|
|
||||||
int bidi_read)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Defined as "scsi command" in include/linux/blkdev.h.
|
|
||||||
*/
|
|
||||||
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
|
||||||
/*
|
|
||||||
* For the extra BIDI-COMMAND READ struct request we do not
|
|
||||||
* need to setup the remaining structure members
|
|
||||||
*/
|
|
||||||
if (bidi_read)
|
|
||||||
return;
|
|
||||||
/*
|
|
||||||
* Setup the done function pointer for struct request,
|
|
||||||
* also set the end_io_data pointer.to struct se_task.
|
|
||||||
*/
|
|
||||||
req->end_io = pscsi_req_done;
|
|
||||||
req->end_io_data = task;
|
|
||||||
/*
|
|
||||||
* Load the referenced struct se_task's SCSI CDB into
|
|
||||||
* include/linux/blkdev.h:struct request->cmd
|
|
||||||
*/
|
|
||||||
req->cmd_len = scsi_command_size(pt->pscsi_cdb);
|
|
||||||
req->cmd = &pt->pscsi_cdb[0];
|
|
||||||
/*
|
|
||||||
* Setup pointer for outgoing sense data.
|
|
||||||
*/
|
|
||||||
req->sense = &pt->pscsi_sense[0];
|
|
||||||
req->sense_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB
|
|
||||||
*/
|
|
||||||
static int pscsi_blk_get_request(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
|
||||||
struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
|
|
||||||
|
|
||||||
pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue,
|
|
||||||
(task->task_data_direction == DMA_TO_DEVICE),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!pt->pscsi_req || IS_ERR(pt->pscsi_req)) {
|
|
||||||
pr_err("PSCSI: blk_get_request() failed: %ld\n",
|
|
||||||
IS_ERR(pt->pscsi_req));
|
|
||||||
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
|
|
||||||
* and setup rq callback, CDB and sense.
|
|
||||||
*/
|
|
||||||
pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pscsi_do_task(): (Part of se_subsystem_api_t template)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int pscsi_do_task(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
|
||||||
struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
|
|
||||||
/*
|
|
||||||
* Set the struct request->timeout value based on peripheral
|
|
||||||
* device type from SCSI.
|
|
||||||
*/
|
|
||||||
if (pdv->pdv_sd->type == TYPE_DISK)
|
|
||||||
pt->pscsi_req->timeout = PS_TIMEOUT_DISK;
|
|
||||||
else
|
|
||||||
pt->pscsi_req->timeout = PS_TIMEOUT_OTHER;
|
|
||||||
|
|
||||||
pt->pscsi_req->retries = PS_RETRY;
|
|
||||||
/*
|
|
||||||
* Queue the struct request into the struct scsi_device->request_queue.
|
|
||||||
* Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd
|
|
||||||
* descriptor
|
|
||||||
*/
|
|
||||||
blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
|
|
||||||
(task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
|
|
||||||
pscsi_req_done);
|
|
||||||
|
|
||||||
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pscsi_free_task(struct se_task *task)
|
static void pscsi_free_task(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
||||||
|
@ -1049,15 +959,12 @@ static inline struct bio *pscsi_get_bio(int sg_num)
|
||||||
return bio;
|
return bio;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __pscsi_map_SG(
|
static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg,
|
||||||
struct se_task *task,
|
struct bio **hbio)
|
||||||
struct scatterlist *task_sg,
|
|
||||||
u32 task_sg_num,
|
|
||||||
int bidi_read)
|
|
||||||
{
|
{
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
|
||||||
struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
|
u32 task_sg_num = task->task_sg_nents;
|
||||||
struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
|
struct bio *bio = NULL, *tbio = NULL;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
u32 data_len = task->task_size, i, len, bytes, off;
|
u32 data_len = task->task_size, i, len, bytes, off;
|
||||||
|
@ -1066,19 +973,8 @@ static int __pscsi_map_SG(
|
||||||
int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
||||||
int rw = (task->task_data_direction == DMA_TO_DEVICE);
|
int rw = (task->task_data_direction == DMA_TO_DEVICE);
|
||||||
|
|
||||||
if (!task->task_size)
|
*hbio = NULL;
|
||||||
return 0;
|
|
||||||
/*
|
|
||||||
* For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
|
|
||||||
* the bio_vec maplist from task->task_sg ->
|
|
||||||
* struct scatterlist memory. The struct se_task->task_sg[] currently needs
|
|
||||||
* to be attached to struct bios for submission to Linux/SCSI using
|
|
||||||
* struct request to struct scsi_device->request_queue.
|
|
||||||
*
|
|
||||||
* Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI
|
|
||||||
* is ported to upstream SCSI passthrough functionality that accepts
|
|
||||||
* struct scatterlist->page_link or struct page as a paraemeter.
|
|
||||||
*/
|
|
||||||
pr_debug("PSCSI: nr_pages: %d\n", nr_pages);
|
pr_debug("PSCSI: nr_pages: %d\n", nr_pages);
|
||||||
|
|
||||||
for_each_sg(task_sg, sg, task_sg_num, i) {
|
for_each_sg(task_sg, sg, task_sg_num, i) {
|
||||||
|
@ -1115,8 +1011,8 @@ static int __pscsi_map_SG(
|
||||||
* bios need to be added to complete a given
|
* bios need to be added to complete a given
|
||||||
* struct se_task
|
* struct se_task
|
||||||
*/
|
*/
|
||||||
if (!hbio)
|
if (!*hbio)
|
||||||
hbio = tbio = bio;
|
*hbio = tbio = bio;
|
||||||
else
|
else
|
||||||
tbio = tbio->bi_next = bio;
|
tbio = tbio->bi_next = bio;
|
||||||
}
|
}
|
||||||
|
@ -1152,92 +1048,82 @@ static int __pscsi_map_SG(
|
||||||
off = 0;
|
off = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND
|
|
||||||
* primary SCSI WRITE poayload mapped for struct se_task->task_sg[]
|
|
||||||
*/
|
|
||||||
if (!bidi_read) {
|
|
||||||
/*
|
|
||||||
* Starting with v2.6.31, call blk_make_request() passing in *hbio to
|
|
||||||
* allocate the pSCSI task a struct request.
|
|
||||||
*/
|
|
||||||
pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue,
|
|
||||||
hbio, GFP_KERNEL);
|
|
||||||
if (!pt->pscsi_req) {
|
|
||||||
pr_err("pSCSI: blk_make_request() failed\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
|
|
||||||
* and setup rq callback, CDB and sense.
|
|
||||||
*/
|
|
||||||
pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
|
|
||||||
|
|
||||||
return task->task_sg_nents;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND
|
|
||||||
* SCSI READ paylaod mapped for struct se_task->task_sg_bidi[]
|
|
||||||
*/
|
|
||||||
pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue,
|
|
||||||
hbio, GFP_KERNEL);
|
|
||||||
if (!pt->pscsi_req->next_rq) {
|
|
||||||
pr_err("pSCSI: blk_make_request() failed for BIDI\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1);
|
|
||||||
|
|
||||||
return task->task_sg_nents;
|
return task->task_sg_nents;
|
||||||
fail:
|
fail:
|
||||||
while (hbio) {
|
while (*hbio) {
|
||||||
bio = hbio;
|
bio = *hbio;
|
||||||
hbio = hbio->bi_next;
|
*hbio = (*hbio)->bi_next;
|
||||||
bio->bi_next = NULL;
|
bio->bi_next = NULL;
|
||||||
bio_endio(bio, 0);
|
bio_endio(bio, 0); /* XXX: should be error */
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int pscsi_do_task(struct se_task *task)
|
||||||
* pSCSI maps both ->map_control_SG() and ->map_data_SG() to a single call.
|
|
||||||
*/
|
|
||||||
static int pscsi_map_SG(struct se_task *task)
|
|
||||||
{
|
{
|
||||||
|
struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr;
|
||||||
|
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
||||||
|
struct request *req;
|
||||||
|
struct bio *hbio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
target_get_task_cdb(task, pt->pscsi_cdb);
|
||||||
* Setup the main struct request for the task->task_sg[] payload
|
|
||||||
*/
|
if (task->task_se_cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
|
||||||
|
req = blk_get_request(pdv->pdv_sd->request_queue,
|
||||||
|
(task->task_data_direction == DMA_TO_DEVICE),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!req || IS_ERR(req)) {
|
||||||
|
pr_err("PSCSI: blk_get_request() failed: %ld\n",
|
||||||
|
req ? IS_ERR(req) : -ENOMEM);
|
||||||
|
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BUG_ON(!task->task_size);
|
||||||
|
|
||||||
ret = __pscsi_map_SG(task, task->task_sg, task->task_sg_nents, 0);
|
|
||||||
if (ret >= 0 && task->task_sg_bidi) {
|
|
||||||
/*
|
/*
|
||||||
* If present, set up the extra BIDI-COMMAND SCSI READ
|
* Setup the main struct request for the task->task_sg[] payload
|
||||||
* struct request and payload.
|
|
||||||
*/
|
*/
|
||||||
ret = __pscsi_map_SG(task, task->task_sg_bidi,
|
ret = pscsi_map_sg(task, task->task_sg, &hbio);
|
||||||
task->task_sg_nents, 1);
|
if (ret < 0)
|
||||||
|
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
||||||
|
|
||||||
|
req = blk_make_request(pdv->pdv_sd->request_queue, hbio,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!req) {
|
||||||
|
pr_err("pSCSI: blk_make_request() failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0)
|
req->cmd_type = REQ_TYPE_BLOCK_PC;
|
||||||
return PYX_TRANSPORT_LU_COMM_FAILURE;
|
req->end_io = pscsi_req_done;
|
||||||
return 0;
|
req->end_io_data = task;
|
||||||
}
|
req->cmd_len = scsi_command_size(pt->pscsi_cdb);
|
||||||
|
req->cmd = &pt->pscsi_cdb[0];
|
||||||
|
req->sense = &pt->pscsi_sense[0];
|
||||||
|
req->sense_len = 0;
|
||||||
|
if (pdv->pdv_sd->type == TYPE_DISK)
|
||||||
|
req->timeout = PS_TIMEOUT_DISK;
|
||||||
|
else
|
||||||
|
req->timeout = PS_TIMEOUT_OTHER;
|
||||||
|
req->retries = PS_RETRY;
|
||||||
|
|
||||||
static int pscsi_CDB_none(struct se_task *task)
|
blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, req,
|
||||||
{
|
(task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG),
|
||||||
return pscsi_blk_get_request(task);
|
pscsi_req_done);
|
||||||
}
|
|
||||||
|
|
||||||
/* pscsi_get_cdb():
|
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static unsigned char *pscsi_get_cdb(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct pscsi_plugin_task *pt = PSCSI_TASK(task);
|
|
||||||
|
|
||||||
return pt->pscsi_cdb;
|
fail:
|
||||||
|
while (hbio) {
|
||||||
|
struct bio *bio = hbio;
|
||||||
|
hbio = hbio->bi_next;
|
||||||
|
bio->bi_next = NULL;
|
||||||
|
bio_endio(bio, 0); /* XXX: should be error */
|
||||||
|
}
|
||||||
|
return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pscsi_get_sense_buffer():
|
/* pscsi_get_sense_buffer():
|
||||||
|
@ -1328,23 +1214,13 @@ static void pscsi_req_done(struct request *req, int uptodate)
|
||||||
pt->pscsi_resid = req->resid_len;
|
pt->pscsi_resid = req->resid_len;
|
||||||
|
|
||||||
pscsi_process_SAM_status(task, pt);
|
pscsi_process_SAM_status(task, pt);
|
||||||
/*
|
|
||||||
* Release BIDI-READ if present
|
|
||||||
*/
|
|
||||||
if (req->next_rq != NULL)
|
|
||||||
__blk_put_request(req->q, req->next_rq);
|
|
||||||
|
|
||||||
__blk_put_request(req->q, req);
|
__blk_put_request(req->q, req);
|
||||||
pt->pscsi_req = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct se_subsystem_api pscsi_template = {
|
static struct se_subsystem_api pscsi_template = {
|
||||||
.name = "pscsi",
|
.name = "pscsi",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
|
.transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
|
||||||
.cdb_none = pscsi_CDB_none,
|
|
||||||
.map_control_SG = pscsi_map_SG,
|
|
||||||
.map_data_SG = pscsi_map_SG,
|
|
||||||
.attach_hba = pscsi_attach_hba,
|
.attach_hba = pscsi_attach_hba,
|
||||||
.detach_hba = pscsi_detach_hba,
|
.detach_hba = pscsi_detach_hba,
|
||||||
.pmode_enable_hba = pscsi_pmode_enable_hba,
|
.pmode_enable_hba = pscsi_pmode_enable_hba,
|
||||||
|
@ -1358,7 +1234,6 @@ static struct se_subsystem_api pscsi_template = {
|
||||||
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
|
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
|
||||||
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
|
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
|
||||||
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
|
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
|
||||||
.get_cdb = pscsi_get_cdb,
|
|
||||||
.get_sense_buffer = pscsi_get_sense_buffer,
|
.get_sense_buffer = pscsi_get_sense_buffer,
|
||||||
.get_device_rev = pscsi_get_device_rev,
|
.get_device_rev = pscsi_get_device_rev,
|
||||||
.get_device_type = pscsi_get_device_type,
|
.get_device_type = pscsi_get_device_type,
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct pscsi_plugin_task {
|
||||||
int pscsi_direction;
|
int pscsi_direction;
|
||||||
int pscsi_result;
|
int pscsi_result;
|
||||||
u32 pscsi_resid;
|
u32 pscsi_resid;
|
||||||
struct request *pscsi_req;
|
|
||||||
unsigned char pscsi_cdb[0];
|
unsigned char pscsi_cdb[0];
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/parser.h>
|
#include <linux/parser.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
@ -351,7 +350,7 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
|
||||||
static int rd_MEMCPY_read(struct rd_request *req)
|
static int rd_MEMCPY_read(struct rd_request *req)
|
||||||
{
|
{
|
||||||
struct se_task *task = &req->rd_task;
|
struct se_task *task = &req->rd_task;
|
||||||
struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
|
struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
|
||||||
struct rd_dev_sg_table *table;
|
struct rd_dev_sg_table *table;
|
||||||
struct scatterlist *sg_d, *sg_s;
|
struct scatterlist *sg_d, *sg_s;
|
||||||
void *dst, *src;
|
void *dst, *src;
|
||||||
|
@ -467,7 +466,7 @@ static int rd_MEMCPY_read(struct rd_request *req)
|
||||||
static int rd_MEMCPY_write(struct rd_request *req)
|
static int rd_MEMCPY_write(struct rd_request *req)
|
||||||
{
|
{
|
||||||
struct se_task *task = &req->rd_task;
|
struct se_task *task = &req->rd_task;
|
||||||
struct rd_dev *dev = req->rd_task.se_dev->dev_ptr;
|
struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr;
|
||||||
struct rd_dev_sg_table *table;
|
struct rd_dev_sg_table *table;
|
||||||
struct scatterlist *sg_d, *sg_s;
|
struct scatterlist *sg_d, *sg_s;
|
||||||
void *dst, *src;
|
void *dst, *src;
|
||||||
|
@ -582,7 +581,7 @@ static int rd_MEMCPY_write(struct rd_request *req)
|
||||||
*/
|
*/
|
||||||
static int rd_MEMCPY_do_task(struct se_task *task)
|
static int rd_MEMCPY_do_task(struct se_task *task)
|
||||||
{
|
{
|
||||||
struct se_device *dev = task->se_dev;
|
struct se_device *dev = task->task_se_cmd->se_dev;
|
||||||
struct rd_request *req = RD_REQ(task);
|
struct rd_request *req = RD_REQ(task);
|
||||||
unsigned long long lba;
|
unsigned long long lba;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -692,17 +691,6 @@ static ssize_t rd_show_configfs_dev_params(
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rd_get_cdb(): (Part of se_subsystem_api_t template)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static unsigned char *rd_get_cdb(struct se_task *task)
|
|
||||||
{
|
|
||||||
struct rd_request *req = RD_REQ(task);
|
|
||||||
|
|
||||||
return req->rd_scsi_cdb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 rd_get_device_rev(struct se_device *dev)
|
static u32 rd_get_device_rev(struct se_device *dev)
|
||||||
{
|
{
|
||||||
return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
|
return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
|
||||||
|
@ -736,7 +724,6 @@ static struct se_subsystem_api rd_mcp_template = {
|
||||||
.check_configfs_dev_params = rd_check_configfs_dev_params,
|
.check_configfs_dev_params = rd_check_configfs_dev_params,
|
||||||
.set_configfs_dev_params = rd_set_configfs_dev_params,
|
.set_configfs_dev_params = rd_set_configfs_dev_params,
|
||||||
.show_configfs_dev_params = rd_show_configfs_dev_params,
|
.show_configfs_dev_params = rd_show_configfs_dev_params,
|
||||||
.get_cdb = rd_get_cdb,
|
|
||||||
.get_device_rev = rd_get_device_rev,
|
.get_device_rev = rd_get_device_rev,
|
||||||
.get_device_type = rd_get_device_type,
|
.get_device_type = rd_get_device_type,
|
||||||
.get_blocks = rd_get_blocks,
|
.get_blocks = rd_get_blocks,
|
||||||
|
|
|
@ -22,8 +22,6 @@ void rd_module_exit(void);
|
||||||
struct rd_request {
|
struct rd_request {
|
||||||
struct se_task rd_task;
|
struct se_task rd_task;
|
||||||
|
|
||||||
/* SCSI CDB from iSCSI Command PDU */
|
|
||||||
unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
|
|
||||||
/* Offset from start of page */
|
/* Offset from start of page */
|
||||||
u32 rd_offset;
|
u32 rd_offset;
|
||||||
/* Starting page in Ramdisk for request */
|
/* Starting page in Ramdisk for request */
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Filename: target_core_scdb.c
|
|
||||||
*
|
|
||||||
* This file contains the generic target engine Split CDB related functions.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004-2005 PyX Technologies, Inc.
|
|
||||||
* Copyright (c) 2005, 2006, 2007 SBE, Inc.
|
|
||||||
* Copyright (c) 2007-2010 Rising Tide Systems
|
|
||||||
* Copyright (c) 2008-2010 Linux-iSCSI.org
|
|
||||||
*
|
|
||||||
* Nicholas A. Bellinger <nab@kernel.org>
|
|
||||||
*
|
|
||||||
* 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; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include <linux/net.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <scsi/scsi.h>
|
|
||||||
#include <asm/unaligned.h>
|
|
||||||
|
|
||||||
#include <target/target_core_base.h>
|
|
||||||
#include <target/target_core_transport.h>
|
|
||||||
|
|
||||||
#include "target_core_scdb.h"
|
|
||||||
|
|
||||||
/* split_cdb_XX_6():
|
|
||||||
*
|
|
||||||
* 21-bit LBA w/ 8-bit SECTORS
|
|
||||||
*/
|
|
||||||
void split_cdb_XX_6(
|
|
||||||
unsigned long long lba,
|
|
||||||
u32 sectors,
|
|
||||||
unsigned char *cdb)
|
|
||||||
{
|
|
||||||
cdb[1] = (lba >> 16) & 0x1f;
|
|
||||||
cdb[2] = (lba >> 8) & 0xff;
|
|
||||||
cdb[3] = lba & 0xff;
|
|
||||||
cdb[4] = sectors & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split_cdb_XX_10():
|
|
||||||
*
|
|
||||||
* 32-bit LBA w/ 16-bit SECTORS
|
|
||||||
*/
|
|
||||||
void split_cdb_XX_10(
|
|
||||||
unsigned long long lba,
|
|
||||||
u32 sectors,
|
|
||||||
unsigned char *cdb)
|
|
||||||
{
|
|
||||||
put_unaligned_be32(lba, &cdb[2]);
|
|
||||||
put_unaligned_be16(sectors, &cdb[7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split_cdb_XX_12():
|
|
||||||
*
|
|
||||||
* 32-bit LBA w/ 32-bit SECTORS
|
|
||||||
*/
|
|
||||||
void split_cdb_XX_12(
|
|
||||||
unsigned long long lba,
|
|
||||||
u32 sectors,
|
|
||||||
unsigned char *cdb)
|
|
||||||
{
|
|
||||||
put_unaligned_be32(lba, &cdb[2]);
|
|
||||||
put_unaligned_be32(sectors, &cdb[6]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split_cdb_XX_16():
|
|
||||||
*
|
|
||||||
* 64-bit LBA w/ 32-bit SECTORS
|
|
||||||
*/
|
|
||||||
void split_cdb_XX_16(
|
|
||||||
unsigned long long lba,
|
|
||||||
u32 sectors,
|
|
||||||
unsigned char *cdb)
|
|
||||||
{
|
|
||||||
put_unaligned_be64(lba, &cdb[2]);
|
|
||||||
put_unaligned_be32(sectors, &cdb[10]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* split_cdb_XX_32():
|
|
||||||
*
|
|
||||||
* 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32
|
|
||||||
*/
|
|
||||||
void split_cdb_XX_32(
|
|
||||||
unsigned long long lba,
|
|
||||||
u32 sectors,
|
|
||||||
unsigned char *cdb)
|
|
||||||
{
|
|
||||||
put_unaligned_be64(lba, &cdb[12]);
|
|
||||||
put_unaligned_be32(sectors, &cdb[28]);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
#ifndef TARGET_CORE_SCDB_H
|
|
||||||
#define TARGET_CORE_SCDB_H
|
|
||||||
|
|
||||||
extern void split_cdb_XX_6(unsigned long long, u32, unsigned char *);
|
|
||||||
extern void split_cdb_XX_10(unsigned long long, u32, unsigned char *);
|
|
||||||
extern void split_cdb_XX_12(unsigned long long, u32, unsigned char *);
|
|
||||||
extern void split_cdb_XX_16(unsigned long long, u32, unsigned char *);
|
|
||||||
extern void split_cdb_XX_32(unsigned long long, u32, unsigned char *);
|
|
||||||
|
|
||||||
#endif /* TARGET_CORE_SCDB_H */
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
@ -44,12 +43,12 @@
|
||||||
struct se_tmr_req *core_tmr_alloc_req(
|
struct se_tmr_req *core_tmr_alloc_req(
|
||||||
struct se_cmd *se_cmd,
|
struct se_cmd *se_cmd,
|
||||||
void *fabric_tmr_ptr,
|
void *fabric_tmr_ptr,
|
||||||
u8 function)
|
u8 function,
|
||||||
|
gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
struct se_tmr_req *tmr;
|
struct se_tmr_req *tmr;
|
||||||
|
|
||||||
tmr = kmem_cache_zalloc(se_tmr_req_cache, (in_interrupt()) ?
|
tmr = kmem_cache_zalloc(se_tmr_req_cache, gfp_flags);
|
||||||
GFP_ATOMIC : GFP_KERNEL);
|
|
||||||
if (!tmr) {
|
if (!tmr) {
|
||||||
pr_err("Unable to allocate struct se_tmr_req\n");
|
pr_err("Unable to allocate struct se_tmr_req\n");
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
@ -67,15 +66,16 @@ void core_tmr_release_req(
|
||||||
struct se_tmr_req *tmr)
|
struct se_tmr_req *tmr)
|
||||||
{
|
{
|
||||||
struct se_device *dev = tmr->tmr_dev;
|
struct se_device *dev = tmr->tmr_dev;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
kmem_cache_free(se_tmr_req_cache, tmr);
|
kmem_cache_free(se_tmr_req_cache, tmr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irq(&dev->se_tmr_lock);
|
spin_lock_irqsave(&dev->se_tmr_lock, flags);
|
||||||
list_del(&tmr->tmr_list);
|
list_del(&tmr->tmr_list);
|
||||||
spin_unlock_irq(&dev->se_tmr_lock);
|
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
|
||||||
|
|
||||||
kmem_cache_free(se_tmr_req_cache, tmr);
|
kmem_cache_free(se_tmr_req_cache, tmr);
|
||||||
}
|
}
|
||||||
|
@ -100,54 +100,20 @@ static void core_tmr_handle_tas_abort(
|
||||||
transport_cmd_finish_abort(cmd, 0);
|
transport_cmd_finish_abort(cmd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int core_tmr_lun_reset(
|
static void core_tmr_drain_tmr_list(
|
||||||
struct se_device *dev,
|
struct se_device *dev,
|
||||||
struct se_tmr_req *tmr,
|
struct se_tmr_req *tmr,
|
||||||
struct list_head *preempt_and_abort_list,
|
struct list_head *preempt_and_abort_list)
|
||||||
struct se_cmd *prout_cmd)
|
|
||||||
{
|
{
|
||||||
struct se_cmd *cmd, *tcmd;
|
LIST_HEAD(drain_tmr_list);
|
||||||
struct se_node_acl *tmr_nacl = NULL;
|
|
||||||
struct se_portal_group *tmr_tpg = NULL;
|
|
||||||
struct se_queue_obj *qobj = &dev->dev_queue_obj;
|
|
||||||
struct se_tmr_req *tmr_p, *tmr_pp;
|
struct se_tmr_req *tmr_p, *tmr_pp;
|
||||||
struct se_task *task, *task_tmp;
|
struct se_cmd *cmd;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int fe_count, tas;
|
|
||||||
/*
|
|
||||||
* TASK_ABORTED status bit, this is configurable via ConfigFS
|
|
||||||
* struct se_device attributes. spc4r17 section 7.4.6 Control mode page
|
|
||||||
*
|
|
||||||
* A task aborted status (TAS) bit set to zero specifies that aborted
|
|
||||||
* tasks shall be terminated by the device server without any response
|
|
||||||
* to the application client. A TAS bit set to one specifies that tasks
|
|
||||||
* aborted by the actions of an I_T nexus other than the I_T nexus on
|
|
||||||
* which the command was received shall be completed with TASK ABORTED
|
|
||||||
* status (see SAM-4).
|
|
||||||
*/
|
|
||||||
tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
|
|
||||||
/*
|
|
||||||
* Determine if this se_tmr is coming from a $FABRIC_MOD
|
|
||||||
* or struct se_device passthrough..
|
|
||||||
*/
|
|
||||||
if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
|
|
||||||
tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
|
|
||||||
tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
|
|
||||||
if (tmr_nacl && tmr_tpg) {
|
|
||||||
pr_debug("LUN_RESET: TMR caller fabric: %s"
|
|
||||||
" initiator port %s\n",
|
|
||||||
tmr_tpg->se_tpg_tfo->get_fabric_name(),
|
|
||||||
tmr_nacl->initiatorname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
|
|
||||||
(preempt_and_abort_list) ? "Preempt" : "TMR",
|
|
||||||
dev->transport->name, tas);
|
|
||||||
/*
|
/*
|
||||||
* Release all pending and outgoing TMRs aside from the received
|
* Release all pending and outgoing TMRs aside from the received
|
||||||
* LUN_RESET tmr..
|
* LUN_RESET tmr..
|
||||||
*/
|
*/
|
||||||
spin_lock_irq(&dev->se_tmr_lock);
|
spin_lock_irqsave(&dev->se_tmr_lock, flags);
|
||||||
list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
|
list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
|
||||||
/*
|
/*
|
||||||
* Allow the received TMR to return with FUNCTION_COMPLETE.
|
* Allow the received TMR to return with FUNCTION_COMPLETE.
|
||||||
|
@ -169,29 +135,48 @@ int core_tmr_lun_reset(
|
||||||
(core_scsi3_check_cdb_abort_and_preempt(
|
(core_scsi3_check_cdb_abort_and_preempt(
|
||||||
preempt_and_abort_list, cmd) != 0))
|
preempt_and_abort_list, cmd) != 0))
|
||||||
continue;
|
continue;
|
||||||
spin_unlock_irq(&dev->se_tmr_lock);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&cmd->t_state_lock, flags);
|
spin_lock(&cmd->t_state_lock);
|
||||||
if (!atomic_read(&cmd->t_transport_active)) {
|
if (!atomic_read(&cmd->t_transport_active)) {
|
||||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
spin_unlock(&cmd->t_state_lock);
|
||||||
spin_lock_irq(&dev->se_tmr_lock);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
|
if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
|
||||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
spin_unlock(&cmd->t_state_lock);
|
||||||
spin_lock_irq(&dev->se_tmr_lock);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&cmd->t_state_lock);
|
||||||
|
|
||||||
|
list_move_tail(&tmr->tmr_list, &drain_tmr_list);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
|
||||||
|
|
||||||
|
while (!list_empty(&drain_tmr_list)) {
|
||||||
|
tmr = list_entry(drain_tmr_list.next, struct se_tmr_req, tmr_list);
|
||||||
|
list_del(&tmr->tmr_list);
|
||||||
|
cmd = tmr_p->task_cmd;
|
||||||
|
|
||||||
pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
|
pr_debug("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
|
||||||
" Response: 0x%02x, t_state: %d\n",
|
" Response: 0x%02x, t_state: %d\n",
|
||||||
(preempt_and_abort_list) ? "Preempt" : "", tmr_p,
|
(preempt_and_abort_list) ? "Preempt" : "", tmr,
|
||||||
tmr_p->function, tmr_p->response, cmd->t_state);
|
tmr->function, tmr->response, cmd->t_state);
|
||||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
|
||||||
|
|
||||||
transport_cmd_finish_abort_tmr(cmd);
|
transport_cmd_finish_abort(cmd, 1);
|
||||||
spin_lock_irq(&dev->se_tmr_lock);
|
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&dev->se_tmr_lock);
|
}
|
||||||
|
|
||||||
|
static void core_tmr_drain_task_list(
|
||||||
|
struct se_device *dev,
|
||||||
|
struct se_cmd *prout_cmd,
|
||||||
|
struct se_node_acl *tmr_nacl,
|
||||||
|
int tas,
|
||||||
|
struct list_head *preempt_and_abort_list)
|
||||||
|
{
|
||||||
|
LIST_HEAD(drain_task_list);
|
||||||
|
struct se_cmd *cmd;
|
||||||
|
struct se_task *task, *task_tmp;
|
||||||
|
unsigned long flags;
|
||||||
|
int fe_count;
|
||||||
/*
|
/*
|
||||||
* Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
|
* Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
|
||||||
* This is following sam4r17, section 5.6 Aborting commands, Table 38
|
* This is following sam4r17, section 5.6 Aborting commands, Table 38
|
||||||
|
@ -236,18 +221,28 @@ int core_tmr_lun_reset(
|
||||||
if (prout_cmd == cmd)
|
if (prout_cmd == cmd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_del(&task->t_state_list);
|
list_move_tail(&task->t_state_list, &drain_task_list);
|
||||||
atomic_set(&task->task_state_active, 0);
|
atomic_set(&task->task_state_active, 0);
|
||||||
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
|
/*
|
||||||
|
* Remove from task execute list before processing drain_task_list
|
||||||
|
*/
|
||||||
|
if (!list_empty(&task->t_execute_list))
|
||||||
|
__transport_remove_task_from_execute_queue(task, dev);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
|
||||||
|
|
||||||
|
while (!list_empty(&drain_task_list)) {
|
||||||
|
task = list_entry(drain_task_list.next, struct se_task, t_state_list);
|
||||||
|
list_del(&task->t_state_list);
|
||||||
|
cmd = task->task_se_cmd;
|
||||||
|
|
||||||
spin_lock_irqsave(&cmd->t_state_lock, flags);
|
|
||||||
pr_debug("LUN_RESET: %s cmd: %p task: %p"
|
pr_debug("LUN_RESET: %s cmd: %p task: %p"
|
||||||
" ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/"
|
" ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d"
|
||||||
"def_t_state: %d/%d cdb: 0x%02x\n",
|
"cdb: 0x%02x\n",
|
||||||
(preempt_and_abort_list) ? "Preempt" : "", cmd, task,
|
(preempt_and_abort_list) ? "Preempt" : "", cmd, task,
|
||||||
cmd->se_tfo->get_task_tag(cmd), 0,
|
cmd->se_tfo->get_task_tag(cmd), 0,
|
||||||
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
|
cmd->se_tfo->get_cmd_state(cmd), cmd->t_state,
|
||||||
cmd->deferred_t_state, cmd->t_task_cdb[0]);
|
cmd->t_task_cdb[0]);
|
||||||
pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
|
pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
|
||||||
" t_task_cdbs: %d t_task_cdbs_left: %d"
|
" t_task_cdbs: %d t_task_cdbs_left: %d"
|
||||||
" t_task_cdbs_sent: %d -- t_transport_active: %d"
|
" t_task_cdbs_sent: %d -- t_transport_active: %d"
|
||||||
|
@ -260,35 +255,24 @@ int core_tmr_lun_reset(
|
||||||
atomic_read(&cmd->t_transport_stop),
|
atomic_read(&cmd->t_transport_stop),
|
||||||
atomic_read(&cmd->t_transport_sent));
|
atomic_read(&cmd->t_transport_sent));
|
||||||
|
|
||||||
if (atomic_read(&task->task_active)) {
|
/*
|
||||||
atomic_set(&task->task_stop, 1);
|
* If the command may be queued onto a workqueue cancel it now.
|
||||||
spin_unlock_irqrestore(
|
*
|
||||||
&cmd->t_state_lock, flags);
|
* This is equivalent to removal from the execute queue in the
|
||||||
|
* loop above, but we do it down here given that
|
||||||
|
* cancel_work_sync may block.
|
||||||
|
*/
|
||||||
|
if (cmd->t_state == TRANSPORT_COMPLETE)
|
||||||
|
cancel_work_sync(&cmd->work);
|
||||||
|
|
||||||
pr_debug("LUN_RESET: Waiting for task: %p to shutdown"
|
spin_lock_irqsave(&cmd->t_state_lock, flags);
|
||||||
" for dev: %p\n", task, dev);
|
target_stop_task(task, &flags);
|
||||||
wait_for_completion(&task->task_stop_comp);
|
|
||||||
pr_debug("LUN_RESET Completed task: %p shutdown for"
|
|
||||||
" dev: %p\n", task, dev);
|
|
||||||
spin_lock_irqsave(&cmd->t_state_lock, flags);
|
|
||||||
atomic_dec(&cmd->t_task_cdbs_left);
|
|
||||||
|
|
||||||
atomic_set(&task->task_active, 0);
|
|
||||||
atomic_set(&task->task_stop, 0);
|
|
||||||
} else {
|
|
||||||
if (atomic_read(&task->task_execute_queue) != 0)
|
|
||||||
transport_remove_task_from_execute_queue(task, dev);
|
|
||||||
}
|
|
||||||
__transport_stop_task_timer(task, &flags);
|
|
||||||
|
|
||||||
if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
|
if (!atomic_dec_and_test(&cmd->t_task_cdbs_ex_left)) {
|
||||||
spin_unlock_irqrestore(
|
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||||
&cmd->t_state_lock, flags);
|
|
||||||
pr_debug("LUN_RESET: Skipping task: %p, dev: %p for"
|
pr_debug("LUN_RESET: Skipping task: %p, dev: %p for"
|
||||||
" t_task_cdbs_ex_left: %d\n", task, dev,
|
" t_task_cdbs_ex_left: %d\n", task, dev,
|
||||||
atomic_read(&cmd->t_task_cdbs_ex_left));
|
atomic_read(&cmd->t_task_cdbs_ex_left));
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->execute_task_lock, flags);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fe_count = atomic_read(&cmd->t_fe_count);
|
fe_count = atomic_read(&cmd->t_fe_count);
|
||||||
|
@ -298,22 +282,31 @@ int core_tmr_lun_reset(
|
||||||
" task: %p, t_fe_count: %d dev: %p\n", task,
|
" task: %p, t_fe_count: %d dev: %p\n", task,
|
||||||
fe_count, dev);
|
fe_count, dev);
|
||||||
atomic_set(&cmd->t_transport_aborted, 1);
|
atomic_set(&cmd->t_transport_aborted, 1);
|
||||||
spin_unlock_irqrestore(&cmd->t_state_lock,
|
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||||
flags);
|
|
||||||
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->execute_task_lock, flags);
|
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p,"
|
pr_debug("LUN_RESET: Got t_transport_active = 0 for task: %p,"
|
||||||
" t_fe_count: %d dev: %p\n", task, fe_count, dev);
|
" t_fe_count: %d dev: %p\n", task, fe_count, dev);
|
||||||
atomic_set(&cmd->t_transport_aborted, 1);
|
atomic_set(&cmd->t_transport_aborted, 1);
|
||||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||||
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->execute_task_lock, flags);
|
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&dev->execute_task_lock, flags);
|
}
|
||||||
|
|
||||||
|
static void core_tmr_drain_cmd_list(
|
||||||
|
struct se_device *dev,
|
||||||
|
struct se_cmd *prout_cmd,
|
||||||
|
struct se_node_acl *tmr_nacl,
|
||||||
|
int tas,
|
||||||
|
struct list_head *preempt_and_abort_list)
|
||||||
|
{
|
||||||
|
LIST_HEAD(drain_cmd_list);
|
||||||
|
struct se_queue_obj *qobj = &dev->dev_queue_obj;
|
||||||
|
struct se_cmd *cmd, *tcmd;
|
||||||
|
unsigned long flags;
|
||||||
/*
|
/*
|
||||||
* Release all commands remaining in the struct se_device cmd queue.
|
* Release all commands remaining in the struct se_device cmd queue.
|
||||||
*
|
*
|
||||||
|
@ -337,11 +330,26 @@ int core_tmr_lun_reset(
|
||||||
*/
|
*/
|
||||||
if (prout_cmd == cmd)
|
if (prout_cmd == cmd)
|
||||||
continue;
|
continue;
|
||||||
|
/*
|
||||||
|
* Skip direct processing of TRANSPORT_FREE_CMD_INTR for
|
||||||
|
* HW target mode fabrics.
|
||||||
|
*/
|
||||||
|
spin_lock(&cmd->t_state_lock);
|
||||||
|
if (cmd->t_state == TRANSPORT_FREE_CMD_INTR) {
|
||||||
|
spin_unlock(&cmd->t_state_lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
spin_unlock(&cmd->t_state_lock);
|
||||||
|
|
||||||
atomic_dec(&cmd->t_transport_queue_active);
|
atomic_set(&cmd->t_transport_queue_active, 0);
|
||||||
atomic_dec(&qobj->queue_cnt);
|
atomic_dec(&qobj->queue_cnt);
|
||||||
list_del(&cmd->se_queue_node);
|
list_move_tail(&cmd->se_queue_node, &drain_cmd_list);
|
||||||
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
|
}
|
||||||
|
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
|
||||||
|
|
||||||
|
while (!list_empty(&drain_cmd_list)) {
|
||||||
|
cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node);
|
||||||
|
list_del_init(&cmd->se_queue_node);
|
||||||
|
|
||||||
pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
|
pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
|
||||||
" %d t_fe_count: %d\n", (preempt_and_abort_list) ?
|
" %d t_fe_count: %d\n", (preempt_and_abort_list) ?
|
||||||
|
@ -354,9 +362,53 @@ int core_tmr_lun_reset(
|
||||||
|
|
||||||
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
|
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
|
||||||
atomic_read(&cmd->t_fe_count));
|
atomic_read(&cmd->t_fe_count));
|
||||||
spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
|
}
|
||||||
|
|
||||||
|
int core_tmr_lun_reset(
|
||||||
|
struct se_device *dev,
|
||||||
|
struct se_tmr_req *tmr,
|
||||||
|
struct list_head *preempt_and_abort_list,
|
||||||
|
struct se_cmd *prout_cmd)
|
||||||
|
{
|
||||||
|
struct se_node_acl *tmr_nacl = NULL;
|
||||||
|
struct se_portal_group *tmr_tpg = NULL;
|
||||||
|
int tas;
|
||||||
|
/*
|
||||||
|
* TASK_ABORTED status bit, this is configurable via ConfigFS
|
||||||
|
* struct se_device attributes. spc4r17 section 7.4.6 Control mode page
|
||||||
|
*
|
||||||
|
* A task aborted status (TAS) bit set to zero specifies that aborted
|
||||||
|
* tasks shall be terminated by the device server without any response
|
||||||
|
* to the application client. A TAS bit set to one specifies that tasks
|
||||||
|
* aborted by the actions of an I_T nexus other than the I_T nexus on
|
||||||
|
* which the command was received shall be completed with TASK ABORTED
|
||||||
|
* status (see SAM-4).
|
||||||
|
*/
|
||||||
|
tas = dev->se_sub_dev->se_dev_attrib.emulate_tas;
|
||||||
|
/*
|
||||||
|
* Determine if this se_tmr is coming from a $FABRIC_MOD
|
||||||
|
* or struct se_device passthrough..
|
||||||
|
*/
|
||||||
|
if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
|
||||||
|
tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
|
||||||
|
tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
|
||||||
|
if (tmr_nacl && tmr_tpg) {
|
||||||
|
pr_debug("LUN_RESET: TMR caller fabric: %s"
|
||||||
|
" initiator port %s\n",
|
||||||
|
tmr_tpg->se_tpg_tfo->get_fabric_name(),
|
||||||
|
tmr_nacl->initiatorname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pr_debug("LUN_RESET: %s starting for [%s], tas: %d\n",
|
||||||
|
(preempt_and_abort_list) ? "Preempt" : "TMR",
|
||||||
|
dev->transport->name, tas);
|
||||||
|
|
||||||
|
core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
|
||||||
|
core_tmr_drain_task_list(dev, prout_cmd, tmr_nacl, tas,
|
||||||
|
preempt_and_abort_list);
|
||||||
|
core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas,
|
||||||
|
preempt_and_abort_list);
|
||||||
/*
|
/*
|
||||||
* Clear any legacy SPC-2 reservation when called during
|
* Clear any legacy SPC-2 reservation when called during
|
||||||
* LOGICAL UNIT RESET
|
* LOGICAL UNIT RESET
|
||||||
|
@ -379,3 +431,4 @@ int core_tmr_lun_reset(
|
||||||
dev->transport->name);
|
dev->transport->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,6 @@
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <linux/version.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -115,7 +114,7 @@ void ft_release_cmd(struct se_cmd *se_cmd)
|
||||||
|
|
||||||
void ft_check_stop_free(struct se_cmd *se_cmd)
|
void ft_check_stop_free(struct se_cmd *se_cmd)
|
||||||
{
|
{
|
||||||
transport_generic_free_cmd(se_cmd, 0, 0);
|
transport_generic_free_cmd(se_cmd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -268,9 +267,8 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
|
||||||
|
|
||||||
if (IS_ERR(fp)) {
|
if (IS_ERR(fp)) {
|
||||||
/* XXX need to find cmd if queued */
|
/* XXX need to find cmd if queued */
|
||||||
cmd->se_cmd.t_state = TRANSPORT_REMOVE;
|
|
||||||
cmd->seq = NULL;
|
cmd->seq = NULL;
|
||||||
transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
|
transport_generic_free_cmd(&cmd->se_cmd, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +286,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg)
|
||||||
__func__, fh->fh_r_ctl);
|
__func__, fh->fh_r_ctl);
|
||||||
ft_invl_hw_context(cmd);
|
ft_invl_hw_context(cmd);
|
||||||
fc_frame_free(fp);
|
fc_frame_free(fp);
|
||||||
transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
|
transport_generic_free_cmd(&cmd->se_cmd, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,7 +395,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("alloc tm cmd fn %d\n", tm_func);
|
pr_debug("alloc tm cmd fn %d\n", tm_func);
|
||||||
tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
|
tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func, GFP_KERNEL);
|
||||||
if (!tmr) {
|
if (!tmr) {
|
||||||
pr_debug("alloc failed\n");
|
pr_debug("alloc failed\n");
|
||||||
ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
|
ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
|
||||||
|
@ -421,7 +419,7 @@ static void ft_send_tm(struct ft_cmd *cmd)
|
||||||
sess = cmd->sess;
|
sess = cmd->sess;
|
||||||
transport_send_check_condition_and_sense(&cmd->se_cmd,
|
transport_send_check_condition_and_sense(&cmd->se_cmd,
|
||||||
cmd->se_cmd.scsi_sense_reason, 0);
|
cmd->se_cmd.scsi_sense_reason, 0);
|
||||||
transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
|
transport_generic_free_cmd(&cmd->se_cmd, 0);
|
||||||
ft_sess_put(sess);
|
ft_sess_put(sess);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -628,7 +626,7 @@ static void ft_send_work(struct work_struct *work)
|
||||||
if (ret == -ENOMEM) {
|
if (ret == -ENOMEM) {
|
||||||
transport_send_check_condition_and_sense(se_cmd,
|
transport_send_check_condition_and_sense(se_cmd,
|
||||||
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
|
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
|
||||||
transport_generic_free_cmd(se_cmd, 0, 0);
|
transport_generic_free_cmd(se_cmd, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ret == -EINVAL) {
|
if (ret == -EINVAL) {
|
||||||
|
@ -637,10 +635,10 @@ static void ft_send_work(struct work_struct *work)
|
||||||
else
|
else
|
||||||
transport_send_check_condition_and_sense(se_cmd,
|
transport_send_check_condition_and_sense(se_cmd,
|
||||||
se_cmd->scsi_sense_reason, 0);
|
se_cmd->scsi_sense_reason, 0);
|
||||||
transport_generic_free_cmd(se_cmd, 0, 0);
|
transport_generic_free_cmd(se_cmd, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
transport_generic_handle_cdb(se_cmd);
|
transport_handle_cdb_direct(se_cmd);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -32,6 +31,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/configfs.h>
|
#include <linux/configfs.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
|
@ -71,10 +71,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
|
||||||
{
|
{
|
||||||
const char *cp;
|
const char *cp;
|
||||||
char c;
|
char c;
|
||||||
u32 nibble;
|
|
||||||
u32 byte = 0;
|
u32 byte = 0;
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
u32 err;
|
u32 err;
|
||||||
|
int val;
|
||||||
|
|
||||||
*wwn = 0;
|
*wwn = 0;
|
||||||
for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
|
for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
|
||||||
|
@ -95,13 +95,10 @@ static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
|
||||||
return cp - name;
|
return cp - name;
|
||||||
}
|
}
|
||||||
err = 3;
|
err = 3;
|
||||||
if (isdigit(c))
|
val = hex_to_bin(c);
|
||||||
nibble = c - '0';
|
if (val < 0 || (strict && isupper(c)))
|
||||||
else if (isxdigit(c) && (islower(c) || !strict))
|
|
||||||
nibble = tolower(c) - 'a' + 10;
|
|
||||||
else
|
|
||||||
goto fail;
|
goto fail;
|
||||||
*wwn = (*wwn << 4) | nibble;
|
*wwn = (*wwn << 4) | val;
|
||||||
}
|
}
|
||||||
err = 4;
|
err = 4;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <generated/utsrelease.h>
|
#include <generated/utsrelease.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
|
@ -10,10 +10,7 @@
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
#define TARGET_CORE_MOD_VERSION "v4.1.0-rc1-ml"
|
#define TARGET_CORE_MOD_VERSION "v4.1.0-rc1-ml"
|
||||||
#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
|
|
||||||
|
|
||||||
/* Used by transport_generic_allocate_iovecs() */
|
|
||||||
#define TRANSPORT_IOV_DATA_BUFFER 5
|
|
||||||
/* Maximum Number of LUNs per Target Portal Group */
|
/* Maximum Number of LUNs per Target Portal Group */
|
||||||
/* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */
|
/* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */
|
||||||
#define TRANSPORT_MAX_LUNS_PER_TPG 256
|
#define TRANSPORT_MAX_LUNS_PER_TPG 256
|
||||||
|
@ -75,32 +72,26 @@ enum transport_tpg_type_table {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used for generate timer flags */
|
/* Used for generate timer flags */
|
||||||
enum timer_flags_table {
|
enum se_task_flags {
|
||||||
TF_RUNNING = 0x01,
|
TF_ACTIVE = (1 << 0),
|
||||||
TF_STOP = 0x02,
|
TF_SENT = (1 << 1),
|
||||||
|
TF_REQUEST_STOP = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Special transport agnostic struct se_cmd->t_states */
|
/* Special transport agnostic struct se_cmd->t_states */
|
||||||
enum transport_state_table {
|
enum transport_state_table {
|
||||||
TRANSPORT_NO_STATE = 0,
|
TRANSPORT_NO_STATE = 0,
|
||||||
TRANSPORT_NEW_CMD = 1,
|
TRANSPORT_NEW_CMD = 1,
|
||||||
TRANSPORT_DEFERRED_CMD = 2,
|
|
||||||
TRANSPORT_WRITE_PENDING = 3,
|
TRANSPORT_WRITE_PENDING = 3,
|
||||||
TRANSPORT_PROCESS_WRITE = 4,
|
TRANSPORT_PROCESS_WRITE = 4,
|
||||||
TRANSPORT_PROCESSING = 5,
|
TRANSPORT_PROCESSING = 5,
|
||||||
TRANSPORT_COMPLETE_OK = 6,
|
TRANSPORT_COMPLETE = 6,
|
||||||
TRANSPORT_COMPLETE_FAILURE = 7,
|
|
||||||
TRANSPORT_COMPLETE_TIMEOUT = 8,
|
|
||||||
TRANSPORT_PROCESS_TMR = 9,
|
TRANSPORT_PROCESS_TMR = 9,
|
||||||
TRANSPORT_TMR_COMPLETE = 10,
|
|
||||||
TRANSPORT_ISTATE_PROCESSING = 11,
|
TRANSPORT_ISTATE_PROCESSING = 11,
|
||||||
TRANSPORT_ISTATE_PROCESSED = 12,
|
|
||||||
TRANSPORT_KILL = 13,
|
|
||||||
TRANSPORT_REMOVE = 14,
|
|
||||||
TRANSPORT_FREE = 15,
|
|
||||||
TRANSPORT_NEW_CMD_MAP = 16,
|
TRANSPORT_NEW_CMD_MAP = 16,
|
||||||
TRANSPORT_FREE_CMD_INTR = 17,
|
TRANSPORT_FREE_CMD_INTR = 17,
|
||||||
TRANSPORT_COMPLETE_QF_WP = 18,
|
TRANSPORT_COMPLETE_QF_WP = 18,
|
||||||
|
TRANSPORT_COMPLETE_QF_OK = 19,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used for struct se_cmd->se_cmd_flags */
|
/* Used for struct se_cmd->se_cmd_flags */
|
||||||
|
@ -125,7 +116,6 @@ enum se_cmd_flags_table {
|
||||||
SCF_UNUSED = 0x00100000,
|
SCF_UNUSED = 0x00100000,
|
||||||
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
|
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
|
||||||
SCF_EMULATE_CDB_ASYNC = 0x01000000,
|
SCF_EMULATE_CDB_ASYNC = 0x01000000,
|
||||||
SCF_EMULATE_QUEUE_FULL = 0x02000000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
|
/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
|
||||||
|
@ -401,34 +391,22 @@ struct se_queue_obj {
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
struct se_task {
|
struct se_task {
|
||||||
unsigned char task_sense;
|
|
||||||
struct scatterlist *task_sg;
|
|
||||||
u32 task_sg_nents;
|
|
||||||
struct scatterlist *task_sg_bidi;
|
|
||||||
u8 task_scsi_status;
|
|
||||||
u8 task_flags;
|
|
||||||
int task_error_status;
|
|
||||||
int task_state_flags;
|
|
||||||
bool task_padded_sg;
|
|
||||||
unsigned long long task_lba;
|
unsigned long long task_lba;
|
||||||
u32 task_no;
|
u32 task_sectors;
|
||||||
u32 task_sectors;
|
u32 task_size;
|
||||||
u32 task_size;
|
struct se_cmd *task_se_cmd;
|
||||||
|
struct scatterlist *task_sg;
|
||||||
|
u32 task_sg_nents;
|
||||||
|
u16 task_flags;
|
||||||
|
u8 task_sense;
|
||||||
|
u8 task_scsi_status;
|
||||||
|
int task_error_status;
|
||||||
enum dma_data_direction task_data_direction;
|
enum dma_data_direction task_data_direction;
|
||||||
struct se_cmd *task_se_cmd;
|
atomic_t task_state_active;
|
||||||
struct se_device *se_dev;
|
struct list_head t_list;
|
||||||
|
struct list_head t_execute_list;
|
||||||
|
struct list_head t_state_list;
|
||||||
struct completion task_stop_comp;
|
struct completion task_stop_comp;
|
||||||
atomic_t task_active;
|
|
||||||
atomic_t task_execute_queue;
|
|
||||||
atomic_t task_timeout;
|
|
||||||
atomic_t task_sent;
|
|
||||||
atomic_t task_stop;
|
|
||||||
atomic_t task_state_active;
|
|
||||||
struct timer_list task_timer;
|
|
||||||
struct se_device *se_obj_ptr;
|
|
||||||
struct list_head t_list;
|
|
||||||
struct list_head t_execute_list;
|
|
||||||
struct list_head t_state_list;
|
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
struct se_cmd {
|
struct se_cmd {
|
||||||
|
@ -446,8 +424,6 @@ struct se_cmd {
|
||||||
int sam_task_attr;
|
int sam_task_attr;
|
||||||
/* Transport protocol dependent state, see transport_state_table */
|
/* Transport protocol dependent state, see transport_state_table */
|
||||||
enum transport_state_table t_state;
|
enum transport_state_table t_state;
|
||||||
/* Transport protocol dependent state for out of order CmdSNs */
|
|
||||||
int deferred_t_state;
|
|
||||||
/* Transport specific error status */
|
/* Transport specific error status */
|
||||||
int transport_error_status;
|
int transport_error_status;
|
||||||
/* See se_cmd_flags_table */
|
/* See se_cmd_flags_table */
|
||||||
|
@ -461,7 +437,6 @@ struct se_cmd {
|
||||||
u32 orig_fe_lun;
|
u32 orig_fe_lun;
|
||||||
/* Persistent Reservation key */
|
/* Persistent Reservation key */
|
||||||
u64 pr_res_key;
|
u64 pr_res_key;
|
||||||
atomic_t transport_sent;
|
|
||||||
/* Used for sense data */
|
/* Used for sense data */
|
||||||
void *sense_buffer;
|
void *sense_buffer;
|
||||||
struct list_head se_delayed_node;
|
struct list_head se_delayed_node;
|
||||||
|
@ -479,10 +454,7 @@ struct se_cmd {
|
||||||
struct list_head se_queue_node;
|
struct list_head se_queue_node;
|
||||||
struct target_core_fabric_ops *se_tfo;
|
struct target_core_fabric_ops *se_tfo;
|
||||||
int (*transport_emulate_cdb)(struct se_cmd *);
|
int (*transport_emulate_cdb)(struct se_cmd *);
|
||||||
void (*transport_split_cdb)(unsigned long long, u32, unsigned char *);
|
|
||||||
void (*transport_wait_for_tasks)(struct se_cmd *, int, int);
|
|
||||||
void (*transport_complete_callback)(struct se_cmd *);
|
void (*transport_complete_callback)(struct se_cmd *);
|
||||||
int (*transport_qf_callback)(struct se_cmd *);
|
|
||||||
|
|
||||||
unsigned char *t_task_cdb;
|
unsigned char *t_task_cdb;
|
||||||
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
|
unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
|
||||||
|
@ -495,7 +467,6 @@ struct se_cmd {
|
||||||
atomic_t t_se_count;
|
atomic_t t_se_count;
|
||||||
atomic_t t_task_cdbs_left;
|
atomic_t t_task_cdbs_left;
|
||||||
atomic_t t_task_cdbs_ex_left;
|
atomic_t t_task_cdbs_ex_left;
|
||||||
atomic_t t_task_cdbs_timeout_left;
|
|
||||||
atomic_t t_task_cdbs_sent;
|
atomic_t t_task_cdbs_sent;
|
||||||
atomic_t t_transport_aborted;
|
atomic_t t_transport_aborted;
|
||||||
atomic_t t_transport_active;
|
atomic_t t_transport_active;
|
||||||
|
@ -503,7 +474,6 @@ struct se_cmd {
|
||||||
atomic_t t_transport_queue_active;
|
atomic_t t_transport_queue_active;
|
||||||
atomic_t t_transport_sent;
|
atomic_t t_transport_sent;
|
||||||
atomic_t t_transport_stop;
|
atomic_t t_transport_stop;
|
||||||
atomic_t t_transport_timeout;
|
|
||||||
atomic_t transport_dev_active;
|
atomic_t transport_dev_active;
|
||||||
atomic_t transport_lun_active;
|
atomic_t transport_lun_active;
|
||||||
atomic_t transport_lun_fe_stop;
|
atomic_t transport_lun_fe_stop;
|
||||||
|
@ -514,6 +484,8 @@ struct se_cmd {
|
||||||
struct completion transport_lun_stop_comp;
|
struct completion transport_lun_stop_comp;
|
||||||
struct scatterlist *t_tasks_sg_chained;
|
struct scatterlist *t_tasks_sg_chained;
|
||||||
|
|
||||||
|
struct work_struct work;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used for pre-registered fabric SGL passthrough WRITE and READ
|
* Used for pre-registered fabric SGL passthrough WRITE and READ
|
||||||
* with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
|
* with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
|
||||||
|
@ -670,7 +642,6 @@ struct se_dev_attrib {
|
||||||
u32 optimal_sectors;
|
u32 optimal_sectors;
|
||||||
u32 hw_queue_depth;
|
u32 hw_queue_depth;
|
||||||
u32 queue_depth;
|
u32 queue_depth;
|
||||||
u32 task_timeout;
|
|
||||||
u32 max_unmap_lba_count;
|
u32 max_unmap_lba_count;
|
||||||
u32 max_unmap_block_desc_count;
|
u32 max_unmap_block_desc_count;
|
||||||
u32 unmap_granularity;
|
u32 unmap_granularity;
|
||||||
|
|
|
@ -27,7 +27,7 @@ enum tcm_tmrsp_table {
|
||||||
|
|
||||||
extern struct kmem_cache *se_tmr_req_cache;
|
extern struct kmem_cache *se_tmr_req_cache;
|
||||||
|
|
||||||
extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8);
|
extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
|
||||||
extern void core_tmr_release_req(struct se_tmr_req *);
|
extern void core_tmr_release_req(struct se_tmr_req *);
|
||||||
extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
|
extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
|
||||||
struct list_head *, struct se_cmd *);
|
struct list_head *, struct se_cmd *);
|
||||||
|
|
|
@ -22,10 +22,9 @@
|
||||||
#define PYX_TRANSPORT_LU_COMM_FAILURE -7
|
#define PYX_TRANSPORT_LU_COMM_FAILURE -7
|
||||||
#define PYX_TRANSPORT_UNKNOWN_MODE_PAGE -8
|
#define PYX_TRANSPORT_UNKNOWN_MODE_PAGE -8
|
||||||
#define PYX_TRANSPORT_WRITE_PROTECTED -9
|
#define PYX_TRANSPORT_WRITE_PROTECTED -9
|
||||||
#define PYX_TRANSPORT_TASK_TIMEOUT -10
|
#define PYX_TRANSPORT_RESERVATION_CONFLICT -10
|
||||||
#define PYX_TRANSPORT_RESERVATION_CONFLICT -11
|
#define PYX_TRANSPORT_ILLEGAL_REQUEST -11
|
||||||
#define PYX_TRANSPORT_ILLEGAL_REQUEST -12
|
#define PYX_TRANSPORT_USE_SENSE_REASON -12
|
||||||
#define PYX_TRANSPORT_USE_SENSE_REASON -13
|
|
||||||
|
|
||||||
#ifndef SAM_STAT_RESERVATION_CONFLICT
|
#ifndef SAM_STAT_RESERVATION_CONFLICT
|
||||||
#define SAM_STAT_RESERVATION_CONFLICT 0x18
|
#define SAM_STAT_RESERVATION_CONFLICT 0x18
|
||||||
|
@ -38,16 +37,6 @@
|
||||||
#define TRANSPORT_PLUGIN_VHBA_PDEV 2
|
#define TRANSPORT_PLUGIN_VHBA_PDEV 2
|
||||||
#define TRANSPORT_PLUGIN_VHBA_VDEV 3
|
#define TRANSPORT_PLUGIN_VHBA_VDEV 3
|
||||||
|
|
||||||
/* For SE OBJ Plugins, in seconds */
|
|
||||||
#define TRANSPORT_TIMEOUT_TUR 10
|
|
||||||
#define TRANSPORT_TIMEOUT_TYPE_DISK 60
|
|
||||||
#define TRANSPORT_TIMEOUT_TYPE_ROM 120
|
|
||||||
#define TRANSPORT_TIMEOUT_TYPE_TAPE 600
|
|
||||||
#define TRANSPORT_TIMEOUT_TYPE_OTHER 300
|
|
||||||
|
|
||||||
/* For se_task->task_state_flags */
|
|
||||||
#define TSF_EXCEPTION_CLEARED 0x01
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct se_subsystem_dev->su_dev_flags
|
* struct se_subsystem_dev->su_dev_flags
|
||||||
*/
|
*/
|
||||||
|
@ -64,8 +53,6 @@
|
||||||
#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004
|
#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004
|
||||||
|
|
||||||
/* struct se_dev_attrib sanity values */
|
/* struct se_dev_attrib sanity values */
|
||||||
/* 10 Minutes */
|
|
||||||
#define DA_TASK_TIMEOUT_MAX 600
|
|
||||||
/* Default max_unmap_lba_count */
|
/* Default max_unmap_lba_count */
|
||||||
#define DA_MAX_UNMAP_LBA_COUNT 0
|
#define DA_MAX_UNMAP_LBA_COUNT 0
|
||||||
/* Default max_unmap_block_desc_count */
|
/* Default max_unmap_block_desc_count */
|
||||||
|
@ -110,16 +97,13 @@
|
||||||
|
|
||||||
#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs))
|
#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs))
|
||||||
|
|
||||||
struct se_mem;
|
|
||||||
struct se_subsystem_api;
|
struct se_subsystem_api;
|
||||||
|
|
||||||
extern struct kmem_cache *se_mem_cache;
|
|
||||||
|
|
||||||
extern int init_se_kmem_caches(void);
|
extern int init_se_kmem_caches(void);
|
||||||
extern void release_se_kmem_caches(void);
|
extern void release_se_kmem_caches(void);
|
||||||
extern u32 scsi_get_new_index(scsi_index_t);
|
extern u32 scsi_get_new_index(scsi_index_t);
|
||||||
extern void transport_init_queue_obj(struct se_queue_obj *);
|
extern void transport_init_queue_obj(struct se_queue_obj *);
|
||||||
extern int transport_subsystem_check_init(void);
|
extern void transport_subsystem_check_init(void);
|
||||||
extern int transport_subsystem_register(struct se_subsystem_api *);
|
extern int transport_subsystem_register(struct se_subsystem_api *);
|
||||||
extern void transport_subsystem_release(struct se_subsystem_api *);
|
extern void transport_subsystem_release(struct se_subsystem_api *);
|
||||||
extern void transport_load_plugins(void);
|
extern void transport_load_plugins(void);
|
||||||
|
@ -134,7 +118,6 @@ extern void transport_free_session(struct se_session *);
|
||||||
extern void transport_deregister_session_configfs(struct se_session *);
|
extern void transport_deregister_session_configfs(struct se_session *);
|
||||||
extern void transport_deregister_session(struct se_session *);
|
extern void transport_deregister_session(struct se_session *);
|
||||||
extern void transport_cmd_finish_abort(struct se_cmd *, int);
|
extern void transport_cmd_finish_abort(struct se_cmd *, int);
|
||||||
extern void transport_cmd_finish_abort_tmr(struct se_cmd *);
|
|
||||||
extern void transport_complete_sync_cache(struct se_cmd *, int);
|
extern void transport_complete_sync_cache(struct se_cmd *, int);
|
||||||
extern void transport_complete_task(struct se_task *, int);
|
extern void transport_complete_task(struct se_task *, int);
|
||||||
extern void transport_add_task_to_execute_queue(struct se_task *,
|
extern void transport_add_task_to_execute_queue(struct se_task *,
|
||||||
|
@ -142,6 +125,8 @@ extern void transport_add_task_to_execute_queue(struct se_task *,
|
||||||
struct se_device *);
|
struct se_device *);
|
||||||
extern void transport_remove_task_from_execute_queue(struct se_task *,
|
extern void transport_remove_task_from_execute_queue(struct se_task *,
|
||||||
struct se_device *);
|
struct se_device *);
|
||||||
|
extern void __transport_remove_task_from_execute_queue(struct se_task *,
|
||||||
|
struct se_device *);
|
||||||
unsigned char *transport_dump_cmd_direction(struct se_cmd *);
|
unsigned char *transport_dump_cmd_direction(struct se_cmd *);
|
||||||
extern void transport_dump_dev_state(struct se_device *, char *, int *);
|
extern void transport_dump_dev_state(struct se_device *, char *, int *);
|
||||||
extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
|
extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
|
||||||
|
@ -169,29 +154,24 @@ extern void transport_init_se_cmd(struct se_cmd *,
|
||||||
unsigned char *);
|
unsigned char *);
|
||||||
void *transport_kmap_first_data_page(struct se_cmd *cmd);
|
void *transport_kmap_first_data_page(struct se_cmd *cmd);
|
||||||
void transport_kunmap_first_data_page(struct se_cmd *cmd);
|
void transport_kunmap_first_data_page(struct se_cmd *cmd);
|
||||||
extern void transport_free_se_cmd(struct se_cmd *);
|
|
||||||
extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
|
extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
|
||||||
extern int transport_generic_handle_cdb(struct se_cmd *);
|
|
||||||
extern int transport_handle_cdb_direct(struct se_cmd *);
|
extern int transport_handle_cdb_direct(struct se_cmd *);
|
||||||
extern int transport_generic_handle_cdb_map(struct se_cmd *);
|
extern int transport_generic_handle_cdb_map(struct se_cmd *);
|
||||||
extern int transport_generic_handle_data(struct se_cmd *);
|
extern int transport_generic_handle_data(struct se_cmd *);
|
||||||
extern void transport_new_cmd_failure(struct se_cmd *);
|
extern void transport_new_cmd_failure(struct se_cmd *);
|
||||||
extern int transport_generic_handle_tmr(struct se_cmd *);
|
extern int transport_generic_handle_tmr(struct se_cmd *);
|
||||||
extern void transport_generic_free_cmd_intr(struct se_cmd *);
|
extern void transport_generic_free_cmd_intr(struct se_cmd *);
|
||||||
extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
|
extern bool target_stop_task(struct se_task *task, unsigned long *flags);
|
||||||
extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
|
extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
|
||||||
struct scatterlist *, u32);
|
struct scatterlist *, u32);
|
||||||
extern int transport_clear_lun_from_sessions(struct se_lun *);
|
extern int transport_clear_lun_from_sessions(struct se_lun *);
|
||||||
|
extern void transport_wait_for_tasks(struct se_cmd *);
|
||||||
extern int transport_check_aborted_status(struct se_cmd *, int);
|
extern int transport_check_aborted_status(struct se_cmd *, int);
|
||||||
extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
|
extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
|
||||||
extern void transport_send_task_abort(struct se_cmd *);
|
extern void transport_send_task_abort(struct se_cmd *);
|
||||||
extern void transport_release_cmd(struct se_cmd *);
|
extern void transport_release_cmd(struct se_cmd *);
|
||||||
extern void transport_generic_free_cmd(struct se_cmd *, int, int);
|
extern void transport_generic_free_cmd(struct se_cmd *, int);
|
||||||
extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
|
extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
|
||||||
extern int transport_init_task_sg(struct se_task *, struct se_mem *, u32);
|
|
||||||
extern int transport_map_mem_to_sg(struct se_task *, struct list_head *,
|
|
||||||
struct scatterlist *, struct se_mem *,
|
|
||||||
struct se_mem **, u32 *, u32 *);
|
|
||||||
extern void transport_do_task_sg_chain(struct se_cmd *);
|
extern void transport_do_task_sg_chain(struct se_cmd *);
|
||||||
extern void transport_generic_process_write(struct se_cmd *);
|
extern void transport_generic_process_write(struct se_cmd *);
|
||||||
extern int transport_generic_new_cmd(struct se_cmd *);
|
extern int transport_generic_new_cmd(struct se_cmd *);
|
||||||
|
@ -200,6 +180,7 @@ extern int transport_generic_do_tmr(struct se_cmd *);
|
||||||
extern int core_alua_check_nonop_delay(struct se_cmd *);
|
extern int core_alua_check_nonop_delay(struct se_cmd *);
|
||||||
/* From target_core_cdb.c */
|
/* From target_core_cdb.c */
|
||||||
extern int transport_emulate_control_cdb(struct se_task *);
|
extern int transport_emulate_control_cdb(struct se_task *);
|
||||||
|
extern void target_get_task_cdb(struct se_task *task, unsigned char *cdb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each se_transport_task_t can have N number of possible struct se_task's
|
* Each se_transport_task_t can have N number of possible struct se_task's
|
||||||
|
@ -227,6 +208,10 @@ struct se_subsystem_api {
|
||||||
* Transport Type.
|
* Transport Type.
|
||||||
*/
|
*/
|
||||||
u8 transport_type;
|
u8 transport_type;
|
||||||
|
|
||||||
|
unsigned int fua_write_emulated : 1;
|
||||||
|
unsigned int write_cache_emulated : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct module for struct se_hba references
|
* struct module for struct se_hba references
|
||||||
*/
|
*/
|
||||||
|
@ -235,18 +220,6 @@ struct se_subsystem_api {
|
||||||
* Used for global se_subsystem_api list_head
|
* Used for global se_subsystem_api list_head
|
||||||
*/
|
*/
|
||||||
struct list_head sub_api_list;
|
struct list_head sub_api_list;
|
||||||
/*
|
|
||||||
* For SCF_SCSI_NON_DATA_CDB
|
|
||||||
*/
|
|
||||||
int (*cdb_none)(struct se_task *);
|
|
||||||
/*
|
|
||||||
* For SCF_SCSI_DATA_SG_IO_CDB
|
|
||||||
*/
|
|
||||||
int (*map_data_SG)(struct se_task *);
|
|
||||||
/*
|
|
||||||
* For SCF_SCSI_CONTROL_SG_IO_CDB
|
|
||||||
*/
|
|
||||||
int (*map_control_SG)(struct se_task *);
|
|
||||||
/*
|
/*
|
||||||
* attach_hba():
|
* attach_hba():
|
||||||
*/
|
*/
|
||||||
|
@ -274,22 +247,6 @@ struct se_subsystem_api {
|
||||||
*/
|
*/
|
||||||
void (*free_device)(void *);
|
void (*free_device)(void *);
|
||||||
|
|
||||||
/*
|
|
||||||
* dpo_emulated():
|
|
||||||
*/
|
|
||||||
int (*dpo_emulated)(struct se_device *);
|
|
||||||
/*
|
|
||||||
* fua_write_emulated():
|
|
||||||
*/
|
|
||||||
int (*fua_write_emulated)(struct se_device *);
|
|
||||||
/*
|
|
||||||
* fua_read_emulated():
|
|
||||||
*/
|
|
||||||
int (*fua_read_emulated)(struct se_device *);
|
|
||||||
/*
|
|
||||||
* write_cache_emulated():
|
|
||||||
*/
|
|
||||||
int (*write_cache_emulated)(struct se_device *);
|
|
||||||
/*
|
/*
|
||||||
* transport_complete():
|
* transport_complete():
|
||||||
*
|
*
|
||||||
|
@ -330,10 +287,6 @@ struct se_subsystem_api {
|
||||||
*/
|
*/
|
||||||
ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
|
ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
|
||||||
char *);
|
char *);
|
||||||
/*
|
|
||||||
* get_cdb():
|
|
||||||
*/
|
|
||||||
unsigned char *(*get_cdb)(struct se_task *);
|
|
||||||
/*
|
/*
|
||||||
* get_device_rev():
|
* get_device_rev():
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue