Commit a61236da authored by Tyrel Datwyler's avatar Tyrel Datwyler Committed by Martin K. Petersen
Browse files

scsi: ibmvfc: Add cancel mad initialization helper

Add a helper routine for initializing a Cancel MAD. This will be useful for
a channelized client that needs to send Cancel commands down every channel
commands were sent for a particular LUN.

Link: https://lore.kernel.org/r/20210114203148.246656-18-tyreld@linux.ibm.com


Reviewed-by: default avatarBrian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarTyrel Datwyler <tyreld@linux.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent b88a5d9b
Loading
Loading
Loading
Loading
+40 −28
Original line number Diff line number Diff line
@@ -2379,6 +2379,45 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
	return SUCCESS;
}

static struct ibmvfc_event *ibmvfc_init_tmf(struct ibmvfc_queue *queue,
					    struct scsi_device *sdev,
					    int type)
{
	struct ibmvfc_host *vhost = shost_priv(sdev->host);
	struct scsi_target *starget = scsi_target(sdev);
	struct fc_rport *rport = starget_to_rport(starget);
	struct ibmvfc_event *evt;
	struct ibmvfc_tmf *tmf;

	evt = ibmvfc_get_event(queue);
	ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);

	tmf = &evt->iu.tmf;
	memset(tmf, 0, sizeof(*tmf));
	if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
		tmf->common.version = cpu_to_be32(2);
		tmf->target_wwpn = cpu_to_be64(rport->port_name);
	} else {
		tmf->common.version = cpu_to_be32(1);
	}
	tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD);
	tmf->common.length = cpu_to_be16(sizeof(*tmf));
	tmf->scsi_id = cpu_to_be64(rport->port_id);
	int_to_scsilun(sdev->lun, &tmf->lun);
	if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS))
		type &= ~IBMVFC_TMF_SUPPRESS_ABTS;
	if (vhost->state == IBMVFC_ACTIVE)
		tmf->flags = cpu_to_be32((type | IBMVFC_TMF_LUA_VALID));
	else
		tmf->flags = cpu_to_be32(((type & IBMVFC_TMF_SUPPRESS_ABTS) | IBMVFC_TMF_LUA_VALID));
	tmf->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata);
	tmf->my_cancel_key = cpu_to_be32((unsigned long)starget->hostdata);

	init_completion(&evt->comp);

	return evt;
}

/**
 * ibmvfc_cancel_all - Cancel all outstanding commands to the device
 * @sdev:	scsi device to cancel commands
@@ -2393,9 +2432,6 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
{
	struct ibmvfc_host *vhost = shost_priv(sdev->host);
	struct scsi_target *starget = scsi_target(sdev);
	struct fc_rport *rport = starget_to_rport(starget);
	struct ibmvfc_tmf *tmf;
	struct ibmvfc_event *evt, *found_evt;
	union ibmvfc_iu rsp;
	int rsp_rc = -EBUSY;
@@ -2422,32 +2458,8 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
	}

	if (vhost->logged_in) {
		evt = ibmvfc_get_event(&vhost->crq);
		ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);

		tmf = &evt->iu.tmf;
		memset(tmf, 0, sizeof(*tmf));
		if (ibmvfc_check_caps(vhost, IBMVFC_HANDLE_VF_WWPN)) {
			tmf->common.version = cpu_to_be32(2);
			tmf->target_wwpn = cpu_to_be64(rport->port_name);
		} else {
			tmf->common.version = cpu_to_be32(1);
		}
		tmf->common.opcode = cpu_to_be32(IBMVFC_TMF_MAD);
		tmf->common.length = cpu_to_be16(sizeof(*tmf));
		tmf->scsi_id = cpu_to_be64(rport->port_id);
		int_to_scsilun(sdev->lun, &tmf->lun);
		if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS))
			type &= ~IBMVFC_TMF_SUPPRESS_ABTS;
		if (vhost->state == IBMVFC_ACTIVE)
			tmf->flags = cpu_to_be32((type | IBMVFC_TMF_LUA_VALID));
		else
			tmf->flags = cpu_to_be32(((type & IBMVFC_TMF_SUPPRESS_ABTS) | IBMVFC_TMF_LUA_VALID));
		tmf->cancel_key = cpu_to_be32((unsigned long)sdev->hostdata);
		tmf->my_cancel_key = cpu_to_be32((unsigned long)starget->hostdata);

		evt = ibmvfc_init_tmf(&vhost->crq, sdev, type);
		evt->sync_iu = &rsp;
		init_completion(&evt->comp);
		rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout);
	}