You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger:
"It's been usually busy for summer, with most of the efforts centered
around TCMU developments and various target-core + fabric driver bug
fixing activities. Not particularly large in terms of LoC, but lots of
smaller patches from many different folks.
The highlights include:
- ibmvscsis logical partition manager support (Michael Cyr + Bryant
Ly)
- Convert target/iblock WRITE_SAME to blkdev_issue_zeroout (hch +
nab)
- Add support for TMR percpu LUN reference counting (nab)
- Fix a potential deadlock between EXTENDED_COPY and iscsi shutdown
(Bart)
- Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce (Jiang Yi)
- Fix TMCU module removal (Xiubo Li)
- Fix iser-target OOPs during login failure (Andrea Righi + Sagi)
- Breakup target-core free_device backend driver callback (mnc)
- Perform TCMU add/delete/reconfig synchronously (mnc)
- Fix TCMU multiple UIO open/close sequences (mnc)
- Fix TCMU CHECK_CONDITION sense handling (mnc)
- Fix target-core SAM_STAT_BUSY + TASK_SET_FULL handling (mnc + nab)
- Introduce TYPE_ZBC support in PSCSI (Damien Le Moal)
- Fix possible TCMU memory leak + OOPs when recalculating cmd base
size (Xiubo Li + Bryant Ly + Damien Le Moal + mnc)
- Add login_keys_workaround attribute for non RFC initiators (Robert
LeBlanc + Arun Easi + nab)"
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (68 commits)
iscsi-target: Add login_keys_workaround attribute for non RFC initiators
Revert "qla2xxx: Fix incorrect tcm_qla2xxx_free_cmd use during TMR ABORT"
tcmu: clean up the code and with one small fix
tcmu: Fix possbile memory leak / OOPs when recalculating cmd base size
target: export lio pgr/alua support as device attr
target: Fix return sense reason in target_scsi3_emulate_pr_out
target: Fix cmd size for PR-OUT in passthrough_parse_cdb
tcmu: Fix dev_config_store
target: pscsi: Introduce TYPE_ZBC support
target: Use macro for WRITE_VERIFY_32 operation codes
target: fix SAM_STAT_BUSY/TASK_SET_FULL handling
target: remove transport_complete
pscsi: finish cmd processing from pscsi_req_done
tcmu: fix sense handling during completion
target: add helper to copy sense to se_cmd buffer
target: do not require a transport_complete for SCF_TRANSPORT_TASK_SENSE
target: make device_mutex and device_list static
tcmu: Fix flushing cmd entry dcache page
tcmu: fix multiple uio open/close sequences
tcmu: drop configured check in destroy
...
This commit is contained in:
@@ -1452,7 +1452,7 @@ static void
|
||||
isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
{
|
||||
struct isert_conn *isert_conn = wc->qp->qp_context;
|
||||
struct ib_device *ib_dev = isert_conn->cm_id->device;
|
||||
struct ib_device *ib_dev = isert_conn->device->ib_device;
|
||||
|
||||
if (unlikely(wc->status != IB_WC_SUCCESS)) {
|
||||
isert_print_wc(wc, "login recv");
|
||||
|
||||
@@ -1157,8 +1157,8 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx)
|
||||
}
|
||||
spin_unlock_irqrestore(&ioctx->spinlock, flags);
|
||||
|
||||
pr_debug("Aborting cmd with state %d and tag %lld\n", state,
|
||||
ioctx->cmd.tag);
|
||||
pr_debug("Aborting cmd with state %d -> %d and tag %lld\n", state,
|
||||
ioctx->state, ioctx->cmd.tag);
|
||||
|
||||
switch (state) {
|
||||
case SRPT_STATE_NEW:
|
||||
|
||||
@@ -155,6 +155,9 @@ static long ibmvscsis_unregister_command_q(struct scsi_info *vscsi)
|
||||
qrc = h_free_crq(vscsi->dds.unit_id);
|
||||
switch (qrc) {
|
||||
case H_SUCCESS:
|
||||
spin_lock_bh(&vscsi->intr_lock);
|
||||
vscsi->flags &= ~PREP_FOR_SUSPEND_FLAGS;
|
||||
spin_unlock_bh(&vscsi->intr_lock);
|
||||
break;
|
||||
|
||||
case H_HARDWARE:
|
||||
@@ -422,6 +425,9 @@ static void ibmvscsis_disconnect(struct work_struct *work)
|
||||
new_state = vscsi->new_state;
|
||||
vscsi->new_state = 0;
|
||||
|
||||
vscsi->flags |= DISCONNECT_SCHEDULED;
|
||||
vscsi->flags &= ~SCHEDULE_DISCONNECT;
|
||||
|
||||
pr_debug("disconnect: flags 0x%x, state 0x%hx\n", vscsi->flags,
|
||||
vscsi->state);
|
||||
|
||||
@@ -802,6 +808,13 @@ static long ibmvscsis_establish_new_q(struct scsi_info *vscsi)
|
||||
long rc = ADAPT_SUCCESS;
|
||||
uint format;
|
||||
|
||||
rc = h_vioctl(vscsi->dds.unit_id, H_ENABLE_PREPARE_FOR_SUSPEND, 30000,
|
||||
0, 0, 0, 0);
|
||||
if (rc == H_SUCCESS)
|
||||
vscsi->flags |= PREP_FOR_SUSPEND_ENABLED;
|
||||
else if (rc != H_NOT_FOUND)
|
||||
pr_err("Error from Enable Prepare for Suspend: %ld\n", rc);
|
||||
|
||||
vscsi->flags &= PRESERVE_FLAG_FIELDS;
|
||||
vscsi->rsp_q_timer.timer_pops = 0;
|
||||
vscsi->debit = 0;
|
||||
@@ -950,6 +963,63 @@ static void ibmvscsis_free_cmd_resources(struct scsi_info *vscsi,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvscsis_ready_for_suspend() - Helper function to call VIOCTL
|
||||
* @vscsi: Pointer to our adapter structure
|
||||
* @idle: Indicates whether we were called from adapter_idle. This
|
||||
* is important to know if we need to do a disconnect, since if
|
||||
* we're called from adapter_idle, we're still processing the
|
||||
* current disconnect, so we can't just call post_disconnect.
|
||||
*
|
||||
* This function is called when the adapter is idle when phyp has sent
|
||||
* us a Prepare for Suspend Transport Event.
|
||||
*
|
||||
* EXECUTION ENVIRONMENT:
|
||||
* Process or interrupt environment called with interrupt lock held
|
||||
*/
|
||||
static long ibmvscsis_ready_for_suspend(struct scsi_info *vscsi, bool idle)
|
||||
{
|
||||
long rc = 0;
|
||||
struct viosrp_crq *crq;
|
||||
|
||||
/* See if there is a Resume event in the queue */
|
||||
crq = vscsi->cmd_q.base_addr + vscsi->cmd_q.index;
|
||||
|
||||
pr_debug("ready_suspend: flags 0x%x, state 0x%hx crq_valid:%x\n",
|
||||
vscsi->flags, vscsi->state, (int)crq->valid);
|
||||
|
||||
if (!(vscsi->flags & PREP_FOR_SUSPEND_ABORTED) && !(crq->valid)) {
|
||||
rc = h_vioctl(vscsi->dds.unit_id, H_READY_FOR_SUSPEND, 0, 0, 0,
|
||||
0, 0);
|
||||
if (rc) {
|
||||
pr_err("Ready for Suspend Vioctl failed: %ld\n", rc);
|
||||
rc = 0;
|
||||
}
|
||||
} else if (((vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE) &&
|
||||
(vscsi->flags & PREP_FOR_SUSPEND_ABORTED)) ||
|
||||
((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
|
||||
(crq->format != RESUME_FROM_SUSP)))) {
|
||||
if (idle) {
|
||||
vscsi->state = ERR_DISCONNECT_RECONNECT;
|
||||
ibmvscsis_reset_queue(vscsi);
|
||||
rc = -1;
|
||||
} else if (vscsi->state == CONNECTED) {
|
||||
ibmvscsis_post_disconnect(vscsi,
|
||||
ERR_DISCONNECT_RECONNECT, 0);
|
||||
}
|
||||
|
||||
vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
|
||||
|
||||
if ((crq->valid) && ((crq->valid != VALID_TRANS_EVENT) ||
|
||||
(crq->format != RESUME_FROM_SUSP)))
|
||||
pr_err("Invalid element in CRQ after Prepare for Suspend");
|
||||
}
|
||||
|
||||
vscsi->flags &= ~(PREP_FOR_SUSPEND_PENDING | PREP_FOR_SUSPEND_ABORTED);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvscsis_trans_event() - Handle a Transport Event
|
||||
* @vscsi: Pointer to our adapter structure
|
||||
@@ -974,18 +1044,8 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
|
||||
case PARTNER_FAILED:
|
||||
case PARTNER_DEREGISTER:
|
||||
ibmvscsis_delete_client_info(vscsi, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = ERROR;
|
||||
dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
|
||||
(uint)crq->format);
|
||||
ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
|
||||
RESPONSE_Q_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == ADAPT_SUCCESS) {
|
||||
if (crq->format == MIGRATED)
|
||||
vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
|
||||
switch (vscsi->state) {
|
||||
case NO_QUEUE:
|
||||
case ERR_DISCONNECTED:
|
||||
@@ -1034,6 +1094,60 @@ static long ibmvscsis_trans_event(struct scsi_info *vscsi,
|
||||
vscsi->flags |= (RESPONSE_Q_DOWN | TRANS_EVENT);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PREPARE_FOR_SUSPEND:
|
||||
pr_debug("Prep for Suspend, crq status = 0x%x\n",
|
||||
(int)crq->status);
|
||||
switch (vscsi->state) {
|
||||
case ERR_DISCONNECTED:
|
||||
case WAIT_CONNECTION:
|
||||
case CONNECTED:
|
||||
ibmvscsis_ready_for_suspend(vscsi, false);
|
||||
break;
|
||||
case SRP_PROCESSING:
|
||||
vscsi->resume_state = vscsi->state;
|
||||
vscsi->flags |= PREP_FOR_SUSPEND_PENDING;
|
||||
if (crq->status == CRQ_ENTRY_OVERWRITTEN)
|
||||
vscsi->flags |= PREP_FOR_SUSPEND_OVERWRITE;
|
||||
ibmvscsis_post_disconnect(vscsi, WAIT_IDLE, 0);
|
||||
break;
|
||||
case NO_QUEUE:
|
||||
case UNDEFINED:
|
||||
case UNCONFIGURING:
|
||||
case WAIT_ENABLED:
|
||||
case ERR_DISCONNECT:
|
||||
case ERR_DISCONNECT_RECONNECT:
|
||||
case WAIT_IDLE:
|
||||
pr_err("Invalid state for Prepare for Suspend Trans Event: 0x%x\n",
|
||||
vscsi->state);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RESUME_FROM_SUSP:
|
||||
pr_debug("Resume from Suspend, crq status = 0x%x\n",
|
||||
(int)crq->status);
|
||||
if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
|
||||
vscsi->flags |= PREP_FOR_SUSPEND_ABORTED;
|
||||
} else {
|
||||
if ((crq->status == CRQ_ENTRY_OVERWRITTEN) ||
|
||||
(vscsi->flags & PREP_FOR_SUSPEND_OVERWRITE)) {
|
||||
ibmvscsis_post_disconnect(vscsi,
|
||||
ERR_DISCONNECT_RECONNECT,
|
||||
0);
|
||||
vscsi->flags &= ~PREP_FOR_SUSPEND_OVERWRITE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = ERROR;
|
||||
dev_err(&vscsi->dev, "trans_event: invalid format %d\n",
|
||||
(uint)crq->format);
|
||||
ibmvscsis_post_disconnect(vscsi, ERR_DISCONNECT,
|
||||
RESPONSE_Q_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = vscsi->flags & SCHEDULE_DISCONNECT;
|
||||
@@ -1201,6 +1315,7 @@ static struct ibmvscsis_cmd *ibmvscsis_get_free_cmd(struct scsi_info *vscsi)
|
||||
static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
|
||||
{
|
||||
int free_qs = false;
|
||||
long rc = 0;
|
||||
|
||||
pr_debug("adapter_idle: flags 0x%x, state 0x%hx\n", vscsi->flags,
|
||||
vscsi->state);
|
||||
@@ -1240,7 +1355,14 @@ static void ibmvscsis_adapter_idle(struct scsi_info *vscsi)
|
||||
vscsi->rsp_q_timer.timer_pops = 0;
|
||||
vscsi->debit = 0;
|
||||
vscsi->credit = 0;
|
||||
if (vscsi->flags & TRANS_EVENT) {
|
||||
if (vscsi->flags & PREP_FOR_SUSPEND_PENDING) {
|
||||
vscsi->state = vscsi->resume_state;
|
||||
vscsi->resume_state = 0;
|
||||
rc = ibmvscsis_ready_for_suspend(vscsi, true);
|
||||
vscsi->flags &= ~DISCONNECT_SCHEDULED;
|
||||
if (rc)
|
||||
break;
|
||||
} else if (vscsi->flags & TRANS_EVENT) {
|
||||
vscsi->state = WAIT_CONNECTION;
|
||||
vscsi->flags &= PRESERVE_FLAG_FIELDS;
|
||||
} else {
|
||||
@@ -3792,8 +3914,16 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn,
|
||||
{
|
||||
struct ibmvscsis_tport *tport =
|
||||
container_of(wwn, struct ibmvscsis_tport, tport_wwn);
|
||||
u16 tpgt;
|
||||
int rc;
|
||||
|
||||
if (strstr(name, "tpgt_") != name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
rc = kstrtou16(name + 5, 0, &tpgt);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
tport->tport_tpgt = tpgt;
|
||||
|
||||
tport->releasing = false;
|
||||
|
||||
rc = core_tpg_register(&tport->tport_wwn, &tport->se_tpg,
|
||||
|
||||
@@ -262,6 +262,14 @@ struct scsi_info {
|
||||
#define DISCONNECT_SCHEDULED 0x00800
|
||||
/* remove function is sleeping */
|
||||
#define CFG_SLEEPING 0x01000
|
||||
/* Register for Prepare for Suspend Transport Events */
|
||||
#define PREP_FOR_SUSPEND_ENABLED 0x02000
|
||||
/* Prepare for Suspend event sent */
|
||||
#define PREP_FOR_SUSPEND_PENDING 0x04000
|
||||
/* Resume from Suspend event sent */
|
||||
#define PREP_FOR_SUSPEND_ABORTED 0x08000
|
||||
/* Prepare for Suspend event overwrote another CRQ entry */
|
||||
#define PREP_FOR_SUSPEND_OVERWRITE 0x10000
|
||||
u32 flags;
|
||||
/* adapter lock */
|
||||
spinlock_t intr_lock;
|
||||
@@ -272,6 +280,7 @@ struct scsi_info {
|
||||
/* used in crq, to tag what iu the response is for */
|
||||
u64 empty_iu_tag;
|
||||
uint new_state;
|
||||
uint resume_state;
|
||||
/* control block for the response queue timer */
|
||||
struct timer_cb rsp_q_timer;
|
||||
/* keep last client to enable proper accounting */
|
||||
@@ -324,8 +333,13 @@ struct scsi_info {
|
||||
#define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \
|
||||
((VSCSI)->flags & BLOCK))
|
||||
|
||||
#define PREP_FOR_SUSPEND_FLAGS (PREP_FOR_SUSPEND_ENABLED | \
|
||||
PREP_FOR_SUSPEND_PENDING | \
|
||||
PREP_FOR_SUSPEND_ABORTED | \
|
||||
PREP_FOR_SUSPEND_OVERWRITE)
|
||||
|
||||
/* flag bit that are not reset during disconnect */
|
||||
#define PRESERVE_FLAG_FIELDS 0
|
||||
#define PRESERVE_FLAG_FIELDS (PREP_FOR_SUSPEND_FLAGS)
|
||||
|
||||
#define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))
|
||||
|
||||
@@ -333,8 +347,15 @@ struct scsi_info {
|
||||
#define WRITE_CMD(cdb) (((cdb)[0] & 0x1F) == 0xA)
|
||||
|
||||
#ifndef H_GET_PARTNER_INFO
|
||||
#define H_GET_PARTNER_INFO 0x0000000000000008LL
|
||||
#define H_GET_PARTNER_INFO 0x0000000000000008LL
|
||||
#endif
|
||||
#ifndef H_ENABLE_PREPARE_FOR_SUSPEND
|
||||
#define H_ENABLE_PREPARE_FOR_SUSPEND 0x000000000000001DLL
|
||||
#endif
|
||||
#ifndef H_READY_FOR_SUSPEND
|
||||
#define H_READY_FOR_SUSPEND 0x000000000000001ELL
|
||||
#endif
|
||||
|
||||
|
||||
#define h_copy_rdma(l, sa, sb, da, db) \
|
||||
plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
|
||||
|
||||
@@ -30,10 +30,13 @@ enum srp_trans_event {
|
||||
UNUSED_FORMAT = 0,
|
||||
PARTNER_FAILED = 1,
|
||||
PARTNER_DEREGISTER = 2,
|
||||
MIGRATED = 6
|
||||
MIGRATED = 6,
|
||||
PREPARE_FOR_SUSPEND = 9,
|
||||
RESUME_FROM_SUSP = 0xA
|
||||
};
|
||||
|
||||
enum srp_status {
|
||||
CRQ_ENTRY_OVERWRITTEN = 0x20,
|
||||
HEADER_DESCRIPTOR = 0xF1,
|
||||
PING = 0xF5,
|
||||
PING_RESPONSE = 0xF6
|
||||
|
||||
@@ -1874,36 +1874,13 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
|
||||
struct abts_recv_from_24xx *abts, struct fc_port *sess)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct se_session *se_sess = sess->se_sess;
|
||||
struct qla_tgt_mgmt_cmd *mcmd;
|
||||
struct qla_tgt_cmd *cmd;
|
||||
struct se_cmd *se_cmd;
|
||||
int rc;
|
||||
bool found_lun = false;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
||||
list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) {
|
||||
if (se_cmd->tag == abts->exchange_addr_to_abort) {
|
||||
found_lun = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
||||
|
||||
/* cmd not in LIO lists, look in qla list */
|
||||
if (!found_lun) {
|
||||
if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
|
||||
/* send TASK_ABORT response immediately */
|
||||
qlt_24xx_send_abts_resp(ha->base_qpair, abts,
|
||||
FCP_TMF_CMPL, false);
|
||||
return 0;
|
||||
} else {
|
||||
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081,
|
||||
"unable to find cmd in driver or LIO for tag 0x%x\n",
|
||||
abts->exchange_addr_to_abort);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
|
||||
/* send TASK_ABORT response immediately */
|
||||
qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
|
||||
@@ -1919,14 +1896,17 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
|
||||
}
|
||||
memset(mcmd, 0, sizeof(*mcmd));
|
||||
|
||||
cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
|
||||
mcmd->sess = sess;
|
||||
memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts));
|
||||
mcmd->reset_count = ha->base_qpair->chip_reset;
|
||||
mcmd->tmr_func = QLA_TGT_ABTS;
|
||||
mcmd->qpair = ha->base_qpair;
|
||||
|
||||
rc = ha->tgt.tgt_ops->handle_tmr(mcmd, cmd->unpacked_lun, mcmd->tmr_func,
|
||||
/*
|
||||
* LUN is looked up by target-core internally based on the passed
|
||||
* abts->exchange_addr_to_abort tag.
|
||||
*/
|
||||
rc = ha->tgt.tgt_ops->handle_tmr(mcmd, 0, mcmd->tmr_func,
|
||||
abts->exchange_addr_to_abort);
|
||||
if (rc != 0) {
|
||||
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf052,
|
||||
|
||||
@@ -600,11 +600,13 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun,
|
||||
struct fc_port *sess = mcmd->sess;
|
||||
struct se_cmd *se_cmd = &mcmd->se_cmd;
|
||||
int transl_tmr_func = 0;
|
||||
int flags = TARGET_SCF_ACK_KREF;
|
||||
|
||||
switch (tmr_func) {
|
||||
case QLA_TGT_ABTS:
|
||||
pr_debug("%ld: ABTS received\n", sess->vha->host_no);
|
||||
transl_tmr_func = TMR_ABORT_TASK;
|
||||
flags |= TARGET_SCF_LOOKUP_LUN_FROM_TAG;
|
||||
break;
|
||||
case QLA_TGT_2G_ABORT_TASK:
|
||||
pr_debug("%ld: 2G Abort Task received\n", sess->vha->host_no);
|
||||
@@ -637,7 +639,7 @@ static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, u64 lun,
|
||||
}
|
||||
|
||||
return target_submit_tmr(se_cmd, sess->se_sess, NULL, lun, mcmd,
|
||||
transl_tmr_func, GFP_ATOMIC, tag, TARGET_SCF_ACK_KREF);
|
||||
transl_tmr_func, GFP_ATOMIC, tag, flags);
|
||||
}
|
||||
|
||||
static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
|
||||
|
||||
@@ -488,15 +488,13 @@ EXPORT_SYMBOL(iscsit_queue_rsp);
|
||||
|
||||
void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
|
||||
{
|
||||
bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
|
||||
|
||||
spin_lock_bh(&conn->cmd_lock);
|
||||
if (!list_empty(&cmd->i_conn_node) &&
|
||||
!(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
|
||||
list_del_init(&cmd->i_conn_node);
|
||||
spin_unlock_bh(&conn->cmd_lock);
|
||||
|
||||
__iscsit_free_cmd(cmd, scsi_cmd, true);
|
||||
__iscsit_free_cmd(cmd, true);
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_aborted_task);
|
||||
|
||||
@@ -1251,12 +1249,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
|
||||
* execution. These exceptions are processed in CmdSN order using
|
||||
* iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
|
||||
*/
|
||||
if (cmd->sense_reason) {
|
||||
if (cmd->reject_reason)
|
||||
return 0;
|
||||
|
||||
if (cmd->sense_reason)
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Call directly into transport_generic_new_cmd() to perform
|
||||
* the backend memory allocation.
|
||||
|
||||
@@ -781,6 +781,7 @@ DEF_TPG_ATTRIB(default_erl);
|
||||
DEF_TPG_ATTRIB(t10_pi);
|
||||
DEF_TPG_ATTRIB(fabric_prot_type);
|
||||
DEF_TPG_ATTRIB(tpg_enabled_sendtargets);
|
||||
DEF_TPG_ATTRIB(login_keys_workaround);
|
||||
|
||||
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_attr_authentication,
|
||||
@@ -796,6 +797,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
|
||||
&iscsi_tpg_attrib_attr_t10_pi,
|
||||
&iscsi_tpg_attrib_attr_fabric_prot_type,
|
||||
&iscsi_tpg_attrib_attr_tpg_enabled_sendtargets,
|
||||
&iscsi_tpg_attrib_attr_login_keys_workaround,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
@@ -655,28 +655,6 @@ err:
|
||||
iscsit_deaccess_np(np, tpg, tpg_np);
|
||||
}
|
||||
|
||||
static void iscsi_target_do_cleanup(struct work_struct *work)
|
||||
{
|
||||
struct iscsi_conn *conn = container_of(work,
|
||||
struct iscsi_conn, login_cleanup_work.work);
|
||||
struct sock *sk = conn->sock->sk;
|
||||
struct iscsi_login *login = conn->login;
|
||||
struct iscsi_np *np = login->np;
|
||||
struct iscsi_portal_group *tpg = conn->tpg;
|
||||
struct iscsi_tpg_np *tpg_np = conn->tpg_np;
|
||||
|
||||
pr_debug("Entering iscsi_target_do_cleanup\n");
|
||||
|
||||
cancel_delayed_work_sync(&conn->login_work);
|
||||
conn->orig_state_change(sk);
|
||||
|
||||
iscsi_target_restore_sock_callbacks(conn);
|
||||
iscsi_target_login_drop(conn, login);
|
||||
iscsit_deaccess_np(np, tpg, tpg_np);
|
||||
|
||||
pr_debug("iscsi_target_do_cleanup done()\n");
|
||||
}
|
||||
|
||||
static void iscsi_target_sk_state_change(struct sock *sk)
|
||||
{
|
||||
struct iscsi_conn *conn;
|
||||
@@ -886,7 +864,8 @@ static int iscsi_target_handle_csg_zero(
|
||||
SENDER_TARGET,
|
||||
login->rsp_buf,
|
||||
&login->rsp_length,
|
||||
conn->param_list);
|
||||
conn->param_list,
|
||||
conn->tpg->tpg_attrib.login_keys_workaround);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
@@ -956,7 +935,8 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log
|
||||
SENDER_TARGET,
|
||||
login->rsp_buf,
|
||||
&login->rsp_length,
|
||||
conn->param_list);
|
||||
conn->param_list,
|
||||
conn->tpg->tpg_attrib.login_keys_workaround);
|
||||
if (ret < 0) {
|
||||
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
|
||||
ISCSI_LOGIN_STATUS_INIT_ERR);
|
||||
@@ -1082,7 +1062,6 @@ int iscsi_target_locate_portal(
|
||||
int sessiontype = 0, ret = 0, tag_num, tag_size;
|
||||
|
||||
INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx);
|
||||
INIT_DELAYED_WORK(&conn->login_cleanup_work, iscsi_target_do_cleanup);
|
||||
iscsi_target_set_sock_callbacks(conn);
|
||||
|
||||
login->np = np;
|
||||
@@ -1331,7 +1310,6 @@ int iscsi_target_start_negotiation(
|
||||
|
||||
if (ret < 0) {
|
||||
cancel_delayed_work_sync(&conn->login_work);
|
||||
cancel_delayed_work_sync(&conn->login_cleanup_work);
|
||||
iscsi_target_restore_sock_callbacks(conn);
|
||||
iscsi_remove_failed_auth_entry(conn);
|
||||
}
|
||||
|
||||
@@ -765,7 +765,8 @@ static int iscsi_check_for_auth_key(char *key)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
|
||||
static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param,
|
||||
bool keys_workaround)
|
||||
{
|
||||
if (IS_TYPE_BOOL_AND(param)) {
|
||||
if (!strcmp(param->value, NO))
|
||||
@@ -773,19 +774,31 @@ static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
|
||||
} else if (IS_TYPE_BOOL_OR(param)) {
|
||||
if (!strcmp(param->value, YES))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
/*
|
||||
* Required for gPXE iSCSI boot client
|
||||
*/
|
||||
if (!strcmp(param->name, IMMEDIATEDATA))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
|
||||
if (keys_workaround) {
|
||||
/*
|
||||
* Required for gPXE iSCSI boot client
|
||||
*/
|
||||
if (!strcmp(param->name, IMMEDIATEDATA))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
}
|
||||
} else if (IS_TYPE_NUMBER(param)) {
|
||||
if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
/*
|
||||
* Required for gPXE iSCSI boot client
|
||||
*/
|
||||
if (!strcmp(param->name, MAXCONNECTIONS))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
|
||||
if (keys_workaround) {
|
||||
/*
|
||||
* Required for Mellanox Flexboot PXE boot ROM
|
||||
*/
|
||||
if (!strcmp(param->name, FIRSTBURSTLENGTH))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
|
||||
/*
|
||||
* Required for gPXE iSCSI boot client
|
||||
*/
|
||||
if (!strcmp(param->name, MAXCONNECTIONS))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
}
|
||||
} else if (IS_PHASE_DECLARATIVE(param))
|
||||
SET_PSTATE_REPLY_OPTIONAL(param);
|
||||
}
|
||||
@@ -1422,7 +1435,8 @@ int iscsi_encode_text_output(
|
||||
u8 sender,
|
||||
char *textbuf,
|
||||
u32 *length,
|
||||
struct iscsi_param_list *param_list)
|
||||
struct iscsi_param_list *param_list,
|
||||
bool keys_workaround)
|
||||
{
|
||||
char *output_buf = NULL;
|
||||
struct iscsi_extra_response *er;
|
||||
@@ -1458,7 +1472,8 @@ int iscsi_encode_text_output(
|
||||
*length += 1;
|
||||
output_buf = textbuf + *length;
|
||||
SET_PSTATE_PROPOSER(param);
|
||||
iscsi_check_proposer_for_optional_reply(param);
|
||||
iscsi_check_proposer_for_optional_reply(param,
|
||||
keys_workaround);
|
||||
pr_debug("Sending key: %s=%s\n",
|
||||
param->name, param->value);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ extern int iscsi_extract_key_value(char *, char **, char **);
|
||||
extern int iscsi_update_param_value(struct iscsi_param *, char *);
|
||||
extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_conn *);
|
||||
extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
|
||||
struct iscsi_param_list *);
|
||||
struct iscsi_param_list *, bool);
|
||||
extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
|
||||
extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
|
||||
struct iscsi_param_list *);
|
||||
|
||||
@@ -227,6 +227,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
|
||||
a->t10_pi = TA_DEFAULT_T10_PI;
|
||||
a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE;
|
||||
a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS;
|
||||
a->login_keys_workaround = TA_DEFAULT_LOGIN_KEYS_WORKAROUND;
|
||||
}
|
||||
|
||||
int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
|
||||
@@ -311,11 +312,9 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
|
||||
struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
|
||||
int ret;
|
||||
|
||||
spin_lock(&tpg->tpg_state_lock);
|
||||
if (tpg->tpg_state == TPG_STATE_ACTIVE) {
|
||||
pr_err("iSCSI target portal group: %hu is already"
|
||||
" active, ignoring request.\n", tpg->tpgt);
|
||||
spin_unlock(&tpg->tpg_state_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
@@ -324,10 +323,8 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
|
||||
* is enforced (as per default), and remove the NONE option.
|
||||
*/
|
||||
param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
|
||||
if (!param) {
|
||||
spin_unlock(&tpg->tpg_state_lock);
|
||||
if (!param)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tpg->tpg_attrib.authentication) {
|
||||
if (!strcmp(param->value, NONE)) {
|
||||
@@ -341,6 +338,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock(&tpg->tpg_state_lock);
|
||||
tpg->tpg_state = TPG_STATE_ACTIVE;
|
||||
spin_unlock(&tpg->tpg_state_lock);
|
||||
|
||||
@@ -353,7 +351,6 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
spin_unlock(&tpg->tpg_state_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -899,3 +896,21 @@ int iscsit_ta_tpg_enabled_sendtargets(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iscsit_ta_login_keys_workaround(
|
||||
struct iscsi_portal_group *tpg,
|
||||
u32 flag)
|
||||
{
|
||||
struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
|
||||
|
||||
if ((flag != 0) && (flag != 1)) {
|
||||
pr_err("Illegal value %d\n", flag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
a->login_keys_workaround = flag;
|
||||
pr_debug("iSCSI_TPG[%hu] - TPG enabled bit for login keys workaround: %s ",
|
||||
tpg->tpgt, (a->login_keys_workaround) ? "ON" : "OFF");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -48,5 +48,6 @@ extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32);
|
||||
extern int iscsit_ta_login_keys_workaround(struct iscsi_portal_group *, u32);
|
||||
|
||||
#endif /* ISCSI_TARGET_TPG_H */
|
||||
|
||||
@@ -167,6 +167,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
|
||||
|
||||
cmd->se_cmd.map_tag = tag;
|
||||
cmd->conn = conn;
|
||||
cmd->data_direction = DMA_NONE;
|
||||
INIT_LIST_HEAD(&cmd->i_conn_node);
|
||||
INIT_LIST_HEAD(&cmd->datain_list);
|
||||
INIT_LIST_HEAD(&cmd->cmd_r2t_list);
|
||||
@@ -711,19 +712,16 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_release_cmd);
|
||||
|
||||
void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
|
||||
bool check_queues)
|
||||
void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues)
|
||||
{
|
||||
struct iscsi_conn *conn = cmd->conn;
|
||||
|
||||
if (scsi_cmd) {
|
||||
if (cmd->data_direction == DMA_TO_DEVICE) {
|
||||
iscsit_stop_dataout_timer(cmd);
|
||||
iscsit_free_r2ts_from_list(cmd);
|
||||
}
|
||||
if (cmd->data_direction == DMA_FROM_DEVICE)
|
||||
iscsit_free_all_datain_reqs(cmd);
|
||||
if (cmd->data_direction == DMA_TO_DEVICE) {
|
||||
iscsit_stop_dataout_timer(cmd);
|
||||
iscsit_free_r2ts_from_list(cmd);
|
||||
}
|
||||
if (cmd->data_direction == DMA_FROM_DEVICE)
|
||||
iscsit_free_all_datain_reqs(cmd);
|
||||
|
||||
if (conn && check_queues) {
|
||||
iscsit_remove_cmd_from_immediate_queue(cmd, conn);
|
||||
@@ -736,50 +734,18 @@ void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
|
||||
|
||||
void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
|
||||
{
|
||||
struct se_cmd *se_cmd = NULL;
|
||||
struct se_cmd *se_cmd = cmd->se_cmd.se_tfo ? &cmd->se_cmd : NULL;
|
||||
int rc;
|
||||
bool op_scsi = false;
|
||||
/*
|
||||
* Determine if a struct se_cmd is associated with
|
||||
* this struct iscsi_cmd.
|
||||
*/
|
||||
switch (cmd->iscsi_opcode) {
|
||||
case ISCSI_OP_SCSI_CMD:
|
||||
op_scsi = true;
|
||||
/*
|
||||
* Fallthrough
|
||||
*/
|
||||
case ISCSI_OP_SCSI_TMFUNC:
|
||||
se_cmd = &cmd->se_cmd;
|
||||
__iscsit_free_cmd(cmd, op_scsi, shutdown);
|
||||
|
||||
__iscsit_free_cmd(cmd, shutdown);
|
||||
if (se_cmd) {
|
||||
rc = transport_generic_free_cmd(se_cmd, shutdown);
|
||||
if (!rc && shutdown && se_cmd->se_sess) {
|
||||
__iscsit_free_cmd(cmd, op_scsi, shutdown);
|
||||
__iscsit_free_cmd(cmd, shutdown);
|
||||
target_put_sess_cmd(se_cmd);
|
||||
}
|
||||
break;
|
||||
case ISCSI_OP_REJECT:
|
||||
/*
|
||||
* Handle special case for REJECT when iscsi_add_reject*() has
|
||||
* overwritten the original iscsi_opcode assignment, and the
|
||||
* associated cmd->se_cmd needs to be released.
|
||||
*/
|
||||
if (cmd->se_cmd.se_tfo != NULL) {
|
||||
se_cmd = &cmd->se_cmd;
|
||||
__iscsit_free_cmd(cmd, true, shutdown);
|
||||
|
||||
rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
|
||||
if (!rc && shutdown && se_cmd->se_sess) {
|
||||
__iscsit_free_cmd(cmd, true, shutdown);
|
||||
target_put_sess_cmd(se_cmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Fall-through */
|
||||
default:
|
||||
__iscsit_free_cmd(cmd, false, shutdown);
|
||||
} else {
|
||||
iscsit_release_cmd(cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iscsit_free_cmd);
|
||||
|
||||
@@ -37,7 +37,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co
|
||||
extern bool iscsit_conn_all_queues_empty(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_free_cmd(struct iscsi_cmd *, bool, bool);
|
||||
extern void __iscsit_free_cmd(struct iscsi_cmd *, bool);
|
||||
extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
|
||||
extern int iscsit_check_session_usage_count(struct iscsi_session *);
|
||||
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
|
||||
|
||||
@@ -51,19 +51,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd);
|
||||
*/
|
||||
static int tcm_loop_check_stop_free(struct se_cmd *se_cmd)
|
||||
{
|
||||
/*
|
||||
* Do not release struct se_cmd's containing a valid TMR
|
||||
* pointer. These will be released directly in tcm_loop_device_reset()
|
||||
* with transport_generic_free_cmd().
|
||||
*/
|
||||
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
|
||||
return 0;
|
||||
/*
|
||||
* Release the struct se_cmd, which will make a callback to release
|
||||
* struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd()
|
||||
*/
|
||||
transport_generic_free_cmd(se_cmd, 0);
|
||||
return 1;
|
||||
return transport_generic_free_cmd(se_cmd, 0);
|
||||
}
|
||||
|
||||
static void tcm_loop_release_cmd(struct se_cmd *se_cmd)
|
||||
@@ -218,10 +206,8 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
|
||||
{
|
||||
struct se_cmd *se_cmd = NULL;
|
||||
struct se_session *se_sess;
|
||||
struct se_portal_group *se_tpg;
|
||||
struct tcm_loop_nexus *tl_nexus;
|
||||
struct tcm_loop_cmd *tl_cmd = NULL;
|
||||
struct tcm_loop_tmr *tl_tmr = NULL;
|
||||
int ret = TMR_FUNCTION_FAILED, rc;
|
||||
|
||||
/*
|
||||
@@ -240,55 +226,29 @@ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg,
|
||||
return ret;
|
||||
}
|
||||
|
||||
tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL);
|
||||
if (!tl_tmr) {
|
||||
pr_err("Unable to allocate memory for tl_tmr\n");
|
||||
goto release;
|
||||
}
|
||||
init_waitqueue_head(&tl_tmr->tl_tmr_wait);
|
||||
init_completion(&tl_cmd->tmr_done);
|
||||
|
||||
se_cmd = &tl_cmd->tl_se_cmd;
|
||||
se_tpg = &tl_tpg->tl_se_tpg;
|
||||
se_sess = tl_tpg->tl_nexus->se_sess;
|
||||
/*
|
||||
* Initialize struct se_cmd descriptor from target_core_mod infrastructure
|
||||
*/
|
||||
transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0,
|
||||
DMA_NONE, TCM_SIMPLE_TAG,
|
||||
&tl_cmd->tl_sense_buf[0]);
|
||||
|
||||
rc = core_tmr_alloc_req(se_cmd, tl_tmr, tmr, GFP_KERNEL);
|
||||
rc = target_submit_tmr(se_cmd, se_sess, tl_cmd->tl_sense_buf, lun,
|
||||
NULL, tmr, GFP_KERNEL, task,
|
||||
TARGET_SCF_ACK_KREF);
|
||||
if (rc < 0)
|
||||
goto release;
|
||||
|
||||
if (tmr == TMR_ABORT_TASK)
|
||||
se_cmd->se_tmr_req->ref_task_tag = task;
|
||||
|
||||
/*
|
||||
* Locate the underlying TCM struct se_lun
|
||||
*/
|
||||
if (transport_lookup_tmr_lun(se_cmd, lun) < 0) {
|
||||
ret = TMR_LUN_DOES_NOT_EXIST;
|
||||
goto release;
|
||||
}
|
||||
/*
|
||||
* Queue the TMR to TCM Core and sleep waiting for
|
||||
* tcm_loop_queue_tm_rsp() to wake us up.
|
||||
*/
|
||||
transport_generic_handle_tmr(se_cmd);
|
||||
wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete));
|
||||
/*
|
||||
* The TMR LUN_RESET has completed, check the response status and
|
||||
* then release allocations.
|
||||
*/
|
||||
wait_for_completion(&tl_cmd->tmr_done);
|
||||
ret = se_cmd->se_tmr_req->response;
|
||||
target_put_sess_cmd(se_cmd);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
release:
|
||||
if (se_cmd)
|
||||
transport_generic_free_cmd(se_cmd, 1);
|
||||
transport_generic_free_cmd(se_cmd, 0);
|
||||
else
|
||||
kmem_cache_free(tcm_loop_cmd_cache, tl_cmd);
|
||||
kfree(tl_tmr);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int tcm_loop_abort_task(struct scsi_cmnd *sc)
|
||||
@@ -669,14 +629,11 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)
|
||||
|
||||
static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)
|
||||
{
|
||||
struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
|
||||
struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr;
|
||||
/*
|
||||
* The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead
|
||||
* and wake up the wait_queue_head_t in tcm_loop_device_reset()
|
||||
*/
|
||||
atomic_set(&tl_tmr->tmr_complete, 1);
|
||||
wake_up(&tl_tmr->tl_tmr_wait);
|
||||
struct tcm_loop_cmd *tl_cmd = container_of(se_cmd,
|
||||
struct tcm_loop_cmd, tl_se_cmd);
|
||||
|
||||
/* Wake up tcm_loop_issue_tmr(). */
|
||||
complete(&tl_cmd->tmr_done);
|
||||
}
|
||||
|
||||
static void tcm_loop_aborted_task(struct se_cmd *se_cmd)
|
||||
|
||||
@@ -16,15 +16,11 @@ struct tcm_loop_cmd {
|
||||
/* The TCM I/O descriptor that is accessed via container_of() */
|
||||
struct se_cmd tl_se_cmd;
|
||||
struct work_struct work;
|
||||
struct completion tmr_done;
|
||||
/* Sense buffer that will be mapped into outgoing status */
|
||||
unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER];
|
||||
};
|
||||
|
||||
struct tcm_loop_tmr {
|
||||
atomic_t tmr_complete;
|
||||
wait_queue_head_t tl_tmr_wait;
|
||||
};
|
||||
|
||||
struct tcm_loop_nexus {
|
||||
/*
|
||||
* Pointer to TCM session for I_T Nexus
|
||||
|
||||
@@ -205,8 +205,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
|
||||
/*
|
||||
* TARGET PORT GROUP
|
||||
*/
|
||||
buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff);
|
||||
buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff);
|
||||
put_unaligned_be16(tg_pt_gp->tg_pt_gp_id, &buf[off]);
|
||||
off += 2;
|
||||
|
||||
off++; /* Skip over Reserved */
|
||||
/*
|
||||
@@ -235,8 +235,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
|
||||
/*
|
||||
* Set RELATIVE TARGET PORT IDENTIFIER
|
||||
*/
|
||||
buf[off++] = ((lun->lun_rtpi >> 8) & 0xff);
|
||||
buf[off++] = (lun->lun_rtpi & 0xff);
|
||||
put_unaligned_be16(lun->lun_rtpi, &buf[off]);
|
||||
off += 2;
|
||||
rd_len += 4;
|
||||
}
|
||||
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
|
||||
|
||||
@@ -1085,6 +1085,24 @@ static ssize_t block_size_store(struct config_item *item,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t alua_support_show(struct config_item *item, char *page)
|
||||
{
|
||||
struct se_dev_attrib *da = to_attrib(item);
|
||||
u8 flags = da->da_dev->transport->transport_flags;
|
||||
|
||||
return snprintf(page, PAGE_SIZE, "%d\n",
|
||||
flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ? 0 : 1);
|
||||
}
|
||||
|
||||
static ssize_t pgr_support_show(struct config_item *item, char *page)
|
||||
{
|
||||
struct se_dev_attrib *da = to_attrib(item);
|
||||
u8 flags = da->da_dev->transport->transport_flags;
|
||||
|
||||
return snprintf(page, PAGE_SIZE, "%d\n",
|
||||
flags & TRANSPORT_FLAG_PASSTHROUGH_PGR ? 0 : 1);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR(, emulate_model_alias);
|
||||
CONFIGFS_ATTR(, emulate_dpo);
|
||||
CONFIGFS_ATTR(, emulate_fua_write);
|
||||
@@ -1116,6 +1134,8 @@ CONFIGFS_ATTR(, unmap_granularity);
|
||||
CONFIGFS_ATTR(, unmap_granularity_alignment);
|
||||
CONFIGFS_ATTR(, unmap_zeroes_data);
|
||||
CONFIGFS_ATTR(, max_write_same_len);
|
||||
CONFIGFS_ATTR_RO(, alua_support);
|
||||
CONFIGFS_ATTR_RO(, pgr_support);
|
||||
|
||||
/*
|
||||
* dev_attrib attributes for devices using the target core SBC/SPC
|
||||
@@ -1154,6 +1174,8 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
|
||||
&attr_unmap_granularity_alignment,
|
||||
&attr_unmap_zeroes_data,
|
||||
&attr_max_write_same_len,
|
||||
&attr_alua_support,
|
||||
&attr_pgr_support,
|
||||
NULL,
|
||||
};
|
||||
EXPORT_SYMBOL(sbc_attrib_attrs);
|
||||
@@ -1168,6 +1190,8 @@ struct configfs_attribute *passthrough_attrib_attrs[] = {
|
||||
&attr_hw_block_size,
|
||||
&attr_hw_max_sectors,
|
||||
&attr_hw_queue_depth,
|
||||
&attr_alua_support,
|
||||
&attr_pgr_support,
|
||||
NULL,
|
||||
};
|
||||
EXPORT_SYMBOL(passthrough_attrib_attrs);
|
||||
@@ -2236,7 +2260,11 @@ static void target_core_dev_release(struct config_item *item)
|
||||
target_free_device(dev);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations target_core_dev_item_ops = {
|
||||
/*
|
||||
* Used in target_core_fabric_configfs.c to verify valid se_device symlink
|
||||
* within target_fabric_port_link()
|
||||
*/
|
||||
struct configfs_item_operations target_core_dev_item_ops = {
|
||||
.release = target_core_dev_release,
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user