Commit afb54c14 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI fixes from James Bottomley:
 "Driver (and enclosure) only fixes. Most are obvious. The big change is
  in the tcm_loop driver to add command draining to error handling (the
  lack of which was causing hangs with the potential for double use
  crashes)"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: target: file: Use kzalloc_flex for aio_cmd
  scsi: scsi_transport_sas: Fix the maximum channel scanning issue
  scsi: target: tcm_loop: Drain commands in target_reset handler
  scsi: ibmvfc: Fix OOB access in ibmvfc_discover_targets_done()
  scsi: ses: Handle positive SCSI error from ses_recv_diag()
parents 26df51ad 01f784fc
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4966,7 +4966,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt)
	switch (mad_status) {
	case IBMVFC_MAD_SUCCESS:
		ibmvfc_dbg(vhost, "Discover Targets succeeded\n");
		vhost->num_targets = be32_to_cpu(rsp->num_written);
		vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written),
					   max_targets);
		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
		break;
	case IBMVFC_MAD_FAILED:
+1 −1
Original line number Diff line number Diff line
@@ -1734,7 +1734,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
		break;

	default:
		if (channel < shost->max_channel) {
		if (channel <= shost->max_channel) {
			res = scsi_scan_host_selected(shost, channel, id, lun,
						      SCSI_SCAN_MANUAL);
		} else {
+1 −1
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
	unsigned char *type_ptr = ses_dev->page1_types;
	unsigned char *desc_ptr = ses_dev->page2 + 8;

	if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0)
	if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len))
		return NULL;

	for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) {
+46 −6
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/configfs.h>
#include <linux/blk-mq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
@@ -269,15 +270,27 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
	return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}

static bool tcm_loop_flush_work_iter(struct request *rq, void *data)
{
	struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq);
	struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
	struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd;

	flush_work(&se_cmd->work);
	return true;
}

static int tcm_loop_target_reset(struct scsi_cmnd *sc)
{
	struct tcm_loop_hba *tl_hba;
	struct tcm_loop_tpg *tl_tpg;
	struct Scsi_Host *sh = sc->device->host;
	int ret;

	/*
	 * Locate the tcm_loop_hba_t pointer
	 */
	tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
	tl_hba = *(struct tcm_loop_hba **)shost_priv(sh);
	if (!tl_hba) {
		pr_err("Unable to perform device reset without active I_T Nexus\n");
		return FAILED;
@@ -286,12 +299,39 @@ static int tcm_loop_target_reset(struct scsi_cmnd *sc)
	 * Locate the tl_tpg pointer from TargetID in sc->device->id
	 */
	tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
	if (tl_tpg) {
	if (!tl_tpg)
		return FAILED;

	/*
	 * Issue a LUN_RESET to drain all commands that the target core
	 * knows about.  This handles commands not yet marked CMD_T_COMPLETE.
	 */
	ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET);
	if (ret != TMR_FUNCTION_COMPLETE)
		return FAILED;

	/*
	 * Flush any deferred target core completion work that may still be
	 * queued.  Commands that already had CMD_T_COMPLETE set before the TMR
	 * are skipped by the TMR drain, but their async completion work
	 * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done)
	 * may still be pending in target_completion_wq.
	 *
	 * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery
	 * commands (e.g. TUR) immediately after this handler returns SUCCESS —
	 * if deferred work is still pending, the memset in queuecommand would
	 * zero the se_cmd while the work accesses it, leaking the LUN
	 * percpu_ref and hanging configfs unlink forever.
	 *
	 * Use blk_mq_tagset_busy_iter() to find all started requests and
	 * flush_work() on each — the same pattern used by mpi3mr, scsi_debug,
	 * and other SCSI drivers to drain outstanding commands during reset.
	 */
	blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL);

	tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
	return SUCCESS;
}
	return FAILED;
}

static const struct scsi_host_template tcm_loop_driver_template = {
	.show_info		= tcm_loop_show_info,
+1 −1
Original line number Diff line number Diff line
@@ -276,7 +276,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
	ssize_t len = 0;
	int ret = 0, i;

	aio_cmd = kmalloc_flex(*aio_cmd, bvecs, sgl_nents);
	aio_cmd = kzalloc_flex(*aio_cmd, bvecs, sgl_nents);
	if (!aio_cmd)
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;