diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 14:27:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-13 14:27:32 -0700 |
commit | 48ea2cedde3507941f4549b0d27ed46ed29e39ff (patch) | |
tree | 07dfc2fe520445598e5429df88b32bd470f0f055 /drivers/scsi | |
parent | 62403005975c678ba7594a36670ae3bf0273d7c4 (diff) | |
parent | 138d351eefb727ab9e41a3dc5f112ceb4f6e59f2 (diff) | |
download | linux-48ea2cedde3507941f4549b0d27ed46ed29e39ff.tar.bz2 |
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
...
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 156 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h | 25 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi_tgt/libsrp.h | 5 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 38 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.c | 4 |
5 files changed, 182 insertions, 46 deletions
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 659ab483d716..1f75d0380516 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -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; @@ -951,6 +964,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 * @crq: Pointer to CRQ entry containing the Transport Event @@ -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, diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h index b4391a8de456..cc96c2731134 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h @@ -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) diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.h b/drivers/scsi/ibmvscsi_tgt/libsrp.h index 4696f331453e..9fec55b36322 100644 --- a/drivers/scsi/ibmvscsi_tgt/libsrp.h +++ b/drivers/scsi/ibmvscsi_tgt/libsrp.h @@ -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 diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 2a0173e5d10e..c2dc836dc484 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -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, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index c4b414833b86..b20da0d27ad7 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -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) |